[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [17496] branches/projection-paint/source/ blender/src/imagepaint.c: Some improvements brecht suggested, only noticable change is faster multithreading

Campbell Barton ideasman42 at gmail.com
Tue Nov 18 14:51:51 CET 2008


Revision: 17496
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=17496
Author:   campbellbarton
Date:     2008-11-18 14:51:51 +0100 (Tue, 18 Nov 2008)

Log Message:
-----------
Some improvements brecht suggested, only noticable change is faster multithreading

General optimizations
* Precompute 1/x when dividing by x multiple times.
* Use float constants like 0.0f instead of 0.0, avoids conversions from float to doubles and back.

ProjectPixel
* make pixel (and similar pointers elsewhere) a union with a float and unsigned int pointer to reduce the number of casts a little. generally there are a lot of casts going on in the code, makes it hard to read.

project_paint_begin()
* the perspective case checks with (*projScreenCo)[3] > 0.001) for faces behind the view. - Changed to use the clip start from get_view3d_viewplane 
* removed arbitrary check for brush size to disable threads.

imapaint_paint_sub_stroke_project()
* Make clone tool use IMB_blend_color to reduce the code and support blend modes.

imapaint_paint_sub_stroke_project_mt()
* Make threaded and non threaded mode use same function (just dont start threads when its set to 1)
* removed PIL_sleep_ms, was not needed and slowed down threading (my bad!, was copied from bake code).

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-18 13:51:02 UTC (rev 17495)
+++ branches/projection-paint/source/blender/src/imagepaint.c	2008-11-18 13:51:51 UTC (rev 17496)
@@ -148,7 +148,7 @@
  * 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_BRUSH_DIV 4
 
 #define PROJ_BUCKET_RECT_MIN 4
 #define PROJ_BUCKET_RECT_MAX 256
@@ -187,16 +187,16 @@
 /* This is mainly a convenience struct used so we can keep an array of images we use
  * Thir imbufs, etc, in 1 array, When using threads this array is copied for each thread
  * because 'partRedrawRect' and 'touch' values would not be thread safe */
-typedef struct ProjectPaintImage {
+typedef struct ProjPaintImage {
 	Image *ima;
 	ImBuf *ibuf;
 	ImagePaintPartialRedraw *partRedrawRect;
 	struct UndoTile **undoRect; /* only used to build undo tiles after painting */
 	int touch;
-} ProjectPaintImage;
+} ProjPaintImage;
 
 /* Main projection painting struct passed to all projection painting functions */
-typedef struct ProjectPaintState {
+typedef struct ProjPaintState {
 	Brush *brush;
 	short tool, blend;
 	Object *ob;
@@ -214,7 +214,7 @@
 	/* projection painting only */
 	MemArena *arena;			/* use for alocating many pixel structs and link-lists */
 	MemArena *arena_mt[BLENDER_MAX_THREADS];		/* Same as above but use for multithreading */
-	LinkNode **bucketRect;				/* screen sized 2D array, each pixel has a linked list of ProjectPixel's */
+	LinkNode **bucketRect;				/* screen sized 2D array, each pixel has a linked list of ProjPixel's */
 	LinkNode **bucketFaces;				/* bucketRect alligned array linkList of faces overlapping each bucket */
 	char *bucketFlags;					/* store if the bucks have been initialized  */
 #ifndef PROJ_DEBUG_NOSEAMBLEED
@@ -225,7 +225,7 @@
 	int buckets_x;						/* The size of the bucket grid, the grid span's screen_min/screen_max so you can paint outsize the screen or with 2 brushes at once */
 	int buckets_y;
 	
-	ProjectPaintImage *projImages;
+	ProjPaintImage *projImages;
 	
 	int image_tot;				/* size of projectImages array */
 	
@@ -256,26 +256,41 @@
 	int bucket_min[2];
 	int bucket_max[2];
 	int context_bucket_x, context_bucket_y; /* must lock threads while accessing these */
-} ProjectPaintState;
+} ProjPaintState;
 
-typedef struct ProjectPixel {
+typedef union pixelPointer
+{
+	float *f_pt;			/* float buffer */
+	unsigned int *uint_pt; /* 2 ways to access a char buffer */
+	char *ch_pt;
+} PixelPointer;
+
+typedef union pixelStore
+{
+	char ch[4];
+	int uint;
+} PixelStore;
+
+typedef struct ProjPixel {
 	float projCo2D[2]; /* the floating point screen projection of this pixel */
-	char origColor[4];
 	short x_px, y_px;
-	void *pixel;
+	
+	PixelStore origColor;
+	PixelPointer pixel;
+	
 	short image_index; /* if anyone wants to paint onto more then 32000 images they can bite me */
 	short bb_cell_index;
-} ProjectPixel;
+} ProjPixel;
 
-typedef struct ProjectPixelClone {
-	struct ProjectPixel __pp;
-	char clonepx[4];
-} ProjectPixelClone;
+typedef struct ProjPixelClone {
+	struct ProjPixel __pp;
+	PixelStore clonepx;
+} ProjPixelClone;
 
-typedef struct ProjectPixelCloneFloat {
-	struct ProjectPixel __pp;
-	float clonepx[4];
-} ProjectPixelCloneFloat;
+typedef struct ProjPixelCloneFloat {
+	struct ProjPixel __pp;
+	float clonepx_f[4];
+} ProjPixelCloneFloat;
 
 /* Finish projection painting structs */
 
@@ -459,7 +474,7 @@
 }
 
 /* fast projection bucket array lookup, use the safe version for bound checking  */
-static int project_paint_BucketOffset(ProjectPaintState *ps, float projCo2D[2])
+static int project_paint_BucketOffset(ProjPaintState *ps, float projCo2D[2])
 {
 	/* If we were not dealing with screenspace 2D coords we could simple do...
 	 * ps->bucketRect[x + (y*ps->buckets_y)] */
@@ -475,7 +490,7 @@
 		(	(	(int)(( (projCo2D[1] - ps->screen_min[1])  / ps->screen_height) * ps->buckets_y)) * ps->buckets_x );
 }
 
-static int project_paint_BucketOffsetSafe(ProjectPaintState *ps, float projCo2D[2])
+static int project_paint_BucketOffsetSafe(ProjPaintState *ps, float projCo2D[2])
 {
 	int bucket_index = project_paint_BucketOffset(ps, projCo2D);
 	
@@ -488,15 +503,16 @@
 
 /* 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;
+	float wtot, wtot_inv;
 	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];
-	if (wtot > 0.0) { /* just incase */
-		w[0]/=wtot;
-		w[1]/=wtot;
-		w[2]/=wtot;
+	if (wtot > 0.0f) { /* just incase */
+		wtot_inv = 1.0f / wtot; 
+		w[0]*=wtot_inv;
+		w[1]*=wtot_inv;
+		w[2]*=wtot_inv;
 	} else {
 		w[0] = w[1] = w[2] = 1.0/3.0; /* dummy values for zero area face */
 	}
@@ -505,30 +521,31 @@
 /* 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);
+	float wtot_inv, wtot = AreaF2Dfl(v1, v2, v3);
 	if (wtot > 0.0) {
+		wtot_inv = 1.0f / wtot;
 		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(v2,v3, pt)>0.0) != (SIDE_OF_LINE(v2,v3, v1)>0.0))	w[0]*= -wtot_inv;
+		else																w[0]*=  wtot_inv;
 
-		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(v3,v1, pt)>0.0) != (SIDE_OF_LINE(v3,v1, v2)>0.0))	w[1]*= -wtot_inv;
+		else																w[1]*=  wtot_inv;
 
-		if ((SIDE_OF_LINE(v1,v2, pt)>0.0) != (SIDE_OF_LINE(v1,v2, v3)>0.0))	w[2]/= -wtot;
-		else																w[2]/=  wtot;
+		if ((SIDE_OF_LINE(v1,v2, pt)>0.0) != (SIDE_OF_LINE(v1,v2, v3)>0.0))	w[2]*= -wtot_inv;
+		else																w[2]*=  wtot_inv;
 	} else {
-		w[0] = w[1] = w[2] = 1.0/3.0; /* dummy values for zero area face */
+		w[0] = w[1] = w[2] = 1.0f/3.0f; /* dummy values for zero area face */
 	}
 }
 
 /* still use 2D X,Y space but this works for verts transformed by a perspective matrix, using their 4th component as a weight */
 
 static void BarycentricWeightsPersp2f(float v1[4], float v2[4], float v3[4], float pt[2], float w[3]) {
-	float persp_tot;
+	float persp_tot, persp_tot_inv;
 	BarycentricWeights2f(v1,v2,v3,pt,w);
 	
 	w[0] /= v1[3];
@@ -536,14 +553,19 @@
 	w[2] /= v3[3];
 	
 	persp_tot = w[0]+w[1]+w[2];
-	
-	w[0] /= persp_tot;
-	w[1] /= persp_tot;
-	w[2] /= persp_tot;
+	if (persp_tot > 0.0f) {
+		persp_tot_inv = 1.0f / persp_tot;
+		w[0] *= persp_tot_inv;
+		w[1] *= persp_tot_inv;
+		w[2] *= persp_tot_inv;
+	} else {
+		w[0] = w[1] = w[2] = 1.0f/3.0f; /* dummy values for zero area face */
+	}
 }
 
-static void BarycentricWeightsSimplePersp2f(float v1[4], float v2[4], float v3[4], float pt[2], float w[3]) {
-	float persp_tot;
+static void BarycentricWeightsSimplePersp2f(float v1[4], float v2[4], float v3[4], float pt[2], float w[3])
+{
+	float persp_tot_inv, persp_tot;
 	BarycentricWeightsSimple2f(v1,v2,v3,pt,w);
 	
 	w[0] /= v1[3];
@@ -551,10 +573,14 @@
 	w[2] /= v3[3];
 	
 	persp_tot = w[0]+w[1]+w[2];
-	
-	w[0] /= persp_tot;
-	w[1] /= persp_tot;
-	w[2] /= persp_tot;
+	if (persp_tot > 0.0f) {
+		persp_tot_inv = 1.0f / persp_tot;
+		w[0] *= persp_tot_inv;
+		w[1] *= persp_tot_inv;
+		w[2] *= persp_tot_inv;
+	} else {
+		w[0] = w[1] = w[2] = 1.0f/3.0f; /* 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])
@@ -565,7 +591,7 @@
 
 
 /* Return the top-most face index that the screen space coord 'pt' touches (or -1) */
-static int project_paint_PickFace(ProjectPaintState *ps, float pt[2], float w[3], int *side) {
+static int project_paint_PickFace(ProjPaintState *ps, float pt[2], float w[3], int *side) {
 	LinkNode *node;
 	float w_tmp[3];
 	float *v1, *v2, *v3, *v4;
@@ -713,7 +739,7 @@
 }
 
 /* Set the top-most face color that the screen space coord 'pt' touches (or return 0 if none touch) */
-static int project_paint_PickColor(ProjectPaintState *ps, float pt[2], float *rgba_fp, char *rgba, int interp)
+static int project_paint_PickColor(ProjPaintState *ps, float pt[2], float *rgba_fp, char *rgba, int interp)
 {
 	float w[3], uv[2];
 	int side;
@@ -745,14 +771,14 @@
 	if (interp) {
 		float x,y;
 		/* use */
-		x = (float)fmod(uv[0], 1.0);
-		y = (float)fmod(uv[1], 1.0);
+		x = (float)fmod(uv[0], 1.0f);
+		y = (float)fmod(uv[1], 1.0f);
 		
-		if (x < 0.0) x += 1.0;
-		if (y < 0.0) y += 1.0;
+		if (x < 0.0f) x += 1.0f;
+		if (y < 0.0f) y += 1.0f;
 		
-		x = x * ibuf->x - 0.5;
-		y = y * ibuf->y - 0.5;
+		x = x * ibuf->x - 0.5f;
+		y = y * ibuf->y - 0.5f;
 		
 		if (ibuf->rect_float) {
 			if (rgba_fp) {
@@ -772,8 +798,8 @@
 			}
 		}
 	} else {
-		xi = (uv[0]*ibuf->x) + 0.5;
-		yi = (uv[1]*ibuf->y) + 0.5;
+		xi = (uv[0]*ibuf->x) + 0.5f;
+		yi = (uv[1]*ibuf->y) + 0.5f;
 		
 		//if (xi<0 || xi>=ibuf->x  ||  yi<0 || yi>=ibuf->y) return 0;
 		
@@ -838,7 +864,7 @@
 /* Check if a screenspace location is occluded by any other faces
  * check, pixelScreenCo must be in screenspace, its Z-Depth only needs to be used for comparison
  * and dosn't need to be correct in relation to X and Y coords (this is the case in perspective view) */
-static int project_bucket_point_occluded(ProjectPaintState *ps, int bucket_index, int orig_face, float pixelScreenCo[4])
+static int project_bucket_point_occluded(ProjPaintState *ps, int bucket_index, int orig_face, float pixelScreenCo[4])
 {
 	LinkNode *node = ps->bucketFaces[bucket_index];
 	MFace *mf;
@@ -934,7 +960,7 @@
 /* simple func use for comparing UV locations to check if there are seams */
 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;
+	return ((fabs(vec2a[0]-vec2b[0]) < 0.0001f) && (fabs(vec2a[1]-vec2b[1]) < 0.0001f)) ? 1:0;
 }
 
 
@@ -968,7 +994,7 @@
 

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list