diff options
Diffstat (limited to 'source/blender/editors/sculpt_paint/paint_image.c')
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_image.c | 220 |
1 files changed, 129 insertions, 91 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 6e921b57d9d..6a8d5043c43 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -44,8 +44,10 @@ #include "BLI_dynstr.h" #include "BLI_linklist.h" #include "BLI_memarena.h" -#include "PIL_time.h" #include "BLI_threads.h" +#include "BLI_utildefines.h" + +#include "PIL_time.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -163,17 +165,17 @@ typedef struct ImagePaintRegion { #define PROJ_DEBUG_WINCLIP 1 /* projectFaceSeamFlags options */ -//#define PROJ_FACE_IGNORE 1<<0 /* When the face is hidden, backfacing or occluded */ -//#define PROJ_FACE_INIT 1<<1 /* When we have initialized the faces data */ -#define PROJ_FACE_SEAM1 1<<0 /* If this face has a seam on any of its edges */ -#define PROJ_FACE_SEAM2 1<<1 -#define PROJ_FACE_SEAM3 1<<2 -#define PROJ_FACE_SEAM4 1<<3 - -#define PROJ_FACE_NOSEAM1 1<<4 -#define PROJ_FACE_NOSEAM2 1<<5 -#define PROJ_FACE_NOSEAM3 1<<6 -#define PROJ_FACE_NOSEAM4 1<<7 +//#define PROJ_FACE_IGNORE (1<<0) /* When the face is hidden, backfacing or occluded */ +//#define PROJ_FACE_INIT (1<<1) /* When we have initialized the faces data */ +#define PROJ_FACE_SEAM1 (1<<0) /* If this face has a seam on any of its edges */ +#define PROJ_FACE_SEAM2 (1<<1) +#define PROJ_FACE_SEAM3 (1<<2) +#define PROJ_FACE_SEAM4 (1<<3) + +#define PROJ_FACE_NOSEAM1 (1<<4) +#define PROJ_FACE_NOSEAM2 (1<<5) +#define PROJ_FACE_NOSEAM3 (1<<6) +#define PROJ_FACE_NOSEAM4 (1<<7) #define PROJ_SRC_VIEW 1 #define PROJ_SRC_IMAGE_CAM 2 @@ -189,8 +191,8 @@ typedef struct ImagePaintRegion { #define PROJ_FACE_SCALE_SEAM 0.99f #define PROJ_BUCKET_NULL 0 -#define PROJ_BUCKET_INIT 1<<0 -// #define PROJ_BUCKET_CLONE_INIT 1<<1 +#define PROJ_BUCKET_INIT (1<<0) +// #define PROJ_BUCKET_CLONE_INIT (1<<1) /* used for testing doubles, if a point is on a line etc */ #define PROJ_GEOM_TOLERANCE 0.00075f @@ -383,7 +385,7 @@ static void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int return tile->rect; if (*tmpibuf==NULL) - *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat|IB_rect, 0); + *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat|IB_rect); tile= MEM_callocN(sizeof(UndoImageTile), "UndoImageTile"); strcpy(tile->idname, ima->id.name); @@ -410,7 +412,7 @@ static void image_undo_restore(bContext *C, ListBase *lb) UndoImageTile *tile; tmpibuf= IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, - IB_rectfloat|IB_rect, 0); + IB_rectfloat|IB_rect); for(tile=lb->first; tile; tile=tile->next) { /* find image based on name, pointer becomes invalid with global undo */ @@ -430,7 +432,8 @@ static void image_undo_restore(bContext *C, ListBase *lb) GPU_free_image(ima); /* force OpenGL reload */ if(ibuf->rect_float) - imb_freerectImBuf(ibuf); /* force recreate of char rect */ + ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */ + } IMB_freeImBuf(tmpibuf); @@ -473,8 +476,6 @@ static int project_bucket_offset_safe(const ProjPaintState *ps, const float proj } } -#define SIDE_OF_LINE(pa, pb, pp) ((pa[0]-pp[0])*(pb[1]-pp[1]))-((pb[0]-pp[0])*(pa[1]-pp[1])) - /* 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 barycentric_weights_v2_persp(float v1[4], float v2[4], float v3[4], float co[2], float w[3]) { @@ -639,9 +640,8 @@ static int project_paint_PickColor(const ProjPaintState *ps, float pt[2], float } } else { - xi = (int)((uv[0]*ibuf->x) + 0.5f); - yi = (int)((uv[1]*ibuf->y) + 0.5f); - + //xi = (int)((uv[0]*ibuf->x) + 0.5f); + //yi = (int)((uv[1]*ibuf->y) + 0.5f); //if (xi<0 || xi>=ibuf->x || yi<0 || yi>=ibuf->y) return 0; /* wrap */ @@ -936,7 +936,7 @@ static int pixel_bounds_array(float (* uv)[2], rcti *bounds_px, const int ibuf_x #ifndef PROJ_DEBUG_NOSEAMBLEED -/* This function returns 1 if this face has a seam along the 2 face-vert indicies +/* This function returns 1 if this face has a seam along the 2 face-vert indices * 'orig_i1_fidx' and 'orig_i2_fidx' */ static int check_seam(const ProjPaintState *ps, const int orig_face, const int orig_i1_fidx, const int orig_i2_fidx, int *other_face, int *orig_fidx) { @@ -949,7 +949,7 @@ static int check_seam(const ProjPaintState *ps, const int orig_face, const int o const MFace *orig_mf = ps->dm_mface + orig_face; const MTFace *orig_tf = ps->dm_mtface + orig_face; - /* vert indicies from face vert order indicies */ + /* vert indices from face vert order indices */ i1 = (*(&orig_mf->v1 + orig_i1_fidx)); i2 = (*(&orig_mf->v1 + orig_i2_fidx)); @@ -1013,8 +1013,11 @@ static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], const fl float puv[4][2]; /* pixelspace uv's */ float no1[2], no2[2], no3[2], no4[2]; /* normals */ float dir1[2], dir2[2], dir3[2], dir4[2]; - float ibuf_inv[2] = {1.0f / (float)ibuf_x, 1.0f / (float)ibuf_y}; - + float ibuf_inv[2]; + + ibuf_inv[0]= 1.0f / (float)ibuf_x; + ibuf_inv[1]= 1.0f / (float)ibuf_y; + /* make UV's in pixel space so we can */ puv[0][0] = orig_uv[0][0] * ibuf_x; puv[0][1] = orig_uv[0][1] * ibuf_y; @@ -1139,6 +1142,7 @@ static void project_face_seams_init(const ProjPaintState *ps, const int face_ind /* TODO - move to arithb.c */ /* little sister we only need to know lambda */ +#ifndef PROJ_DEBUG_NOSEAMBLEED static float lambda_cp_line2(const float p[2], const float l1[2], const float l2[2]) { float h[2], u[2]; @@ -1151,6 +1155,7 @@ static float lambda_cp_line2(const float p[2], const float l1[2], const float l2 return(dot_v2v2(u, h)/dot_v2v2(u, u)); } +#endif // PROJ_DEBUG_NOSEAMBLEED /* Converts a UV location to a 3D screenspace location @@ -1623,6 +1628,7 @@ static int line_clip_rect2f( /* scale the quad & tri about its center * scaling by PROJ_FACE_SCALE_SEAM (0.99x) is used for getting fake UV pixel coords that are on the * edge of the face but slightly inside it occlusion tests dont return hits on adjacent faces */ +#ifndef PROJ_DEBUG_NOSEAMBLEED static void scale_quad(float insetCos[4][3], float *origCos[4], const float inset) { float cent[3]; @@ -1666,7 +1672,7 @@ static void scale_tri(float insetCos[4][3], float *origCos[4], const float inset add_v3_v3(insetCos[1], cent); add_v3_v3(insetCos[2], cent); } - +#endif //PROJ_DEBUG_NOSEAMBLEED static float Vec2Lenf_nosqrt(const float *v1, const float *v2) { @@ -1689,7 +1695,7 @@ static float Vec2Lenf_nosqrt_other(const float *v1, const float v2_1, const floa /* note, use a squared value so we can use Vec2Lenf_nosqrt * be sure that you have done a bounds check first or this may fail */ /* only give bucket_bounds as an arg because we need it elsewhere */ -static int project_bucket_isect_circle(const int bucket_x, const int bucket_y, const float cent[2], const float radius_squared, rctf *bucket_bounds) +static int project_bucket_isect_circle(const float cent[2], const float radius_squared, rctf *bucket_bounds) { /* Would normally to a simple intersection test, however we know the bounds of these 2 already intersect @@ -1852,7 +1858,7 @@ static void project_bucket_clip_face( { int inside_bucket_flag = 0; int inside_face_flag = 0; - const int flip = ((SIDE_OF_LINE(v1coSS, v2coSS, v3coSS) > 0.0f) != (SIDE_OF_LINE(uv1co, uv2co, uv3co) > 0.0f)); + const int flip = ((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) != (line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f)); float bucket_bounds_ss[4][2]; @@ -2134,15 +2140,15 @@ if __name__ == '__main__': /* checks if pt is inside a convex 2D polyline, the polyline must be ordered rotating clockwise - * otherwise it would have to test for mixed (SIDE_OF_LINE > 0.0f) cases */ + * otherwise it would have to test for mixed (line_point_side_v2 > 0.0f) cases */ int IsectPoly2Df(const float pt[2], float uv[][2], const int tot) { int i; - if (SIDE_OF_LINE(uv[tot-1], uv[0], pt) < 0.0f) + if (line_point_side_v2(uv[tot-1], uv[0], pt) < 0.0f) return 0; for (i=1; i<tot; i++) { - if (SIDE_OF_LINE(uv[i-1], uv[i], pt) < 0.0f) + if (line_point_side_v2(uv[i-1], uv[i], pt) < 0.0f) return 0; } @@ -2152,10 +2158,10 @@ int IsectPoly2Df(const float pt[2], float uv[][2], const int tot) static int IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot) { int i; - int side = (SIDE_OF_LINE(uv[tot-1], uv[0], pt) > 0.0f); + int side = (line_point_side_v2(uv[tot-1], uv[0], pt) > 0.0f); for (i=1; i<tot; i++) { - if ((SIDE_OF_LINE(uv[i-1], uv[i], pt) > 0.0f) != side) + if ((line_point_side_v2(uv[i-1], uv[i], pt) > 0.0f) != side) return 0; } @@ -2496,26 +2502,32 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i /* Only bother calculating the weights if we intersect */ if (ps->do_mask_normal || ps->dm_mtface_clone) { -#if 0 - /* This is not QUITE correct since UV is not inside the UV's but good enough for seams */ +#if 1 + /* get the UV on the line since we want to copy the pixels from there for bleeding */ + float uv_close[2]; + float fac= closest_to_line_v2(uv_close, uv, tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2]); + if (fac < 0.0f) copy_v2_v2(uv_close, tf_uv_pxoffset[fidx1]); + else if (fac > 1.0f) copy_v2_v2(uv_close, tf_uv_pxoffset[fidx2]); + if (side) { - barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset[2], tf_uv_pxoffset[3], uv, w); + barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset[2], tf_uv_pxoffset[3], uv_close, w); } else { - barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset[1], tf_uv_pxoffset[2], uv, w); + barycentric_weights_v2(tf_uv_pxoffset[0], tf_uv_pxoffset[1], tf_uv_pxoffset[2], uv_close, w); } -#endif -#if 1 +#else /* this is buggy with quads, dont use for now */ + /* Cheat, we know where we are along the edge so work out the weights from that */ fac = fac1 + (fac * (fac2-fac1)); + w[0]=w[1]=w[2]= 0.0; if (side) { - w[fidx1?fidx1-1:0] = fac; - w[fidx2?fidx2-1:0] = 1.0f-fac; + w[fidx1?fidx1-1:0] = 1.0f-fac; + w[fidx2?fidx2-1:0] = fac; } else { - w[fidx1] = fac; - w[fidx2] = 1.0f-fac; + w[fidx1] = 1.0f-fac; + w[fidx2] = fac; } #endif } @@ -2565,7 +2577,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i } -/* takes floating point screenspace min/max and returns int min/max to be used as indicies for ps->bucketRect, ps->bucketFlags */ +/* takes floating point screenspace min/max and returns int min/max to be used as indices for ps->bucketRect, ps->bucketFlags */ static void project_paint_bucket_bounds(const ProjPaintState *ps, const float min[2], const float max[2], int bucketMin[2], int bucketMax[2]) { /* divide by bucketWidth & bucketHeight so the bounds are offset in bucket grid units */ @@ -2652,7 +2664,7 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index * calculated when it might not be needed later, (at the moment at least) * obviously it shouldn't have bugs though */ -static int project_bucket_face_isect(ProjPaintState *ps, float min[2], float max[2], int bucket_x, int bucket_y, int bucket_index, const MFace *mf) +static int project_bucket_face_isect(ProjPaintState *ps, int bucket_x, int bucket_y, const MFace *mf) { /* TODO - replace this with a tricker method that uses sideofline for all screenCoords's edges against the closest bucket corner */ rctf bucket_bounds; @@ -2712,11 +2724,11 @@ static int project_bucket_face_isect(ProjPaintState *ps, float min[2], float max /* Add faces to the bucket but dont initialize its pixels * TODO - when painting occluded, sort the faces on their min-Z and only add faces that faces that are not occluded */ -static void project_paint_delayed_face_init(ProjPaintState *ps, const MFace *mf, const MTFace *tf, const int face_index) +static void project_paint_delayed_face_init(ProjPaintState *ps, const MFace *mf, const int face_index) { float min[2], max[2], *vCoSS; int bucketMin[2], bucketMax[2]; /* for ps->bucketRect indexing */ - int fidx, bucket_x, bucket_y, bucket_index; + int fidx, bucket_x, bucket_y; int has_x_isect = -1, has_isect = 0; /* for early loop exit */ MemArena *arena = ps->arena_mt[0]; /* just use the first thread arena since threading has not started yet */ @@ -2733,10 +2745,8 @@ static void project_paint_delayed_face_init(ProjPaintState *ps, const MFace *mf, for (bucket_y = bucketMin[1]; bucket_y < bucketMax[1]; bucket_y++) { has_x_isect = 0; for (bucket_x = bucketMin[0]; bucket_x < bucketMax[0]; bucket_x++) { - - bucket_index = bucket_x + (bucket_y * ps->buckets_x); - - if (project_bucket_face_isect(ps, min, max, bucket_x, bucket_y, bucket_index, mf)) { + if (project_bucket_face_isect(ps, bucket_x, bucket_y, mf)) { + int bucket_index= bucket_x + (bucket_y * ps->buckets_x); BLI_linklist_prepend_arena( &ps->bucketFaces[ bucket_index ], SET_INT_IN_POINTER(face_index), /* cast to a pointer to shut up the compiler */ @@ -2820,7 +2830,7 @@ static void project_paint_begin(ProjPaintState *ps) /* Workaround for subsurf selection, try the display mesh first */ if (ps->source==PROJ_SRC_IMAGE_CAM) { /* using render mesh, assume only camera was rendered from */ - ps->dm = mesh_create_derived_render(ps->scene, ps->ob, ps->v3d->customdata_mask | CD_MASK_MTFACE); + ps->dm = mesh_create_derived_render(ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MTFACE); ps->dm_release= TRUE; } else if(ps->ob->derivedFinal && CustomData_has_layer( &ps->ob->derivedFinal->faceData, CD_MTFACE)) { @@ -2828,7 +2838,7 @@ static void project_paint_begin(ProjPaintState *ps) ps->dm_release= FALSE; } else { - ps->dm = mesh_get_derived_final(ps->scene, ps->ob, ps->v3d->customdata_mask | CD_MASK_MTFACE); + ps->dm = mesh_get_derived_final(ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MTFACE); ps->dm_release= TRUE; } @@ -3194,7 +3204,7 @@ static void project_paint_begin(ProjPaintState *ps) } } else { - if (SIDE_OF_LINE(v1coSS, v2coSS, v3coSS) < 0.0f) { + if (line_point_side_v2(v1coSS, v2coSS, v3coSS) < 0.0f) { continue; } @@ -3217,7 +3227,7 @@ static void project_paint_begin(ProjPaintState *ps) if (image_index != -1) { /* Initialize the faces screen pixels */ /* Add this to a list to initialize later */ - project_paint_delayed_face_init(ps, mf, tf, face_index); + project_paint_delayed_face_init(ps, mf, face_index); } } } @@ -3500,7 +3510,7 @@ static int project_bucket_iter_next(ProjPaintState *ps, int *bucket_index, rctf project_bucket_bounds(ps, ps->context_bucket_x, ps->context_bucket_y, bucket_bounds); if ( (ps->source != PROJ_SRC_VIEW) || - project_bucket_isect_circle(ps->context_bucket_x, ps->context_bucket_y, mval, (float)(diameter*diameter), bucket_bounds) + project_bucket_isect_circle(mval, (float)(diameter*diameter), bucket_bounds) ) { *bucket_index = ps->context_bucket_x + (ps->context_bucket_y * ps->buckets_x); ps->context_bucket_x++; @@ -3569,7 +3579,7 @@ static void blend_color_mix_accum(unsigned char *cp, const unsigned char *cp1, c cp[3]= alpha > 255 ? 255 : alpha; } -static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, float *rgba, float alpha, float mask) +static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask) { if (ps->is_airbrush==0 && mask < 1.0f) { projPixel->newColor.uint = IMB_blend_color(projPixel->newColor.uint, ((ProjPixelClone*)projPixel)->clonepx.uint, (int)(alpha*255), ps->blend); @@ -3580,7 +3590,7 @@ static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, floa } } -static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, float *rgba, float alpha, float mask) +static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask) { if (ps->is_airbrush==0 && mask < 1.0f) { IMB_blend_color_float(projPixel->newColor.f, projPixel->newColor.f, ((ProjPixelClone *)projPixel)->clonepx.f, alpha, ps->blend); @@ -3597,7 +3607,7 @@ static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, fl * accumulation of color greater then 'projPixel->mask' however in the case of smear its not * really that important to be correct as it is with clone and painting */ -static void do_projectpaint_smear(ProjPaintState *ps, ProjPixel *projPixel, float *rgba, float alpha, float mask, MemArena *smearArena, LinkNode **smearPixels, float co[2]) +static void do_projectpaint_smear(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask, MemArena *smearArena, LinkNode **smearPixels, float co[2]) { unsigned char rgba_ub[4]; @@ -3608,7 +3618,7 @@ static void do_projectpaint_smear(ProjPaintState *ps, ProjPixel *projPixel, floa BLI_linklist_prepend_arena(smearPixels, (void *)projPixel, smearArena); } -static void do_projectpaint_smear_f(ProjPaintState *ps, ProjPixel *projPixel, float *rgba, float alpha, float mask, MemArena *smearArena, LinkNode **smearPixels_f, float co[2]) +static void do_projectpaint_smear_f(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask, MemArena *smearArena, LinkNode **smearPixels_f, float co[2]) { unsigned char rgba_ub[4]; unsigned char rgba_smear[4]; @@ -3757,6 +3767,7 @@ static void *do_projectpaint_thread(void *ph_v) if (falloff > 0.0f) { if (ps->is_texbrush) { + /* note, for clone and smear, we only use the alpha, could be a special function */ brush_sample_tex(ps->brush, projPixel->projCoSS, rgba, thread_index); alpha = rgba[3]; } else { @@ -3808,20 +3819,20 @@ static void *do_projectpaint_thread(void *ph_v) case PAINT_TOOL_CLONE: if (is_floatbuf) { if (((ProjPixelClone *)projPixel)->clonepx.f[3]) { - do_projectpaint_clone_f(ps, projPixel, rgba, alpha, mask); + do_projectpaint_clone_f(ps, projPixel, alpha, mask); /* rgba isnt used for cloning, only alpha */ } } else { if (((ProjPixelClone*)projPixel)->clonepx.ch[3]) { - do_projectpaint_clone(ps, projPixel, rgba, alpha, mask); + do_projectpaint_clone(ps, projPixel, alpha, mask); /* rgba isnt used for cloning, only alpha */ } } break; case PAINT_TOOL_SMEAR: sub_v2_v2v2(co, projPixel->projCoSS, pos_ofs); - if (is_floatbuf) do_projectpaint_smear_f(ps, projPixel, rgba, alpha, mask, smearArena, &smearPixels_f, co); - else do_projectpaint_smear(ps, projPixel, rgba, alpha, mask, smearArena, &smearPixels, co); + if (is_floatbuf) do_projectpaint_smear_f(ps, projPixel, alpha, mask, smearArena, &smearPixels_f, co); + else do_projectpaint_smear(ps, projPixel, alpha, mask, smearArena, &smearPixels, co); break; default: if (is_floatbuf) do_projectpaint_draw_f(ps, projPixel, rgba, alpha, mask); @@ -3861,7 +3872,7 @@ static void *do_projectpaint_thread(void *ph_v) return NULL; } -static int project_paint_op(void *state, ImBuf *ibufb, float *lastpos, float *pos) +static int project_paint_op(void *state, ImBuf *UNUSED(ibufb), float *lastpos, float *pos) { /* First unpack args from the struct */ ProjPaintState *ps = (ProjPaintState *)state; @@ -3928,7 +3939,7 @@ static int project_paint_op(void *state, ImBuf *ibufb, float *lastpos, float *po } -static int project_paint_sub_stroke(ProjPaintState *ps, BrushPainter *painter, int *prevmval_i, int *mval_i, double time, float pressure) +static int project_paint_sub_stroke(ProjPaintState *ps, BrushPainter *painter, int *UNUSED(prevmval_i), int *mval_i, double time, float pressure) { /* Use mouse coords as floats for projection painting */ @@ -3964,7 +3975,7 @@ static int project_paint_stroke(ProjPaintState *ps, BrushPainter *painter, int * /* Imagepaint Partial Redraw & Dirty Region */ -static void imapaint_clear_partial_redraw() +static void imapaint_clear_partial_redraw(void) { memset(&imapaintpartial, 0, sizeof(imapaintpartial)); } @@ -4012,9 +4023,10 @@ static void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, s { if(ibuf->rect_float) /* TODO - should just update a portion from imapaintpartial! */ - imb_freerectImBuf(ibuf); /* force recreate of char rect */ + ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */ + if(ibuf->mipmap[0]) - imb_freemipmapImBuf(ibuf); + ibuf->userflags |= IB_MIPMAP_INVALID; /* todo: should set_tpage create ->rect? */ if(texpaint || (sima && sima->lock)) { @@ -4181,7 +4193,7 @@ static void imapaint_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos) int a, tot; imapaint_set_region(region, 0, 0, pos[0], pos[1], ibufb->x, ibufb->y); - tot= imapaint_torus_split_region(region, ibuf, ibufb); + tot= imapaint_torus_split_region(region, ibufb, ibuf); for(a=0; a<tot; a++) IMB_rectblend(ibufb, ibuf, region[a].destx, region[a].desty, @@ -4194,7 +4206,7 @@ static ImBuf *imapaint_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos) /* note: allocImbuf returns zero'd memory, so regions outside image will have zero alpha, and hence not be blended onto the image */ int w=ibufb->x, h=ibufb->y, destx=0, desty=0, srcx=pos[0], srcy=pos[1]; - ImBuf *clonebuf= IMB_allocImBuf(w, h, ibufb->depth, ibufb->flags, 0); + ImBuf *clonebuf= IMB_allocImBuf(w, h, ibufb->depth, ibufb->flags); IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h); IMB_rectblend(clonebuf, ibuf, destx, desty, srcx, srcy, w, h, @@ -4387,7 +4399,7 @@ static int imapaint_paint_stroke(ViewContext *vc, ImagePaintState *s, BrushPaint ibuf= BKE_image_get_ibuf(newimage, s->sima? &s->sima->iuser: NULL); if(ibuf && ibuf->rect) - imapaint_pick_uv(s->scene, s->ob, s->me, newfaceindex, mval, newuv); + imapaint_pick_uv(s->scene, s->ob, newfaceindex, mval, newuv); else { newimage = NULL; newuv[0] = newuv[1] = 0.0f; @@ -4398,8 +4410,8 @@ static int imapaint_paint_stroke(ViewContext *vc, ImagePaintState *s, BrushPaint /* see if stroke is broken, and if so finish painting in old position */ if (s->image) { - imapaint_pick_uv(s->scene, s->ob, s->me, s->faceindex, mval, fwuv); - imapaint_pick_uv(s->scene, s->ob, s->me, newfaceindex, prevmval, bkuv); + imapaint_pick_uv(s->scene, s->ob, s->faceindex, mval, fwuv); + imapaint_pick_uv(s->scene, s->ob, newfaceindex, prevmval, bkuv); if (newimage == s->image) breakstroke= texpaint_break_stroke(s->uv, fwuv, bkuv, newuv); @@ -4410,7 +4422,7 @@ static int imapaint_paint_stroke(ViewContext *vc, ImagePaintState *s, BrushPaint fwuv[0]= fwuv[1]= 0.0f; if (breakstroke) { - imapaint_pick_uv(s->scene, s->ob, s->me, s->faceindex, mval, fwuv); + imapaint_pick_uv(s->scene, s->ob, s->faceindex, mval, fwuv); redraw |= imapaint_paint_sub_stroke(s, painter, s->image, texpaint, fwuv, time, 1, pressure); imapaint_clear_partial_redraw(); @@ -4526,6 +4538,8 @@ typedef struct PaintOperation { ViewContext vc; wmTimer *timer; + + short restore_projection; } PaintOperation; static void paint_redraw(bContext *C, ImagePaintState *s, int final) @@ -4611,6 +4625,13 @@ static int texture_paint_init(bContext *C, wmOperator *op) pop->first= 1; op->customdata= pop; + /* XXX: Soften tool does not support projection painting atm, so just disable + projection for this brush */ + if(brush->imagepaint_tool == PAINT_TOOL_SOFTEN) { + settings->imapaint.flag |= IMAGEPAINT_PROJECT_DISABLE; + pop->restore_projection = 1; + } + /* initialize from context */ if(CTX_wm_region_view3d(C)) { pop->mode= PAINT_MODE_3D; @@ -4731,6 +4752,9 @@ static void paint_exit(bContext *C, wmOperator *op) if(pop->timer) WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), pop->timer); + if(pop->restore_projection) + settings->imapaint.flag &= ~IMAGEPAINT_PROJECT_DISABLE; + settings->imapaint.flag &= ~IMAGEPAINT_DRAWING; imapaint_canvas_free(&pop->s); brush_painter_free(pop->painter); @@ -4923,7 +4947,7 @@ static int get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy) /************************ cursor drawing *******************************/ -static void brush_drawcursor(bContext *C, int x, int y, void *customdata) +static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata)) { Brush *brush= image_paint_brush(C); Paint *paint= paint_get_active(CTX_data_scene(C)); @@ -4964,23 +4988,38 @@ static void toggle_paint_cursor(bContext *C, int enable) settings->imapaint.paintcursor= WM_paint_cursor_activate(CTX_wm_manager(C), image_paint_poll, brush_drawcursor, NULL); } +/* enable the paint cursor if it isn't already. + + purpose is to make sure the paint cursor is shown if paint + mode is enabled in the image editor. the paint poll will + ensure that the cursor is hidden when not in paint mode */ +void ED_space_image_paint_update(wmWindowManager *wm, ToolSettings *settings) +{ + ImagePaintSettings *imapaint = &settings->imapaint; + + if(!imapaint->paintcursor) { + imapaint->paintcursor = + WM_paint_cursor_activate(wm, image_paint_poll, + brush_drawcursor, NULL); + } +} + /* ************ image paint radial control *************/ static int paint_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event) { float zoom; ToolSettings *ts = CTX_data_scene(C)->toolsettings; get_imapaint_zoom(C, &zoom, &zoom); - toggle_paint_cursor(C, !ts->imapaint.paintcursor); + toggle_paint_cursor(C, 0); brush_radial_control_invoke(op, paint_brush(&ts->imapaint.paint), zoom); return WM_radial_control_invoke(C, op, event); } static int paint_radial_control_modal(bContext *C, wmOperator *op, wmEvent *event) { - ToolSettings *ts = CTX_data_scene(C)->toolsettings; int ret = WM_radial_control_modal(C, op, event); if(ret != OPERATOR_RUNNING_MODAL) - toggle_paint_cursor(C, !ts->imapaint.paintcursor); + toggle_paint_cursor(C, 1); return ret; } @@ -4989,10 +5028,10 @@ static int paint_radial_control_exec(bContext *C, wmOperator *op) Brush *brush = paint_brush(&CTX_data_scene(C)->toolsettings->imapaint.paint); float zoom; int ret; - char str[256]; + char str[64]; get_imapaint_zoom(C, &zoom, &zoom); ret = brush_radial_control_exec(op, brush, 1.0f / zoom); - WM_radial_control_string(op, str, 256); + WM_radial_control_string(op, str, sizeof(str)); WM_event_add_notifier(C, NC_BRUSH|NA_EDITED, brush); @@ -5087,7 +5126,7 @@ static int grab_clone_modal(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_RUNNING_MODAL; } -static int grab_clone_cancel(bContext *C, wmOperator *op) +static int grab_clone_cancel(bContext *UNUSED(C), wmOperator *op) { MEM_freeN(op->customdata); return OPERATOR_CANCELLED; @@ -5302,7 +5341,7 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op) toggle_paint_cursor(C, 1); } - DAG_id_flush_update(&ob->id, OB_RECALC_DATA); + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_SCENE|ND_MODE, scene); return OPERATOR_FINISHED; @@ -5336,8 +5375,8 @@ static int texture_paint_radial_control_exec(bContext *C, wmOperator *op) { Brush *brush = paint_brush(&CTX_data_scene(C)->toolsettings->imapaint.paint); int ret = brush_radial_control_exec(op, brush, 1); - char str[256]; - WM_radial_control_string(op, str, 256); + char str[64]; + WM_radial_control_string(op, str, sizeof(str)); WM_event_add_notifier(C, NC_BRUSH|NA_EDITED, brush); @@ -5385,13 +5424,11 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op) { Image *image= BLI_findlink(&CTX_data_main(C)->image, RNA_enum_get(op->ptr, "image")); Scene *scene= CTX_data_scene(C); - ProjPaintState ps; + ProjPaintState ps= {0}; int orig_brush_size; IDProperty *idgroup; IDProperty *view_data= NULL; - memset(&ps, 0, sizeof(ps)); - project_state_init(C, OBACT, &ps); if(ps.ob==NULL || ps.ob->type != OB_MESH) { @@ -5415,10 +5452,10 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op) idgroup= IDP_GetProperties(&image->id, 0); if(idgroup) { - view_data= IDP_GetPropertyFromGroup(idgroup, PROJ_VIEW_DATA_ID); + view_data= IDP_GetPropertyTypeFromGroup(idgroup, PROJ_VIEW_DATA_ID, IDP_ARRAY); /* type check to make sure its ok */ - if(view_data->len != PROJ_VIEW_DATA_SIZE || view_data->type != IDP_ARRAY || view_data->subtype != IDP_FLOAT) { + if(view_data->len != PROJ_VIEW_DATA_SIZE || view_data->subtype != IDP_FLOAT) { BKE_report(op->reports, RPT_ERROR, "Image project data invalid."); return OPERATOR_CANCELLED; } @@ -5572,6 +5609,7 @@ void PAINT_OT_image_from_view(wmOperatorType *ot) /* api callbacks */ ot->exec= texture_paint_image_from_view_exec; + ot->poll= ED_operator_region_view3d_active; /* flags */ ot->flag= OPTYPE_REGISTER; |