Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2008-11-12 08:56:37 +0300
committerCampbell Barton <ideasman42@gmail.com>2008-11-12 08:56:37 +0300
commitc63c99d49ec38c722730624542b0252d16b759a6 (patch)
treef3a4820d0464b42daa85030259efc39066fd14eb
parent58b861170c9c174f4fd85171955fe6ce4d5b7dba (diff)
Option to have painting multi-threaded.
Each thread process the next free bucket the brush is over until they are all done.
-rw-r--r--source/blender/src/imagepaint.c647
1 files changed, 436 insertions, 211 deletions
diff --git a/source/blender/src/imagepaint.c b/source/blender/src/imagepaint.c
index af2e3141a32..b4cdda4ab71 100644
--- a/source/blender/src/imagepaint.c
+++ b/source/blender/src/imagepaint.c
@@ -49,6 +49,7 @@
#include "BLI_linklist.h"
#include "BLI_memarena.h"
#include "PIL_time.h"
+#include "BLI_threads.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -138,6 +139,7 @@ typedef struct ImagePaintState {
//#define PROJ_DEBUG_PAINT 1
#define PROJ_DEBUG_NOSCANLINE 1
//#define PROJ_DEBUG_NOSEAMBLEED 1
+//#define PROJ_DEBUG_PRINT_THREADS 1
/* projectFaceSeamFlags options */
//#define PROJ_FACE_IGNORE 1<<0 /* When the face is hidden, backfacing or occluded */
@@ -178,6 +180,7 @@ typedef struct ProjectPaintState {
/* projection painting only */
MemArena *projectArena; /* use for alocating many pixel structs and link-lists */
+ MemArena *projectArena_mt[BLENDER_MAX_THREADS]; /* Same as above but use for multithreading */
LinkNode **projectBuckets; /* screen sized 2D array, each pixel has a linked list of ProjectPixel's */
LinkNode **projectFaces; /* projectBuckets alligned array linkList of faces overlapping each bucket */
char *projectBucketFlags; /* store if the bucks have been initialized */
@@ -193,7 +196,6 @@ typedef struct ProjectPaintState {
ImBuf **projectImBufs; /* array of imbufs we are painting onto while, use so we can get the rect and rect_float quickly */
int projectImageTotal; /* size of projectImages array */
- int imaContextIndex; /* current image, use for context switching */
float (*projectVertScreenCos)[4]; /* verts projected into floating point screen space */
@@ -216,6 +218,12 @@ typedef struct ProjectPaintState {
float viewMax2D[2];
float viewWidth; /* Calculated from viewMin2D & viewMax2D */
float viewHeight;
+
+ /* threads */
+ int thread_tot;
+ int min_bucket[2];
+ int max_bucket[2];
+ int context_bucket_x, context_bucket_y; /* must lock threads while accessing these */
} ProjectPaintState;
#ifndef PROJ_DEBUG_NOSCANLINE
@@ -1201,6 +1209,8 @@ static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], float sc
/*
* Be tricky with flags, first 4 bits are PROJ_FACE_SEAM1 to 4, last 4 bits are PROJ_FACE_NOSEAM1 to 4
* 1<<i - where i is (0-3)
+ *
+ * If we're multithreadng, make sure threads are locked when this is called
*/
static void project_face_seams_init(ProjectPaintState *ps, int face_index, int is_quad)
{
@@ -1280,7 +1290,7 @@ static screen_px_from_persp(
/* Only run this function once for new ProjectPixelClone's */
#define pixel_size 4
-static void project_paint_uvpixel_init(ProjectPaintState *ps, ImBuf *ibuf, int x, int y, int bucket_index, int face_index, float pixelScreenCo[4])
+static void project_paint_uvpixel_init(ProjectPaintState *ps, int thread_index, ImBuf *ibuf, int x, int y, int bucket_index, int face_index, int image_index, float pixelScreenCo[4])
{
ProjectPixel *projPixel;
short size;
@@ -1308,7 +1318,7 @@ static void project_paint_uvpixel_init(ProjectPaintState *ps, ImBuf *ibuf, int x
size = sizeof(ProjectPixel);
}
- projPixel = (ProjectPixel *)BLI_memarena_alloc(ps->projectArena, size);
+ projPixel = (ProjectPixel *)BLI_memarena_alloc(ps->projectArena_mt[thread_index], size);
if (ibuf->rect_float) {
projPixel->pixel = (void *) ((( float * ) ibuf->rect_float) + (( x + y * ibuf->x ) * pixel_size));
@@ -1345,12 +1355,12 @@ static void project_paint_uvpixel_init(ProjectPaintState *ps, ImBuf *ibuf, int x
if (ibuf->rect_float) ((float *)projPixel->pixel)[1] = 0;
else ((char *)projPixel->pixel)[1] = 0;
#endif
- projPixel->image_index = ps->imaContextIndex;
+ projPixel->image_index = image_index;
BLI_linklist_prepend_arena(
&ps->projectBuckets[ bucket_index ],
projPixel,
- ps->projectArena
+ ps->projectArena_mt[thread_index]
);
}
}
@@ -1493,8 +1503,50 @@ static void scale_tri(float *origCos[4], float insetCos[4][3], float inset)
VecAddf(insetCos[2], insetCos[2], cent);
}
-/**/
-static void project_paint_face_init(ProjectPaintState *ps, int bucket_index, int face_index, float bucket_bounds[4], ImBuf *ibuf)
+static void rect_to_uvspace(
+ ProjectPaintState *ps, float bucket_bounds[4],
+ float *v1coSS, float *v2coSS, float *v3coSS,
+ float *uv1co, float *uv2co, float *uv3co,
+ float bucket_bounds_uv[4][2]
+ )
+{
+ float uv[2];
+ float w[3];
+
+ /* get the UV space bounding box */
+ uv[0] = bucket_bounds[PROJ_BUCKET_RIGHT];
+ uv[1] = bucket_bounds[PROJ_BUCKET_BOTTOM];
+ if (ps->projectIsOrtho) BarycentricWeights2f(v1coSS, v2coSS, v3coSS, uv, w);
+ else BarycentricWeightsPersp2f(v1coSS, v2coSS, v3coSS, uv, w);
+ bucket_bounds_uv[0][0] = uv1co[0]*w[0] + uv2co[0]*w[1] + uv3co[0]*w[2];
+ bucket_bounds_uv[0][1] = uv1co[1]*w[0] + uv2co[1]*w[1] + uv3co[1]*w[2];
+
+ //uv[0] = bucket_bounds[PROJ_BUCKET_RIGHT]; // set above
+ uv[1] = bucket_bounds[PROJ_BUCKET_TOP];
+ if (ps->projectIsOrtho) BarycentricWeights2f(v1coSS, v2coSS, v3coSS, uv, w);
+ else BarycentricWeightsPersp2f(v1coSS, v2coSS, v3coSS, uv, w);
+ bucket_bounds_uv[1][0] = uv1co[0]*w[0] + uv2co[0]*w[1] + uv3co[0]*w[2];
+ bucket_bounds_uv[1][1] = uv1co[1]*w[0] + uv2co[1]*w[1] + uv3co[1]*w[2];
+
+
+ uv[0] = bucket_bounds[PROJ_BUCKET_LEFT];
+ //uv[1] = bucket_bounds[PROJ_BUCKET_TOP]; // set above
+ if (ps->projectIsOrtho) BarycentricWeights2f(v1coSS, v2coSS, v3coSS, uv, w);
+ else BarycentricWeightsPersp2f(v1coSS, v2coSS, v3coSS, uv, w);
+ bucket_bounds_uv[2][0] = uv1co[0]*w[0] + uv2co[0]*w[1] + uv3co[0]*w[2];
+ bucket_bounds_uv[2][1] = uv1co[1]*w[0] + uv2co[1]*w[1] + uv3co[1]*w[2];
+
+ //uv[0] = bucket_bounds[PROJ_BUCKET_LEFT]; // set above
+ uv[1] = bucket_bounds[PROJ_BUCKET_BOTTOM];
+ if (ps->projectIsOrtho) BarycentricWeights2f(v1coSS, v2coSS, v3coSS, uv, w);
+ else BarycentricWeightsPersp2f(v1coSS, v2coSS, v3coSS, uv, w);
+ bucket_bounds_uv[3][0] = uv1co[0]*w[0] + uv2co[0]*w[1] + uv3co[0]*w[2];
+ bucket_bounds_uv[3][1] = uv1co[1]*w[0] + uv2co[1]*w[1] + uv3co[1]*w[2];
+}
+
+
+/* initialize pixels from this face where it intersects with the bucket_index, initialize pixels for removing seams */
+static void project_paint_face_init(ProjectPaintState *ps, int thread_index, int bucket_index, int face_index, int image_index, float bucket_bounds[4], ImBuf *ibuf)
{
/* Projection vars, to get the 3D locations into screen space */
@@ -1508,7 +1560,7 @@ static void project_paint_face_init(ProjectPaintState *ps, int bucket_index, int
int min_px[2], max_px[2]; /* UV Bounds converted to int's for pixel */
int min_px_tf[2], max_px_tf[2]; /* UV Bounds converted to int's for pixel */
- int min_px_bucket[2][2], max_px_bucket[2][2]; /* Bucket Bounds converted to int's for pixel */
+ int min_px_bucket[2], max_px_bucket[2]; /* Bucket Bounds converted to int's for pixel */
float *v1coSS, *v2coSS, *v3coSS, *v4coSS; /* vert co screen-space, these will be assigned to mf->v1,2,3 or mf->v1,3,4 */
float *v1co, *v2co, *v3co; /* vert co */
float *vCo[4]; /* vertex screenspace coords */
@@ -1551,43 +1603,15 @@ static void project_paint_face_init(ProjectPaintState *ps, int bucket_index, int
v2coSS = ps->projectVertScreenCos[ (*(&mf->v1 + i2)) ];
v3coSS = ps->projectVertScreenCos[ (*(&mf->v1 + i3)) ];
- /* get the UV space bounding box */
- uv[0] = bucket_bounds[PROJ_BUCKET_RIGHT];
- uv[1] = bucket_bounds[PROJ_BUCKET_BOTTOM];
- if (ps->projectIsOrtho) BarycentricWeights2f(v1coSS, v2coSS, v3coSS, uv, w);
- else BarycentricWeightsPersp2f(v1coSS, v2coSS, v3coSS, uv, w);
- bucket_bounds_uv[0][0] = uv1co[0]*w[0] + uv2co[0]*w[1] + uv3co[0]*w[2];
- bucket_bounds_uv[0][1] = uv1co[1]*w[0] + uv2co[1]*w[1] + uv3co[1]*w[2];
-
- //uv[0] = bucket_bounds[PROJ_BUCKET_RIGHT]; // set above
- uv[1] = bucket_bounds[PROJ_BUCKET_TOP];
- if (ps->projectIsOrtho) BarycentricWeights2f(v1coSS, v2coSS, v3coSS, uv, w);
- else BarycentricWeightsPersp2f(v1coSS, v2coSS, v3coSS, uv, w);
- bucket_bounds_uv[1][0] = uv1co[0]*w[0] + uv2co[0]*w[1] + uv3co[0]*w[2];
- bucket_bounds_uv[1][1] = uv1co[1]*w[0] + uv2co[1]*w[1] + uv3co[1]*w[2];
-
-
- uv[0] = bucket_bounds[PROJ_BUCKET_LEFT];
- //uv[1] = bucket_bounds[PROJ_BUCKET_TOP]; // set above
- if (ps->projectIsOrtho) BarycentricWeights2f(v1coSS, v2coSS, v3coSS, uv, w);
- else BarycentricWeightsPersp2f(v1coSS, v2coSS, v3coSS, uv, w);
- bucket_bounds_uv[2][0] = uv1co[0]*w[0] + uv2co[0]*w[1] + uv3co[0]*w[2];
- bucket_bounds_uv[2][1] = uv1co[1]*w[0] + uv2co[1]*w[1] + uv3co[1]*w[2];
-
- //uv[0] = bucket_bounds[PROJ_BUCKET_LEFT]; // set above
- uv[1] = bucket_bounds[PROJ_BUCKET_BOTTOM];
- if (ps->projectIsOrtho) BarycentricWeights2f(v1coSS, v2coSS, v3coSS, uv, w);
- else BarycentricWeightsPersp2f(v1coSS, v2coSS, v3coSS, uv, w);
- bucket_bounds_uv[3][0] = uv1co[0]*w[0] + uv2co[0]*w[1] + uv3co[0]*w[2];
- bucket_bounds_uv[3][1] = uv1co[1]*w[0] + uv2co[1]*w[1] + uv3co[1]*w[2];
+ rect_to_uvspace(ps, bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, bucket_bounds_uv);
//printf("Bounds: %f | %f | %f | %f\n", bucket_bounds[0], bucket_bounds[1], bucket_bounds[2], bucket_bounds[3]);
if ( uv_image_rect(uv1co, uv2co, uv3co, NULL, min_px_tf, max_px_tf, ibuf->x, ibuf->y, 0) &&
- uv_image_rect(bucket_bounds_uv[0], bucket_bounds_uv[1], bucket_bounds_uv[2], bucket_bounds_uv[3], min_px_bucket[i], max_px_bucket[i], ibuf->x, ibuf->y, 1) )
+ uv_image_rect(bucket_bounds_uv[0], bucket_bounds_uv[1], bucket_bounds_uv[2], bucket_bounds_uv[3], min_px_bucket, max_px_bucket, ibuf->x, ibuf->y, 1) )
{
- uvpixel_rect_intersect(min_px, max_px, min_px_bucket[i], max_px_bucket[i], min_px_tf, max_px_tf);
+ uvpixel_rect_intersect(min_px, max_px, min_px_bucket, max_px_bucket, min_px_tf, max_px_tf);
/* clip face and */
@@ -1607,7 +1631,7 @@ static void project_paint_face_init(ProjectPaintState *ps, int bucket_index, int
screen_px_from_persp(ps, uv, vCo[i1],vCo[i2],vCo[i3], uv1co,uv2co,uv3co, pixelScreenCo);
}
- project_paint_uvpixel_init(ps, ibuf, x,y, bucket_index, face_index, pixelScreenCo);
+ project_paint_uvpixel_init(ps, thread_index, ibuf, x,y, bucket_index, face_index, image_index, pixelScreenCo);
}
}
}
@@ -1615,21 +1639,30 @@ static void project_paint_face_init(ProjectPaintState *ps, int bucket_index, int
} while(i--);
#ifndef PROJ_DEBUG_NOSEAMBLEED
if (ps->projectSeamBleed > 0.0) {
+ int face_seam_flag;
+
+ if (ps->thread_tot > 1)
+ BLI_lock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */
- int flag = ps->projectFaceSeamFlags[face_index];
+ face_seam_flag = ps->projectFaceSeamFlags[face_index];
/* are any of our edges un-initialized? */
- if ((flag & (PROJ_FACE_SEAM1|PROJ_FACE_NOSEAM1))==0 ||
- (flag & (PROJ_FACE_SEAM2|PROJ_FACE_NOSEAM2))==0 ||
- (flag & (PROJ_FACE_SEAM3|PROJ_FACE_NOSEAM3))==0 ||
- (flag & (PROJ_FACE_SEAM4|PROJ_FACE_NOSEAM4))==0
+ if ((face_seam_flag & (PROJ_FACE_SEAM1|PROJ_FACE_NOSEAM1))==0 ||
+ (face_seam_flag & (PROJ_FACE_SEAM2|PROJ_FACE_NOSEAM2))==0 ||
+ (face_seam_flag & (PROJ_FACE_SEAM3|PROJ_FACE_NOSEAM3))==0 ||
+ (face_seam_flag & (PROJ_FACE_SEAM4|PROJ_FACE_NOSEAM4))==0
) {
project_face_seams_init(ps, face_index, mf->v4);
- flag = ps->projectFaceSeamFlags[face_index];
+ face_seam_flag = ps->projectFaceSeamFlags[face_index];
//printf("seams - %d %d %d %d\n", flag&PROJ_FACE_SEAM1, flag&PROJ_FACE_SEAM2, flag&PROJ_FACE_SEAM3, flag&PROJ_FACE_SEAM4);
}
- if (flag & (PROJ_FACE_SEAM1|PROJ_FACE_SEAM2|PROJ_FACE_SEAM3|PROJ_FACE_SEAM4)) {
+ if ((face_seam_flag & (PROJ_FACE_SEAM1|PROJ_FACE_SEAM2|PROJ_FACE_SEAM3|PROJ_FACE_SEAM4))==0) {
+
+ if (ps->thread_tot > 1)
+ BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */
+
+ } else {
/* we have a seam - deal with it! */
/* Now create new UV's for the seam face */
@@ -1652,6 +1685,10 @@ static void project_paint_face_init(ProjectPaintState *ps, int bucket_index, int
if (outset_uv[0][0]==MAXFLOAT) /* first time initialize */
uv_image_outset(tf->uv, outset_uv, ps->projectSeamBleed, ibuf->x, ibuf->y, mf->v4);
+ /* ps->projectFaceSeamUVs cant be modified when threading, now this is done we can unlock */
+ if (ps->thread_tot > 1)
+ BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */
+
vCoSS[0] = ps->projectVertScreenCos[ mf->v1 ];
vCoSS[1] = ps->projectVertScreenCos[ mf->v2 ];
vCoSS[2] = ps->projectVertScreenCos[ mf->v3 ];
@@ -1670,7 +1707,7 @@ static void project_paint_face_init(ProjectPaintState *ps, int bucket_index, int
if (mf->v4) fidx2 = (fidx1==3) ? 0 : fidx1+1; /* next fidx in the face (0,1,2,3) -> (1,2,3,0) */
else fidx2 = (fidx1==2) ? 0 : fidx1+1; /* next fidx in the face (0,1,2) -> (1,2,0) */
- if ( (ps->projectFaceSeamFlags[face_index] & (1<<fidx1) ) && /* 1<<fidx1 -> PROJ_FACE_SEAM# */
+ if ( (face_seam_flag & (1<<fidx1) ) && /* 1<<fidx1 -> PROJ_FACE_SEAM# */
line_clip_rect2f(bucket_bounds, vCoSS[fidx1], vCoSS[fidx2], bucket_clip_edges[0], bucket_clip_edges[1])
) {
@@ -1736,7 +1773,7 @@ static void project_paint_face_init(ProjectPaintState *ps, int bucket_index, int
pixelScreenCo[2] = pixelScreenCo[2]/pixelScreenCo[3]; /* Use the depth for bucket point occlusion */
}
- project_paint_uvpixel_init(ps, ibuf, x, y, bucket_index, face_index, pixelScreenCo);
+ project_paint_uvpixel_init(ps, thread_index, ibuf, x, y, bucket_index, face_index, image_index, pixelScreenCo);
}
}
}
@@ -1778,10 +1815,10 @@ static void project_bucket_bounds(ProjectPaintState *ps, int bucket_x, int bucke
}
/* have bucket_bounds as an arg so we dont need to give bucket_x/y the rect function need */
-static void project_paint_bucket_init(ProjectPaintState *ps, int bucket_index, float bucket_bounds[4])
+static void project_paint_bucket_init(ProjectPaintState *ps, int thread_index, int bucket_index, float bucket_bounds[4])
{
LinkNode *node;
- int face_index;
+ int face_index, image_index;
ImBuf *ibuf;
MTFace *tf;
@@ -1797,23 +1834,23 @@ static void project_paint_bucket_init(ProjectPaintState *ps, int bucket_index, f
if (tpage_last != tf->tpage) {
tpage_last = tf->tpage;
- ps->imaContextIndex = -1; /* sanity check */
+ image_index = -1; /* sanity check */
for (tpage_index=0; tpage_index < ps->projectImageTotal; tpage_index++) {
if (ps->projectImages[tpage_index] == tpage_last) {
- ps->imaContextIndex = tpage_index;
+ image_index = tpage_index;
break;
}
}
- if (ps->imaContextIndex==-1) {
+ if (image_index==-1) {
printf("Error, should never happen!\n");
return;
}
ibuf = BKE_image_get_ibuf(tpage_last, NULL); /* TODO - this may be slow */
}
- project_paint_face_init(ps, bucket_index, face_index, bucket_bounds, ibuf);
+ project_paint_face_init(ps, thread_index, bucket_index, face_index, image_index, bucket_bounds, ibuf);
node = node->next;
} while (node);
@@ -1896,7 +1933,9 @@ static void project_paint_delayed_face_init(ProjectPaintState *ps, MFace *mf, MT
float min[2], max[2];
int bucket_min[2], bucket_max[2]; /* for ps->projectBuckets indexing */
int i, a, bucket_x, bucket_y, bucket_index;
-
+
+ int has_x_isect = -1, has_isect = -1; /* for early loop exit */
+
INIT_MINMAX2(min,max);
i = mf->v4 ? 3:2;
@@ -1920,6 +1959,7 @@ static void project_paint_delayed_face_init(ProjectPaintState *ps, MFace *mf, MT
project_paint_rect(ps, min, max, bucket_min, bucket_max);
for (bucket_y = bucket_min[1]; bucket_y < bucket_max[1]; bucket_y++) {
+ has_x_isect = 0;
for (bucket_x = bucket_min[0]; bucket_x < bucket_max[0]; bucket_x++) {
bucket_index = bucket_x + (bucket_y * ps->bucketsX);
@@ -1930,8 +1970,18 @@ static void project_paint_delayed_face_init(ProjectPaintState *ps, MFace *mf, MT
(void *)face_index, /* cast to a pointer to shut up the compiler */
ps->projectArena
);
+
+ has_x_isect = has_isect = 1;
+ } else if (has_x_isect) {
+ /* assuming the face is not a bow-tie - we know we cant intersect again on the X */
+ break;
}
}
+
+ /* no intersection for this entire row, after some intersection above means we can quit now */
+ if (has_x_isect==0 && has_isect) {
+ break;
+ }
}
#ifndef PROJ_DEBUG_NOSEAMBLEED
@@ -1978,6 +2028,7 @@ static void project_paint_begin( ProjectPaintState *ps, short mval[2])
MTFace *tf;
int a, i; /* generic looping vars */
+ int image_index;
/* memory sized to add to arena size */
int tot_bucketMem=0;
@@ -2000,10 +2051,8 @@ static void project_paint_begin( ProjectPaintState *ps, short mval[2])
ps->dm_totvert = ps->dm->getNumVerts( ps->dm );
ps->dm_totface = ps->dm->getNumFaces( ps->dm );
- ps->bucketsX = PROJ_BUCKET_DIV;
- ps->bucketsY = PROJ_BUCKET_DIV;
-
- ps->imaContextIndex = -1;
+ ps->bucketsX = G.rt ? G.rt : PROJ_BUCKET_DIV;
+ ps->bucketsY = G.rt ? G.rt : PROJ_BUCKET_DIV;
ps->viewDir[0] = 0.0;
ps->viewDir[1] = 0.0;
@@ -2028,8 +2077,8 @@ static void project_paint_begin( ProjectPaintState *ps, short mval[2])
tot_faceListMem +
tot_faceSeamFlagMem +
tot_faceSeamUVMem +
- tot_bucketVertFacesMem + (1<<16));
-
+ tot_bucketVertFacesMem + (1<<18));
+ //BLI_memarena_use_calloc(ps->projectArena); ?
ps->projectBuckets = (LinkNode **)BLI_memarena_alloc( ps->projectArena, tot_bucketMem);
ps->projectFaces= (LinkNode **)BLI_memarena_alloc( ps->projectArena, tot_faceListMem);
@@ -2054,6 +2103,18 @@ static void project_paint_begin( ProjectPaintState *ps, short mval[2])
memset(ps->projectFaceSeamUVs, 0, tot_faceSeamUVMem);
}
#endif
+
+ /* Thread stuff */
+ 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->projectArena_mt[a] = BLI_memarena_new(1<<16);
+ }
+
Mat4Invert(ps->ob->imat, ps->ob->obmat);
Mat3CpyMat4(mat, G.vd->viewinv);
@@ -2169,11 +2230,11 @@ static void project_paint_begin( ProjectPaintState *ps, short mval[2])
ibuf= BKE_image_get_ibuf((Image *)tf->tpage, NULL);
if (ibuf) {
- ps->imaContextIndex = BLI_linklist_index(image_LinkList, tf->tpage);
+ image_index = BLI_linklist_index(image_LinkList, tf->tpage);
- if (ps->imaContextIndex==-1) { /* MemArena dosnt have an append func */
+ if (image_index==-1) { /* MemArena dosnt have an append func */
BLI_linklist_append(&image_LinkList, tf->tpage);
- ps->imaContextIndex = ps->projectImageTotal;
+ image_index = ps->projectImageTotal;
ps->projectImageTotal++;
}
}
@@ -2205,7 +2266,13 @@ static void project_paint_begin( ProjectPaintState *ps, short mval[2])
static void project_paint_end( ProjectPaintState *ps )
{
+ int a;
BLI_memarena_free(ps->projectArena);
+
+ for (a=0; a<ps->thread_tot; a++) {
+ BLI_memarena_free(ps->projectArena_mt[a]);
+ }
+
ps->dm->release(ps->dm);
}
@@ -2711,7 +2778,86 @@ static int project_bucket_circle_isect(ProjectPaintState *ps, int bucket_x, int
return 0;
}
-static int imapaint_paint_sub_stroke_project(ProjectPaintState *ps, BrushPainter *painter, short prevmval[2], short mval[2], double time, int update, float pressure)
+/* Loop over all images on this mesh and update any we have touched */
+static int imapaint_refresh_tagged(ProjectPaintState *ps)
+{
+ int a;
+ int redraw = 0;
+ for (a=0; a < ps->projectImageTotal; a++) {
+ Image *ima = ps->projectImages[a];
+ if (ima->id.flag & LIB_DOIT) {
+ imapaint_image_update(ima, BKE_image_get_ibuf(ima, NULL), 1 /*texpaint*/ );
+ redraw = 1;
+
+ ima->id.flag &= ~LIB_DOIT; /* clear for reuse */
+ }
+ }
+
+ return redraw;
+}
+
+
+static int bucket_iter_init(ProjectPaintState *ps, float mval_f[2])
+{
+ float min_brush[2], max_brush[2];
+
+ min_brush[0] = mval_f[0] - (ps->brush->size/2);
+ min_brush[1] = mval_f[1] - (ps->brush->size/2);
+
+ max_brush[0] = mval_f[0] + (ps->brush->size/2);
+ max_brush[1] = mval_f[1] + (ps->brush->size/2);
+
+ /* offset to make this a valid bucket index */
+ project_paint_rect(ps, min_brush, max_brush, ps->min_bucket, ps->max_bucket);
+
+ /* mouse outside the model areas? */
+ if (ps->min_bucket[0]==ps->max_bucket[0] || ps->min_bucket[1]==ps->max_bucket[1]) {
+ return 0;
+ }
+
+ ps->context_bucket_x = ps->min_bucket[0];
+ ps->context_bucket_y = ps->min_bucket[1];
+#ifdef PROJ_DEBUG_PRINT_THREADS
+ printf("Initializing Values %d %d!", ps->min_bucket[0], ps->min_bucket[1]);
+#endif
+ return 1;
+}
+
+static int bucket_iter_next(ProjectPaintState *ps, int *bucket_index, float bucket_bounds[4], float mval_f[2])
+{
+ if (ps->thread_tot > 1)
+ BLI_lock_thread(LOCK_CUSTOM1);
+
+ //printf("%d %d \n", ps->context_bucket_x, ps->context_bucket_y);
+
+ for ( ; ps->context_bucket_y < ps->max_bucket[1]; ps->context_bucket_y++) {
+ for ( ; ps->context_bucket_x < ps->max_bucket[0]; ps->context_bucket_x++) {
+
+ /* 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)) {
+ *bucket_index = ps->context_bucket_x + (ps->context_bucket_y * ps->bucketsX);
+#ifdef PROJ_DEBUG_PRINT_THREADS
+ printf(" --- %d %d \n", ps->context_bucket_x, ps->context_bucket_y);
+#endif
+ ps->context_bucket_x++;
+
+ if (ps->thread_tot > 1)
+ BLI_unlock_thread(LOCK_CUSTOM1);
+
+ return 1;
+ }
+ }
+ ps->context_bucket_x = ps->min_bucket[0];
+ }
+
+ if (ps->thread_tot > 1)
+ BLI_unlock_thread(LOCK_CUSTOM1);
+ return 0;
+}
+
+static int imapaint_paint_sub_stroke_project(ProjectPaintState *ps, BrushPainter *painter, short prevmval[2], short mval[2], double time, float pressure, int thread_index)
{
/* TODO - texpaint option : is there any use in projection painting from the image window??? - could be interesting */
/* TODO - floating point images */
@@ -2727,19 +2873,18 @@ static int imapaint_paint_sub_stroke_project(ProjectPaintState *ps, BrushPainter
char rgba_ub[4];
float rgba_fp[4];
float brush_size_sqared;
- float min[2], max[2]; /* brush bounds in screenspace */
+ //float min[2], max[2]; /* brush bounds in screenspace */
int bucket_min[2], bucket_max[2]; /* brush bounds in bucket grid space */
int bucket_index;
int a;
int is_floatbuf = 0;
short blend= ps->blend;
+
/* pixel values */
char *cp;
float *fp;
float bucket_bounds[4];
- int bucket_x, bucket_y;
-
/* for smear only */
float mval_ofs[2];
@@ -2747,22 +2892,8 @@ static int imapaint_paint_sub_stroke_project(ProjectPaintState *ps, BrushPainter
LinkNode *smearPixels = NULL;
LinkNode *smearPixels_float = NULL;
MemArena *smearArena = NULL; /* mem arena for this brush projection only */
-
- mval_f[0] = mval[0]; mval_f[1] = mval[1];
-
- min[0] = mval_f[0] - (ps->brush->size/2);
- min[1] = mval_f[1] - (ps->brush->size/2);
-
- max[0] = mval_f[0] + (ps->brush->size/2);
- max[1] = mval_f[1] + (ps->brush->size/2);
-
- /* offset to make this a valid bucket index */
- project_paint_rect(ps, min, max, bucket_min, bucket_max);
-
- /* mouse outside the model areas? */
- if (bucket_min[0]==bucket_max[0] || bucket_min[1]==bucket_max[1]) {
- return 0;
- }
+
+ mval_f[0] = mval[0]; mval_f[1] = mval[1];
if (ps->tool==PAINT_TOOL_SMEAR) {
mval_ofs[0] = (float)(mval[0] - prevmval[0]);
@@ -2781,130 +2912,128 @@ static int imapaint_paint_sub_stroke_project(ProjectPaintState *ps, BrushPainter
/* no clamping needed, dont use screen bounds, use vert bounds */
- for (bucket_y = bucket_min[1]; bucket_y < bucket_max[1]; bucket_y++) {
- for (bucket_x = bucket_min[0]; bucket_x < bucket_max[0]; bucket_x++) {
-
- /* use bucket_bounds for project_bucket_circle_isect and project_paint_bucket_init*/
- project_bucket_bounds(ps, bucket_x, bucket_y, bucket_bounds);
-
- if (project_bucket_circle_isect(ps, bucket_x, bucket_y, mval_f, brush_size_sqared, bucket_bounds)) {
-
- bucket_index = bucket_x + (bucket_y * ps->bucketsX);
-
- /* Check this bucket and its faces are initialized */
- if (ps->projectBucketFlags[bucket_index] == PROJ_BUCKET_NULL) {
- /* No pixels initialized */
- project_paint_bucket_init(ps, bucket_index, bucket_bounds);
- }
-
- /* TODO - we may want to init clone data in a seperate to project_paint_bucket_init
- * so we dont go overboard and init too many clone pixels */
+ //for (bucket_y = bucket_min[1]; bucket_y < bucket_max[1]; bucket_y++) {
+#ifdef PROJ_DEBUG_PRINT_THREADS
+ printf("THREAD %d %d %d\n", ps->thread_tot, thread_index, (ps->max_bucket[0] - ps->min_bucket[0]) * (ps->max_bucket[1] - ps->min_bucket[1]) );
+#endif
+ while (bucket_iter_next(ps, &bucket_index, bucket_bounds, mval_f)) {
+
+#ifdef PROJ_DEBUG_PRINT_THREADS
+ printf("\t%d %d\n", thread_index, bucket_index);
+#endif
+
+ /* Check this bucket and its faces are initialized */
+ if (ps->projectBucketFlags[bucket_index] == PROJ_BUCKET_NULL) {
+ /* No pixels initialized */
+ project_paint_bucket_init(ps, thread_index, bucket_index, bucket_bounds);
+ }
+
+ /* TODO - we may want to init clone data in a seperate to project_paint_bucket_init
+ * so we dont go overboard and init too many clone pixels */
- if ((node = ps->projectBuckets[bucket_index])) {
+ if ((node = ps->projectBuckets[bucket_index])) {
+
+ do {
+ projPixel = (ProjectPixel *)node->link;
- do {
- projPixel = (ProjectPixel *)node->link;
-
- /*dist = Vec2Lenf(projPixel->projCo2D, mval_f);*/ /* correct but uses a sqrt */
- dist_nosqrt = Vec2Lenf_nosqrt(projPixel->projCo2D, mval_f);
-
- /*if (dist < s->brush->size) {*/ /* correct but uses a sqrt */
- if (dist_nosqrt < brush_size_sqared) {
-
- if (last_index != projPixel->image_index) {
- last_index = projPixel->image_index;
- ps->projectImages[last_index]->id.flag |= LIB_DOIT;
- is_floatbuf = ps->projectImBufs[last_index]->rect_float ? 1 : 0;
+ /*dist = Vec2Lenf(projPixel->projCo2D, mval_f);*/ /* correct but uses a sqrt */
+ dist_nosqrt = Vec2Lenf_nosqrt(projPixel->projCo2D, mval_f);
+
+ /*if (dist < s->brush->size) {*/ /* correct but uses a sqrt */
+ if (dist_nosqrt < brush_size_sqared) {
+
+ if (last_index != projPixel->image_index) {
+ last_index = projPixel->image_index;
+ ps->projectImages[last_index]->id.flag |= LIB_DOIT; /* halgrind complains this is not threadsafe but probably ok? - we are only setting this flag anyway */
+ is_floatbuf = ps->projectImBufs[last_index]->rect_float ? 1 : 0;
+ }
+
+ dist = (float)sqrt(dist_nosqrt);
+
+ switch(ps->tool) {
+ case PAINT_TOOL_CLONE:
+ if (is_floatbuf) {
+ if (((ProjectPixelCloneFloat*)projPixel)->clonepx[3]) {
+ alpha = brush_sample_falloff(ps->brush, dist);
+ fp = ((ProjectPixelCloneFloat *)projPixel)->clonepx;
+ if (alpha >= 1.0) {
+ VECCOPY((float *)projPixel->pixel, ((ProjectPixelCloneFloat *)projPixel)->clonepx );
+ } else {
+ ((float *)projPixel->pixel)[0] = (fp[0] * alpha) + ((((float *)projPixel->pixel)[0])*(1.0-alpha));
+ ((float *)projPixel->pixel)[1] = (fp[1] * alpha) + ((((float *)projPixel->pixel)[1])*(1.0-alpha));
+ ((float *)projPixel->pixel)[2] = (fp[2] * alpha) + ((((float *)projPixel->pixel)[2])*(1.0-alpha));
+ }
}
-
- dist = (float)sqrt(dist_nosqrt);
-
- switch(ps->tool) {
- case PAINT_TOOL_CLONE:
- if (is_floatbuf) {
- if (((ProjectPixelCloneFloat*)projPixel)->clonepx[3]) {
- alpha = brush_sample_falloff(ps->brush, dist);
- fp = ((ProjectPixelCloneFloat *)projPixel)->clonepx;
- if (alpha >= 1.0) {
- VECCOPY((float *)projPixel->pixel, ((ProjectPixelCloneFloat *)projPixel)->clonepx );
- } else {
- ((float *)projPixel->pixel)[0] = (fp[0] * alpha) + ((((float *)projPixel->pixel)[0])*(1.0-alpha));
- ((float *)projPixel->pixel)[1] = (fp[1] * alpha) + ((((float *)projPixel->pixel)[1])*(1.0-alpha));
- ((float *)projPixel->pixel)[2] = (fp[2] * alpha) + ((((float *)projPixel->pixel)[2])*(1.0-alpha));
- }
- }
+ } else {
+ if (((ProjectPixelClone*)projPixel)->clonepx[3]) {
+ alpha = brush_sample_falloff(ps->brush, dist);
+ cp = (char *)((ProjectPixelClone*)projPixel)->clonepx;
+ if (alpha >= 1.0) {
+ ((char *)projPixel->pixel)[0] = cp[0];
+ ((char *)projPixel->pixel)[1] = cp[1];
+ ((char *)projPixel->pixel)[2] = cp[2];
} else {
- if (((ProjectPixelClone*)projPixel)->clonepx[3]) {
- alpha = brush_sample_falloff(ps->brush, dist);
- cp = (char *)((ProjectPixelClone*)projPixel)->clonepx;
- if (alpha >= 1.0) {
- ((char *)projPixel->pixel)[0] = cp[0];
- ((char *)projPixel->pixel)[1] = cp[1];
- ((char *)projPixel->pixel)[2] = cp[2];
- } else {
- ((char *)projPixel->pixel)[0] = FTOCHAR( (((cp[0]/255.0) * alpha) + (((((char *)projPixel->pixel)[0])/255.0)*(1.0-alpha))) );
- ((char *)projPixel->pixel)[1] = FTOCHAR( (((cp[1]/255.0) * alpha) + (((((char *)projPixel->pixel)[1])/255.0)*(1.0-alpha))) );
- ((char *)projPixel->pixel)[2] = FTOCHAR( (((cp[2]/255.0) * alpha) + (((((char *)projPixel->pixel)[2])/255.0)*(1.0-alpha))) );
- }
- }
+ ((char *)projPixel->pixel)[0] = FTOCHAR( (((cp[0]/255.0) * alpha) + (((((char *)projPixel->pixel)[0])/255.0)*(1.0-alpha))) );
+ ((char *)projPixel->pixel)[1] = FTOCHAR( (((cp[1]/255.0) * alpha) + (((((char *)projPixel->pixel)[1])/255.0)*(1.0-alpha))) );
+ ((char *)projPixel->pixel)[2] = FTOCHAR( (((cp[2]/255.0) * alpha) + (((((char *)projPixel->pixel)[2])/255.0)*(1.0-alpha))) );
}
- break;
- case PAINT_TOOL_SMEAR:
- Vec2Subf(co, projPixel->projCo2D, mval_ofs);
- if (screenco_pickcol(ps, co, NULL, rgba_ub, 0)) { /* Note, no interpolation here, only needed for clone, nearest should be is OK */
- brush_sample_tex(ps->brush, projPixel->projCo2D, rgba);
- alpha = rgba[3]*brush_sample_falloff(ps->brush, dist);
- /* drat! - this could almost be very simple if we ignore
- * the fact that applying the color directly gives feedback,
- * instead, collect the colors and apply after :/ */
-
+ }
+ }
+ break;
+ case PAINT_TOOL_SMEAR:
+ Vec2Subf(co, projPixel->projCo2D, mval_ofs);
+ if (screenco_pickcol(ps, co, NULL, rgba_ub, 0)) { /* Note, no interpolation here, only needed for clone, nearest should be is OK */
+ brush_sample_tex(ps->brush, projPixel->projCo2D, rgba);
+ alpha = rgba[3]*brush_sample_falloff(ps->brush, dist);
+ /* drat! - this could almost be very simple if we ignore
+ * the fact that applying the color directly gives feedback,
+ * instead, collect the colors and apply after :/ */
+
#if 0 /* looks OK but not correct - also would need float buffer */
- *((unsigned int *)projPixel->pixel) = IMB_blend_color( *((unsigned int *)projPixel->pixel), *((unsigned int *)rgba_ub), (int)(alpha*255), blend);
+ *((unsigned int *)projPixel->pixel) = IMB_blend_color( *((unsigned int *)projPixel->pixel), *((unsigned int *)rgba_ub), (int)(alpha*255), blend);
#endif
-
- /* add to memarena instead */
- if (is_floatbuf) {
- /* TODO FLOAT */ /* Smear wont do float properly yet */
- char rgba_smear[4];
- IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba_smear, (float *)projPixel->pixel);
- *((unsigned int *) &((ProjectPixelClone *)projPixel)->clonepx) = IMB_blend_color( *((unsigned int *)rgba_smear), *((unsigned int *)rgba_ub), (int)(alpha*255), blend);
- BLI_linklist_prepend_arena( &smearPixels_float, (void *)projPixel, smearArena );
- } else {
- *((unsigned int *) &((ProjectPixelClone *)projPixel)->clonepx) = IMB_blend_color( *((unsigned int *)projPixel->pixel), *((unsigned int *)rgba_ub), (int)(alpha*255), blend);
- BLI_linklist_prepend_arena( &smearPixels, (void *)projPixel, smearArena );
- }
- }
- break;
- default:
- brush_sample_tex(ps->brush, projPixel->projCo2D, rgba);
- alpha = rgba[3]*brush_sample_falloff(ps->brush, dist);
- if (alpha > 0.0) {
- if (is_floatbuf) {
- rgba_fp[0] = rgba[0] * ps->brush->rgb[0];
- rgba_fp[1] = rgba[1] * ps->brush->rgb[1];
- rgba_fp[2] = rgba[2] * ps->brush->rgb[2];
- rgba_fp[3] = rgba[3];
- IMB_blend_color_float( (float *)projPixel->pixel, (float *)projPixel->pixel, rgba_fp, alpha, blend);
- } else {
- rgba_ub[0] = FTOCHAR(rgba[0] * ps->brush->rgb[0]);
- rgba_ub[1] = FTOCHAR(rgba[1] * ps->brush->rgb[1]);
- rgba_ub[2] = FTOCHAR(rgba[2] * ps->brush->rgb[2]);
- rgba_ub[3] = FTOCHAR(rgba[3]);
-
- *((unsigned int *)projPixel->pixel) = IMB_blend_color( *((unsigned int *)projPixel->pixel), *((unsigned int *)rgba_ub), (int)(alpha*255), blend);
- }
- }
- break;
+
+ /* add to memarena instead */
+ if (is_floatbuf) {
+ /* TODO FLOAT */ /* Smear wont do float properly yet */
+ char rgba_smear[4];
+ IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba_smear, (float *)projPixel->pixel);
+ *((unsigned int *) &((ProjectPixelClone *)projPixel)->clonepx) = IMB_blend_color( *((unsigned int *)rgba_smear), *((unsigned int *)rgba_ub), (int)(alpha*255), blend);
+ BLI_linklist_prepend_arena( &smearPixels_float, (void *)projPixel, smearArena );
+ } else {
+ *((unsigned int *) &((ProjectPixelClone *)projPixel)->clonepx) = IMB_blend_color( *((unsigned int *)projPixel->pixel), *((unsigned int *)rgba_ub), (int)(alpha*255), blend);
+ BLI_linklist_prepend_arena( &smearPixels, (void *)projPixel, smearArena );
+ }
+ }
+ break;
+ default:
+ brush_sample_tex(ps->brush, projPixel->projCo2D, rgba);
+ alpha = rgba[3]*brush_sample_falloff(ps->brush, dist);
+ if (alpha > 0.0) {
+ if (is_floatbuf) {
+ rgba_fp[0] = rgba[0] * ps->brush->rgb[0];
+ rgba_fp[1] = rgba[1] * ps->brush->rgb[1];
+ rgba_fp[2] = rgba[2] * ps->brush->rgb[2];
+ rgba_fp[3] = rgba[3];
+ IMB_blend_color_float( (float *)projPixel->pixel, (float *)projPixel->pixel, rgba_fp, alpha, blend);
+ } else {
+ rgba_ub[0] = FTOCHAR(rgba[0] * ps->brush->rgb[0]);
+ rgba_ub[1] = FTOCHAR(rgba[1] * ps->brush->rgb[1]);
+ rgba_ub[2] = FTOCHAR(rgba[2] * ps->brush->rgb[2]);
+ rgba_ub[3] = FTOCHAR(rgba[3]);
+ *((unsigned int *)projPixel->pixel) = IMB_blend_color( *((unsigned int *)projPixel->pixel), *((unsigned int *)rgba_ub), (int)(alpha*255), blend);
}
-
- /* done painting */
}
+ break;
- node = node->next;
- } while (node);
+ }
+
+ /* done painting */
}
- }
+
+ node = node->next;
+ } while (node);
}
}
@@ -2928,20 +3057,109 @@ static int imapaint_paint_sub_stroke_project(ProjectPaintState *ps, BrushPainter
BLI_memarena_free(smearArena);
}
+
/* Loop over all images on this mesh and update any we have touched */
- for (a=0; a < ps->projectImageTotal; a++) {
- Image *ima = ps->projectImages[a];
- if (ima->id.flag & LIB_DOIT) {
- imapaint_image_update(ima, BKE_image_get_ibuf(ima, NULL), 1 /*texpaint*/ );
- redraw = 1;
-
- ima->id.flag &= ~LIB_DOIT; /* clear for reuse */
- }
+ if (ps->thread_tot < 2) { /* only run this if we have no threads */
+ redraw = imapaint_refresh_tagged(ps);
}
return redraw;
}
+
+typedef struct ProjectHandle {
+ /* args */
+ ProjectPaintState *ps;
+ BrushPainter *painter;
+ short prevmval[2];
+ short mval[2];
+ double time;
+ float pressure;
+
+ /* thread settings */
+ int thread_tot;
+ int thread_index;
+ int ready;
+} ProjectHandle;
+
+
+static void *do_projectpaint_thread(void *ph_v)
+{
+ ProjectHandle *ph= ph_v;
+
+ imapaint_paint_sub_stroke_project(
+ ph->ps,
+ ph->painter,
+ ph->prevmval,
+ ph->mval,
+ ph->time,
+ ph->pressure,
+
+ ph->thread_index
+ );
+
+ ph->ready= 1;
+
+ return NULL;
+}
+
+static int imapaint_paint_sub_stroke_project_mt(ProjectPaintState *ps, BrushPainter *painter, short prevmval[2], short mval[2], double time, float pressure)
+{
+ ProjectHandle handles[BLENDER_MAX_THREADS];
+ ListBase threads;
+ int a;
+
+ float mval_f[2];
+ mval_f[0] = mval[0]; mval_f[1] = mval[1];
+
+ if (bucket_iter_init(ps, mval_f)==0)
+ return 0;
+#ifdef PROJ_DEBUG_PRINT_THREADS
+ printf("Begin Threads %d\n", ps->thread_tot);
+#endif
+
+ BLI_init_threads(&threads, do_projectpaint_thread, ps->thread_tot);
+
+ /* get the threads running */
+ for(a=0; a < ps->thread_tot; a++) {
+#ifdef PROJ_DEBUG_PRINT_THREADS
+ printf("INIT THREAD %d\n", a);
+#endif
+
+ /* set defaults in handles */
+ //memset(&handles[a], 0, sizeof(BakeShade));
+
+ handles[a].ps = ps;
+ handles[a].painter = painter;
+ VECCOPY2D(handles[a].prevmval, prevmval);
+ VECCOPY2D(handles[a].mval, mval);
+ handles[a].time = time;
+ handles[a].pressure = pressure;
+
+ /* thread spesific */
+ handles[a].thread_index = a;
+ handles[a].ready = 0;
+
+ BLI_insert_thread(&threads, &handles[a]);
+ }
+
+ /* wait for everything to be done */
+ a= 0;
+ while(a != ps->thread_tot) {
+ PIL_sleep_ms(1);
+
+ for(a=0; a < ps->thread_tot; a++)
+ if(handles[a].ready==0)
+ break;
+ }
+
+ BLI_end_threads(&threads);
+
+ return imapaint_refresh_tagged(ps);
+}
+
+
+
static void imapaint_paint_stroke(ImagePaintState *s, BrushPainter *painter, short texpaint, short *prevmval, short *mval, double time, float pressure)
{
Image *newimage = NULL;
@@ -3027,8 +3245,14 @@ static void imapaint_paint_stroke_project(ProjectPaintState *ps, BrushPainter *p
int redraw_flag = 0;
/* TODO - support more brush operations, airbrush etc */
- {
- redraw_flag |= imapaint_paint_sub_stroke_project(ps, painter, prevmval, mval, time, 1, pressure);
+ if (ps->thread_tot > 1) {
+ redraw_flag |= imapaint_paint_sub_stroke_project_mt(ps, painter, prevmval, mval, time, pressure);
+ } else {
+ float mval_f[2];
+ mval_f[0] = mval[0]; mval_f[1] = mval[1];
+ if (bucket_iter_init(ps, mval_f)) {
+ redraw_flag |= imapaint_paint_sub_stroke_project(ps, painter, prevmval, mval, time, pressure, 0); /* no threads */
+ }
}
if (redraw && redraw_flag) {
@@ -3044,7 +3268,6 @@ static int imapaint_paint_gp_to_stroke(float **points_gp) {
bGPDstroke *gps;
tGPspoint *pt;
- int stroke_gp = 0;
int index_gp = 0;
int tot_gp = 0;
float *vec_gp;
@@ -3140,10 +3363,12 @@ void imagepaint_paint(short mousebutton, short texpaint)
return;
}
- /* TODO - add UI */
+ /* TODO - grease pencil stroke is verry basic now and only useful for benchmarking, should make this nicer */
+ // stroke_gp = 1;
+ /*
if (G.rt==123) {
- stroke_gp = 1;
- }
+
+ }*/
/* initialize state */
memset(&s, 0, sizeof(s));