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-19 16:17:59 +0300
committerCampbell Barton <ideasman42@gmail.com>2018-03-31 21:40:37 +0300
commit651b8fb14eb6ee5cbfa98bffe80a966a0753b14e (patch)
tree2281978509d82a25fb5fbf586f34335e3606442d /source/blender/editors/sculpt_paint
parent91d0825b5556150c017dad767f7971bb6a731aec (diff)
Undo: unified undo system w/ linear history
- Use a single undo history for all operations. - UndoType's are registered and poll the context to check if they should be used when performing an undo push. - Mode switching is used to ensure the state is correct before undo data is restored. - Some undo types accumulate changes (image & text editing) others store the state multiple times (with de-duplication). This is supported by checking UndoStack.mode `ACCUMULATE` / `STORE`. - Each undo step stores ID datablocks they use with utilities to help manage restoring correct ID's. Needed since global undo is now mixed with other modes undo. - Currently performs each undo step when going up/down history Previously this wasn't done, making history fail in some cases. This can be optimized to skip some combinations of undo steps. grease-pencil is an exception which has not been updated since it integrates undo into the draw-session. See D3113
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_curve.c22
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve_undo.c162
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c15
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c5
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_undo.c161
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h10
-rw-r--r--source/blender/editors/sculpt_paint/paint_undo.c410
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c171
11 files changed, 418 insertions, 547 deletions
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index adead9a8b9e..9527dc4fe83 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -51,7 +51,6 @@ set(SRC
paint_mask.c
paint_ops.c
paint_stroke.c
- paint_undo.c
paint_utils.c
paint_vertex.c
paint_vertex_color_ops.c
diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c
index 8d9812f41d9..120514762f4 100644
--- a/source/blender/editors/sculpt_paint/paint_curve.c
+++ b/source/blender/editors/sculpt_paint/paint_curve.c
@@ -40,6 +40,7 @@
#include "BKE_paint.h"
#include "ED_view3d.h"
+#include "ED_paint.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -203,7 +204,7 @@ static void paintcurve_point_add(bContext *C, wmOperator *op, const int loc[2])
br->paint_curve = pc = BKE_paint_curve_add(bmain, "PaintCurve");
}
- ED_paintcurve_undo_push(C, op, pc);
+ ED_paintcurve_undo_push_begin(op->type->name);
pcp = MEM_mallocN((pc->tot_points + 1) * sizeof(PaintCurvePoint), "PaintCurvePoint");
add_index = pc->add_index;
@@ -241,6 +242,8 @@ static void paintcurve_point_add(bContext *C, wmOperator *op, const int loc[2])
pcp[add_index].bez.h1 = HD_ALIGN;
}
+ ED_paintcurve_undo_push_end();
+
WM_paint_cursor_tag_redraw(window, ar);
}
@@ -302,7 +305,7 @@ static int paintcurve_delete_point_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- ED_paintcurve_undo_push(C, op, pc);
+ ED_paintcurve_undo_push_begin(op->type->name);
#define DELETE_TAG 2
@@ -342,6 +345,8 @@ static int paintcurve_delete_point_exec(bContext *C, wmOperator *op)
#undef DELETE_TAG
+ ED_paintcurve_undo_push_end();
+
WM_paint_cursor_tag_redraw(window, ar);
return OPERATOR_FINISHED;
@@ -379,7 +384,7 @@ static bool paintcurve_point_select(bContext *C, wmOperator *op, const int loc[2
if (!pc)
return false;
- ED_paintcurve_undo_push(C, op, pc);
+ ED_paintcurve_undo_push_begin(op->type->name);
if (toggle) {
PaintCurvePoint *pcp;
@@ -444,10 +449,14 @@ static bool paintcurve_point_select(bContext *C, wmOperator *op, const int loc[2
}
}
- if (!pcp)
+ if (!pcp) {
+ ED_paintcurve_undo_push_end();
return false;
+ }
}
+ ED_paintcurve_undo_push_end();
+
WM_paint_cursor_tag_redraw(window, ar);
return true;
@@ -562,9 +571,6 @@ static int paintcurve_slide_invoke(bContext *C, wmOperator *op, const wmEvent *e
psd->align = align;
op->customdata = psd;
- if (do_select)
- ED_paintcurve_undo_push(C, op, pc);
-
/* first, clear all selection from points */
for (i = 0; i < pc->tot_points; i++)
pc->points[i].bez.f1 = pc->points[i].bez.f3 = pc->points[i].bez.f2 = 0;
@@ -587,6 +593,8 @@ static int paintcurve_slide_modal(bContext *C, wmOperator *op, const wmEvent *ev
if (event->type == psd->event && event->val == KM_RELEASE) {
MEM_freeN(psd);
+ ED_paintcurve_undo_push_begin(op->type->name);
+ ED_paintcurve_undo_push_end();
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/sculpt_paint/paint_curve_undo.c b/source/blender/editors/sculpt_paint/paint_curve_undo.c
index 70f92999864..d5b7496fa3e 100644
--- a/source/blender/editors/sculpt_paint/paint_curve_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_curve_undo.c
@@ -30,9 +30,13 @@
#include "DNA_space_types.h"
#include "BLI_string.h"
+#include "BLI_array_utils.h"
#include "BKE_context.h"
#include "BKE_paint.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_undo_system.h"
#include "ED_paint.h"
@@ -41,89 +45,125 @@
#include "paint_intern.h"
-typedef struct UndoCurve {
- struct UndoImageTile *next, *prev;
+/* -------------------------------------------------------------------- */
+/** \name Undo Conversion
+ * \{ */
+typedef struct UndoCurve {
PaintCurvePoint *points; /* points of curve */
int tot_points;
- int active_point;
-
- char idname[MAX_ID_NAME]; /* name instead of pointer*/
+ int add_index;
} UndoCurve;
-static void paintcurve_undo_restore(bContext *C, ListBase *lb)
+static void undocurve_from_paintcurve(UndoCurve *uc, const PaintCurve *pc)
{
- Paint *p = BKE_paint_get_active_from_context(C);
- UndoCurve *uc;
- PaintCurve *pc = NULL;
+ BLI_assert(BLI_array_is_zeroed(uc, 1));
+ uc->points = MEM_dupallocN(pc->points);
+ uc->tot_points = pc->tot_points;
+ uc->add_index = pc->add_index;
+}
- if (p->brush) {
- pc = p->brush->paint_curve;
- }
+static void undocurve_to_paintcurve(const UndoCurve *uc, PaintCurve *pc)
+{
+ MEM_SAFE_FREE(pc->points);
+ pc->points = MEM_dupallocN(uc->points);
+ pc->tot_points = uc->tot_points;
+ pc->add_index = uc->add_index;
+}
- if (!pc) {
- return;
- }
+static void undocurve_free_data(UndoCurve *uc)
+{
+ MEM_SAFE_FREE(uc->points);
+}
- uc = (UndoCurve *)lb->first;
+/** \} */
- if (STREQLEN(uc->idname, pc->id.name, BLI_strnlen(uc->idname, sizeof(uc->idname)))) {
- SWAP(PaintCurvePoint *, pc->points, uc->points);
- SWAP(int, pc->tot_points, uc->tot_points);
- SWAP(int, pc->add_index, uc->active_point);
- }
-}
+/* -------------------------------------------------------------------- */
+/** \name Implements ED Undo System
+ * \{ */
-static void paintcurve_undo_delete(ListBase *lb)
+typedef struct PaintCurveUndoStep {
+ UndoStep step;
+ PaintCurve *pc;
+ UndoCurve data;
+} PaintCurveUndoStep;
+
+static bool paintcurve_undosys_poll(bContext *C)
{
- UndoCurve *uc;
- uc = (UndoCurve *)lb->first;
+ Paint *p = BKE_paint_get_active_from_context(C);
+ return (p->brush && p->brush->paint_curve);
+}
- if (uc->points)
- MEM_freeN(uc->points);
- uc->points = NULL;
+static void paintcurve_undosys_step_encode_init(struct bContext *C, UndoStep *us_p)
+{
+ /* XXX, use to set the undo type only. */
+ UNUSED_VARS(C, us_p);
}
-/**
- * \note This is called before executing steps (not after).
- */
-void ED_paintcurve_undo_push(bContext *C, wmOperator *op, PaintCurve *pc)
+static bool paintcurve_undosys_step_encode(struct bContext *C, UndoStep *us_p)
{
- ePaintMode mode = BKE_paintmode_get_active_from_context(C);
- ListBase *lb = NULL;
- int undo_stack_id;
- UndoCurve *uc;
-
- switch (mode) {
- case ePaintTexture2D:
- case ePaintTextureProjective:
- undo_stack_id = UNDO_PAINT_IMAGE;
- break;
-
- case ePaintSculpt:
- undo_stack_id = UNDO_PAINT_MESH;
- break;
-
- default:
- /* do nothing, undo is handled by global */
- return;
+ Paint *p = BKE_paint_get_active_from_context(C);
+ PaintCurve *pc = p ? (p->brush ? p->brush->paint_curve : NULL) : NULL;
+ if (pc == NULL) {
+ return false;
}
+ PaintCurveUndoStep *us = (PaintCurveUndoStep *)us_p;
+ BLI_assert(us->step.data_size == 0);
- ED_undo_paint_push_begin(undo_stack_id, op->type->name,
- paintcurve_undo_restore, paintcurve_undo_delete, NULL);
- lb = undo_paint_push_get_list(undo_stack_id);
+ us->pc = pc;
+ undocurve_from_paintcurve(&us->data, pc);
- uc = MEM_callocN(sizeof(*uc), "Undo_curve");
+ return true;
+}
- lb->first = uc;
+static void paintcurve_undosys_step_decode(struct bContext *UNUSED(C), UndoStep *us_p, int UNUSED(dir))
+{
+ PaintCurveUndoStep *us = (PaintCurveUndoStep *)us_p;
+ undocurve_to_paintcurve(&us->data, us->pc);
+}
- BLI_strncpy(uc->idname, pc->id.name, sizeof(uc->idname));
- uc->tot_points = pc->tot_points;
- uc->active_point = pc->add_index;
- uc->points = MEM_dupallocN(pc->points);
+static void paintcurve_undosys_step_free(UndoStep *us_p)
+{
+ PaintCurveUndoStep *us = (PaintCurveUndoStep *)us_p;
+ undocurve_free_data(&us->data);
+}
+
+/* Export for ED_undo_sys. */
+void ED_paintcurve_undosys_type(UndoType *ut)
+{
+ ut->name = "Paint Curve";
+ /* don't poll for now */
+ ut->poll = paintcurve_undosys_poll;
+ ut->step_encode_init = paintcurve_undosys_step_encode_init;
+ ut->step_encode = paintcurve_undosys_step_encode;
+ ut->step_decode = paintcurve_undosys_step_decode;
+ ut->step_free = paintcurve_undosys_step_free;
+
+ ut->mode = BKE_UNDOTYPE_MODE_STORE;
+ ut->use_context = false;
+
+ ut->step_size = sizeof(PaintCurveUndoStep);
+}
+
+/** \} */
- undo_paint_push_count_alloc(undo_stack_id, sizeof(*uc) + sizeof(*pc->points) * pc->tot_points);
- ED_undo_paint_push_end(undo_stack_id);
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+void ED_paintcurve_undo_push_begin(const char *name)
+{
+ bContext *C = NULL; /* special case, we never read from this. */
+ wmWindowManager *wm = G.main->wm.first;
+ BKE_undosys_step_push_init_with_type(wm->undo_stack, C, name, BKE_UNDOSYS_TYPE_PAINTCURVE);
}
+
+void ED_paintcurve_undo_push_end(void)
+{
+ wmWindowManager *wm = G.main->wm.first; /* XXX, avoids adding extra arg. */
+ BKE_undosys_step_push(wm->undo_stack, NULL, NULL);
+}
+
+/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index c6472b258ca..5d133ee622f 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -58,6 +58,9 @@
#include "BKE_material.h"
#include "BKE_node.h"
#include "BKE_paint.h"
+#include "BKE_undo_system.h"
+
+#include "BKE_global.h"
#include "UI_interface.h"
#include "UI_view2d.h"
@@ -145,9 +148,11 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int
imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh);
+ ListBase *undo_tiles = ED_image_undo_get_tiles();
+
for (ty = tiley; ty <= tileh; ty++)
for (tx = tilex; tx <= tilew; tx++)
- image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old);
+ image_undo_push_tile(undo_tiles, ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old);
ibuf->userflags |= IB_BITMAPDIRTY;
@@ -491,7 +496,8 @@ 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)) {
- ED_image_undo_restore();
+ UndoStack *ustack = CTX_wm_manager(C)->undo_stack;
+ ED_image_undo_restore(ustack->step_init);
}
if (pop->mode == PAINT_MODE_3D_PROJECT) {
@@ -1174,14 +1180,17 @@ void PAINT_OT_brush_colors_flip(wmOperatorType *ot)
void ED_imapaint_bucket_fill(struct bContext *C, float color[3], wmOperator *op)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = sima->image;
+ BKE_undosys_step_push_init_with_type(wm->undo_stack, C, op->type->name, BKE_UNDOSYS_TYPE_IMAGE);
+
ED_image_undo_push_begin(op->type->name);
paint_2d_bucket_fill(C, color, NULL, NULL, NULL);
- ED_undo_paint_push_end(UNDO_PAINT_IMAGE);
+ BKE_undosys_step_push(wm->undo_stack, C, op->type->name);
DAG_id_tag_update(&ima->id, 0);
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 894277402a7..c1dd31ea055 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -1035,6 +1035,8 @@ static void paint_2d_do_making_brush(ImagePaintState *s,
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 */
@@ -1043,9 +1045,9 @@ static void paint_2d_do_making_brush(ImagePaintState *s,
int origy = region->desty - ty * IMAPAINT_TILE_SIZE;
if (s->canvas->rect_float)
- tmpbuf.rect_float = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false);
+ tmpbuf.rect_float = image_undo_find_tile(undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
else
- tmpbuf.rect = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false);
+ 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,
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 60fe8555ba2..e5bddae971d 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -1499,15 +1499,16 @@ static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
if (generate_tile) {
+ ListBase *undo_tiles = ED_image_undo_get_tiles();
volatile void *undorect;
if (tinf->masked) {
undorect = image_undo_push_tile(
- pjIma->ima, pjIma->ibuf, tinf->tmpibuf,
+ undo_tiles, pjIma->ima, pjIma->ibuf, tinf->tmpibuf,
tx, ty, &pjIma->maskRect[tile_index], &pjIma->valid[tile_index], true, false);
}
else {
undorect = image_undo_push_tile(
- pjIma->ima, pjIma->ibuf, tinf->tmpibuf,
+ undo_tiles, pjIma->ima, pjIma->ibuf, tinf->tmpibuf,
tx, ty, NULL, &pjIma->valid[tile_index], true, false);
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_undo.c b/source/blender/editors/sculpt_paint/paint_image_undo.c
index b5b64eb3e16..9d1987943a5 100644
--- a/source/blender/editors/sculpt_paint/paint_image_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_image_undo.c
@@ -29,6 +29,10 @@
#include "BLI_threads.h"
#include "DNA_image_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -37,6 +41,8 @@
#include "BKE_depsgraph.h"
#include "BKE_image.h"
#include "BKE_main.h"
+#include "BKE_global.h"
+#include "BKE_undo_system.h"
#include "ED_paint.h"
@@ -44,10 +50,14 @@
#include "paint_intern.h"
+/* -------------------------------------------------------------------- */
+/** \name Undo Conversion
+ * \{ */
+
typedef struct UndoImageTile {
struct UndoImageTile *next, *prev;
- char idname[MAX_ID_NAME]; /* name instead of pointer*/
+ char idname[MAX_ID_NAME]; /* name instead of pointer */
char ibufname[IMB_FILENAME_SIZE];
union {
@@ -64,6 +74,8 @@ typedef struct UndoImageTile {
short source, use_float;
char gen_type;
bool valid;
+
+ size_t undo_size;
} UndoImageTile;
/* this is a static resource for non-globality,
@@ -129,13 +141,14 @@ static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, Cop
}
}
-void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate)
+void *image_undo_find_tile(
+ ListBase *undo_tiles,
+ 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) {
+ for (tile = undo_tiles->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)) {
@@ -161,10 +174,10 @@ void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsi
}
void *image_undo_push_tile(
+ ListBase *undo_tiles,
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;
@@ -174,7 +187,7 @@ void *image_undo_push_tile(
/* 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);
+ data = image_undo_find_tile(undo_tiles, ima, ibuf, x_tile, y_tile, mask, true);
if (data) {
return data;
}
@@ -214,8 +227,7 @@ void *image_undo_push_tile(
if (proj) {
BLI_spin_lock(&undolock);
}
- undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize);
- BLI_addtail(lb, tile);
+ BLI_addtail(undo_tiles, tile);
if (proj) {
BLI_spin_unlock(&undolock);
@@ -225,10 +237,10 @@ void *image_undo_push_tile(
void image_undo_remove_masks(void)
{
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+ ListBase *undo_tiles = ED_image_undo_get_tiles();
UndoImageTile *tile;
- for (tile = lb->first; tile; tile = tile->next) {
+ for (tile = undo_tiles->first; tile; tile = tile->next) {
if (tile->mask) {
MEM_freeN(tile->mask);
tile->mask = NULL;
@@ -346,50 +358,145 @@ static void image_undo_free_list(ListBase *lb)
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);
+ bContext *C = NULL; /* special case, we never read from this. */
+ wmWindowManager *wm = G.main->wm.first;
+ BKE_undosys_step_push_init_with_type(wm->undo_stack, C, name, BKE_UNDOSYS_TYPE_IMAGE);
}
void ED_image_undo_push_end(void)
{
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+ wmWindowManager *wm = G.main->wm.first; /* XXX, avoids adding extra arg. */
+ BKE_undosys_step_push(wm->undo_stack, NULL, NULL);
+}
+
+static void image_undo_invalidate(void)
+{
UndoImageTile *tile;
- int deallocsize = 0;
+ ListBase *lb = ED_image_undo_get_tiles();
+
+ for (tile = lb->first; tile; tile = tile->next) {
+ tile->valid = false;
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Implements ED Undo System
+ * \{ */
+
+typedef struct ImageUndoStep {
+ UndoStep step;
+ ListBase tiles;
+} ImageUndoStep;
+
+static bool image_undosys_poll(bContext *C)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && (sa->spacetype == SPACE_IMAGE)) {
+ SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
+ if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
+ return true;
+ }
+ }
+ else if (sa && (sa->spacetype == SPACE_VIEW3D)) {
+ if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void image_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ /* dummy, memory is cleared anyway. */
+ BLI_listbase_clear(&us->tiles);
+}
+
+static bool image_undosys_step_encode(struct bContext *UNUSED(C), UndoStep *us_p)
+{
+ /* dummy, encoding is done along the way by adding tiles
+ * to the current 'ImageUndoStep' added by encode_init. */
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+
+ BLI_assert(us->step.data_size == 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;) {
+ for (UndoImageTile *tile = us->tiles.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);
+ BLI_freelinkN(&us->tiles, tile);
tile = tmp_tile;
}
else {
+ us->step.data_size += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char));
tile = tile->next;
}
}
- /* don't forget to remove the size of deallocated tiles */
- undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, -deallocsize);
+ return true;
+}
- ED_undo_paint_push_end(UNDO_PAINT_IMAGE);
+static void image_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ image_undo_restore_list(C, &us->tiles);
}
-static void image_undo_invalidate(void)
+static void image_undosys_step_free(UndoStep *us_p)
{
- UndoImageTile *tile;
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ image_undo_free_list(&us->tiles);
+}
- for (tile = lb->first; tile; tile = tile->next) {
- tile->valid = false;
- }
+/* Export for ED_undo_sys. */
+void ED_image_undosys_type(UndoType *ut)
+{
+ ut->name = "Image";
+ ut->poll = image_undosys_poll;
+ ut->step_encode_init = image_undosys_step_encode_init;
+ ut->step_encode = image_undosys_step_encode;
+ ut->step_decode = image_undosys_step_decode;
+ ut->step_free = image_undosys_step_free;
+
+ ut->mode = BKE_UNDOTYPE_MODE_ACCUMULATE;
+ ut->use_context = true;
+
+ ut->step_size = sizeof(ImageUndoStep);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+ListBase *ED_image_undosys_step_get_tiles(UndoStep *us_p)
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ return &us->tiles;
+}
+
+ListBase *ED_image_undo_get_tiles(void)
+{
+ wmWindowManager *wm = G.main->wm.first; /* XXX, avoids adding extra arg. */
+ UndoStep *us = BKE_undosys_stack_init_or_active_with_type(wm->undo_stack, BKE_UNDOSYS_TYPE_IMAGE);
+ return ED_image_undosys_step_get_tiles(us);
}
/* restore painting image to previous state. Used for anchored and drag-dot style brushes*/
-void ED_image_undo_restore(void)
+void ED_image_undo_restore(UndoStep *us)
{
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+ ListBase *lb = ED_image_undosys_step_get_tiles(us);
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 52be4be4c0d..63a12b3c145 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -55,6 +55,7 @@ struct wmOperator;
struct wmOperatorType;
struct wmWindowManager;
struct DMCoNo;
+struct UndoStep;
enum ePaintMode;
/* paint_stroke.c */
@@ -221,15 +222,20 @@ void PAINT_OT_add_simple_uvs(struct wmOperatorType *ot);
/* paint_image_undo.c */
void *image_undo_find_tile(
+ ListBase *undo_tiles,
struct Image *ima, struct ImBuf *ibuf, int x_tile, int y_tile,
unsigned short **mask, bool validate);
void *image_undo_push_tile(
+ ListBase *undo_tiles,
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);
+struct ListBase *ED_image_undosys_step_get_tiles(struct UndoStep *us_p);
+struct ListBase *ED_image_undo_get_tiles(void);
+
/* sculpt_uv.c */
int uv_sculpt_poll(struct bContext *C);
int uv_sculpt_keymap_poll(struct bContext *C);
@@ -304,10 +310,6 @@ typedef enum {
void set_brush_rc_props(struct PointerRNA *ptr, const char *paint, const char *prop, const char *secondary_prop,
RCFlags flags);
-/* paint_undo.c */
-struct ListBase *undo_paint_push_get_list(int type);
-void undo_paint_push_count_alloc(int type, int size);
-
/* paint_hide.c */
typedef enum {
diff --git a/source/blender/editors/sculpt_paint/paint_undo.c b/source/blender/editors/sculpt_paint/paint_undo.c
deleted file mode 100644
index 27d3f6648a2..00000000000
--- a/source/blender/editors/sculpt_paint/paint_undo.c
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * ***** 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.
- *
- * You should have received a copy of the GNU General Public License
- * 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_undo.c
- * \ingroup edsculpt
- * \brief Undo system for painting and sculpting.
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_listbase.h"
-#include "BLI_utildefines.h"
-#include "BLI_string.h"
-
-#include "DNA_userdef_types.h"
-
-#include "BKE_blender_undo.h"
-#include "BKE_context.h"
-#include "BKE_global.h"
-
-#include "ED_paint.h"
-
-#include "paint_intern.h"
-
-typedef struct UndoElem {
- struct UndoElem *next, *prev;
- char name[BKE_UNDO_STR_MAX];
- uintptr_t undosize;
-
- ListBase elems;
-
- UndoRestoreCb restore;
- UndoFreeCb free;
- UndoCleanupCb cleanup;
-} UndoElem;
-
-typedef struct UndoStack {
- int type;
- ListBase elems;
- UndoElem *current;
-} UndoStack;
-
-static UndoStack ImageUndoStack = {UNDO_PAINT_IMAGE, {NULL, NULL}, NULL};
-static UndoStack MeshUndoStack = {UNDO_PAINT_MESH, {NULL, NULL}, NULL};
-
-/* Generic */
-
-static void undo_restore(bContext *C, UndoStack *UNUSED(stack), UndoElem *uel)
-{
- if (uel && uel->restore)
- uel->restore(C, &uel->elems);
-}
-
-static void undo_elem_free(UndoStack *UNUSED(stack), UndoElem *uel)
-{
- if (uel && uel->free) {
- uel->free(&uel->elems);
- BLI_freelistN(&uel->elems);
- }
-}
-
-static void undo_stack_push_begin(UndoStack *stack, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup)
-{
- UndoElem *uel;
- int nr;
-
- /* Undo push is split up in begin and end, the reason is that as painting
- * happens more tiles/nodes are added to the list, and at the very end we
- * know how much memory the undo used to remove old undo elements */
-
- /* remove all undos after (also when stack->current==NULL) */
- while (stack->elems.last != stack->current) {
- uel = stack->elems.last;
- undo_elem_free(stack, uel);
- BLI_freelinkN(&stack->elems, uel);
- }
-
- /* make new */
- stack->current = uel = MEM_callocN(sizeof(UndoElem), "undo file");
- uel->restore = restore;
- uel->free = free;
- uel->cleanup = cleanup;
- BLI_addtail(&stack->elems, uel);
-
- /* name can be a dynamic string */
- BLI_strncpy(uel->name, name, sizeof(uel->name));
-
- /* limit amount to the maximum amount*/
- nr = 0;
- uel = stack->elems.last;
- while (uel) {
- nr++;
- if (nr == U.undosteps) break;
- uel = uel->prev;
- }
- if (uel) {
- while (stack->elems.first != uel) {
- UndoElem *first = stack->elems.first;
- undo_elem_free(stack, first);
- BLI_freelinkN(&stack->elems, first);
- }
- }
-}
-
-static void undo_stack_push_end(UndoStack *stack)
-{
- UndoElem *uel;
- uintptr_t totmem, maxmem;
- int totundo = 0;
-
- /* first limit to undo steps */
- uel = stack->elems.last;
-
- while (uel) {
- totundo++;
- if (totundo > U.undosteps) break;
- uel = uel->prev;
- }
-
- if (uel) {
- UndoElem *first;
-
- /* in case the undo steps are zero, the current pointer will be invalid */
- if (uel == stack->current)
- stack->current = NULL;
-
- do {
- first = stack->elems.first;
- undo_elem_free(stack, first);
- BLI_freelinkN(&stack->elems, first);
- } while (first != uel);
- }
-
- if (U.undomemory != 0) {
- /* limit to maximum memory (afterwards, we can't know in advance) */
- totmem = 0;
- maxmem = ((uintptr_t)U.undomemory) * 1024 * 1024;
-
- uel = stack->elems.last;
- while (uel) {
- totmem += uel->undosize;
- if (totmem > maxmem) break;
- uel = uel->prev;
- }
-
- if (uel) {
- while (stack->elems.first != uel) {
- UndoElem *first = stack->elems.first;
- undo_elem_free(stack, first);
- BLI_freelinkN(&stack->elems, first);
- }
- }
- }
-}
-
-static void undo_stack_cleanup(UndoStack *stack, bContext *C)
-{
- UndoElem *uel = stack->elems.first;
- bool stack_reset = false;
-
- while (uel) {
- if (uel->cleanup && uel->cleanup(C, &uel->elems)) {
- UndoElem *uel_tmp = uel->next;
- if (stack->current == uel) {
- stack->current = NULL;
- stack_reset = true;
- }
- undo_elem_free(stack, uel);
- BLI_freelinkN(&stack->elems, uel);
- uel = uel_tmp;
- }
- else
- uel = uel->next;
- }
- if (stack_reset) {
- stack->current = stack->elems.last;
- }
-
-}
-
-static int undo_stack_step(bContext *C, UndoStack *stack, int step, const char *name)
-{
- UndoElem *undo;
-
- /* first cleanup any old undo steps that may belong to invalid data */
- undo_stack_cleanup(stack, C);
-
- if (step == 1) {
- if (stack->current == NULL) {
- /* pass */
- }
- else {
- if (!name || STREQ(stack->current->name, name)) {
- if (G.debug & G_DEBUG_WM) {
- printf("%s: undo '%s'\n", __func__, stack->current->name);
- }
- undo_restore(C, stack, stack->current);
- stack->current = stack->current->prev;
- return 1;
- }
- }
- }
- else if (step == -1) {
- if ((stack->current != NULL && stack->current->next == NULL) || BLI_listbase_is_empty(&stack->elems)) {
- /* pass */
- }
- else {
- if (!name || STREQ(stack->current->name, name)) {
- undo = (stack->current && stack->current->next) ? stack->current->next : stack->elems.first;
- undo_restore(C, stack, undo);
- stack->current = undo;
- if (G.debug & G_DEBUG_WM) {
- printf("%s: redo %s\n", __func__, undo->name);
- }
- return 1;
- }
- }
- }
-
- return 0;
-}
-
-static void undo_stack_free(UndoStack *stack)
-{
- UndoElem *uel;
-
- for (uel = stack->elems.first; uel; uel = uel->next)
- undo_elem_free(stack, uel);
-
- BLI_freelistN(&stack->elems);
- stack->current = NULL;
-}
-
-/* Exported Functions */
-
-void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup)
-{
- if (type == UNDO_PAINT_IMAGE)
- undo_stack_push_begin(&ImageUndoStack, name, restore, free, cleanup);
- else if (type == UNDO_PAINT_MESH)
- undo_stack_push_begin(&MeshUndoStack, name, restore, free, cleanup);
-}
-
-ListBase *undo_paint_push_get_list(int type)
-{
- if (type == UNDO_PAINT_IMAGE) {
- if (ImageUndoStack.current) {
- return &ImageUndoStack.current->elems;
- }
- }
- else if (type == UNDO_PAINT_MESH) {
- if (MeshUndoStack.current) {
- return &MeshUndoStack.current->elems;
- }
- }
-
- return NULL;
-}
-
-void undo_paint_push_count_alloc(int type, int size)
-{
- if (type == UNDO_PAINT_IMAGE)
- ImageUndoStack.current->undosize += size;
- else if (type == UNDO_PAINT_MESH)
- MeshUndoStack.current->undosize += size;
-}
-
-void ED_undo_paint_push_end(int type)
-{
- if (type == UNDO_PAINT_IMAGE)
- undo_stack_push_end(&ImageUndoStack);
- else if (type == UNDO_PAINT_MESH)
- undo_stack_push_end(&MeshUndoStack);
-}
-
-int ED_undo_paint_step(bContext *C, int type, int step, const char *name)
-{
- if (type == UNDO_PAINT_IMAGE)
- return undo_stack_step(C, &ImageUndoStack, step, name);
- else if (type == UNDO_PAINT_MESH)
- return undo_stack_step(C, &MeshUndoStack, step, name);
-
- return 0;
-}
-
-static void undo_step_num(bContext *C, UndoStack *stack, int step)
-{
- UndoElem *uel;
- int a = 0;
- int curnum = BLI_findindex(&stack->elems, stack->current);
-
- for (uel = stack->elems.first; uel; uel = uel->next, a++) {
- if (a == step) break;
- }
-
- if (curnum > a) {
- while (a++ != curnum)
- undo_stack_step(C, stack, 1, NULL);
- }
- else if (curnum < a) {
- while (a-- != curnum)
- undo_stack_step(C, stack, -1, NULL);
- }
-}
-
-void ED_undo_paint_step_num(bContext *C, int type, int step)
-{
- if (type == UNDO_PAINT_IMAGE)
- undo_step_num(C, &ImageUndoStack, step);
- else if (type == UNDO_PAINT_MESH)
- undo_step_num(C, &MeshUndoStack, step);
-}
-
-static char *undo_stack_get_name(UndoStack *stack, int nr, bool *r_active)
-{
- UndoElem *uel;
-
- if (r_active) *r_active = false;
-
- uel = BLI_findlink(&stack->elems, nr);
- if (uel) {
- if (r_active && (uel == stack->current)) {
- *r_active = true;
- }
- return uel->name;
- }
-
- return NULL;
-}
-
-const char *ED_undo_paint_get_name(bContext *C, int type, int nr, bool *r_active)
-{
-
- if (type == UNDO_PAINT_IMAGE) {
- undo_stack_cleanup(&ImageUndoStack, C);
- return undo_stack_get_name(&ImageUndoStack, nr, r_active);
- }
- else if (type == UNDO_PAINT_MESH) {
- undo_stack_cleanup(&MeshUndoStack, C);
- return undo_stack_get_name(&MeshUndoStack, nr, r_active);
- }
- return NULL;
-}
-
-bool ED_undo_paint_empty(int type)
-{
- UndoStack *stack;
-
- if (type == UNDO_PAINT_IMAGE)
- stack = &ImageUndoStack;
- else if (type == UNDO_PAINT_MESH)
- stack = &MeshUndoStack;
- else
- return true;
-
- if (stack->current == NULL) {
- return true;
- }
-
- return false;
-}
-
-bool ED_undo_paint_is_valid(int type, const char *name)
-{
- UndoStack *stack;
-
- if (type == UNDO_PAINT_IMAGE)
- stack = &ImageUndoStack;
- else if (type == UNDO_PAINT_MESH)
- stack = &MeshUndoStack;
- else
- return 0;
-
- if (stack->current == NULL) {
- /* pass */
- }
- else {
- if (name && STREQ(stack->current->name, name))
- return 1;
- else
- return stack->elems.first != stack->elems.last;
- }
- return 0;
-}
-
-void ED_undo_paint_free(void)
-{
- undo_stack_free(&ImageUndoStack);
- undo_stack_free(&MeshUndoStack);
-}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index cf1937f14d4..e46760258e1 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -122,6 +122,8 @@ typedef struct SculptUndoNode {
/* shape keys */
char shapeName[sizeof(((KeyBlock *)0))->name];
+
+ size_t undo_size;
} SculptUndoNode;
/* Factor of brush to have rake point following behind
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 794ac14483a..4e2bcab9f36 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -48,6 +48,8 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "BKE_ccg.h"
#include "BKE_context.h"
@@ -57,6 +59,9 @@
#include "BKE_key.h"
#include "BKE_mesh.h"
#include "BKE_subsurf.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_undo_system.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -64,12 +69,21 @@
#include "GPU_buffers.h"
#include "ED_paint.h"
+#include "ED_object.h"
+#include "ED_sculpt.h"
#include "bmesh.h"
#include "paint_intern.h"
#include "sculpt_intern.h"
-/************************** Undo *************************/
+
+typedef struct UndoSculpt {
+ ListBase nodes;
+
+ size_t undo_size;
+} UndoSculpt;
+
+static UndoSculpt *sculpt_undo_get_nodes(void);
static void update_cb(PBVHNode *node, void *rebuild)
{
@@ -454,7 +468,7 @@ static int sculpt_undo_bmesh_restore(bContext *C,
return false;
}
-static void sculpt_undo_restore(bContext *C, ListBase *lb)
+static void sculpt_undo_restore_list(bContext *C, ListBase *lb)
{
Scene *scene = CTX_data_scene(C);
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -574,7 +588,7 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
}
}
-static void sculpt_undo_free(ListBase *lb)
+static void sculpt_undo_free_list(ListBase *lb)
{
SculptUndoNode *unode;
int i;
@@ -617,6 +631,8 @@ static void sculpt_undo_free(ListBase *lb)
}
}
+/* Most likely we don't need this. */
+#if 0
static bool sculpt_undo_cleanup(bContext *C, ListBase *lb)
{
Object *ob = CTX_data_active_object(C);
@@ -633,16 +649,17 @@ static bool sculpt_undo_cleanup(bContext *C, ListBase *lb)
return false;
}
+#endif
SculptUndoNode *sculpt_undo_get_node(PBVHNode *node)
{
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH);
+ UndoSculpt *usculpt = sculpt_undo_get_nodes();
- if (!lb) {
+ if (usculpt == NULL) {
return NULL;
}
- return BLI_findptr(lb, node, offsetof(SculptUndoNode, node));
+ return BLI_findptr(&usculpt->nodes, node, offsetof(SculptUndoNode, node));
}
static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh,
@@ -668,10 +685,11 @@ static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh,
}
}
-static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node,
- SculptUndoType type)
+static SculptUndoNode *sculpt_undo_alloc_node(
+ Object *ob, PBVHNode *node,
+ SculptUndoType type)
{
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH);
+ UndoSculpt *usculpt = sculpt_undo_get_nodes();
SculptUndoNode *unode;
SculptSession *ss = ob->sculpt;
int totvert, allvert, totgrid, maxgrid, gridsize, *grids;
@@ -696,23 +714,23 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node,
/* general TODO, fix count_alloc */
switch (type) {
case SCULPT_UNDO_COORDS:
- unode->co = MEM_mapallocN(sizeof(float) * 3 * allvert, "SculptUndoNode.co");
- unode->no = MEM_mapallocN(sizeof(short) * 3 * allvert, "SculptUndoNode.no");
- undo_paint_push_count_alloc(UNDO_PAINT_MESH,
- (sizeof(float) * 3 +
- sizeof(short) * 3 +
- sizeof(int)) * allvert);
+ unode->co = MEM_mapallocN(sizeof(float[3]) * allvert, "SculptUndoNode.co");
+ unode->no = MEM_mapallocN(sizeof(short[3]) * allvert, "SculptUndoNode.no");
+
+ usculpt->undo_size = (sizeof(float[3]) + sizeof(short[3]) + sizeof(int)) * allvert;
break;
case SCULPT_UNDO_HIDDEN:
if (maxgrid)
sculpt_undo_alloc_and_store_hidden(ss->pbvh, unode);
else
unode->vert_hidden = BLI_BITMAP_NEW(allvert, "SculptUndoNode.vert_hidden");
-
+
break;
case SCULPT_UNDO_MASK:
unode->mask = MEM_mapallocN(sizeof(float) * allvert, "SculptUndoNode.mask");
- undo_paint_push_count_alloc(UNDO_PAINT_MESH, (sizeof(float) * sizeof(int)) * allvert);
+
+ usculpt->undo_size += (sizeof(float) * sizeof(int)) * allvert;
+
break;
case SCULPT_UNDO_DYNTOPO_BEGIN:
case SCULPT_UNDO_DYNTOPO_END:
@@ -721,7 +739,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node,
break;
}
- BLI_addtail(lb, unode);
+ BLI_addtail(&usculpt->nodes, unode);
if (maxgrid) {
/* multires */
@@ -798,12 +816,13 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob,
PBVHNode *node,
SculptUndoType type)
{
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH);
- SculptUndoNode *unode = lb->first;
+ UndoSculpt *usculpt = sculpt_undo_get_nodes();
SculptSession *ss = ob->sculpt;
PBVHVertexIter vd;
- if (!lb->first) {
+ SculptUndoNode *unode = usculpt->nodes.first;
+
+ if (unode == NULL) {
unode = MEM_callocN(sizeof(*unode), __func__);
BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname));
@@ -842,7 +861,7 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob,
unode->bm_entry = BM_log_entry_add(ss->bm_log);
}
- BLI_addtail(lb, unode);
+ BLI_addtail(&usculpt->nodes, unode);
}
if (node) {
@@ -883,8 +902,9 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob,
return unode;
}
-SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node,
- SculptUndoType type)
+SculptUndoNode *sculpt_undo_push_node(
+ Object *ob, PBVHNode *node,
+ SculptUndoType type)
{
SculptSession *ss = ob->sculpt;
SculptUndoNode *unode;
@@ -954,17 +974,18 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node,
void sculpt_undo_push_begin(const char *name)
{
- ED_undo_paint_push_begin(UNDO_PAINT_MESH, name,
- sculpt_undo_restore, sculpt_undo_free, sculpt_undo_cleanup);
+ bContext *C = NULL; /* special case, we never read from this. */
+ wmWindowManager *wm = G.main->wm.first;
+ BKE_undosys_step_push_init_with_type(wm->undo_stack, C, name, BKE_UNDOSYS_TYPE_SCULPT);
}
void sculpt_undo_push_end(void)
{
- ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH);
+ UndoSculpt *usculpt = sculpt_undo_get_nodes();
SculptUndoNode *unode;
/* we don't need normals in the undo stack */
- for (unode = lb->first; unode; unode = unode->next) {
+ for (unode = usculpt->nodes.first; unode; unode = unode->next) {
if (unode->no) {
MEM_freeN(unode->no);
unode->no = NULL;
@@ -974,7 +995,97 @@ void sculpt_undo_push_end(void)
BKE_pbvh_node_layer_disp_free(unode->node);
}
- ED_undo_paint_push_end(UNDO_PAINT_MESH);
+ wmWindowManager *wm = G.main->wm.first; /* XXX, avoids adding extra arg. */
+ BKE_undosys_step_push(wm->undo_stack, NULL, NULL);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Implements ED Undo System
+ * \{ */
+
+typedef struct SculptUndoStep {
+ UndoStep step;
+ /* note: will split out into list for multi-object-sculpt-mode. */
+ UndoSculpt data;
+} SculptUndoStep;
+
+static bool sculpt_undosys_poll(bContext *C)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && (sa->spacetype == SPACE_VIEW3D)) {
+ Object *obact = CTX_data_active_object(C);
+ if (obact && (obact->mode & OB_MODE_SCULPT)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void sculpt_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
+{
+ SculptUndoStep *us = (SculptUndoStep *)us_p;
+ /* dummy, memory is cleared anyway. */
+ BLI_listbase_clear(&us->data.nodes);
+}
+
+static bool sculpt_undosys_step_encode(struct bContext *UNUSED(C), UndoStep *us_p)
+{
+ /* dummy, encoding is done along the way by adding tiles
+ * to the current 'SculptUndoStep' added by encode_init. */
+ SculptUndoStep *us = (SculptUndoStep *)us_p;
+ us->step.data_size = us->data.undo_size;
+ return true;
+}
+
+static void sculpt_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
+{
+ /* TODO(campbell): undo_system: use low-level API to set mode. */
+ ED_object_mode_set(C, OB_MODE_SCULPT);
+ BLI_assert(sculpt_undosys_poll(C));
+
+ SculptUndoStep *us = (SculptUndoStep *)us_p;
+ sculpt_undo_restore_list(C, &us->data.nodes);
+}
- WM_file_tag_modified();
+static void sculpt_undosys_step_free(UndoStep *us_p)
+{
+ SculptUndoStep *us = (SculptUndoStep *)us_p;
+ sculpt_undo_free_list(&us->data.nodes);
}
+
+/* Export for ED_undo_sys. */
+void ED_sculpt_undosys_type(UndoType *ut)
+{
+ ut->name = "Sculpt";
+ ut->poll = sculpt_undosys_poll;
+ ut->step_encode_init = sculpt_undosys_step_encode_init;
+ ut->step_encode = sculpt_undosys_step_encode;
+ ut->step_decode = sculpt_undosys_step_decode;
+ ut->step_free = sculpt_undosys_step_free;
+
+ ut->mode = BKE_UNDOTYPE_MODE_ACCUMULATE;
+ ut->use_context = true;
+
+ ut->step_size = sizeof(SculptUndoStep);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+static UndoSculpt *sculpt_undosys_step_get_nodes(UndoStep *us_p)
+{
+ SculptUndoStep *us = (SculptUndoStep *)us_p;
+ return &us->data;
+}
+
+static UndoSculpt *sculpt_undo_get_nodes(void)
+{
+ wmWindowManager *wm = G.main->wm.first; /* XXX, avoids adding extra arg. */
+ UndoStep *us = BKE_undosys_stack_init_or_active_with_type(wm->undo_stack, BKE_UNDOSYS_TYPE_SCULPT);
+ return sculpt_undosys_step_get_nodes(us);
+}
+
+/** \} */