Image paint: 2D painting now supports texture masks and does masking more
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Sun, 12 May 2013 09:14:13 +0000 (09:14 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Sun, 12 May 2013 09:14:13 +0000 (09:14 +0000)
consistent with projection painting.

Also did some refactoring of this code, moving the brush image creation code
out of brush.c and making it consistent with image updating code.

source/blender/blenkernel/BKE_brush.h
source/blender/blenkernel/intern/brush.c
source/blender/editors/sculpt_paint/paint_image_2d.c
source/blender/editors/sculpt_paint/paint_image_proj.c
source/blender/imbuf/IMB_imbuf.h
source/blender/imbuf/intern/rectop.c
source/gameengine/VideoTexture/ImageBuff.cpp

index 60c50b989fbbdb33caf71065fb08606024735c50..9990aeda92b8035ff9b6288c77533f4c939b9ce9 100644 (file)
@@ -81,12 +81,6 @@ float BKE_brush_sample_tex_3D(const Scene *scene, struct Brush *br, const float
 float BKE_brush_sample_masktex(const Scene *scene, struct Brush *br, const float point[3],
                                const int thread, struct ImagePool *pool);
 
-enum BrushImBufFill { BRUSH_IMBUF_MASK, BRUSH_IMBUF_TEX, BRUSH_IMBUF_TEX_MASK };
-void BKE_brush_imbuf_new(const struct Scene *scene, struct Brush *brush, bool use_float,
-                         enum BrushImBufFill fill, int size, struct ImBuf **imbuf,
-                         bool use_color_correction, bool use_brush_alpha,
-                         struct ImagePool *pool, struct rctf *mapping);
-
 /* texture */
 unsigned int *BKE_brush_gen_texture_cache(struct Brush *br, int half_side);
 
index 621c41c3df70189f0cddfc9efdcad50cb1e6dbeb..a8c78b430be3ea54a7c81109dc4223669df57470 100644 (file)
@@ -758,122 +758,6 @@ float BKE_brush_sample_masktex(const Scene *scene, Brush *br,
        return intensity;
 }
 
-static void brush_imbuf_tex_co(rctf *mapping, int x, int y, float texco[3])
-{
-       texco[0] = mapping->xmin + x * mapping->xmax;
-       texco[1] = mapping->ymin + y * mapping->ymax;
-       texco[2] = 0.0f;
-}
-
-/* NOTE: only used for 2d brushes currently! and needs to stay in sync
- * with brush_painter_2d_do_partial */
-void BKE_brush_imbuf_new(const Scene *scene, Brush *brush, bool use_float,
-                         enum BrushImBufFill fill, int bufsize,
-                         ImBuf **outbuf, bool use_color_correction, bool use_brush_alpha,
-                         struct ImagePool *pool, rctf *mapping)
-{
-       ImBuf *ibuf;
-       float xy[2], texco[3], rgba[4], *dstf;
-       int x, y, rowbytes, xoff, yoff, imbflag;
-       const int radius = BKE_brush_size_get(scene, brush);
-       unsigned char *dst, crgb[3];
-       const float alpha = (use_brush_alpha)? BKE_brush_alpha_get(scene, brush): 1.0f;
-       float brush_rgb[3] = {1.0f, 1.0f, 1.0f};
-       int thread = 0;
-
-       imbflag = (use_float) ? IB_rectfloat : IB_rect;
-       xoff = -bufsize / 2.0f + 0.5f;
-       yoff = -bufsize / 2.0f + 0.5f;
-       rowbytes = bufsize * 4;
-
-       if (*outbuf)
-               ibuf = *outbuf;
-       else
-               ibuf = IMB_allocImBuf(bufsize, bufsize, 32, imbflag);
-
-       if (use_float) {
-               if (brush->imagepaint_tool == PAINT_TOOL_DRAW) {
-                       copy_v3_v3(brush_rgb, brush->rgb);
-                       if (use_color_correction) {
-                               srgb_to_linearrgb_v3_v3(brush_rgb, brush_rgb);
-                       }
-               }
-
-               for (y = 0; y < ibuf->y; y++) {
-                       dstf = ibuf->rect_float + y * rowbytes;
-
-                       for (x = 0; x < ibuf->x; x++, dstf += 4) {
-                               xy[0] = x + xoff;
-                               xy[1] = y + yoff;
-
-                               if (fill == BRUSH_IMBUF_MASK) {
-                                       copy_v3_v3(dstf, brush_rgb);
-                                       dstf[3] = alpha * BKE_brush_curve_strength_clamp(brush, len_v2(xy), radius);
-                               }
-                               else if (fill == BRUSH_IMBUF_TEX) {
-                                       brush_imbuf_tex_co(mapping, x, y, texco);
-                                       BKE_brush_sample_tex_3D(scene, brush, texco, dstf, thread, pool);
-                               }
-                               else { /* if (fill == BRUSH_IMBUF_TEX_MASK) */
-                                       brush_imbuf_tex_co(mapping, x, y, texco);
-                                       BKE_brush_sample_tex_3D(scene, brush, texco, rgba, thread, pool);
-
-                                       mul_v3_v3v3(dstf, rgba, brush_rgb);
-                                       dstf[3] = rgba[3] * alpha * BKE_brush_curve_strength_clamp(brush, len_v2(xy), radius);
-                               }
-
-                               /* output premultiplied alpha image */
-                               dstf[0] *= dstf[3];
-                               dstf[1] *= dstf[3];
-                               dstf[2] *= dstf[3];
-                       }
-               }
-       }
-       else {
-               float alpha_f; /* final float alpha to convert to char */
-
-               if (brush->imagepaint_tool == PAINT_TOOL_DRAW)
-                       copy_v3_v3(brush_rgb, brush->rgb);
-
-               rgb_float_to_uchar(crgb, brush->rgb);
-
-               for (y = 0; y < ibuf->y; y++) {
-                       dst = (unsigned char *)ibuf->rect + y * rowbytes;
-
-                       for (x = 0; x < ibuf->x; x++, dst += 4) {
-                               xy[0] = x + xoff;
-                               xy[1] = y + yoff;
-
-                               if (fill == BRUSH_IMBUF_MASK) {
-                                       alpha_f = alpha * BKE_brush_curve_strength_clamp(brush, len_v2(xy), radius);
-
-                                       dst[0] = crgb[0];
-                                       dst[1] = crgb[1];
-                                       dst[2] = crgb[2];
-                                       dst[3] = FTOCHAR(alpha_f);
-                               }
-                               else if (fill == BRUSH_IMBUF_TEX) {
-                                       brush_imbuf_tex_co(mapping, x, y, texco);
-                                       BKE_brush_sample_tex_3D(scene, brush, texco, rgba, thread, pool);
-                                       rgba_float_to_uchar(dst, rgba);
-                               }
-                               else { /* if (fill == BRUSH_IMBUF_TEX_MASK) */
-                                       brush_imbuf_tex_co(mapping, x, y, texco);
-                                       BKE_brush_sample_tex_3D(scene, brush, texco, rgba, thread, pool);
-
-                                       mul_v3_v3(rgba, brush_rgb);
-                                       alpha_f = rgba[3] * alpha * BKE_brush_curve_strength_clamp(brush, len_v2(xy), radius);
-
-                                       rgb_float_to_uchar(dst, rgba);
-                                       dst[3] = FTOCHAR(alpha_f);
-                               }
-                       }
-               }
-       }
-
-       *outbuf = ibuf;
-}
-
 /* Unified Size and Strength */
 
 /* XXX: be careful about setting size and unprojected radius
index efb810455b781bdd2a8e7dc6c114428dd1c6ac21..55dd96eff36ae9d50186bcd56acad729538f5963 100644 (file)
@@ -88,17 +88,24 @@ BLI_INLINE unsigned char f_to_char(const float val)
 #define IMAPAINT_FLOAT_RGB_COPY(a, b) copy_v3_v3(a, b)
 
 typedef struct BrushPainterCache {
-       int size;           /* size override, if 0 uses 2*BKE_brush_size_get(brush) */
-       short flt;          /* need float imbuf? */
+       int size;                    /* size override, if 0 uses 2*BKE_brush_size_get(brush) */
+
+       bool use_float;              /* need float imbuf? */
+       bool use_color_correction;   /* use color correction for float */
+       bool use_masking;            /* use masking? */
+
+       bool is_texbrush;
+       bool is_maskbrush;
 
        int lastsize;
        float lastalpha;
        float lastjitter;
-       float last_rotation;
+       float last_tex_rotation;
+       float last_mask_rotation;
 
        ImBuf *ibuf;
        ImBuf *texibuf;
-       ImBuf *maskibuf;
+       unsigned short *mask;
 } BrushPainterCache;
 
 typedef struct BrushPainter {
@@ -111,7 +118,8 @@ typedef struct BrushPainter {
        short firsttouch;       /* first paint op */
 
        struct ImagePool *pool; /* image pool */
-       rctf mapping;                   /* texture coordinate mapping */
+       rctf tex_mapping;               /* texture coordinate mapping */
+       rctf mask_mapping;              /* mask texture coordinate mapping */
 
        BrushPainterCache cache;
 } BrushPainter;
@@ -161,144 +169,314 @@ static BrushPainter *brush_painter_2d_new(Scene *scene, Brush *brush)
 }
 
 
-static void brush_painter_2d_require_imbuf(BrushPainter *painter, short flt, int size)
+static void brush_painter_2d_require_imbuf(BrushPainter *painter, bool use_float, bool use_color_correction, bool use_masking)
 {
-       if ((painter->cache.flt != flt) || (painter->cache.size != size)) {
+       Brush *brush = painter->brush;
+
+       if ((painter->cache.use_float != use_float)) {
                if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf);
-               if (painter->cache.maskibuf) IMB_freeImBuf(painter->cache.maskibuf);
-               painter->cache.ibuf = painter->cache.maskibuf = NULL;
+               if (painter->cache.mask) MEM_freeN(painter->cache.mask);
+               painter->cache.ibuf = NULL;
+               painter->cache.mask = NULL;
                painter->cache.lastsize = -1; /* force ibuf create in refresh */
        }
 
-       if (painter->cache.flt != flt) {
+       if (painter->cache.use_float != use_float) {
                if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf);
                painter->cache.texibuf = NULL;
                painter->cache.lastsize = -1; /* force ibuf create in refresh */
        }
 
-       painter->cache.size = size;
-       painter->cache.flt = flt;
+       painter->cache.use_float = use_float;
+       painter->cache.use_color_correction = use_float && use_color_correction;
+       painter->cache.use_masking = use_masking;
+       painter->cache.is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? true : false;
+       painter->cache.is_maskbrush = (brush->mask_mtex.tex) ? true : false;
 }
 
 static void brush_painter_2d_free(BrushPainter *painter)
 {
        if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf);
        if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf);
-       if (painter->cache.maskibuf) IMB_freeImBuf(painter->cache.maskibuf);
+       if (painter->cache.mask) MEM_freeN(painter->cache.mask);
        MEM_freeN(painter);
 }
 
-static void brush_painter_2d_do_partial(BrushPainter *painter, ImBuf *oldtexibuf,
-                                     int x, int y, int w, int h, int xt, int yt,
-                                     const float pos[2])
+static void brush_imbuf_tex_co(rctf *mapping, int x, int y, float texco[3])
+{
+       texco[0] = mapping->xmin + x * mapping->xmax;
+       texco[1] = mapping->ymin + y * mapping->ymax;
+       texco[2] = 0.0f;
+}
+
+/* create a mask with the falloff strength and optionally brush alpha */
+static unsigned short *brush_painter_mask_new(BrushPainter *painter, int size)
 {
        Scene *scene = painter->scene;
        Brush *brush = painter->brush;
-       ImBuf *ibuf, *maskibuf, *texibuf;
-       float *bf, *mf, *tf, *otf = NULL, texco[3], rgba[4];
-       unsigned char *b, *m, *t, *ot = NULL;
-       int dotexold, origx = x, origy = y;
-       int thread = 0;
-       rctf mapping = painter->mapping;
-
-       if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_TILED) {
-               mapping.xmin += (int)pos[0] - (int)painter->startpaintpos[0];
-               mapping.ymin += (int)pos[1] - (int)painter->startpaintpos[1];
-       }
-
-       ibuf = painter->cache.ibuf;
-       texibuf = painter->cache.texibuf;
-       maskibuf = painter->cache.maskibuf;
-
-       dotexold = (oldtexibuf != NULL);
-
-       /* not sure if it's actually needed or it's a mistake in coords/sizes
-        * calculation in brush_painter_fixed_tex_partial_update(), but without this
-        * limitation memory gets corrupted at fast strokes with quite big spacing (sergey) */
-       w = min_ii(w, ibuf->x);
-       h = min_ii(h, ibuf->y);
-
-       if (painter->cache.flt) {
-               for (; y < h; y++) {
-                       bf = ibuf->rect_float + (y * ibuf->x + origx) * 4;
-                       tf = texibuf->rect_float + (y * texibuf->x + origx) * 4;
-                       mf = maskibuf->rect_float + (y * maskibuf->x + origx) * 4;
-
-                       if (dotexold)
-                               otf = oldtexibuf->rect_float + ((y - origy + yt) * oldtexibuf->x + xt) * 4;
-
-                       for (x = origx; x < w; x++, bf += 4, mf += 4, tf += 4) {
-                               if (dotexold) {
-                                       copy_v4_v4(tf, otf);
-                                       otf += 4;
-                               }
-                               else {
-                                       texco[0] = mapping.xmin + x * mapping.xmax;
-                                       texco[1] = mapping.ymin + y * mapping.ymax;
-                                       texco[2] = 0.0f;
+       bool use_masking = painter->cache.use_masking;
 
-                                       BKE_brush_sample_tex_3D(scene, brush, texco, tf, thread, painter->pool);
-                               }
+       float alpha = (use_masking)? 1.0f: BKE_brush_alpha_get(scene, brush);
+       int radius = BKE_brush_size_get(scene, brush);
+       int xoff = -size * 0.5f + 0.5f;
+       int yoff = -size * 0.5f + 0.5f;
 
-                               /* output premultiplied float image, mf was already premultiplied */
-                               bf[0] = tf[0] * tf[3] * mf[0];
-                               bf[1] = tf[1] * tf[3] * mf[1];
-                               bf[2] = tf[2] * tf[3] * mf[2];
-                               bf[3] = tf[3] * tf[3] * mf[3];
+       unsigned short *mask, *m;
+       int x, y;
+
+       mask = MEM_callocN(sizeof(unsigned short)*size*size, "brush_painter_mask");
+       m = mask;
+
+       for (y = 0; y < size; y++) {
+               for (x = 0; x < size; x++, m++) {
+                       float xy[2] = {x + xoff, y + yoff};
+                       float len = len_v2(xy);
+                       float strength = alpha;
+
+                       strength *= BKE_brush_curve_strength_clamp(brush, len, radius);
+
+                       *m = (unsigned short)(65535.0f * strength);
+               }
+       }
+
+       return mask;
+}
+
+/* create imbuf with brush color */
+static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size)
+{
+       Scene *scene = painter->scene;
+       Brush *brush = painter->brush;
+
+       rctf tex_mapping = painter->tex_mapping;
+       rctf mask_mapping = painter->mask_mapping;
+       struct ImagePool *pool = painter->pool;
+
+       bool use_masking = painter->cache.use_masking;
+       bool use_color_correction = painter->cache.use_color_correction;
+       bool use_float = painter->cache.use_float;
+       bool is_texbrush = painter->cache.is_texbrush;
+       bool is_maskbrush = painter->cache.is_maskbrush;
+
+       float alpha = (use_masking)? 1.0f: BKE_brush_alpha_get(scene, brush);
+       int radius = BKE_brush_size_get(scene, brush);
+       int xoff = -size * 0.5f + 0.5f;
+       int yoff = -size * 0.5f + 0.5f;
+
+       int x, y, thread = 0;
+       float brush_rgb[3];
+
+       /* allocate image buffer */
+       ImBuf *ibuf = IMB_allocImBuf(size, size, 32, (use_float) ? IB_rectfloat : IB_rect);
+
+       /* get brush color */
+       if (brush->imagepaint_tool == PAINT_TOOL_DRAW) {
+               copy_v3_v3(brush_rgb, brush->rgb);
+
+               if (use_color_correction)
+                       srgb_to_linearrgb_v3_v3(brush_rgb, brush_rgb);
+       }
+       else {
+               brush_rgb[0] = 1.0f;
+               brush_rgb[1] = 1.0f;
+               brush_rgb[2] = 1.0f;
+       }
+
+       /* fill image buffer */
+       for (y = 0; y < size; y++) {
+               for (x = 0; x < size; x++) {
+                       /* sample texture and multiply with brush color */
+                       float texco[3], rgba[4];
+
+                       if (is_texbrush) {
+                               brush_imbuf_tex_co(&tex_mapping, x, y, texco);
+                               BKE_brush_sample_tex_3D(scene, brush, texco, rgba, thread, pool);
+                               mul_v3_v3(rgba, brush_rgb);
+                       }
+                       else {
+                               copy_v3_v3(rgba, brush_rgb);
+                               rgba[3] = 1.0f;
+                       }
+
+                       if (is_maskbrush) {
+                               brush_imbuf_tex_co(&mask_mapping, x, y, texco);
+                               rgba[3] *= BKE_brush_sample_masktex(scene, brush, texco, thread, pool);
+                       }
+
+                       /* when not using masking, multiply in falloff and strength */
+                       if (!use_masking) {
+                               float xy[2] = {x + xoff, y + yoff};
+                               float len = len_v2(xy);
+
+                               rgba[3] *= alpha * BKE_brush_curve_strength_clamp(brush, len, radius);
+                       }
+
+                       if (use_float) {
+                               /* write to float pixel */
+                               float *dstf = ibuf->rect_float + (y * size + x) * 4;
+                               mul_v3_v3fl(dstf, rgba, rgba[3]); /* premultiply */
+                               dstf[3] = rgba[3];
+                       }
+                       else {
+                               /* write to byte pixel */
+                               unsigned char *dst = (unsigned char *)ibuf->rect + (y * size + x) * 4;
+
+                               rgb_float_to_uchar(dst, rgba);
+                               dst[3] = FTOCHAR(rgba[3]);
                        }
                }
        }
+
+       return ibuf;
+}
+
+/* update rectangular section of the brush image */
+static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf,
+                                       int origx, int origy, int w, int h, int xt, int yt)
+{
+       Scene *scene = painter->scene;
+       Brush *brush = painter->brush;
+
+       rctf tex_mapping = painter->tex_mapping;
+       rctf mask_mapping = painter->mask_mapping;
+       struct ImagePool *pool = painter->pool;
+
+       bool use_masking = painter->cache.use_masking;
+       bool use_color_correction = painter->cache.use_color_correction;
+       bool use_float = painter->cache.use_float;
+       bool is_texbrush = painter->cache.is_texbrush;
+       bool is_maskbrush = painter->cache.is_maskbrush;
+       bool use_texture_old = (oldtexibuf != NULL);
+
+       int x, y, thread = 0;
+       float brush_rgb[3];
+
+       ImBuf *ibuf = painter->cache.ibuf;
+       ImBuf *texibuf = painter->cache.texibuf;
+       unsigned short *mask = painter->cache.mask;
+
+       /* get brush color */
+       if (brush->imagepaint_tool == PAINT_TOOL_DRAW) {
+               copy_v3_v3(brush_rgb, brush->rgb);
+
+               if (use_color_correction)
+                       srgb_to_linearrgb_v3_v3(brush_rgb, brush_rgb);
+       }
        else {
-               for (; y < h; y++) {
-                       b = (unsigned char *)ibuf->rect + (y * ibuf->x + origx) * 4;
-                       t = (unsigned char *)texibuf->rect + (y * texibuf->x + origx) * 4;
-                       m = (unsigned char *)maskibuf->rect + (y * maskibuf->x + origx) * 4;
-
-                       if (dotexold)
-                               ot = (unsigned char *)oldtexibuf->rect + ((y - origy + yt) * oldtexibuf->x + xt) * 4;
-
-                       for (x = origx; x < w; x++, b += 4, m += 4, t += 4) {
-                               if (dotexold) {
-                                       t[0] = ot[0];
-                                       t[1] = ot[1];
-                                       t[2] = ot[2];
-                                       t[3] = ot[3];
-                                       ot += 4;
+               brush_rgb[0] = 1.0f;
+               brush_rgb[1] = 1.0f;
+               brush_rgb[2] = 1.0f;
+       }
+
+       /* fill pixes */
+       for (y = origy; y < h; y++) {
+               for (x = origx; x < w; x++) {
+                       /* sample texture and multiply with brush color */
+                       float texco[3], rgba[4];
+
+                       if (!use_texture_old) {
+                               if (is_texbrush) {
+                                       brush_imbuf_tex_co(&tex_mapping, x, y, texco);
+                                       BKE_brush_sample_tex_3D(scene, brush, texco, rgba, thread, pool);
+                                       mul_v3_v3(rgba, brush_rgb);
                                }
                                else {
-                                       texco[0] = mapping.xmin + x * mapping.xmax;
-                                       texco[1] = mapping.ymin + y * mapping.ymax;
-                                       texco[2] = 0.0f;
+                                       copy_v3_v3(rgba, brush_rgb);
+                                       rgba[3] = 1.0f;
+                               }
 
-                                       BKE_brush_sample_tex_3D(scene, brush, texco, rgba, thread, painter->pool);
-                                       rgba_float_to_uchar(t, rgba);
+                               if (is_maskbrush) {
+                                       brush_imbuf_tex_co(&mask_mapping, x, y, texco);
+                                       rgba[3] *= BKE_brush_sample_masktex(scene, brush, texco, thread, pool);
                                }
+                       }
+
+                       if (use_float) {
+                               /* handle float pixel */
+                               float *bf = ibuf->rect_float + (y * ibuf->x + x) * 4;
+                               float *tf = texibuf->rect_float + (y * texibuf->x + x) * 4;
+
+                               /* read from old texture buffer */
+                               if (use_texture_old) {
+                                       float *otf = oldtexibuf->rect_float + ((y - origy + yt) * oldtexibuf->x + (x - origx + xt)) * 4;
+                                       copy_v4_v4(rgba, otf);
+                               }
+
+                               /* write to new texture buffer */
+                               copy_v4_v4(tf, rgba);
 
-                               b[0] = t[0] * m[0] / 255;
-                               b[1] = t[1] * m[1] / 255;
-                               b[2] = t[2] * m[2] / 255;
-                               b[3] = t[3] * m[3] / 255;
+                               /* if not using masking, multiply in the mask now */
+                               if (!use_masking) {
+                                       unsigned short *m = mask + (y * ibuf->x + x);
+                                       rgba[3] *= *m * (1.0f / 65535.0f);
+                               }
+
+                               /* output premultiplied float image, mf was already premultiplied */
+                               mul_v3_v3fl(bf, rgba, rgba[3]);
+                               bf[3] = rgba[3];
+                       }
+                       else {
+                               unsigned char crgba[4];
+
+                               /* handle byte pixel */
+                               unsigned char *b = (unsigned char *)ibuf->rect + (y * ibuf->x + x) * 4;
+                               unsigned char *t = (unsigned char *)texibuf->rect + (y * texibuf->x + x) * 4;
+
+                               /* read from old texture buffer */
+                               if (use_texture_old) {
+                                       unsigned char *ot = (unsigned char *)oldtexibuf->rect + ((y - origy + yt) * oldtexibuf->x + (x - origx + xt)) * 4;
+                                       crgba[0] = ot[0];
+                                       crgba[1] = ot[1];
+                                       crgba[2] = ot[2];
+                                       crgba[3] = ot[3];
+                               }
+                               else
+                                       rgba_float_to_uchar(crgba, rgba);
+
+                               /* write to new texture buffer */
+                               t[0] = crgba[0];
+                               t[1] = crgba[1];
+                               t[2] = crgba[2];
+                               t[3] = crgba[3];
+
+                               /* if not using masking, multiply in the mask now */
+                               if (!use_masking) {
+                                       unsigned short *m = mask + (y * ibuf->x + x);
+                                       crgba[3] = (crgba[3] * (*m)) / 65535;
+                               }
+
+                               /* write to brush image buffer */
+                               b[0] = crgba[0];
+                               b[1] = crgba[1];
+                               b[2] = crgba[2];
+                               b[3] = crgba[3];
                        }
                }
        }
 }
 
-static void brush_painter_2d_tiled_tex_partial_update(BrushPainter *painter, const float pos[2])
+/* update the brush image by trying to reuse the cached texture result. this
+ * can be considerably faster for brushes that change size due to pressure or
+ * textures that stick to the surface where only part of the pixels are new */
+static void brush_painter_imbuf_partial_update(BrushPainter *painter, const float pos[2])
 {
        const Scene *scene = painter->scene;
        Brush *brush = painter->brush;
        BrushPainterCache *cache = &painter->cache;
        ImBuf *oldtexibuf, *ibuf;
        int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
-       const int diameter = 2 * BKE_brush_size_get(scene, brush);
+       int diameter = 2 * BKE_brush_size_get(scene, brush);
 
-       imbflag = (cache->flt) ? IB_rectfloat : IB_rect;
+       /* create brush image buffer if it didn't exist yet */
+       imbflag = (cache->use_float) ? IB_rectfloat : IB_rect;
        if (!cache->ibuf)
                cache->ibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag);
        ibuf = cache->ibuf;
 
+       /* create new texture image buffer with coordinates relative to old */
        oldtexibuf = cache->texibuf;
        cache->texibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag);
+
        if (oldtexibuf) {
                srcx = srcy = 0;
                destx = (int)painter->lastpaintpos[0] - (int)pos[0];
@@ -316,28 +494,28 @@ static void brush_painter_2d_tiled_tex_partial_update(BrushPainter *painter, con
        
        x1 = destx;
        y1 = desty;
-       x2 = destx + w;
-       y2 = desty + h;
+       x2 = min_ii(destx + w, ibuf->x);
+       y2 = min_ii(desty + h, ibuf->y);
 
        /* blend existing texture in new position */
        if ((x1 < x2) && (y1 < y2))
-               brush_painter_2d_do_partial(painter, oldtexibuf, x1, y1, x2, y2, srcx, srcy, pos);
+               brush_painter_imbuf_update(painter, oldtexibuf, x1, y1, x2, y2, srcx, srcy);
 
        if (oldtexibuf)
                IMB_freeImBuf(oldtexibuf);
 
        /* sample texture in new areas */
        if ((0 < x1) && (0 < ibuf->y))
-               brush_painter_2d_do_partial(painter, NULL, 0, 0, x1, ibuf->y, 0, 0, pos);
+               brush_painter_imbuf_update(painter, NULL, 0, 0, x1, ibuf->y, 0, 0);
        if ((x2 < ibuf->x) && (0 < ibuf->y))
-               brush_painter_2d_do_partial(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0, pos);
+               brush_painter_imbuf_update(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0);
        if ((x1 < x2) && (0 < y1))
-               brush_painter_2d_do_partial(painter, NULL, x1, 0, x2, y1, 0, 0, pos);
+               brush_painter_imbuf_update(painter, NULL, x1, 0, x2, y1, 0, 0);
        if ((x1 < x2) && (y2 < ibuf->y))
-               brush_painter_2d_do_partial(painter, NULL, x1, y2, x2, ibuf->y, 0, 0, pos);
+               brush_painter_imbuf_update(painter, NULL, x1, y2, x2, ibuf->y, 0, 0);
 }
 
-static void brush_painter_2d_tex_mapping(ImagePaintState *s, int bufsize, const float pos[2], bool do_stencil, bool do_3D, bool do_view, rctf *mapping)
+static void brush_painter_2d_tex_mapping(ImagePaintState *s, int size, const float startpos[2], const float pos[2], int mapmode, rctf *mapping)
 {
        float invw = 1.0f / (float)s->canvas->x;
        float invh = 1.0f / (float)s->canvas->y;
@@ -345,104 +523,136 @@ static void brush_painter_2d_tex_mapping(ImagePaintState *s, int bufsize, const
        int ipos[2];
 
        /* find start coordinate of brush in canvas */
-       ipos[0] = (int)floorf((pos[0] - bufsize / 2) + 1.0f);
-       ipos[1] = (int)floorf((pos[1] - bufsize / 2) + 1.0f);
+       ipos[0] = (int)floorf((pos[0] - size / 2) + 1.0f);
+       ipos[1] = (int)floorf((pos[1] - size / 2) + 1.0f);
 
-       if (do_stencil || do_view) {
+       if (ELEM(mapmode, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_VIEW)) {
                /* map from view coordinates of brush to region coordinates */
                UI_view2d_to_region_no_clip(s->v2d, ipos[0] * invw, ipos[1] * invh, &xmin, &ymin);
-               UI_view2d_to_region_no_clip(s->v2d, (ipos[0] + bufsize) * invw, (ipos[1] + bufsize) * invh, &xmax, &ymax);
+               UI_view2d_to_region_no_clip(s->v2d, (ipos[0] + size) * invw, (ipos[1] + size) * invh, &xmax, &ymax);
 
                /* output mapping from brush ibuf x/y to region coordinates */
                mapping->xmin = xmin;
                mapping->ymin = ymin;
-               mapping->xmax = (xmax - xmin) / (float)bufsize;
-               mapping->ymax = (ymax - ymin) / (float)bufsize;
+               mapping->xmax = (xmax - xmin) / (float)size;
+               mapping->ymax = (ymax - ymin) / (float)size;
        }
-       else if (do_3D) {
+       else if (mapmode == MTEX_MAP_MODE_3D) {
                /* 3D mapping, just mapping to canvas 0..1  */
                mapping->xmin = ipos[0] * invw;
                mapping->ymin = ipos[1] * invh;
-               mapping->xmax = bufsize * invw / (float)bufsize;
-               mapping->ymax = bufsize * invh / (float)bufsize;
+               mapping->xmax = size * invw / (float)size;
+               mapping->ymax = size * invh / (float)size;
        }
        else {
                /* other mapping */
-               mapping->xmin = -bufsize * 0.5f + 0.5f;
-               mapping->ymin = -bufsize * 0.5f + 0.5f;
+               mapping->xmin = -size * 0.5f + 0.5f;
+               mapping->ymin = -size * 0.5f + 0.5f;
                mapping->xmax = 1.0f;
                mapping->ymax = 1.0f;
        }
+
+       if (mapmode == MTEX_MAP_MODE_TILED) {
+               /* offset relative to start position for tiled */
+               mapping->xmin += (int)pos[0] - (int)startpos[0];
+               mapping->ymin += (int)pos[1] - (int)startpos[1];
+       }
 }
 
-static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *painter, const float pos[2], bool use_color_correction)
+static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *painter, const float pos[2])
 {
        const Scene *scene = painter->scene;
        UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
        Brush *brush = painter->brush;
        BrushPainterCache *cache = &painter->cache;
-       MTex *mtex = &brush->mtex;
        const int diameter = 2 * BKE_brush_size_get(scene, brush);
        const int size = (cache->size) ? cache->size : diameter;
-       const short flt = cache->flt;
        const float alpha = BKE_brush_alpha_get(scene, brush);
-       const bool do_3D = brush->mtex.brush_map_mode == MTEX_MAP_MODE_3D;
-       const bool do_tiled = brush->mtex.brush_map_mode == MTEX_MAP_MODE_TILED;
-       const bool do_stencil = brush->mtex.brush_map_mode == MTEX_MAP_MODE_STENCIL;
-       const bool do_random = brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM;
-       const bool do_view = brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW;
-       const bool use_brush_alpha = !s->do_masking;
-       float rotation = -mtex->rot;
+       const bool use_masking = painter->cache.use_masking;
+
+       bool do_random = false;
+       bool do_partial_update = false;
+       bool do_view = false;
+       float tex_rotation = -brush->mtex.rot;
+       float mask_rotation = -brush->mask_mtex.rot;
+
+       /* determine how can update based on textures used */
+       if (painter->cache.is_texbrush) {
+               if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
+                       do_view = true;
+                       tex_rotation += ups->brush_rotation;
+               }
+               else if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
+                       do_random = true;
+               else
+                       do_partial_update = true;
+
+               brush_painter_2d_tex_mapping(s, size, painter->startpaintpos, pos,
+                                            brush->mtex.brush_map_mode, &painter->tex_mapping);
+       }
+
+       if (painter->cache.is_maskbrush) {
+               if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
+                       do_view = true;
+                       mask_rotation += ups->brush_rotation;
+               }
+               else if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
+                       do_random = true;
+               else
+                       do_partial_update = true;
 
-       if (do_view) {
-               rotation += ups->brush_rotation;
+               brush_painter_2d_tex_mapping(s, size, painter->startpaintpos,
+                                                                        pos, brush->mask_mtex.brush_map_mode, &painter->mask_mapping);
        }
 
-       brush_painter_2d_tex_mapping(s, size, pos, do_stencil, do_3D, do_view, &painter->mapping);
+       if (do_view || do_random)
+               do_partial_update = false;
 
        painter->pool = BKE_image_pool_new();
 
+       /* detect if we need to recreate image brush buffer */
        if (diameter != cache->lastsize ||
-           (use_brush_alpha && alpha != cache->lastalpha) ||
+           alpha != cache->lastalpha ||
            brush->jitter != cache->lastjitter ||
-           rotation != cache->last_rotation ||
+           tex_rotation != cache->last_tex_rotation ||
+           mask_rotation != cache->last_mask_rotation ||
            do_random)
        {
                if (cache->ibuf) {
                        IMB_freeImBuf(cache->ibuf);
                        cache->ibuf = NULL;
                }
-               if (cache->maskibuf) {
-                       IMB_freeImBuf(cache->maskibuf);
-                       cache->maskibuf = NULL;
+               if (cache->mask) {
+                       MEM_freeN(cache->mask);
+                       cache->mask = NULL;
                }
 
-               if (do_tiled || do_3D || do_stencil) {
-                       BKE_brush_imbuf_new(scene, brush, flt, BRUSH_IMBUF_MASK,
-                                           size, &cache->maskibuf,
-                                           use_color_correction, use_brush_alpha,
-                                           painter->pool, &painter->mapping);
-
-                       brush_painter_2d_tiled_tex_partial_update(painter, pos);
+               if (do_partial_update) {
+                       /* do partial update of texture + recreate mask */
+                       cache->mask = brush_painter_mask_new(painter, size);
+                       brush_painter_imbuf_partial_update(painter, pos);
                }
                else {
-                       BKE_brush_imbuf_new(scene, brush, flt, BRUSH_IMBUF_TEX_MASK,
-                                           size, &cache->ibuf,
-                                           use_color_correction, use_brush_alpha,
-                                           painter->pool, &painter->mapping);
+                       /* create brush and mask from scratch */
+                       if (use_masking)
+                               cache->mask = brush_painter_mask_new(painter, size);
+                       cache->ibuf = brush_painter_imbuf_new(painter, size);
                }
 
                cache->lastsize = diameter;
                cache->lastalpha = alpha;
                cache->lastjitter = brush->jitter;
-               cache->last_rotation = rotation;
+               cache->last_tex_rotation = tex_rotation;
+               cache->last_mask_rotation = mask_rotation;
        }
-       else if ((do_tiled || do_3D || do_stencil) && mtex && mtex->tex) {
+       else if (do_partial_update) {
+               /* do only partial update of texture */
                int dx = (int)painter->lastpaintpos[0] - (int)pos[0];
                int dy = (int)painter->lastpaintpos[1] - (int)pos[1];
 
-               if ((dx != 0) || (dy != 0))
-                       brush_painter_2d_tiled_tex_partial_update(painter, pos);
+               if ((dx != 0) || (dy != 0)) {
+                       brush_painter_imbuf_partial_update(painter, pos);
+               }
        }
 
        BKE_image_pool_free(painter->pool);
@@ -616,7 +826,7 @@ static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos)
        tot = paint_2d_torus_split_region(region, ibufb, ibuf);
 
        for (a = 0; a < tot; a++)
-               IMB_rectblend(ibufb, ibufb, ibuf, NULL, 0, region[a].destx, region[a].desty,
+               IMB_rectblend(ibufb, ibufb, ibuf, NULL, NULL, 0, region[a].destx, region[a].desty,
                              region[a].destx, region[a].desty,
                              region[a].srcx, region[a].srcy,
                              region[a].width, region[a].height, IMB_BLEND_COPY_RGB);
@@ -630,9 +840,9 @@ static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos)
        ImBuf *clonebuf = IMB_allocImBuf(w, h, ibufb->planes, ibufb->flags);
 
        IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h);
-       IMB_rectblend(clonebuf, clonebuf, ibuf, NULL, 0, destx, desty, destx, desty, srcx, srcy, w, h,
+       IMB_rectblend(clonebuf, clonebuf, ibuf, NULL, NULL, 0, destx, desty, destx, desty, srcx, srcy, w, h,
                      IMB_BLEND_COPY_RGB);
-       IMB_rectblend(clonebuf, clonebuf, ibufb, NULL, 0, destx, desty, destx, desty, destx, desty, w, h,
+       IMB_rectblend(clonebuf, clonebuf, ibufb, NULL, NULL, 0, destx, desty, destx, desty, destx, desty, w, h,
                      IMB_BLEND_COPY_ALPHA);
 
        return clonebuf;
@@ -644,7 +854,7 @@ static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[
        ipos[1] = (int)floorf((pos[1] - ibufb->y / 2) + 1.0f);
 }
 
-static int paint_2d_op(void *state, ImBuf *ibufb, const float lastpos[2], const float pos[2])
+static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *maskb, const float lastpos[2], const float pos[2])
 {
        ImagePaintState *s = ((ImagePaintState *)state);
        ImBuf *clonebuf = NULL, *frombuf, *tmpbuf = NULL;
@@ -719,7 +929,8 @@ static int paint_2d_op(void *state, ImBuf *ibufb, const float lastpos[2], const
                                        else
                                                tmpbuf->rect = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask);
 
-                                       IMB_rectblend(s->canvas, tmpbuf, frombuf, mask, mask_max,
+                                       IMB_rectblend(s->canvas, tmpbuf, frombuf, mask,
+                                                     maskb, mask_max,
                                                      region[a].destx, region[a].desty,
                                                      origx, origy,
                                                      region[a].srcx, region[a].srcy,
@@ -729,7 +940,7 @@ static int paint_2d_op(void *state, ImBuf *ibufb, const float lastpos[2], const
                }
                else {
                        /* no masking, composite brush directly onto canvas */
-                       IMB_rectblend(s->canvas, s->canvas, frombuf, NULL, 0,
+                       IMB_rectblend(s->canvas, s->canvas, frombuf, NULL, NULL, 0,
                                      region[a].destx, region[a].desty,
                                      region[a].destx, region[a].desty,
                                      region[a].srcx, region[a].srcy,
@@ -845,14 +1056,15 @@ int paint_2d_stroke(void *ps, const int prev_mval[2], const int mval[2], int era
        else {
                copy_v2_v2(painter->lastpaintpos, olduv);
        }
+
        /* OCIO_TODO: float buffers are now always linear, so always use color correction
         *            this should probably be changed when texture painting color space is supported
         */
-       brush_painter_2d_require_imbuf(painter, ((ibuf->rect_float) ? 1 : 0), 0);
+       brush_painter_2d_require_imbuf(painter, (ibuf->rect_float != NULL), !is_data, s->do_masking);
 
-       brush_painter_2d_refresh_cache(s, painter, newuv, is_data == false);
+       brush_painter_2d_refresh_cache(s, painter, newuv);
 
-       if (paint_2d_op(s, painter->cache.ibuf, olduv, newuv)) {
+       if (paint_2d_op(s, painter->cache.ibuf, painter->cache.mask, olduv, newuv)) {
                imapaint_image_update(s->sima, s->image, ibuf, false);
                BKE_image_release_ibuf(s->image, ibuf, NULL);
                redraw |= 1;
index 7523d10996aea93bcdf08dc171499144392fe856..0aef1ccf9fe67d67cbf3e0dce127d05af1d5259f 100644 (file)
@@ -3669,7 +3669,7 @@ static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, const
        }
 
        rgb_float_to_uchar(rgba_ub, rgb);
-       rgba_ub[3] = 255 * mask;
+       rgba_ub[3] = FTOCHAR(mask);
 
        if (ps->do_masking) {
                IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch, rgba_ub, ps->blend);
index 7253a61092ccbd4c931dd1f83b777b1db45f24dd..819026facc670ebcc7a024d3150c1c5463c1fb8a 100644 (file)
@@ -179,7 +179,7 @@ void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx,
 void IMB_rectcpy(struct ImBuf *drect, struct ImBuf *srect, int destx,
        int desty, int srcx, int srcy, int width, int height);
 void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *obuf, struct ImBuf *sbuf,
-       unsigned short *mask, unsigned short mask_max,
+       unsigned short *dmask, unsigned short *smask, unsigned short mask_max,
        int destx,  int desty, int origx, int origy, int srcx, int srcy,
        int width, int height, IMB_BlendMode mode);
 
index 3d80be93deddee3907f159f2dbcaa7b683485c58..71f81239547874f072636ee91c462b52eb1642d9 100644 (file)
@@ -226,20 +226,22 @@ static void imb_rectclip3(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, int *destx,
 void IMB_rectcpy(ImBuf *dbuf, ImBuf *sbuf, int destx, 
                  int desty, int srcx, int srcy, int width, int height)
 {
-       IMB_rectblend(dbuf, dbuf, sbuf, NULL, 0, destx, desty, destx, desty, srcx, srcy, width, height, IMB_BLEND_COPY);
+       IMB_rectblend(dbuf, dbuf, sbuf, NULL, NULL, 0, destx, desty, destx, desty, srcx, srcy, width, height, IMB_BLEND_COPY);
 }
 
 typedef void (*IMB_blend_func)(unsigned char *dst, const unsigned char *src1, const unsigned char *src2);
 typedef void (*IMB_blend_func_float)(float *dst, const float *src1, const float *src2);
 
 
-void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *maskrect, unsigned short mask_max,
+void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask,
+                   unsigned short *smask, unsigned short mask_max,
                    int destx,  int desty, int origx, int origy, int srcx, int srcy, int width, int height,
                    IMB_BlendMode mode)
 {
        unsigned int *drect = NULL, *orect, *srect = NULL, *dr, *or, *sr;
        float *drectf = NULL, *orectf, *srectf = NULL, *drf, *orf, *srf;
-       unsigned short *mr;
+       unsigned short *smaskrect = smask, *smr;
+       unsigned short *dmaskrect = dmask, *dmr;
        int do_float, do_char, srcskip, destskip, origskip, x;
        IMB_blend_func func = NULL;
        IMB_blend_func_float func_float = NULL;
@@ -264,8 +266,8 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *maskre
                orectf = obuf->rect_float + (origy * obuf->x + origx) * 4;
        }
 
-       if (maskrect)
-               maskrect += origy * obuf->x + origx;
+       if (dmaskrect)
+               dmaskrect += origy * obuf->x + origx;
 
        destskip = dbuf->x;
        origskip = obuf->x;
@@ -274,6 +276,9 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *maskre
                if (do_char) srect = sbuf->rect + srcy * sbuf->x + srcx;
                if (do_float) srectf = sbuf->rect_float + (srcy * sbuf->x + srcx) * 4;
                srcskip = sbuf->x;
+
+               if (smaskrect)
+                       smaskrect += srcy * sbuf->x + srcx;
        }
        else {
                srect = drect;
@@ -392,32 +397,34 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *maskre
                                or = orect;
                                sr = srect;
 
-                               if (maskrect) {
+                               if (dmaskrect && smaskrect) {
                                        /* mask accumulation for painting */
-                                       mr = maskrect;
+                                       dmr = dmaskrect;
+                                       smr = smaskrect;
 
-                                       for (x = width; x > 0; x--, dr++, or++, sr++, mr++) {
+                                       for (x = width; x > 0; x--, dr++, or++, sr++, dmr++, smr++) {
                                                unsigned char *src = (unsigned char *)sr;
 
-                                               if (src[3]) {
-                                                       unsigned short mask = *mr + divide_round_i((mask_max - *mr) * src[3], 255);
+                                               if (src[3] && *smr) {
+                                                       unsigned short mask = *dmr + (((mask_max - *dmr) * (*smr)) / 65535);
 
-                                                       if (mask > *mr) {
+                                                       if (mask > *dmr) {
                                                                unsigned char mask_src[4];
 
-                                                               *mr = mask;
+                                                               *dmr = mask;
 
                                                                mask_src[0] = src[0];
                                                                mask_src[1] = src[1];
                                                                mask_src[2] = src[2];
-                                                               mask_src[3] = mask >> 8;
+                                                               mask_src[3] = divide_round_i(src[3] * mask, 65535);
 
                                                                func((unsigned char *)dr, (unsigned char *)or, mask_src);
                                                        }
                                                }
                                        }
 
-                                       maskrect += origskip;
+                                       dmaskrect += origskip;
+                                       smaskrect += srcskip;
                                }
                                else {
                                        /* regular blending */
@@ -437,33 +444,28 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *maskre
                                orf = orectf;
                                srf = srectf;
 
-                               if (maskrect) {
+                               if (dmaskrect && smaskrect) {
                                        /* mask accumulation for painting */
-                                       mr = maskrect;
+                                       dmr = dmaskrect;
+                                       smr = smaskrect;
 
-                                       for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4, mr++) {
-                                               if (srf[3] != 0) {
-                                                       float alpha = CLAMPIS(srf[3], 0.0f, 1.0f);
-                                                       unsigned short mask = (unsigned short)(*mr + (mask_max - *mr) * alpha);
+                                       for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4, dmr++, smr++) {
+                                               if (srf[3] != 0 && *smr) {
+                                                       unsigned short mask = *dmr + (((mask_max - *dmr) * (*smr)) / 65535);
 
-                                                       if (mask > *mr) {
+                                                       if (mask > *dmr) {
                                                                float mask_srf[4];
-                                                               float new_alpha = mask * (1.0f / 65535.0f);
-                                                               float map_alpha = new_alpha / srf[3];
-
-                                                               *mr = mask;
 
-                                                               mask_srf[0] = map_alpha * srf[0];
-                                                               mask_srf[1] = map_alpha * srf[1];
-                                                               mask_srf[2] = map_alpha * srf[2];
-                                                               mask_srf[3] = new_alpha;
+                                                               *dmr = mask;
+                                                               mul_v4_v4fl(mask_srf, srf, mask * (1.0f / 65535.0f));
 
                                                                func_float(drf, orf, mask_srf);
                                                        }
                                                }
                                        }
 
-                                       maskrect += origskip;
+                                       dmaskrect += origskip;
+                                       smaskrect += srcskip;
                                }
                                else {
                                        /* regular blending */
index eb68ea2425df993639bb9e0fce1eb17ed94e728c..6cc8d287e66fc8f8873359649b7b3c2e8abb79f8 100644 (file)
@@ -163,7 +163,7 @@ void ImageBuff::plot(unsigned char *img, short width, short height, short x, sho
        // assign temporarily our buffer to the ImBuf buffer, we use the same format
        tmpbuf->rect = (unsigned int*)img;
        m_imbuf->rect = m_image;
-       IMB_rectblend(m_imbuf, m_imbuf, tmpbuf, NULL, 0, x, y, x, y, 0, 0, width, height, (IMB_BlendMode)mode);
+       IMB_rectblend(m_imbuf, m_imbuf, tmpbuf, NULL, NULL, 0, x, y, x, y, 0, 0, width, height, (IMB_BlendMode)mode);
        // remove so that MB_freeImBuf will free our buffer
        m_imbuf->rect = NULL;
        tmpbuf->rect = NULL;
@@ -186,7 +186,7 @@ void ImageBuff::plot(ImageBuff *img, short x, short y, short mode)
        // assign temporarily our buffer to the ImBuf buffer, we use the same format
        img->m_imbuf->rect = img->m_image;
        m_imbuf->rect = m_image;
-       IMB_rectblend(m_imbuf, m_imbuf, img->m_imbuf, NULL, 0, x, y, x, y, 0, 0, img->m_imbuf->x, img->m_imbuf->y, (IMB_BlendMode)mode);
+       IMB_rectblend(m_imbuf, m_imbuf, img->m_imbuf, NULL, NULL, 0, x, y, x, y, 0, 0, img->m_imbuf->x, img->m_imbuf->y, (IMB_BlendMode)mode);
        // remove so that MB_freeImBuf will free our buffer
        m_imbuf->rect = NULL;
        img->m_imbuf->rect = NULL;