Sculpt-dev: Cleanup of edge collapse

Still a work in progress.
This commit is contained in:
Joseph Eagar 2022-12-20 02:54:34 -08:00
parent bb764e418a
commit a5bddb4364
6 changed files with 155 additions and 91 deletions

View File

@ -2263,6 +2263,8 @@ static bool check_face_is_tri(PBVH *pbvh, BMFace *f)
ATTR_NO_OPT static bool destroy_nonmanifold_fins(PBVH *pbvh, BMEdge *e_root)
{
return false;
bm_logstack_push();
static int max_faces = 64;
@ -2270,8 +2272,7 @@ ATTR_NO_OPT static bool destroy_nonmanifold_fins(PBVH *pbvh, BMEdge *e_root)
BMLoop *l = e_root->l;
Vector<BMLoop *, 5> ls;
Vector<BMFace *, 32> fs;
int minfs = INT_MAX;
Vector<BMFace *, 32> minfs;
if (!l) {
bm_logstack_pop();
@ -2309,7 +2310,7 @@ ATTR_NO_OPT static bool destroy_nonmanifold_fins(PBVH *pbvh, BMEdge *e_root)
void **val = nullptr;
BMFace *f2 = l->radial_next->f;
if (!visit.lookup_key_or_add(f2)) {
if (visit.add(f2)) {
if (fs2.size() > max_faces) {
bad = true;
break;
@ -2325,17 +2326,8 @@ ATTR_NO_OPT static bool destroy_nonmanifold_fins(PBVH *pbvh, BMEdge *e_root)
}
}
if (!bad && fs2.size() < minfs) {
#if 0
if (fs2.size() > 0) {
fs.resize(fs2.size());
memcpy((void *)&fs[0], (void *)&fs2[0], sizeof(void *) * fs2.size());
} else {
fs.clear();
}
#endif
fs = fs2;
minfs = fs.size();
if (!bad && fs2.size() && (minfs.size() == 0 || fs2.size() < minfs.size())) {
minfs = fs2;
}
}
@ -2343,19 +2335,28 @@ ATTR_NO_OPT static bool destroy_nonmanifold_fins(PBVH *pbvh, BMEdge *e_root)
PBVH_UpdateTriAreas;
nupdateflag = nupdateflag | PBVH_UpdateNormals | PBVH_UpdateTris | PBVH_RebuildDrawBuffers;
if (!fs.size()) {
if (!minfs.size()) {
bm_logstack_pop();
return false;
}
printf("manifold fin size: %d\n", fs.size());
printf("manifold fin size: %d\n", minfs.size());
const int tag = BM_ELEM_TAG_ALT;
for (int i = 0; i < fs.size(); i++) {
BMFace *f = fs[i];
for (int i = 0; i < minfs.size(); i++) {
BMFace *f = minfs[i];
BMLoop *l = f->l_first;
do {
BMLoop *l2 = l;
do {
BMLoop *l3 = l2;
do {
l3->v->head.hflag &= ~tag;
l3->e->head.hflag &= ~tag;
} while ((l3 = l3->next) != l2);
} while ((l2 = l2->radial_next) != l);
l->v->head.hflag &= ~tag;
l->e->head.hflag &= ~tag;
} while ((l = l->next) != f->l_first);
@ -2364,8 +2365,8 @@ ATTR_NO_OPT static bool destroy_nonmanifold_fins(PBVH *pbvh, BMEdge *e_root)
Vector<BMVert *, 32> vs;
Vector<BMEdge *, 32> es;
for (int i = 0; i < fs.size(); i++) {
BMFace *f = fs[i];
for (int i = 0; i < minfs.size(); i++) {
BMFace *f = minfs[i];
BMLoop *l = f->l_first;
do {
@ -2381,17 +2382,17 @@ ATTR_NO_OPT static bool destroy_nonmanifold_fins(PBVH *pbvh, BMEdge *e_root)
} while ((l = l->next) != f->l_first);
}
for (int i = 0; i < minfs; i++) {
for (int j = 0; j < minfs; j++) {
if (i != j && fs[i] == fs[j]) {
for (int i = 0; i < minfs.size(); i++) {
for (int j = 0; j < minfs.size(); j++) {
if (i != j && minfs[i] == minfs[j]) {
printf("%s: duplicate faces\n", __func__);
continue;
}
}
}
for (int i = 0; i < minfs; i++) {
BMFace *f = fs[i];
for (int i = 0; i < minfs.size(); i++) {
BMFace *f = minfs[i];
if (f->head.htype != BM_FACE) {
printf("%s: corruption!\n", __func__);
@ -3167,6 +3168,7 @@ static bool bm_edge_collapse_is_degenerate_topology(BMEdge *e_first)
typedef struct TraceData {
PBVH *pbvh;
SmallHash visit;
blender::Set<void *> visit2;
BMEdge *e;
} TraceData;
@ -3240,6 +3242,10 @@ ATTR_NO_OPT void col_on_vert_add(BMesh *bm, BMVert *v, void *userdata)
TraceData *data = (TraceData *)userdata;
PBVH *pbvh = data->pbvh;
if (!data->visit2.add(static_cast<void *>(v))) {
// return;
}
pbvh_boundary_update_bmesh(pbvh, v);
MSculptVert *mv = (MSculptVert *)BM_ELEM_CD_GET_VOID_P(v, data->pbvh->cd_sculpt_vert);
@ -3254,6 +3260,10 @@ ATTR_NO_OPT void col_on_edge_add(BMesh *bm, BMEdge *e, void *userdata)
TraceData *data = (TraceData *)userdata;
PBVH *pbvh = data->pbvh;
if (!data->visit2.add(static_cast<void *>(e))) {
// return;
}
collapse_restore_id(pbvh->bm_idmap, (BMElem *)e);
BM_log_edge_post(pbvh->bm_log, e);
}
@ -3263,6 +3273,10 @@ ATTR_NO_OPT void col_on_face_add(BMesh *bm, BMFace *f, void *userdata)
TraceData *data = (TraceData *)userdata;
PBVH *pbvh = data->pbvh;
if (!data->visit2.add(static_cast<void *>(f))) {
// return;
}
if (bm_elem_is_free((BMElem *)f, BM_FACE)) {
printf("%s: error, f was freed!\n", __func__);
return;
@ -3864,7 +3878,6 @@ ATTR_NO_OPT static BMVert *pbvh_bmesh_collapse_edge(PBVH *pbvh,
const int facetag = COLLAPSE_FACE_TAG;
const int log_rings = 1;
edge_ring_do(e, collapse_ring_callback_pre2, &tdata, tag, facetag, log_rings - 1);
// edge_ring_do(e, collapse_ring_callback_pre, &tdata, tag, facetag, log_rings - 1);
pbvh_bmesh_vert_remove(pbvh, v_del);
@ -3881,6 +3894,8 @@ ATTR_NO_OPT static BMVert *pbvh_bmesh_collapse_edge(PBVH *pbvh,
BM_idmap_release(pbvh->bm_idmap, (BMElem *)v_del, true);
#endif
// edge_ring_do(e, collapse_ring_callback_pre2, &tdata, tag, facetag, log_rings - 1);
if (deleted_verts) {
BLI_ghash_insert(deleted_verts, (void *)v_del, nullptr);
}
@ -3957,7 +3972,7 @@ ATTR_NO_OPT static BMVert *pbvh_bmesh_collapse_edge(PBVH *pbvh,
MV_ADD_FLAG(mv_conn, mupdateflag);
#if 1
#if 0
e2 = v_conn->e;
BMEdge *enext;
do {
@ -3976,9 +3991,7 @@ ATTR_NO_OPT static BMVert *pbvh_bmesh_collapse_edge(PBVH *pbvh,
} while (v_conn->e && (e2 = enext) != v_conn->e);
#endif
// vert_ring_do(v_conn, collapse_ring_callback_post, &tdata, tag, facetag, log_rings - 1);
{
if (0) {
BMElem *elem = nullptr;
SmallHashIter siter;
void **val = BLI_smallhash_iternew_p(&tdata.visit, &siter, (uintptr_t *)&elem);
@ -4020,7 +4033,10 @@ ATTR_NO_OPT static BMVert *pbvh_bmesh_collapse_edge(PBVH *pbvh,
pbvh_bmesh_vert_remove(pbvh, v_conn);
}
// if (!BLI_smallhash_lookup(&tdata.visit, (intptr_t)v_conn)) {
BM_log_vert_removed(pbvh->bm_log, v_conn, 0);
//}
#ifdef USE_NEW_IDMAP
BM_idmap_release(pbvh->bm_idmap, (BMElem *)v_conn, true);
#endif
@ -4858,10 +4874,14 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
break;
}
printf("\n");
modified = true;
pbvh_bmesh_collapse_edge(pbvh, e, e->v1, e->v2, nullptr, nullptr, &eq_ctx);
VALIDATE_LOG(pbvh->bm_log);
printf("\n");
// XXX
BM_log_entry_add_ex(pbvh->header.bm, pbvh->bm_log, true);
break;
}
default:

View File

@ -3217,7 +3217,8 @@ BMesh *BKE_sculptsession_empty_bmesh_create()
params.id_elem_mask = BM_VERT | BM_EDGE | BM_FACE;
params.id_map = true;
params.temporary_ids = false;
params.no_reuse_ids = false;
params.no_reuse_ids = true; //XXX
BMesh *bm = BM_mesh_create(&allocsize, &params);
@ -3464,15 +3465,23 @@ ATTR_NO_OPT static bool sculpt_attr_update(Object *ob, SculptAttribute *attr)
}
}
PBVHType pbvhtype;
if (ss->pbvh) {
pbvhtype = BKE_pbvh_type(ss->pbvh);
}
else if (ss->bm) {
pbvhtype = PBVH_BMESH;
}
else if (ss->subdiv_ccg) {
pbvhtype = PBVH_GRIDS;
}
else {
pbvhtype = PBVH_FACES;
}
if (bad) {
sculpt_attribute_create(ss,
ob,
attr->domain,
attr->proptype,
attr->name,
attr,
&attr->params,
BKE_pbvh_type(ss->pbvh));
sculpt_attribute_create(
ss, ob, attr->domain, attr->proptype, attr->name, attr, &attr->params, pbvhtype);
}
return bad;

View File

@ -277,17 +277,22 @@ void bm_alloc_id(BMesh *bm, BMElem *elem)
return;
}
#ifdef WITH_BM_ID_FREELIST
uint id;
if (bm->idmap.freelist_len > 0) {
#ifdef WITH_BM_ID_FREELIST
if (bm->idmap.freelist_len > 0 && !(bm->idmap.flag & BM_NO_REUSE_IDS)) {
id = bm_id_freelist_pop(bm);
}
else {
id = bm->idmap.maxid + 1;
}
#else
uint id = range_tree_uint_take_any(bm->idmap.idtree);
if (!(bm->idmap.flag & BM_NO_REUSE_IDS)) {
id = range_tree_uint_take_any(bm->idmap.idtree);
}
else {
id = bm->idmap.maxid + 1;
}
#endif
bm_assign_id_intern(bm, elem, id);
@ -307,7 +312,9 @@ void bm_free_id(BMesh *bm, BMElem *elem)
range_tree_uint_release(bm->idmap.idtree, id);
}
#else
if (!(bm->idmap.flag & BM_NO_REUSE_IDS)) {
bm_id_freelist_push(bm, id);
}
#endif
if ((bm->idmap.flag & BM_HAS_ID_MAP)) {

View File

@ -31,6 +31,7 @@
#include "bmesh.h"
#include "intern/bmesh_private.h"
#include "bmesh_log_intern.h"
#include "range_tree.h"
#include <stdarg.h>
@ -2449,14 +2450,13 @@ ATTR_NO_OPT static bool cleanup_vert(BMesh *bm, BMVert *v, const BMTracer *trace
return false;
}
bm_logstack_push();
BMFace *f_example = NULL;
do {
BMLoop *l = e->l;
if (!l) {
if (tracer) {
tracer->on_edge_kill(bm, e, tracer->userdata);
}
continue;
}
@ -2469,12 +2469,14 @@ ATTR_NO_OPT static bool cleanup_vert(BMesh *bm, BMVert *v, const BMTracer *trace
tracer->on_face_kill(bm, l->f, tracer->userdata);
}
} while ((l = l->radial_next) != e->l);
if (tracer) {
tracer->on_edge_kill(bm, e, tracer->userdata);
}
} while ((e = BM_DISK_EDGE_NEXT(e, v)) != v->e);
if (tracer) {
do {
tracer->on_edge_kill(bm, e, tracer->userdata);
} while ((e = BM_DISK_EDGE_NEXT(e, v)) != v->e);
}
if (tracer) {
tracer->on_vert_kill(bm, v, tracer->userdata);
}
@ -2500,6 +2502,7 @@ ATTR_NO_OPT static bool cleanup_vert(BMesh *bm, BMVert *v, const BMTracer *trace
tracer->on_face_create(bm, f, tracer->userdata);
}
bm_logstack_pop();
return true;
}
@ -2509,6 +2512,8 @@ ATTR_NO_OPT static void bmesh_kernel_check_val3_vert(BMesh *bm, BMEdge *e, const
return;
}
bm_logstack_push();
bool stop;
do {
@ -2535,6 +2540,8 @@ ATTR_NO_OPT static void bmesh_kernel_check_val3_vert(BMesh *bm, BMEdge *e, const
}
} while ((l = l->radial_next) != e->l);
} while (!stop);
bm_logstack_pop();
}
ATTR_NO_OPT BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
@ -2559,6 +2566,7 @@ ATTR_NO_OPT BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
_last_local_obj = strdup(saved_obj);
#endif
/* Free any surrounding valence-3 rings disconnected from the edge. */
bmesh_kernel_check_val3_vert(bm, e, tracer);
BMFace **fs = NULL;
@ -2578,11 +2586,16 @@ ATTR_NO_OPT BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
JVKE_CHECK_ELEMENT(v_conn);
JVKE_CHECK_ELEMENT(v_del);
#define _OTHER_TRACES //paranoia (and likely duplicate) calls to tracer callbacks
#define _OTHER_TRACES // paranoia (and likely duplicate) calls to tracer callbacks
/* first clear tags */
for (int i = 0; i < 2; i++) {
BMVert *v = i ? v_del : v_conn;
if (!v->e) {
continue;
}
BMEdge *e2 = v->e;
do {
/* build list of edges if needed for tracing */
@ -2761,7 +2774,17 @@ ATTR_NO_OPT BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
#ifdef _OTHER_TRACES
if (tracer) {
tracer->on_edge_kill(bm, deles[i], tracer->userdata);
bool found = false;
for (int j = 0; j < BLI_array_len(es); j++) {
if (es[j] == deles[i]) {
found = true;
break;
}
}
if (!found) {
tracer->on_edge_kill(bm, deles[i], tracer->userdata);
}
}
#endif
@ -2800,7 +2823,7 @@ ATTR_NO_OPT BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
} while (lnext && (l = lnext) != f->l_first);
if (f->len <= 2) {
#ifdef _OTHER_TRACES
#if 0 //def _OTHER_TRACES
if (tracer) {
tracer->on_face_kill(bm, f, tracer->userdata);
}
@ -2986,18 +3009,22 @@ ATTR_NO_OPT BMVert *bmesh_kernel_join_vert_kill_edge(BMesh *bm,
tracer->on_vert_kill(bm, v_del, tracer->userdata);
}
if (v_del->e) {
if (v_del->e && v_del->e->l) {
printf("%s: vert is not cleared\n", __func__);
}
BM_vert_kill(bm, v_del);
if (!(v_del->e && v_del->e->l)) {
BM_vert_kill(bm, v_del);
}
}
if (tracer && v_conn->e) {
e = v_conn->e;
do {
tracer->on_edge_create(bm, e, tracer->userdata);
} while ((e = BM_DISK_EDGE_NEXT(e, v_conn)) != v_conn->e);
do {
BMLoop *l = e->l;
if (!l) {
continue;

View File

@ -57,9 +57,10 @@
void CustomData_bmesh_asan_unpoison(const CustomData *data, void *block);
void CustomData_bmesh_asan_poison(const CustomData *data, void *block);
//#define DEBUG_LOG_TO_FILE
//#define DO_LOG_PRINT
//#define DEBUG_LOG_TO_FILE
#define BM_LOG_USE_SMALLHASH
#ifdef BM_LOG_USE_SMALLHASH
@ -140,7 +141,10 @@ static void *my_popkey(SmallHash *sh, const void *key)
# undef BM_ELEM_FROM_ID
# endif
# define BM_ELEM_FROM_ID(bm, id) bm->idmap.map[id]
# define BM_ELEM_FROM_ID(bm, id) \
((bm->idmap.flag & BM_NO_REUSE_IDS) ? \
BLI_ghash_lookup(bm->idmap.ghash, POINTER_FROM_UINT(id)) : \
bm->idmap.map[id])
#endif
//#define DEBUG_LOG_REFCOUNTNG
@ -274,7 +278,7 @@ static int msg_idgen = 1;
static char msg_buffer[256] = {0};
# define SET_MSG(le) memcpy(le->msg, msg_buffer, sizeof(le->msg))
# define GET_MSG(le) le->msg
# define GET_MSG(le) (le)->msg
# ifdef DEBUG_LOG_CALL_STACKS
# define LOGPRINT(entry, ...) \
fprintf(DEBUG_FILE, "%d: %s: ", entry->id, bm_logstack_head()); \
@ -719,6 +723,8 @@ static uint bm_log_vert_id_get(BMLog *log, BMVert *v)
return (uint)BM_ELEM_GET_ID(log->bm, v);
}
# undef BLI_ghash_lookup
/*Get a vertex from its unique ID */
static BMElem *bm_log_elem_from_id(BMLog *log, uint id)
{
@ -781,6 +787,7 @@ static BMFace *bm_log_face_from_id(BMLog *log, uint id)
return (BMFace *)BM_ELEM_FROM_ID(log->bm, id);
}
# define BLI_ghash_lookup(sh, key) BLI_smallhash_lookup((sh), (uintptr_t)(key))
#endif
@ -951,7 +958,7 @@ static BMLogEdge *bm_log_edge_alloc(BMLog *log, BMEdge *e, bool log_customdata)
SET_TRACE(le);
#ifdef DO_LOG_PRINT
le->msg[0] = 0;
le->head.msg[0] = 0;
#endif
bm_log_edge_bmedge_copy(log, entry, le, e, log_customdata);
@ -1137,7 +1144,7 @@ static void bm_log_edges_unmake_pre(
"%s: missing edge; id: %d [%s]\n",
GET_TRACE(le, entry),
le->head.id,
GET_MSG(le));
GET_MSG(&le->head));
continue;
}
@ -1147,7 +1154,7 @@ static void bm_log_edges_unmake_pre(
GET_TRACE(le, entry),
le->head.id,
e->head.htype,
GET_MSG(le));
GET_MSG(&le->head));
continue;
}
@ -1210,7 +1217,7 @@ static void bm_log_edges_unmake(
"%s: missing edge; edge id: %d [%s]\n",
GET_TRACE(le, entry),
le->head.id,
GET_MSG(le));
GET_MSG(&le->head));
continue;
}
@ -1220,7 +1227,7 @@ static void bm_log_edges_unmake(
GET_TRACE(le, entry),
le->head.id,
e->head.htype,
GET_MSG(le));
GET_MSG(&le->head));
continue;
}
@ -2526,7 +2533,7 @@ static void log_idmap_save(BMesh *bm, BMLog *log, BMLogEntry *entry)
BM_ITER_MESH_INDEX (elem, &iter, bm, iters[i], j) {
int id = BM_ELEM_CD_GET_INT(elem, cd_off);
if (!reported && (BMElem *)BM_ELEM_FROM_ID(bm, id) != elem) {
if (!reported && (BMElem *)bm_log_elem_from_id(log, id) != elem) {
fprintf(DEBUG_FILE, "IDMap error for elem type %d\n", elem->head.htype);
fprintf(DEBUG_FILE, " further errors suppressed\n");
reported = true;
@ -2775,6 +2782,9 @@ static void bm_log_undo_intern(BMesh *bm, BMLog *log, BMLogEntry *entry, BMLogCa
return;
}
// XXX
bm_update_idmap_cdlayers(bm);
/* Delete added faces and verts */
bm_log_faces_unmake_pre(bm, log, entry->topo_modified_faces_post, entry, callbacks);
bm_log_edges_unmake_pre(bm, log, entry->topo_modified_edges_post, entry, callbacks);
@ -3231,7 +3241,6 @@ void _BM_log_face_pre(BMLog *log, BMFace *f BMLOG_DEBUG_ARGS)
*val = (void *)lf;
}
VALIDATE_LOG(log->bm, log->current_entry);
bm_logstack_pop();
}
@ -3273,7 +3282,6 @@ void _BM_log_face_post(BMLog *log, BMFace *f BMLOG_DEBUG_ARGS)
}
}
VALIDATE_LOG(log->bm, log->current_entry);
bm_logstack_pop();
}
@ -3321,7 +3329,6 @@ void _BM_log_edge_pre(BMLog *log, BMEdge *e BMLOG_DEBUG_ARGS)
*val = (void *)le;
}
VALIDATE_LOG(log->bm, log->current_entry);
bm_logstack_pop();
}
@ -3362,7 +3369,6 @@ void _BM_log_edge_post(BMLog *log, BMEdge *e BMLOG_DEBUG_ARGS)
*val = (void *)le;
}
VALIDATE_LOG(log->bm, log->current_entry);
bm_logstack_pop();
}
@ -3405,7 +3411,6 @@ void _BM_log_vert_pre(BMLog *log, BMVert *v BMLOG_DEBUG_ARGS)
*val = (void *)lv;
}
VALIDATE_LOG(log->bm, log->current_entry);
bm_logstack_pop();
}
@ -3456,8 +3461,6 @@ void _BM_log_vert_post(BMLog *log, BMVert *v BMLOG_DEBUG_ARGS)
}
}
VALIDATE_LOG(log->bm, log->current_entry);
bm_logstack_pop();
}
/* Log a vertex as removed from the BMesh
@ -4001,11 +4004,12 @@ static bool check_log_elem(BMesh *bm, BMLog *newlog, int id, int type, bool expe
BMElem *elem = bm_log_elem_from_id(newlog, id);
if (!!elem != expected) {
debuglog("Missing %s %d\n", elem_type_to_str(type), id);
debuglog("%s: Missing %s %d\n", __func__, elem_type_to_str(type), id);
return false;
}
else if (elem && (elem->head.htype == type) != expected) {
debuglog("Expected %s at id %d; got %s instead\n",
debuglog("%s: Expected %s at id %d; got %s instead\n",
__func__,
elem_type_to_str(type),
id,
elem_type_to_str(elem->head.htype));
@ -4015,7 +4019,7 @@ static bool check_log_elem(BMesh *bm, BMLog *newlog, int id, int type, bool expe
return true;
}
static bool bm_check_ghash_set(
ATTR_NO_OPT static bool bm_check_ghash_set(
GHash *ghashes[4], BMesh *bm, BMLog *newlog, BMLogEntry *entry, bool shouldExist)
{
bool ok = true;
@ -4055,7 +4059,7 @@ static bool bm_check_ghash_set(
return ok;
}
static bool bm_log_validate_intern(
ATTR_NO_OPT static bool bm_log_validate_intern(
BMesh *bm, BMLog *newlog, BMLogEntry *srcEntry, bool is_applied, bool do_apply)
{
bool precopy = do_apply;
@ -4120,16 +4124,18 @@ static bool bm_log_validate_intern(
}
}
if (is_applied) {
}
else {
/*element should exist in post but not in pre, or in neither*/
if (exist1 && !exist2) {
debuglog("element %u:%s should not exist\n", id, elem_type_to_str(1 << i));
bool exist_bad = exist1 && !exist2;
// debuglog("%s %u existes in both pre and post log sets!\n", elem_type_to_str(type),
// id); ok = false;
}
if (is_applied) {
exist_bad = !exist_bad;
}
/*element should exist in post but not in pre, or in neither*/
if (exist_bad) {
debuglog("element %u:%s should not exist\n", id, elem_type_to_str(1 << i));
// debuglog("%s %u existes in both pre and post log sets!\n", elem_type_to_str(type),
// id); ok = false;
}
}
}
@ -4265,7 +4271,9 @@ void BM_log_get_changed(BMesh *bm, BMIdMap *idmap, BMLogEntry *_entry, SmallHash
}
#endif
#undef BLI_ghash_lookup
BMElem *elem = BM_ELEM_FROM_ID(bm, id);
#define BLI_ghash_lookup(sh, key) BLI_smallhash_lookup((sh), (uintptr_t)(key))
if (!elem) {
continue;

View File

@ -602,14 +602,7 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
#if 1
if (!ss->bm) {
ss->bm = BM_mesh_create(
&allocsize,
&((struct BMeshCreateParams){.use_toolflags = false,
.create_unique_ids = true,
.id_elem_mask = BM_VERT | BM_EDGE | BM_FACE,
.id_map = true,
.temporary_ids = false,
.no_reuse_ids = false}));
ss->bm = BKE_sculptsession_empty_bmesh_create();
BM_mesh_bm_from_me(NULL,
ss->bm,