Fix T69822: Switching sculpt objects breaks undo
authorCampbell Barton <ideasman42@gmail.com>
Thu, 7 Nov 2019 05:52:03 +0000 (16:52 +1100)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 7 Nov 2019 05:56:21 +0000 (16:56 +1100)
This introduces object mode tagging for data which hasn't yet been
written back to the ID data.

Now when selecting other sculpt objects, the original objects data is
flushed back to the ID before writing a memfile undo step.

24 files changed:
source/blender/blenkernel/BKE_editmesh.h
source/blender/blenkernel/BKE_font.h
source/blender/blenkernel/BKE_main.h
source/blender/blenkernel/BKE_object.h
source/blender/blenkernel/BKE_paint.h
source/blender/blenkernel/intern/object.c
source/blender/blenloader/intern/readfile.c
source/blender/editors/armature/editarmature_undo.c
source/blender/editors/curve/editcurve_undo.c
source/blender/editors/curve/editfont_undo.c
source/blender/editors/include/ED_mball.h
source/blender/editors/include/ED_util.h
source/blender/editors/lattice/editlattice_undo.c
source/blender/editors/mesh/editmesh_undo.c
source/blender/editors/metaball/editmball_undo.c
source/blender/editors/object/object_edit.c
source/blender/editors/sculpt_paint/sculpt_undo.c
source/blender/editors/undo/ed_undo.c
source/blender/editors/undo/memfile_undo.c
source/blender/editors/util/ed_util.c
source/blender/makesdna/DNA_armature_types.h
source/blender/makesdna/DNA_curve_types.h
source/blender/makesdna/DNA_lattice_types.h
source/blender/makesdna/DNA_meta_types.h

index 47c8f31ead3e73a6c6c6dcaa1cbf42623efdeb07..1b9e318146ee55b750773c3c1cfaa03a3a61a2e5 100644 (file)
@@ -79,6 +79,13 @@ typedef struct BMEditMesh {
 
   /*temp variables for x-mirror editing*/
   int mirror_cdlayer; /* -1 is invalid */
+
+  /**
+   * ID data is older than edit-mode data.
+   * Set #Main.is_memfile_undo_flush_needed when enabling.
+   */
+  char needs_flush_to_id;
+
 } BMEditMesh;
 
 /* editmesh.c */
index e440d617f7a62de0ea38adac4092a30daa368698..3dd2a551a93e7f89c2473040e33627ff350b306f 100644 (file)
@@ -61,6 +61,12 @@ typedef struct EditFont {
   int len, pos;
   int selstart, selend;
 
+  /**
+   * ID data is older than edit-mode data.
+   * Set #Main.is_memfile_undo_flush_needed when enabling.
+   */
+  char needs_flush_to_id;
+
 } EditFont;
 
 bool BKE_vfont_is_builtin(struct VFont *vfont);
index 1b2e8bcbf42e5f5758c9fdfa59f04093f936bdc1..c48a9cad44304952556677f4895be9004130dd15 100644 (file)
@@ -80,6 +80,11 @@ typedef struct Main {
   char recovered;                  /* indicate the main->name (file) is the recovered one */
   /** All current ID's exist in the last memfile undo step. */
   char is_memfile_undo_written;
+  /**
+   * An ID needs it's data to be flushed back.
+   * use "needs_flush_to_id" in edit data to flag data which needs updating.
+   */
+  char is_memfile_undo_flush_needed;
 
   BlendThumbnail *blen_thumb;
 
index ffdcb9cd2c0a2f0cfb18d8c21b94fa1b198e9504..d76c55f081529c291fa94980821a26099dc99bae 100644 (file)
@@ -99,6 +99,8 @@ bool BKE_object_is_mode_compat(const struct Object *ob, eObjectMode object_mode)
 
 bool BKE_object_data_is_in_editmode(const struct ID *id);
 
+char *BKE_object_data_editmode_flush_ptr_get(struct ID *id);
+
 void BKE_object_update_select_id(struct Main *bmain);
 
 typedef enum eObjectVisibilityResult {
index 4413ad2a70f70dece03a8c86890d5dd6a4a94d40..48f9e1fd95e20d66110ec625cb13839aac3d28f1 100644 (file)
@@ -306,6 +306,13 @@ typedef struct SculptSession {
 
   /* This flag prevents PBVH from being freed when creating the vp_handle for texture paint. */
   bool building_vp_handle;
+
+  /**
+   * ID data is older than sculpt-mode data.
+   * Set #Main.is_memfile_undo_flush_needed when enabling.
+   */
+  char needs_flush_to_id;
+
 } SculptSession;
 
 void BKE_sculptsession_free(struct Object *ob);
index 773e2d19b227f327d3eb3c041f3a1c0eeadf4d21..b50e152527e75d00824e5f89613c9c534751b538 100644 (file)
@@ -81,6 +81,7 @@
 #include "BKE_curve.h"
 #include "BKE_displist.h"
 #include "BKE_effect.h"
+#include "BKE_font.h"
 #include "BKE_fcurve.h"
 #include "BKE_gpencil_modifier.h"
 #include "BKE_icons.h"
@@ -629,6 +630,54 @@ bool BKE_object_data_is_in_editmode(const ID *id)
   }
 }
 
+char *BKE_object_data_editmode_flush_ptr_get(struct ID *id)
+{
+  const short type = GS(id->name);
+  switch (type) {
+    case ID_ME: {
+      BMEditMesh *em = ((Mesh *)id)->edit_mesh;
+      if (em != NULL) {
+        return &em->needs_flush_to_id;
+      }
+      break;
+    }
+    case ID_CU: {
+      if (((Curve *)id)->vfont != NULL) {
+        EditFont *ef = ((Curve *)id)->editfont;
+        if (ef != NULL) {
+          return &ef->needs_flush_to_id;
+        }
+      }
+      else {
+        EditNurb *editnurb = ((Curve *)id)->editnurb;
+        if (editnurb) {
+          return &editnurb->needs_flush_to_id;
+        }
+      }
+      break;
+    }
+    case ID_MB: {
+      MetaBall *mb = (MetaBall *)id;
+      return &mb->needs_flush_to_id;
+    }
+    case ID_LT: {
+      EditLatt *editlatt = ((Lattice *)id)->editlatt;
+      if (editlatt) {
+        return &editlatt->needs_flush_to_id;
+      }
+      break;
+    }
+    case ID_AR: {
+      bArmature *arm = (bArmature *)id;
+      return &arm->needs_flush_to_id;
+    }
+    default:
+      BLI_assert(0);
+      return NULL;
+  }
+  return NULL;
+}
+
 bool BKE_object_is_in_wpaint_select_vert(const Object *ob)
 {
   if (ob->type == OB_MESH) {
index 3866878b12ab2f9a32f3e3bea460819d8adc8411..452e75081d6b20f016a56911778e85c008338b65 100644 (file)
@@ -3862,6 +3862,8 @@ static void direct_link_armature(FileData *fd, bArmature *arm)
   link_list(fd, &arm->bonebase);
   arm->bonehash = NULL;
   arm->edbo = NULL;
+  /* Must always be cleared (armatures don't have their own edit-data). */
+  arm->needs_flush_to_id = 0;
 
   arm->adt = newdataadr(fd, arm->adt);
   direct_link_animdata(fd, arm->adt);
@@ -4079,6 +4081,8 @@ static void direct_link_mball(FileData *fd, MetaBall *mb)
 
   BLI_listbase_clear(&mb->disp);
   mb->editelems = NULL;
+  /* Must always be cleared (meta's don't have their own edit-data). */
+  mb->needs_flush_to_id = 0;
   /*  mb->edit_elems.first= mb->edit_elems.last= NULL;*/
   mb->lastelem = NULL;
   mb->batch_cache = NULL;
index 4a82a8fccee7191cc27add170492f7791097d31c..4e3ab11a9f7739b545636b179eca409cb5b1f1b1 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "BKE_context.h"
 #include "BKE_layer.h"
+#include "BKE_main.h"
 #include "BKE_undo_system.h"
 
 #include "DEG_depsgraph.h"
@@ -142,9 +143,7 @@ static bool armature_undosys_poll(bContext *C)
   return editarm_object_from_context(C) != NULL;
 }
 
-static bool armature_undosys_step_encode(struct bContext *C,
-                                         struct Main *UNUSED(bmain),
-                                         UndoStep *us_p)
+static bool armature_undosys_step_encode(struct bContext *C, struct Main *bmain, UndoStep *us_p)
 {
   ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
 
@@ -165,17 +164,18 @@ static bool armature_undosys_step_encode(struct bContext *C,
     elem->obedit_ref.ptr = ob;
     bArmature *arm = elem->obedit_ref.ptr->data;
     undoarm_from_editarm(&elem->data, arm);
+    arm->needs_flush_to_id = 1;
     us->step.data_size += elem->data.undo_size;
   }
   MEM_freeN(objects);
+
+  bmain->is_memfile_undo_flush_needed = true;
+
   return true;
 }
 
-static void armature_undosys_step_decode(struct bContext *C,
-                                         struct Main *UNUSED(bmain),
-                                         UndoStep *us_p,
-                                         int UNUSED(dir),
-                                         bool UNUSED(is_final))
+static void armature_undosys_step_decode(
+    struct bContext *C, struct Main *bmain, UndoStep *us_p, int UNUSED(dir), bool UNUSED(is_final))
 {
   ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
 
@@ -198,6 +198,7 @@ static void armature_undosys_step_decode(struct bContext *C,
       continue;
     }
     undoarm_to_editarm(&elem->data, arm);
+    arm->needs_flush_to_id = 1;
     DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
   }
 
@@ -205,6 +206,8 @@ static void armature_undosys_step_decode(struct bContext *C,
   ED_undo_object_set_active_or_warn(
       CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG);
 
+  bmain->is_memfile_undo_flush_needed = true;
+
   WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
 }
 
index f21b4f0624650ff18692048ec7010cc86cf2b72f..ff3a1386fd971a0bd4c5818adb24f1fa4b00a2ce 100644 (file)
@@ -208,9 +208,7 @@ static bool curve_undosys_poll(bContext *C)
   return (obedit != NULL);
 }
 
-static bool curve_undosys_step_encode(struct bContext *C,
-                                      struct Main *UNUSED(bmain),
-                                      UndoStep *us_p)
+static bool curve_undosys_step_encode(struct bContext *C, struct Main *bmain, UndoStep *us_p)
 {
   CurveUndoStep *us = (CurveUndoStep *)us_p;
 
@@ -226,13 +224,18 @@ static bool curve_undosys_step_encode(struct bContext *C,
 
   for (uint i = 0; i < objects_len; i++) {
     Object *ob = objects[i];
+    Curve *cu = ob->data;
     CurveUndoStep_Elem *elem = &us->elems[i];
 
     elem->obedit_ref.ptr = ob;
     undocurve_from_editcurve(&elem->data, ob->data, ob->shapenr);
+    cu->editnurb->needs_flush_to_id = 1;
     us->step.data_size += elem->data.undo_size;
   }
   MEM_freeN(objects);
+
+  bmain->is_memfile_undo_flush_needed = true;
+
   return true;
 }
 
@@ -260,6 +263,7 @@ static void curve_undosys_step_decode(
       continue;
     }
     undocurve_to_editcurve(bmain, &elem->data, obedit->data, &obedit->shapenr);
+    cu->editnurb->needs_flush_to_id = 1;
     DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
   }
 
@@ -267,6 +271,8 @@ static void curve_undosys_step_decode(
   ED_undo_object_set_active_or_warn(
       CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG);
 
+  bmain->is_memfile_undo_flush_needed = true;
+
   WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
 }
 
index ae858ec4c241daeb95b85ad47fd284c1183e9ac9..26c0e5cf6c993b9074a83191391fe685bef4f728 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "BKE_context.h"
 #include "BKE_font.h"
+#include "BKE_main.h"
 #include "BKE_undo_system.h"
 
 #include "DEG_depsgraph.h"
@@ -341,23 +342,21 @@ static bool font_undosys_poll(bContext *C)
   return editfont_object_from_context(C) != NULL;
 }
 
-static bool font_undosys_step_encode(struct bContext *C,
-                                     struct Main *UNUSED(bmain),
-                                     UndoStep *us_p)
+static bool font_undosys_step_encode(struct bContext *C, struct Main *bmain, UndoStep *us_p)
 {
   FontUndoStep *us = (FontUndoStep *)us_p;
   us->obedit_ref.ptr = editfont_object_from_context(C);
   Curve *cu = us->obedit_ref.ptr->data;
   undofont_from_editfont(&us->data, cu);
   us->step.data_size = us->data.undo_size;
+  cu->editfont->needs_flush_to_id = 1;
+  bmain->is_memfile_undo_flush_needed = true;
+
   return true;
 }
 
-static void font_undosys_step_decode(struct bContext *C,
-                                     struct Main *UNUSED(bmain),
-                                     UndoStep *us_p,
-                                     int UNUSED(dir),
-                                     bool UNUSED(is_final))
+static void font_undosys_step_decode(
+    struct bContext *C, struct Main *bmain, UndoStep *us_p, int UNUSED(dir), bool UNUSED(is_final))
 {
   /* TODO(campbell): undo_system: use low-level API to set mode. */
   ED_object_mode_set(C, OB_MODE_EDIT);
@@ -368,6 +367,8 @@ static void font_undosys_step_decode(struct bContext *C,
   Curve *cu = obedit->data;
   undofont_to_editfont(&us->data, cu);
   DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
+  cu->editfont->needs_flush_to_id = 1;
+  bmain->is_memfile_undo_flush_needed = true;
   WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
 }
 
index 8ffae0f2b6686f60e5ad73df317d4944480987cd..5afb645d9e7d5d213610805703961092369fcdd7 100644 (file)
@@ -25,6 +25,7 @@
 #define __ED_MBALL_H__
 
 struct Base;
+struct MetaBall;
 struct Object;
 struct UndoType;
 struct bContext;
index 87f57b4e144cab75fdececfbdc142ca4d6156ae2..003e84bbf055b400f79c99fe80fd8bdeb251739d 100644 (file)
@@ -34,6 +34,8 @@ struct wmOperatorType;
 void ED_editors_init_for_undo(struct Main *bmain);
 void ED_editors_init(struct bContext *C);
 void ED_editors_exit(struct Main *bmain, bool do_undo_system);
+
+bool ED_editors_flush_edits_ex(struct Main *bmain, bool for_render, bool check_needs_flush);
 bool ED_editors_flush_edits(struct Main *bmain, bool for_render);
 
 void ED_spacedata_id_remap(struct ScrArea *sa,
index abc5224c4d6af172c4cedbc4156be7724ad08892..2790e6b55583d0dd27eaebd334e6de443259fd87 100644 (file)
@@ -39,6 +39,7 @@
 
 #include "BKE_context.h"
 #include "BKE_layer.h"
+#include "BKE_main.h"
 #include "BKE_undo_system.h"
 
 #include "DEG_depsgraph.h"
@@ -154,9 +155,7 @@ static bool lattice_undosys_poll(bContext *C)
   return editlatt_object_from_context(C) != NULL;
 }
 
-static bool lattice_undosys_step_encode(struct bContext *C,
-                                        struct Main *UNUSED(bmain),
-                                        UndoStep *us_p)
+static bool lattice_undosys_step_encode(struct bContext *C, Main *bmain, UndoStep *us_p)
 {
   LatticeUndoStep *us = (LatticeUndoStep *)us_p;
 
@@ -177,17 +176,18 @@ static bool lattice_undosys_step_encode(struct bContext *C,
     elem->obedit_ref.ptr = ob;
     Lattice *lt = ob->data;
     undolatt_from_editlatt(&elem->data, lt->editlatt);
+    lt->editlatt->needs_flush_to_id = 1;
     us->step.data_size += elem->data.undo_size;
   }
   MEM_freeN(objects);
+
+  bmain->is_memfile_undo_flush_needed = true;
+
   return true;
 }
 
-static void lattice_undosys_step_decode(struct bContext *C,
-                                        struct Main *UNUSED(bmain),
-                                        UndoStep *us_p,
-                                        int UNUSED(dir),
-                                        bool UNUSED(is_final))
+static void lattice_undosys_step_decode(
+    struct bContext *C, struct Main *bmain, UndoStep *us_p, int UNUSED(dir), bool UNUSED(is_final))
 {
   LatticeUndoStep *us = (LatticeUndoStep *)us_p;
 
@@ -210,6 +210,7 @@ static void lattice_undosys_step_decode(struct bContext *C,
       continue;
     }
     undolatt_to_editlatt(&elem->data, lt->editlatt);
+    lt->editlatt->needs_flush_to_id = 1;
     DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
   }
 
@@ -217,6 +218,8 @@ static void lattice_undosys_step_decode(struct bContext *C,
   ED_undo_object_set_active_or_warn(
       CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG);
 
+  bmain->is_memfile_undo_flush_needed = true;
+
   WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
 }
 
index 7071258d8cfda37284f2e17179960f714813d589..44984251243d9fb7653ea5ec58ad40386cb91df9 100644 (file)
@@ -34,6 +34,7 @@
 #include "BKE_context.h"
 #include "BKE_key.h"
 #include "BKE_layer.h"
+#include "BKE_main.h"
 #include "BKE_mesh.h"
 #include "BKE_editmesh.h"
 #include "BKE_undo_system.h"
@@ -708,9 +709,7 @@ static bool mesh_undosys_poll(bContext *C)
   return editmesh_object_from_context(C) != NULL;
 }
 
-static bool mesh_undosys_step_encode(struct bContext *C,
-                                     struct Main *UNUSED(bmain),
-                                     UndoStep *us_p)
+static bool mesh_undosys_step_encode(struct bContext *C, struct Main *bmain, UndoStep *us_p)
 {
   MeshUndoStep *us = (MeshUndoStep *)us_p;
 
@@ -730,18 +729,20 @@ static bool mesh_undosys_step_encode(struct bContext *C,
 
     elem->obedit_ref.ptr = ob;
     Mesh *me = elem->obedit_ref.ptr->data;
+    BMEditMesh *em = me->edit_mesh;
     undomesh_from_editmesh(&elem->data, me->edit_mesh, me->key);
+    em->needs_flush_to_id = 1;
     us->step.data_size += elem->data.undo_size;
   }
   MEM_freeN(objects);
+
+  bmain->is_memfile_undo_flush_needed = true;
+
   return true;
 }
 
-static void mesh_undosys_step_decode(struct bContext *C,
-                                     struct Main *UNUSED(bmain),
-                                     UndoStep *us_p,
-                                     int UNUSED(dir),
-                                     bool UNUSED(is_final))
+static void mesh_undosys_step_decode(
+    struct bContext *C, struct Main *bmain, UndoStep *us_p, int UNUSED(dir), bool UNUSED(is_final))
 {
   MeshUndoStep *us = (MeshUndoStep *)us_p;
 
@@ -765,6 +766,7 @@ static void mesh_undosys_step_decode(struct bContext *C,
     }
     BMEditMesh *em = me->edit_mesh;
     undomesh_to_editmesh(&elem->data, em, obedit->data);
+    em->needs_flush_to_id = 1;
     DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
   }
 
@@ -775,6 +777,8 @@ static void mesh_undosys_step_decode(struct bContext *C,
   Scene *scene = CTX_data_scene(C);
   scene->toolsettings->selectmode = us->elems[0].data.selectmode;
 
+  bmain->is_memfile_undo_flush_needed = true;
+
   WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
 }
 
index 9a95560ccdda043806259b264852acdcd12f1521..e8700e94e910d5714b678643b08adcd0f9c2ccd5 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "BKE_context.h"
 #include "BKE_layer.h"
+#include "BKE_main.h"
 #include "BKE_undo_system.h"
 
 #include "DEG_depsgraph.h"
@@ -153,9 +154,7 @@ static bool mball_undosys_poll(bContext *C)
   return editmball_object_from_context(C) != NULL;
 }
 
-static bool mball_undosys_step_encode(struct bContext *C,
-                                      struct Main *UNUSED(bmain),
-                                      UndoStep *us_p)
+static bool mball_undosys_step_encode(struct bContext *C, struct Main *bmain, UndoStep *us_p)
 {
   MBallUndoStep *us = (MBallUndoStep *)us_p;
 
@@ -176,17 +175,18 @@ static bool mball_undosys_step_encode(struct bContext *C,
     elem->obedit_ref.ptr = ob;
     MetaBall *mb = ob->data;
     editmball_from_undomball(&elem->data, mb);
+    mb->needs_flush_to_id = 1;
     us->step.data_size += elem->data.undo_size;
   }
   MEM_freeN(objects);
+
+  bmain->is_memfile_undo_flush_needed = true;
+
   return true;
 }
 
-static void mball_undosys_step_decode(struct bContext *C,
-                                      struct Main *UNUSED(bmain),
-                                      UndoStep *us_p,
-                                      int UNUSED(dir),
-                                      bool UNUSED(is_final))
+static void mball_undosys_step_decode(
+    struct bContext *C, struct Main *bmain, UndoStep *us_p, int UNUSED(dir), bool UNUSED(is_final))
 {
   MBallUndoStep *us = (MBallUndoStep *)us_p;
 
@@ -209,6 +209,7 @@ static void mball_undosys_step_decode(struct bContext *C,
       continue;
     }
     undomball_to_editmball(&elem->data, mb);
+    mb->needs_flush_to_id = 1;
     DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
   }
 
@@ -216,6 +217,8 @@ static void mball_undosys_step_decode(struct bContext *C,
   ED_undo_object_set_active_or_warn(
       CTX_data_view_layer(C), us->elems[0].obedit_ref.ptr, us_p->name, &LOG);
 
+  bmain->is_memfile_undo_flush_needed = true;
+
   WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
 }
 
index 70d024c7902e204e4174c8762f214156cd8d899f..be815fb0d10f5a9560f20856103547137bfec02e 100644 (file)
@@ -514,6 +514,11 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f
     }
   }
 
+  char *needs_flush_ptr = BKE_object_data_editmode_flush_ptr_get(obedit->data);
+  if (needs_flush_ptr) {
+    *needs_flush_ptr = false;
+  }
+
   return true;
 }
 
@@ -616,10 +621,13 @@ bool ED_object_editmode_enter_ex(Main *bmain, Scene *scene, Object *ob, int flag
     WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_MESH, NULL);
   }
   else if (ob->type == OB_ARMATURE) {
+    bArmature *arm = ob->data;
     ok = 1;
-    ED_armature_to_edit(ob->data);
+    ED_armature_to_edit(arm);
     /* to ensure all goes in restposition and without striding */
 
+    arm->needs_flush_to_id = 0;
+
     /* XXX: should this be ID_RECALC_GEOMETRY? */
     DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
 
@@ -632,9 +640,13 @@ bool ED_object_editmode_enter_ex(Main *bmain, Scene *scene, Object *ob, int flag
     WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_TEXT, scene);
   }
   else if (ob->type == OB_MBALL) {
+    MetaBall *mb = ob->data;
+
     ok = 1;
     ED_mball_editmball_make(ob);
 
+    mb->needs_flush_to_id = 0;
+
     WM_main_add_notifier(NC_SCENE | ND_MODE | NS_EDITMODE_MBALL, scene);
   }
   else if (ob->type == OB_LATTICE) {
index fc990c01bfbd5f5f6878bd2f27508c6814ee7a17..052f2bd03a479c342e5eb5d2b63105884240ed7c 100644 (file)
@@ -1027,6 +1027,8 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
   /* list is manipulated by multiple threads, so we lock */
   BLI_thread_lock(LOCK_CUSTOM1);
 
+  ss->needs_flush_to_id = 1;
+
   if (ss->bm || ELEM(type, SCULPT_UNDO_DYNTOPO_BEGIN, SCULPT_UNDO_DYNTOPO_END)) {
     /* Dynamic topology stores only one undo node per stroke,
      * regardless of the number of PBVH nodes modified */
@@ -1142,17 +1144,6 @@ typedef struct SculptUndoStep {
   UndoSculpt data;
 } SculptUndoStep;
 
-static bool sculpt_undosys_poll(bContext *C)
-{
-  Object *obact = CTX_data_active_object(C);
-  if (obact && obact->type == OB_MESH) {
-    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;
@@ -1161,7 +1152,7 @@ static void sculpt_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep
 }
 
 static bool sculpt_undosys_step_encode(struct bContext *UNUSED(C),
-                                       struct Main *UNUSED(bmain),
+                                       struct Main *bmain,
                                        UndoStep *us_p)
 {
   /* dummy, encoding is done along the way by adding tiles
@@ -1174,6 +1165,11 @@ static bool sculpt_undosys_step_encode(struct bContext *UNUSED(C),
     us->step.use_memfile_step = true;
   }
   us->step.is_applied = true;
+
+  if (!BLI_listbase_is_empty(&us->data.nodes)) {
+    bmain->is_memfile_undo_flush_needed = true;
+  }
+
   return true;
 }
 
@@ -1256,7 +1252,11 @@ static void sculpt_undosys_step_decode(
         me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
         ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, true, NULL);
       }
-      BLI_assert(sculpt_undosys_poll(C));
+
+      if (ob->sculpt) {
+        ob->sculpt->needs_flush_to_id = 1;
+      }
+      bmain->is_memfile_undo_flush_needed = true;
     }
     else {
       BLI_assert(0);
@@ -1295,7 +1295,6 @@ void ED_sculpt_undo_geometry_end(struct Object *ob)
 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;
index 315a4c73e5f6fb3f2737abb4256a8c33c45c8623..9770b52158ad6b752537664da168dd3cefe7fe08 100644 (file)
@@ -322,7 +322,7 @@ bool ED_undo_is_memfile_compatible(const bContext *C)
   if (view_layer != NULL) {
     Object *obact = OBACT(view_layer);
     if (obact != NULL) {
-      if (obact->mode & (OB_MODE_SCULPT | OB_MODE_EDIT)) {
+      if (obact->mode & OB_MODE_EDIT) {
         return false;
       }
     }
index f3e2ee92558a80f9723d7f8f6677b6d234a15f8e..a5f30409aa67f9f674c7c74a3b871ff6c5691074 100644 (file)
@@ -28,6 +28,7 @@
 #include "BKE_blender_undo.h"
 #include "BKE_context.h"
 #include "BKE_undo_system.h"
+#include "BKE_main.h"
 
 #include "WM_api.h"
 #include "WM_types.h"
@@ -74,6 +75,10 @@ static bool memfile_undosys_step_encode(struct bContext *UNUSED(C),
   /* Important we only use 'main' from the context (see: BKE_undosys_stack_init_from_main). */
   UndoStack *ustack = ED_undo_stack_get();
 
+  if (bmain->is_memfile_undo_flush_needed) {
+    ED_editors_flush_edits_ex(bmain, false, true);
+  }
+
   /* can be NULL, use when set. */
   MemFileUndoStep *us_prev = (MemFileUndoStep *)BKE_undosys_step_find_by_type(
       ustack, BKE_UNDOSYS_TYPE_MEMFILE);
index f5548119e0aa4606b8d04a49d3905308f7a715f0..1a33b50ff10fe90c32bc902ec58ad6772fecf819 100644 (file)
@@ -230,7 +230,7 @@ void ED_editors_exit(Main *bmain, bool do_undo_system)
 
 /* flush any temp data from object editing to DNA before writing files,
  * rendering, copying, etc. */
-bool ED_editors_flush_edits(Main *bmain, bool for_render)
+bool ED_editors_flush_edits_ex(Main *bmain, bool for_render, bool check_needs_flush)
 {
   bool has_edited = false;
   Object *ob;
@@ -244,6 +244,15 @@ bool ED_editors_flush_edits(Main *bmain, bool for_render)
        * Auto-save prevents this from happening but scripts
        * may cause a flush on saving: T53986. */
       if ((ob->sculpt && ob->sculpt->cache) == 0) {
+
+        {
+          char *needs_flush_ptr = &ob->sculpt->needs_flush_to_id;
+          if (check_needs_flush && (*needs_flush_ptr == 0)) {
+            continue;
+          }
+          *needs_flush_ptr = 0;
+        }
+
         /* flush multires changes (for sculpt) */
         multires_flush_sculpt_updates(ob);
         has_edited = true;
@@ -260,15 +269,31 @@ bool ED_editors_flush_edits(Main *bmain, bool for_render)
       }
     }
     else if (ob->mode & OB_MODE_EDIT) {
+
+      char *needs_flush_ptr = BKE_object_data_editmode_flush_ptr_get(ob->data);
+      if (needs_flush_ptr != NULL) {
+        if (check_needs_flush && (*needs_flush_ptr == 0)) {
+          continue;
+        }
+        *needs_flush_ptr = 0;
+      }
+
       /* get editmode results */
       has_edited = true;
       ED_object_editmode_load(bmain, ob);
     }
   }
 
+  bmain->is_memfile_undo_flush_needed = false;
+
   return has_edited;
 }
 
+bool ED_editors_flush_edits(Main *bmain, bool for_render)
+{
+  return ED_editors_flush_edits_ex(bmain, for_render, false);
+}
+
 /* ***** XXX: functions are using old blender names, cleanup later ***** */
 
 /* now only used in 2d spaces, like time, ipo, nla, sima... */
index 1b2345809ad2a8057f961eb7b31ddba6c84ed266..3bad2a04a65826054f283d5e35d94831e4661b6a 100644 (file)
@@ -126,6 +126,10 @@ typedef struct bArmature {
   /** Active editbone (in editmode). */
   struct EditBone *act_edbone;
 
+  /** ID data is older than edit-mode data (TODO: move to edit-mode struct). */
+  char needs_flush_to_id;
+  char _pad0[7];
+
   int flag;
   int drawtype;
 
index 7a641189bcbcfa62b124a15ddac8a0a1d18de1fd..13eaa8925bcb290feba7aaf1c6b7ee94010dce3a 100644 (file)
@@ -206,7 +206,12 @@ typedef struct EditNurb {
   /* shape key being edited */
   int shapenr;
 
-  char _pad[4];
+  /**
+   * ID data is older than edit-mode data.
+   * Set #Main.is_memfile_undo_flush_needed when enabling.
+   */
+  char needs_flush_to_id;
+
 } EditNurb;
 
 typedef struct Curve {
index 3864593158dfca949b20644faf8a7d01e350a763..f67553c34de2a6b9e44a66984bd0a4e4f0141be3 100644 (file)
@@ -39,6 +39,12 @@ typedef struct EditLatt {
   struct Lattice *latt;
 
   int shapenr;
+
+  /**
+   * ID data is older than edit-mode data.
+   * Set #Main.is_memfile_undo_flush_needed when enabling.
+   */
+  char needs_flush_to_id;
 } EditLatt;
 
 typedef struct Lattice {
index c98842eb6d74578714d2f2cd60225d352a1431bd..8b218dd7ce630554a2fd742c8877d773b8e5f3a1 100644 (file)
@@ -81,7 +81,13 @@ typedef struct MetaBall {
   short totcol;
   /** Used to store MB_AUTOSPACE. */
   short texflag;
-  char _pad[2];
+  char _pad[1];
+
+  /**
+   * ID data is older than edit-mode data (TODO: move to edit-mode struct).
+   * Set #Main.is_memfile_undo_flush_needed when enabling.
+   */
+  char needs_flush_to_id;
 
   /* texture space, copied as one block in editobject.c */
   float loc[3];