[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [17329] branches/projection-paint/source/ blender/src/imagepaint.c: fix for pixels not being drawn in 2 cases.

Campbell Barton ideasman42 at gmail.com
Wed Nov 5 04:13:00 CET 2008


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. @@




More information about the Bf-blender-cvs mailing list