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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2013-04-30 10:07:42 +0400
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2013-04-30 10:07:42 +0400
commit63f05576b840c597f91414fd2ca6db8ca869e3e9 (patch)
treee6d0bbd3dc57e67a0799a5fc066e72c8f630abc7 /source/blender
parentb735402c19782402e4a9970280cd3a3c8457296f (diff)
More image painting fixes:
* 2D image painting support for masking to limit the max contribution of a stroke to a pixel, to get it working compatible with projection painting. Not strictly a bugfix, but the inconsistency here was annoying. * Fix python errors in Texture Mask panel in image editor, was missing overlay options. * Clamp paint mask to 0..1 in case some texture exceeds it, this could give black pixels due to integer overflow.
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_brush.h2
-rw-r--r--source/blender/blenkernel/intern/brush.c5
-rw-r--r--source/blender/blenlib/intern/math_color_blend_inline.c30
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c84
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c79
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h3
-rw-r--r--source/blender/imbuf/IMB_imbuf.h6
-rw-r--r--source/blender/imbuf/intern/rectop.c198
9 files changed, 339 insertions, 70 deletions
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index 452030d05e6..863d7b05693 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -82,7 +82,7 @@ float BKE_brush_sample_tex_2D(const struct Scene *scene, struct Brush *brush, co
float BKE_brush_sample_masktex(const Scene *scene, struct Brush *br, const float point[3],
const int thread, struct ImagePool *pool);
void BKE_brush_imbuf_new(const struct Scene *scene, struct Brush *brush, short flt, short texfalloff, int size,
- struct ImBuf **imbuf, int use_color_correction);
+ struct ImBuf **imbuf, bool use_color_correction, bool use_brush_alpha);
/* 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 517180964a5..c24aab1629c 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -828,14 +828,15 @@ float BKE_brush_sample_tex_2D(const Scene *scene, Brush *brush, const float xy[2
/* TODO, use define for 'texfall' arg
* NOTE: only used for 2d brushes currently! */
-void BKE_brush_imbuf_new(const Scene *scene, Brush *brush, short flt, short texfall, int bufsize, ImBuf **outbuf, int use_color_correction)
+void BKE_brush_imbuf_new(const Scene *scene, Brush *brush, short flt, short texfall, int bufsize,
+ ImBuf **outbuf, bool use_color_correction, bool use_brush_alpha)
{
ImBuf *ibuf;
float xy[2], 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 = BKE_brush_alpha_get(scene, brush);
+ const float alpha = (use_brush_alpha)? BKE_brush_alpha_get(scene, brush): 1.0f;
float brush_rgb[3];
imbflag = (flt) ? IB_rectfloat : IB_rect;
diff --git a/source/blender/blenlib/intern/math_color_blend_inline.c b/source/blender/blenlib/intern/math_color_blend_inline.c
index 94a474da681..121750fe919 100644
--- a/source/blender/blenlib/intern/math_color_blend_inline.c
+++ b/source/blender/blenlib/intern/math_color_blend_inline.c
@@ -372,12 +372,17 @@ MINLINE void blend_color_erase_alpha_float(float dst[4], const float src1[4], co
{
if (src2[3] != 0.0f && src1[3] > 0.0f) {
/* subtract alpha and remap RGB channels to match */
- const float alpha = max_ff(src1[3] - src2[3], 0.0f);
- const float map_alpha = alpha / src1[3];
+ float alpha = max_ff(src1[3] - src2[3], 0.0f);
+ float map_alpha;
- dst[0] *= map_alpha;
- dst[1] *= map_alpha;
- dst[2] *= map_alpha;
+ if (alpha <= 0.0005f)
+ alpha = 0.0f;
+
+ map_alpha = alpha / src1[3];
+
+ dst[0] = src1[0] * map_alpha;
+ dst[1] = src1[1] * map_alpha;
+ dst[2] = src1[2] * map_alpha;
dst[3] = alpha;
}
else {
@@ -393,12 +398,17 @@ MINLINE void blend_color_add_alpha_float(float dst[4], const float src1[4], cons
{
if (src2[3] != 0.0f && src1[3] < 1.0f) {
/* add alpha and remap RGB channels to match */
- const float alpha = min_ff(src1[3] + src2[3], 1.0f);
- const float map_alpha = (src1[3] > 0.0f) ? alpha / src1[3] : 1.0f;
+ float alpha = min_ff(src1[3] + src2[3], 1.0f);
+ float map_alpha;
+
+ if (alpha >= 1.0f - 0.0005f)
+ alpha = 1.0f;
+
+ map_alpha = (src1[3] > 0.0f) ? alpha / src1[3] : 1.0f;
- dst[0] *= map_alpha;
- dst[1] *= map_alpha;
- dst[2] *= map_alpha;
+ dst[0] = src1[0] * map_alpha;
+ dst[1] = src1[1] * map_alpha;
+ dst[2] = src1[2] * map_alpha;
dst[3] = alpha;
}
else {
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index e3adf40a7eb..f059a0b1a0a 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -101,9 +101,6 @@
#include "paint_intern.h"
-#define IMAPAINT_TILE_BITS 6
-#define IMAPAINT_TILE_SIZE (1 << IMAPAINT_TILE_BITS)
-
typedef struct UndoImageTile {
struct UndoImageTile *next, *prev;
@@ -115,6 +112,9 @@ typedef struct UndoImageTile {
unsigned int *uint;
void *pt;
} rect;
+
+ unsigned short *mask;
+
int x, y;
short source, use_float;
@@ -156,18 +156,45 @@ static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int
tile->y * IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
}
+void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask)
+{
+ ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+ UndoImageTile *tile;
+ short use_float = ibuf->rect_float ? 1 : 0;
+
+ for (tile = lb->first; tile; tile = tile->next) {
+ if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type && ima->source == tile->source) {
+ if (tile->use_float == use_float) {
+ if (strcmp(tile->idname, ima->id.name) == 0 && strcmp(tile->ibufname, ibuf->name) == 0) {
+ if (mask) {
+ /* allocate mask if requested */
+ if (!tile->mask)
+ tile->mask = MEM_callocN(sizeof(unsigned short)*IMAPAINT_TILE_SIZE*IMAPAINT_TILE_SIZE, "UndoImageTile.mask");
+
+ *mask = tile->mask;
+ }
+
+ return tile->rect.pt;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile)
{
ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
UndoImageTile *tile;
int allocsize;
short use_float = ibuf->rect_float ? 1 : 0;
+ void *data;
- for (tile = lb->first; tile; tile = tile->next)
- if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type && ima->source == tile->source)
- if (tile->use_float == use_float)
- if (strcmp(tile->idname, ima->id.name) == 0 && strcmp(tile->ibufname, ibuf->name) == 0)
- return tile->rect.pt;
+ /* check if tile is already pushed */
+ data = image_undo_find_tile(ima, ibuf, x_tile, y_tile, NULL);
+ if (data)
+ return data;
if (*tmpibuf == NULL)
*tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
@@ -195,6 +222,19 @@ void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile,
return tile->rect.pt;
}
+void image_undo_remove_masks(void)
+{
+ ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+ UndoImageTile *tile;
+
+ for (tile = lb->first; tile; tile = tile->next) {
+ if (tile->mask) {
+ MEM_freeN(tile->mask);
+ tile->mask = NULL;
+ }
+ }
+}
+
void image_undo_restore(bContext *C, ListBase *lb)
{
Main *bmain = CTX_data_main(C);
@@ -276,10 +316,23 @@ void imapaint_clear_partial_redraw(void)
memset(&imapaintpartial, 0, sizeof(imapaintpartial));
}
+void imapaint_region_tiles(ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th)
+{
+ int srcx = 0, srcy = 0;
+
+ IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h);
+
+ *tw = ((x + w - 1) >> IMAPAINT_TILE_BITS);
+ *th = ((y + h - 1) >> IMAPAINT_TILE_BITS);
+ *tx = (x >> IMAPAINT_TILE_BITS);
+ *ty = (y >> IMAPAINT_TILE_BITS);
+}
+
void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h)
{
ImBuf *tmpibuf = NULL;
- int srcx = 0, srcy = 0, origx;
+ int tilex, tiley, tilew, tileh, tx, ty;
+ int srcx = 0, srcy = 0;
IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h);
@@ -300,14 +353,11 @@ void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h)
imapaintpartial.y2 = max_ii(imapaintpartial.y2, y + h);
}
- w = ((x + w - 1) >> IMAPAINT_TILE_BITS);
- h = ((y + h - 1) >> IMAPAINT_TILE_BITS);
- origx = (x >> IMAPAINT_TILE_BITS);
- y = (y >> IMAPAINT_TILE_BITS);
-
- for (; y <= h; y++)
- for (x = origx; x <= w; x++)
- image_undo_push_tile(ima, ibuf, &tmpibuf, x, y);
+ imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh);
+
+ for (ty = tiley; ty <= tileh; ty++)
+ for (tx = tilex; tx <= tilew; tx++)
+ image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty);
ibuf->userflags |= IB_BITMAPDIRTY;
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 1c50b048fce..d6a634ec404 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -133,6 +133,8 @@ typedef struct ImagePaintState {
char *warnpackedfile;
char *warnmultifile;
+ bool do_masking;
+
/* viewport texture paint only, but _not_ project paint */
Object *ob;
int faceindex;
@@ -327,7 +329,7 @@ static void brush_painter_2d_tiled_tex_partial_update(BrushPainter *painter, con
brush_painter_2d_do_partial(painter, NULL, x1, y2, x2, ibuf->y, 0, 0, pos);
}
-static void brush_painter_2d_refresh_cache(BrushPainter *painter, const float pos[2], int use_color_correction)
+static void brush_painter_2d_refresh_cache(BrushPainter *painter, const float pos[2], bool use_color_correction, bool use_brush_alpha)
{
const Scene *scene = painter->scene;
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
@@ -347,7 +349,7 @@ static void brush_painter_2d_refresh_cache(BrushPainter *painter, const float po
}
if (diameter != cache->lastsize ||
- alpha != cache->lastalpha ||
+ (use_brush_alpha && alpha != cache->lastalpha) ||
brush->jitter != cache->lastjitter ||
rotation != cache->last_rotation ||
do_random)
@@ -365,11 +367,13 @@ static void brush_painter_2d_refresh_cache(BrushPainter *painter, const float po
size = (cache->size) ? cache->size : diameter;
if (do_tiled) {
- BKE_brush_imbuf_new(scene, brush, flt, 3, size, &cache->maskibuf, use_color_correction);
+ BKE_brush_imbuf_new(scene, brush, flt, 3, size, &cache->maskibuf,
+ use_color_correction, use_brush_alpha);
brush_painter_2d_tiled_tex_partial_update(painter, pos);
}
else
- BKE_brush_imbuf_new(scene, brush, flt, 2, size, &cache->ibuf, use_color_correction);
+ BKE_brush_imbuf_new(scene, brush, flt, 2, size, &cache->ibuf,
+ use_color_correction, use_brush_alpha);
cache->lastsize = diameter;
cache->lastalpha = alpha;
@@ -552,7 +556,8 @@ 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, ibuf, region[a].destx, region[a].desty,
+ IMB_rectblend(ibufb, ibufb, ibuf, 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);
}
@@ -565,9 +570,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, ibuf, destx, desty, srcx, srcy, w, h,
+ IMB_rectblend(clonebuf, clonebuf, ibuf, NULL, 0, destx, desty, destx, desty, srcx, srcy, w, h,
IMB_BLEND_COPY_RGB);
- IMB_rectblend(clonebuf, ibufb, destx, desty, destx, desty, w, h,
+ IMB_rectblend(clonebuf, clonebuf, ibufb, NULL, 0, destx, desty, destx, desty, destx, desty, w, h,
IMB_BLEND_COPY_ALPHA);
return clonebuf;
@@ -582,12 +587,14 @@ static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[
static int paint_2d_op(void *state, ImBuf *ibufb, const float lastpos[2], const float pos[2])
{
ImagePaintState *s = ((ImagePaintState *)state);
- ImBuf *clonebuf = NULL, *frombuf;
+ ImBuf *clonebuf = NULL, *frombuf, *tmpbuf = NULL;
ImagePaintRegion region[4];
short torus = s->brush->flag & BRUSH_TORUS;
short blend = s->blend;
float *offset = s->brush->clone.offset;
float liftpos[2];
+ float brush_alpha = BKE_brush_alpha_get(s->scene, s->brush);
+ unsigned short mask_max = (unsigned short)(brush_alpha * 65535.0f);
int bpos[2], blastpos[2], bliftpos[2];
int a, tot;
@@ -623,19 +630,55 @@ static int paint_2d_op(void *state, ImBuf *ibufb, const float lastpos[2], const
tot = 1;
}
+ if (s->do_masking)
+ tmpbuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0);
+
/* blend into canvas */
for (a = 0; a < tot; a++) {
imapaint_dirty_region(s->image, s->canvas,
region[a].destx, region[a].desty,
region[a].width, region[a].height);
-
- IMB_rectblend(s->canvas, frombuf,
- region[a].destx, region[a].desty,
- region[a].srcx, region[a].srcy,
- region[a].width, region[a].height, blend);
+
+ if (s->do_masking) {
+ /* masking, find original pixels tiles from undo buffer to composite over */
+ int tilex, tiley, tilew, tileh, tx, ty;
+
+ imapaint_region_tiles(s->canvas, region[a].destx, region[a].desty,
+ region[a].width, region[a].height,
+ &tilex, &tiley, &tilew, &tileh);
+
+ for (ty = tiley; ty <= tileh; ty++) {
+ for (tx = tilex; tx <= tilew; tx++) {
+ /* retrieve original pixels + mask from undo buffer */
+ unsigned short *mask;
+ int origx = region[a].destx - tx * IMAPAINT_TILE_SIZE;
+ int origy = region[a].desty - ty * IMAPAINT_TILE_SIZE;
+
+ if (s->canvas->rect_float)
+ tmpbuf->rect_float = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask);
+ else
+ tmpbuf->rect = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask);
+
+ IMB_rectblend(s->canvas, tmpbuf, frombuf, mask, mask_max,
+ region[a].destx, region[a].desty,
+ origx, origy,
+ region[a].srcx, region[a].srcy,
+ region[a].width, region[a].height, blend);
+ }
+ }
+ }
+ else {
+ /* no masking, composite brush directly onto canvas */
+ IMB_rectblend(s->canvas, s->canvas, frombuf, 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, blend);
+ }
}
if (clonebuf) IMB_freeImBuf(clonebuf);
+ if (tmpbuf) IMB_freeImBuf(tmpbuf);
return 1;
}
@@ -684,6 +727,11 @@ static int paint_2d_canvas_set(ImagePaintState *s, Image *ima)
IMB_rect_from_float(s->clonecanvas);
}
+ /* set masking */
+ s->do_masking = (s->brush->flag & BRUSH_AIRBRUSH || (s->brush->mtex.tex &&
+ !ELEM(s->brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL)))
+ ? false : true;
+
return 1;
}
@@ -691,6 +739,9 @@ static void paint_2d_canvas_free(ImagePaintState *s)
{
BKE_image_release_ibuf(s->image, s->canvas, NULL);
BKE_image_release_ibuf(s->brush->clone.image, s->clonecanvas, NULL);
+
+ if (s->do_masking)
+ image_undo_remove_masks();
}
int paint_2d_stroke(void *ps, const int prev_mval[2], const int mval[2], int eraser)
@@ -734,7 +785,7 @@ int paint_2d_stroke(void *ps, const int prev_mval[2], const int mval[2], int era
*/
brush_painter_2d_require_imbuf(painter, ((ibuf->rect_float) ? 1 : 0), 0);
- brush_painter_2d_refresh_cache(painter, newuv, is_data == false);
+ brush_painter_2d_refresh_cache(painter, newuv, is_data == false, s->do_masking);
if (paint_2d_op(s, painter->cache.ibuf, olduv, newuv)) {
imapaint_image_update(s->sima, s->image, ibuf, false);
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 0088e5aa3cb..13b3629518f 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -3887,6 +3887,8 @@ static void *do_projectpaint_thread(void *ph_v)
mask *= BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool);
}
+ CLAMP(mask, 0.0f, 1.0f);
+
if (ps->do_masking) {
/* masking to keep brush contribution to a pixel limited. note we do not do
* a simple max(mask, mask_accum), as this is very sensitive to spacing and
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index f77d0ac4144..0085998bd58 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -126,7 +126,9 @@ typedef struct ImagePaintPartialRedraw {
#define IMAPAINT_CHAR_TO_FLOAT(c) ((c) / 255.0f)
int image_texture_paint_poll(struct bContext *C);
+void *image_undo_find_tile(struct Image *ima, struct ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask);
void *image_undo_push_tile(struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile);
+void image_undo_remove_masks(void);
void image_undo_restore(struct bContext *C, struct ListBase *lb);
void image_undo_free(struct ListBase *lb);
void imapaint_image_update(struct SpaceImage *sima, struct Image *image, struct ImBuf *ibuf, short texpaint);
@@ -134,6 +136,7 @@ struct ImagePaintPartialRedraw *get_imapaintpartial(void);
void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr);
void imapaint_clear_partial_redraw(void);
void imapaint_dirty_region(struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h);
+void imapaint_region_tiles(struct ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th);
int get_imapaint_zoom(struct bContext *C, float *zoomx, float *zoomy);
void *paint_2d_new_stroke(struct bContext *, struct wmOperator *);
void paint_2d_redraw(const bContext *C, void *ps, int final);
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 04179b28e56..7253a61092c 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -178,8 +178,10 @@ void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx,
int *desty, int *srcx, int *srcy, int *width, int *height);
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 *sbuf, int destx,
- int desty, int srcx, int srcy, int width, int height, IMB_BlendMode mode);
+void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *obuf, struct ImBuf *sbuf,
+ unsigned short *mask, 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 95426c573db..d9fc4fe172a 100644
--- a/source/blender/imbuf/intern/rectop.c
+++ b/source/blender/imbuf/intern/rectop.c
@@ -104,7 +104,7 @@ void IMB_blend_color_float(float dst[4], float src1[4], float src2[4], IMB_Blend
/* clipping */
-void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx,
+void IMB_rectclip(ImBuf *dbuf, ImBuf *sbuf, int *destx,
int *desty, int *srcx, int *srcy, int *width, int *height)
{
int tmp;
@@ -150,43 +150,125 @@ void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx,
}
}
+static void imb_rectclip3(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, int *destx,
+ int *desty, int *origx, int *origy, int *srcx, int *srcy,
+ int *width, int *height)
+{
+ int tmp;
+
+ if (dbuf == NULL) return;
+
+ if (*destx < 0) {
+ *srcx -= *destx;
+ *origx -= *destx;
+ *width += *destx;
+ *destx = 0;
+ }
+ if (*origx < 0) {
+ *destx -= *origx;
+ *srcx -= *origx;
+ *width += *origx;
+ *origx = 0;
+ }
+ if (*srcx < 0) {
+ *destx -= *srcx;
+ *origx -= *srcx;
+ *width += *srcx;
+ *srcx = 0;
+ }
+
+ if (*desty < 0) {
+ *srcy -= *desty;
+ *origy -= *desty;
+ *height += *desty;
+ *desty = 0;
+ }
+ if (*origy < 0) {
+ *desty -= *origy;
+ *srcy -= *origy;
+ *height += *origy;
+ *origy = 0;
+ }
+ if (*srcy < 0) {
+ *desty -= *srcy;
+ *origy -= *srcy;
+ *height += *srcy;
+ *srcy = 0;
+ }
+
+ tmp = dbuf->x - *destx;
+ if (*width > tmp) *width = tmp;
+ tmp = dbuf->y - *desty;
+ if (*height > tmp) *height = tmp;
+
+ if (obuf) {
+ tmp = obuf->x - *origx;
+ if (*width > tmp) *width = tmp;
+ tmp = obuf->y - *origy;
+ if (*height > tmp) *height = tmp;
+ }
+
+ if (sbuf) {
+ tmp = sbuf->x - *srcx;
+ if (*width > tmp) *width = tmp;
+ tmp = sbuf->y - *srcy;
+ if (*height > tmp) *height = tmp;
+ }
+
+ if ((*height <= 0) || (*width <= 0)) {
+ *width = 0;
+ *height = 0;
+ }
+}
+
/* copy and blend */
-void IMB_rectcpy(struct ImBuf *dbuf, struct 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, sbuf, destx, desty, srcx, srcy, width, height,
- IMB_BLEND_COPY);
+ IMB_rectblend(dbuf, dbuf, sbuf, 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(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
- int desty, int srcx, int srcy, int width, int height, IMB_BlendMode mode)
+void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *maskrect, 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, *srect = NULL, *dr, *sr;
- float *drectf = NULL, *srectf = NULL, *drf, *srf;
- int do_float, do_char, srcskip, destskip, x;
+ unsigned int *drect = NULL, *orect, *srect = NULL, *dr, *or, *sr;
+ float *drectf = NULL, *orectf, *srectf = NULL, *drf, *orf, *srf;
+ unsigned short *mr;
+ int do_float, do_char, srcskip, destskip, origskip, x;
IMB_blend_func func = NULL;
IMB_blend_func_float func_float = NULL;
- if (dbuf == NULL) return;
+ if (dbuf == NULL || obuf == NULL) return;
- IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &width, &height);
+ imb_rectclip3(dbuf, obuf, sbuf, &destx, &desty, &origx, &origy, &srcx, &srcy, &width, &height);
if (width == 0 || height == 0) return;
if (sbuf && sbuf->channels != 4) return;
if (dbuf->channels != 4) return;
-
- do_char = (sbuf && sbuf->rect && dbuf->rect);
- do_float = (sbuf && sbuf->rect_float && dbuf->rect_float);
- if (do_char) drect = dbuf->rect + desty * dbuf->x + destx;
- if (do_float) drectf = dbuf->rect_float + (desty * dbuf->x + destx) * 4;
+ do_char = (sbuf && sbuf->rect && dbuf->rect && obuf->rect);
+ do_float = (sbuf && sbuf->rect_float && dbuf->rect_float && obuf->rect_float);
+
+ if (do_char) {
+ drect = dbuf->rect + desty * dbuf->x + destx;
+ orect = obuf->rect + origy * obuf->x + origx;
+ }
+ if (do_float) {
+ drectf = dbuf->rect_float + (desty * dbuf->x + destx) * 4;
+ orectf = obuf->rect_float + (origy * obuf->x + origx) * 4;
+ }
+
+ if (maskrect)
+ maskrect += origy * obuf->x + origx;
destskip = dbuf->x;
+ origskip = obuf->x;
if (sbuf) {
if (do_char) srect = sbuf->rect + srcy * sbuf->x + srcx;
@@ -307,24 +389,92 @@ void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
for (; height > 0; height--) {
if (do_char) {
dr = drect;
+ or = orect;
sr = srect;
- for (x = width; x > 0; x--, dr++, sr++) {
- if (((unsigned char *)sr)[3])
- func((unsigned char *)dr, (unsigned char *)dr, (unsigned char *)sr);
+
+ if (maskrect) {
+ /* mask accumulation for painting */
+ mr = maskrect;
+
+ for (x = width; x > 0; x--, dr++, or++, sr++, mr++) {
+ unsigned char *src = (unsigned char*)sr;
+
+ if (src[3]) {
+ unsigned short mask = *mr + divide_round_i((mask_max - *mr) * src[3], 255);
+
+ if (mask > *mr) {
+ unsigned char mask_src[4];
+
+ *mr = mask;
+
+ mask_src[0] = src[0];
+ mask_src[1] = src[1];
+ mask_src[2] = src[2];
+ mask_src[3] = mask >> 8;
+
+ func((unsigned char *)dr, (unsigned char *)or, mask_src);
+ }
+ }
+ }
+
+ maskrect += origskip;
+ }
+ else {
+ /* regular blending */
+ for (x = width; x > 0; x--, dr++, or++, sr++) {
+ if (((unsigned char *)sr)[3])
+ func((unsigned char *)dr, (unsigned char *)or, (unsigned char *)sr);
+ }
}
drect += destskip;
+ orect += origskip;
srect += srcskip;
}
if (do_float) {
drf = drectf;
+ orf = orectf;
srf = srectf;
- for (x = width; x > 0; x--, drf += 4, srf += 4) {
- if (srf[3] != 0)
- func_float(drf, drf, srf);
+
+ if (maskrect) {
+ /* mask accumulation for painting */
+ mr = maskrect;
+
+ 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);
+
+ if (mask > *mr) {
+ 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;
+
+ func_float(drf, orf, mask_srf);
+ }
+ }
+ }
+
+ maskrect += origskip;
}
+ else {
+ /* regular blending */
+ for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4) {
+ if (srf[3] != 0)
+ func_float(drf, orf, srf);
+ }
+ }
+
drectf += destskip * 4;
+ orectf += origskip * 4;
srectf += srcskip * 4;
}
}
@@ -333,7 +483,7 @@ void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
/* fill */
-void IMB_rectfill(struct ImBuf *drect, const float col[4])
+void IMB_rectfill(ImBuf *drect, const float col[4])
{
int num;
@@ -462,7 +612,7 @@ void buf_rectfill_area(unsigned char *rect, float *rectf, int width, int height,
}
}
-void IMB_rectfill_area(struct ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2, struct ColorManagedDisplay *display)
+void IMB_rectfill_area(ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2, struct ColorManagedDisplay *display)
{
if (!ibuf) return;
buf_rectfill_area((unsigned char *) ibuf->rect, ibuf->rect_float, ibuf->x, ibuf->y, col, display,