[Bf-blender-cvs] [582c30d32fb] temp_bmesh_multires: Fix nasty edge case for BMLog.

Joseph Eagar noreply at git.blender.org
Thu May 13 01:40:24 CEST 2021


Commit: 582c30d32fb12141ace4a4cfc66ece71191ab9ba
Author: Joseph Eagar
Date:   Tue May 11 22:57:06 2021 -0700
Branches: temp_bmesh_multires
https://developer.blender.org/rB582c30d32fb12141ace4a4cfc66ece71191ab9ba

Fix nasty edge case for BMLog.

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

M	source/blender/bmesh/intern/bmesh_log.c
M	source/blender/editors/sculpt_paint/sculpt_dyntopo.c
M	source/blender/editors/sculpt_paint/sculpt_undo.c

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

diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c
index f793561119a..a5ce2d67e0c 100644
--- a/source/blender/bmesh/intern/bmesh_log.c
+++ b/source/blender/bmesh/intern/bmesh_log.c
@@ -166,6 +166,8 @@ typedef struct {
 #define logkey_cmp BLI_ghashutil_intcmp
 
 static void full_copy_swap(BMesh *bm, BMLog *log, BMLogEntry *entry);
+static void full_copy_load(BMesh *bm, BMLog *log, BMLogEntry *entry);
+
 static void bm_log_entry_free(BMLogEntry *entry);
 
 static void *log_ghash_lookup(BMLog *log, GHash *gh, const void *key)
@@ -822,18 +824,11 @@ void BM_log_cleanup_entry(BMLogEntry *entry)
   }
 }
 
-/* Allocate and initialize a new BMLog using existing BMLogEntries
- *
- * The 'entry' should be the last entry in the BMLog. Its prev pointer
- * will be followed back to find the first entry.
- *
- * The unused IDs field of the log will be initialized by taking all
- * keys from all GHashes in the log entry.
- */
-BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry)
+BMLog *bm_log_from_existing_entries_create(BMesh *bm,
+                                           BMLog *log,
+                                           BMLogEntry *entry,
+                                           bool restore_ids)
 {
-  BMLog *log = BM_log_create(bm, -1);
-
   if (entry->prev) {
     log->current_entry = entry;
   }
@@ -871,21 +866,46 @@ BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry)
   return log;
 }
 
-BMLog *BM_log_unfreeze(BMesh *bm, BMLogEntry *entry)
+/* Allocate and initialize a new BMLog using existing BMLogEntries
+ *
+ * The 'entry' should be the last entry in the BMLog. Its prev pointer
+ * will be followed back to find the first entry.
+ *
+ * The unused IDs field of the log will be initialized by taking all
+ * keys from all GHashes in the log entry.
+ */
+BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry)
+{
+  BMLog *log = BM_log_create(bm, -1);
+  bm_log_from_existing_entries_create(bm, log, entry, true);
+
+  return log;
+}
+
+ATTR_NO_OPT BMLog *BM_log_unfreeze(BMesh *bm, BMLogEntry *entry)
 {
   if (!entry || !entry->log) {
     return NULL;
   }
 
-  if (!entry->log->frozen_full_mesh) {
-    return entry->log;
+  BMLogEntry *frozen = entry->log->frozen_full_mesh;
+  if (!frozen && entry->fully_copy) {
+    frozen = entry;
+  }
+
+  if (!frozen) {
+    return entry->log->bm == bm ? entry->log : NULL;
   }
 
-  full_copy_swap(bm, entry->log, entry->log->frozen_full_mesh);
+  entry->log->bm = bm;
 
-  entry->log->frozen_full_mesh->log = NULL;
-  bm_log_entry_free(entry->log->frozen_full_mesh);
-  entry->log->frozen_full_mesh = NULL;
+  full_copy_load(bm, entry->log, frozen);
+
+  if (entry->log->frozen_full_mesh) {
+    entry->log->frozen_full_mesh->log = NULL;
+    bm_log_entry_free(entry->log->frozen_full_mesh);
+    entry->log->frozen_full_mesh = NULL;
+  }
 
   return entry->log;
 }
@@ -898,11 +918,15 @@ void BM_log_free(BMLog *log, bool safe_mode)
   BMLogEntry *entry;
 
   if (safe_mode && log->refcount) {
-    if (!log->frozen_full_mesh) {
-      log->frozen_full_mesh = bm_log_entry_create();
-      bm_log_full_mesh_intern(log->bm, log, log->frozen_full_mesh);
+    if (log->frozen_full_mesh) {
+      log->frozen_full_mesh->log = NULL;
+      bm_log_entry_free(log->frozen_full_mesh);
     }
 
+    log->frozen_full_mesh = bm_log_entry_create();
+
+    bm_log_full_mesh_intern(log->bm, log, log->frozen_full_mesh);
+
     return;
   }
 
@@ -1158,6 +1182,63 @@ void BM_log_entry_drop(BMLogEntry *entry)
   bm_log_entry_free(entry);
   BLI_freelinkN(&log->entries, entry);
 }
+
+static void full_copy_load(BMesh *bm, BMLog *log, BMLogEntry *entry)
+{
+  CustomData_MeshMasks cd_mask_extra = {CD_MASK_DYNTOPO_VERT, 0, 0, 0, 0};
+
+  BM_mesh_clear(bm);
+  BM_mesh_bm_from_me(NULL,
+                     bm,
+                     entry->full_copy_mesh,
+                     (&(struct BMeshFromMeshParams){.calc_face_normal = false,
+                                                    .add_key_index = false,
+                                                    .use_shapekey = false,
+                                                    .active_shapekey = -1,
+
+                                                    .cd_mask_extra = cd_mask_extra,
+                                                    .copy_temp_cdlayers = true}));
+
+  bm->elem_index_dirty |= BM_VERT | BM_FACE;
+
+  BM_mesh_elem_table_ensure(bm, BM_VERT | BM_FACE);
+  BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE);
+
+  // restores ids
+  GHashIterator gi;
+  GHASH_ITER (gi, entry->full_copy_idmap) {
+    // uint id = POINTER_AS_UINT(BLI_ghashIterator_getKey(&gi));
+    uintptr_t id = (uintptr_t)BLI_ghashIterator_getKey(&gi);
+    uintptr_t key = (uintptr_t)BLI_ghashIterator_getValue(&gi);
+
+    uintptr_t idx = (key & ((1LL << 31LL) - 1LL));
+    uintptr_t type = key >> 31LL;
+    BMHeader *elem = NULL;
+
+    switch (type) {
+      case BM_VERT:
+        elem = &bm->vtable[idx]->head;
+        break;
+      case BM_FACE:
+        elem = &bm->ftable[idx]->head;
+        break;
+    }
+
+    if (elem) {
+      log_ghash_reinsert(log, log->id_to_elem, POINTER_FROM_UINT(id), elem, NULL, NULL);
+      log_ghash_reinsert(log, log->elem_to_id, elem, POINTER_FROM_UINT(id), NULL, NULL);
+    }
+    else {
+      // eek, error!
+      printf("bmlog error!\n");
+      log_ghash_remove(log, log->id_to_elem, (void *)id, NULL, NULL);
+    }
+  }
+
+  bm->elem_index_dirty |= BM_VERT | BM_EDGE | BM_FACE;
+  bm->elem_table_dirty |= BM_VERT | BM_EDGE | BM_FACE;
+}
+
 static void full_copy_swap(BMesh *bm, BMLog *log, BMLogEntry *entry)
 {
   CustomData_MeshMasks cd_mask_extra = {CD_MASK_DYNTOPO_VERT, 0, 0, 0, 0};
diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
index ee084cfc920..4b746757997 100644
--- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
@@ -26,11 +26,11 @@
 #include "BLI_alloca.h"
 #include "BLI_array.h"
 #include "BLI_blenlib.h"
+#include "BLI_compiler_attrs.h"
 #include "BLI_hash.h"
 #include "BLI_linklist.h"
 #include "BLI_math.h"
 #include "BLI_memarena.h"
-#include "BLI_compiler_attrs.h"
 #include "BLI_polyfill_2d.h"
 #include "BLI_task.h"
 
@@ -91,7 +91,7 @@ void SCULPT_dynamic_topology_triangulate(BMesh *bm)
   BMIter iter;
   BMFace *f;
 
-  BM_ITER_MESH(f, &iter, bm, BM_FACES_OF_MESH) {
+  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
     BM_elem_flag_enable(f, BM_ELEM_TAG);
   }
 
@@ -128,15 +128,15 @@ void SCULPT_dynamic_topology_triangulate(BMesh *bm)
     for (int i = 0; i < faces_array_tot; i++) {
       BMFace *f2 = faces_array[i];
 
-      //forcibly copy selection state
+      // forcibly copy selection state
       if (sel) {
         BM_face_select_set(bm, f2, true);
 
-        //restore original face selection state too, triangulate code unset it
+        // restore original face selection state too, triangulate code unset it
         BM_face_select_set(bm, f, true);
       }
 
-      //paranoia check that tag flag wasn't copied over
+      // paranoia check that tag flag wasn't copied over
       BM_elem_flag_disable(f2, BM_ELEM_TAG);
     }
   }
@@ -206,8 +206,10 @@ static char layer_id[] = "_dyntopo_node_id";
 void SCULPT_dyntopo_node_layers_update_offsets(SculptSession *ss)
 {
   SCULPT_dyntopo_node_layers_add(ss);
-  BKE_pbvh_update_offsets(
-      ss->pbvh, ss->cd_vert_node_offset, ss->cd_face_node_offset, ss->cd_dyn_vert);
+  if (ss->pbvh) {
+    BKE_pbvh_update_offsets(
+        ss->pbvh, ss->cd_vert_node_offset, ss->cd_face_node_offset, ss->cd_dyn_vert);
+  }
 }
 
 bool SCULPT_dyntopo_has_templayer(SculptSession *ss, int type, const char *name)
@@ -608,15 +610,26 @@ static void SCULPT_dynamic_topology_disable_ex(
   /* Clear data. */
   me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
 
+  bool disp_saved = false;
+
   if (ss->bm_log) {
+    if (ss->bm) {
+      disp_saved = true;
+
+      // rebuild ss->persistent_base if necassary
+      SCULPT_dyntopo_save_persistent_base(ss);
+    }
+
     BM_log_free(ss->bm_log, true);
     ss->bm_log = NULL;
   }
 
   /* Typically valid but with global-undo they can be NULL, see: T36234. */
   if (ss->bm) {
-    // rebuild ss->persistent_base if necassary
-    SCULPT_dyntopo_save_persistent_base(ss);
+    if (!disp_saved) {
+      // rebuild ss->persistent_base if necassary
+      SCULPT_dyntopo_save_persistent_base(ss);
+    }
 
     BM_mesh_free(ss->bm);
     ss->bm = NULL;
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index d0ab8c8e9b6..c9feb96e3a3 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -463,15 +463,21 @@ static void sculpt_undo_bmesh_enable(Object *ob, SculptUndoNode *unode)
 
   me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
 
-  /* Restore the BMLog using saved entries. */
-  ss->bm_log = BM_log_from_existing_entries_create(ss->bm, unode->bm_entry);
+  ss->bm_log = BM_log_unfreeze(ss->bm, unode->bm_entry);
+
+  if (!ss->bm_log) {
+    /* Restore the BMLog using saved entries. */
+    ss->bm_log = BM_log_from_existing_entries_create(ss->bm, unode->bm_entry);
+  }
+
+  SCULPT_dyntopo_node_layers_update_offsets(ss);
   BM_log_set_cd_offsets(ss->bm_log, ss->cd_dyn_vert);
 }
 
-static void sculpt_undo_bmesh_restore_begin(bContext *C,
-                                            SculptUndoNode *unode,
-                                            Object *ob,
-                                            SculptSession *ss)
+ATTR_NO_OPT static void sculpt_undo_bmesh_restore_begin(bContext *C,
+                                                        SculptUndoNode *unode,
+                                                        Object *ob,
+                                                        SculptSession *ss)
 {
   if (unode->applied) {
     SCULPT_dynamic_topology_disable(C, unode);
@@ -487,10 +493,10 @@ static void sculpt_undo_bmesh_restore_begin(bContext *C,
   }
 }
 
-static void sculpt_undo_bmesh_restore_end(bContext *C,
-                         

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list