[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