From 4d460369c05ed77a5e0d9399a2db9fcf6c09a1d8 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 6 Nov 2008 08:01:11 +0000 Subject: [PATCH] WIP commit before some optimizations, fix for possible divide by zero. added BarryCentricWeights2f(), returns weights for points outside the triangle. --- source/blender/src/imagepaint.c | 71 ++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 15 deletions(-) diff --git a/source/blender/src/imagepaint.c b/source/blender/src/imagepaint.c index f8af2d91a88..361776e9b59 100644 --- a/source/blender/src/imagepaint.c +++ b/source/blender/src/imagepaint.c @@ -135,6 +135,7 @@ typedef struct ImagePaintState { // #define PROJ_DEBUG_PAINT 1 // #define PROJ_DEBUG_NOSCANLINE 1 +//#define PROJ_DEBUG_NOSEAMBLEED 1 /* projectFaceFlags options */ #define PROJ_FACE_IGNORE 1<<0 /* When the face is hidden, backfacing or occluded */ @@ -144,7 +145,6 @@ typedef struct ImagePaintState { #define PROJ_FACE_SEAM3 1<<4 #define PROJ_FACE_SEAM4 1<<5 - #define PROJ_BUCKET_NULL 0 #define PROJ_BUCKET_INIT 1<<0 // #define PROJ_BUCKET_CLONE_INIT 1<<1 @@ -191,8 +191,9 @@ typedef struct ProjectPaintState { short projectIsOcclude; /* Use raytraced occlusion? - ortherwise will paint right through to the back*/ short projectIsBackfaceCull; /* ignore faces with normals pointing away, skips a lot of raycasts if your normals are correctly flipped */ short projectIsOrtho; +#ifndef PROJ_DEBUG_NOSEAMBLEED float projectSeamBleed; - +#endif /* clone vars */ float cloneOfs[2]; @@ -411,21 +412,48 @@ static int project_paint_BucketOffsetSafe(ProjectPaintState *ps, float *projCo2D } } -/* assume they intersect */ -static void BarryCentricWeights2f(float v1[2], float v2[2], float v3[2], float pt[2], float w[3]) { +/* The point must be inside the triangle */ +static void BaryCentricWeightsSimple2f(float v1[2], float v2[2], float v3[2], float pt[2], float w[3]) { float wtot; w[0] = AreaF2Dfl(v2, v3, pt); w[1] = AreaF2Dfl(v3, v1, pt); w[2] = AreaF2Dfl(v1, v2, pt); wtot = w[0]+w[1]+w[2]; - w[0]/=wtot; - w[1]/=wtot; - w[2]/=wtot; + if (wtot > 0.0) { /* just incase */ + w[0]/=wtot; + w[1]/=wtot; + w[2]/=wtot; + } else { + w[0] = w[1] = w[2] = 1.0/3.0; /* dummy values for zero area face */ + } +} + +/* also works for points outside the triangle */ +#define SIDE_OF_LINE(pa,pb,pp) ((pa[0]-pp[0])*(pb[1]-pp[1]))-((pb[0]-pp[0])*(pa[1]-pp[1])) +static void BaryCentricWeights2f(float v1[2], float v2[2], float v3[2], float pt[2], float w[3]) { + float wtot = AreaF2Dfl(v1, v2, v3); + if (wtot > 0.0) { + w[0] = AreaF2Dfl(v2, v3, pt); + w[1] = AreaF2Dfl(v3, v1, pt); + w[2] = AreaF2Dfl(v1, v2, pt); + + /* negate weights when 'pt' is on the outer side of the the triangles edge */ + if ((SIDE_OF_LINE(v2,v3, pt)>0.0) != (SIDE_OF_LINE(v2,v3, v1)>0.0)) w[0]/= -wtot; + else w[0]/= wtot; + + if ((SIDE_OF_LINE(v3,v1, pt)>0.0) != (SIDE_OF_LINE(v3,v1, v2)>0.0)) w[1]/= -wtot; + else w[1]/= wtot; + + if ((SIDE_OF_LINE(v1,v2, pt)>0.0) != (SIDE_OF_LINE(v1,v2, v3)>0.0)) w[2]/= -wtot; + else w[2]/= wtot; + } else { + w[0] = w[1] = w[2] = 1.0/3.0; /* dummy values for zero area face */ + } } static float tri_depth_2d(float v1[3], float v2[3], float v3[3], float pt[2], float w[3]) { - BarryCentricWeights2f(v1,v2,v3,pt,w); + BaryCentricWeightsSimple2f(v1,v2,v3,pt,w); return (v1[2]*w[0]) + (v2[2]*w[1]) + (v3[2]*w[2]); } @@ -749,6 +777,7 @@ static int cmp_uv(float vec2a[2], float vec2b[2]) } +#ifndef PROJ_DEBUG_NOSEAMBLEED static int check_seam(ProjectPaintState *ps, int orig_face, int orig_i1_fidx, int orig_i2_fidx) { LinkNode *node; @@ -825,6 +854,7 @@ static void project_face_seams_init(ProjectPaintState *ps, int face_index, int i (check_seam(ps, face_index, 2,0) ? PROJ_FACE_SEAM3 : 0); } } +#endif // PROJ_DEBUG_NOSEAMBLEED static float angleToLength(float angle) { @@ -1004,7 +1034,7 @@ static screen_px_from_ortho( float pixelScreenCo[4] ) { float w[3]; - BarryCentricWeights2f(uv1co,uv2co,uv3co,uv,w); + BaryCentricWeightsSimple2f(uv1co,uv2co,uv3co,uv,w); pixelScreenCo[0] = v1co[0]*w[0] + v2co[0]*w[1] + v3co[0]*w[2]; pixelScreenCo[1] = v1co[1]*w[0] + v2co[1]*w[1] + v3co[1]*w[2]; pixelScreenCo[2] = v1co[2]*w[0] + v2co[2]*w[1] + v3co[2]*w[2]; @@ -1017,7 +1047,7 @@ static screen_px_from_persp( float pixelScreenCo[4]) { float w[3]; - BarryCentricWeights2f(uv1co,uv2co,uv3co,uv,w); + BaryCentricWeightsSimple2f(uv1co,uv2co,uv3co,uv,w); pixelScreenCo[0] = v1co[0]*w[0] + v2co[0]*w[1] + v3co[0]*w[2]; pixelScreenCo[1] = v1co[1]*w[0] + v2co[1]*w[1] + v3co[1]*w[2]; pixelScreenCo[2] = v1co[2]*w[0] + v2co[2]*w[1] + v3co[2]*w[2]; @@ -1131,10 +1161,12 @@ static void project_paint_face_init(ProjectPaintState *ps, int face_index, ImBuf if (!uv_image_rect(tf->uv[0], tf->uv[1], tf->uv[2], tf->uv[3], min_px, max_px, ibuf->x, ibuf->y, mf->v4)) return; - + +#ifndef PROJ_DEBUG_NOSEAMBLEED /* detect UV seams so we can bleed */ if (ps->projectSeamBleed > 0.0) project_face_seams_init(ps, face_index, mf->v4); +#endif for (y = min_px[1]; y < max_px[1]; y++) { uv[1] = (((float)y)+0.5) / (float)ibuf->y; /* TODO - this is not pixel aligned correctly */ @@ -1214,7 +1246,8 @@ static void project_paint_face_init(ProjectPaintState *ps, int face_index, ImBuf } -#ifndef PROJ_DEBUG_NOSCANLINE +#ifndef PROJ_DEBUG_NOSCANLINE +#ifndef PROJ_DEBUG_NOSEAMBLEED /* Pretty much a copy of above, except fill in seams if we have any */ if (ps->projectFaceFlags[face_index] & (PROJ_FACE_SEAM1|PROJ_FACE_SEAM2|PROJ_FACE_SEAM3|PROJ_FACE_SEAM4)) { float outset_uv[4][2]; /* expanded UV's */ @@ -1378,6 +1411,7 @@ static void project_paint_face_init(ProjectPaintState *ps, int face_index, ImBuf } } #endif +#endif } @@ -1544,6 +1578,7 @@ static void project_paint_delayed_face_init(ProjectPaintState *ps, MFace *mf, MT DO_MINMAX2(ps->projectVertScreenCos[ a ], min, max); +#ifndef PROJ_DEBUG_NOSEAMBLEED /* add face user if we have bleed enabled, set the UV seam flags later */ if (ps->projectSeamBleed > 0.0) { BLI_linklist_prepend_arena( @@ -1552,6 +1587,7 @@ static void project_paint_delayed_face_init(ProjectPaintState *ps, MFace *mf, MT ps->projectArena ); } +#endif } while (i--); project_paint_rect(ps, min, max, bucket_min, bucket_max); @@ -1642,9 +1678,10 @@ static void project_paint_begin( ProjectPaintState *ps, short mval[2]) tot_faceListMem = sizeof(LinkNode *) * ps->bucketsX * ps->bucketsY; tot_faceFlagMem = sizeof(char) * ps->dm_totface; tot_bucketFlagMem = sizeof(char) * ps->bucketsX * ps->bucketsY; +#ifndef PROJ_DEBUG_NOSEAMBLEED if (ps->projectSeamBleed > 0.0) /* UV Seams for bleeding */ tot_bucketVertFacesMem = sizeof(LinkNode *) * ps->dm_totvert; - +#endif ps->projectArena = BLI_memarena_new( tot_bucketMem + @@ -1656,16 +1693,19 @@ static void project_paint_begin( ProjectPaintState *ps, short mval[2]) ps->projectFaces= (LinkNode **)BLI_memarena_alloc( ps->projectArena, tot_faceListMem); ps->projectFaceFlags = (char *)BLI_memarena_alloc( ps->projectArena, tot_faceFlagMem); ps->projectBucketFlags= (char *)BLI_memarena_alloc( ps->projectArena, tot_bucketFlagMem); +#ifndef PROJ_DEBUG_NOSEAMBLEED if (ps->projectSeamBleed > 0.0) ps->projectVertFaces= (LinkNode **)BLI_memarena_alloc( ps->projectArena, tot_bucketVertFacesMem); +#endif memset(ps->projectBuckets, 0, tot_bucketMem); memset(ps->projectFaces, 0, tot_faceListMem); memset(ps->projectFaceFlags, 0, tot_faceFlagMem); memset(ps->projectBucketFlags, 0, tot_bucketFlagMem); +#ifndef PROJ_DEBUG_NOSEAMBLEED if (ps->projectSeamBleed > 0.0) memset(ps->projectVertFaces, 0, tot_bucketVertFacesMem); - +#endif Mat4Invert(ps->ob->imat, ps->ob->obmat); Mat3CpyMat4(mat, G.vd->viewinv); @@ -2658,8 +2698,9 @@ void imagepaint_paint(short mousebutton, short texpaint) /* setup projection painting data */ ps.projectIsBackfaceCull = 1; ps.projectIsOcclude = 1; +#ifndef PROJ_DEBUG_NOSEAMBLEED ps.projectSeamBleed = 2.0; /* pixel num to bleed */ - +#endif project_paint_begin(&ps, mval); } else {