Revision: 17329 http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=17329 Author: campbellbarton Date: 2008-11-05 04:12:59 +0100 (Wed, 05 Nov 2008)
Log Message: ----------- fix for pixels not being drawn in 2 cases. 1 issue was caused by detecting 2d horizontal line intersections for lines that had points equal to the horizontal Y value - solved by detecting point on line cases. Another was because the 2D bounding box for painting could have faces edges running along it - solved by adding a small margin to the bounding box. Modified Paths: -------------- branches/projection-paint/source/blender/src/imagepaint.c Modified: branches/projection-paint/source/blender/src/imagepaint.c =================================================================== --- branches/projection-paint/source/blender/src/imagepaint.c 2008-11-04 23:46:01 UTC (rev 17328) +++ branches/projection-paint/source/blender/src/imagepaint.c 2008-11-05 03:12:59 UTC (rev 17329) @@ -119,7 +119,6 @@ ImBuf *canvas; ImBuf *clonecanvas; short clonefreefloat; - short project; /* is projection texture painting enabled */ char *warnpackedfile; char *warnmultifile; @@ -135,6 +134,7 @@ #define PROJ_BUCKET_DIV 128 /* TODO - test other values, this is a guess, seems ok */ // #define PROJ_DEBUG_PAINT 1 +// #define PROJ_DEBUG_NOSCANLINE 1 /* projectFaceFlags options */ #define PROJ_FACE_IGNORE 1<<0 /* When the face is hidden, backfacing or occluded */ @@ -155,6 +155,10 @@ #define PROJ_BUCKET_TOP 3 typedef struct ProjectPaintState { + Brush *brush; + short tool, blend; + Object *ob; + /* end similarities with ImagePaintState */ DerivedMesh *dm; int dm_totface; @@ -479,40 +483,28 @@ return 0; } -/* basic line intersection, could move to arithb.c, 2 points with a horiz line */ -static int project_scanline_isect(float *p1, float *p2, float y_level, float *y_isect) +/* basic line intersection, could move to arithb.c, 2 points with a horiz line + * 1 for an intersection, 2 if the first point is aligned, 3 if the second point is aligned */ +#define ISECT_TRUE 1 +#define ISECT_TRUE_P1 2 +#define ISECT_TRUE_P2 3 +static int project_scanline_isect(float *p1, float *p2, float y_level, float *x_isect) { - if (p1[1] > y_level && p2[1] < y_level) { - *y_isect = (p2[0]*(p1[1]-y_level) + p1[0]*(y_level-p2[1])) / (p1[1]-p2[1]); - return 1; - } else if (p1[1] < y_level && p2[1] > y_level) { - *y_isect = (p2[0]*(y_level-p1[1]) + p1[0]*(p2[1]-y_level)) / (p2[1]-p1[1]); - return 1; - } else { - return 0; + if (y_level==p1[1]) { + *x_isect = p1[0]; + return ISECT_TRUE_P1; } -} - -/* take 3 uv coords, a horizontal x_limits and set the min|max intersections points here */ -static int project_uv_scanline(float *uv1, float *uv2, float *uv3, float y_level, float x_limits[2]) -{ - int i = 0; - - if (project_scanline_isect(uv1, uv2, y_level, &x_limits[0])) i++; - if (project_scanline_isect(uv2, uv3, y_level, &x_limits[i])) i++; - /* if the triangle intersects then the first 2 lines must */ - if (i==0) { - return 0; - } else if (i!=2) { - /* if we are here then this really should not fail since 2 edges MUST intersect */ - if (project_scanline_isect(uv3, uv1, y_level, &x_limits[i])) i++; + if (y_level==p2[1]) { + *x_isect = p2[0]; + return ISECT_TRUE_P2; } - if (i==2) { - if (x_limits[0] > x_limits[1]) { - SWAP(float, x_limits[0], x_limits[1]); - } - return 1; + if (p1[1] > y_level && p2[1] < y_level) { + *x_isect = (p2[0]*(p1[1]-y_level) + p1[0]*(y_level-p2[1])) / (p1[1]-p2[1]); + return ISECT_TRUE; + } else if (p1[1] < y_level && p2[1] > y_level) { + *x_isect = (p2[0]*(y_level-p1[1]) + p1[0]*(p2[1]-y_level)) / (p2[1]-p1[1]); + return ISECT_TRUE; } else { return 0; } @@ -523,14 +515,15 @@ /* Create a scanlines for the face at this Y level * triangles will only ever have 1 scanline, quads may have 2 */ int totscanlines = 0; + short i1=0,i2=0,i3=0; if (v4) { /* This is a quad?*/ - short i1,i2,i3,i4, i_mid; + int i4=0, i_mid=0; float xi1, xi2, xi3, xi4, xi_mid; - - + i1 = project_scanline_isect(v1, v2, y_level, &xi1); - i2 = project_scanline_isect(v2, v3, y_level, &xi2); + if (i1 != ISECT_TRUE_P2) /* rare cases we could be on the line, in these cases we dont want to intersect with the same point twice */ + i2 = project_scanline_isect(v2, v3, y_level, &xi2); if (i1 && i2) { /* both the first 2 edges intersect, this means the second half of the quad wont intersect */ sc->v[0] = 0; @@ -540,8 +533,10 @@ sc->x_limits[1] = MAX2(xi1, xi2); totscanlines = 1; } else { - i3 = project_scanline_isect(v3, v4, y_level, &xi3); - i4 = project_scanline_isect(v4, v1, y_level, &xi4); + if (i2 != ISECT_TRUE_P2) + i3 = project_scanline_isect(v3, v4, y_level, &xi3); + if (i1 != ISECT_TRUE_P1 && i3 != ISECT_TRUE_P2) + i4 = project_scanline_isect(v4, v1, y_level, &xi4); if (i3 && i4) { /* second 2 edges only intersect, same as above */ sc->v[0] = 0; @@ -573,14 +568,38 @@ } } } + } else { /* triangle */ + int i = 0; - } else { - if (project_uv_scanline(v1, v2, v3, y_level, sc->x_limits)) { - sc->v[0] = 0; - sc->v[1] = 1; - sc->v[2] = 2; - totscanlines = 1; + i1 = project_scanline_isect(v1, v2, y_level, &sc->x_limits[0]); + if (i1) i++; + + if (i1 != ISECT_TRUE_P2) { + i2 = project_scanline_isect(v2, v3, y_level, &sc->x_limits[i]); + if (i2) i++; } + + /* if the triangle intersects then the first 2 lines must */ + if (i!=0) { + if (i!=2) { + /* if we are here then this really should not fail since 2 edges MUST intersect */ + if (i1 != ISECT_TRUE_P1 && i2 != ISECT_TRUE_P2) { + i3 = project_scanline_isect(v3, v1, y_level, &sc->x_limits[i]); + if (i3) i++; + + } + } + + if (i==2) { + if (sc->x_limits[0] > sc->x_limits[1]) { + SWAP(float, sc->x_limits[0], sc->x_limits[1]); + } + sc->v[0] = 0; + sc->v[1] = 1; + sc->v[2] = 2; + totscanlines = 1; + } + } } /* done setting up scanlines */ return totscanlines; @@ -883,10 +902,12 @@ /* can provide own own coords, use for seams when we want to bleed our from the original location */ #define pixel_size 4 -static void project_paint_uvpixel_init(ProjectPaintState *ps, ProjectScanline *sc, ImBuf *ibuf, float *uv, int x, int y, int face_index, float *pixelScreenCo) +static void project_paint_uvpixel_init(ProjectPaintState *ps, ImBuf *ibuf, float *uv, int x, int y, int face_index, float *pixelScreenCo) { int bucket_index; + // printf("adding px (%d %d), (%f %f)\n", x,y,uv[0],uv[1]); + ProjectPixel *projPixel; bucket_index = project_paint_BucketOffset(ps, pixelScreenCo); @@ -940,10 +961,12 @@ int i, j; /* scanlines since quads can have 2 triangles intersecting the same vertical location */ +#ifndef PROJ_DEBUG_NOSCANLINE ProjectScanline scanlines[2]; ProjectScanline *sc; int totscanlines; /* can only be 1 or 2, oh well */ - +#endif + 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; @@ -951,15 +974,16 @@ if (ps->projectSeamBleed > 0.0) project_face_seams_init(ps, face_index, mf->v4); - for (y = min_px[1]-2; y < max_px[1]+2; y++) { + 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 */ - + +#ifndef PROJ_DEBUG_NOSCANLINE totscanlines = project_face_scanline(scanlines, uv[1], tf->uv[0], tf->uv[1], tf->uv[2], mf->v4 ? tf->uv[3]:NULL); /* Loop over scanlines a bit silly since there can only be 1 or 2, but its easier then having tri/quad spesific functions */ for (j=0, sc=scanlines; j<totscanlines; j++, sc++) { - min_px[0] = (int)((ibuf->x * sc->x_limits[0])+0.5); + min_px[0] = (int)((ibuf->x * sc->x_limits[0])-0.5); max_px[0] = (int)((ibuf->x * sc->x_limits[1])+0.5); CLAMP(min_px[0], 0, ibuf->x); CLAMP(max_px[0], 0, ibuf->x); @@ -976,26 +1000,8 @@ for (x = min_px[0]; x < max_px[0]; x++) { uv[0] = (((float)x)+0.5) / (float)ibuf->x; screen_px_from_ortho(ps, uv, v1co,v2co,v3co, uv1co,uv2co,uv3co, pixelScreenCo); - project_paint_uvpixel_init(ps, sc, ibuf, uv, x,y,face_index, pixelScreenCo); + project_paint_uvpixel_init(ps, ibuf, uv, x,y,face_index, pixelScreenCo); } - - /* interpolation is faster - no workies :( */ - /* - x = min_px[0]; - uv[0] = (((float)x)+0.5) / (float)ibuf->x; - screen_px_from_ortho(ps, uv, v1co,v2co,v3co, uv1co,uv2co,uv3co, pixelScreenCoXMin); - - x = max_px[0]-1; - uv[0] = (((float)x)+0.5) / (float)ibuf->x; - screen_px_from_ortho(ps, uv, v1co,v2co,v3co, uv1co,uv2co,uv3co, pixelScreenCoXMax); - - for (x = min_px[0]; x < max_px[0]; x++) { - uv[0] = (((float)x)+0.5) / (float)ibuf->x; - VecLerpf(pixelScreenCo, pixelScreenCoXMin, pixelScreenCoXMax, ((float)x) / ((float)(max_px[0]-min_px[0])) ); - project_paint_uvpixel_init(ps, sc, ibuf, uv, x,y, face_index, pixelScreenCo); - } - */ - } else { v1co = ps->dm_mvert[ (*(&mf->v1 + sc->v[0])) ].co; v2co = ps->dm_mvert[ (*(&mf->v1 + sc->v[1])) ].co; @@ -1004,31 +1010,49 @@ for (x = min_px[0]; x < max_px[0]; x++) { uv[0] = (((float)x)+0.5) / (float)ibuf->x; screen_px_from_persp(ps, uv, v1co,v2co,v3co, uv1co,uv2co,uv3co, pixelScreenCo); - project_paint_uvpixel_init(ps, sc, ibuf, uv, x,y,face_index, pixelScreenCo); + project_paint_uvpixel_init(ps, ibuf, uv, x,y,face_index, pixelScreenCo); } - - - /* interpolation is faster */ - /* - x = min_px[0]; + } + } +#else /* slow, non scanline method */ + + /* mainly for debuggung scanline, use point-in-tri for every x/y test */ + /* at the moment only works with ortho triangles */ + uv1co = tf->uv[0]; + uv2co = tf->uv[1]; + uv3co = tf->uv[2]; + + if (ps->projectIsOrtho) { + v1co = ps->projectVertScreenCos[ mf->v1 ]; + v2co = ps->projectVertScreenCos[ mf->v2 ]; + v3co = ps->projectVertScreenCos[ mf->v3 ]; + + for (x = min_px[0]; x < max_px[0]; x++) { uv[0] = (((float)x)+0.5) / (float)ibuf->x; - screen_px_from_persp(ps, uv, v1co,v2co,v3co, uv1co,uv2co,uv3co, pixelScreenCoXMin); - - x = max_px[0]-1; - uv[0] = (((float)x)+0.5) / (float)ibuf->x; - screen_px_from_persp(ps, uv, v1co,v2co,v3co, uv1co,uv2co,uv3co, pixelScreenCoXMax); - - for (x = min_px[0]; x < max_px[0]; x++) { - uv[0] = (((float)x)+0.5) / (float)ibuf->x; - VecLerpf(pixelScreenCo, pixelScreenCoXMin, pixelScreenCoXMax, ((float)x) / ((float)(max_px[0]-min_px[0])) ); - project_paint_uvpixel_init(ps, sc, ibuf, uv, x,y, face_index, pixelScreenCo); + if (IsectPT2Df(uv, uv1co, uv2co, uv3co)) { + screen_px_from_ortho(ps, uv, v1co,v2co,v3co, uv1co,uv2co,uv3co, pixelScreenCo); + project_paint_uvpixel_init(ps, ibuf, uv, x,y,face_index, pixelScreenCo); } - */ + } + } else { + /* + v1co = ps->dm_mvert[ (*(&mf->v1 + sc->v[0])) ].co; + v2co = ps->dm_mvert[ (*(&mf->v1 + sc->v[1])) ].co; + v3co = ps->dm_mvert[ (*(&mf->v1 + sc->v[2])) ].co; @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org http://lists.blender.org/mailman/listinfo/bf-blender-cvs