diff options
Diffstat (limited to 'source/blender/editors/sculpt_paint/sculpt_undo.c')
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt_undo.c | 94 |
1 files changed, 93 insertions, 1 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 340f7191b95..c07ebf790d4 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -55,6 +55,9 @@ #include "BKE_subsurf.h" #include "BKE_undo_system.h" +// XXX: Ideally should be no direct call to such low level things. +#include "BKE_subdiv_eval.h" + #include "DEG_depsgraph.h" #include "WM_api.h" @@ -552,7 +555,9 @@ static void sculpt_undo_geometry_free_data(SculptUndoNodeGeometry *geometry) static void sculpt_undo_geometry_restore(SculptUndoNode *unode, Object *object) { - SCULPT_pbvh_clear(object); + if (unode->geometry_clear_pbvh) { + SCULPT_pbvh_clear(object); + } if (unode->applied) { sculpt_undo_geometry_restore_data(&unode->geometry_modified, object); @@ -740,6 +745,10 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase } } + if (subdiv_ccg != NULL) { + BKE_subdiv_eval_refine_from_mesh(subdiv_ccg->subdiv, ob->data, NULL); + } + if (update || rebuild) { bool tag_update = false; /* We update all nodes still, should be more clever, but also @@ -1079,6 +1088,7 @@ static SculptUndoNode *sculpt_undo_geometry_push(Object *object, SculptUndoType { SculptUndoNode *unode = sculpt_undo_find_or_alloc_node_type(object, type); unode->applied = false; + unode->geometry_clear_pbvh = true; SculptUndoNodeGeometry *geometry = sculpt_undo_geometry_get(unode); sculpt_undo_geometry_store_data(geometry, object); @@ -1510,3 +1520,85 @@ static UndoSculpt *sculpt_undo_get_nodes(void) } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Undo for changes happening on a base mesh for multires sculpting. + * + * Use this for multires operators which changes base mesh and which are to be + * possible. Example of such operators is Apply Base. + * + * Usage: + * + * static int operator_exec((bContext *C, wmOperator *op) { + * + * ED_sculpt_undo_push_mixed_begin(C, op->type->name); + * // Modify base mesh. + * ED_sculpt_undo_push_mixed_end(C, op->type->name); + * + * return OPERATOR_FINISHED; + * } + * + * If object is not in sculpt mode or sculpt does not happen on multires then + * regular ED_undo_push() is used. + * * + * \{ */ + +static bool sculpt_undo_use_multires_mesh(bContext *C) +{ + if (BKE_paintmode_get_active_from_context(C) != PAINT_MODE_SCULPT) { + return false; + } + + Object *object = CTX_data_active_object(C); + SculptSession *sculpt_session = object->sculpt; + + return sculpt_session->multires.active; +} + +static void sculpt_undo_push_all_grids(Object *object) +{ + SculptSession *ss = object->sculpt; + PBVHNode **nodes; + int totnodes; + + BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnodes); + for (int i = 0; i < totnodes; i++) { + SculptUndoNode *unode = SCULPT_undo_push_node(object, nodes[i], SCULPT_UNDO_COORDS); + unode->node = NULL; + } + + MEM_SAFE_FREE(nodes); +} + +void ED_sculpt_undo_push_multires_mesh_begin(bContext *C, const char *str) +{ + if (!sculpt_undo_use_multires_mesh(C)) { + return; + } + + Object *object = CTX_data_active_object(C); + + SCULPT_undo_push_begin(str); + + SculptUndoNode *geometry_unode = SCULPT_undo_push_node(object, NULL, SCULPT_UNDO_GEOMETRY); + geometry_unode->geometry_clear_pbvh = false; + + sculpt_undo_push_all_grids(object); +} + +void ED_sculpt_undo_push_multires_mesh_end(bContext *C, const char *str) +{ + if (!sculpt_undo_use_multires_mesh(C)) { + ED_undo_push(C, str); + return; + } + + Object *object = CTX_data_active_object(C); + + SculptUndoNode *geometry_unode = SCULPT_undo_push_node(object, NULL, SCULPT_UNDO_GEOMETRY); + geometry_unode->geometry_clear_pbvh = false; + + SCULPT_undo_push_end(); +} + +/** \} */ |