Fix nasty edge case for BMLog.
This commit is contained in:
parent
b047b333b0
commit
582c30d32f
|
@ -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;
|
||||
}
|
||||
|
||||
full_copy_swap(bm, entry->log, entry->log->frozen_full_mesh);
|
||||
if (!frozen) {
|
||||
return entry->log->bm == bm ? entry->log : NULL;
|
||||
}
|
||||
|
||||
entry->log->frozen_full_mesh->log = NULL;
|
||||
bm_log_entry_free(entry->log->frozen_full_mesh);
|
||||
entry->log->frozen_full_mesh = NULL;
|
||||
entry->log->bm = bm;
|
||||
|
||||
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};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
SculptUndoNode *unode,
|
||||
Object *ob,
|
||||
SculptSession *ss)
|
||||
ATTR_NO_OPT static void sculpt_undo_bmesh_restore_end(bContext *C,
|
||||
SculptUndoNode *unode,
|
||||
Object *ob,
|
||||
SculptSession *ss)
|
||||
{
|
||||
if (unode->applied) {
|
||||
sculpt_undo_bmesh_enable(ob, unode);
|
||||
|
@ -506,7 +512,9 @@ static void sculpt_undo_bmesh_restore_end(bContext *C,
|
|||
unode->applied = true;
|
||||
}
|
||||
|
||||
BM_mesh_elem_index_ensure(ss->bm, BM_VERT);
|
||||
if (ss->bm) {
|
||||
BM_mesh_elem_index_ensure(ss->bm, BM_VERT);
|
||||
}
|
||||
}
|
||||
|
||||
static void sculpt_undo_geometry_store_data(SculptUndoNodeGeometry *geometry, Object *object)
|
||||
|
@ -593,10 +601,10 @@ static void sculpt_undo_geometry_restore(SculptUndoNode *unode, Object *object)
|
|||
*
|
||||
* Returns true if this was a dynamic-topology undo step, otherwise
|
||||
* returns false to indicate the non-dyntopo code should run. */
|
||||
static int sculpt_undo_bmesh_restore(bContext *C,
|
||||
SculptUndoNode *unode,
|
||||
Object *ob,
|
||||
SculptSession *ss)
|
||||
ATTR_NO_OPT static int sculpt_undo_bmesh_restore(bContext *C,
|
||||
SculptUndoNode *unode,
|
||||
Object *ob,
|
||||
SculptSession *ss)
|
||||
{
|
||||
if (ss->bm_log && ss->bm) {
|
||||
SCULPT_dyntopo_node_layers_update_offsets(ss);
|
||||
|
@ -610,7 +618,9 @@ static int sculpt_undo_bmesh_restore(bContext *C,
|
|||
return true;
|
||||
|
||||
case SCULPT_UNDO_DYNTOPO_END:
|
||||
sculpt_undo_bmesh_restore_end(C, unode, ob, ss);
|
||||
if (ss->bm) {
|
||||
sculpt_undo_bmesh_restore_end(C, unode, ob, ss);
|
||||
}
|
||||
SCULPT_vertex_random_access_ensure(ss);
|
||||
return true;
|
||||
default:
|
||||
|
@ -671,15 +681,19 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
|
|||
|
||||
SCULPT_dynamic_topology_enable_ex(CTX_data_main(C), depsgraph, scene, ob);
|
||||
|
||||
//see if we have a saved log in the entry
|
||||
ss->bm_log = BM_log_unfreeze(ss->bm, unode->bm_entry);
|
||||
// see if we have a saved log in the entry
|
||||
BMLog *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);
|
||||
if (log) {
|
||||
if (ss->bm_log) {
|
||||
BM_log_free(ss->bm_log, false);
|
||||
}
|
||||
|
||||
ss->bm_log = log;
|
||||
|
||||
SCULPT_dyntopo_node_layers_update_offsets(ss);
|
||||
BM_log_set_cd_offsets(ss->bm_log, ss->cd_dyn_vert);
|
||||
}
|
||||
|
||||
BM_log_set_cd_offsets(ss->bm_log, ss->cd_dyn_vert);
|
||||
}
|
||||
|
||||
/* Restore pivot. */
|
||||
|
@ -1293,7 +1307,7 @@ static SculptUndoNode *sculpt_undo_face_sets_push(Object *ob, SculptUndoType typ
|
|||
return unode;
|
||||
}
|
||||
|
||||
static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, SculptUndoType type)
|
||||
ATTR_NO_OPT static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, SculptUndoType type)
|
||||
{
|
||||
UndoSculpt *usculpt = sculpt_undo_get_nodes();
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
@ -1313,7 +1327,9 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
|
|||
|
||||
if (type == SCULPT_UNDO_DYNTOPO_END) {
|
||||
unode->bm_entry = BM_log_entry_add(ss->bm, ss->bm_log);
|
||||
BM_log_before_all_removed(ss->bm, ss->bm_log);
|
||||
BM_log_full_mesh(ss->bm, ss->bm_log);
|
||||
|
||||
// BM_log_before_all_removed(ss->bm, ss->bm_log);
|
||||
}
|
||||
else if (type == SCULPT_UNDO_DYNTOPO_BEGIN) {
|
||||
/* Store a copy of the mesh's current vertices, loops, and
|
||||
|
@ -1325,7 +1341,8 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
|
|||
sculpt_undo_geometry_store_data(geometry, ob);
|
||||
|
||||
unode->bm_entry = BM_log_entry_add(ss->bm, ss->bm_log);
|
||||
BM_log_all_added(ss->bm, ss->bm_log);
|
||||
//BM_log_all_added(ss->bm, ss->bm_log);
|
||||
BM_log_full_mesh(ss->bm, ss->bm_log);
|
||||
}
|
||||
else {
|
||||
unode->bm_entry = BM_log_entry_add(ss->bm, ss->bm_log);
|
||||
|
|
Loading…
Reference in New Issue