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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/sculpt_paint')
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c21
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c722
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c118
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h2
4 files changed, 559 insertions, 304 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 0b770f17314..de09a52258f 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -119,7 +119,8 @@ void imapaint_region_tiles(
*ty = (y >> ED_IMAGE_UNDO_TILE_BITS);
}
-void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h, bool find_old)
+void ED_imapaint_dirty_region(
+ Image *ima, ImBuf *ibuf, int tile_number, int x, int y, int w, int h, bool find_old)
{
ImBuf *tmpibuf = NULL;
int tilex, tiley, tilew, tileh, tx, ty;
@@ -152,7 +153,7 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int
for (ty = tiley; ty <= tileh; ty++) {
for (tx = tilex; tx <= tilew; tx++) {
ED_image_paint_tile_push(
- undo_tiles, ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old);
+ undo_tiles, ima, ibuf, &tmpibuf, tile_number, tx, ty, NULL, NULL, false, find_old);
}
}
@@ -163,7 +164,8 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int
}
}
-void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short texpaint)
+void imapaint_image_update(
+ SpaceImage *sima, Image *image, ImBuf *ibuf, ImageUser *iuser, short texpaint)
{
if (imapaintpartial.x1 != imapaintpartial.x2 && imapaintpartial.y1 != imapaintpartial.y2) {
IMB_partial_display_buffer_update_delayed(
@@ -180,8 +182,7 @@ void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short te
int h = imapaintpartial.y2 - imapaintpartial.y1;
if (w && h) {
/* Testing with partial update in uv editor too */
- GPU_paint_update_image(
- image, (sima ? &sima->iuser : NULL), imapaintpartial.x1, imapaintpartial.y1, w, h);
+ GPU_paint_update_image(image, iuser, imapaintpartial.x1, imapaintpartial.y1, w, h);
}
}
}
@@ -623,7 +624,7 @@ static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke)
else {
srgb_to_linearrgb_v3_v3(color, BKE_brush_color_get(scene, brush));
}
- paint_2d_bucket_fill(C, color, brush, pop->prevmouse, pop->custom_paint);
+ paint_2d_bucket_fill(C, color, brush, pop->startmouse, pop->prevmouse, pop->custom_paint);
}
else {
paint_proj_stroke(C,
@@ -1297,7 +1298,10 @@ void PAINT_OT_brush_colors_flip(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-void ED_imapaint_bucket_fill(struct bContext *C, float color[3], wmOperator *op)
+void ED_imapaint_bucket_fill(struct bContext *C,
+ float color[3],
+ wmOperator *op,
+ const int mouse[2])
{
wmWindowManager *wm = CTX_wm_manager(C);
SpaceImage *sima = CTX_wm_space_image(C);
@@ -1307,7 +1311,8 @@ void ED_imapaint_bucket_fill(struct bContext *C, float color[3], wmOperator *op)
ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D);
- paint_2d_bucket_fill(C, color, NULL, NULL, NULL);
+ float mouse_init[2] = {mouse[0], mouse[1]};
+ paint_2d_bucket_fill(C, color, NULL, mouse_init, NULL, NULL);
BKE_undosys_step_push(wm->undo_stack, C, op->type->name);
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 004caae8a00..06d79b8a49d 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -30,6 +30,7 @@
#include "DNA_space_types.h"
#include "DNA_object_types.h"
+#include "BLI_listbase.h"
#include "BLI_math_color_blend.h"
#include "BLI_stack.h"
#include "BLI_bitmap.h"
@@ -84,22 +85,21 @@ typedef struct BrushPainterCache {
unsigned short *tex_mask_old;
unsigned int tex_mask_old_w;
unsigned int tex_mask_old_h;
+
+ int image_size[2];
} BrushPainterCache;
typedef struct BrushPainter {
Scene *scene;
Brush *brush;
- float lastpaintpos[2]; /* position of last paint op */
- float startpaintpos[2]; /* position of first paint */
-
short firsttouch; /* first paint op */
struct ImagePool *pool; /* image pool */
rctf tex_mapping; /* texture coordinate mapping */
rctf mask_mapping; /* mask texture coordinate mapping */
- BrushPainterCache cache;
+ bool cache_invert;
} BrushPainter;
typedef struct ImagePaintRegion {
@@ -108,6 +108,27 @@ typedef struct ImagePaintRegion {
int width, height;
} ImagePaintRegion;
+typedef enum ImagePaintTileState {
+ PAINT2D_TILE_UNINITIALIZED = 0,
+ PAINT2D_TILE_MISSING,
+ PAINT2D_TILE_READY,
+} ImagePaintTileState;
+
+typedef struct ImagePaintTile {
+ ImageUser iuser;
+ ImBuf *canvas;
+ float radius_fac;
+ int size[2];
+ float uv_origin[2]; /* Stores the position of this tile in UV space. */
+ bool need_redraw;
+ BrushPainterCache cache;
+
+ ImagePaintTileState state;
+
+ float last_paintpos[2]; /* position of last paint op */
+ float start_paintpos[2]; /* position of first paint */
+} ImagePaintTile;
+
typedef struct ImagePaintState {
BrushPainter *painter;
SpaceImage *sima;
@@ -119,10 +140,7 @@ typedef struct ImagePaintState {
Brush *brush;
short tool, blend;
Image *image;
- ImBuf *canvas;
ImBuf *clonecanvas;
- const char *warnpackedfile;
- const char *warnmultifile;
bool do_masking;
@@ -133,7 +151,8 @@ typedef struct ImagePaintState {
int do_facesel;
int symmetry;
- bool need_redraw;
+ ImagePaintTile *tiles;
+ int num_tiles;
BlurKernel *blurkernel;
} ImagePaintState;
@@ -145,63 +164,60 @@ static BrushPainter *brush_painter_2d_new(Scene *scene, Brush *brush, bool inver
painter->brush = brush;
painter->scene = scene;
painter->firsttouch = 1;
- painter->cache.lastdiameter = -1; /* force ibuf create in refresh */
- painter->cache.invert = invert;
+ painter->cache_invert = invert;
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(
+ Brush *brush, ImagePaintTile *tile, bool use_float, bool use_color_correction, bool invert)
{
- Brush *brush = painter->brush;
+ BrushPainterCache *cache = &tile->cache;
- if ((painter->cache.use_float != use_float)) {
- if (painter->cache.ibuf) {
- IMB_freeImBuf(painter->cache.ibuf);
+ if ((cache->use_float != use_float)) {
+ if (cache->ibuf) {
+ IMB_freeImBuf(cache->ibuf);
}
- if (painter->cache.curve_mask) {
- MEM_freeN(painter->cache.curve_mask);
+ if (cache->curve_mask) {
+ MEM_freeN(cache->curve_mask);
}
- if (painter->cache.tex_mask) {
- MEM_freeN(painter->cache.tex_mask);
+ if (cache->tex_mask) {
+ MEM_freeN(cache->tex_mask);
}
- if (painter->cache.tex_mask_old) {
- MEM_freeN(painter->cache.tex_mask_old);
+ if (cache->tex_mask_old) {
+ MEM_freeN(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;
+ cache->ibuf = NULL;
+ cache->curve_mask = NULL;
+ cache->tex_mask = NULL;
+ cache->lastdiameter = -1; /* force ibuf create in refresh */
+ cache->invert = invert;
+ }
+
+ cache->use_float = use_float;
+ cache->use_color_correction = use_float && use_color_correction;
+ cache->is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? true :
+ false;
+ cache->is_maskbrush = (brush->mask_mtex.tex) ? true : false;
}
-static void brush_painter_2d_free(BrushPainter *painter)
+static void brush_painter_cache_2d_free(BrushPainterCache *cache)
{
- if (painter->cache.ibuf) {
- IMB_freeImBuf(painter->cache.ibuf);
+ if (cache->ibuf) {
+ IMB_freeImBuf(cache->ibuf);
}
- if (painter->cache.texibuf) {
- IMB_freeImBuf(painter->cache.texibuf);
+ if (cache->texibuf) {
+ IMB_freeImBuf(cache->texibuf);
}
- if (painter->cache.curve_mask) {
- MEM_freeN(painter->cache.curve_mask);
+ if (cache->curve_mask) {
+ MEM_freeN(cache->curve_mask);
}
- if (painter->cache.tex_mask) {
- MEM_freeN(painter->cache.tex_mask);
+ if (cache->tex_mask) {
+ MEM_freeN(cache->tex_mask);
}
- if (painter->cache.tex_mask_old) {
- MEM_freeN(painter->cache.tex_mask_old);
+ if (cache->tex_mask_old) {
+ MEM_freeN(cache->tex_mask_old);
}
- MEM_freeN(painter);
}
static void brush_imbuf_tex_co(rctf *mapping, int x, int y, float texco[3])
@@ -212,7 +228,7 @@ static void brush_imbuf_tex_co(rctf *mapping, int x, int y, float texco[3])
}
/* create a mask with the mask texture */
-static unsigned short *brush_painter_mask_ibuf_new(BrushPainter *painter, int size)
+static unsigned short *brush_painter_mask_ibuf_new(BrushPainter *painter, const int size)
{
Scene *scene = painter->scene;
Brush *brush = painter->brush;
@@ -240,6 +256,7 @@ static unsigned short *brush_painter_mask_ibuf_new(BrushPainter *painter, int si
/* update rectangular section of the brush image */
static void brush_painter_mask_imbuf_update(BrushPainter *painter,
+ ImagePaintTile *tile,
unsigned short *tex_mask_old,
int origx,
int origy,
@@ -247,10 +264,11 @@ static void brush_painter_mask_imbuf_update(BrushPainter *painter,
int h,
int xt,
int yt,
- int diameter)
+ const int diameter)
{
Scene *scene = painter->scene;
Brush *brush = painter->brush;
+ BrushPainterCache *cache = &tile->cache;
rctf tex_mapping = painter->mask_mapping;
struct ImagePool *pool = painter->pool;
unsigned short res;
@@ -259,8 +277,8 @@ static void brush_painter_mask_imbuf_update(BrushPainter *painter,
int x, y, thread = 0;
- unsigned short *tex_mask = painter->cache.tex_mask;
- unsigned short *tex_mask_cur = painter->cache.tex_mask_old;
+ unsigned short *tex_mask = cache->tex_mask;
+ unsigned short *tex_mask_cur = cache->tex_mask_old;
/* fill pixels */
for (y = origy; y < h; y++) {
@@ -280,8 +298,7 @@ static void brush_painter_mask_imbuf_update(BrushPainter *painter,
/* 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)));
+ res = *(tex_mask_old + ((y - origy + yt) * cache->tex_mask_old_w + (x - origx + xt)));
}
/* write to new texture mask */
@@ -298,10 +315,11 @@ static void brush_painter_mask_imbuf_update(BrushPainter *painter,
* textures that stick to the surface where only part of the pixels are new
*/
static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter,
+ ImagePaintTile *tile,
const float pos[2],
- int diameter)
+ const int diameter)
{
- BrushPainterCache *cache = &painter->cache;
+ BrushPainterCache *cache = &tile->cache;
unsigned short *tex_mask_old;
int destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
@@ -319,15 +337,16 @@ static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter,
if (tex_mask_old) {
ImBuf maskibuf;
ImBuf maskibuf_old;
- maskibuf.x = maskibuf.y = diameter;
+ maskibuf.x = diameter;
+ 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);
+ destx = (int)floorf(tile->last_paintpos[0]) - (int)floorf(pos[0]) + (diameter / 2 - w / 2);
+ desty = (int)floorf(tile->last_paintpos[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);
@@ -345,7 +364,8 @@ static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter,
/* 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);
+ brush_painter_mask_imbuf_update(
+ painter, tile, tex_mask_old, x1, y1, x2, y2, srcx, srcy, diameter);
}
if (tex_mask_old) {
@@ -354,16 +374,17 @@ static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter,
/* sample texture in new areas */
if ((0 < x1) && (0 < diameter)) {
- brush_painter_mask_imbuf_update(painter, NULL, 0, 0, x1, diameter, 0, 0, diameter);
+ brush_painter_mask_imbuf_update(painter, tile, 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);
+ brush_painter_mask_imbuf_update(
+ painter, tile, 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);
+ brush_painter_mask_imbuf_update(painter, tile, 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);
+ brush_painter_mask_imbuf_update(painter, tile, NULL, x1, y2, x2, diameter, 0, 0, diameter);
}
/* through with sampling, now update sizes */
@@ -445,13 +466,12 @@ static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter,
}
/* 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, ImagePaintTile *tile, const int size, float pressure, float distance)
{
Scene *scene = painter->scene;
Brush *brush = painter->brush;
+ BrushPainterCache *cache = &tile->cache;
const char *display_device = scene->display_settings.display_device;
struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
@@ -459,9 +479,9 @@ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter,
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_color_correction = cache->use_color_correction;
+ bool use_float = cache->use_float;
+ bool is_texbrush = cache->is_texbrush;
int x, y, thread = 0;
float brush_rgb[3];
@@ -471,14 +491,8 @@ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter,
/* 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);
+ paint_brush_color_get(
+ scene, brush, use_color_correction, cache->invert, distance, pressure, brush_rgb, display);
}
else {
brush_rgb[0] = 1.0f;
@@ -526,11 +540,19 @@ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter,
}
/* 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)
+static void brush_painter_imbuf_update(BrushPainter *painter,
+ ImagePaintTile *tile,
+ ImBuf *oldtexibuf,
+ int origx,
+ int origy,
+ int w,
+ int h,
+ int xt,
+ int yt)
{
Scene *scene = painter->scene;
Brush *brush = painter->brush;
+ BrushPainterCache *cache = &tile->cache;
const char *display_device = scene->display_settings.display_device;
struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
@@ -538,21 +560,21 @@ static void brush_painter_imbuf_update(
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_color_correction = cache->use_color_correction;
+ bool use_float = cache->use_float;
+ bool is_texbrush = 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;
+ ImBuf *ibuf = cache->ibuf;
+ ImBuf *texibuf = 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);
+ scene, brush, use_color_correction, cache->invert, 0.0, 1.0, brush_rgb, display);
}
else {
brush_rgb[0] = 1.0f;
@@ -641,10 +663,11 @@ static void brush_painter_imbuf_update(
* 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,
+ ImagePaintTile *tile,
const float pos[2],
- int diameter)
+ const int diameter)
{
- BrushPainterCache *cache = &painter->cache;
+ BrushPainterCache *cache = &tile->cache;
ImBuf *oldtexibuf, *ibuf;
int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
@@ -663,8 +686,8 @@ static void brush_painter_imbuf_partial_update(BrushPainter *painter,
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);
+ destx = (int)floorf(tile->last_paintpos[0]) - (int)floorf(pos[0]) + (diameter / 2 - w / 2);
+ desty = (int)floorf(tile->last_paintpos[1]) - (int)floorf(pos[1]) + (diameter / 2 - h / 2);
IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h);
}
@@ -681,7 +704,7 @@ static void brush_painter_imbuf_partial_update(BrushPainter *painter,
/* blend existing texture in new position */
if ((x1 < x2) && (y1 < y2)) {
- brush_painter_imbuf_update(painter, oldtexibuf, x1, y1, x2, y2, srcx, srcy);
+ brush_painter_imbuf_update(painter, tile, oldtexibuf, x1, y1, x2, y2, srcx, srcy);
}
if (oldtexibuf) {
@@ -690,29 +713,30 @@ static void brush_painter_imbuf_partial_update(BrushPainter *painter,
/* sample texture in new areas */
if ((0 < x1) && (0 < ibuf->y)) {
- brush_painter_imbuf_update(painter, NULL, 0, 0, x1, ibuf->y, 0, 0);
+ brush_painter_imbuf_update(painter, tile, 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);
+ brush_painter_imbuf_update(painter, tile, 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);
+ brush_painter_imbuf_update(painter, tile, 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);
+ brush_painter_imbuf_update(painter, tile, NULL, x1, y2, x2, ibuf->y, 0, 0);
}
}
static void brush_painter_2d_tex_mapping(ImagePaintState *s,
- int diameter,
+ ImBuf *canvas,
+ const 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;
+ float invw = 1.0f / (float)canvas->x;
+ float invh = 1.0f / (float)canvas->y;
int xmin, ymin, xmax, ymax;
int ipos[2];
@@ -756,6 +780,7 @@ static void brush_painter_2d_tex_mapping(ImagePaintState *s,
static void brush_painter_2d_refresh_cache(ImagePaintState *s,
BrushPainter *painter,
+ ImagePaintTile *tile,
const float pos[2],
const float mouse[2],
float pressure,
@@ -765,7 +790,7 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
const Scene *scene = painter->scene;
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
Brush *brush = painter->brush;
- BrushPainterCache *cache = &painter->cache;
+ BrushPainterCache *cache = &tile->cache;
/* Adding 4 pixels of padding for brush antialiasing */
const int diameter = MAX2(1, size * 2) + 4;
@@ -782,7 +807,7 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
painter->pool = BKE_image_pool_new();
/* determine how can update based on textures used */
- if (painter->cache.is_texbrush) {
+ if (cache->is_texbrush) {
if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
tex_rotation += ups->brush_rotation;
}
@@ -794,15 +819,16 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
}
brush_painter_2d_tex_mapping(s,
+ tile->canvas,
diameter,
- painter->startpaintpos,
+ tile->start_paintpos,
pos,
mouse,
brush->mtex.brush_map_mode,
&painter->tex_mapping);
}
- if (painter->cache.is_maskbrush) {
+ if (cache->is_maskbrush) {
bool renew_maxmask = false;
bool do_partial_update_mask = false;
/* invalidate case for all mapping modes */
@@ -822,7 +848,7 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
renew_maxmask = true;
}
- if ((diameter != cache->lastdiameter) || (mask_rotation != cache->last_mask_rotation) ||
+ if (diameter != cache->lastdiameter || (mask_rotation != cache->last_mask_rotation) ||
renew_maxmask) {
if (cache->tex_mask) {
MEM_freeN(cache->tex_mask);
@@ -830,15 +856,16 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
}
brush_painter_2d_tex_mapping(s,
+ tile->canvas,
diameter,
- painter->startpaintpos,
+ tile->start_paintpos,
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);
+ brush_painter_mask_imbuf_partial_update(painter, tile, pos, diameter);
}
else {
cache->tex_mask = brush_painter_mask_ibuf_new(painter, diameter);
@@ -856,8 +883,8 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size, pos);
/* detect if we need to recreate image brush buffer */
- if ((diameter != cache->lastdiameter) || (tex_rotation != cache->last_tex_rotation) ||
- do_random || update_color) {
+ if (diameter != cache->lastdiameter || (tex_rotation != cache->last_tex_rotation) || do_random ||
+ update_color) {
if (cache->ibuf) {
IMB_freeImBuf(cache->ibuf);
cache->ibuf = NULL;
@@ -865,11 +892,11 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
if (do_partial_update) {
/* do partial update of texture */
- brush_painter_imbuf_partial_update(painter, pos, diameter);
+ brush_painter_imbuf_partial_update(painter, tile, pos, diameter);
}
else {
/* create brush from scratch */
- cache->ibuf = brush_painter_imbuf_new(painter, diameter, pressure, distance);
+ cache->ibuf = brush_painter_imbuf_new(painter, tile, diameter, pressure, distance);
}
cache->lastdiameter = diameter;
@@ -878,11 +905,11 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
}
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]);
+ int dx = (int)floorf(tile->last_paintpos[0]) - (int)floorf(pos[0]);
+ int dy = (int)floorf(tile->last_paintpos[1]) - (int)floorf(pos[1]);
if ((dx != 0) || (dy != 0)) {
- brush_painter_imbuf_partial_update(painter, pos, diameter);
+ brush_painter_imbuf_partial_update(painter, tile, pos, diameter);
}
}
@@ -890,6 +917,56 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
painter->pool = NULL;
}
+static bool paint_2d_ensure_tile_canvas(ImagePaintState *s, int i)
+{
+ if (i == 0) {
+ return true;
+ }
+ if (i >= s->num_tiles) {
+ return false;
+ }
+
+ if (s->tiles[i].state == PAINT2D_TILE_READY) {
+ return true;
+ }
+ if (s->tiles[i].state == PAINT2D_TILE_MISSING) {
+ return false;
+ }
+
+ s->tiles[i].cache.lastdiameter = -1;
+
+ s->tiles[i].iuser.ok = true;
+
+ ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, &s->tiles[i].iuser, NULL);
+ if (ibuf != NULL) {
+ if (ibuf->channels != 4) {
+ s->tiles[i].state = PAINT2D_TILE_MISSING;
+ }
+ else if ((s->tiles[0].canvas->rect && !ibuf->rect) ||
+ (s->tiles[0].canvas->rect_float && !ibuf->rect_float)) {
+ s->tiles[i].state = PAINT2D_TILE_MISSING;
+ }
+ else {
+ s->tiles[i].size[0] = ibuf->x;
+ s->tiles[i].size[1] = ibuf->y;
+ s->tiles[i].radius_fac = sqrtf(((float)ibuf->x * (float)ibuf->y) /
+ (s->tiles[0].size[0] * s->tiles[0].size[1]));
+ s->tiles[i].state = PAINT2D_TILE_READY;
+ }
+ }
+ else {
+ s->tiles[i].state = PAINT2D_TILE_MISSING;
+ }
+
+ if (s->tiles[i].state == PAINT2D_TILE_MISSING) {
+ BKE_image_release_ibuf(s->image, ibuf, NULL);
+ return false;
+ }
+
+ s->tiles[i].canvas = ibuf;
+ return true;
+}
+
/* keep these functions in sync */
static void paint_2d_ibuf_rgb_get(ImBuf *ibuf, int x, int y, float r_rgb[4])
{
@@ -935,15 +1012,15 @@ static void paint_2d_ibuf_rgb_set(
}
}
-static void paint_2d_ibuf_tile_convert(ImBuf *ibuf, int *x, int *y, short tile)
+static void paint_2d_ibuf_tile_convert(ImBuf *ibuf, int *x, int *y, short paint_tile)
{
- if (tile & PAINT_TILE_X) {
+ if (paint_tile & PAINT_TILE_X) {
*x %= ibuf->x;
if (*x < 0) {
*x += ibuf->x;
}
}
- if (tile & PAINT_TILE_Y) {
+ if (paint_tile & PAINT_TILE_Y) {
*y %= ibuf->y;
if (*y < 0) {
*y += ibuf->y;
@@ -951,12 +1028,13 @@ static void paint_2d_ibuf_tile_convert(ImBuf *ibuf, int *x, int *y, short tile)
}
}
-static float paint_2d_ibuf_add_if(ImBuf *ibuf, int x, int y, float *outrgb, short tile, float w)
+static float paint_2d_ibuf_add_if(
+ ImBuf *ibuf, int x, int y, float *outrgb, short paint_tile, float w)
{
float inrgb[4];
- if (tile) {
- paint_2d_ibuf_tile_convert(ibuf, &x, &y, tile);
+ if (paint_tile) {
+ paint_2d_ibuf_tile_convert(ibuf, &x, &y, paint_tile);
}
/* need to also do clipping here always since tiled coordinates
* are not always within bounds */
@@ -973,10 +1051,14 @@ static float paint_2d_ibuf_add_if(ImBuf *ibuf, int x, int y, float *outrgb, shor
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,
+ ImagePaintTile *tile,
+ ImBuf *ibuf,
+ ImBuf *ibufb,
+ int *pos,
+ const short paint_tile)
{
- bool sharpen = (s->painter->cache.invert ^ ((s->brush->flag & BRUSH_DIR_IN) != 0));
+ bool sharpen = (tile->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;
@@ -992,7 +1074,7 @@ static void paint_2d_lift_soften(
in_off[1] = pos[1];
out_off[0] = out_off[1] = 0;
- if (!tile) {
+ if (!paint_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)) {
@@ -1010,8 +1092,8 @@ static void paint_2d_lift_soften(
yi = in_off[1] + y;
count = 0.0;
- if (tile) {
- paint_2d_ibuf_tile_convert(ibuf, &xi, &yi, tile);
+ if (paint_tile) {
+ paint_2d_ibuf_tile_convert(ibuf, &xi, &yi, paint_tile);
if (xi < ibuf->x && xi >= 0 && yi < ibuf->y && yi >= 0) {
paint_2d_ibuf_rgb_get(ibuf, xi, yi, rgba);
}
@@ -1031,7 +1113,7 @@ static void paint_2d_lift_soften(
xi + xk - kernel->pixel_len,
yi + yk - kernel->pixel_len,
outrgb,
- tile,
+ paint_tile,
kernel->wdata[xk + yk * kernel->side]);
}
}
@@ -1085,7 +1167,7 @@ static void paint_2d_set_region(
static int paint_2d_torus_split_region(ImagePaintRegion region[4],
ImBuf *dbuf,
ImBuf *sbuf,
- short tile)
+ short paint_tile)
{
int destx = region->destx;
int desty = region->desty;
@@ -1096,7 +1178,7 @@ static int paint_2d_torus_split_region(ImagePaintRegion region[4],
int origw, origh, w, h, tot = 0;
/* convert destination and source coordinates to be within image */
- if (tile & PAINT_TILE_X) {
+ if (paint_tile & PAINT_TILE_X) {
destx = destx % dbuf->x;
if (destx < 0) {
destx += dbuf->x;
@@ -1106,7 +1188,7 @@ static int paint_2d_torus_split_region(ImagePaintRegion region[4],
srcx += sbuf->x;
}
}
- if (tile & PAINT_TILE_Y) {
+ if (paint_tile & PAINT_TILE_Y) {
desty = desty % dbuf->y;
if (desty < 0) {
desty += dbuf->y;
@@ -1126,15 +1208,15 @@ static int paint_2d_torus_split_region(ImagePaintRegion region[4],
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) {
+ if ((paint_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) {
+ if ((paint_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)) {
+ if ((paint_tile & PAINT_TILE_X) && (paint_tile & PAINT_TILE_Y) && (w < origw) && (h < origh)) {
paint_2d_set_region(&region[tot++],
(destx + w) % dbuf->x,
(desty + h) % dbuf->y,
@@ -1147,13 +1229,13 @@ static int paint_2d_torus_split_region(ImagePaintRegion region[4],
return tot;
}
-static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos, short tile)
+static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos, short paint_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);
+ tot = paint_2d_torus_split_region(region, ibufb, ibuf, paint_tile);
for (a = 0; a < tot; a++) {
IMB_rectblend(ibufb,
@@ -1229,9 +1311,8 @@ static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[
}
static void paint_2d_do_making_brush(ImagePaintState *s,
+ ImagePaintTile *tile,
ImagePaintRegion *region,
- unsigned short *curveb,
- unsigned short *texmaskb,
ImBuf *frombuf,
float mask_max,
short blend,
@@ -1252,21 +1333,21 @@ static void paint_2d_do_making_brush(ImagePaintState *s,
int origx = region->destx - tx * ED_IMAGE_UNDO_TILE_SIZE;
int origy = region->desty - ty * ED_IMAGE_UNDO_TILE_SIZE;
- if (s->canvas->rect_float) {
+ if (tile->canvas->rect_float) {
tmpbuf.rect_float = ED_image_paint_tile_find(
- undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
+ undo_tiles, s->image, tile->canvas, tile->iuser.tile, tx, ty, &mask, false);
}
else {
tmpbuf.rect = ED_image_paint_tile_find(
- undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
+ undo_tiles, s->image, tile->canvas, tile->iuser.tile, tx, ty, &mask, false);
}
- IMB_rectblend(s->canvas,
+ IMB_rectblend(tile->canvas,
&tmpbuf,
frombuf,
mask,
- curveb,
- texmaskb,
+ tile->cache.curve_mask,
+ tile->cache.tex_mask,
mask_max,
region->destx,
region->desty,
@@ -1284,9 +1365,8 @@ static void paint_2d_do_making_brush(ImagePaintState *s,
typedef struct Paint2DForeachData {
ImagePaintState *s;
+ ImagePaintTile *tile;
ImagePaintRegion *region;
- unsigned short *curveb;
- unsigned short *texmaskb;
ImBuf *frombuf;
float mask_max;
short blend;
@@ -1300,9 +1380,8 @@ static void paint_2d_op_foreach_do(void *__restrict data_v,
{
Paint2DForeachData *data = (Paint2DForeachData *)data_v;
paint_2d_do_making_brush(data->s,
+ data->tile,
data->region,
- data->curveb,
- data->texmaskb,
data->frombuf,
data->mask_max,
data->blend,
@@ -1313,16 +1392,16 @@ static void paint_2d_op_foreach_do(void *__restrict data_v,
}
static int paint_2d_op(void *state,
- ImBuf *ibufb,
- unsigned short *curveb,
- unsigned short *texmaskb,
+ ImagePaintTile *tile,
const float lastpos[2],
const float pos[2])
{
ImagePaintState *s = ((ImagePaintState *)state);
ImBuf *clonebuf = NULL, *frombuf;
+ ImBuf *canvas = tile->canvas;
+ ImBuf *ibufb = tile->cache.ibuf;
ImagePaintRegion region[4];
- short tile = s->symmetry & (PAINT_TILE_X | PAINT_TILE_Y);
+ short paint_tile = s->symmetry & (PAINT_TILE_X | PAINT_TILE_Y);
short blend = s->blend;
const float *offset = s->brush->clone.offset;
float liftpos[2];
@@ -1334,7 +1413,7 @@ static int paint_2d_op(void *state,
/* lift from canvas */
if (s->tool == PAINT_TOOL_SOFTEN) {
- paint_2d_lift_soften(s, s->canvas, ibufb, bpos, tile);
+ paint_2d_lift_soften(s, tile, canvas, ibufb, bpos, paint_tile);
blend = IMB_BLEND_INTERPOLATE;
}
else if (s->tool == PAINT_TOOL_SMEAR) {
@@ -1343,12 +1422,12 @@ static int paint_2d_op(void *state,
}
paint_2d_convert_brushco(ibufb, lastpos, blastpos);
- paint_2d_lift_smear(s->canvas, ibufb, blastpos, tile);
+ paint_2d_lift_smear(canvas, ibufb, blastpos, paint_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;
+ liftpos[0] = pos[0] - offset[0] * canvas->x;
+ liftpos[1] = pos[1] - offset[1] * canvas->y;
paint_2d_convert_brushco(ibufb, liftpos, bliftpos);
clonebuf = paint_2d_lift_clone(s->clonecanvas, ibufb, bliftpos);
@@ -1356,9 +1435,9 @@ static int paint_2d_op(void *state,
frombuf = (clonebuf) ? clonebuf : ibufb;
- if (tile) {
+ if (paint_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);
+ tot = paint_2d_torus_split_region(region, canvas, frombuf, paint_tile);
}
else {
paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
@@ -1368,7 +1447,8 @@ static int paint_2d_op(void *state,
/* blend into canvas */
for (a = 0; a < tot; a++) {
ED_imapaint_dirty_region(s->image,
- s->canvas,
+ canvas,
+ tile->iuser.tile,
region[a].destx,
region[a].desty,
region[a].width,
@@ -1379,7 +1459,7 @@ static int paint_2d_op(void *state,
/* masking, find original pixels tiles from undo buffer to composite over */
int tilex, tiley, tilew, tileh;
- imapaint_region_tiles(s->canvas,
+ imapaint_region_tiles(canvas,
region[a].destx,
region[a].desty,
region[a].width,
@@ -1391,14 +1471,13 @@ static int paint_2d_op(void *state,
if (tiley == tileh) {
paint_2d_do_making_brush(
- s, &region[a], curveb, texmaskb, frombuf, mask_max, blend, tilex, tiley, tilew, tileh);
+ s, tile, &region[a], frombuf, mask_max, blend, tilex, tiley, tilew, tileh);
}
else {
Paint2DForeachData data;
data.s = s;
+ data.tile = tile;
data.region = &region[a];
- data.curveb = curveb;
- data.texmaskb = texmaskb;
data.frombuf = frombuf;
data.mask_max = mask_max;
data.blend = blend;
@@ -1412,12 +1491,12 @@ static int paint_2d_op(void *state,
}
else {
/* no masking, composite brush directly onto canvas */
- IMB_rectblend_threaded(s->canvas,
- s->canvas,
+ IMB_rectblend_threaded(canvas,
+ canvas,
frombuf,
NULL,
- curveb,
- texmaskb,
+ tile->cache.curve_mask,
+ tile->cache.tex_mask,
mask_max,
region[a].destx,
region[a].desty,
@@ -1439,47 +1518,25 @@ static int paint_2d_op(void *state,
return 1;
}
-static int paint_2d_canvas_set(ImagePaintState *s, Image *ima)
+static int paint_2d_canvas_set(ImagePaintState *s)
{
- 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);
+ Image *ima = s->brush->clone.image;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, 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) {
+ if (s->tiles[0].canvas->rect_float && !s->clonecanvas->rect_float) {
IMB_float_from_rect(s->clonecanvas);
}
- else if (!s->canvas->rect_float && !s->clonecanvas->rect) {
+ else if (!s->tiles[0].canvas->rect_float && !s->clonecanvas->rect) {
IMB_rect_from_float(s->clonecanvas);
}
}
@@ -1492,7 +1549,9 @@ static int paint_2d_canvas_set(ImagePaintState *s, Image *ima)
static void paint_2d_canvas_free(ImagePaintState *s)
{
- BKE_image_release_ibuf(s->image, s->canvas, NULL);
+ for (int i = 0; i < s->num_tiles; i++) {
+ BKE_image_release_ibuf(s->image, s->tiles[i].canvas, NULL);
+ }
BKE_image_release_ibuf(s->brush->clone.image, s->clonecanvas, NULL);
if (s->blurkernel) {
@@ -1501,71 +1560,107 @@ static void paint_2d_canvas_free(ImagePaintState *s)
}
}
+static void paint_2d_transform_mouse(ImagePaintState *s, const float in[2], float out[2])
+{
+ UI_view2d_region_to_view(s->v2d, in[0], in[1], &out[0], &out[1]);
+}
+
+static bool is_inside_tile(const int size[2], const float pos[2], const float brush[2])
+{
+ return (pos[0] >= -brush[0]) && (pos[0] < size[0] + brush[0]) && (pos[1] >= -brush[1]) &&
+ (pos[1] < size[1] + brush[1]);
+}
+
+static void paint_2d_uv_to_coord(ImagePaintTile *tile, const float uv[2], float coord[2])
+{
+ coord[0] = (uv[0] - tile->uv_origin[0]) * tile->size[0];
+ coord[1] = (uv[1] - tile->uv_origin[1]) * tile->size[1];
+}
+
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 base_size)
{
- float newuv[2], olduv[2];
+ float new_uv[2], old_uv[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;
- }
+ const bool is_data = s->tiles[0].canvas->colormanage_flag & IMB_COLORMANAGE_IS_DATA;
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]);
-
- newuv[0] *= ibuf->x;
- newuv[1] *= ibuf->y;
-
- olduv[0] *= ibuf->x;
- olduv[1] *= ibuf->y;
+ UI_view2d_region_to_view(s->v2d, mval[0], mval[1], &new_uv[0], &new_uv[1]);
+ UI_view2d_region_to_view(s->v2d, prev_mval[0], prev_mval[1], &old_uv[0], &old_uv[1]);
+ float last_uv[2], start_uv[2];
+ UI_view2d_region_to_view(s->v2d, 0.0f, 0.0f, &start_uv[0], &start_uv[1]);
if (painter->firsttouch) {
- float startuv[2];
-
- 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;
-
- painter->firsttouch = 0;
- copy_v2_v2(painter->lastpaintpos, newuv);
+ copy_v2_v2(last_uv, new_uv);
}
else {
- copy_v2_v2(painter->lastpaintpos, olduv);
+ copy_v2_v2(last_uv, old_uv);
}
- /* 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);
+ float uv_brush_size[2] = {base_size / s->tiles[0].size[0], base_size / s->tiles[0].size[1]};
+
+ for (int i = 0; i < s->num_tiles; i++) {
+ ImagePaintTile *tile = &s->tiles[i];
+
+ /* First test: Project brush into UV space, clip against tile. */
+ const int uv_size[2] = {1, 1};
+ float local_new_uv[2], local_old_uv[2];
+ sub_v2_v2v2(local_new_uv, new_uv, tile->uv_origin);
+ sub_v2_v2v2(local_old_uv, old_uv, tile->uv_origin);
+ if (!(is_inside_tile(uv_size, local_new_uv, uv_brush_size) ||
+ is_inside_tile(uv_size, local_old_uv, uv_brush_size))) {
+ continue;
+ }
+
+ /* Lazy tile loading to get size in pixels. */
+ if (!paint_2d_ensure_tile_canvas(s, i)) {
+ continue;
+ }
+
+ float size = base_size * tile->radius_fac;
+
+ float new_coord[2], old_coord[2];
+ paint_2d_uv_to_coord(tile, new_uv, new_coord);
+ paint_2d_uv_to_coord(tile, old_uv, old_coord);
+ if (painter->firsttouch) {
+ paint_2d_uv_to_coord(tile, start_uv, tile->start_paintpos);
+ }
+ paint_2d_uv_to_coord(tile, last_uv, tile->last_paintpos);
+
+ /* Second check in pixel coordinates. */
+ const float pixel_brush_size[] = {size, size};
+ if (!(is_inside_tile(tile->size, new_coord, pixel_brush_size) ||
+ is_inside_tile(tile->size, old_coord, pixel_brush_size))) {
+ continue;
+ }
+
+ ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, &tile->iuser, NULL);
- brush_painter_2d_refresh_cache(s, painter, newuv, mval, pressure, distance, size);
+ /* 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->brush, tile, (ibuf->rect_float != NULL), !is_data, painter->cache_invert);
- if (paint_2d_op(s,
- painter->cache.ibuf,
- painter->cache.curve_mask,
- painter->cache.tex_mask,
- olduv,
- newuv)) {
- s->need_redraw = true;
+ brush_painter_2d_refresh_cache(s, painter, tile, new_coord, mval, pressure, distance, size);
+
+ if (paint_2d_op(s, tile, old_coord, new_coord))
+ tile->need_redraw = true;
}
- BKE_image_release_ibuf(s->image, ibuf, NULL);
+ painter->firsttouch = 0;
}
void *paint_2d_new_stroke(bContext *C, wmOperator *op, int mode)
@@ -1588,13 +1683,57 @@ void *paint_2d_new_stroke(bContext *C, wmOperator *op, int mode)
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 (s->image == NULL) {
+ MEM_freeN(s);
+ return NULL;
+ }
+ if (BKE_image_has_packedfile(s->image) && s->image->rr != NULL) {
+ BKE_report(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted");
+ MEM_freeN(s);
+ return 0;
+ }
+
+ s->num_tiles = BLI_listbase_count(&s->image->tiles);
+ s->tiles = MEM_callocN(sizeof(ImagePaintTile) * s->num_tiles, "ImagePaintTile");
+ for (int i = 0; i < s->num_tiles; i++) {
+ BKE_imageuser_default(&s->tiles[i].iuser);
+ }
+ s->tiles[0].iuser.ok = true;
+
+ zero_v2(s->tiles[0].uv_origin);
+
+ ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, &s->tiles[0].iuser, NULL);
+ if (ibuf == NULL) {
+ MEM_freeN(s->tiles);
+ MEM_freeN(s);
+ return NULL;
+ }
+
+ if (ibuf->channels != 4) {
+ BKE_report(op->reports, RPT_WARNING, "Image requires 4 color channels to paint");
+ MEM_freeN(s->tiles);
+ MEM_freeN(s);
+ return NULL;
+ }
+
+ s->tiles[0].size[0] = ibuf->x;
+ s->tiles[0].size[1] = ibuf->y;
+ s->tiles[0].radius_fac = 1.0f;
+
+ s->tiles[0].canvas = ibuf;
+ s->tiles[0].state = PAINT2D_TILE_READY;
+
+ /* Initialize offsets here, they're needed for the uv space clip test before lazy-loading the
+ * tile properly. */
+ int tile_idx = 0;
+ for (ImageTile *tile = s->image->tiles.first; tile; tile = tile->next, tile_idx++) {
+ s->tiles[tile_idx].iuser.tile = tile->tile_number;
+ s->tiles[tile_idx].uv_origin[0] = ((tile->tile_number - 1001) % 10);
+ s->tiles[tile_idx].uv_origin[1] = ((tile->tile_number - 1001) / 10);
+ }
+
+ if (!paint_2d_canvas_set(s)) {
+ MEM_freeN(s->tiles);
MEM_freeN(s);
return NULL;
@@ -1616,18 +1755,28 @@ 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);
+ bool had_redraw = false;
+ for (int i = 0; i < s->num_tiles; i++) {
+ if (s->tiles[i].need_redraw) {
+ ImBuf *ibuf = BKE_image_acquire_ibuf(s->image, &s->tiles[i].iuser, NULL);
- imapaint_image_update(s->sima, s->image, ibuf, false);
- ED_imapaint_clear_partial_redraw();
+ imapaint_image_update(s->sima, s->image, ibuf, &s->tiles[i].iuser, false);
- BKE_image_release_ibuf(s->image, ibuf, NULL);
+ BKE_image_release_ibuf(s->image, ibuf, NULL);
- s->need_redraw = false;
+ s->tiles[i].need_redraw = false;
+ had_redraw = true;
+ }
}
- else if (!final) {
- return;
+
+ if (had_redraw) {
+ ED_imapaint_clear_partial_redraw();
+ if (s->sima == NULL || !s->sima->lock) {
+ ED_region_tag_redraw(CTX_wm_region(C));
+ }
+ else {
+ WM_event_add_notifier(C, NC_IMAGE | NA_PAINTING, s->image);
+ }
}
if (final) {
@@ -1639,14 +1788,6 @@ void paint_2d_redraw(const bContext *C, void *ps, bool final)
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)
@@ -1654,7 +1795,11 @@ void paint_2d_stroke_done(void *ps)
ImagePaintState *s = ps;
paint_2d_canvas_free(s);
- brush_painter_2d_free(s->painter);
+ for (int i = 0; i < s->num_tiles; i++) {
+ brush_painter_cache_2d_free(&s->tiles[i].cache);
+ }
+ MEM_freeN(s->painter);
+ MEM_freeN(s->tiles);
paint_brush_exit_tex(s->brush);
MEM_freeN(s);
@@ -1713,9 +1858,29 @@ static void paint_2d_fill_add_pixel_float(const int x_px,
}
}
+static ImageUser *paint_2d_get_tile_iuser(ImagePaintState *s, int tile_number)
+{
+ ImageUser *iuser = &s->tiles[0].iuser;
+ for (int i = 0; i < s->num_tiles; i++) {
+ if (s->tiles[i].iuser.tile == tile_number) {
+ if (!paint_2d_ensure_tile_canvas(s, i)) {
+ return NULL;
+ }
+ iuser = &s->tiles[i].iuser;
+ break;
+ }
+ }
+
+ return iuser;
+}
+
/* 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)
+void paint_2d_bucket_fill(const bContext *C,
+ const float color[3],
+ 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;
@@ -1734,8 +1899,17 @@ void paint_2d_bucket_fill(
return;
}
- ibuf = BKE_image_acquire_ibuf(ima, &sima->iuser, NULL);
+ float uv_origin[2];
+ float image_init[2];
+ paint_2d_transform_mouse(s, mouse_init, image_init);
+ int tile_number = BKE_image_get_tile_from_pos(ima, image_init, image_init, uv_origin);
+ ImageUser *iuser = paint_2d_get_tile_iuser(s, tile_number);
+ if (!iuser) {
+ return;
+ }
+
+ ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
if (!ibuf) {
return;
}
@@ -1753,9 +1927,9 @@ void paint_2d_bucket_fill(
color_f[3] = strength;
}
- if (!mouse_init || !br) {
+ if (!mouse_final || !br) {
/* first case, no image UV, fill the whole image */
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
+ ED_imapaint_dirty_region(ima, ibuf, tile_number, 0, 0, ibuf->x, ibuf->y, false);
if (do_float) {
for (x_px = 0; x_px < ibuf->x; x_px++) {
@@ -1783,15 +1957,12 @@ void paint_2d_bucket_fill(
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;
@@ -1801,7 +1972,7 @@ void paint_2d_bucket_fill(
}
/* change image invalidation method later */
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
+ ED_imapaint_dirty_region(ima, ibuf, tile_number, 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");
@@ -1913,7 +2084,7 @@ void paint_2d_bucket_fill(
BLI_stack_free(stack);
}
- imapaint_image_update(sima, ima, ibuf, false);
+ imapaint_image_update(sima, ima, ibuf, iuser, false);
ED_imapaint_clear_partial_redraw();
BKE_image_release_ibuf(ima, ibuf, NULL);
@@ -1938,19 +2109,26 @@ void paint_2d_gradient_fill(
bool do_float;
- if (!ima) {
+ if (ima == NULL) {
return;
}
- ibuf = BKE_image_acquire_ibuf(ima, &sima->iuser, NULL);
+ float uv_origin[2];
+ int tile_number = BKE_image_get_tile_from_pos(ima, image_init, image_init, uv_origin);
+ ImageUser *iuser = paint_2d_get_tile_iuser(s, tile_number);
+ if (!iuser) {
+ return;
+ }
- if (!ibuf) {
+ ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
+ if (ibuf == NULL) {
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]);
+ paint_2d_transform_mouse(s, mouse_final, image_final);
+ paint_2d_transform_mouse(s, mouse_init, image_init);
+ sub_v2_v2(image_init, uv_origin);
+ sub_v2_v2(image_final, uv_origin);
image_final[0] *= ibuf->x;
image_final[1] *= ibuf->y;
@@ -1967,7 +2145,7 @@ void paint_2d_gradient_fill(
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);
+ ED_imapaint_dirty_region(ima, ibuf, tile_number, 0, 0, ibuf->x, ibuf->y, false);
if (do_float) {
for (x_px = 0; x_px < ibuf->x; x_px++) {
@@ -2027,7 +2205,7 @@ void paint_2d_gradient_fill(
}
}
- imapaint_image_update(sima, ima, ibuf, false);
+ imapaint_image_update(sima, ima, ibuf, iuser, false);
ED_imapaint_clear_partial_redraw();
BKE_image_release_ibuf(ima, ibuf, NULL);
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index c57490041bc..6a67c469955 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -197,6 +197,7 @@ BLI_INLINE unsigned char f_to_char(const float val)
*/
typedef struct ProjPaintImage {
Image *ima;
+ ImageUser iuser;
ImBuf *ibuf;
ImagePaintPartialRedraw *partRedrawRect;
/** Only used to build undo tiles during painting. */
@@ -530,6 +531,18 @@ BLI_INLINE const MPoly *ps_tri_index_to_mpoly(const ProjPaintState *ps, int tri_
/* Finish projection painting structs */
+static int project_paint_face_paint_tile(Image *ima, const float *uv)
+{
+ if (ima == NULL || ima->source != IMA_SRC_TILED) {
+ return 0;
+ }
+
+ /* Currently, faces are assumed to belong to one tile, so checking the first loop is enough. */
+ int tx = (int)uv[0];
+ int ty = (int)uv[1];
+ return 1001 + 10 * ty + tx;
+}
+
static TexPaintSlot *project_paint_face_paint_slot(const ProjPaintState *ps, int tri_index)
{
const MPoly *mp = ps_tri_index_to_mpoly(ps, tri_index);
@@ -729,9 +742,17 @@ static bool project_paint_PickColor(const ProjPaintState *ps,
ima = project_paint_face_paint_image(ps, tri_index);
/** we must have got the imbuf before getting here. */
- ibuf = BKE_image_get_first_ibuf(ima);
- if (!ibuf) {
- return 0;
+ int tile_number = project_paint_face_paint_tile(ima, lt_tri_uv[0]);
+ ImageUser iuser;
+ BKE_imageuser_default(&iuser);
+ iuser.tile = tile_number;
+ ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
+ if (ibuf == NULL) {
+ iuser.tile = 0;
+ ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
+ if (ibuf == NULL) {
+ return 0;
+ }
}
if (interp) {
@@ -1154,6 +1175,8 @@ static bool check_seam(const ProjPaintState *ps,
const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt)};
Image *tpage = project_paint_face_paint_image(ps, tri_index);
Image *orig_tpage = project_paint_face_paint_image(ps, orig_face);
+ int tile = project_paint_face_paint_tile(tpage, lt_tri_uv[0]);
+ int orig_tile = project_paint_face_paint_tile(orig_tpage, orig_lt_tri_uv[0]);
BLI_assert(i1_fidx != -1);
@@ -1171,7 +1194,8 @@ static bool check_seam(const ProjPaintState *ps,
}
/* first test if they have the same image */
- if ((orig_tpage == tpage) && cmp_uv(orig_lt_tri_uv[orig_i1_fidx], lt_tri_uv[i1_fidx]) &&
+ if ((orig_tpage == tpage) && (orig_tile == tile) &&
+ cmp_uv(orig_lt_tri_uv[orig_i1_fidx], lt_tri_uv[i1_fidx]) &&
cmp_uv(orig_lt_tri_uv[orig_i2_fidx], lt_tri_uv[i2_fidx])) {
/* if faces don't have the same winding in uv space,
* they are on the same side so edge is boundary */
@@ -1817,6 +1841,7 @@ static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
pjIma->ima,
pjIma->ibuf,
tinf->tmpibuf,
+ pjIma->iuser.tile,
tx,
ty,
&pjIma->maskRect[tile_index],
@@ -1829,6 +1854,7 @@ static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
pjIma->ima,
pjIma->ibuf,
tinf->tmpibuf,
+ pjIma->iuser.tile,
tx,
ty,
NULL,
@@ -3486,6 +3512,7 @@ static void project_bucket_init(const ProjPaintState *ps,
ImBuf *ibuf = NULL;
Image *tpage_last = NULL, *tpage;
ImBuf *tmpibuf = NULL;
+ int tile_last = 0;
if (ps->image_tot == 1) {
/* Simple loop, no context switching */
@@ -3509,17 +3536,34 @@ static void project_bucket_init(const ProjPaintState *ps,
for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
tri_index = POINTER_AS_INT(node->link);
+ const MLoopTri *lt = &ps->mlooptri_eval[tri_index];
+ const float *lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt)};
+
/* Image context switching */
tpage = project_paint_face_paint_image(ps, tri_index);
- if (tpage_last != tpage) {
+ int tile = project_paint_face_paint_tile(tpage, lt_tri_uv[0]);
+ if (tpage_last != tpage || tile_last != tile) {
tpage_last = tpage;
+ tile_last = tile;
+ ibuf = NULL;
for (image_index = 0; image_index < ps->image_tot; image_index++) {
- if (ps->projImages[image_index].ima == tpage_last) {
- ibuf = ps->projImages[image_index].ibuf;
+ ProjPaintImage *projIma = &ps->projImages[image_index];
+ if ((projIma->ima == tpage) && (projIma->iuser.tile == tile)) {
+ ibuf = projIma->ibuf;
break;
}
}
+ if (ibuf == NULL) {
+ /* Failed to find the specific tile, fall back to the primary tile. */
+ for (image_index = 0; image_index < ps->image_tot; image_index++) {
+ ProjPaintImage *projIma = &ps->projImages[image_index];
+ if ((projIma->ima == tpage) && (projIma->iuser.tile == 0)) {
+ ibuf = projIma->ibuf;
+ break;
+ }
+ }
+ }
}
/* context switching done */
@@ -4232,22 +4276,36 @@ static bool project_paint_winclip(const ProjPaintState *ps, const ProjPaintFaceC
}
#endif // PROJ_DEBUG_WINCLIP
+typedef struct PrepareImageEntry {
+ struct PrepareImageEntry *next, *prev;
+ Image *ima;
+ int tile;
+} PrepareImageEntry;
+
static void project_paint_build_proj_ima(ProjPaintState *ps,
MemArena *arena,
- LinkNode *image_LinkList)
+ ListBase *used_images)
{
ProjPaintImage *projIma;
- LinkNode *node;
+ PrepareImageEntry *entry;
int i;
/* build an array of images we use */
projIma = ps->projImages = BLI_memarena_alloc(arena, sizeof(ProjPaintImage) * ps->image_tot);
- for (node = image_LinkList, i = 0; node; node = node->next, i++, projIma++) {
+ for (entry = used_images->first, i = 0; entry; entry = entry->next, i++, projIma++) {
+ memset(&projIma->iuser, 0, sizeof(ImageUser));
+ BKE_imageuser_default(&projIma->iuser);
+ projIma->iuser.tile = entry->tile;
int size;
- projIma->ima = node->link;
+ projIma->ima = entry->ima;
projIma->touch = 0;
- projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, NULL, NULL);
+ projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, &projIma->iuser, NULL);
+ if (projIma->ibuf == NULL) {
+ projIma->iuser.tile = 0;
+ projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, &projIma->iuser, NULL);
+ BLI_assert(projIma->ibuf != NULL);
+ }
size = sizeof(void **) * ED_IMAGE_UNDO_TILE_NUMBER(projIma->ibuf->x) *
ED_IMAGE_UNDO_TILE_NUMBER(projIma->ibuf->y);
projIma->partRedrawRect = BLI_memarena_alloc(
@@ -4270,15 +4328,18 @@ static void project_paint_prepare_all_faces(ProjPaintState *ps,
const bool is_multi_view)
{
/* Image Vars - keep track of images we have used */
- LinkNodePair image_LinkList = {NULL, NULL};
+ ListBase used_images = {NULL};
Image *tpage_last = NULL, *tpage;
TexPaintSlot *slot_last = NULL;
TexPaintSlot *slot = NULL;
+ int tile_last = -1, tile;
const MLoopTri *lt;
int image_index = -1, tri_index;
int prev_poly = -1;
+ BLI_assert(ps->image_tot == 0);
+
for (tri_index = 0, lt = ps->mlooptri_eval; tri_index < ps->totlooptri_eval; tri_index++, lt++) {
bool is_face_sel;
bool skip_tri = false;
@@ -4321,6 +4382,8 @@ static void project_paint_prepare_all_faces(ProjPaintState *ps,
ps->poly_to_loop_uv[lt->poly] = mloopuv_base;
+ tile = project_paint_face_paint_tile(tpage, mloopuv_base[lt->tri[0]].uv);
+
#ifndef PROJ_DEBUG_NOSEAMBLEED
project_paint_bleed_add_face_user(ps, arena, lt, tri_index);
#endif
@@ -4382,18 +4445,24 @@ static void project_paint_prepare_all_faces(ProjPaintState *ps,
}
}
- if (tpage_last != tpage) {
-
- image_index = BLI_linklist_index(image_LinkList.list, tpage);
+ if (tpage_last != tpage || tile_last != tile) {
+ image_index = 0;
+ for (PrepareImageEntry *e = used_images.first; e; e = e->next, image_index++) {
+ if (e->ima == tpage && e->tile == tile) {
+ break;
+ }
+ }
- if (image_index == -1 && BKE_image_has_ibuf(tpage, NULL)) {
- /* MemArena doesn't have an append func */
- BLI_linklist_append(&image_LinkList, tpage);
- image_index = ps->image_tot;
+ if (image_index == ps->image_tot) {
+ PrepareImageEntry *e = MEM_callocN(sizeof(PrepareImageEntry), "PrepareImageEntry");
+ e->ima = tpage;
+ e->tile = tile;
+ BLI_addtail(&used_images, e);
ps->image_tot++;
}
tpage_last = tpage;
+ tile_last = tile;
}
if (image_index != -1) {
@@ -4406,11 +4475,11 @@ static void project_paint_prepare_all_faces(ProjPaintState *ps,
/* build an array of images we use*/
if (ps->is_shared_user == false) {
- project_paint_build_proj_ima(ps, arena, image_LinkList.list);
+ project_paint_build_proj_ima(ps, arena, &used_images);
}
/* we have built the array, discard the linked list */
- BLI_linklist_free(image_LinkList.list, NULL);
+ BLI_freelistN(&used_images);
}
/* run once per stroke before projection painting */
@@ -4675,7 +4744,7 @@ static bool project_image_refresh_tagged(ProjPaintState *ps)
pr = &(projIma->partRedrawRect[i]);
if (pr->x2 != -1) { /* TODO - use 'enabled' ? */
set_imapaintpartial(pr);
- imapaint_image_update(NULL, projIma->ima, projIma->ibuf, true);
+ imapaint_image_update(NULL, projIma->ima, projIma->ibuf, &projIma->iuser, true);
redraw = 1;
}
@@ -6441,7 +6510,8 @@ static Image *proj_paint_image_create(wmOperator *op, Main *bmain, bool is_data)
gen_type,
color,
false,
- is_data);
+ is_data,
+ false); /* TODO(lukas): Add option */
return ima;
}
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 84665728e17..53beb981522 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -186,6 +186,7 @@ bool image_texture_paint_poll(struct bContext *C);
void imapaint_image_update(struct SpaceImage *sima,
struct Image *image,
struct ImBuf *ibuf,
+ struct ImageUser *iuser,
short texpaint);
struct ImagePaintPartialRedraw *get_imapaintpartial(void);
void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr);
@@ -206,6 +207,7 @@ void paint_2d_bucket_fill(const struct bContext *C,
const float color[3],
struct Brush *br,
const float mouse_init[2],
+ const float mouse_final[2],
void *ps);
void paint_2d_gradient_fill(const struct bContext *C,
struct Brush *br,