[Bf-blender-cvs] [fdebdba] soc-2013-paint: Speedup for 2D painting: Use partial update for mask textures.
Antony Riakiotakis
noreply at git.blender.org
Mon Mar 10 23:59:40 CET 2014
Commit: fdebdba07d9df438da5cddd2af95fa2b7ac7ba1f
Author: Antony Riakiotakis
Date: Tue Mar 11 00:59:21 2014 +0200
https://developer.blender.org/rBfdebdba07d9df438da5cddd2af95fa2b7ac7ba1f
Speedup for 2D painting: Use partial update for mask textures.
===================================================================
M source/blender/editors/sculpt_paint/paint_image_2d.c
===================================================================
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index c5bb760..5051eb3 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -91,6 +91,9 @@ typedef struct BrushPainterCache {
ImBuf *texibuf;
unsigned short *curve_mask;
unsigned short *tex_mask;
+ unsigned short *tex_mask_old;
+ unsigned int tex_mask_old_w;
+ unsigned int tex_mask_old_h;
} BrushPainterCache;
typedef struct BrushPainter {
@@ -167,18 +170,13 @@ static void brush_painter_2d_require_imbuf(BrushPainter *painter, bool use_float
if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf);
if (painter->cache.curve_mask) MEM_freeN(painter->cache.curve_mask);
if (painter->cache.tex_mask) MEM_freeN(painter->cache.tex_mask);
+ if (painter->cache.tex_mask_old) MEM_freeN(painter->cache.tex_mask_old);
painter->cache.ibuf = NULL;
painter->cache.curve_mask = NULL;
painter->cache.tex_mask = NULL;
painter->cache.lastdiameter = -1; /* force ibuf create in refresh */
}
- if (painter->cache.use_float != use_float) {
- if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf);
- painter->cache.texibuf = NULL;
- painter->cache.lastdiameter = -1; /* force ibuf create in refresh */
- }
-
painter->cache.use_float = use_float;
painter->cache.use_color_correction = use_float && use_color_correction;
painter->cache.is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? true : false;
@@ -191,6 +189,7 @@ static void brush_painter_2d_free(BrushPainter *painter)
if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf);
if (painter->cache.curve_mask) MEM_freeN(painter->cache.curve_mask);
if (painter->cache.tex_mask) MEM_freeN(painter->cache.tex_mask);
+ if (painter->cache.tex_mask_old) MEM_freeN(painter->cache.tex_mask_old);
MEM_freeN(painter);
}
@@ -213,7 +212,7 @@ static unsigned short *brush_painter_mask_ibuf_new(BrushPainter *painter, int si
unsigned short *mask, *m;
int x, y, thread = 0;
- mask = MEM_callocN(sizeof(unsigned short) * size * size, "brush_painter_mask");
+ mask = MEM_mallocN(sizeof(unsigned short) * size * size, "brush_painter_mask");
m = mask;
for (y = 0; y < size; y++) {
@@ -229,6 +228,117 @@ static unsigned short *brush_painter_mask_ibuf_new(BrushPainter *painter, int si
return mask;
}
+/* update rectangular section of the brush image */
+static void brush_painter_mask_imbuf_update(BrushPainter *painter, unsigned short *tex_mask_old,
+ int origx, int origy, int w, int h, int xt, int yt, int diameter)
+{
+ Scene *scene = painter->scene;
+ Brush *brush = painter->brush;
+ rctf tex_mapping = painter->mask_mapping;
+ struct ImagePool *pool = painter->pool;
+ unsigned short res;
+
+ bool use_texture_old = (tex_mask_old != NULL);
+
+ int x, y, thread = 0;
+
+ unsigned short *tex_mask = painter->cache.tex_mask;
+ unsigned short *tex_mask_cur = painter->cache.tex_mask_old;
+
+ /* fill pixels */
+ for (y = origy; y < h; y++) {
+ for (x = origx; x < w; x++) {
+ /* sample texture */
+ float texco[3];
+
+ /* handle byte pixel */
+ unsigned short *b = tex_mask + (y * diameter + x);
+ unsigned short *t = tex_mask_cur + (y * diameter + x);
+
+ if (!use_texture_old) {
+ brush_imbuf_tex_co(&tex_mapping, x, y, texco);
+ res = (unsigned short)(65535.0f * BKE_brush_sample_masktex(scene, brush, texco, thread, pool));
+ }
+
+ /* read from old texture buffer */
+ if (use_texture_old) {
+ res = *(tex_mask_old + ((y - origy + yt) * painter->cache.tex_mask_old_w + (x - origx + xt)));
+ }
+
+ /* write to new texture mask */
+ *t = res;
+ /* write to mask image buffer */
+ *b = res;
+ }
+ }
+}
+
+
+/* update the brush mask 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_mask_imbuf_partial_update(BrushPainter *painter, const float pos[2], int diameter)
+{
+ BrushPainterCache *cache = &painter->cache;
+ unsigned short *tex_mask_old;
+ int destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
+
+ /* create brush image buffer if it didn't exist yet */
+ if (!cache->tex_mask)
+ cache->tex_mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");
+
+ /* create new texture image buffer with coordinates relative to old */
+ tex_mask_old = cache->tex_mask_old;
+ cache->tex_mask_old = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");
+
+ if (tex_mask_old) {
+ ImBuf maskibuf;
+ ImBuf maskibuf_old;
+ maskibuf.x = maskibuf.y = diameter;
+ maskibuf_old.x = cache->tex_mask_old_w;
+ maskibuf_old.y = cache->tex_mask_old_h;
+
+ srcx = srcy = 0;
+ destx = (int)painter->lastpaintpos[0] - (int)pos[0];
+ desty = (int)painter->lastpaintpos[1] - (int)pos[1];
+ w = cache->tex_mask_old_w;
+ h = cache->tex_mask_old_h;
+
+ /* hack, use temporary rects so that clipping works */
+ IMB_rectclip(&maskibuf, &maskibuf_old, &destx, &desty, &srcx, &srcy, &w, &h);
+ }
+ else {
+ srcx = srcy = 0;
+ destx = desty = 0;
+ w = h = 0;
+ }
+
+ x1 = destx;
+ y1 = desty;
+ x2 = min_ii(destx + w, diameter);
+ y2 = min_ii(desty + h, diameter);
+
+ /* blend existing texture in new position */
+ if ((x1 < x2) && (y1 < y2))
+ brush_painter_mask_imbuf_update(painter, tex_mask_old, x1, y1, x2, y2, srcx, srcy, diameter);
+
+ if (tex_mask_old)
+ MEM_freeN(tex_mask_old);
+
+ /* sample texture in new areas */
+ if ((0 < x1) && (0 < diameter))
+ brush_painter_mask_imbuf_update(painter, NULL, 0, 0, x1, diameter, 0, 0, diameter);
+ if ((x2 < diameter) && (0 < diameter))
+ brush_painter_mask_imbuf_update(painter, NULL, x2, 0, diameter, diameter, 0, 0, diameter);
+ if ((x1 < x2) && (0 < y1))
+ brush_painter_mask_imbuf_update(painter, NULL, x1, 0, x2, y1, 0, 0, diameter);
+ if ((x1 < x2) && (y2 < diameter))
+ brush_painter_mask_imbuf_update(painter, NULL, x1, y2, x2, diameter, 0, 0, diameter);
+
+ /* through with sampling, now update sizes */
+ cache->tex_mask_old_w = diameter;
+ cache->tex_mask_old_h = diameter;
+}
/* create a mask with the falloff strength */
static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter, int diameter, float radius)
@@ -241,7 +351,7 @@ static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter, int d
unsigned short *mask, *m;
int x, y;
- mask = MEM_callocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");
+ mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");
m = mask;
for (y = 0; y < diameter; y++) {
@@ -596,7 +706,7 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *pai
brush->mask_mtex.brush_map_mode, &painter->mask_mapping);
if (do_partial_update_mask)
- cache->tex_mask = brush_painter_mask_ibuf_new(painter, diameter);
+ brush_painter_mask_imbuf_partial_update(painter, pos, diameter);
else
cache->tex_mask = brush_painter_mask_ibuf_new(painter, diameter);
cache->last_mask_rotation = mask_rotation;
More information about the Bf-blender-cvs
mailing list