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:
Diffstat (limited to 'source/blender/editors/sculpt_paint/paint_image_2d.c')
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c518
1 files changed, 365 insertions, 153 deletions
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;