[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [17334] branches/projection-paint/source/ blender/src/imagepaint.c: projection painting clone tool - gives a similar work flow to cloning in the gimp , Ctrl+Click to set the cursor source, then paint from this location.

Campbell Barton ideasman42 at gmail.com
Wed Nov 5 15:45:54 CET 2008


Revision: 17334
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=17334
Author:   campbellbarton
Date:     2008-11-05 15:45:54 +0100 (Wed, 05 Nov 2008)

Log Message:
-----------
projection painting clone tool - gives a similar work flow to cloning in the gimp, Ctrl+Click to set the cursor source, then paint from this location.

todo...
* pixel interpolation.
* clone option can currently only be set from the image paint panel.
* only initialize clone pixels under the mouse.
* overlap between source/target while painting could cause problems. need to look into this.

also fixed some cashes in painting normally.

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-05 13:22:10 UTC (rev 17333)
+++ branches/projection-paint/source/blender/src/imagepaint.c	2008-11-05 14:45:54 UTC (rev 17334)
@@ -145,8 +145,9 @@
 #define PROJ_FACE_SEAM4	1<<5
 
 
-#define PROJ_BUCKET_NULL	0
-#define PROJ_BUCKET_INIT	1
+#define PROJ_BUCKET_NULL		0
+#define PROJ_BUCKET_INIT		1<<0
+// #define PROJ_BUCKET_CLONE_INIT	1<<1
 
 /* only for readability */
 #define PROJ_BUCKET_LEFT		0
@@ -217,8 +218,10 @@
 } ProjectPixel;
 
 typedef struct ProjectPixelClone {
-	struct ProjectPixel;
-	void *source;
+	struct ProjectPixel __pp;
+	char backbuf[4];	/* TODO - float buffer? */
+	char clonebuf[4];
+	//void *source;		/* pointer to source pixels */
 } ProjectPixelClone;
 
 /* Finish projection painting structs */
@@ -396,15 +399,144 @@
 		(	(	(int)(( (projCo2D[1] - ps->viewMin2D[1])  / ps->viewHeight) * ps->bucketsY)) * ps->bucketsX );
 }
 
+static int project_paint_BucketOffsetSafe(ProjectPaintState *ps, float *projCo2D)
+{
+	int bucket_index = project_paint_BucketOffset(ps, projCo2D);
+	
+	if (bucket_index < 0 || bucket_index >= ps->bucketsX*ps->bucketsY) {	
+		return -1;
+	} else {
+		return bucket_index;
+	}
+}
+
+/* assume they intersect */
+static void BarryCentricWeights2f(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;
+}
+
+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);
+	return (v1[2]*w[0]) + (v2[2]*w[1]) + (v3[2]*w[2]);
+}
+
+
+/* return the topmost face  in screen coords index or -1
+ * bucket_index can be -1 if we dont know it to begin with */
+static int screenco_pickface(ProjectPaintState *ps, float pt[2], float w[3], int *side) {
+	LinkNode *node;
+	float w_tmp[3];
+	float *v1, *v2, *v3, *v4;
+	int bucket_index;
+	int face_index;
+	int best_side = -1;
+	int best_face_index = -1;
+	float z_depth_best = MAXFLOAT, z_depth;
+	MFace *mf;
+	
+	bucket_index = project_paint_BucketOffsetSafe(ps, pt);
+	if (bucket_index==-1)
+		return -1;
+	
+	node = ps->projectFaces[bucket_index];
+	
+	/* we could return 0 for 1 face buckets, as long as this function assumes
+	 * that the point its testing is only every originated from an existing face */
+	
+	while (node) {
+		face_index = (int)node->link;
+		mf = ps->dm_mface + face_index;
+		
+		v1 = ps->projectVertScreenCos[mf->v1];
+		v2 = ps->projectVertScreenCos[mf->v2];
+		v3 = ps->projectVertScreenCos[mf->v3];
+		
+		if ( IsectPT2Df(pt, v1, v2, v3) ) {
+			z_depth = tri_depth_2d(v1,v2,v3,pt,w_tmp);
+			if (z_depth < z_depth_best) {
+				best_face_index = face_index;
+				best_side = 0;
+				z_depth_best = z_depth;
+				VECCOPY(w, w_tmp);
+			}
+		} else if (mf->v4) {
+			v4 = ps->projectVertScreenCos[mf->v4];
+			
+			if ( IsectPT2Df(pt, v1, v3, v4) ) {
+				z_depth = tri_depth_2d(v1,v3,v4,pt,w_tmp);
+				if (z_depth < z_depth_best) {
+					best_face_index = face_index;
+					best_side = 1;
+					z_depth_best = z_depth;
+					VECCOPY(w, w_tmp);
+				}
+			}
+		}
+		
+		node = node->next;
+	}
+	
+	*side = best_side;
+	return best_face_index; /* will be -1 or a valid face */
+}
+
+/* bucket_index is optional, since in some cases we know it */
+static int screenco_pickcol(ProjectPaintState *ps, int bucket_index, float pt[2], char rgba[4])
+{
+	float w[3], uv[2];
+	int side;
+	int face_index;
+	MTFace *tf;
+	ImBuf *ibuf;
+	int x,y;
+	char *pixel;
+	
+	face_index = screenco_pickface(ps,pt,w, &side);
+	
+	if (face_index == -1)
+		return 0;
+	
+	tf = ps->dm_mtface + face_index;
+	
+	if (side==0) {
+		uv[0] = tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[2][0]*w[2];
+		uv[1] = tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[2][1]*w[2];
+	} else { /* QUAD */
+		uv[0] = tf->uv[0][0]*w[0] + tf->uv[2][0]*w[1] + tf->uv[3][0]*w[2];
+		uv[1] = tf->uv[0][1]*w[0] + tf->uv[2][1]*w[1] + tf->uv[3][1]*w[2];
+	}
+	
+	ibuf = BKE_image_get_ibuf((Image *)tf->tpage, NULL); /* TODO - this may be slow */
+	
+	x = uv[0]*ibuf->x;
+	y = uv[1]*ibuf->y;
+	
+	if (x<0 || x>=ibuf->x  ||  y<0 || y>=ibuf->y) return 0;
+	
+	pixel = (( char * ) ibuf->rect) + (( x + y * ibuf->x ) * 4);
+	
+	rgba[0] = pixel[0];
+	rgba[1] = pixel[1];
+	rgba[2] = pixel[2];
+	rgba[3] = pixel[3];
+	return 1;
+}
+
 /* return...
  * 0	: no occlusion
  * -1	: no occlusion but 2D intersection is true (avoid testing the other half of a quad)
  * 1	: occluded */
 
-static int screenco_tri_pt_occlude(float *pt, float *v1, float *v2, float *v3)
+static int screenco_tri_pt_occlude(float pt[3], float v1[3], float v2[3], float v3[3])
 {
-	float w1, w2, w3, wtot; /* weights for converting the pixel into 3d worldspace coords */
-	
 	/* if all are behind us, return false */
 	if(v1[2] > pt[2] && v2[2] > pt[2] && v3[2] > pt[2])
 		return 0;
@@ -419,13 +551,9 @@
 	if(	v1[2] < pt[2] && v2[2] < pt[2] && v3[2] < pt[2]) {
 		return 1;
 	} else {
+		float w[3];
 		/* we intersect? - find the exact depth at the point of intersection */
-		w1 = AreaF2Dfl(v2, v3, pt);
-		w2 = AreaF2Dfl(v3, v1, pt);
-		w3 = AreaF2Dfl(v1, v2, pt);
-		wtot = w1 + w2 + w3;
-		
-		if ((v1[2]*w1/wtot) + (v2[2]*w2/wtot) + (v3[2]*w3/wtot) < pt[2]) {
+		if (tri_depth_2d(v1,v2,v3,pt,w) < pt[2]) {
 			return 1; /* This point is occluded by another face */
 		}
 	}
@@ -497,7 +625,7 @@
 #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)
+static int project_scanline_isect(float p1[2], float p2[2], float y_level, float *x_isect)
 {
 	if (y_level==p1[1]) {
 		*x_isect = p1[0];
@@ -519,7 +647,7 @@
 	}
 }
 
-static int project_face_scanline(ProjectScanline *sc, float y_level, float *v1, float *v2, float *v3, float *v4)
+static int project_face_scanline(ProjectScanline *sc, float y_level, float v1[2], float v2[2], float v3[2], float v4[2])
 {	
 	/* Create a scanlines for the face at this Y level 
 	 * triangles will only ever have 1 scanline, quads may have 2 */
@@ -614,7 +742,7 @@
 	return totscanlines;
 }
 
-static int cmp_uv(float *vec2a, float *vec2b)
+static int cmp_uv(float vec2a[2], float vec2b[2])
 {
 	return ((fabs(vec2a[0]-vec2b[0]) < 0.0001) && (fabs(vec2a[1]-vec2b[1]) < 0.0001)) ? 1:0;
 }
@@ -712,7 +840,7 @@
 }
 
 /* return zero if there is no area in the returned rectangle */
-static int uv_image_rect(float *uv1, float *uv2, float *uv3, float *uv4, int *min_px, int *max_px, int x_px, int y_px, int is_quad)
+static int uv_image_rect(float uv1[2], float uv2[2], float uv3[2], float uv4[2], int min_px[2], int max_px[2], int x_px, int y_px, int is_quad)
 {
 	float min_uv[2], max_uv[2]; /* UV bounds */
 	int i;
@@ -862,41 +990,29 @@
 }
 
 static screen_px_from_ortho(
-		ProjectPaintState *ps, float *uv,
-		float *v1co, float *v2co, float *v3co, /* Screenspace coords */
-		float *uv1co, float *uv2co, float *uv3co,
-		float *pixelScreenCo )
+		ProjectPaintState *ps, float uv[2],
+		float v1co[3], float v2co[3], float v3co[3], /* Screenspace coords */
+		float uv1co[2], float uv2co[2], float uv3co[2],
+		float pixelScreenCo[4] )
 {
-	float w1, w2, w3, wtot; /* weights for converting the pixel into 3d screenspace coords */
-	w1 = AreaF2Dfl(uv2co, uv3co, uv);
-	w2 = AreaF2Dfl(uv3co, uv1co, uv);
-	w3 = AreaF2Dfl(uv1co, uv2co, uv);
-	
-	wtot = w1 + w2 + w3;
-	w1 /= wtot; w2 /= wtot; w3 /= wtot;
-	
-	pixelScreenCo[0] = v1co[0]*w1 + v2co[0]*w2 + v3co[0]*w3;
-	pixelScreenCo[1] = v1co[1]*w1 + v2co[1]*w2 + v3co[1]*w3;
-	pixelScreenCo[2] = v1co[2]*w1 + v2co[2]*w2 + v3co[2]*w3;	
+	float w[3];
+	BarryCentricWeights2f(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];	
 }
 
 static screen_px_from_persp(
-		ProjectPaintState *ps, float *uv,
-		float *v1co, float *v2co, float *v3co, /* Worldspace coords */
-		float *uv1co, float *uv2co, float *uv3co,
-		float *pixelScreenCo )
+		ProjectPaintState *ps, float uv[2],
+		float v1co[3], float v2co[3], float v3co[3], /* Worldspace coords */
+		float uv1co[2], float uv2co[2], float uv3co[2],
+		float pixelScreenCo[4])
 {
-	float w1, w2, w3, wtot; /* weights for converting the pixel into 3d screenspace coords */
-	w1 = AreaF2Dfl(uv2co, uv3co, uv);
-	w2 = AreaF2Dfl(uv3co, uv1co, uv);
-	w3 = AreaF2Dfl(uv1co, uv2co, uv);
-	
-	wtot = w1 + w2 + w3;
-	w1 /= wtot; w2 /= wtot; w3 /= wtot;
-	
-	pixelScreenCo[0] = v1co[0]*w1 + v2co[0]*w2 + v3co[0]*w3;
-	pixelScreenCo[1] = v1co[1]*w1 + v2co[1]*w2 + v3co[1]*w3;
-	pixelScreenCo[2] = v1co[2]*w1 + v2co[2]*w2 + v3co[2]*w3;	
+	float w[3];
+	BarryCentricWeights2f(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];
 	pixelScreenCo[3] = 1.0;
 	
 	Mat4MulVec4fl(ps->projectMat, pixelScreenCo);
@@ -908,10 +1024,13 @@
 	pixelScreenCo[2] = pixelScreenCo[2]/pixelScreenCo[3]; /* Use the depth for bucket point occlusion */
 }
 
-/* can provide own own coords, use for seams when we want to bleed our from the original location */
 
+static void project_paint_bucket_init(ProjectPaintState *ps, int bucket_index);
+
+/* Only run this function once for new ProjectPixelClone's */
 #define pixel_size 4
-static void project_paint_uvpixel_init(ProjectPaintState *ps, 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[2], int x, int y, int face_index, float pixelScreenCo[4])
 {
 	int bucket_index;
 	
@@ -919,10 +1038,10 @@
 	
 	ProjectPixel *projPixel;
 	
-	bucket_index = project_paint_BucketOffset(ps, pixelScreenCo);
+	bucket_index = project_paint_BucketOffsetSafe(ps, pixelScreenCo);
 	
 	/* even though it should be clamped, in some cases it can still run over */
-	if (bucket_index < 0 || bucket_index >= ps->bucketsX * ps->bucketsY)
+	if (bucket_index==-1)
 		return;
 	
 	/* Use viewMin2D to make (0,0) the bottom left of the bounds 
@@ -931,13 +1050,39 @@
 	/* Is this UV visible from the view? - raytrace */

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list