diff options
Diffstat (limited to 'source/blender/editors/sculpt_paint/paint_image.c')
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_image.c | 197 |
1 files changed, 124 insertions, 73 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 77cd06581fd..1effd8fd377 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -189,7 +189,7 @@ typedef struct ImagePaintPartialRedraw { // #define PROJ_BUCKET_CLONE_INIT 1<<1 /* used for testing doubles, if a point is on a line etc */ -#define PROJ_GEOM_TOLERANCE 0.0002f +#define PROJ_GEOM_TOLERANCE 0.00075f /* vert flags */ #define PROJ_VERT_CULL 1 @@ -238,8 +238,8 @@ typedef struct ProjPaintState { char *faceSeamFlags; /* store info about faces, if they are initialized etc*/ float (*faceSeamUVs)[4][2]; /* expanded UVs for faces to use as seams */ LinkNode **vertFaces; /* Only needed for when seam_bleed_px is enabled, use to find UV seams */ - char *vertFlags; /* store options per vert, now only store if the vert is pointing away from the view */ #endif + char *vertFlags; /* store options per vert, now only store if the vert is pointing away from the view */ int buckets_x; /* The size of the bucket grid, the grid span's screenMin/screenMax so you can paint outsize the screen or with 2 brushes at once */ int buckets_y; @@ -341,7 +341,7 @@ typedef struct UndoTile { typedef struct UndoElem { struct UndoElem *next, *prev; char name[MAXUNDONAME]; - unsigned long undosize; + uintptr_t undosize; ImBuf *ibuf; ListBase tiles; @@ -485,12 +485,12 @@ static void undo_imagepaint_push_begin(char *name) static void undo_imagepaint_push_end() { UndoElem *uel; - unsigned long totmem, maxmem; + uintptr_t totmem, maxmem; if(U.undomemory != 0) { /* limit to maximum memory (afterwards, we can't know in advance) */ totmem= 0; - maxmem= ((unsigned long)U.undomemory)*1024*1024; + maxmem= ((uintptr_t)U.undomemory)*1024*1024; uel= undobase.last; while(uel) { @@ -716,8 +716,8 @@ static int project_paint_PickFace(const ProjPaintState *ps, float pt[2], float w static void uvco_to_wrapped_pxco(float uv[2], int ibuf_x, int ibuf_y, float *x, float *y) { /* use */ - *x = (float)fmod(uv[0], 1.0f); - *y = (float)fmod(uv[1], 1.0f); + *x = (float)fmodf(uv[0], 1.0f); + *y = (float)fmodf(uv[1], 1.0f); if (*x < 0.0f) *x += 1.0f; if (*y < 0.0f) *y += 1.0f; @@ -751,7 +751,7 @@ static int project_paint_PickColor(const ProjPaintState *ps, float pt[2], float Vec2Weightf(uv, tf->uv[0], tf->uv[2], tf->uv[3], w); } - ibuf = BKE_image_get_ibuf((Image *)tf->tpage, NULL); /* TODO - this may be slow, the only way around it is to have an ibuf index per face */ + ibuf = tf->tpage->ibufs.first; /* we must have got the imbuf before getting here */ if (!ibuf) return 0; if (interp) { @@ -760,21 +760,21 @@ static int project_paint_PickColor(const ProjPaintState *ps, float pt[2], float if (ibuf->rect_float) { if (rgba_fp) { - bilinear_interpolation_color(ibuf, NULL, rgba_fp, x, y); + bilinear_interpolation_color_wrap(ibuf, NULL, rgba_fp, x, y); } else { float rgba_tmp_f[4]; - bilinear_interpolation_color(ibuf, NULL, rgba_tmp_f, x, y); + bilinear_interpolation_color_wrap(ibuf, NULL, rgba_tmp_f, x, y); IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba, rgba_tmp_f); } } else { if (rgba) { - bilinear_interpolation_color(ibuf, rgba, NULL, x, y); + bilinear_interpolation_color_wrap(ibuf, rgba, NULL, x, y); } else { unsigned char rgba_tmp[4]; - bilinear_interpolation_color(ibuf, rgba_tmp, NULL, x, y); + bilinear_interpolation_color_wrap(ibuf, rgba_tmp, NULL, x, y); IMAPAINT_CHAR_RGBA_TO_FLOAT(rgba_fp, rgba_tmp); } } @@ -911,7 +911,7 @@ static int project_bucket_point_occluded(const ProjPaintState *ps, LinkNode *buc else isect_ret = project_paint_occlude_ptv(pixelScreenCo, ps->screenCoords[mf->v1], ps->screenCoords[mf->v3], ps->screenCoords[mf->v4], w, ps->is_ortho); } - if (isect_ret==1) { + if (isect_ret>=1) { /* TODO - we may want to cache the first hit, * it is not possible to swap the face order in the list anymore */ return 1; @@ -939,7 +939,7 @@ static int line_isect_y(const float p1[2], const float p2[2], const float y_leve return ISECT_TRUE_P2; } - y_diff= fabs(p1[1]-p2[1]); /* yuck, horizontal line, we cant do much here */ + y_diff= fabsf(p1[1]-p2[1]); /* yuck, horizontal line, we cant do much here */ if (y_diff < 0.000001f) { *x_isect = (p1[0]+p2[0]) * 0.5f; @@ -972,7 +972,7 @@ static int line_isect_x(const float p1[2], const float p2[2], const float x_leve return ISECT_TRUE_P2; } - x_diff= fabs(p1[0]-p2[0]); /* yuck, horizontal line, we cant do much here */ + x_diff= fabsf(p1[0]-p2[0]); /* yuck, horizontal line, we cant do much here */ if (x_diff < 0.000001) { /* yuck, vertical line, we cant do much here */ *y_isect = (p1[0]+p2[0]) * 0.5f; @@ -996,14 +996,15 @@ static int line_isect_x(const float p1[2], const float p2[2], const float x_leve * Its possible this gives incorrect results, when the UVs for 1 face go into the next * tile, but do not do this for the adjacent face, it could return a false positive. * This is so unlikely that Id not worry about it. */ +#ifndef PROJ_DEBUG_NOSEAMBLEED static int cmp_uv(const float vec2a[2], const float vec2b[2]) { /* if the UV's are not between 0.0 and 1.0 */ - float xa = (float)fmod(vec2a[0], 1.0f); - float ya = (float)fmod(vec2a[1], 1.0f); + float xa = (float)fmodf(vec2a[0], 1.0f); + float ya = (float)fmodf(vec2a[1], 1.0f); - float xb = (float)fmod(vec2b[0], 1.0f); - float yb = (float)fmod(vec2b[1], 1.0f); + float xb = (float)fmodf(vec2b[0], 1.0f); + float yb = (float)fmodf(vec2b[1], 1.0f); if (xa < 0.0f) xa += 1.0f; if (ya < 0.0f) ya += 1.0f; @@ -1011,12 +1012,13 @@ static int cmp_uv(const float vec2a[2], const float vec2b[2]) if (xb < 0.0f) xb += 1.0f; if (yb < 0.0f) yb += 1.0f; - return ((fabs(xa-xb) < PROJ_GEOM_TOLERANCE) && (fabs(ya-yb) < PROJ_GEOM_TOLERANCE)) ? 1:0; + return ((fabsf(xa-xb) < PROJ_GEOM_TOLERANCE) && (fabsf(ya-yb) < PROJ_GEOM_TOLERANCE)) ? 1:0; } - +#endif /* set min_px and max_px to the image space bounds of the UV coords * return zero if there is no area in the returned rectangle */ +#ifndef PROJ_DEBUG_NOSEAMBLEED static int pixel_bounds_uv( const float uv1[2], const float uv2[2], const float uv3[2], const float uv4[2], rcti *bounds_px, @@ -1044,6 +1046,7 @@ static int pixel_bounds_uv( /* face uses no UV area when quantized to pixels? */ return (bounds_px->xmin == bounds_px->xmax || bounds_px->ymin == bounds_px->ymax) ? 0 : 1; } +#endif static int pixel_bounds_array(float (* uv)[2], rcti *bounds_px, const int ibuf_x, const int ibuf_y, int tot) { @@ -1151,7 +1154,7 @@ static float angleToLength(float angle) return 1.0f; } else { - return fabs(1.0f / cos(angle * (M_PI/180.0f))); + return fabsf(1.0f / cosf(angle * (M_PI/180.0f))); } } @@ -1384,10 +1387,10 @@ static void project_face_pixel(const MTFace *tf_other, ImBuf *ibuf_other, const if (ibuf_other->rect_float) { /* from float to float */ - bilinear_interpolation_color(ibuf_other, NULL, rgba_f, x, y); + bilinear_interpolation_color_wrap(ibuf_other, NULL, rgba_f, x, y); } else { /* from char to float */ - bilinear_interpolation_color(ibuf_other, rgba_ub, NULL, x, y); + bilinear_interpolation_color_wrap(ibuf_other, rgba_ub, NULL, x, y); } } @@ -1407,7 +1410,7 @@ float project_paint_uvpixel_mask( ImBuf *ibuf_other; const MTFace *tf_other = ps->dm_mtface_mask + face_index; - if (tf_other->tpage && (ibuf_other = BKE_image_get_ibuf((Image *)tf_other->tpage, NULL))) { + if (tf_other->tpage && (ibuf_other = BKE_image_get_ibuf(tf_other->tpage, NULL))) { /* BKE_image_get_ibuf - TODO - this may be slow */ unsigned char rgba_ub[4]; float rgba_f[4]; @@ -1563,7 +1566,7 @@ static ProjPixel *project_paint_uvpixel_init( ImBuf *ibuf_other; const MTFace *tf_other = ps->dm_mtface_clone + face_index; - if (tf_other->tpage && (ibuf_other = BKE_image_get_ibuf((Image *)tf_other->tpage, NULL))) { + if (tf_other->tpage && (ibuf_other = BKE_image_get_ibuf(tf_other->tpage, NULL))) { /* BKE_image_get_ibuf - TODO - this may be slow */ if (ibuf->rect_float) { @@ -1632,7 +1635,7 @@ static int line_clip_rect2f( { /* first account for horizontal, then vertical lines */ /* horiz */ - if (fabs(l1[1]-l2[1]) < PROJ_GEOM_TOLERANCE) { + if (fabsf(l1[1]-l2[1]) < PROJ_GEOM_TOLERANCE) { /* is the line out of range on its Y axis? */ if (l1[1] < rect->ymin || l1[1] > rect->ymax) { return 0; @@ -1643,7 +1646,7 @@ static int line_clip_rect2f( } - if (fabs(l1[0]-l2[0]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/ + if (fabsf(l1[0]-l2[0]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/ if (BLI_in_rctf(rect, l1[0], l1[1])) { VECCOPY2D(l1_clip, l1); VECCOPY2D(l2_clip, l2); @@ -1660,7 +1663,7 @@ static int line_clip_rect2f( CLAMP(l2_clip[0], rect->xmin, rect->xmax); return 1; } - else if (fabs(l1[0]-l2[0]) < PROJ_GEOM_TOLERANCE) { + else if (fabsf(l1[0]-l2[0]) < PROJ_GEOM_TOLERANCE) { /* is the line out of range on its X axis? */ if (l1[0] < rect->xmin || l1[0] > rect->xmax) { return 0; @@ -1671,7 +1674,7 @@ static int line_clip_rect2f( return 0; } - if (fabs(l1[1]-l2[1]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/ + if (fabsf(l1[1]-l2[1]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/ if (BLI_in_rctf(rect, l1[0], l1[1])) { VECCOPY2D(l1_clip, l1); VECCOPY2D(l2_clip, l2); @@ -2015,7 +2018,6 @@ static void project_bucket_clip_face( const int flip = ((SIDE_OF_LINE(v1coSS, v2coSS, v3coSS) > 0.0f) != (SIDE_OF_LINE(uv1co, uv2co, uv3co) > 0.0f)); float bucket_bounds_ss[4][2]; - float w[3]; /* get the UV space bounding box */ inside_bucket_flag |= BLI_in_rctf(bucket_bounds, v1coSS[0], v1coSS[1]); @@ -2086,6 +2088,7 @@ static void project_bucket_clip_face( /* Maximum possible 6 intersections when using a rectangle and triangle */ float isectVCosSS[8][3]; /* The 3rd float is used to store angle for qsort(), NOT as a Z location */ float v1_clipSS[2], v2_clipSS[2]; + float w[3]; /* calc center*/ float cent[2] = {0.0f, 0.0f}; @@ -2128,6 +2131,7 @@ static void project_bucket_clip_face( if ((*tot) < 3) { /* no intersections to speak of */ *tot = 0; + return; } /* now we have all points we need, collect their angles and sort them clockwise */ @@ -2156,16 +2160,15 @@ static void project_bucket_clip_face( for(i=0; i<(*tot); i++) { v2_clipSS[0] = isectVCosSS[i][0] - cent[0]; v2_clipSS[1] = isectVCosSS[i][1] - cent[1]; - isectVCosSS[i][2] = atan2(v1_clipSS[0]*v2_clipSS[1] - v1_clipSS[1]*v2_clipSS[0], v1_clipSS[0]*v2_clipSS[0]+v1_clipSS[1]*v2_clipSS[1]); + isectVCosSS[i][2] = atan2f(v1_clipSS[0]*v2_clipSS[1] - v1_clipSS[1]*v2_clipSS[0], v1_clipSS[0]*v2_clipSS[0]+v1_clipSS[1]*v2_clipSS[1]); } if (flip) qsort(isectVCosSS, *tot, sizeof(float)*3, float_z_sort_flip); else qsort(isectVCosSS, *tot, sizeof(float)*3, float_z_sort); - /* remove doubles */ /* first/last check */ - if (fabs(isectVCosSS[0][0]-isectVCosSS[(*tot)-1][0]) < PROJ_GEOM_TOLERANCE && fabs(isectVCosSS[0][1]-isectVCosSS[(*tot)-1][1]) < PROJ_GEOM_TOLERANCE) { + if (fabsf(isectVCosSS[0][0]-isectVCosSS[(*tot)-1][0]) < PROJ_GEOM_TOLERANCE && fabsf(isectVCosSS[0][1]-isectVCosSS[(*tot)-1][1]) < PROJ_GEOM_TOLERANCE) { (*tot)--; } @@ -2180,8 +2183,8 @@ static void project_bucket_clip_face( while (doubles==TRUE) { doubles = FALSE; for(i=1; i<(*tot); i++) { - if (fabs(isectVCosSS[i-1][0]-isectVCosSS[i][0]) < PROJ_GEOM_TOLERANCE && - fabs(isectVCosSS[i-1][1]-isectVCosSS[i][1]) < PROJ_GEOM_TOLERANCE) + if (fabsf(isectVCosSS[i-1][0]-isectVCosSS[i][0]) < PROJ_GEOM_TOLERANCE && + fabsf(isectVCosSS[i-1][1]-isectVCosSS[i][1]) < PROJ_GEOM_TOLERANCE) { int j; for(j=i+1; j<(*tot); j++) { @@ -2309,6 +2312,19 @@ int IsectPoly2Df(const float pt[2], float uv[][2], const int tot) return 1; } +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); + + for (i=1; i<tot; i++) { + if ((SIDE_OF_LINE(uv[i-1], uv[i], pt) > 0.0f) != side) + return 0; + + } + + return 1; +} /* One of the most important function for projectiopn painting, since it selects the pixels to be added into each bucket. * initialize pixels from this face where it intersects with the bucket_index, optionally initialize pixels for removing seams */ @@ -2352,6 +2368,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i float uv_clip[8][2]; int uv_clip_tot; const short is_ortho = ps->is_ortho; + const short do_backfacecull = ps->do_backfacecull; vCo[0] = ps->dm_mvert[mf->v1].co; vCo[1] = ps->dm_mvert[mf->v2].co; @@ -2361,9 +2378,20 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i /* Use tf_uv_pxoffset instead of tf->uv so we can offset the UV half a pixel * this is done so we can avoid offseting all the pixels by 0.5 which causes * problems when wrapping negative coords */ - xhalfpx = 0.5f / ibuf_xf; - yhalfpx = 0.5f / ibuf_yf; - + xhalfpx = (0.5f+ (PROJ_GEOM_TOLERANCE/3.0f) ) / ibuf_xf; + yhalfpx = (0.5f+ (PROJ_GEOM_TOLERANCE/4.0f) ) / ibuf_yf; + + /* Note about (PROJ_GEOM_TOLERANCE/x) above... + Needed to add this offset since UV coords are often quads aligned to pixels. + In this case pixels can be exactly between 2 triangles causing nasty + artifacts. + + This workaround can be removed and painting will still work on most cases + but since the first thing most people try is painting onto a quad- better make it work. + */ + + + tf_uv_pxoffset[0][0] = tf->uv[0][0] - xhalfpx; tf_uv_pxoffset[0][1] = tf->uv[0][1] - yhalfpx; @@ -2399,8 +2427,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i v1coSS = ps->screenCoords[ (*(&mf->v1 + i1)) ]; v2coSS = ps->screenCoords[ (*(&mf->v1 + i2)) ]; v3coSS = ps->screenCoords[ (*(&mf->v1 + i3)) ]; - - + /* This funtion gives is a concave polyline in UV space from the clipped quad and tri*/ project_bucket_clip_face( is_ortho, bucket_bounds, @@ -2408,8 +2435,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i uv1co, uv2co, uv3co, uv_clip, &uv_clip_tot ); - - + /* sometimes this happens, better just allow for 8 intersectiosn even though there should be max 6 */ /* if (uv_clip_tot>6) { @@ -2431,7 +2457,10 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i //uv[0] = (((float)x) + 0.5f) / ibuf->x; uv[0] = (float)x / ibuf_xf; /* use pixel offset UV coords instead */ - if (IsectPoly2Df(uv, uv_clip, uv_clip_tot)) { + /* Note about IsectPoly2Df_twoside, checking the face or uv flipping doesnt work, + * could check the poly direction but better to do this */ + if( (do_backfacecull && IsectPoly2Df(uv, uv_clip, uv_clip_tot)) || + (do_backfacecull==0 && IsectPoly2Df_twoside(uv, uv_clip, uv_clip_tot))) { has_x_isect = has_isect = 1; @@ -2518,7 +2547,6 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i float (*outset_uv)[2] = ps->faceSeamUVs[face_index]; float insetCos[4][3]; /* inset face coords. NOTE!!! ScreenSace for ortho, Worldspace in prespective view */ - float *uv_seam_quad[4]; float fac; float *vCoSS[4]; /* vertex screenspace coords */ @@ -2574,16 +2602,11 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i fac1 = Vec2Lenf(vCoSS[fidx1], bucket_clip_edges[0]) / ftot; fac2 = Vec2Lenf(vCoSS[fidx1], bucket_clip_edges[1]) / ftot; - uv_seam_quad[0] = tf_uv_pxoffset[fidx1]; - uv_seam_quad[1] = tf_uv_pxoffset[fidx2]; - uv_seam_quad[2] = outset_uv[fidx2]; - uv_seam_quad[3] = outset_uv[fidx1]; - - Vec2Lerpf(seam_subsection[0], uv_seam_quad[0], uv_seam_quad[1], fac1); - Vec2Lerpf(seam_subsection[1], uv_seam_quad[0], uv_seam_quad[1], fac2); - - Vec2Lerpf(seam_subsection[2], uv_seam_quad[3], uv_seam_quad[2], fac2); - Vec2Lerpf(seam_subsection[3], uv_seam_quad[3], uv_seam_quad[2], fac1); + Vec2Lerpf(seam_subsection[0], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac1); + Vec2Lerpf(seam_subsection[1], tf_uv_pxoffset[fidx1], tf_uv_pxoffset[fidx2], fac2); + + Vec2Lerpf(seam_subsection[2], outset_uv[fidx1], outset_uv[fidx2], fac2); + Vec2Lerpf(seam_subsection[3], outset_uv[fidx1], outset_uv[fidx2], fac1); /* if the bucket_clip_edges values Z values was kept we could avoid this * Inset needs to be added so occlusion tests wont hit adjacent faces */ @@ -2636,14 +2659,28 @@ 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) { - /* TODO, this is not QUITE correct since UV is not inside the UV's but good enough for seams */ +#if 0 + /* This is not QUITE correct since UV is not inside the UV's but good enough for seams */ if (side) { BarycentricWeights2f(uv, tf_uv_pxoffset[0], tf_uv_pxoffset[2], tf_uv_pxoffset[3], w); } else { BarycentricWeights2f(uv, tf_uv_pxoffset[0], tf_uv_pxoffset[1], tf_uv_pxoffset[2], w); } - +#endif +#if 1 + /* 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.0-fac; + } + else { + w[fidx1] = fac; + w[fidx2] = 1.0-fac; + } +#endif } /* a pitty we need to get the worldspace pixel location here */ @@ -3076,7 +3113,7 @@ static void project_paint_begin(ProjPaintState *ps) 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); + /* 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 */ @@ -3232,7 +3269,7 @@ static void project_paint_begin(ProjPaintState *ps) image_index = BLI_linklist_index(image_LinkList, tf->tpage); - if (image_index==-1 && BKE_image_get_ibuf((Image *)tf->tpage, NULL)) { /* MemArena dosnt have an append func */ + if (image_index==-1 && BKE_image_get_ibuf(tf->tpage, NULL)) { /* MemArena dosnt have an append func */ BLI_linklist_append(&image_LinkList, tf->tpage); image_index = ps->image_tot; ps->image_tot++; @@ -3254,10 +3291,10 @@ static void project_paint_begin(ProjPaintState *ps) for (node= image_LinkList, i=0; node; node= node->next, i++, projIma++) { projIma->ima = node->link; - // calloced - projIma->touch = 0; + projIma->touch = 0; projIma->ibuf = BKE_image_get_ibuf(projIma->ima, NULL); projIma->partRedrawRect = BLI_memarena_alloc(arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); - // calloced - memset(projIma->partRedrawRect, 0, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); + memset(projIma->partRedrawRect, 0, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED); } /* we have built the array, discard the linked list */ @@ -3308,6 +3345,7 @@ static void project_paint_end(ProjPaintState *ps) int size = sizeof(UndoTile **) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->y); last_projIma->undoRect = (UndoTile **) BLI_memarena_alloc(arena, size); memset(last_projIma->undoRect, 0, size); + last_projIma->ibuf->userflags |= IB_BITMAPDIRTY; } for (bucket_index = 0; bucket_index < bucket_tot; bucket_index++) { @@ -3375,15 +3413,16 @@ static void project_paint_end(ProjPaintState *ps) MEM_freeN(ps->bucketFaces); MEM_freeN(ps->bucketFlags); +#ifndef PROJ_DEBUG_NOSEAMBLEED if (ps->seam_bleed_px > 0.0f) { MEM_freeN(ps->vertFaces); MEM_freeN(ps->faceSeamFlags); MEM_freeN(ps->faceSeamUVs); } +#endif if (ps->vertFlags) MEM_freeN(ps->vertFlags); - for (a=0; a<ps->thread_tot; a++) { BLI_memarena_free(ps->arena_mt[a]); } @@ -3411,7 +3450,7 @@ static void partial_redraw_array_init(ImagePaintPartialRedraw *pr) static int partial_redraw_array_merge(ImagePaintPartialRedraw *pr, ImagePaintPartialRedraw *pr_other, int tot) { - int touch; + int touch= 0; while (tot--) { pr->x1 = MIN2(pr->x1, pr_other->x1); pr->y1 = MIN2(pr->y1, pr_other->y1); @@ -3539,6 +3578,7 @@ static void blend_color_mix(unsigned char *cp, const unsigned char *cp1, const u cp[0]= (mfac*cp1[0]+fac*cp2[0])/255; cp[1]= (mfac*cp1[1]+fac*cp2[1])/255; cp[2]= (mfac*cp1[2]+fac*cp2[2])/255; + cp[3]= (mfac*cp1[3]+fac*cp2[3])/255; } static void blend_color_mix_float(float *cp, const float *cp1, const float *cp2, const float fac) @@ -3547,6 +3587,7 @@ static void blend_color_mix_float(float *cp, const float *cp1, const float *cp2, cp[0]= mfac*cp1[0] + fac*cp2[0]; cp[1]= mfac*cp1[1] + fac*cp2[1]; cp[2]= mfac*cp1[2] + fac*cp2[2]; + cp[3]= mfac*cp1[3] + fac*cp2[3]; } static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, float *rgba, float alpha, float mask) @@ -3583,8 +3624,8 @@ static void do_projectpaint_smear(ProjPaintState *ps, ProjPixel *projPixel, floa if (project_paint_PickColor(ps, co, NULL, rgba_ub, 1)==0) return; - - ((ProjPixelClone *)projPixel)->clonepx.uint = IMB_blend_color(*projPixel->pixel.uint_pt, *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend); + /* ((ProjPixelClone *)projPixel)->clonepx.uint = IMB_blend_color(*projPixel->pixel.uint_pt, *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend); */ + blend_color_mix(((ProjPixelClone *)projPixel)->clonepx.ch, projPixel->pixel.ch_pt, rgba_ub, (int)(alpha*mask*255)); BLI_linklist_prepend_arena(smearPixels, (void *)projPixel, smearArena); } @@ -3597,7 +3638,8 @@ static void do_projectpaint_smear_f(ProjPaintState *ps, ProjPixel *projPixel, fl return; IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba_smear, projPixel->pixel.f_pt); - ((ProjPixelClone *)projPixel)->clonepx.uint = IMB_blend_color(*((unsigned int *)rgba_smear), *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend); + /* (ProjPixelClone *)projPixel)->clonepx.uint = IMB_blend_color(*((unsigned int *)rgba_smear), *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend); */ + blend_color_mix(((ProjPixelClone *)projPixel)->clonepx.ch, rgba_smear, (rgba_ub), (int)(alpha*mask*255)); BLI_linklist_prepend_arena(smearPixels_f, (void *)projPixel, smearArena); } @@ -3708,12 +3750,12 @@ static void *do_projectpaint_thread(void *ph_v) projPixel = (ProjPixel *)node->link; - /*dist = Vec2Lenf(projPixel->projCoSS, pos);*/ /* correct but uses a sqrt */ + /*dist = Vec2Lenf(projPixel->projCoSS, pos);*/ /* correct but uses a sqrtf */ dist_nosqrt = Vec2Lenf_nosqrt(projPixel->projCoSS, pos); - /*if (dist < s->brush->size) {*/ /* correct but uses a sqrt */ + /*if (dist < s->brush->size) {*/ /* correct but uses a sqrtf */ if (dist_nosqrt < brush_size_sqared) { - falloff = brush_sample_falloff_noalpha(ps->brush, sqrt(dist_nosqrt)); + falloff = brush_sample_falloff_noalpha(ps->brush, sqrtf(dist_nosqrt)); if (falloff > 0.0f) { if (ps->is_texbrush) { brush_sample_tex(ps->brush, projPixel->projCoSS, rgba); @@ -3802,10 +3844,9 @@ static void *do_projectpaint_thread(void *ph_v) *projPixel->pixel.uint_pt = ((ProjPixelClone *)projPixel)->clonepx.uint; } - for (node= smearPixels_f; node; node= node->next) { /* this wont run for a float image */ + for (node= smearPixels_f; node; node= node->next) { projPixel = node->link; IMAPAINT_CHAR_RGBA_TO_FLOAT(projPixel->pixel.f_pt, ((ProjPixelClone *)projPixel)->clonepx.ch); - node = node->next; } BLI_memarena_free(smearArena); @@ -4261,7 +4302,7 @@ static int imapaint_paint_stroke(ViewContext *vc, ImagePaintState *s, BrushPaint ) { ImBuf *ibuf; - newimage = (Image*)((s->me->mtface+newfaceindex)->tpage); + newimage = (s->me->mtface+newfaceindex)->tpage; ibuf= BKE_image_get_ibuf(newimage, s->sima? &s->sima->iuser: NULL); if(ibuf && ibuf->rect) @@ -4399,6 +4440,7 @@ typedef struct PaintOperation { int first; int prevmouse[2]; + int brush_size_orig; double starttime; ViewContext vc; @@ -4485,6 +4527,8 @@ static int paint_init(bContext *C, wmOperator *op) pop->ps.brush = pop->s.brush; pop->ps.tool = pop->s.tool; pop->ps.blend = pop->s.blend; + + pop->brush_size_orig = pop->ps.brush->size; /* not nice hack because 1 size brushes always fail with projection paint */ } if(pop->mode != PAINT_MODE_2D) { @@ -4504,6 +4548,10 @@ static int paint_init(bContext *C, wmOperator *op) return 0; } + + /* Dont allow brush size below 2 */ + if (pop->ps.brush->size<=1) + pop->ps.brush->size = 2; } /* note, if we have no UVs on the derived mesh, then we must return here */ @@ -4602,8 +4650,10 @@ static void paint_exit(bContext *C, wmOperator *op) imapaint_canvas_free(&pop->s); brush_painter_free(pop->painter); - if(pop->mode == PAINT_MODE_3D_PROJECT) + if(pop->mode == PAINT_MODE_3D_PROJECT) { + pop->ps.brush->size = pop->brush_size_orig; project_paint_end(&pop->ps); + } paint_redraw(C, &pop->s, 1); undo_imagepaint_push_end(); @@ -5186,3 +5236,4 @@ void PAINT_OT_texture_paint_radial_control(wmOperatorType *ot) ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; } + |