[Bf-blender-cvs] [b2c2d7b7f13] master: Sculpt: Implement undo of Apply Base during sculpt session

Sergey Sharybin noreply at git.blender.org
Tue Apr 14 09:52:11 CEST 2020


Commit: b2c2d7b7f13a0c033853dcc87b49dbda4ba737af
Author: Sergey Sharybin
Date:   Mon Mar 30 09:35:01 2020 +0200
Branches: master
https://developer.blender.org/rBb2c2d7b7f13a0c033853dcc87b49dbda4ba737af

Sculpt: Implement undo of Apply Base during sculpt session

The idea is to push both base mesh geometry and PBVH coordinates
so it is possible to undo everything without loosing data which was
not flushed from sculpt session to base mesh.

It is possible do memory optimization to avoid push custom data
layers which are not touched by operator, but before doing that
better to ensure this is a correct and working approach.

Differential Revision: https://developer.blender.org/D7381

===================================================================

M	source/blender/editors/include/ED_sculpt.h
M	source/blender/editors/object/object_modifier.c
M	source/blender/editors/sculpt_paint/sculpt_intern.h
M	source/blender/editors/sculpt_paint/sculpt_undo.c

===================================================================

diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 26871cf8dd0..e61c7be5216 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -54,6 +54,11 @@ void ED_sculpt_undosys_type(struct UndoType *ut);
 void ED_sculpt_undo_geometry_begin(struct Object *ob, const char *name);
 void ED_sculpt_undo_geometry_end(struct Object *ob);
 
+/* Undo for changes happening on a base mesh for multires sculpting.
+ * if there is no multires sculpt active regular undo is used. */
+void ED_sculpt_undo_push_multires_mesh_begin(struct bContext *C, const char *str);
+void ED_sculpt_undo_push_multires_mesh_end(struct bContext *C, const char *str);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 2babf27eb61..a24f3ba2269 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -86,6 +86,7 @@
 #include "ED_mesh.h"
 #include "ED_object.h"
 #include "ED_screen.h"
+#include "ED_sculpt.h"
 
 #include "WM_api.h"
 #include "WM_types.h"
@@ -1697,8 +1698,12 @@ static int multires_base_apply_exec(bContext *C, wmOperator *op)
     return OPERATOR_CANCELLED;
   }
 
+  ED_sculpt_undo_push_multires_mesh_begin(C, op->type->name);
+
   multiresModifier_base_apply(depsgraph, object, mmd);
 
+  ED_sculpt_undo_push_multires_mesh_end(C, op->type->name);
+
   DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, object);
 
@@ -1726,7 +1731,7 @@ void OBJECT_OT_multires_base_apply(wmOperatorType *ot)
   ot->exec = multires_base_apply_exec;
 
   /* flags */
-  ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+  ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL;
   edit_modifier_properties(ot);
 }
 
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index e2fd54596e7..b379c1ab8af 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -478,6 +478,7 @@ typedef struct SculptUndoNode {
    * the object when undoing the operation
    *
    * Modified geometry is stored after the modification and is used to redo the modification. */
+  bool geometry_clear_pbvh;
   SculptUndoNodeGeometry geometry_original;
   SculptUndoNodeGeometry geometry_modified;
 
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();
+}
+
+/** \} */



More information about the Bf-blender-cvs mailing list