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>2018-03-23 14:05:55 +0300
committerCampbell Barton <ideasman42@gmail.com>2018-03-23 14:05:55 +0300
commit8eb8aa49397fb038ffa98dbe5dc4aed86e7b3e94 (patch)
treef5742a0f4414a99bd6738aae9cf4dc21b307fbfc /source/blender/editors/sculpt_paint
parentda00a50f7f48bfd95924705e69babea41f9d7b2b (diff)
parent7cc2b27099b7435cc1a29a48ae0e4c8335d811f3 (diff)
Merge branch 'master' into blender2.8
Diffstat (limited to 'source/blender/editors/sculpt_paint')
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt1
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c352
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c3
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_undo.c396
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h41
5 files changed, 435 insertions, 358 deletions
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index b3e125baae3..1a709382581 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -47,6 +47,7 @@ set(SRC
paint_image.c
paint_image_2d.c
paint_image_proj.c
+ paint_image_undo.c
paint_mask.c
paint_ops.c
paint_stroke.c
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 969bf8f37b1..b7cbdfecfe8 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -39,7 +39,6 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BLI_threads.h"
#include "BLT_translation.h"
@@ -54,7 +53,6 @@
#include "BKE_context.h"
#include "BKE_DerivedMesh.h"
#include "BKE_brush.h"
-#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_node.h"
@@ -87,43 +85,10 @@
#include "paint_intern.h"
-typedef struct UndoImageTile {
- struct UndoImageTile *next, *prev;
-
- char idname[MAX_ID_NAME]; /* name instead of pointer*/
- char ibufname[IMB_FILENAME_SIZE];
-
- union {
- float *fp;
- unsigned int *uint;
- void *pt;
- } rect;
-
- unsigned short *mask;
-
- int x, y;
-
- Image *ima;
- short source, use_float;
- char gen_type;
- bool valid;
-} UndoImageTile;
-
/* this is a static resource for non-globality,
* Maybe it should be exposed as part of the
* paint operation, but for now just give a public interface */
static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0};
-static SpinLock undolock;
-
-void image_undo_init_locks(void)
-{
- BLI_spin_init(&undolock);
-}
-
-void image_undo_end_locks(void)
-{
- BLI_spin_end(&undolock);
-}
ImagePaintPartialRedraw *get_imapaintpartial(void)
{
@@ -135,296 +100,6 @@ void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr)
imapaintpartial = *ippr;
}
-/* UNDO */
-typedef enum {
- COPY = 0,
- RESTORE = 1,
- RESTORE_COPY = 2
-} CopyMode;
-
-static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, CopyMode mode)
-{
- if (mode == COPY) {
- /* copy or swap contents of tile->rect and region in ibuf->rect */
- IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE,
- tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
-
- if (ibuf->rect_float) {
- SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
- }
- else {
- SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
- }
- }
- else {
- if (mode == RESTORE_COPY) {
- IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE,
- tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
- }
- /* swap to the tmpbuf for easy copying */
- if (ibuf->rect_float) {
- SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
- }
- else {
- SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
- }
-
- IMB_rectcpy(ibuf, tmpibuf, tile->x * IMAPAINT_TILE_SIZE,
- tile->y * IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
-
- if (mode == RESTORE) {
- if (ibuf->rect_float) {
- SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
- }
- else {
- SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
- }
- }
- }
-}
-
-void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate)
-{
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
- UndoImageTile *tile;
- short use_float = ibuf->rect_float ? 1 : 0;
-
- for (tile = lb->first; tile; tile = tile->next) {
- if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type && ima->source == tile->source) {
- if (tile->use_float == use_float) {
- if (STREQ(tile->idname, ima->id.name) && STREQ(tile->ibufname, ibuf->name)) {
- if (mask) {
- /* allocate mask if requested */
- if (!tile->mask) {
- tile->mask = MEM_callocN(sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE,
- "UndoImageTile.mask");
- }
-
- *mask = tile->mask;
- }
- if (validate)
- tile->valid = true;
-
- return tile->rect.pt;
- }
- }
- }
- }
-
- return NULL;
-}
-
-void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **mask, bool **valid, bool proj, bool find_prev)
-{
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
- UndoImageTile *tile;
- int allocsize;
- short use_float = ibuf->rect_float ? 1 : 0;
- void *data;
-
- /* check if tile is already pushed */
-
- /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
- if (find_prev) {
- data = image_undo_find_tile(ima, ibuf, x_tile, y_tile, mask, true);
- if (data)
- return data;
- }
-
- if (*tmpibuf == NULL)
- *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
-
- tile = MEM_callocN(sizeof(UndoImageTile), "UndoImageTile");
- BLI_strncpy(tile->idname, ima->id.name, sizeof(tile->idname));
- tile->x = x_tile;
- tile->y = y_tile;
-
- /* add mask explicitly here */
- if (mask)
- *mask = tile->mask = MEM_callocN(sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE,
- "UndoImageTile.mask");
-
- allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
- allocsize *= (ibuf->rect_float) ? sizeof(float) : sizeof(char);
- tile->rect.pt = MEM_mapallocN(allocsize, "UndeImageTile.rect");
-
- BLI_strncpy(tile->ibufname, ibuf->name, sizeof(tile->ibufname));
-
- tile->gen_type = ima->gen_type;
- tile->source = ima->source;
- tile->use_float = use_float;
- tile->valid = true;
- tile->ima = ima;
-
- if (valid)
- *valid = &tile->valid;
-
- undo_copy_tile(tile, *tmpibuf, ibuf, COPY);
-
- if (proj)
- BLI_spin_lock(&undolock);
-
- undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize);
- BLI_addtail(lb, tile);
-
- if (proj)
- BLI_spin_unlock(&undolock);
-
- return tile->rect.pt;
-}
-
-void image_undo_remove_masks(void)
-{
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
- UndoImageTile *tile;
-
- for (tile = lb->first; tile; tile = tile->next) {
- if (tile->mask) {
- MEM_freeN(tile->mask);
- tile->mask = NULL;
- }
- }
-}
-
-static void image_undo_restore_runtime(ListBase *lb)
-{
- ImBuf *ibuf, *tmpibuf;
- UndoImageTile *tile;
-
- tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32,
- IB_rectfloat | IB_rect);
-
- for (tile = lb->first; tile; tile = tile->next) {
- Image *ima = tile->ima;
- ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
-
- undo_copy_tile(tile, tmpibuf, ibuf, RESTORE);
-
- GPU_free_image(ima); /* force OpenGL reload (maybe partial update will operate better?) */
- if (ibuf->rect_float)
- ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
- if (ibuf->mipmap[0])
- ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */
- ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
- }
-
- IMB_freeImBuf(tmpibuf);
-}
-
-void ED_image_undo_restore(bContext *C, ListBase *lb)
-{
- Main *bmain = CTX_data_main(C);
- Image *ima = NULL;
- ImBuf *ibuf, *tmpibuf;
- UndoImageTile *tile;
-
- tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32,
- IB_rectfloat | IB_rect);
-
- for (tile = lb->first; tile; tile = tile->next) {
- short use_float;
-
- /* find image based on name, pointer becomes invalid with global undo */
- if (ima && STREQ(tile->idname, ima->id.name)) {
- /* ima is valid */
- }
- else {
- ima = BLI_findstring(&bmain->image, tile->idname, offsetof(ID, name));
- }
-
- ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
-
- if (ima && ibuf && !STREQ(tile->ibufname, ibuf->name)) {
- /* current ImBuf filename was changed, probably current frame
- * was changed when painting on image sequence, rather than storing
- * full image user (which isn't so obvious, btw) try to find ImBuf with
- * matched file name in list of already loaded images */
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
-
- ibuf = BKE_image_get_ibuf_with_name(ima, tile->ibufname);
- }
-
- if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
-
- if (ima->gen_type != tile->gen_type || ima->source != tile->source) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
-
- use_float = ibuf->rect_float ? 1 : 0;
-
- if (use_float != tile->use_float) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
-
- undo_copy_tile(tile, tmpibuf, ibuf, RESTORE_COPY);
-
- GPU_free_image(ima); /* force OpenGL reload */
- if (ibuf->rect_float)
- ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
- if (ibuf->mipmap[0])
- ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */
- ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
-
- DEG_id_tag_update(&ima->id, 0);
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
- }
-
- IMB_freeImBuf(tmpibuf);
-}
-
-void ED_image_undo_free(ListBase *lb)
-{
- UndoImageTile *tile;
-
- for (tile = lb->first; tile; tile = tile->next)
- MEM_freeN(tile->rect.pt);
-}
-
-static void image_undo_end(void)
-{
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
- UndoImageTile *tile;
- int deallocsize = 0;
- int allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
-
- /* first dispose of invalid tiles (may happen due to drag dot for instance) */
- for (tile = lb->first; tile;) {
- if (!tile->valid) {
- UndoImageTile *tmp_tile = tile->next;
- deallocsize += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char));
- MEM_freeN(tile->rect.pt);
- BLI_freelinkN(lb, tile);
- tile = tmp_tile;
- }
- else {
- tile = tile->next;
- }
- }
-
- /* don't forget to remove the size of deallocated tiles */
- undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, -deallocsize);
-
- ED_undo_paint_push_end(UNDO_PAINT_IMAGE);
-}
-
-static void image_undo_invalidate(void)
-{
- UndoImageTile *tile;
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
-
- for (tile = lb->first; tile; tile = tile->next)
- tile->valid = false;
-}
-
/* Imagepaint Partial Redraw & Dirty Region */
void ED_imapaint_clear_partial_redraw(void)
@@ -454,7 +129,7 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int
if (w == 0 || h == 0)
return;
-
+
if (!imapaintpartial.enabled) {
imapaintpartial.x1 = x;
imapaintpartial.y1 = y;
@@ -476,7 +151,7 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int
image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old);
ibuf->userflags |= IB_BITMAPDIRTY;
-
+
if (tmpibuf)
IMB_freeImBuf(tmpibuf);
}
@@ -658,8 +333,9 @@ bool paint_use_opacity_masking(Brush *brush)
false : true;
}
-void paint_brush_color_get(struct Scene *scene, struct Brush *br, bool color_correction, bool invert, float distance,
- float pressure, float color[3], struct ColorManagedDisplay *display)
+void paint_brush_color_get(
+ struct Scene *scene, struct Brush *br, bool color_correction, bool invert, float distance,
+ float pressure, float color[3], struct ColorManagedDisplay *display)
{
if (invert)
copy_v3_v3(color, BKE_brush_secondary_color_get(scene, br));
@@ -794,20 +470,11 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const flo
}
settings->imapaint.flag |= IMAGEPAINT_DRAWING;
- ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name,
- ED_image_undo_restore, ED_image_undo_free, NULL);
+ ED_image_undo_push_begin(op->type->name);
return pop;
}
-/* restore painting image to previous state. Used for anchored and drag-dot style brushes*/
-static void paint_stroke_restore(void)
-{
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
- image_undo_restore_runtime(lb);
- image_undo_invalidate();
-}
-
static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
{
PaintOperation *pop = paint_stroke_mode_data(stroke);
@@ -844,7 +511,7 @@ static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, Po
BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * alphafac));
if ((brush->flag & BRUSH_DRAG_DOT) || (brush->flag & BRUSH_ANCHORED)) {
- paint_stroke_restore();
+ ED_image_undo_restore();
}
if (pop->mode == PAINT_MODE_3D_PROJECT) {
@@ -921,7 +588,7 @@ static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke)
WM_paint_cursor_end(CTX_wm_manager(C), pop->cursor);
}
- image_undo_end();
+ ED_image_undo_push_end();
/* duplicate warning, see texpaint_init */
#if 0
@@ -1544,8 +1211,7 @@ void ED_imapaint_bucket_fill(struct bContext *C, float color[3], wmOperator *op)
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = sima->image;
- ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name,
- ED_image_undo_restore, ED_image_undo_free, NULL);
+ ED_image_undo_push_begin(op->type->name);
paint_2d_bucket_fill(C, color, NULL, NULL, NULL);
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 21612339eb5..58c03330256 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -5396,8 +5396,7 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
scene->toolsettings->imapaint.flag |= IMAGEPAINT_DRAWING;
- ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name,
- ED_image_undo_restore, ED_image_undo_free, NULL);
+ ED_image_undo_push_begin(op->type->name);
/* allocate and initialize spatial data structures */
project_paint_begin(C, &ps, false, 0);
diff --git a/source/blender/editors/sculpt_paint/paint_image_undo.c b/source/blender/editors/sculpt_paint/paint_image_undo.c
new file mode 100644
index 00000000000..d080c324d6c
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/paint_image_undo.c
@@ -0,0 +1,396 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/sculpt_paint/paint_image_undo.c
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_threads.h"
+
+#include "DNA_image_types.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "BKE_context.h"
+#include "BKE_image.h"
+#include "BKE_main.h"
+
+#include "DEG_depsgraph.h"
+
+#include "ED_paint.h"
+
+#include "GPU_draw.h"
+
+#include "paint_intern.h"
+
+typedef struct UndoImageTile {
+ struct UndoImageTile *next, *prev;
+
+ char idname[MAX_ID_NAME]; /* name instead of pointer*/
+ char ibufname[IMB_FILENAME_SIZE];
+
+ union {
+ float *fp;
+ unsigned int *uint;
+ void *pt;
+ } rect;
+
+ unsigned short *mask;
+
+ int x, y;
+
+ Image *ima;
+ short source, use_float;
+ char gen_type;
+ bool valid;
+} UndoImageTile;
+
+/* this is a static resource for non-globality,
+ * Maybe it should be exposed as part of the
+ * paint operation, but for now just give a public interface */
+static SpinLock undolock;
+
+void image_undo_init_locks(void)
+{
+ BLI_spin_init(&undolock);
+}
+
+void image_undo_end_locks(void)
+{
+ BLI_spin_end(&undolock);
+}
+
+/* UNDO */
+typedef enum {
+ COPY = 0,
+ RESTORE = 1,
+ RESTORE_COPY = 2
+} CopyMode;
+
+static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, CopyMode mode)
+{
+ if (mode == COPY) {
+ /* copy or swap contents of tile->rect and region in ibuf->rect */
+ IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE,
+ tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
+
+ if (ibuf->rect_float) {
+ SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
+ }
+ else {
+ SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
+ }
+ }
+ else {
+ if (mode == RESTORE_COPY) {
+ IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE,
+ tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
+ }
+ /* swap to the tmpbuf for easy copying */
+ if (ibuf->rect_float) {
+ SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
+ }
+ else {
+ SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
+ }
+
+ IMB_rectcpy(ibuf, tmpibuf, tile->x * IMAPAINT_TILE_SIZE,
+ tile->y * IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
+
+ if (mode == RESTORE) {
+ if (ibuf->rect_float) {
+ SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
+ }
+ else {
+ SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
+ }
+ }
+ }
+}
+
+void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate)
+{
+ ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+ UndoImageTile *tile;
+ short use_float = ibuf->rect_float ? 1 : 0;
+
+ for (tile = lb->first; tile; tile = tile->next) {
+ if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type && ima->source == tile->source) {
+ if (tile->use_float == use_float) {
+ if (STREQ(tile->idname, ima->id.name) && STREQ(tile->ibufname, ibuf->name)) {
+ if (mask) {
+ /* allocate mask if requested */
+ if (!tile->mask) {
+ tile->mask = MEM_callocN(sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE,
+ "UndoImageTile.mask");
+ }
+
+ *mask = tile->mask;
+ }
+ if (validate) {
+ tile->valid = true;
+ }
+ return tile->rect.pt;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void *image_undo_push_tile(
+ Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile,
+ unsigned short **mask, bool **valid, bool proj, bool find_prev)
+{
+ ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+ UndoImageTile *tile;
+ int allocsize;
+ short use_float = ibuf->rect_float ? 1 : 0;
+ void *data;
+
+ /* check if tile is already pushed */
+
+ /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
+ if (find_prev) {
+ data = image_undo_find_tile(ima, ibuf, x_tile, y_tile, mask, true);
+ if (data) {
+ return data;
+ }
+ }
+
+ if (*tmpibuf == NULL) {
+ *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
+ }
+
+ tile = MEM_callocN(sizeof(UndoImageTile), "UndoImageTile");
+ BLI_strncpy(tile->idname, ima->id.name, sizeof(tile->idname));
+ tile->x = x_tile;
+ tile->y = y_tile;
+
+ /* add mask explicitly here */
+ if (mask) {
+ *mask = tile->mask = MEM_callocN(sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE,
+ "UndoImageTile.mask");
+ }
+ allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
+ allocsize *= (ibuf->rect_float) ? sizeof(float) : sizeof(char);
+ tile->rect.pt = MEM_mapallocN(allocsize, "UndeImageTile.rect");
+
+ BLI_strncpy(tile->ibufname, ibuf->name, sizeof(tile->ibufname));
+
+ tile->gen_type = ima->gen_type;
+ tile->source = ima->source;
+ tile->use_float = use_float;
+ tile->valid = true;
+ tile->ima = ima;
+
+ if (valid) {
+ *valid = &tile->valid;
+ }
+ undo_copy_tile(tile, *tmpibuf, ibuf, COPY);
+
+ if (proj) {
+ BLI_spin_lock(&undolock);
+ }
+ undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize);
+ BLI_addtail(lb, tile);
+
+ if (proj) {
+ BLI_spin_unlock(&undolock);
+ }
+ return tile->rect.pt;
+}
+
+void image_undo_remove_masks(void)
+{
+ ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+ UndoImageTile *tile;
+
+ for (tile = lb->first; tile; tile = tile->next) {
+ if (tile->mask) {
+ MEM_freeN(tile->mask);
+ tile->mask = NULL;
+ }
+ }
+}
+
+static void image_undo_restore_runtime(ListBase *lb)
+{
+ ImBuf *ibuf, *tmpibuf;
+ UndoImageTile *tile;
+
+ tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32,
+ IB_rectfloat | IB_rect);
+
+ for (tile = lb->first; tile; tile = tile->next) {
+ Image *ima = tile->ima;
+ ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+
+ undo_copy_tile(tile, tmpibuf, ibuf, RESTORE);
+
+ GPU_free_image(ima); /* force OpenGL reload (maybe partial update will operate better?) */
+ if (ibuf->rect_float) {
+ ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
+ }
+ if (ibuf->mipmap[0]) {
+ ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */
+ }
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ }
+
+ IMB_freeImBuf(tmpibuf);
+}
+
+static void image_undo_restore_list(bContext *C, ListBase *lb)
+{
+ Main *bmain = CTX_data_main(C);
+ Image *ima = NULL;
+ ImBuf *ibuf, *tmpibuf;
+ UndoImageTile *tile;
+
+ tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32,
+ IB_rectfloat | IB_rect);
+
+ for (tile = lb->first; tile; tile = tile->next) {
+ short use_float;
+
+ /* find image based on name, pointer becomes invalid with global undo */
+ if (ima && STREQ(tile->idname, ima->id.name)) {
+ /* ima is valid */
+ }
+ else {
+ ima = BLI_findstring(&bmain->image, tile->idname, offsetof(ID, name));
+ }
+
+ ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+
+ if (ima && ibuf && !STREQ(tile->ibufname, ibuf->name)) {
+ /* current ImBuf filename was changed, probably current frame
+ * was changed when painting on image sequence, rather than storing
+ * full image user (which isn't so obvious, btw) try to find ImBuf with
+ * matched file name in list of already loaded images */
+
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+
+ ibuf = BKE_image_get_ibuf_with_name(ima, tile->ibufname);
+ }
+
+ if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) {
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ continue;
+ }
+
+ if (ima->gen_type != tile->gen_type || ima->source != tile->source) {
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ continue;
+ }
+
+ use_float = ibuf->rect_float ? 1 : 0;
+
+ if (use_float != tile->use_float) {
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ continue;
+ }
+
+ undo_copy_tile(tile, tmpibuf, ibuf, RESTORE_COPY);
+
+ GPU_free_image(ima); /* force OpenGL reload */
+ if (ibuf->rect_float) {
+ ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
+ }
+ if (ibuf->mipmap[0]) {
+ ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */
+ }
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+
+ DEG_id_tag_update(&ima->id, 0);
+
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ }
+
+ IMB_freeImBuf(tmpibuf);
+}
+
+static void image_undo_free_list(ListBase *lb)
+{
+ UndoImageTile *tile;
+
+ for (tile = lb->first; tile; tile = tile->next) {
+ MEM_freeN(tile->rect.pt);
+ }
+}
+
+void ED_image_undo_push_begin(const char *name)
+{
+ ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, name, image_undo_restore_list, image_undo_free_list, NULL);
+}
+
+void ED_image_undo_push_end(void)
+{
+ ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+ UndoImageTile *tile;
+ int deallocsize = 0;
+ int allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
+
+ /* first dispose of invalid tiles (may happen due to drag dot for instance) */
+ for (tile = lb->first; tile;) {
+ if (!tile->valid) {
+ UndoImageTile *tmp_tile = tile->next;
+ deallocsize += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char));
+ MEM_freeN(tile->rect.pt);
+ BLI_freelinkN(lb, tile);
+ tile = tmp_tile;
+ }
+ else {
+ tile = tile->next;
+ }
+ }
+
+ /* don't forget to remove the size of deallocated tiles */
+ undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, -deallocsize);
+
+ ED_undo_paint_push_end(UNDO_PAINT_IMAGE);
+}
+
+static void image_undo_invalidate(void)
+{
+ UndoImageTile *tile;
+ ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+
+ for (tile = lb->first; tile; tile = tile->next) {
+ tile->valid = false;
+ }
+}
+
+/* restore painting image to previous state. Used for anchored and drag-dot style brushes*/
+void ED_image_undo_restore(void)
+{
+ ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+ image_undo_restore_runtime(lb);
+ image_undo_invalidate();
+}
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 28d9dfe13b0..089a12dbd45 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -176,12 +176,6 @@ typedef struct ImagePaintPartialRedraw {
#define IMAPAINT_TILE_NUMBER(size) (((size) + IMAPAINT_TILE_SIZE - 1) >> IMAPAINT_TILE_BITS)
int image_texture_paint_poll(struct bContext *C);
-void *image_undo_find_tile(struct Image *ima, struct ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate);
-void *image_undo_push_tile(struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **, bool **valid, bool proj, bool find_prev);
-void image_undo_remove_masks(void);
-void image_undo_init_locks(void);
-void image_undo_end_locks(void);
-
void imapaint_image_update(struct SpaceImage *sima, struct Image *image, struct ImBuf *ibuf, short texpaint);
struct ImagePaintPartialRedraw *get_imapaintpartial(void);
void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr);
@@ -190,15 +184,25 @@ int get_imapaint_zoom(struct bContext *C, float *zoomx, float *zoomy);
void *paint_2d_new_stroke(struct bContext *, struct wmOperator *, int mode);
void paint_2d_redraw(const struct bContext *C, void *ps, bool final);
void paint_2d_stroke_done(void *ps);
-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_bucket_fill(const struct bContext *C, const float color[3], struct Brush *br, const float mouse_init[2], void *ps);
-void paint_2d_gradient_fill(const struct bContext *C, struct Brush *br, const float mouse_init[2], const float mouse_final[2], void *ps);
-void *paint_proj_new_stroke(struct bContext *C, struct Object *ob, const float mouse[2], int mode);
-void paint_proj_stroke(const struct bContext *C, void *ps, const float prevmval_i[2], const float mval_i[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);
+void paint_2d_bucket_fill(
+ const struct bContext *C, const float color[3], struct Brush *br, const float mouse_init[2], void *ps);
+void paint_2d_gradient_fill(
+ const struct bContext *C, struct Brush *br, const float mouse_init[2], const float mouse_final[2], void *ps);
+void *paint_proj_new_stroke(
+ struct bContext *C, struct Object *ob, const float mouse[2], int mode);
+void paint_proj_stroke(
+ const struct bContext *C, void *ps, const float prevmval_i[2], const float mval_i[2],
+ const bool eraser, float pressure, float distance, float size);
void paint_proj_redraw(const struct bContext *C, void *pps, bool final);
void paint_proj_stroke_done(void *ps);
-void paint_brush_color_get(struct Scene *scene, struct Brush *br, bool color_correction, bool invert, float distance, float pressure, float color[3], struct ColorManagedDisplay *display);
+void paint_brush_color_get(
+ struct Scene *scene, struct Brush *br,
+ bool color_correction, bool invert, float distance, float pressure, float color[3],
+ struct ColorManagedDisplay *display);
bool paint_use_opacity_masking(struct Brush *brush);
void paint_brush_init_tex(struct Brush *brush);
void paint_brush_exit_tex(struct Brush *brush);
@@ -214,7 +218,18 @@ void PAINT_OT_delete_texture_paint_slot(struct wmOperatorType *ot);
void PAINT_OT_image_paint(struct wmOperatorType *ot);
void PAINT_OT_add_simple_uvs(struct wmOperatorType *ot);
-/* uv sculpting */
+/* paint_image_undo.c */
+void *image_undo_find_tile(
+ struct Image *ima, struct ImBuf *ibuf, int x_tile, int y_tile,
+ unsigned short **mask, bool validate);
+void *image_undo_push_tile(
+ struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile,
+ unsigned short **, bool **valid, bool proj, bool find_prev);
+void image_undo_remove_masks(void);
+void image_undo_init_locks(void);
+void image_undo_end_locks(void);
+
+/* sculpt_uv.c */
int uv_sculpt_poll(struct bContext *C);
int uv_sculpt_keymap_poll(struct bContext *C);