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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2013-05-12 13:14:13 +0400
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2013-05-12 13:14:13 +0400
commit70eaf2fe44934da315753df30aff450333082630 (patch)
treea3dd92ddd4989a586fb64b475047fd645b148f2e /source
parent698f1b56037ea9c6eec170a0f3b74b7a46eaae1d (diff)
Image paint: 2D painting now supports texture masks and does masking more
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.
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_brush.h6
-rw-r--r--source/blender/blenkernel/intern/brush.c116
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c518
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c2
-rw-r--r--source/blender/imbuf/IMB_imbuf.h2
-rw-r--r--source/blender/imbuf/intern/rectop.c62
-rw-r--r--source/gameengine/VideoTexture/ImageBuff.cpp4
7 files changed, 401 insertions, 309 deletions
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index 60c50b989fb..9990aeda92b 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -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);
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 621c41c3df7..a8c78b430be 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -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
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index efb810455b7..55dd96eff36 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -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;
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 7523d10996a..0aef1ccf9fe 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -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);
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 7253a61092c..819026facc6 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -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);
diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c
index 3d80be93ded..71f81239547 100644
--- a/source/blender/imbuf/intern/rectop.c
+++ b/source/blender/imbuf/intern/rectop.c
@@ -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 */
diff --git a/source/gameengine/VideoTexture/ImageBuff.cpp b/source/gameengine/VideoTexture/ImageBuff.cpp
index eb68ea2425d..6cc8d287e66 100644
--- a/source/gameengine/VideoTexture/ImageBuff.cpp
+++ b/source/gameengine/VideoTexture/ImageBuff.cpp
@@ -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;