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:
authorCampbell Barton <ideasman42@gmail.com>2019-04-17 07:17:24 +0300
committerCampbell Barton <ideasman42@gmail.com>2019-04-17 07:21:24 +0300
commite12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch)
tree8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/editors/sculpt_paint/paint_image_2d.c
parentb3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff)
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211. For details on usage and instructions for migrating branches without conflicts, see: https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/editors/sculpt_paint/paint_image_2d.c')
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c3129
1 files changed, 1652 insertions, 1477 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index cad75efbf56..5390f18304a 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -30,7 +30,6 @@
#include "DNA_space_types.h"
#include "DNA_object_types.h"
-
#include "BLI_math_color_blend.h"
#include "BLI_stack.h"
#include "BLI_bitmap.h"
@@ -57,7 +56,6 @@
#include "UI_view2d.h"
-
#include "GPU_draw.h"
#include "paint_intern.h"
@@ -67,1677 +65,1854 @@
/* Defines and Structs */
typedef struct BrushPainterCache {
- bool use_float; /* need float imbuf? */
- bool use_color_correction; /* use color correction for float */
- bool invert;
-
- bool is_texbrush;
- bool is_maskbrush;
-
- int lastdiameter;
- float last_tex_rotation;
- float last_mask_rotation;
- float last_pressure;
-
- ImBuf *ibuf;
- 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;
+ bool use_float; /* need float imbuf? */
+ bool use_color_correction; /* use color correction for float */
+ bool invert;
+
+ bool is_texbrush;
+ bool is_maskbrush;
+
+ int lastdiameter;
+ float last_tex_rotation;
+ float last_mask_rotation;
+ float last_pressure;
+
+ ImBuf *ibuf;
+ 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 {
- Scene *scene;
- Brush *brush;
+ Scene *scene;
+ Brush *brush;
- float lastpaintpos[2]; /* position of last paint op */
- float startpaintpos[2]; /* position of first paint */
+ float lastpaintpos[2]; /* position of last paint op */
+ float startpaintpos[2]; /* position of first paint */
- short firsttouch; /* first paint op */
+ short firsttouch; /* first paint op */
- struct ImagePool *pool; /* image pool */
- rctf tex_mapping; /* texture coordinate mapping */
- rctf mask_mapping; /* mask texture coordinate mapping */
+ struct ImagePool *pool; /* image pool */
+ rctf tex_mapping; /* texture coordinate mapping */
+ rctf mask_mapping; /* mask texture coordinate mapping */
- BrushPainterCache cache;
+ BrushPainterCache cache;
} BrushPainter;
typedef struct ImagePaintRegion {
- int destx, desty;
- int srcx, srcy;
- int width, height;
+ int destx, desty;
+ int srcx, srcy;
+ int width, height;
} ImagePaintRegion;
typedef struct ImagePaintState {
- BrushPainter *painter;
- SpaceImage *sima;
- View2D *v2d;
- Scene *scene;
- bScreen *screen;
- struct ImagePool *image_pool;
-
- Brush *brush;
- short tool, blend;
- Image *image;
- ImBuf *canvas;
- ImBuf *clonecanvas;
- const char *warnpackedfile;
- const char *warnmultifile;
-
- bool do_masking;
-
- /* viewport texture paint only, but _not_ project paint */
- Object *ob;
- int faceindex;
- float uv[2];
- int do_facesel;
- int symmetry;
-
- bool need_redraw;
-
- BlurKernel *blurkernel;
+ BrushPainter *painter;
+ SpaceImage *sima;
+ View2D *v2d;
+ Scene *scene;
+ bScreen *screen;
+ struct ImagePool *image_pool;
+
+ Brush *brush;
+ short tool, blend;
+ Image *image;
+ ImBuf *canvas;
+ ImBuf *clonecanvas;
+ const char *warnpackedfile;
+ const char *warnmultifile;
+
+ bool do_masking;
+
+ /* viewport texture paint only, but _not_ project paint */
+ Object *ob;
+ int faceindex;
+ float uv[2];
+ int do_facesel;
+ int symmetry;
+
+ bool need_redraw;
+
+ BlurKernel *blurkernel;
} ImagePaintState;
-
static BrushPainter *brush_painter_2d_new(Scene *scene, Brush *brush, bool invert)
{
- BrushPainter *painter = MEM_callocN(sizeof(BrushPainter), "BrushPainter");
+ BrushPainter *painter = MEM_callocN(sizeof(BrushPainter), "BrushPainter");
- painter->brush = brush;
- painter->scene = scene;
- painter->firsttouch = 1;
- painter->cache.lastdiameter = -1; /* force ibuf create in refresh */
- painter->cache.invert = invert;
+ painter->brush = brush;
+ painter->scene = scene;
+ painter->firsttouch = 1;
+ painter->cache.lastdiameter = -1; /* force ibuf create in refresh */
+ painter->cache.invert = invert;
- return painter;
+ return painter;
}
-
-static void brush_painter_2d_require_imbuf(BrushPainter *painter, bool use_float, bool use_color_correction)
+static void brush_painter_2d_require_imbuf(BrushPainter *painter,
+ bool use_float,
+ bool use_color_correction)
{
- Brush *brush = painter->brush;
-
- if ((painter->cache.use_float != 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 */
- }
-
- 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;
- painter->cache.is_maskbrush = (brush->mask_mtex.tex) ? true : false;
+ Brush *brush = painter->brush;
+
+ if ((painter->cache.use_float != 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 */
+ }
+
+ 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;
+ 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.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);
+ if (painter->cache.ibuf)
+ IMB_freeImBuf(painter->cache.ibuf);
+ 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);
}
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;
+ texco[0] = mapping->xmin + x * mapping->xmax;
+ texco[1] = mapping->ymin + y * mapping->ymax;
+ texco[2] = 0.0f;
}
/* create a mask with the mask texture */
static unsigned short *brush_painter_mask_ibuf_new(BrushPainter *painter, int size)
{
- Scene *scene = painter->scene;
- Brush *brush = painter->brush;
- rctf mask_mapping = painter->mask_mapping;
- struct ImagePool *pool = painter->pool;
-
- float texco[3];
- unsigned short *mask, *m;
- int x, y, thread = 0;
-
- mask = MEM_mallocN(sizeof(unsigned short) * size * size, "brush_painter_mask");
- m = mask;
-
- for (y = 0; y < size; y++) {
- for (x = 0; x < size; x++, m++) {
- float res;
- brush_imbuf_tex_co(&mask_mapping, x, y, texco);
- res = BKE_brush_sample_masktex(scene, brush, texco, thread, pool);
- *m = (unsigned short)(65535.0f * res);
- }
- }
-
- return mask;
+ Scene *scene = painter->scene;
+ Brush *brush = painter->brush;
+ rctf mask_mapping = painter->mask_mapping;
+ struct ImagePool *pool = painter->pool;
+
+ float texco[3];
+ unsigned short *mask, *m;
+ int x, y, thread = 0;
+
+ mask = MEM_mallocN(sizeof(unsigned short) * size * size, "brush_painter_mask");
+ m = mask;
+
+ for (y = 0; y < size; y++) {
+ for (x = 0; x < size; x++, m++) {
+ float res;
+ brush_imbuf_tex_co(&mask_mapping, x, y, texco);
+ res = BKE_brush_sample_masktex(scene, brush, texco, thread, pool);
+ *m = (unsigned short)(65535.0f * res);
+ }
+ }
+
+ 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)
+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;
- }
- }
+ 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)
+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;
- w = cache->tex_mask_old_w;
- h = cache->tex_mask_old_h;
- destx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0]) + (diameter / 2 - w / 2);
- desty = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1]) + (diameter / 2 - h / 2);
-
- /* 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 = min_ii(destx, diameter);
- y1 = min_ii(desty, diameter);
- 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;
+ 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;
+ w = cache->tex_mask_old_w;
+ h = cache->tex_mask_old_h;
+ destx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0]) + (diameter / 2 - w / 2);
+ desty = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1]) + (diameter / 2 - h / 2);
+
+ /* 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 = min_ii(destx, diameter);
+ y1 = min_ii(desty, diameter);
+ 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)
+static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter,
+ int diameter,
+ float radius)
{
- Brush *brush = painter->brush;
+ Brush *brush = painter->brush;
- int xoff = -radius;
- int yoff = -radius;
+ int xoff = -radius;
+ int yoff = -radius;
- unsigned short *mask, *m;
- int x, y;
+ unsigned short *mask, *m;
+ int x, y;
- mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");
- m = mask;
+ mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");
+ m = mask;
- for (y = 0; y < diameter; y++) {
- for (x = 0; x < diameter; x++, m++) {
- float xy[2] = {x + xoff, y + yoff};
- float len = len_v2(xy);
+ for (y = 0; y < diameter; y++) {
+ for (x = 0; x < diameter; x++, m++) {
+ float xy[2] = {x + xoff, y + yoff};
+ float len = len_v2(xy);
- *m = (unsigned short)(65535.0f * BKE_brush_curve_strength_clamped(brush, len, radius));
- }
- }
+ *m = (unsigned short)(65535.0f * BKE_brush_curve_strength_clamped(brush, len, radius));
+ }
+ }
- return mask;
+ return mask;
}
-
/* create imbuf with brush color */
-static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size, float pressure, float distance)
+static ImBuf *brush_painter_imbuf_new(BrushPainter *painter,
+ int size,
+ float pressure,
+ float distance)
{
- Scene *scene = painter->scene;
- Brush *brush = painter->brush;
-
- const char *display_device = scene->display_settings.display_device;
- struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
-
- rctf tex_mapping = painter->tex_mapping;
- struct ImagePool *pool = painter->pool;
-
- bool use_color_correction = painter->cache.use_color_correction;
- bool use_float = painter->cache.use_float;
- bool is_texbrush = painter->cache.is_texbrush;
-
- 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) {
- paint_brush_color_get(scene, brush, use_color_correction, painter->cache.invert, distance, pressure, brush_rgb, display);
- }
- 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);
- /* TODO(sergey): Support texture paint color space. */
- if (!use_float) {
- IMB_colormanagement_scene_linear_to_display_v3(rgba, display);
- }
- mul_v3_v3(rgba, brush_rgb);
- }
- else {
- copy_v3_v3(rgba, brush_rgb);
- rgba[3] = 1.0f;
- }
-
- 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] = unit_float_to_uchar_clamp(rgba[3]);
- }
- }
- }
-
- return ibuf;
+ Scene *scene = painter->scene;
+ Brush *brush = painter->brush;
+
+ const char *display_device = scene->display_settings.display_device;
+ struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
+
+ rctf tex_mapping = painter->tex_mapping;
+ struct ImagePool *pool = painter->pool;
+
+ bool use_color_correction = painter->cache.use_color_correction;
+ bool use_float = painter->cache.use_float;
+ bool is_texbrush = painter->cache.is_texbrush;
+
+ 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) {
+ paint_brush_color_get(scene,
+ brush,
+ use_color_correction,
+ painter->cache.invert,
+ distance,
+ pressure,
+ brush_rgb,
+ display);
+ }
+ 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);
+ /* TODO(sergey): Support texture paint color space. */
+ if (!use_float) {
+ IMB_colormanagement_scene_linear_to_display_v3(rgba, display);
+ }
+ mul_v3_v3(rgba, brush_rgb);
+ }
+ else {
+ copy_v3_v3(rgba, brush_rgb);
+ rgba[3] = 1.0f;
+ }
+
+ 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] = unit_float_to_uchar_clamp(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)
+ BrushPainter *painter, ImBuf *oldtexibuf, int origx, int origy, int w, int h, int xt, int yt)
{
- Scene *scene = painter->scene;
- Brush *brush = painter->brush;
-
- const char *display_device = scene->display_settings.display_device;
- struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
-
- rctf tex_mapping = painter->tex_mapping;
- struct ImagePool *pool = painter->pool;
-
- bool use_color_correction = painter->cache.use_color_correction;
- bool use_float = painter->cache.use_float;
- bool is_texbrush = painter->cache.is_texbrush;
- 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;
-
- /* get brush color */
- if (brush->imagepaint_tool == PAINT_TOOL_DRAW) {
- paint_brush_color_get(scene, brush, use_color_correction, painter->cache.invert, 0.0, 1.0, brush_rgb, display);
- }
- else {
- brush_rgb[0] = 1.0f;
- brush_rgb[1] = 1.0f;
- brush_rgb[2] = 1.0f;
- }
-
- /* fill pixels */
- 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);
- /* TODO(sergey): Support texture paint color space. */
- if (!use_float) {
- IMB_colormanagement_scene_linear_to_display_v3(rgba, display);
- }
- mul_v3_v3(rgba, brush_rgb);
- }
- else {
- copy_v3_v3(rgba, brush_rgb);
- rgba[3] = 1.0f;
- }
- }
-
- 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) {
- const 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);
-
- /* 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];
-
- /* write to brush image buffer */
- b[0] = crgba[0];
- b[1] = crgba[1];
- b[2] = crgba[2];
- b[3] = crgba[3];
- }
- }
- }
+ Scene *scene = painter->scene;
+ Brush *brush = painter->brush;
+
+ const char *display_device = scene->display_settings.display_device;
+ struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
+
+ rctf tex_mapping = painter->tex_mapping;
+ struct ImagePool *pool = painter->pool;
+
+ bool use_color_correction = painter->cache.use_color_correction;
+ bool use_float = painter->cache.use_float;
+ bool is_texbrush = painter->cache.is_texbrush;
+ 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;
+
+ /* get brush color */
+ if (brush->imagepaint_tool == PAINT_TOOL_DRAW) {
+ paint_brush_color_get(
+ scene, brush, use_color_correction, painter->cache.invert, 0.0, 1.0, brush_rgb, display);
+ }
+ else {
+ brush_rgb[0] = 1.0f;
+ brush_rgb[1] = 1.0f;
+ brush_rgb[2] = 1.0f;
+ }
+
+ /* fill pixels */
+ 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);
+ /* TODO(sergey): Support texture paint color space. */
+ if (!use_float) {
+ IMB_colormanagement_scene_linear_to_display_v3(rgba, display);
+ }
+ mul_v3_v3(rgba, brush_rgb);
+ }
+ else {
+ copy_v3_v3(rgba, brush_rgb);
+ rgba[3] = 1.0f;
+ }
+ }
+
+ 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) {
+ const 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);
+
+ /* 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];
+
+ /* write to brush image buffer */
+ b[0] = crgba[0];
+ b[1] = crgba[1];
+ b[2] = crgba[2];
+ b[3] = crgba[3];
+ }
+ }
+ }
}
/* 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], int diameter)
+static void brush_painter_imbuf_partial_update(BrushPainter *painter,
+ const float pos[2],
+ int diameter)
{
- BrushPainterCache *cache = &painter->cache;
- ImBuf *oldtexibuf, *ibuf;
- int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
-
- /* 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;
- w = oldtexibuf->x;
- h = oldtexibuf->y;
- destx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0]) + (diameter / 2 - w / 2);
- desty = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1]) + (diameter / 2 - h / 2);
-
- IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h);
- }
- else {
- srcx = srcy = 0;
- destx = desty = 0;
- w = h = 0;
- }
-
- x1 = min_ii(destx, ibuf->x);
- y1 = min_ii(desty, ibuf->y);
- 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_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_imbuf_update(painter, NULL, 0, 0, x1, ibuf->y, 0, 0);
- if ((x2 < ibuf->x) && (0 < ibuf->y))
- brush_painter_imbuf_update(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0);
- if ((x1 < x2) && (0 < y1))
- brush_painter_imbuf_update(painter, NULL, x1, 0, x2, y1, 0, 0);
- if ((x1 < x2) && (y2 < ibuf->y))
- brush_painter_imbuf_update(painter, NULL, x1, y2, x2, ibuf->y, 0, 0);
+ BrushPainterCache *cache = &painter->cache;
+ ImBuf *oldtexibuf, *ibuf;
+ int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
+
+ /* 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;
+ w = oldtexibuf->x;
+ h = oldtexibuf->y;
+ destx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0]) + (diameter / 2 - w / 2);
+ desty = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1]) + (diameter / 2 - h / 2);
+
+ IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h);
+ }
+ else {
+ srcx = srcy = 0;
+ destx = desty = 0;
+ w = h = 0;
+ }
+
+ x1 = min_ii(destx, ibuf->x);
+ y1 = min_ii(desty, ibuf->y);
+ 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_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_imbuf_update(painter, NULL, 0, 0, x1, ibuf->y, 0, 0);
+ if ((x2 < ibuf->x) && (0 < ibuf->y))
+ brush_painter_imbuf_update(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0);
+ if ((x1 < x2) && (0 < y1))
+ brush_painter_imbuf_update(painter, NULL, x1, 0, x2, y1, 0, 0);
+ if ((x1 < x2) && (y2 < ibuf->y))
+ brush_painter_imbuf_update(painter, NULL, x1, y2, x2, ibuf->y, 0, 0);
}
-static void brush_painter_2d_tex_mapping(ImagePaintState *s, int diameter, const float startpos[2], const float pos[2], const float mouse[2], int mapmode, rctf *mapping)
+static void brush_painter_2d_tex_mapping(ImagePaintState *s,
+ int diameter,
+ const float startpos[2],
+ const float pos[2],
+ const float mouse[2],
+ int mapmode,
+ rctf *mapping)
{
- float invw = 1.0f / (float)s->canvas->x;
- float invh = 1.0f / (float)s->canvas->y;
- int xmin, ymin, xmax, ymax;
- int ipos[2];
-
- /* find start coordinate of brush in canvas */
- ipos[0] = (int)floorf((pos[0] - diameter / 2) + 1.0f);
- ipos[1] = (int)floorf((pos[1] - diameter / 2) + 1.0f);
-
- if (mapmode == MTEX_MAP_MODE_STENCIL) {
- /* map from view coordinates of brush to region coordinates */
- UI_view2d_view_to_region(s->v2d, ipos[0] * invw, ipos[1] * invh, &xmin, &ymin);
- UI_view2d_view_to_region(s->v2d, (ipos[0] + diameter) * invw, (ipos[1] + diameter) * invh, &xmax, &ymax);
-
- /* output mapping from brush ibuf x/y to region coordinates */
- mapping->xmin = xmin;
- mapping->ymin = ymin;
- mapping->xmax = (xmax - xmin) / (float)diameter;
- mapping->ymax = (ymax - ymin) / (float)diameter;
- }
- else if (mapmode == MTEX_MAP_MODE_3D) {
- /* 3D mapping, just mapping to canvas 0..1 */
- mapping->xmin = 2.0f * (ipos[0] * invw - 0.5f);
- mapping->ymin = 2.0f * (ipos[1] * invh - 0.5f);
- mapping->xmax = 2.0f * invw;
- mapping->ymax = 2.0f * invh;
- }
- else if (ELEM(mapmode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_RANDOM)) {
- /* view mapping */
- mapping->xmin = mouse[0] - diameter * 0.5f + 0.5f;
- mapping->ymin = mouse[1] - diameter * 0.5f + 0.5f;
- mapping->xmax = 1.0f;
- mapping->ymax = 1.0f;
- }
- else /* if (mapmode == MTEX_MAP_MODE_TILED) */ {
- mapping->xmin = (int)(-diameter * 0.5) + (int)floorf(pos[0]) - (int)floorf(startpos[0]);
- mapping->ymin = (int)(-diameter * 0.5) + (int)floorf(pos[1]) - (int)floorf(startpos[1]);
- mapping->xmax = 1.0f;
- mapping->ymax = 1.0f;
- }
+ float invw = 1.0f / (float)s->canvas->x;
+ float invh = 1.0f / (float)s->canvas->y;
+ int xmin, ymin, xmax, ymax;
+ int ipos[2];
+
+ /* find start coordinate of brush in canvas */
+ ipos[0] = (int)floorf((pos[0] - diameter / 2) + 1.0f);
+ ipos[1] = (int)floorf((pos[1] - diameter / 2) + 1.0f);
+
+ if (mapmode == MTEX_MAP_MODE_STENCIL) {
+ /* map from view coordinates of brush to region coordinates */
+ UI_view2d_view_to_region(s->v2d, ipos[0] * invw, ipos[1] * invh, &xmin, &ymin);
+ UI_view2d_view_to_region(
+ s->v2d, (ipos[0] + diameter) * invw, (ipos[1] + diameter) * invh, &xmax, &ymax);
+
+ /* output mapping from brush ibuf x/y to region coordinates */
+ mapping->xmin = xmin;
+ mapping->ymin = ymin;
+ mapping->xmax = (xmax - xmin) / (float)diameter;
+ mapping->ymax = (ymax - ymin) / (float)diameter;
+ }
+ else if (mapmode == MTEX_MAP_MODE_3D) {
+ /* 3D mapping, just mapping to canvas 0..1 */
+ mapping->xmin = 2.0f * (ipos[0] * invw - 0.5f);
+ mapping->ymin = 2.0f * (ipos[1] * invh - 0.5f);
+ mapping->xmax = 2.0f * invw;
+ mapping->ymax = 2.0f * invh;
+ }
+ else if (ELEM(mapmode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_RANDOM)) {
+ /* view mapping */
+ mapping->xmin = mouse[0] - diameter * 0.5f + 0.5f;
+ mapping->ymin = mouse[1] - diameter * 0.5f + 0.5f;
+ mapping->xmax = 1.0f;
+ mapping->ymax = 1.0f;
+ }
+ else /* if (mapmode == MTEX_MAP_MODE_TILED) */ {
+ mapping->xmin = (int)(-diameter * 0.5) + (int)floorf(pos[0]) - (int)floorf(startpos[0]);
+ mapping->ymin = (int)(-diameter * 0.5) + (int)floorf(pos[1]) - (int)floorf(startpos[1]);
+ mapping->xmax = 1.0f;
+ mapping->ymax = 1.0f;
+ }
}
-static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *painter, const float pos[2], const float mouse[2], float pressure, float distance, float size)
+static void brush_painter_2d_refresh_cache(ImagePaintState *s,
+ BrushPainter *painter,
+ const float pos[2],
+ const float mouse[2],
+ float pressure,
+ float distance,
+ float size)
{
- const Scene *scene = painter->scene;
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- Brush *brush = painter->brush;
- BrushPainterCache *cache = &painter->cache;
- const int diameter = 2 * size;
-
- bool do_random = false;
- bool do_partial_update = false;
- bool update_color = (
- (brush->flag & BRUSH_USE_GRADIENT) &&
- ((ELEM(brush->gradient_stroke_mode,
- BRUSH_GRADIENT_SPACING_REPEAT,
- BRUSH_GRADIENT_SPACING_CLAMP)) ||
- (cache->last_pressure != pressure)));
- float tex_rotation = -brush->mtex.rot;
- float mask_rotation = -brush->mask_mtex.rot;
-
- painter->pool = BKE_image_pool_new();
-
- /* determine how can update based on textures used */
- if (painter->cache.is_texbrush) {
- if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
- tex_rotation += ups->brush_rotation;
- }
- else if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
- do_random = true;
- else if (!((brush->flag & BRUSH_ANCHORED) || update_color))
- do_partial_update = true;
-
- brush_painter_2d_tex_mapping(
- s, diameter, painter->startpaintpos, pos, mouse,
- brush->mtex.brush_map_mode, &painter->tex_mapping);
- }
-
- if (painter->cache.is_maskbrush) {
- bool renew_maxmask = false;
- bool do_partial_update_mask = false;
- /* invalidate case for all mapping modes */
- if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
- mask_rotation += ups->brush_rotation_sec;
- }
- else if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) {
- renew_maxmask = true;
- }
- else if (!(brush->flag & BRUSH_ANCHORED)) {
- do_partial_update_mask = true;
- renew_maxmask = true;
- }
- /* explicitly disable partial update even if it has been enabled above */
- if (brush->mask_pressure) {
- do_partial_update_mask = false;
- renew_maxmask = true;
- }
-
- if ((diameter != cache->lastdiameter) ||
- (mask_rotation != cache->last_mask_rotation) ||
- renew_maxmask)
- {
- if (cache->tex_mask) {
- MEM_freeN(cache->tex_mask);
- cache->tex_mask = NULL;
- }
-
- brush_painter_2d_tex_mapping(
- s, diameter, painter->startpaintpos, pos, mouse,
- brush->mask_mtex.brush_map_mode, &painter->mask_mapping);
-
- if (do_partial_update_mask)
- 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;
- }
- }
-
- /* curve mask can only change if the size changes */
- if (diameter != cache->lastdiameter) {
- if (cache->curve_mask) {
- MEM_freeN(cache->curve_mask);
- cache->curve_mask = NULL;
- }
-
- cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size);
- }
-
- /* detect if we need to recreate image brush buffer */
- if ((diameter != cache->lastdiameter) ||
- (tex_rotation != cache->last_tex_rotation) ||
- do_random ||
- update_color)
- {
- if (cache->ibuf) {
- IMB_freeImBuf(cache->ibuf);
- cache->ibuf = NULL;
- }
-
- if (do_partial_update) {
- /* do partial update of texture */
- brush_painter_imbuf_partial_update(painter, pos, diameter);
- }
- else {
- /* create brush from scratch */
- cache->ibuf = brush_painter_imbuf_new(painter, diameter, pressure, distance);
- }
-
- cache->lastdiameter = diameter;
- cache->last_tex_rotation = tex_rotation;
- cache->last_pressure = pressure;
- }
- else if (do_partial_update) {
- /* do only partial update of texture */
- int dx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0]);
- int dy = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1]);
-
- if ((dx != 0) || (dy != 0)) {
- brush_painter_imbuf_partial_update(painter, pos, diameter);
- }
- }
-
- BKE_image_pool_free(painter->pool);
- painter->pool = NULL;
+ const Scene *scene = painter->scene;
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ Brush *brush = painter->brush;
+ BrushPainterCache *cache = &painter->cache;
+ const int diameter = 2 * size;
+
+ bool do_random = false;
+ bool do_partial_update = false;
+ bool update_color = ((brush->flag & BRUSH_USE_GRADIENT) &&
+ ((ELEM(brush->gradient_stroke_mode,
+ BRUSH_GRADIENT_SPACING_REPEAT,
+ BRUSH_GRADIENT_SPACING_CLAMP)) ||
+ (cache->last_pressure != pressure)));
+ float tex_rotation = -brush->mtex.rot;
+ float mask_rotation = -brush->mask_mtex.rot;
+
+ painter->pool = BKE_image_pool_new();
+
+ /* determine how can update based on textures used */
+ if (painter->cache.is_texbrush) {
+ if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
+ tex_rotation += ups->brush_rotation;
+ }
+ else if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
+ do_random = true;
+ else if (!((brush->flag & BRUSH_ANCHORED) || update_color))
+ do_partial_update = true;
+
+ brush_painter_2d_tex_mapping(s,
+ diameter,
+ painter->startpaintpos,
+ pos,
+ mouse,
+ brush->mtex.brush_map_mode,
+ &painter->tex_mapping);
+ }
+
+ if (painter->cache.is_maskbrush) {
+ bool renew_maxmask = false;
+ bool do_partial_update_mask = false;
+ /* invalidate case for all mapping modes */
+ if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
+ mask_rotation += ups->brush_rotation_sec;
+ }
+ else if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) {
+ renew_maxmask = true;
+ }
+ else if (!(brush->flag & BRUSH_ANCHORED)) {
+ do_partial_update_mask = true;
+ renew_maxmask = true;
+ }
+ /* explicitly disable partial update even if it has been enabled above */
+ if (brush->mask_pressure) {
+ do_partial_update_mask = false;
+ renew_maxmask = true;
+ }
+
+ if ((diameter != cache->lastdiameter) || (mask_rotation != cache->last_mask_rotation) ||
+ renew_maxmask) {
+ if (cache->tex_mask) {
+ MEM_freeN(cache->tex_mask);
+ cache->tex_mask = NULL;
+ }
+
+ brush_painter_2d_tex_mapping(s,
+ diameter,
+ painter->startpaintpos,
+ pos,
+ mouse,
+ brush->mask_mtex.brush_map_mode,
+ &painter->mask_mapping);
+
+ if (do_partial_update_mask)
+ 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;
+ }
+ }
+
+ /* curve mask can only change if the size changes */
+ if (diameter != cache->lastdiameter) {
+ if (cache->curve_mask) {
+ MEM_freeN(cache->curve_mask);
+ cache->curve_mask = NULL;
+ }
+
+ cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size);
+ }
+
+ /* detect if we need to recreate image brush buffer */
+ if ((diameter != cache->lastdiameter) || (tex_rotation != cache->last_tex_rotation) ||
+ do_random || update_color) {
+ if (cache->ibuf) {
+ IMB_freeImBuf(cache->ibuf);
+ cache->ibuf = NULL;
+ }
+
+ if (do_partial_update) {
+ /* do partial update of texture */
+ brush_painter_imbuf_partial_update(painter, pos, diameter);
+ }
+ else {
+ /* create brush from scratch */
+ cache->ibuf = brush_painter_imbuf_new(painter, diameter, pressure, distance);
+ }
+
+ cache->lastdiameter = diameter;
+ cache->last_tex_rotation = tex_rotation;
+ cache->last_pressure = pressure;
+ }
+ else if (do_partial_update) {
+ /* do only partial update of texture */
+ int dx = (int)floorf(painter->lastpaintpos[0]) - (int)floorf(pos[0]);
+ int dy = (int)floorf(painter->lastpaintpos[1]) - (int)floorf(pos[1]);
+
+ if ((dx != 0) || (dy != 0)) {
+ brush_painter_imbuf_partial_update(painter, pos, diameter);
+ }
+ }
+
+ BKE_image_pool_free(painter->pool);
+ painter->pool = NULL;
}
/* keep these functions in sync */
static void paint_2d_ibuf_rgb_get(ImBuf *ibuf, int x, int y, float r_rgb[4])
{
- if (ibuf->rect_float) {
- const float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4;
- copy_v4_v4(r_rgb, rrgbf);
- }
- else {
- unsigned char *rrgb = (unsigned char *)ibuf->rect + (ibuf->x * y + x) * 4;
- straight_uchar_to_premul_float(r_rgb, rrgb);
- }
+ if (ibuf->rect_float) {
+ const float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4;
+ copy_v4_v4(r_rgb, rrgbf);
+ }
+ else {
+ unsigned char *rrgb = (unsigned char *)ibuf->rect + (ibuf->x * y + x) * 4;
+ straight_uchar_to_premul_float(r_rgb, rrgb);
+ }
}
-static void paint_2d_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const bool is_torus, const float rgb[4])
+static void paint_2d_ibuf_rgb_set(
+ ImBuf *ibuf, int x, int y, const bool is_torus, const float rgb[4])
{
- if (is_torus) {
- x %= ibuf->x;
- if (x < 0) x += ibuf->x;
- y %= ibuf->y;
- if (y < 0) y += ibuf->y;
- }
-
- if (ibuf->rect_float) {
- float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4;
- float map_alpha = (rgb[3] == 0.0f) ? rrgbf[3] : rrgbf[3] / rgb[3];
-
- mul_v3_v3fl(rrgbf, rgb, map_alpha);
- rrgbf[3] = rgb[3];
- }
- else {
- unsigned char straight[4];
- unsigned char *rrgb = (unsigned char *)ibuf->rect + (ibuf->x * y + x) * 4;
-
- premul_float_to_straight_uchar(straight, rgb);
- rrgb[0] = straight[0];
- rrgb[1] = straight[1];
- rrgb[2] = straight[2];
- rrgb[3] = straight[3];
- }
+ if (is_torus) {
+ x %= ibuf->x;
+ if (x < 0)
+ x += ibuf->x;
+ y %= ibuf->y;
+ if (y < 0)
+ y += ibuf->y;
+ }
+
+ if (ibuf->rect_float) {
+ float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4;
+ float map_alpha = (rgb[3] == 0.0f) ? rrgbf[3] : rrgbf[3] / rgb[3];
+
+ mul_v3_v3fl(rrgbf, rgb, map_alpha);
+ rrgbf[3] = rgb[3];
+ }
+ else {
+ unsigned char straight[4];
+ unsigned char *rrgb = (unsigned char *)ibuf->rect + (ibuf->x * y + x) * 4;
+
+ premul_float_to_straight_uchar(straight, rgb);
+ rrgb[0] = straight[0];
+ rrgb[1] = straight[1];
+ rrgb[2] = straight[2];
+ rrgb[3] = straight[3];
+ }
}
static void paint_2d_ibuf_tile_convert(ImBuf *ibuf, int *x, int *y, short tile)
{
- if (tile & PAINT_TILE_X) {
- *x %= ibuf->x;
- if (*x < 0) *x += ibuf->x;
- }
- if (tile & PAINT_TILE_Y) {
- *y %= ibuf->y;
- if (*y < 0) *y += ibuf->y;
- }
+ if (tile & PAINT_TILE_X) {
+ *x %= ibuf->x;
+ if (*x < 0)
+ *x += ibuf->x;
+ }
+ if (tile & PAINT_TILE_Y) {
+ *y %= ibuf->y;
+ if (*y < 0)
+ *y += ibuf->y;
+ }
}
-
static float paint_2d_ibuf_add_if(ImBuf *ibuf, int x, int y, float *outrgb, short tile, float w)
{
- float inrgb[4];
-
- if (tile) paint_2d_ibuf_tile_convert(ibuf, &x, &y, tile);
- /* need to also do clipping here always since tiled coordinates
- * are not always within bounds */
- if (x < ibuf->x && x >= 0 && y < ibuf->y && y >= 0) {
- paint_2d_ibuf_rgb_get(ibuf, x, y, inrgb);
- }
- else return 0;
-
- mul_v4_fl(inrgb, w);
- add_v4_v4(outrgb, inrgb);
-
- return w;
+ float inrgb[4];
+
+ if (tile)
+ paint_2d_ibuf_tile_convert(ibuf, &x, &y, tile);
+ /* need to also do clipping here always since tiled coordinates
+ * are not always within bounds */
+ if (x < ibuf->x && x >= 0 && y < ibuf->y && y >= 0) {
+ paint_2d_ibuf_rgb_get(ibuf, x, y, inrgb);
+ }
+ else
+ return 0;
+
+ mul_v4_fl(inrgb, w);
+ add_v4_v4(outrgb, inrgb);
+
+ return w;
}
-static void paint_2d_lift_soften(ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb, int *pos, const short tile)
+static void paint_2d_lift_soften(
+ ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb, int *pos, const short tile)
{
- bool sharpen = (s->painter->cache.invert ^ ((s->brush->flag & BRUSH_DIR_IN) != 0));
- float threshold = s->brush->sharp_threshold;
- int x, y, xi, yi, xo, yo, xk, yk;
- float count;
- int out_off[2], in_off[2], dim[2];
- int diff_pos[2];
- float outrgb[4];
- float rgba[4];
- BlurKernel *kernel = s->blurkernel;
-
- dim[0] = ibufb->x;
- dim[1] = ibufb->y;
- in_off[0] = pos[0];
- in_off[1] = pos[1];
- out_off[0] = out_off[1] = 0;
-
- if (!tile) {
- IMB_rectclip(
- ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0],
- &out_off[1], &dim[0], &dim[1]);
-
- if ((dim[0] == 0) || (dim[1] == 0))
- return;
- }
-
- /* find offset inside mask buffers to sample them */
- sub_v2_v2v2_int(diff_pos, out_off, in_off);
-
- for (y = 0; y < dim[1]; y++) {
- for (x = 0; x < dim[0]; x++) {
- /* get input pixel */
- xi = in_off[0] + x;
- yi = in_off[1] + y;
-
- count = 0.0;
- if (tile) {
- paint_2d_ibuf_tile_convert(ibuf, &xi, &yi, tile);
- if (xi < ibuf->x && xi >= 0 && yi < ibuf->y && yi >= 0)
- paint_2d_ibuf_rgb_get(ibuf, xi, yi, rgba);
- else
- zero_v4(rgba);
- }
- else {
- /* coordinates have been clipped properly here, it should be safe to do this */
- paint_2d_ibuf_rgb_get(ibuf, xi, yi, rgba);
- }
- zero_v4(outrgb);
-
- for (yk = 0; yk < kernel->side; yk++) {
- for (xk = 0; xk < kernel->side; xk++) {
- count += paint_2d_ibuf_add_if(
- ibuf, xi + xk - kernel->pixel_len,
- yi + yk - kernel->pixel_len, outrgb, tile,
- kernel->wdata[xk + yk * kernel->side]);
- }
- }
-
- if (count > 0.0f) {
- mul_v4_fl(outrgb, 1.0f / (float)count);
-
- if (sharpen) {
- /* subtract blurred image from normal image gives high pass filter */
- sub_v3_v3v3(outrgb, rgba, outrgb);
-
- /* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
- * colored speckles appearing in final image, and also to check for threshold */
- outrgb[0] = outrgb[1] = outrgb[2] = IMB_colormanagement_get_luminance(outrgb);
- if (fabsf(outrgb[0]) > threshold) {
- float mask = BKE_brush_alpha_get(s->scene, s->brush);
- float alpha = rgba[3];
- rgba[3] = outrgb[3] = mask;
-
- /* add to enhance edges */
- blend_color_add_float(outrgb, rgba, outrgb);
- outrgb[3] = alpha;
- }
- else
- copy_v4_v4(outrgb, rgba);
- }
- }
- else
- copy_v4_v4(outrgb, rgba);
- /* write into brush buffer */
- xo = out_off[0] + x;
- yo = out_off[1] + y;
- paint_2d_ibuf_rgb_set(ibufb, xo, yo, 0, outrgb);
- }
- }
+ bool sharpen = (s->painter->cache.invert ^ ((s->brush->flag & BRUSH_DIR_IN) != 0));
+ float threshold = s->brush->sharp_threshold;
+ int x, y, xi, yi, xo, yo, xk, yk;
+ float count;
+ int out_off[2], in_off[2], dim[2];
+ int diff_pos[2];
+ float outrgb[4];
+ float rgba[4];
+ BlurKernel *kernel = s->blurkernel;
+
+ dim[0] = ibufb->x;
+ dim[1] = ibufb->y;
+ in_off[0] = pos[0];
+ in_off[1] = pos[1];
+ out_off[0] = out_off[1] = 0;
+
+ if (!tile) {
+ IMB_rectclip(ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0], &out_off[1], &dim[0], &dim[1]);
+
+ if ((dim[0] == 0) || (dim[1] == 0))
+ return;
+ }
+
+ /* find offset inside mask buffers to sample them */
+ sub_v2_v2v2_int(diff_pos, out_off, in_off);
+
+ for (y = 0; y < dim[1]; y++) {
+ for (x = 0; x < dim[0]; x++) {
+ /* get input pixel */
+ xi = in_off[0] + x;
+ yi = in_off[1] + y;
+
+ count = 0.0;
+ if (tile) {
+ paint_2d_ibuf_tile_convert(ibuf, &xi, &yi, tile);
+ if (xi < ibuf->x && xi >= 0 && yi < ibuf->y && yi >= 0)
+ paint_2d_ibuf_rgb_get(ibuf, xi, yi, rgba);
+ else
+ zero_v4(rgba);
+ }
+ else {
+ /* coordinates have been clipped properly here, it should be safe to do this */
+ paint_2d_ibuf_rgb_get(ibuf, xi, yi, rgba);
+ }
+ zero_v4(outrgb);
+
+ for (yk = 0; yk < kernel->side; yk++) {
+ for (xk = 0; xk < kernel->side; xk++) {
+ count += paint_2d_ibuf_add_if(ibuf,
+ xi + xk - kernel->pixel_len,
+ yi + yk - kernel->pixel_len,
+ outrgb,
+ tile,
+ kernel->wdata[xk + yk * kernel->side]);
+ }
+ }
+
+ if (count > 0.0f) {
+ mul_v4_fl(outrgb, 1.0f / (float)count);
+
+ if (sharpen) {
+ /* subtract blurred image from normal image gives high pass filter */
+ sub_v3_v3v3(outrgb, rgba, outrgb);
+
+ /* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
+ * colored speckles appearing in final image, and also to check for threshold */
+ outrgb[0] = outrgb[1] = outrgb[2] = IMB_colormanagement_get_luminance(outrgb);
+ if (fabsf(outrgb[0]) > threshold) {
+ float mask = BKE_brush_alpha_get(s->scene, s->brush);
+ float alpha = rgba[3];
+ rgba[3] = outrgb[3] = mask;
+
+ /* add to enhance edges */
+ blend_color_add_float(outrgb, rgba, outrgb);
+ outrgb[3] = alpha;
+ }
+ else
+ copy_v4_v4(outrgb, rgba);
+ }
+ }
+ else
+ copy_v4_v4(outrgb, rgba);
+ /* write into brush buffer */
+ xo = out_off[0] + x;
+ yo = out_off[1] + y;
+ paint_2d_ibuf_rgb_set(ibufb, xo, yo, 0, outrgb);
+ }
+ }
}
-static void paint_2d_set_region(ImagePaintRegion *region, int destx, int desty, int srcx, int srcy, int width, int height)
+static void paint_2d_set_region(
+ ImagePaintRegion *region, int destx, int desty, int srcx, int srcy, int width, int height)
{
- region->destx = destx;
- region->desty = desty;
- region->srcx = srcx;
- region->srcy = srcy;
- region->width = width;
- region->height = height;
+ region->destx = destx;
+ region->desty = desty;
+ region->srcx = srcx;
+ region->srcy = srcy;
+ region->width = width;
+ region->height = height;
}
-static int paint_2d_torus_split_region(ImagePaintRegion region[4], ImBuf *dbuf, ImBuf *sbuf, short tile)
+static int paint_2d_torus_split_region(ImagePaintRegion region[4],
+ ImBuf *dbuf,
+ ImBuf *sbuf,
+ short tile)
{
- int destx = region->destx;
- int desty = region->desty;
- int srcx = region->srcx;
- int srcy = region->srcy;
- int width = region->width;
- int height = region->height;
- int origw, origh, w, h, tot = 0;
-
- /* convert destination and source coordinates to be within image */
- if (tile & PAINT_TILE_X) {
- destx = destx % dbuf->x;
- if (destx < 0) destx += dbuf->x;
- srcx = srcx % sbuf->x;
- if (srcx < 0) srcx += sbuf->x;
- }
- if (tile & PAINT_TILE_Y) {
- desty = desty % dbuf->y;
- if (desty < 0) desty += dbuf->y;
- srcy = srcy % sbuf->y;
- if (srcy < 0) srcy += sbuf->y;
- }
- /* clip width of blending area to destination imbuf, to avoid writing the
- * same pixel twice */
- origw = w = (width > dbuf->x) ? dbuf->x : width;
- origh = h = (height > dbuf->y) ? dbuf->y : height;
-
- /* clip within image */
- IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &w, &h);
- paint_2d_set_region(&region[tot++], destx, desty, srcx, srcy, w, h);
-
- /* do 3 other rects if needed */
- if ((tile & PAINT_TILE_X) && w < origw)
- paint_2d_set_region(&region[tot++], (destx + w) % dbuf->x, desty, (srcx + w) % sbuf->x, srcy, origw - w, h);
- if ((tile & PAINT_TILE_Y) && h < origh)
- paint_2d_set_region(&region[tot++], destx, (desty + h) % dbuf->y, srcx, (srcy + h) % sbuf->y, w, origh - h);
- if ((tile & PAINT_TILE_X) && (tile & PAINT_TILE_Y) && (w < origw) && (h < origh))
- paint_2d_set_region(&region[tot++], (destx + w) % dbuf->x, (desty + h) % dbuf->y, (srcx + w) % sbuf->x, (srcy + h) % sbuf->y, origw - w, origh - h);
-
- return tot;
+ int destx = region->destx;
+ int desty = region->desty;
+ int srcx = region->srcx;
+ int srcy = region->srcy;
+ int width = region->width;
+ int height = region->height;
+ int origw, origh, w, h, tot = 0;
+
+ /* convert destination and source coordinates to be within image */
+ if (tile & PAINT_TILE_X) {
+ destx = destx % dbuf->x;
+ if (destx < 0)
+ destx += dbuf->x;
+ srcx = srcx % sbuf->x;
+ if (srcx < 0)
+ srcx += sbuf->x;
+ }
+ if (tile & PAINT_TILE_Y) {
+ desty = desty % dbuf->y;
+ if (desty < 0)
+ desty += dbuf->y;
+ srcy = srcy % sbuf->y;
+ if (srcy < 0)
+ srcy += sbuf->y;
+ }
+ /* clip width of blending area to destination imbuf, to avoid writing the
+ * same pixel twice */
+ origw = w = (width > dbuf->x) ? dbuf->x : width;
+ origh = h = (height > dbuf->y) ? dbuf->y : height;
+
+ /* clip within image */
+ IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &w, &h);
+ paint_2d_set_region(&region[tot++], destx, desty, srcx, srcy, w, h);
+
+ /* do 3 other rects if needed */
+ if ((tile & PAINT_TILE_X) && w < origw)
+ paint_2d_set_region(
+ &region[tot++], (destx + w) % dbuf->x, desty, (srcx + w) % sbuf->x, srcy, origw - w, h);
+ if ((tile & PAINT_TILE_Y) && h < origh)
+ paint_2d_set_region(
+ &region[tot++], destx, (desty + h) % dbuf->y, srcx, (srcy + h) % sbuf->y, w, origh - h);
+ if ((tile & PAINT_TILE_X) && (tile & PAINT_TILE_Y) && (w < origw) && (h < origh))
+ paint_2d_set_region(&region[tot++],
+ (destx + w) % dbuf->x,
+ (desty + h) % dbuf->y,
+ (srcx + w) % sbuf->x,
+ (srcy + h) % sbuf->y,
+ origw - w,
+ origh - h);
+
+ return tot;
}
static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos, short tile)
{
- ImagePaintRegion region[4];
- int a, tot;
-
- paint_2d_set_region(region, 0, 0, pos[0], pos[1], ibufb->x, ibufb->y);
- tot = paint_2d_torus_split_region(region, ibufb, ibuf, tile);
-
- for (a = 0; a < tot; a++)
- IMB_rectblend(
- ibufb, ibufb, ibuf, NULL, 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, false);
+ ImagePaintRegion region[4];
+ int a, tot;
+
+ paint_2d_set_region(region, 0, 0, pos[0], pos[1], ibufb->x, ibufb->y);
+ tot = paint_2d_torus_split_region(region, ibufb, ibuf, tile);
+
+ for (a = 0; a < tot; a++)
+ IMB_rectblend(ibufb,
+ ibufb,
+ ibuf,
+ NULL,
+ 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,
+ false);
}
static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos)
{
- /* note: allocImbuf returns zero'd memory, so regions outside image will
- * have zero alpha, and hence not be blended onto the image */
- int w = ibufb->x, h = ibufb->y, destx = 0, desty = 0, srcx = pos[0], srcy = pos[1];
- ImBuf *clonebuf = IMB_allocImBuf(w, h, ibufb->planes, ibufb->flags);
-
- IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h);
- IMB_rectblend(
- clonebuf, clonebuf, ibufb, NULL, NULL, NULL, 0, destx, desty, destx, desty, destx, desty, w, h,
- IMB_BLEND_COPY_ALPHA, false);
- IMB_rectblend(
- clonebuf, clonebuf, ibuf, NULL, NULL, NULL, 0, destx, desty, destx, desty, srcx, srcy, w, h,
- IMB_BLEND_COPY_RGB, false);
-
- return clonebuf;
+ /* note: allocImbuf returns zero'd memory, so regions outside image will
+ * have zero alpha, and hence not be blended onto the image */
+ int w = ibufb->x, h = ibufb->y, destx = 0, desty = 0, srcx = pos[0], srcy = pos[1];
+ ImBuf *clonebuf = IMB_allocImBuf(w, h, ibufb->planes, ibufb->flags);
+
+ IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h);
+ IMB_rectblend(clonebuf,
+ clonebuf,
+ ibufb,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ destx,
+ desty,
+ destx,
+ desty,
+ destx,
+ desty,
+ w,
+ h,
+ IMB_BLEND_COPY_ALPHA,
+ false);
+ IMB_rectblend(clonebuf,
+ clonebuf,
+ ibuf,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ destx,
+ desty,
+ destx,
+ desty,
+ srcx,
+ srcy,
+ w,
+ h,
+ IMB_BLEND_COPY_RGB,
+ false);
+
+ return clonebuf;
}
static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[2])
{
- ipos[0] = (int)floorf((pos[0] - ibufb->x / 2));
- ipos[1] = (int)floorf((pos[1] - ibufb->y / 2));
+ ipos[0] = (int)floorf((pos[0] - ibufb->x / 2));
+ ipos[1] = (int)floorf((pos[1] - ibufb->y / 2));
}
-static void paint_2d_do_making_brush(
- ImagePaintState *s,
- ImagePaintRegion *region,
- unsigned short *curveb,
- unsigned short *texmaskb,
- ImBuf *frombuf,
- float mask_max,
- short blend,
- int tilex, int tiley,
- int tilew, int tileh)
+static void paint_2d_do_making_brush(ImagePaintState *s,
+ ImagePaintRegion *region,
+ unsigned short *curveb,
+ unsigned short *texmaskb,
+ ImBuf *frombuf,
+ float mask_max,
+ short blend,
+ int tilex,
+ int tiley,
+ int tilew,
+ int tileh)
{
- ImBuf tmpbuf;
- IMB_initImBuf(&tmpbuf, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0);
-
- ListBase *undo_tiles = ED_image_undo_get_tiles();
-
- for (int ty = tiley; ty <= tileh; ty++) {
- for (int tx = tilex; tx <= tilew; tx++) {
- /* retrieve original pixels + mask from undo buffer */
- unsigned short *mask;
- int origx = region->destx - tx * IMAPAINT_TILE_SIZE;
- int origy = region->desty - ty * IMAPAINT_TILE_SIZE;
-
- if (s->canvas->rect_float)
- tmpbuf.rect_float = image_undo_find_tile(undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
- else
- tmpbuf.rect = image_undo_find_tile(undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
-
- IMB_rectblend(
- s->canvas, &tmpbuf, frombuf, mask,
- curveb, texmaskb, mask_max,
- region->destx, region->desty,
- origx, origy,
- region->srcx, region->srcy,
- region->width, region->height,
- blend, ((s->brush->flag & BRUSH_ACCUMULATE) != 0));
- }
- }
+ ImBuf tmpbuf;
+ IMB_initImBuf(&tmpbuf, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0);
+
+ ListBase *undo_tiles = ED_image_undo_get_tiles();
+
+ for (int ty = tiley; ty <= tileh; ty++) {
+ for (int tx = tilex; tx <= tilew; tx++) {
+ /* retrieve original pixels + mask from undo buffer */
+ unsigned short *mask;
+ int origx = region->destx - tx * IMAPAINT_TILE_SIZE;
+ int origy = region->desty - ty * IMAPAINT_TILE_SIZE;
+
+ if (s->canvas->rect_float)
+ tmpbuf.rect_float = image_undo_find_tile(
+ undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
+ else
+ tmpbuf.rect = image_undo_find_tile(undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
+
+ IMB_rectblend(s->canvas,
+ &tmpbuf,
+ frombuf,
+ mask,
+ curveb,
+ texmaskb,
+ mask_max,
+ region->destx,
+ region->desty,
+ origx,
+ origy,
+ region->srcx,
+ region->srcy,
+ region->width,
+ region->height,
+ blend,
+ ((s->brush->flag & BRUSH_ACCUMULATE) != 0));
+ }
+ }
}
typedef struct Paint2DForeachData {
- ImagePaintState *s;
- ImagePaintRegion *region;
- unsigned short *curveb;
- unsigned short *texmaskb;
- ImBuf *frombuf;
- float mask_max;
- short blend;
- int tilex;
- int tilew;
+ ImagePaintState *s;
+ ImagePaintRegion *region;
+ unsigned short *curveb;
+ unsigned short *texmaskb;
+ ImBuf *frombuf;
+ float mask_max;
+ short blend;
+ int tilex;
+ int tilew;
} Paint2DForeachData;
-static void paint_2d_op_foreach_do(
- void *__restrict data_v,
- const int iter,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void paint_2d_op_foreach_do(void *__restrict data_v,
+ const int iter,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- Paint2DForeachData *data = (Paint2DForeachData *)data_v;
- paint_2d_do_making_brush(
- data->s, data->region, data->curveb,
- data->texmaskb, data->frombuf, data->mask_max,
- data->blend,
- data->tilex, iter,
- data->tilew, iter);
+ Paint2DForeachData *data = (Paint2DForeachData *)data_v;
+ paint_2d_do_making_brush(data->s,
+ data->region,
+ data->curveb,
+ data->texmaskb,
+ data->frombuf,
+ data->mask_max,
+ data->blend,
+ data->tilex,
+ iter,
+ data->tilew,
+ iter);
}
-static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsigned short *texmaskb, const float lastpos[2], const float pos[2])
+static int paint_2d_op(void *state,
+ ImBuf *ibufb,
+ unsigned short *curveb,
+ unsigned short *texmaskb,
+ const float lastpos[2],
+ const float pos[2])
{
- ImagePaintState *s = ((ImagePaintState *)state);
- ImBuf *clonebuf = NULL, *frombuf;
- ImagePaintRegion region[4];
- short tile = s->symmetry & (PAINT_TILE_X | PAINT_TILE_Y);
- short blend = s->blend;
- const float *offset = s->brush->clone.offset;
- float liftpos[2];
- float mask_max = BKE_brush_alpha_get(s->scene, s->brush);
- int bpos[2], blastpos[2], bliftpos[2];
- int a, tot;
-
- paint_2d_convert_brushco(ibufb, pos, bpos);
-
- /* lift from canvas */
- if (s->tool == PAINT_TOOL_SOFTEN) {
- paint_2d_lift_soften(s, s->canvas, ibufb, bpos, tile);
- blend = IMB_BLEND_INTERPOLATE;
- }
- else if (s->tool == PAINT_TOOL_SMEAR) {
- if (lastpos[0] == pos[0] && lastpos[1] == pos[1])
- return 0;
-
- paint_2d_convert_brushco(ibufb, lastpos, blastpos);
- paint_2d_lift_smear(s->canvas, ibufb, blastpos, tile);
- blend = IMB_BLEND_INTERPOLATE;
- }
- else if (s->tool == PAINT_TOOL_CLONE && s->clonecanvas) {
- liftpos[0] = pos[0] - offset[0] * s->canvas->x;
- liftpos[1] = pos[1] - offset[1] * s->canvas->y;
-
- paint_2d_convert_brushco(ibufb, liftpos, bliftpos);
- clonebuf = paint_2d_lift_clone(s->clonecanvas, ibufb, bliftpos);
- }
-
- frombuf = (clonebuf) ? clonebuf : ibufb;
-
- if (tile) {
- paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
- tot = paint_2d_torus_split_region(region, s->canvas, frombuf, tile);
- }
- else {
- paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
- tot = 1;
- }
-
- /* blend into canvas */
- for (a = 0; a < tot; a++) {
- ED_imapaint_dirty_region(
- s->image, s->canvas,
- region[a].destx, region[a].desty,
- region[a].width, region[a].height, true);
-
- if (s->do_masking) {
- /* masking, find original pixels tiles from undo buffer to composite over */
- int tilex, tiley, tilew, tileh;
-
- imapaint_region_tiles(
- s->canvas, region[a].destx, region[a].desty,
- region[a].width, region[a].height,
- &tilex, &tiley, &tilew, &tileh);
-
- if (tiley == tileh) {
- paint_2d_do_making_brush(
- s, &region[a], curveb, texmaskb, frombuf,
- mask_max, blend, tilex, tiley, tilew, tileh);
- }
- else {
- Paint2DForeachData data;
- data.s = s;
- data.region = &region[a];
- data.curveb = curveb;
- data.texmaskb = texmaskb;
- data.frombuf = frombuf;
- data.mask_max = mask_max;
- data.blend = blend;
- data.tilex = tilex;
- data.tilew = tilew;
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- BLI_task_parallel_range(
- tiley, tileh + 1, &data,
- paint_2d_op_foreach_do,
- &settings);
-
- }
- }
- else {
- /* no masking, composite brush directly onto canvas */
- IMB_rectblend_threaded(
- s->canvas, s->canvas, frombuf, NULL, curveb, texmaskb, mask_max,
- 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, false);
- }
- }
-
- if (clonebuf) IMB_freeImBuf(clonebuf);
-
- return 1;
+ ImagePaintState *s = ((ImagePaintState *)state);
+ ImBuf *clonebuf = NULL, *frombuf;
+ ImagePaintRegion region[4];
+ short tile = s->symmetry & (PAINT_TILE_X | PAINT_TILE_Y);
+ short blend = s->blend;
+ const float *offset = s->brush->clone.offset;
+ float liftpos[2];
+ float mask_max = BKE_brush_alpha_get(s->scene, s->brush);
+ int bpos[2], blastpos[2], bliftpos[2];
+ int a, tot;
+
+ paint_2d_convert_brushco(ibufb, pos, bpos);
+
+ /* lift from canvas */
+ if (s->tool == PAINT_TOOL_SOFTEN) {
+ paint_2d_lift_soften(s, s->canvas, ibufb, bpos, tile);
+ blend = IMB_BLEND_INTERPOLATE;
+ }
+ else if (s->tool == PAINT_TOOL_SMEAR) {
+ if (lastpos[0] == pos[0] && lastpos[1] == pos[1])
+ return 0;
+
+ paint_2d_convert_brushco(ibufb, lastpos, blastpos);
+ paint_2d_lift_smear(s->canvas, ibufb, blastpos, tile);
+ blend = IMB_BLEND_INTERPOLATE;
+ }
+ else if (s->tool == PAINT_TOOL_CLONE && s->clonecanvas) {
+ liftpos[0] = pos[0] - offset[0] * s->canvas->x;
+ liftpos[1] = pos[1] - offset[1] * s->canvas->y;
+
+ paint_2d_convert_brushco(ibufb, liftpos, bliftpos);
+ clonebuf = paint_2d_lift_clone(s->clonecanvas, ibufb, bliftpos);
+ }
+
+ frombuf = (clonebuf) ? clonebuf : ibufb;
+
+ if (tile) {
+ paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
+ tot = paint_2d_torus_split_region(region, s->canvas, frombuf, tile);
+ }
+ else {
+ paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
+ tot = 1;
+ }
+
+ /* blend into canvas */
+ for (a = 0; a < tot; a++) {
+ ED_imapaint_dirty_region(s->image,
+ s->canvas,
+ region[a].destx,
+ region[a].desty,
+ region[a].width,
+ region[a].height,
+ true);
+
+ if (s->do_masking) {
+ /* masking, find original pixels tiles from undo buffer to composite over */
+ int tilex, tiley, tilew, tileh;
+
+ imapaint_region_tiles(s->canvas,
+ region[a].destx,
+ region[a].desty,
+ region[a].width,
+ region[a].height,
+ &tilex,
+ &tiley,
+ &tilew,
+ &tileh);
+
+ if (tiley == tileh) {
+ paint_2d_do_making_brush(
+ s, &region[a], curveb, texmaskb, frombuf, mask_max, blend, tilex, tiley, tilew, tileh);
+ }
+ else {
+ Paint2DForeachData data;
+ data.s = s;
+ data.region = &region[a];
+ data.curveb = curveb;
+ data.texmaskb = texmaskb;
+ data.frombuf = frombuf;
+ data.mask_max = mask_max;
+ data.blend = blend;
+ data.tilex = tilex;
+ data.tilew = tilew;
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ BLI_task_parallel_range(tiley, tileh + 1, &data, paint_2d_op_foreach_do, &settings);
+ }
+ }
+ else {
+ /* no masking, composite brush directly onto canvas */
+ IMB_rectblend_threaded(s->canvas,
+ s->canvas,
+ frombuf,
+ NULL,
+ curveb,
+ texmaskb,
+ mask_max,
+ 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,
+ false);
+ }
+ }
+
+ if (clonebuf)
+ IMB_freeImBuf(clonebuf);
+
+ return 1;
}
-
static int paint_2d_canvas_set(ImagePaintState *s, Image *ima)
{
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL);
-
- /* verify that we can paint and set canvas */
- if (ima == NULL) {
- return 0;
- }
- else if (BKE_image_has_packedfile(ima) && ima->rr) {
- s->warnpackedfile = ima->id.name + 2;
- return 0;
- }
- else if (ibuf && ibuf->channels != 4) {
- s->warnmultifile = ima->id.name + 2;
- return 0;
- }
- else if (!ibuf || !(ibuf->rect || ibuf->rect_float))
- return 0;
-
- s->image = ima;
- s->canvas = ibuf;
-
- /* set clone canvas */
- if (s->tool == PAINT_TOOL_CLONE) {
- ima = s->brush->clone.image;
- ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL);
-
- if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- BKE_image_release_ibuf(s->image, s->canvas, NULL);
- return 0;
- }
-
- s->clonecanvas = ibuf;
-
- /* temporarily add float rect for cloning */
- if (s->canvas->rect_float && !s->clonecanvas->rect_float) {
- IMB_float_from_rect(s->clonecanvas);
- }
- else if (!s->canvas->rect_float && !s->clonecanvas->rect)
- IMB_rect_from_float(s->clonecanvas);
- }
-
- /* set masking */
- s->do_masking = paint_use_opacity_masking(s->brush);
-
- return 1;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL);
+
+ /* verify that we can paint and set canvas */
+ if (ima == NULL) {
+ return 0;
+ }
+ else if (BKE_image_has_packedfile(ima) && ima->rr) {
+ s->warnpackedfile = ima->id.name + 2;
+ return 0;
+ }
+ else if (ibuf && ibuf->channels != 4) {
+ s->warnmultifile = ima->id.name + 2;
+ return 0;
+ }
+ else if (!ibuf || !(ibuf->rect || ibuf->rect_float))
+ return 0;
+
+ s->image = ima;
+ s->canvas = ibuf;
+
+ /* set clone canvas */
+ if (s->tool == PAINT_TOOL_CLONE) {
+ ima = s->brush->clone.image;
+ ibuf = BKE_image_acquire_ibuf(ima, s->sima ? &s->sima->iuser : NULL, NULL);
+
+ if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) {
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ BKE_image_release_ibuf(s->image, s->canvas, NULL);
+ return 0;
+ }
+
+ s->clonecanvas = ibuf;
+
+ /* temporarily add float rect for cloning */
+ if (s->canvas->rect_float && !s->clonecanvas->rect_float) {
+ IMB_float_from_rect(s->clonecanvas);
+ }
+ else if (!s->canvas->rect_float && !s->clonecanvas->rect)
+ IMB_rect_from_float(s->clonecanvas);
+ }
+
+ /* set masking */
+ s->do_masking = paint_use_opacity_masking(s->brush);
+
+ return 1;
}
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);
+ BKE_image_release_ibuf(s->image, s->canvas, NULL);
+ BKE_image_release_ibuf(s->brush->clone.image, s->clonecanvas, NULL);
- if (s->blurkernel) {
- paint_delete_blur_kernel(s->blurkernel);
- MEM_freeN(s->blurkernel);
- }
+ if (s->blurkernel) {
+ paint_delete_blur_kernel(s->blurkernel);
+ MEM_freeN(s->blurkernel);
+ }
- image_undo_remove_masks();
+ image_undo_remove_masks();
}
-void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], const bool eraser, float pressure, float distance, float size)
+void paint_2d_stroke(void *ps,
+ const float prev_mval[2],
+ const float mval[2],
+ const bool eraser,
+ float pressure,
+ float distance,
+ float size)
{
- float newuv[2], olduv[2];
- ImagePaintState *s = ps;
- BrushPainter *painter = s->painter;
- ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, s->sima ? &s->sima->iuser : NULL, NULL);
- const bool is_data = (ibuf && ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA);
+ float newuv[2], olduv[2];
+ ImagePaintState *s = ps;
+ BrushPainter *painter = s->painter;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, s->sima ? &s->sima->iuser : NULL, NULL);
+ const bool is_data = (ibuf && ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA);
- if (!ibuf)
- return;
+ if (!ibuf)
+ return;
- s->blend = s->brush->blend;
- if (eraser)
- s->blend = IMB_BLEND_ERASE_ALPHA;
+ s->blend = s->brush->blend;
+ if (eraser)
+ s->blend = IMB_BLEND_ERASE_ALPHA;
- UI_view2d_region_to_view(s->v2d, mval[0], mval[1], &newuv[0], &newuv[1]);
- UI_view2d_region_to_view(s->v2d, prev_mval[0], prev_mval[1], &olduv[0], &olduv[1]);
+ UI_view2d_region_to_view(s->v2d, mval[0], mval[1], &newuv[0], &newuv[1]);
+ UI_view2d_region_to_view(s->v2d, prev_mval[0], prev_mval[1], &olduv[0], &olduv[1]);
- newuv[0] *= ibuf->x;
- newuv[1] *= ibuf->y;
+ newuv[0] *= ibuf->x;
+ newuv[1] *= ibuf->y;
- olduv[0] *= ibuf->x;
- olduv[1] *= ibuf->y;
+ olduv[0] *= ibuf->x;
+ olduv[1] *= ibuf->y;
- if (painter->firsttouch) {
- float startuv[2];
+ if (painter->firsttouch) {
+ float startuv[2];
- UI_view2d_region_to_view(s->v2d, 0, 0, &startuv[0], &startuv[1]);
+ UI_view2d_region_to_view(s->v2d, 0, 0, &startuv[0], &startuv[1]);
- /* paint exactly once on first touch */
- painter->startpaintpos[0] = startuv[0] * ibuf->x;
- painter->startpaintpos[1] = startuv[1] * ibuf->y;
+ /* paint exactly once on first touch */
+ painter->startpaintpos[0] = startuv[0] * ibuf->x;
+ painter->startpaintpos[1] = startuv[1] * ibuf->y;
- painter->firsttouch = 0;
- copy_v2_v2(painter->lastpaintpos, newuv);
- }
- else {
- copy_v2_v2(painter->lastpaintpos, olduv);
- }
+ painter->firsttouch = 0;
+ copy_v2_v2(painter->lastpaintpos, newuv);
+ }
+ 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 != NULL), !is_data);
+ /* 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 != NULL), !is_data);
- brush_painter_2d_refresh_cache(s, painter, newuv, mval, pressure, distance, size);
+ brush_painter_2d_refresh_cache(s, painter, newuv, mval, pressure, distance, size);
- if (paint_2d_op(s, painter->cache.ibuf, painter->cache.curve_mask, painter->cache.tex_mask, olduv, newuv))
- s->need_redraw = true;
+ if (paint_2d_op(s,
+ painter->cache.ibuf,
+ painter->cache.curve_mask,
+ painter->cache.tex_mask,
+ olduv,
+ newuv))
+ s->need_redraw = true;
- BKE_image_release_ibuf(s->image, ibuf, NULL);
+ BKE_image_release_ibuf(s->image, ibuf, NULL);
}
void *paint_2d_new_stroke(bContext *C, wmOperator *op, int mode)
{
- Scene *scene = CTX_data_scene(C);
- ToolSettings *settings = scene->toolsettings;
- Brush *brush = BKE_paint_brush(&settings->imapaint.paint);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *settings = scene->toolsettings;
+ Brush *brush = BKE_paint_brush(&settings->imapaint.paint);
- ImagePaintState *s = MEM_callocN(sizeof(ImagePaintState), "ImagePaintState");
+ ImagePaintState *s = MEM_callocN(sizeof(ImagePaintState), "ImagePaintState");
- s->sima = CTX_wm_space_image(C);
- s->v2d = &CTX_wm_region(C)->v2d;
- s->scene = scene;
- s->screen = CTX_wm_screen(C);
+ s->sima = CTX_wm_space_image(C);
+ s->v2d = &CTX_wm_region(C)->v2d;
+ s->scene = scene;
+ s->screen = CTX_wm_screen(C);
- s->brush = brush;
- s->tool = brush->imagepaint_tool;
- s->blend = brush->blend;
+ s->brush = brush;
+ s->tool = brush->imagepaint_tool;
+ s->blend = brush->blend;
- s->image = s->sima->image;
- s->symmetry = settings->imapaint.paint.symmetry_flags;
+ s->image = s->sima->image;
+ s->symmetry = settings->imapaint.paint.symmetry_flags;
- if (!paint_2d_canvas_set(s, s->image)) {
- if (s->warnmultifile)
- BKE_report(op->reports, RPT_WARNING, "Image requires 4 color channels to paint");
- if (s->warnpackedfile)
- BKE_report(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted");
+ if (!paint_2d_canvas_set(s, s->image)) {
+ if (s->warnmultifile)
+ BKE_report(op->reports, RPT_WARNING, "Image requires 4 color channels to paint");
+ if (s->warnpackedfile)
+ BKE_report(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted");
- MEM_freeN(s);
- return NULL;
- }
+ MEM_freeN(s);
+ return NULL;
+ }
- if (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) {
- s->blurkernel = paint_new_blur_kernel(brush, false);
- }
+ if (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) {
+ s->blurkernel = paint_new_blur_kernel(brush, false);
+ }
- paint_brush_init_tex(s->brush);
+ paint_brush_init_tex(s->brush);
- /* create painter */
- s->painter = brush_painter_2d_new(scene, s->brush, mode == BRUSH_STROKE_INVERT);
+ /* create painter */
+ s->painter = brush_painter_2d_new(scene, s->brush, mode == BRUSH_STROKE_INVERT);
- return s;
+ return s;
}
void paint_2d_redraw(const bContext *C, void *ps, bool final)
{
- ImagePaintState *s = ps;
-
- if (s->need_redraw) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, s->sima ? &s->sima->iuser : NULL, NULL);
-
- imapaint_image_update(s->sima, s->image, ibuf, false);
- ED_imapaint_clear_partial_redraw();
-
- BKE_image_release_ibuf(s->image, ibuf, NULL);
-
- s->need_redraw = false;
- }
- else if (!final) {
- return;
- }
-
- if (final) {
- if (s->image && !(s->sima && s->sima->lock))
- GPU_free_image(s->image);
-
- /* compositor listener deals with updating */
- WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, s->image);
- DEG_id_tag_update(&s->image->id, 0);
- }
- else {
- if (!s->sima || !s->sima->lock)
- ED_region_tag_redraw(CTX_wm_region(C));
- else
- WM_event_add_notifier(C, NC_IMAGE | NA_PAINTING, s->image);
- }
+ ImagePaintState *s = ps;
+
+ if (s->need_redraw) {
+ ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, s->sima ? &s->sima->iuser : NULL, NULL);
+
+ imapaint_image_update(s->sima, s->image, ibuf, false);
+ ED_imapaint_clear_partial_redraw();
+
+ BKE_image_release_ibuf(s->image, ibuf, NULL);
+
+ s->need_redraw = false;
+ }
+ else if (!final) {
+ return;
+ }
+
+ if (final) {
+ if (s->image && !(s->sima && s->sima->lock))
+ GPU_free_image(s->image);
+
+ /* compositor listener deals with updating */
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, s->image);
+ DEG_id_tag_update(&s->image->id, 0);
+ }
+ else {
+ if (!s->sima || !s->sima->lock)
+ ED_region_tag_redraw(CTX_wm_region(C));
+ else
+ WM_event_add_notifier(C, NC_IMAGE | NA_PAINTING, s->image);
+ }
}
void paint_2d_stroke_done(void *ps)
{
- ImagePaintState *s = ps;
+ ImagePaintState *s = ps;
- paint_2d_canvas_free(s);
- brush_painter_2d_free(s->painter);
- paint_brush_exit_tex(s->brush);
+ paint_2d_canvas_free(s);
+ brush_painter_2d_free(s->painter);
+ paint_brush_exit_tex(s->brush);
- MEM_freeN(s);
+ MEM_freeN(s);
}
-static void paint_2d_fill_add_pixel_byte(
- const int x_px, const int y_px, ImBuf *ibuf, BLI_Stack *stack, BLI_bitmap *touched,
- const float color[4], float threshold_sq)
+static void paint_2d_fill_add_pixel_byte(const int x_px,
+ const int y_px,
+ ImBuf *ibuf,
+ BLI_Stack *stack,
+ BLI_bitmap *touched,
+ const float color[4],
+ float threshold_sq)
{
- size_t coordinate;
+ size_t coordinate;
- if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0)
- return;
+ if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0)
+ return;
- coordinate = ((size_t)y_px) * ibuf->x + x_px;
+ coordinate = ((size_t)y_px) * ibuf->x + x_px;
- if (!BLI_BITMAP_TEST(touched, coordinate)) {
- float color_f[4];
- unsigned char *color_b = (unsigned char *)(ibuf->rect + coordinate);
- rgba_uchar_to_float(color_f, color_b);
- straight_to_premul_v4(color_f);
+ if (!BLI_BITMAP_TEST(touched, coordinate)) {
+ float color_f[4];
+ unsigned char *color_b = (unsigned char *)(ibuf->rect + coordinate);
+ rgba_uchar_to_float(color_f, color_b);
+ straight_to_premul_v4(color_f);
- if (len_squared_v4v4(color_f, color) <= threshold_sq) {
- BLI_stack_push(stack, &coordinate);
- }
- BLI_BITMAP_SET(touched, coordinate, true);
- }
+ if (len_squared_v4v4(color_f, color) <= threshold_sq) {
+ BLI_stack_push(stack, &coordinate);
+ }
+ BLI_BITMAP_SET(touched, coordinate, true);
+ }
}
-static void paint_2d_fill_add_pixel_float(
- const int x_px, const int y_px, ImBuf *ibuf, BLI_Stack *stack, BLI_bitmap *touched,
- const float color[4], float threshold_sq)
+static void paint_2d_fill_add_pixel_float(const int x_px,
+ const int y_px,
+ ImBuf *ibuf,
+ BLI_Stack *stack,
+ BLI_bitmap *touched,
+ const float color[4],
+ float threshold_sq)
{
- size_t coordinate;
+ size_t coordinate;
- if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0)
- return;
+ if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0)
+ return;
- coordinate = ((size_t)y_px) * ibuf->x + x_px;
+ coordinate = ((size_t)y_px) * ibuf->x + x_px;
- if (!BLI_BITMAP_TEST(touched, coordinate)) {
- if (len_squared_v4v4(ibuf->rect_float + 4 * coordinate, color) <= threshold_sq) {
- BLI_stack_push(stack, &coordinate);
- }
- BLI_BITMAP_SET(touched, coordinate, true);
- }
+ if (!BLI_BITMAP_TEST(touched, coordinate)) {
+ if (len_squared_v4v4(ibuf->rect_float + 4 * coordinate, color) <= threshold_sq) {
+ BLI_stack_push(stack, &coordinate);
+ }
+ BLI_BITMAP_SET(touched, coordinate, true);
+ }
}
/* this function expects linear space color values */
void paint_2d_bucket_fill(
- const bContext *C, const float color[3], Brush *br,
- const float mouse_init[2],
- void *ps)
+ const bContext *C, const float color[3], Brush *br, const float mouse_init[2], void *ps)
{
- SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = sima->image;
-
- ImagePaintState *s = ps;
-
- ImBuf *ibuf;
- int x_px, y_px;
- unsigned int color_b;
- float color_f[4];
- float strength = br ? br->alpha : 1.0f;
-
- bool do_float;
-
- if (!ima)
- return;
-
- ibuf = BKE_image_acquire_ibuf(ima, &sima->iuser, NULL);
-
- if (!ibuf)
- return;
-
- do_float = (ibuf->rect_float != NULL);
- /* first check if our image is float. If it is not we should correct the color to
- * be in gamma space. strictly speaking this is not correct, but blender does not paint
- * byte images in linear space */
- if (!do_float) {
- linearrgb_to_srgb_uchar3((unsigned char *)&color_b, color);
- *(((char *)&color_b) + 3) = strength * 255;
- }
- else {
- copy_v3_v3(color_f, color);
- color_f[3] = strength;
- }
-
- if (!mouse_init || !br) {
- /* first case, no image UV, fill the whole image */
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
-
- if (do_float) {
- for (x_px = 0; x_px < ibuf->x; x_px++) {
- for (y_px = 0; y_px < ibuf->y; y_px++) {
- blend_color_mix_float(
- ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
- ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px), color_f);
- }
- }
- }
- else {
- for (x_px = 0; x_px < ibuf->x; x_px++) {
- for (y_px = 0; y_px < ibuf->y; y_px++) {
- blend_color_mix_byte(
- (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
- (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px), (unsigned char *)&color_b);
- }
- }
- }
- }
- else {
- /* second case, start sweeping the neighboring pixels, looking for pixels whose
- * value is within the brush fill threshold from the fill color */
- BLI_Stack *stack;
- BLI_bitmap *touched;
- size_t coordinate;
- int width = ibuf->x;
- float image_init[2];
- int minx = ibuf->x, miny = ibuf->y, maxx = 0, maxy = 0;
- float pixel_color[4];
- /* We are comparing to sum of three squared values
- * (assumed in range [0,1]), so need to multiply... */
- float threshold_sq = br->fill_threshold * br->fill_threshold * 3;
-
- UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]);
-
- x_px = image_init[0] * ibuf->x;
- y_px = image_init[1] * ibuf->y;
-
- if (x_px >= ibuf->x || x_px < 0 || y_px > ibuf->y || y_px < 0) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- return;
- }
-
- /* change image invalidation method later */
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
-
- stack = BLI_stack_new(sizeof(size_t), __func__);
- touched = BLI_BITMAP_NEW(((size_t)ibuf->x) * ibuf->y, "bucket_fill_bitmap");
-
- coordinate = (((size_t)y_px) * ibuf->x + x_px);
-
- if (do_float) {
- copy_v4_v4(pixel_color, ibuf->rect_float + 4 * coordinate);
- }
- else {
- int pixel_color_b = *(ibuf->rect + coordinate);
- rgba_uchar_to_float(pixel_color, (unsigned char *)&pixel_color_b);
- straight_to_premul_v4(pixel_color);
- }
-
- BLI_stack_push(stack, &coordinate);
- BLI_BITMAP_SET(touched, coordinate, true);
-
- if (do_float) {
- while (!BLI_stack_is_empty(stack)) {
- BLI_stack_pop(stack, &coordinate);
-
- IMB_blend_color_float(
- ibuf->rect_float + 4 * (coordinate),
- ibuf->rect_float + 4 * (coordinate),
- color_f, br->blend);
-
- /* reconstruct the coordinates here */
- x_px = coordinate % width;
- y_px = coordinate / width;
-
- paint_2d_fill_add_pixel_float(x_px - 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_float(x_px - 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_float(x_px - 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_float(x_px, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_float(x_px, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_float(x_px + 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_float(x_px + 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_float(x_px + 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
-
- if (x_px > maxx)
- maxx = x_px;
- if (x_px < minx)
- minx = x_px;
- if (y_px > maxy)
- maxy = y_px;
- if (x_px > miny)
- miny = y_px;
- }
- }
- else {
- while (!BLI_stack_is_empty(stack)) {
- BLI_stack_pop(stack, &coordinate);
-
- IMB_blend_color_byte(
- (unsigned char *)(ibuf->rect + coordinate),
- (unsigned char *)(ibuf->rect + coordinate),
- (unsigned char *)&color_b, br->blend);
-
- /* reconstruct the coordinates here */
- x_px = coordinate % width;
- y_px = coordinate / width;
-
- paint_2d_fill_add_pixel_byte(x_px - 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_byte(x_px - 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_byte(x_px - 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_byte(x_px, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_byte(x_px, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_byte(x_px + 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_byte(x_px + 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
- paint_2d_fill_add_pixel_byte(x_px + 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
-
- if (x_px > maxx)
- maxx = x_px;
- if (x_px < minx)
- minx = x_px;
- if (y_px > maxy)
- maxy = y_px;
- if (x_px > miny)
- miny = y_px;
- }
- }
-
- MEM_freeN(touched);
- BLI_stack_free(stack);
- }
-
- imapaint_image_update(sima, ima, ibuf, false);
- ED_imapaint_clear_partial_redraw();
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
-
- WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = sima->image;
+
+ ImagePaintState *s = ps;
+
+ ImBuf *ibuf;
+ int x_px, y_px;
+ unsigned int color_b;
+ float color_f[4];
+ float strength = br ? br->alpha : 1.0f;
+
+ bool do_float;
+
+ if (!ima)
+ return;
+
+ ibuf = BKE_image_acquire_ibuf(ima, &sima->iuser, NULL);
+
+ if (!ibuf)
+ return;
+
+ do_float = (ibuf->rect_float != NULL);
+ /* first check if our image is float. If it is not we should correct the color to
+ * be in gamma space. strictly speaking this is not correct, but blender does not paint
+ * byte images in linear space */
+ if (!do_float) {
+ linearrgb_to_srgb_uchar3((unsigned char *)&color_b, color);
+ *(((char *)&color_b) + 3) = strength * 255;
+ }
+ else {
+ copy_v3_v3(color_f, color);
+ color_f[3] = strength;
+ }
+
+ if (!mouse_init || !br) {
+ /* first case, no image UV, fill the whole image */
+ ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
+
+ if (do_float) {
+ for (x_px = 0; x_px < ibuf->x; x_px++) {
+ for (y_px = 0; y_px < ibuf->y; y_px++) {
+ blend_color_mix_float(ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
+ ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
+ color_f);
+ }
+ }
+ }
+ else {
+ for (x_px = 0; x_px < ibuf->x; x_px++) {
+ for (y_px = 0; y_px < ibuf->y; y_px++) {
+ blend_color_mix_byte((unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
+ (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
+ (unsigned char *)&color_b);
+ }
+ }
+ }
+ }
+ else {
+ /* second case, start sweeping the neighboring pixels, looking for pixels whose
+ * value is within the brush fill threshold from the fill color */
+ BLI_Stack *stack;
+ BLI_bitmap *touched;
+ size_t coordinate;
+ int width = ibuf->x;
+ float image_init[2];
+ int minx = ibuf->x, miny = ibuf->y, maxx = 0, maxy = 0;
+ float pixel_color[4];
+ /* We are comparing to sum of three squared values
+ * (assumed in range [0,1]), so need to multiply... */
+ float threshold_sq = br->fill_threshold * br->fill_threshold * 3;
+
+ UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]);
+
+ x_px = image_init[0] * ibuf->x;
+ y_px = image_init[1] * ibuf->y;
+
+ if (x_px >= ibuf->x || x_px < 0 || y_px > ibuf->y || y_px < 0) {
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ return;
+ }
+
+ /* change image invalidation method later */
+ ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
+
+ stack = BLI_stack_new(sizeof(size_t), __func__);
+ touched = BLI_BITMAP_NEW(((size_t)ibuf->x) * ibuf->y, "bucket_fill_bitmap");
+
+ coordinate = (((size_t)y_px) * ibuf->x + x_px);
+
+ if (do_float) {
+ copy_v4_v4(pixel_color, ibuf->rect_float + 4 * coordinate);
+ }
+ else {
+ int pixel_color_b = *(ibuf->rect + coordinate);
+ rgba_uchar_to_float(pixel_color, (unsigned char *)&pixel_color_b);
+ straight_to_premul_v4(pixel_color);
+ }
+
+ BLI_stack_push(stack, &coordinate);
+ BLI_BITMAP_SET(touched, coordinate, true);
+
+ if (do_float) {
+ while (!BLI_stack_is_empty(stack)) {
+ BLI_stack_pop(stack, &coordinate);
+
+ IMB_blend_color_float(ibuf->rect_float + 4 * (coordinate),
+ ibuf->rect_float + 4 * (coordinate),
+ color_f,
+ br->blend);
+
+ /* reconstruct the coordinates here */
+ x_px = coordinate % width;
+ y_px = coordinate / width;
+
+ paint_2d_fill_add_pixel_float(
+ x_px - 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(
+ x_px - 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(
+ x_px - 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(
+ x_px, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(
+ x_px, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(
+ x_px + 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(
+ x_px + 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(
+ x_px + 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+
+ if (x_px > maxx)
+ maxx = x_px;
+ if (x_px < minx)
+ minx = x_px;
+ if (y_px > maxy)
+ maxy = y_px;
+ if (x_px > miny)
+ miny = y_px;
+ }
+ }
+ else {
+ while (!BLI_stack_is_empty(stack)) {
+ BLI_stack_pop(stack, &coordinate);
+
+ IMB_blend_color_byte((unsigned char *)(ibuf->rect + coordinate),
+ (unsigned char *)(ibuf->rect + coordinate),
+ (unsigned char *)&color_b,
+ br->blend);
+
+ /* reconstruct the coordinates here */
+ x_px = coordinate % width;
+ y_px = coordinate / width;
+
+ paint_2d_fill_add_pixel_byte(
+ x_px - 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(
+ x_px - 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(
+ x_px - 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(
+ x_px, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(
+ x_px, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(
+ x_px + 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(
+ x_px + 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(
+ x_px + 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+
+ if (x_px > maxx)
+ maxx = x_px;
+ if (x_px < minx)
+ minx = x_px;
+ if (y_px > maxy)
+ maxy = y_px;
+ if (x_px > miny)
+ miny = y_px;
+ }
+ }
+
+ MEM_freeN(touched);
+ BLI_stack_free(stack);
+ }
+
+ imapaint_image_update(sima, ima, ibuf, false);
+ ED_imapaint_clear_partial_redraw();
+
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
}
void paint_2d_gradient_fill(
- const bContext *C, Brush *br,
- const float mouse_init[2], const float mouse_final[2],
- void *ps)
+ const bContext *C, Brush *br, const float mouse_init[2], const float mouse_final[2], void *ps)
{
- SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = sima->image;
- ImagePaintState *s = ps;
-
- ImBuf *ibuf;
- int x_px, y_px;
- unsigned int color_b;
- float color_f[4];
- float image_init[2], image_final[2];
- float tangent[2];
- float line_len_sq_inv, line_len;
-
- bool do_float;
-
- if (!ima)
- return;
-
- ibuf = BKE_image_acquire_ibuf(ima, &sima->iuser, NULL);
-
- if (!ibuf)
- return;
-
- UI_view2d_region_to_view(s->v2d, mouse_final[0], mouse_final[1], &image_final[0], &image_final[1]);
- UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]);
-
- image_final[0] *= ibuf->x;
- image_final[1] *= ibuf->y;
-
- image_init[0] *= ibuf->x;
- image_init[1] *= ibuf->y;
-
- /* some math to get needed gradient variables */
- sub_v2_v2v2(tangent, image_final, image_init);
- line_len = len_squared_v2(tangent);
- line_len_sq_inv = 1.0f / line_len;
- line_len = sqrtf(line_len);
-
- do_float = (ibuf->rect_float != NULL);
-
- /* this will be substituted by something else when selection is available */
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
-
- if (do_float) {
- for (x_px = 0; x_px < ibuf->x; x_px++) {
- for (y_px = 0; y_px < ibuf->y; y_px++) {
- float f;
- float p[2] = {x_px - image_init[0], y_px - image_init[1]};
-
- switch (br->gradient_fill_mode) {
- case BRUSH_GRADIENT_LINEAR:
- {
- f = dot_v2v2(p, tangent) * line_len_sq_inv;
- break;
- }
- case BRUSH_GRADIENT_RADIAL:
- default:
- {
- f = len_v2(p) / line_len;
- break;
- }
- }
- BKE_colorband_evaluate(br->gradient, f, color_f);
- /* convert to premultiplied */
- mul_v3_fl(color_f, color_f[3]);
- color_f[3] *= br->alpha;
- IMB_blend_color_float(
- ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
- ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
- color_f, br->blend);
- }
- }
- }
- else {
- for (x_px = 0; x_px < ibuf->x; x_px++) {
- for (y_px = 0; y_px < ibuf->y; y_px++) {
- float f;
- float p[2] = {x_px - image_init[0], y_px - image_init[1]};
-
- switch (br->gradient_fill_mode) {
- case BRUSH_GRADIENT_LINEAR:
- {
- f = dot_v2v2(p, tangent) * line_len_sq_inv;
- break;
- }
- case BRUSH_GRADIENT_RADIAL:
- default:
- {
- f = len_v2(p) / line_len;
- break;
- }
- }
-
- BKE_colorband_evaluate(br->gradient, f, color_f);
- linearrgb_to_srgb_v3_v3(color_f, color_f);
- rgba_float_to_uchar((unsigned char *)&color_b, color_f);
- ((unsigned char *)&color_b)[3] *= br->alpha;
- IMB_blend_color_byte(
- (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
- (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
- (unsigned char *)&color_b, br->blend);
- }
- }
- }
-
- imapaint_image_update(sima, ima, ibuf, false);
- ED_imapaint_clear_partial_redraw();
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
-
- WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = sima->image;
+ ImagePaintState *s = ps;
+
+ ImBuf *ibuf;
+ int x_px, y_px;
+ unsigned int color_b;
+ float color_f[4];
+ float image_init[2], image_final[2];
+ float tangent[2];
+ float line_len_sq_inv, line_len;
+
+ bool do_float;
+
+ if (!ima)
+ return;
+
+ ibuf = BKE_image_acquire_ibuf(ima, &sima->iuser, NULL);
+
+ if (!ibuf)
+ return;
+
+ UI_view2d_region_to_view(
+ s->v2d, mouse_final[0], mouse_final[1], &image_final[0], &image_final[1]);
+ UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]);
+
+ image_final[0] *= ibuf->x;
+ image_final[1] *= ibuf->y;
+
+ image_init[0] *= ibuf->x;
+ image_init[1] *= ibuf->y;
+
+ /* some math to get needed gradient variables */
+ sub_v2_v2v2(tangent, image_final, image_init);
+ line_len = len_squared_v2(tangent);
+ line_len_sq_inv = 1.0f / line_len;
+ line_len = sqrtf(line_len);
+
+ do_float = (ibuf->rect_float != NULL);
+
+ /* this will be substituted by something else when selection is available */
+ ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
+
+ if (do_float) {
+ for (x_px = 0; x_px < ibuf->x; x_px++) {
+ for (y_px = 0; y_px < ibuf->y; y_px++) {
+ float f;
+ float p[2] = {x_px - image_init[0], y_px - image_init[1]};
+
+ switch (br->gradient_fill_mode) {
+ case BRUSH_GRADIENT_LINEAR: {
+ f = dot_v2v2(p, tangent) * line_len_sq_inv;
+ break;
+ }
+ case BRUSH_GRADIENT_RADIAL:
+ default: {
+ f = len_v2(p) / line_len;
+ break;
+ }
+ }
+ BKE_colorband_evaluate(br->gradient, f, color_f);
+ /* convert to premultiplied */
+ mul_v3_fl(color_f, color_f[3]);
+ color_f[3] *= br->alpha;
+ IMB_blend_color_float(ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
+ ibuf->rect_float + 4 * (((size_t)y_px) * ibuf->x + x_px),
+ color_f,
+ br->blend);
+ }
+ }
+ }
+ else {
+ for (x_px = 0; x_px < ibuf->x; x_px++) {
+ for (y_px = 0; y_px < ibuf->y; y_px++) {
+ float f;
+ float p[2] = {x_px - image_init[0], y_px - image_init[1]};
+
+ switch (br->gradient_fill_mode) {
+ case BRUSH_GRADIENT_LINEAR: {
+ f = dot_v2v2(p, tangent) * line_len_sq_inv;
+ break;
+ }
+ case BRUSH_GRADIENT_RADIAL:
+ default: {
+ f = len_v2(p) / line_len;
+ break;
+ }
+ }
+
+ BKE_colorband_evaluate(br->gradient, f, color_f);
+ linearrgb_to_srgb_v3_v3(color_f, color_f);
+ rgba_float_to_uchar((unsigned char *)&color_b, color_f);
+ ((unsigned char *)&color_b)[3] *= br->alpha;
+ IMB_blend_color_byte((unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
+ (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
+ (unsigned char *)&color_b,
+ br->blend);
+ }
+ }
+ }
+
+ imapaint_image_update(sima, ima, ibuf, false);
+ ED_imapaint_clear_partial_redraw();
+
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
}