[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [17473] branches/projection-paint/source/ blender/src/imagepaint.c: * fix "dot drawing" problem - draw lines inbetween updates when redrawing the view like how existing painting works .

Campbell Barton ideasman42 at gmail.com
Sun Nov 16 16:26:15 CET 2008


Revision: 17473
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=17473
Author:   campbellbarton
Date:     2008-11-16 16:26:15 +0100 (Sun, 16 Nov 2008)

Log Message:
-----------
* fix "dot drawing" problem - draw lines inbetween updates when redrawing the view like how existing painting works. (this means slow systems wont have the problems when they would only see dots as they dragged their mouse around)
* bucket resolution is now set from the brush size so there is around 9 buckets under the brush - (previously was fixed to 128x128).
* brush sizes below 40 disable multithreading, since threads only speeds up cases where each bucket has enough pixels in it for each core to spend some time.
* make smear use bicubic pixel lookups so a low Spacing value works as expected.
* smear tool was darkening pixels a tiny bit.
* fix for simple mistake causing ProjectPaintImage arrays not to be thread safe.

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-16 11:13:19 UTC (rev 17472)
+++ branches/projection-paint/source/blender/src/imagepaint.c	2008-11-16 15:26:15 UTC (rev 17473)
@@ -140,7 +140,19 @@
 } ImagePaintPartialRedraw;
 
 /* testing options */
-#define PROJ_BUCKET_DIV 128 /* TODO - test other values, this is a guess, seems ok */
+
+/* approx the number of buckets to have under the brush,
+ * used with the brush size to set the ps->buckets_x and ps->buckets_y value.
+ * 
+ * When 3 - a brush should have ~9 buckets under it at once
+ * ...this helps for threading while painting as well as
+ * avoiding initializing pixels that wont touch the brush */
+#define PROJ_BUCKET_BRUSH_DIV 3
+
+#define PROJ_BUCKET_RECT_MIN 4
+#define PROJ_BUCKET_RECT_MAX 256
+
+
 #define PROJ_BOUNDBOX_DIV 6 /* TODO - test other values, this is a guess, seems ok */
 #define PROJ_BOUNDBOX_SQUARED  (PROJ_BOUNDBOX_DIV * PROJ_BOUNDBOX_DIV)
 
@@ -741,8 +753,8 @@
 		if (x < 0.0) x += 1.0;
 		if (y < 0.0) y += 1.0;
 		
-		x *= ibuf->x;
-		y *= ibuf->y;
+		x = x * ibuf->x - 0.5;
+		y = y * ibuf->y - 0.5;
 		
 		if (ibuf->rect_float) {
 			if (rgba_fp) {
@@ -762,8 +774,8 @@
 			}
 		}
 	} else {
-		xi = uv[0]*ibuf->x;
-		yi = uv[1]*ibuf->y;
+		xi = (uv[0]*ibuf->x) + 0.5;
+		yi = (uv[1]*ibuf->y) + 0.5;
 		
 		//if (xi<0 || xi>=ibuf->x  ||  yi<0 || yi>=ibuf->y) return 0;
 		
@@ -2134,15 +2146,89 @@
 	ps->dm_totvert = ps->dm->getNumVerts( ps->dm );
 	ps->dm_totface = ps->dm->getNumFaces( ps->dm );
 	
-	ps->buckets_x = G.rt ? G.rt : PROJ_BUCKET_DIV;
-	ps->buckets_y = G.rt ? G.rt : PROJ_BUCKET_DIV;
-	
 	ps->viewDir[0] = 0.0;
 	ps->viewDir[1] = 0.0;
 	ps->viewDir[2] = 1.0;
 	
 	view3d_get_object_project_mat(curarea, ps->ob, ps->projectMat, ps->viewMat);
 	
+	
+	/* calculate vert screen coords
+	 * run this early so we can calculate the x/y resolution of our bucket rect */
+	
+	/* since we now run this before the memarena is allocated, this will need its own memory */
+	/*ps->screenCoords = BLI_memarena_alloc( ps->arena, sizeof(float) * ps->dm_totvert * 4);*/
+	
+	ps->screenCoords = MEM_mallocN(sizeof(float) * ps->dm_totvert * 4, "ProjectPaint ScreenVerts");
+	projScreenCo = ps->screenCoords;
+	
+	/* TODO - check cameras mode too */
+	if (G.vd->persp == V3D_ORTHO) {
+		ps->is_ortho = 1;
+	}
+	
+	INIT_MINMAX2(ps->screen_min, ps->screen_max);
+
+	if (ps->is_ortho) {
+		for(a=0; a < ps->dm_totvert; a++, projScreenCo++) {
+			VECCOPY((*projScreenCo), ps->dm_mvert[a].co);
+			Mat4MulVecfl(ps->projectMat, (*projScreenCo));
+
+			/* screen space, not clamped */
+			(*projScreenCo)[0] = (float)(curarea->winx/2.0)+(curarea->winx/2.0)*(*projScreenCo)[0];
+			(*projScreenCo)[1] = (float)(curarea->winy/2.0)+(curarea->winy/2.0)*(*projScreenCo)[1];
+			DO_MINMAX2((*projScreenCo), ps->screen_min, ps->screen_max);
+		}
+	} else {
+		for(a=0; a < ps->dm_totvert; a++, projScreenCo++) {
+			VECCOPY((*projScreenCo), ps->dm_mvert[a].co);
+			(*projScreenCo)[3] = 1.0;
+
+			Mat4MulVec4fl(ps->projectMat, (*projScreenCo));
+
+			if( (*projScreenCo)[3] > 0.001 ) {
+				/* screen space, not clamped */
+				(*projScreenCo)[0] = (float)(curarea->winx/2.0)+(curarea->winx/2.0)*(*projScreenCo)[0]/(*projScreenCo)[3];
+				(*projScreenCo)[1] = (float)(curarea->winy/2.0)+(curarea->winy/2.0)*(*projScreenCo)[1]/(*projScreenCo)[3];
+				(*projScreenCo)[2] = (*projScreenCo)[2]/(*projScreenCo)[3]; /* Use the depth for bucket point occlusion */
+				DO_MINMAX2((*projScreenCo), ps->screen_min, ps->screen_max);
+			} else {
+				/* TODO - deal with cases where 1 side of a face goes behind the view ? */
+				(*projScreenCo)[0] = MAXFLOAT;
+			}
+		}
+	}
+	
+	/* If this border is not added we get artifacts for faces that
+	 * have a parallel edge and at the bounds of the the 2D projected verts eg
+	 * - a single screen aligned quad */
+	projMargin = (ps->screen_max[0] - ps->screen_min[0]) * 0.000001;
+	ps->screen_max[0] += projMargin;
+	ps->screen_min[0] -= projMargin;
+	projMargin = (ps->screen_max[1] - ps->screen_min[1]) * 0.000001;
+	ps->screen_max[1] += projMargin;
+	ps->screen_min[1] -= projMargin;
+	
+	
+	/* only for convenience */
+	ps->screen_width  = ps->screen_max[0] - ps->screen_min[0];
+	ps->screen_height = ps->screen_max[1] - ps->screen_min[1];
+	
+	/* done with screen coords */
+	
+	//ps->buckets_x = G.rt ? G.rt : PROJ_BUCKET_BRUSH_DIV;
+	//ps->buckets_y = G.rt ? G.rt : PROJ_BUCKET_BRUSH_DIV;
+
+	ps->buckets_x = (int)(ps->screen_width / (((float)ps->brush->size) / PROJ_BUCKET_BRUSH_DIV));
+	ps->buckets_y = (int)(ps->screen_height / (((float)ps->brush->size) / PROJ_BUCKET_BRUSH_DIV));
+	
+	printf("\tscreenspace bucket division x:%d y:%d\n", ps->buckets_x, ps->buckets_y);
+	
+	/* really high values could cause problems since it has to allocate a few
+	 * (ps->buckets_x*ps->buckets_y) sized arrays  */
+	CLAMP(ps->buckets_x, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
+	CLAMP(ps->buckets_y, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
+	
 	tot_bucketMem =				sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y;
 	tot_faceListMem =			sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y;
 	
@@ -2190,13 +2276,21 @@
 	// calloced - }
 #endif
 	
-	/* Thread stuff */
-	if (G.scene->r.mode & R_FIXED_THREADS) {
-		ps->thread_tot = G.scene->r.threads;
+	/* Thread stuff
+	 * 
+	 * very small brushes run a lot slower multithreaded since the advantage with
+	 * threads is being able to fill in multiple buckets at once.
+	 * Only use threads for bigger brushes. */
+	
+	if (ps->brush->size < 40) {
+		ps->thread_tot = 1;
 	} else {
-		ps->thread_tot = BLI_system_thread_count();
+		if (G.scene->r.mode & R_FIXED_THREADS) {
+			ps->thread_tot = G.scene->r.threads;
+		} else {
+			ps->thread_tot = BLI_system_thread_count();
+		}
 	}
-	
 	for (a=0; a<ps->thread_tot; a++) {
 		ps->arena_mt[a] = BLI_memarena_new(1<<16);
 	}
@@ -2207,48 +2301,7 @@
 	Mat3MulVecfl(mat, ps->viewDir);
 	Mat3CpyMat4(mat, ps->ob->imat);
 	Mat3MulVecfl(mat, ps->viewDir);
-	
-	/* calculate vert screen coords */
-	ps->screenCoords = BLI_memarena_alloc( ps->arena, sizeof(float) * ps->dm_totvert * 4);
-	projScreenCo = ps->screenCoords;
-	
-	/* TODO - check cameras mode too */
-	if (G.vd->persp == V3D_ORTHO) {
-		ps->is_ortho = 1;
-	}
-	
-	INIT_MINMAX2(ps->screen_min, ps->screen_max);
 
-	if (ps->is_ortho) {
-		for(a=0; a < ps->dm_totvert; a++, projScreenCo++) {
-			VECCOPY((*projScreenCo), ps->dm_mvert[a].co);
-			Mat4MulVecfl(ps->projectMat, (*projScreenCo));
-
-			/* screen space, not clamped */
-			(*projScreenCo)[0] = (float)(curarea->winx/2.0)+(curarea->winx/2.0)*(*projScreenCo)[0];
-			(*projScreenCo)[1] = (float)(curarea->winy/2.0)+(curarea->winy/2.0)*(*projScreenCo)[1];
-			DO_MINMAX2((*projScreenCo), ps->screen_min, ps->screen_max);
-		}
-	} else {
-		for(a=0; a < ps->dm_totvert; a++, projScreenCo++) {
-			VECCOPY((*projScreenCo), ps->dm_mvert[a].co);
-			(*projScreenCo)[3] = 1.0;
-
-			Mat4MulVec4fl(ps->projectMat, (*projScreenCo));
-
-			if( (*projScreenCo)[3] > 0.001 ) {
-				/* screen space, not clamped */
-				(*projScreenCo)[0] = (float)(curarea->winx/2.0)+(curarea->winx/2.0)*(*projScreenCo)[0]/(*projScreenCo)[3];
-				(*projScreenCo)[1] = (float)(curarea->winy/2.0)+(curarea->winy/2.0)*(*projScreenCo)[1]/(*projScreenCo)[3];
-				(*projScreenCo)[2] = (*projScreenCo)[2]/(*projScreenCo)[3]; /* Use the depth for bucket point occlusion */
-				DO_MINMAX2((*projScreenCo), ps->screen_min, ps->screen_max);
-			} else {
-				/* TODO - deal with cases where 1 side of a face goes behind the view ? */
-				(*projScreenCo)[0] = MAXFLOAT;
-			}
-		}
-	}
-
 	/* setup clone offset */
 	if (ps->tool == PAINT_TOOL_CLONE) {
 		float projCo[4];
@@ -2265,21 +2318,6 @@
 		
 	}
 	
-	/* If this border is not added we get artifacts for faces that
-	 * have a paralelle edge and at the bounds of the the 2D projected verts eg
-	 * - a simgle screen aligned quad */
-	projMargin = (ps->screen_max[0] - ps->screen_min[0]) * 0.000001;
-	ps->screen_max[0] += projMargin;
-	ps->screen_min[0] -= projMargin;
-	projMargin = (ps->screen_max[1] - ps->screen_min[1]) * 0.000001;
-	ps->screen_max[1] += projMargin;
-	ps->screen_min[1] -= projMargin;
-	
-	
-	/* only for convenience */
-	ps->screen_width  = ps->screen_max[0] - ps->screen_min[0];
-	ps->screen_height = ps->screen_max[1] - ps->screen_min[1];
-	
 	if (!ps->is_ortho) {
 		/* get the view direction relative to the objects matrix */
 		float imat[3][3];
@@ -2448,6 +2486,7 @@
 	}
 	/* done calculating undo data */
 	
+	MEM_freeN(ps->screenCoords);
 	
 	BLI_memarena_free(ps->arena);
 	
@@ -3004,16 +3043,21 @@
 	return redraw;
 }
 
+/* run this per painting onto each mouse location */
 static int bucket_iter_init(ProjectPaintState *ps, float mval_f[2])
 {
 	float min_brush[2], max_brush[2];
+	float size_half = ((float)ps->brush->size)/2.0;
 	
-	min_brush[0] = mval_f[0] - (ps->brush->size/2);
-	min_brush[1] = mval_f[1] - (ps->brush->size/2);
+	/* so we dont have a bucket bounds that is way too small to paint into */
+	// if (size_half < 1.0) size_half = 1.0; // this dosnt work yet :/
 	
-	max_brush[0] = mval_f[0] + (ps->brush->size/2);
-	max_brush[1] = mval_f[1] + (ps->brush->size/2);
+	min_brush[0] = mval_f[0] - size_half;
+	min_brush[1] = mval_f[1] - size_half;
 	
+	max_brush[0] = mval_f[0] + size_half;
+	max_brush[1] = mval_f[1] + size_half;
+	
 	/* offset to make this a valid bucket index */
 	project_paint_rect(ps, min_brush, max_brush, ps->bucket_min, ps->bucket_max);
 	
@@ -3030,7 +3074,7 @@
 	return 1;
 }
 
-static int bucket_iter_next(ProjectPaintState *ps, int *bucket_index, float bucket_bounds[4], float mval_f[2])
+static int bucket_iter_next(ProjectPaintState *ps, int *bucket_index, float bucket_bounds[4], float mval[2])
 {
 	if (ps->thread_tot > 1)
 		BLI_lock_thread(LOCK_CUSTOM1);
@@ -3043,7 +3087,7 @@
 			/* use bucket_bounds for project_bucket_circle_isect and project_paint_bucket_init*/
 			project_bucket_bounds(ps, ps->context_bucket_x, ps->context_bucket_y, bucket_bounds);
 			
-			if (project_bucket_circle_isect(ps, ps->context_bucket_x, ps->context_bucket_y, mval_f, ps->brush->size * ps->brush->size, bucket_bounds)) {
+			if (project_bucket_circle_isect(ps, ps->context_bucket_x, ps->context_bucket_y, mval, ps->brush->size * ps->brush->size, bucket_bounds)) {
 				*bucket_index = ps->context_bucket_x + (ps->context_bucket_y * ps->buckets_x);

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list