Sculpt dyntopo: undo bugfixes

* Fixed nasty undo bug related
  to now rewinding BMLogEntry subchains properly.
* Fixed bug in dyntopo collapse
This commit is contained in:
Joseph Eagar 2021-08-27 01:51:56 -07:00
parent 31d2b04411
commit 019700583b
9 changed files with 293 additions and 87 deletions

View File

@ -159,6 +159,7 @@ static bool check_vert_fan_are_tris(PBVH *pbvh, BMVert *v);
static void pbvh_split_edges(
PBVH *pbvh, BMesh *bm, BMEdge **edges, int totedge, bool ignore_isolated_edges);
void bm_log_message(const char *fmt, ...);
void pbvh_bmesh_check_nodes_simple(PBVH *pbvh);
static BMEdge *bmesh_edge_create_log(PBVH *pbvh, BMVert *v1, BMVert *v2, BMEdge *e_example)
{
@ -804,7 +805,7 @@ static void pbvh_bmesh_face_remove(
else if (ensure_ownership_transfer && !BM_vert_face_count_is_equal(v, 1)) {
pbvh_bmesh_vert_remove(pbvh, v);
f_node->flag |= PBVH_RebuildNodeVerts;
f_node->flag |= PBVH_RebuildNodeVerts | PBVH_UpdateOtherVerts;
// printf("failed to find new_node\n");
}
}
@ -2391,6 +2392,8 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
check_vert_fan_are_tris(pbvh, e->v1);
check_vert_fan_are_tris(pbvh, e->v2);
// pbvh_bmesh_check_nodes_simple(pbvh);
bm_log_message(" == collapse == ");
// make sure origdata is up to date prior to interpolation
@ -2440,6 +2443,8 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
/* Remove the merge vertex from the PBVH */
pbvh_bmesh_vert_remove(pbvh, v_del);
// pbvh_bmesh_check_nodes_simple(pbvh);
/* Remove all faces adjacent to the edge */
BMLoop *l_adj;
while ((l_adj = e->l)) {
@ -2473,6 +2478,8 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
BM_face_kill(pbvh->bm, f_adj);
}
// pbvh_bmesh_check_nodes_simple(pbvh);
/* Kill the edge */
BLI_assert(BM_edge_is_wire(e));
@ -2553,6 +2560,8 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
//*/
}
// pbvh_bmesh_check_nodes_simple(pbvh);
#if 1
BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_del) {
BMFace *existing_face;
@ -2601,6 +2610,8 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
PBVHNode *n = pbvh_bmesh_node_from_face(pbvh, f);
int ni = n - pbvh->nodes;
n->flag |= PBVH_UpdateOtherVerts;
bm_edges_from_tri(pbvh, old_tri, e_tri);
bm_edges_from_tri_example(pbvh, v_tri, e_tri);
@ -2633,6 +2644,8 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
BM_LOOPS_OF_VERT_ITER_END;
#endif
// pbvh_bmesh_check_nodes_simple(pbvh);
/* Delete the tagged faces */
for (int i = 0; i < (int)deleted_faces->count; i++) {
BMFace *f_del = BLI_buffer_at(deleted_faces, BMFace *, i);
@ -2729,12 +2742,41 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
mv_conn->flag |= DYNVERT_NEED_DISK_SORT | DYNVERT_NEED_VALENCE | DYNVERT_NEED_BOUNDARY;
}
if (v_del->e) {
BMEdge *e = v_del->e;
do {
if (e->l) {
BMLoop *l = e->l;
do {
printf("error in collapse_edge\n");
int ni = BM_ELEM_CD_GET_INT(l->f, pbvh->cd_face_node_offset);
BM_log_face_removed(pbvh->bm_log, l->f);
if (ni >= 0) {
PBVHNode *node = pbvh->nodes + ni;
BLI_table_gset_remove(node->bm_faces, l->f, NULL);
BM_ELEM_CD_SET_INT(l->f, pbvh->cd_face_node_offset, DYNTOPO_NODE_NONE);
}
else {
printf("face did not have a node ref\n");
}
} while ((l = l->radial_next) != e->l);
}
e = BM_DISK_EDGE_NEXT(e, v_del);
} while (e != v_del->e);
}
/* Delete v_del */
pbvh_kill_vert(pbvh, v_del);
BLI_array_free(ws);
BLI_array_free(blocks);
BLI_array_free(ls);
// pbvh_bmesh_check_nodes_simple(pbvh);
}
static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,

View File

@ -79,9 +79,11 @@
#include "bmesh.h"
// XXX todo: work our bad module cross ref
// XXX todo: figure out bad cross module refs
void SCULPT_dynamic_topology_sync_layers(Object *ob, Mesh *me);
void SCULPT_on_sculptsession_bmesh_free(SculptSession *ss);
void SCULPT_dyntopo_node_layers_add(SculptSession *ss);
BMesh *SCULPT_dyntopo_empty_bmesh();
static void palette_init_data(ID *id)
{
@ -1383,17 +1385,29 @@ static void sculptsession_bm_to_me_update_data_only(Object *ob, bool reorder)
if (ss->bm) {
if (ob->data) {
if (reorder && ss->bm_log) {
BM_log_mesh_elems_reorder(ss->bm, ss->bm_log);
}
Mesh *me = BKE_object_get_original_mesh(ob);
BM_mesh_bm_to_me(NULL,
NULL,
ss->bm,
ob->data,
(&(struct BMeshToMeshParams){
.calc_object_remap = false,
}));
BM_mesh_bm_to_me(
NULL,
NULL,
ss->bm,
ob->data,
(&(struct BMeshToMeshParams){.calc_object_remap = false,
#ifdef WHEN_GLOBAL_UNDO_WORKS
/*
for memfile undo steps we need to
save id and temporary layers
*/
.copy_temp_cdlayers = true,
.copy_mesh_id_layers = true,
.cd_mask_extra = CD_MASK_MESH_ID | CD_MASK_DYNTOPO_VERT
#else
.copy_temp_cdlayers = false,
.copy_mesh_id_layers = false
#endif
}));
}
}
}
@ -2254,6 +2268,46 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
ob->sculpt->pbvh = pbvh;
}
else {
#ifdef WHEN_GLOBAL_UNDO_WORKS
/*detect if we are loading from an undo memfile step*/
Mesh *mesh_orig = BKE_object_get_original_mesh(ob);
bool is_dyntopo = (mesh_orig->flag & ME_SCULPT_DYNAMIC_TOPOLOGY);
is_dyntopo = is_dyntopo && CustomData_has_layer(&mesh_orig->vdata, CD_MESH_ID);
is_dyntopo = is_dyntopo && CustomData_has_layer(&mesh_orig->edata, CD_MESH_ID);
is_dyntopo = is_dyntopo && CustomData_has_layer(&mesh_orig->pdata, CD_MESH_ID);
if (is_dyntopo) {
BMesh *bm = SCULPT_dyntopo_empty_bmesh();
ob->sculpt->bm = bm;
BM_mesh_bm_from_me(NULL,
bm,
mesh_orig,
(&(struct BMeshFromMeshParams){.calc_face_normal = true,
.use_shapekey = true,
.active_shapekey = ob->shapenr,
.copy_id_layers = true,
.copy_temp_cdlayers = true,
.cd_mask_extra = CD_MASK_DYNTOPO_VERT}));
SCULPT_dyntopo_node_layers_add(ob->sculpt);
pbvh = build_pbvh_for_dynamic_topology(ob);
}
else {
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
Mesh *mesh_eval = object_eval->data;
if (mesh_eval->runtime.subdiv_ccg != NULL) {
pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime.subdiv_ccg, respect_hide);
}
else if (ob->type == OB_MESH) {
Mesh *me_eval_deform = object_eval->runtime.mesh_deform_eval;
pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform, respect_hide);
}
}
#else
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
Mesh *mesh_eval = object_eval->data;
if (mesh_eval->runtime.subdiv_ccg != NULL) {
@ -2263,6 +2317,7 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
Mesh *me_eval_deform = object_eval->runtime.mesh_deform_eval;
pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform, respect_hide);
}
#endif
}
ob->sculpt->pbvh = pbvh;

View File

@ -1418,7 +1418,9 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
for (int i = 0; i < node->tot_mat_draw_buffers; i++) {
if (i >= node->tot_tri_buffers) {
printf("pbvh corruption!\n");
printf("node->tot_mat_draw_buffers >= node->tot_tri_buffers! %d %d\n",
node->tot_mat_draw_buffers,
node->tot_tri_buffers);
continue;
}

View File

@ -70,6 +70,42 @@ Topology rake:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
static void _debugprint(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
void pbvh_bmesh_check_nodes_simple(PBVH *pbvh)
{
#if 0
for (int i = 0; i < pbvh->totnode; i++) {
PBVHNode *node = pbvh->nodes + i;
BMFace *f;
if (!(node->flag & PBVH_Leaf)) {
continue;
}
TGSET_ITER (f, node->bm_faces) {
if (!f || f->head.htype != BM_FACE) {
_debugprint("Corrupted (freed?) face in node->bm_faces\n");
continue;
}
if (BM_ELEM_CD_GET_INT(f, pbvh->cd_face_node_offset) != i) {
_debugprint("Face in more then one node\n");
}
}
TGSET_ITER_END;
}
#endif
}
void pbvh_bmesh_check_nodes(PBVH *pbvh)
{
#if 0
@ -88,11 +124,12 @@ void pbvh_bmesh_check_nodes(PBVH *pbvh)
int ni = BM_ELEM_CD_GET_INT(v, pbvh->cd_vert_node_offset);
if (ni >= 0 && !v->e || !v->e->l) {
printf("wire vert had node reference\n");
_debugprint("wire vert had node reference\n");
BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, DYNTOPO_NODE_NONE);
}
if (ni < -1 || ni >= pbvh->totnode) {
printf("vert node ref was invalid");
_debugprint("vert node ref was invalid");
continue;
}
@ -102,25 +139,25 @@ void pbvh_bmesh_check_nodes(PBVH *pbvh)
PBVHNode *node = pbvh->nodes + ni;
if (!(node->flag & PBVH_Leaf) || !node->bm_unique_verts) {
printf("vert node ref was in non leaf node");
_debugprint("vert node ref was in non leaf node");
continue;
}
if (!BLI_table_gset_haskey(node->bm_unique_verts, v)) {
printf("vert not in node->bm_unique_verts\n");
_debugprint("vert not in node->bm_unique_verts\n");
}
if (BLI_table_gset_haskey(node->bm_other_verts, v)) {
printf("vert in node->bm_other_verts");
_debugprint("vert in node->bm_other_verts");
}
MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v);
BKE_pbvh_bmesh_check_valence(pbvh, (SculptVertRef){.i = (intptr_t)v});
if (BM_vert_edge_count(v) != mv->valence) {
printf("cached vertex valence mismatch; old: %d, should be: %d\n",
mv->valence,
BM_vert_edge_count(v));
_debugprint("cached vertex valence mismatch; old: %d, should be: %d\n",
mv->valence,
BM_vert_edge_count(v));
}
}
@ -131,12 +168,12 @@ void pbvh_bmesh_check_nodes(PBVH *pbvh)
// delete nodes should
if (node->flag & PBVH_Delete) {
printf("orphaned delete node\n");
_debugprint("orphaned delete node\n");
}
if (!(node->flag & PBVH_Leaf)) {
if (node->bm_unique_verts || node->bm_other_verts || node->bm_faces) {
printf("dangling leaf pointers in non-leaf node\n");
_debugprint("dangling leaf pointers in non-leaf node\n");
}
continue;
@ -148,42 +185,43 @@ void pbvh_bmesh_check_nodes(PBVH *pbvh)
if (ni != i) {
if (ni >= 0 && ni < pbvh->totnode) {
PBVHNode *node2 = pbvh->nodes + ni;
printf("v node offset is wrong, %d\n",
!node2->bm_unique_verts ? 0 : BLI_table_gset_haskey(node2->bm_unique_verts, v));
_debugprint("v node offset is wrong, %d\n",
!node2->bm_unique_verts ? 0 :
BLI_table_gset_haskey(node2->bm_unique_verts, v));
}
else {
printf("v node offset is wrong\n");
_debugprint("v node offset is wrong\n");
}
}
if (!v || v->head.htype != BM_VERT) {
printf("corruption in pbvh! bm_unique_verts\n");
_debugprint("corruption in pbvh! bm_unique_verts\n");
}
else if (BLI_table_gset_haskey(node->bm_other_verts, v)) {
printf("v in both unique and other verts\n");
}
}
TGSET_ITER_END;
TGSET_ITER (v, node->bm_other_verts) {
if (!v || v->head.htype != BM_VERT) {
printf("corruption in pbvh! bm_other_verts\n");
}
else if (BLI_table_gset_haskey(node->bm_unique_verts, v)) {
printf("v in both unique and other verts\n");
_debugprint("v in both unique and other verts\n");
}
}
TGSET_ITER_END;
TGSET_ITER (f, node->bm_faces) {
if (!f || f->head.htype != BM_FACE) {
printf("corruption in pbvh! bm_faces\n");
_debugprint("corruption in pbvh! bm_faces\n");
continue;
}
int ni = BM_ELEM_CD_GET_INT(f, pbvh->cd_face_node_offset);
if (pbvh->nodes + ni != node) {
printf("face in multiple nodes!\n");
_debugprint("face in multiple nodes!\n");
}
}
TGSET_ITER_END;
TGSET_ITER (v, node->bm_other_verts) {
if (!v || v->head.htype != BM_VERT) {
_debugprint("corruption in pbvh! bm_other_verts\n");
}
else if (BLI_table_gset_haskey(node->bm_unique_verts, v)) {
_debugprint("v in both unique and other verts\n");
}
}
TGSET_ITER_END;
@ -489,7 +527,7 @@ void bke_pbvh_insert_face_finalize(PBVH *pbvh, BMFace *f, const int ni)
BLI_table_gset_add(node->bm_faces, f);
int updateflag = PBVH_UpdateTris | PBVH_UpdateBB | PBVH_UpdateDrawBuffers |
PBVH_UpdateCurvatureDir;
PBVH_UpdateCurvatureDir | PBVH_UpdateOtherVerts;
updateflag |= PBVH_UpdateColor | PBVH_UpdateMask | PBVH_UpdateNormals | PBVH_UpdateOriginalBB;
updateflag |= PBVH_UpdateVisibility | PBVH_UpdateRedraw;

View File

@ -867,13 +867,19 @@ static void bm_log_faces_restore(
}
if (v->head.htype != BM_VERT) {
printf("bm_log corruption!\n");
printf("vert %d in face %d was not a vertex\n", (int)lf->v_ids[i], POINTER_AS_INT(key));
continue;
}
BLI_array_append(vs_tmp, v);
}
BMFace *f = BM_face_create_verts(bm, vs_tmp, (int)lf->len, NULL, BM_CREATE_SKIP_ID, true);
if ((int)BLI_array_len(vs_tmp) < 2) {
printf("severely malformed face %d in %s\n", POINTER_AS_INT(key), __func__);
continue;
}
BMFace *f = BM_face_create_verts(
bm, vs_tmp, (int)BLI_array_len(vs_tmp), NULL, BM_CREATE_SKIP_ID, true);
f->head.hflag = lf->hflag;
copy_v3_v3(f->no, lf->no);
@ -917,6 +923,11 @@ static void bm_log_vert_values_swap(
uint id = POINTER_AS_UINT(key);
BMVert *v = bm_log_vert_from_id(log, id);
if (!v) {
printf("missing vert in bmlog! %d", id);
continue;
}
swap_v3_v3(v->co, lv->co);
swap_v3_v3(v->no, lv->no);
@ -1370,25 +1381,23 @@ void BM_log_print_entry(BMLog *log, BMLogEntry *entry)
printf("==element IDs snapshot\n");
break;
case LOG_ENTRY_PARTIAL:
printf(" ==entry==\n");
printf(" modified:\n");
printf(" verts: %d\n", BLI_ghash_len(first->modified_verts));
printf(" edges: %d\n", BLI_ghash_len(first->modified_edges));
printf(" faces: %d\n", BLI_ghash_len(first->modified_faces));
printf(" new:\n");
printf(" verts: %d\n", BLI_ghash_len(first->added_verts));
printf(" edges: %d\n", BLI_ghash_len(first->added_edges));
printf(" faces: %d\n", BLI_ghash_len(first->added_faces));
printf(" deleted:\n");
printf(" verts: %d\n", BLI_ghash_len(first->deleted_verts));
printf(" edges: %d\n", BLI_ghash_len(first->deleted_edges));
printf("post edges: %d\n", BLI_ghash_len(first->deleted_edges_post));
printf(" faces: %d\n", BLI_ghash_len(first->deleted_faces));
printf("==modified: ");
printf("v: %d ", BLI_ghash_len(first->modified_verts));
printf("e: %d ", BLI_ghash_len(first->modified_edges));
printf("f: %d ", BLI_ghash_len(first->modified_faces));
printf(" new: ");
printf("v: %d ", BLI_ghash_len(first->added_verts));
printf("e: %d ", BLI_ghash_len(first->added_edges));
printf("f: %d ", BLI_ghash_len(first->added_faces));
printf(" deleted: ");
printf("v: %d ", BLI_ghash_len(first->deleted_verts));
printf("e: %d ", BLI_ghash_len(first->deleted_edges));
printf("pe: %d ", BLI_ghash_len(first->deleted_edges_post));
printf("f: %d ", BLI_ghash_len(first->deleted_faces));
printf("\n");
break;
}
printf("\n");
first = first->combined_next;
}
}
@ -1585,6 +1594,11 @@ void BM_log_entry_drop(BMLogEntry *entry)
{
BMLog *log = entry->log;
// go to head of entry subgroup
while (entry->combined_next) {
entry = entry->combined_next;
}
if (!log) {
/* Unlink */
BLI_assert(!(entry->prev && entry->next));
@ -2469,14 +2483,31 @@ void BM_log_face_removed(BMLog *log, BMFace *f)
!!log_ghash_haskey(log, entry->added_faces, key));
if (!log_ghash_remove(log, entry->added_faces, key, NULL, NULL)) {
BMLogFace *lf;
BMLogFace *lf = bm_log_face_alloc(log, f);
lf = bm_log_face_alloc(log, f);
log_ghash_insert(log, entry->deleted_faces, key, lf);
void **val;
if (BLI_ghash_ensure_p(entry->deleted_faces, key, &val)) {
BMLogFace *lf2 = (BMLogFace *)*val;
if (lf2->customdata_f) {
// BLI_mempool_free(entry->pdata.pool, lf2->customdata_f);
CustomData_bmesh_free_block(&entry->pdata, &lf2->customdata_f);
}
for (uint i = 0; i < lf2->len; i++) {
if (lf2->customdata[i]) {
CustomData_bmesh_free_block(&entry->ldata, &lf2->customdata[i]);
}
}
BLI_mempool_free(entry->pool_faces, (void *)lf2);
}
if (lf) {
bm_log_face_customdata(log->bm, log, f, lf);
}
*val = lf;
}
}

View File

@ -229,25 +229,10 @@ void BM_enter_multires_space(Object *ob, BMesh *bm, int space)
* \warning This function doesn't calculate face normals.
*/
/* joeedh:
GCC under linux is doing something very weird. In the line below:
MultiresModifierData *mmd = ob ? get_multires_modifier(NULL, ob, true) : NULL;
ob is evaulating to true when optimizations are on. The following code:
printf("ob: %p, %s\n", ob, ob ? "true" : "false");
will print (nil), true. Very strange!
*/
#ifdef __GNUC__
__attribute__((optimize("O0")))
#endif
void BM_mesh_bm_from_me(Object *ob,
BMesh *bm,
const Mesh *me,
const struct BMeshFromMeshParams *params)
BMesh *bm,
const Mesh *me,
const struct BMeshFromMeshParams *params)
{
const bool is_new = !(bm->totvert || (bm->vdata.totlayer || bm->edata.totlayer ||
bm->pdata.totlayer || bm->ldata.totlayer));
@ -413,6 +398,7 @@ void BM_mesh_bm_from_me(Object *ob,
BM_mesh_cd_flag_apply(bm, me->cd_flag);
}
int *existing_id_layers[4] = {NULL, NULL, NULL, NULL};
int use_exist_ids = 0;
int has_ids = bm->idmap.flag & BM_HAS_IDS ?
(bm->idmap.flag & (BM_VERT | BM_EDGE | BM_LOOP | BM_FACE)) :
@ -423,9 +409,9 @@ void BM_mesh_bm_from_me(Object *ob,
const CustomData *cdatas[] = {&me->vdata, &me->edata, &me->ldata, &me->pdata};
for (int i = 0; i < 4; i++) {
int idx = CustomData_get_layer_index(cdatas[i], CD_MESH_ID);
existing_id_layers[i] = (int *)CustomData_get_layer(cdatas[i], CD_MESH_ID);
if (idx >= 0) {
if (existing_id_layers[i]) {
use_exist_ids |= 1 << i;
}
}
@ -467,7 +453,7 @@ void BM_mesh_bm_from_me(Object *ob,
if (has_ids & BM_VERT) {
if (use_exist_ids & BM_VERT) {
bm_assign_id(bm, (BMElem *)v, BM_ELEM_GET_ID(bm, v));
bm_assign_id(bm, (BMElem *)v, existing_id_layers[0][i]);
}
else {
bm_alloc_id(bm, (BMElem *)v);
@ -516,7 +502,7 @@ void BM_mesh_bm_from_me(Object *ob,
if (has_ids & BM_EDGE) {
if (use_exist_ids & BM_EDGE) {
bm_assign_id(bm, (BMElem *)e, BM_ELEM_GET_ID(bm, e));
bm_assign_id(bm, (BMElem *)e, existing_id_layers[1][i]);
}
else {
bm_alloc_id(bm, (BMElem *)e);
@ -587,7 +573,7 @@ void BM_mesh_bm_from_me(Object *ob,
if (has_ids & BM_LOOP) {
if (use_exist_ids & BM_LOOP) {
bm_assign_id(bm, (BMElem *)l_iter, BM_ELEM_GET_ID(bm, l_iter));
bm_assign_id(bm, (BMElem *)l_iter, existing_id_layers[2][j - 1]);
}
else {
bm_alloc_id(bm, (BMElem *)l_iter);
@ -600,7 +586,7 @@ void BM_mesh_bm_from_me(Object *ob,
if (has_ids & BM_FACE) {
if (use_exist_ids & BM_FACE) {
bm_assign_id(bm, (BMElem *)f, BM_ELEM_GET_ID(bm, f));
bm_assign_id(bm, (BMElem *)f, existing_id_layers[3][i]);
}
else {
bm_alloc_id(bm, (BMElem *)f);

View File

@ -50,7 +50,7 @@ struct Object;
void BM_mesh_bm_from_me(struct Object *ob,
BMesh *bm,
const struct Mesh *me,
const struct BMeshFromMeshParams *params) ATTR_NONNULL(2, 3);
const struct BMeshFromMeshParams *params) ATTR_NONNULL(2, 4);
struct BMeshToMeshParams {
/** Update object hook indices & vertex parents. */

View File

@ -83,6 +83,18 @@
#include <math.h>
#include <stdlib.h>
BMesh *SCULPT_dyntopo_empty_bmesh()
{
BMesh *bm = BM_mesh_create(
&bm_mesh_allocsize_default,
&((struct BMeshCreateParams){.use_toolflags = false,
.use_unique_ids = true,
.use_id_elem_mask = BM_VERT | BM_EDGE | BM_FACE,
.use_id_map = true,
.no_reuse_ids = false}));
return bm;
}
// TODO: check if (mathematically speaking) is it really necassary
// to sort the edge lists around verts

View File

@ -521,10 +521,28 @@ static void bmesh_undo_on_edge_change(BMEdge *v, void *userdata, void *old_custo
static void bmesh_undo_on_edge_kill(BMEdge *e, void *userdata)
{
BmeshUndoData *data = (BmeshUndoData *)userdata;
MDynTopoVert *mv1 = BKE_PBVH_DYNVERT(data->cd_dyn_vert, e->v1);
MDynTopoVert *mv2 = BKE_PBVH_DYNVERT(data->cd_dyn_vert, e->v2);
mv1->flag |= DYNVERT_NEED_BOUNDARY | DYNVERT_NEED_TRIANGULATE | DYNVERT_NEED_DISK_SORT |
DYNVERT_NEED_VALENCE;
mv2->flag |= DYNVERT_NEED_BOUNDARY | DYNVERT_NEED_TRIANGULATE | DYNVERT_NEED_DISK_SORT |
DYNVERT_NEED_VALENCE;
}
static void bmesh_undo_on_edge_add(BMEdge *e, void *userdata)
{
BmeshUndoData *data = (BmeshUndoData *)userdata;
MDynTopoVert *mv1 = BKE_PBVH_DYNVERT(data->cd_dyn_vert, e->v1);
MDynTopoVert *mv2 = BKE_PBVH_DYNVERT(data->cd_dyn_vert, e->v2);
mv1->flag |= DYNVERT_NEED_BOUNDARY | DYNVERT_NEED_TRIANGULATE | DYNVERT_NEED_DISK_SORT |
DYNVERT_NEED_VALENCE;
mv2->flag |= DYNVERT_NEED_BOUNDARY | DYNVERT_NEED_TRIANGULATE | DYNVERT_NEED_DISK_SORT |
DYNVERT_NEED_VALENCE;
}
static void bmesh_undo_on_vert_change(BMVert *v, void *userdata, void *old_customdata)
@ -884,6 +902,14 @@ static void sculpt_undo_geometry_restore(SculptUndoNode *unode, Object *object)
static int sculpt_undo_bmesh_restore(
bContext *C, SculptUndoNode *unode, Object *ob, SculptSession *ss, int dir)
{
// handle transition from another undo type
#ifdef WHEN_GLOBAL_UNDO_WORKS
if (!ss->bm_log && ss->bm && unode->bm_entry) { // && BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
ss->bm_log = BM_log_from_existing_entries_create(ss->bm, unode->bm_entry);
}
#endif
if (ss->bm_log && ss->bm &&
!ELEM(unode->type, SCULPT_UNDO_DYNTOPO_BEGIN, SCULPT_UNDO_DYNTOPO_END)) {
SCULPT_dyntopo_node_layers_update_offsets(ss);
@ -2149,9 +2175,12 @@ static void sculpt_undosys_step_decode(
BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
Mesh *me = ob->data;
#ifndef WHEN_GLOBAL_UNDO_WORKS
/* Don't add sculpt topology undo steps when reading back undo state.
* The undo steps must enter/exit for us. */
me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
#endif
ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, true, NULL);
}
@ -2376,6 +2405,12 @@ static void print_sculpt_undo_step(UndoStep *us, UndoStep *active, int i)
SculptUndoNode *node;
if (us->type != BKE_UNDOSYS_TYPE_SCULPT) {
printf("%d %s (non-sculpt): '%s', type:%s, use_memfile_step:%s\n",
i,
us == active ? "->" : " ",
us->name,
us->type->name,
us->use_memfile_step ? "true" : "false");
return;
}
@ -2388,7 +2423,12 @@ static void print_sculpt_undo_step(UndoStep *us, UndoStep *active, int i)
id = su->id;
printf("id=%d %s %d %s\n", id, us == active ? "->" : " ", i, us->name);
printf("id=%d %s %d %s (use_memfile_step=%s)\n",
id,
us == active ? "->" : " ",
i,
us->name,
us->use_memfile_step ? "true" : "false");
if (us->type == BKE_UNDOSYS_TYPE_SCULPT) {
UndoSculpt *usculpt = sculpt_undosys_step_get_nodes(us);