From 4742fa7f40c22bab2aa33ffb3fcf2f3a5401f561 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 23 Jul 2024 17:24:20 -0400 Subject: [PATCH] Refactor: Sculpt: Remove BMesh custom data offset from BVH tree Instead just compute the offsets as necessary. This avoids the need to keep them in sync as the BMesh changes, though it requires passing a few more arguments in the dynamic topology remeshing code. --- source/blender/blenkernel/BKE_pbvh_api.hh | 6 +- source/blender/blenkernel/intern/paint.cc | 20 +- .../blender/blenkernel/intern/pbvh_bmesh.cc | 227 +++++++++++------- 3 files changed, 145 insertions(+), 108 deletions(-) diff --git a/source/blender/blenkernel/BKE_pbvh_api.hh b/source/blender/blenkernel/BKE_pbvh_api.hh index 2677c6e7d8c..c93b410026a 100644 --- a/source/blender/blenkernel/BKE_pbvh_api.hh +++ b/source/blender/blenkernel/BKE_pbvh_api.hh @@ -209,8 +209,6 @@ class Tree { /* Dynamic topology */ float bm_max_edge_len_; float bm_min_edge_len_; - int cd_vert_node_offset_ = -1; - int cd_face_node_offset_ = -1; float planes_[6][4]; int num_planes_; @@ -283,9 +281,7 @@ std::unique_ptr build_grids(Mesh *mesh, SubdivCCG *subdiv_ccg); /** * Build a Tree from a BMesh. */ -std::unique_ptr build_bmesh(BMesh *bm, int cd_vert_node_offset, int cd_face_node_offset); - -void update_bmesh_offsets(Tree &pbvh, int cd_vert_node_offset, int cd_face_node_offset); +std::unique_ptr build_bmesh(BMesh *bm); void build_pixels(Tree &pbvh, Mesh *mesh, Image *image, ImageUser *image_user); void free(std::unique_ptr &pbvh); diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc index f3f6ef20c4c..618674f48d6 100644 --- a/source/blender/blenkernel/intern/paint.cc +++ b/source/blender/blenkernel/intern/paint.cc @@ -2296,9 +2296,7 @@ static std::unique_ptr build_pbvh_for_dynamic_topology(Object *ob) { sculptsession_bmesh_add_layers(ob); - return pbvh::build_bmesh(ob->sculpt->bm, - ob->sculpt->attrs.dyntopo_node_id_vertex->bmesh_cd_offset, - ob->sculpt->attrs.dyntopo_node_id_face->bmesh_cd_offset); + return pbvh::build_bmesh(ob->sculpt->bm); } static std::unique_ptr build_pbvh_from_regular_mesh(Object *ob, @@ -2814,20 +2812,6 @@ SculptAttribute *BKE_sculpt_attribute_ensure(Object *ob, ob, domain, proptype, name, &temp_params, ob->sculpt->pbvh->type(), true); } -static void sculptsession_bmesh_attr_update_internal(Object *ob) -{ - using namespace blender; - SculptSession *ss = ob->sculpt; - - sculptsession_bmesh_add_layers(ob); - - if (ss->pbvh) { - bke::pbvh::update_bmesh_offsets(*ss->pbvh, - ob->sculpt->attrs.dyntopo_node_id_vertex->bmesh_cd_offset, - ob->sculpt->attrs.dyntopo_node_id_face->bmesh_cd_offset); - } -} - static void sculptsession_bmesh_add_layers(Object *ob) { SculptSession *ss = ob->sculpt; @@ -2880,7 +2864,7 @@ static void sculpt_attribute_update_refs(Object *ob, blender::bke::pbvh::Type pb } if (ss->bm) { - sculptsession_bmesh_attr_update_internal(ob); + sculptsession_bmesh_add_layers(ob); } } } diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.cc b/source/blender/blenkernel/intern/pbvh_bmesh.cc index 4fcb33331ac..acb10f49aa8 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.cc +++ b/source/blender/blenkernel/intern/pbvh_bmesh.cc @@ -257,11 +257,11 @@ static void pbvh_bmesh_node_finalize(Tree &pbvh, /** Recursively split the node if it exceeds the leaf_limit. */ static void pbvh_bmesh_node_split(Tree &pbvh, + const int cd_vert_node_offset, + const int cd_face_node_offset, const Span> face_bounds, int node_index) { - const int cd_vert_node_offset = pbvh.cd_vert_node_offset_; - const int cd_face_node_offset = pbvh.cd_face_node_offset_; Node *n = &pbvh.nodes_[node_index]; if (n->bm_faces_.size() <= leaf_limit) { @@ -346,8 +346,8 @@ static void pbvh_bmesh_node_split(Tree &pbvh, n->flag_ &= ~PBVH_Leaf; /* Recurse. */ - pbvh_bmesh_node_split(pbvh, face_bounds, children); - pbvh_bmesh_node_split(pbvh, face_bounds, children + 1); + pbvh_bmesh_node_split(pbvh, cd_vert_node_offset, cd_face_node_offset, face_bounds, children); + pbvh_bmesh_node_split(pbvh, cd_vert_node_offset, cd_face_node_offset, face_bounds, children + 1); /* Array maybe reallocated, update current node pointer */ n = &pbvh.nodes_[node_index]; @@ -359,7 +359,10 @@ static void pbvh_bmesh_node_split(Tree &pbvh, } /** Recursively split the node if it exceeds the leaf_limit. */ -static bool pbvh_bmesh_node_limit_ensure(Tree &pbvh, int node_index) +static bool pbvh_bmesh_node_limit_ensure(Tree &pbvh, + const int cd_vert_node_offset, + const int cd_face_node_offset, + int node_index) { Node &node = pbvh.nodes_[node_index]; const int faces_num = node.bm_faces_.size(); @@ -389,37 +392,39 @@ static bool pbvh_bmesh_node_limit_ensure(Tree &pbvh, int node_index) /* Likely this is already dirty. */ pbvh.bm_->elem_index_dirty |= BM_FACE; - pbvh_bmesh_node_split(pbvh, face_bounds, node_index); + pbvh_bmesh_node_split(pbvh, cd_vert_node_offset, cd_face_node_offset, face_bounds, node_index); return true; } /**********************************************************************/ -BLI_INLINE int pbvh_bmesh_node_index_from_vert(Tree &pbvh, const BMVert *key) +BLI_INLINE int pbvh_bmesh_node_index_from_vert(const int cd_vert_node_offset, const BMVert *key) { - const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, pbvh.cd_vert_node_offset_); + const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, cd_vert_node_offset); BLI_assert(node_index != DYNTOPO_NODE_NONE); - BLI_assert(node_index < pbvh.nodes_.size()); return node_index; } -BLI_INLINE int pbvh_bmesh_node_index_from_face(Tree &pbvh, const BMFace *key) +BLI_INLINE int pbvh_bmesh_node_index_from_face(const int cd_face_node_offset, const BMFace *key) { - const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, pbvh.cd_face_node_offset_); + const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, cd_face_node_offset); BLI_assert(node_index != DYNTOPO_NODE_NONE); - BLI_assert(node_index < pbvh.nodes_.size()); return node_index; } -BLI_INLINE Node *pbvh_bmesh_node_from_vert(Tree &pbvh, const BMVert *key) +BLI_INLINE Node *pbvh_bmesh_node_from_vert(Tree &pbvh, + const int cd_vert_node_offset, + const BMVert *key) { - return &pbvh.nodes_[pbvh_bmesh_node_index_from_vert(pbvh, key)]; + return &pbvh.nodes_[pbvh_bmesh_node_index_from_vert(cd_vert_node_offset, key)]; } -BLI_INLINE Node *pbvh_bmesh_node_from_face(Tree &pbvh, const BMFace *key) +BLI_INLINE Node *pbvh_bmesh_node_from_face(Tree &pbvh, + const int cd_face_node_offset, + const BMFace *key) { - return &pbvh.nodes_[pbvh_bmesh_node_index_from_face(pbvh, key)]; + return &pbvh.nodes_[pbvh_bmesh_node_index_from_face(cd_face_node_offset, key)]; } static BMVert *pbvh_bmesh_vert_create(Tree &pbvh, @@ -429,6 +434,7 @@ static BMVert *pbvh_bmesh_vert_create(Tree &pbvh, const int node_index, const float co[3], const float no[3], + const int cd_vert_node_offset, const int cd_vert_mask_offset) { Node *node = &pbvh.nodes_[node_index]; @@ -444,7 +450,7 @@ static BMVert *pbvh_bmesh_vert_create(Tree &pbvh, copy_v3_v3(v->no, no); node->bm_unique_verts_.add(v); - BM_ELEM_CD_SET_INT(v, pbvh.cd_vert_node_offset_, node_index); + BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, node_index); node->flag_ |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_TopologyUpdated; @@ -458,6 +464,7 @@ static BMVert *pbvh_bmesh_vert_create(Tree &pbvh, * \note Callers are responsible for checking if the face exists before adding. */ static BMFace *pbvh_bmesh_face_create(Tree &pbvh, + const int cd_face_node_offset, BMLog &bm_log, int node_index, const Span v_tri, @@ -473,7 +480,7 @@ static BMFace *pbvh_bmesh_face_create(Tree &pbvh, f->head.hflag = f_example->head.hflag; node->bm_faces_.add(f); - BM_ELEM_CD_SET_INT(f, pbvh.cd_face_node_offset_, node_index); + BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index); node->flag_ |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_TopologyUpdated; node->flag_ &= ~PBVH_FullyHidden; @@ -484,19 +491,17 @@ static BMFace *pbvh_bmesh_face_create(Tree &pbvh, return f; } -#define pbvh_bmesh_node_vert_use_count_is_equal(pbvh, node, v, n) \ - (pbvh_bmesh_node_vert_use_count_at_most(pbvh, node, v, (n) + 1) == n) +#define pbvh_bmesh_node_vert_use_count_is_equal(pbvh, cd_face_node_offset, node, v, n) \ + (pbvh_bmesh_node_vert_use_count_at_most(pbvh, cd_face_node_offset, node, v, (n) + 1) == n) -static int pbvh_bmesh_node_vert_use_count_at_most(Tree &pbvh, - Node *node, - BMVert *v, - const int count_max) +static int pbvh_bmesh_node_vert_use_count_at_most( + Tree &pbvh, const int cd_face_node_offset, Node *node, BMVert *v, const int count_max) { int count = 0; BMFace *f; BM_FACES_OF_VERT_ITER_BEGIN (f, v) { - Node *f_node = pbvh_bmesh_node_from_face(pbvh, f); + Node *f_node = pbvh_bmesh_node_from_face(pbvh, cd_face_node_offset, f); if (f_node == node) { count++; if (count == count_max) { @@ -510,13 +515,16 @@ static int pbvh_bmesh_node_vert_use_count_at_most(Tree &pbvh, } /** Return a node that uses vertex `v` other than its current owner. */ -static Node *pbvh_bmesh_vert_other_node_find(Tree &pbvh, BMVert *v) +static Node *pbvh_bmesh_vert_other_node_find(Tree &pbvh, + const int cd_vert_node_offset, + const int cd_face_node_offset, + BMVert *v) { - Node *current_node = pbvh_bmesh_node_from_vert(pbvh, v); + Node *current_node = pbvh_bmesh_node_from_vert(pbvh, cd_vert_node_offset, v); BMFace *f; BM_FACES_OF_VERT_ITER_BEGIN (f, v) { - Node *f_node = pbvh_bmesh_node_from_face(pbvh, f); + Node *f_node = pbvh_bmesh_node_from_face(pbvh, cd_face_node_offset, f); if (f_node != current_node) { return f_node; @@ -527,9 +535,12 @@ static Node *pbvh_bmesh_vert_other_node_find(Tree &pbvh, BMVert *v) return nullptr; } -static void pbvh_bmesh_vert_ownership_transfer(Tree &pbvh, Node *new_owner, BMVert *v) +static void pbvh_bmesh_vert_ownership_transfer(Tree &pbvh, + const int cd_vert_node_offset, + Node *new_owner, + BMVert *v) { - Node *current_owner = pbvh_bmesh_node_from_vert(pbvh, v); + Node *current_owner = pbvh_bmesh_node_from_vert(pbvh, cd_vert_node_offset, v); current_owner->flag_ |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_TopologyUpdated; BLI_assert(current_owner != new_owner); @@ -538,7 +549,7 @@ static void pbvh_bmesh_vert_ownership_transfer(Tree &pbvh, Node *new_owner, BMVe current_owner->bm_unique_verts_.remove(v); /* Set new ownership */ - BM_ELEM_CD_SET_INT(v, pbvh.cd_vert_node_offset_, new_owner - pbvh.nodes_.data()); + BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, new_owner - pbvh.nodes_.data()); new_owner->bm_unique_verts_.add(v); new_owner->bm_other_verts_.remove(v); BLI_assert(!new_owner->bm_other_verts_.contains(v)); @@ -546,19 +557,22 @@ static void pbvh_bmesh_vert_ownership_transfer(Tree &pbvh, Node *new_owner, BMVe new_owner->flag_ |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_TopologyUpdated; } -static void pbvh_bmesh_vert_remove(Tree &pbvh, BMVert *v) +static void pbvh_bmesh_vert_remove(Tree &pbvh, + const int cd_vert_node_offset, + const int cd_face_node_offset, + BMVert *v) { /* Never match for first time. */ int f_node_index_prev = DYNTOPO_NODE_NONE; - Node *v_node = pbvh_bmesh_node_from_vert(pbvh, v); + Node *v_node = pbvh_bmesh_node_from_vert(pbvh, cd_vert_node_offset, v); v_node->bm_unique_verts_.remove(v); - BM_ELEM_CD_SET_INT(v, pbvh.cd_vert_node_offset_, DYNTOPO_NODE_NONE); + BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE); /* Have to check each neighboring face's node. */ BMFace *f; BM_FACES_OF_VERT_ITER_BEGIN (f, v) { - const int f_node_index = pbvh_bmesh_node_index_from_face(pbvh, f); + const int f_node_index = pbvh_bmesh_node_index_from_face(cd_face_node_offset, f); /* Faces often share the same node, quick check to avoid redundant #BLI_gset_remove calls. */ if (f_node_index_prev != f_node_index) { @@ -577,25 +591,30 @@ static void pbvh_bmesh_vert_remove(Tree &pbvh, BMVert *v) BM_FACES_OF_VERT_ITER_END; } -static void pbvh_bmesh_face_remove(Tree &pbvh, BMLog &bm_log, BMFace *f) +static void pbvh_bmesh_face_remove(Tree &pbvh, + const int cd_vert_node_offset, + const int cd_face_node_offset, + BMLog &bm_log, + BMFace *f) { - Node *f_node = pbvh_bmesh_node_from_face(pbvh, f); + Node *f_node = pbvh_bmesh_node_from_face(pbvh, cd_face_node_offset, f); /* Check if any of this face's vertices need to be removed from the node. */ BMLoop *l_first = BM_FACE_FIRST_LOOP(f); BMLoop *l_iter = l_first; do { BMVert *v = l_iter->v; - if (pbvh_bmesh_node_vert_use_count_is_equal(pbvh, f_node, v, 1)) { + if (pbvh_bmesh_node_vert_use_count_is_equal(pbvh, cd_face_node_offset, f_node, v, 1)) { if (f_node->bm_unique_verts_.contains(v)) { /* Find a different node that uses 'v'. */ Node *new_node; - new_node = pbvh_bmesh_vert_other_node_find(pbvh, v); + new_node = pbvh_bmesh_vert_other_node_find( + pbvh, cd_vert_node_offset, cd_face_node_offset, v); BLI_assert(new_node || BM_vert_face_count_is_equal(v, 1)); if (new_node) { - pbvh_bmesh_vert_ownership_transfer(pbvh, new_node, v); + pbvh_bmesh_vert_ownership_transfer(pbvh, cd_vert_node_offset, new_node, v); } } else { @@ -607,7 +626,7 @@ static void pbvh_bmesh_face_remove(Tree &pbvh, BMLog &bm_log, BMFace *f) /* Remove face from node and top level. */ f_node->bm_faces_.remove(f); - BM_ELEM_CD_SET_INT(f, pbvh.cd_face_node_offset_, DYNTOPO_NODE_NONE); + BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE); /* Log removed face. */ BM_log_face_removed(&bm_log, f); @@ -1121,7 +1140,12 @@ static void merge_edge_data(BMesh &bm, BMEdge &dst, const BMEdge &src) BM_data_interp_from_edges(&bm, &src, &dst, &dst, 0.5f); } -static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, Tree &pbvh, BMLog &bm_log, BMEdge *e) +static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, + Tree &pbvh, + const int cd_vert_node_offset, + const int cd_face_node_offset, + BMLog &bm_log, + BMEdge *e) { BMesh *bm = pbvh.bm_; @@ -1136,8 +1160,15 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, Tree &pbvh, BMLog &b normalize_v3(no_mid); int node_index = BM_ELEM_CD_GET_INT(e->v1, eq_ctx->cd_vert_node_offset); - BMVert *v_new = pbvh_bmesh_vert_create( - pbvh, bm_log, e->v1, e->v2, node_index, co_mid, no_mid, eq_ctx->cd_vert_mask_offset); + BMVert *v_new = pbvh_bmesh_vert_create(pbvh, + bm_log, + e->v1, + e->v2, + node_index, + co_mid, + no_mid, + cd_vert_node_offset, + eq_ctx->cd_vert_mask_offset); /* For each face, add two new triangles and delete the original. */ for (const int i : edge_loops.index_range()) { @@ -1156,7 +1187,7 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, Tree &pbvh, BMLog &b BMVert *v2 = l_adj->next->v; if (ni != node_index && i == 0) { - pbvh_bmesh_vert_ownership_transfer(pbvh, &pbvh.nodes_[ni], v_new); + pbvh_bmesh_vert_ownership_transfer(pbvh, cd_vert_node_offset, &pbvh.nodes_[ni], v_new); } /* The 2 new faces created and assigned to `f_new` have their @@ -1189,7 +1220,8 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, Tree &pbvh, BMLog &b const std::array first_edges = bm_edges_from_tri(bm, first_tri); copy_edge_data(*bm, *first_edges[0], *e); - BMFace *f_new_first = pbvh_bmesh_face_create(pbvh, bm_log, ni, first_tri, first_edges, f_adj); + BMFace *f_new_first = pbvh_bmesh_face_create( + pbvh, cd_face_node_offset, bm_log, ni, first_tri, first_edges, f_adj); long_edge_queue_face_add(eq_ctx, f_new_first); /* Create second face (v_new, v2, v_opp). */ @@ -1202,11 +1234,11 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, Tree &pbvh, BMLog &b copy_edge_data(*bm, *second_edges[0], *e); BMFace *f_new_second = pbvh_bmesh_face_create( - pbvh, bm_log, ni, second_tri, second_edges, f_adj); + pbvh, cd_face_node_offset, bm_log, ni, second_tri, second_edges, f_adj); long_edge_queue_face_add(eq_ctx, f_new_second); /* Delete original */ - pbvh_bmesh_face_remove(pbvh, bm_log, f_adj); + pbvh_bmesh_face_remove(pbvh, cd_vert_node_offset, cd_face_node_offset, bm_log, f_adj); BM_face_kill(bm, f_adj); /* Ensure new vertex is in the node */ @@ -1226,7 +1258,11 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, Tree &pbvh, BMLog &b BM_edge_kill(bm, e); } -static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx, Tree &pbvh, BMLog &bm_log) +static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx, + Tree &pbvh, + const int cd_vert_node_offset, + const int cd_face_node_offset, + BMLog &bm_log) { const double start_time = BLI_time_now_seconds(); @@ -1263,7 +1299,7 @@ static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx, Tree &pbvh any_subdivided = true; - pbvh_bmesh_split_edge(eq_ctx, pbvh, bm_log, e); + pbvh_bmesh_split_edge(eq_ctx, pbvh, cd_vert_node_offset, cd_face_node_offset, bm_log, e); } #ifdef USE_EDGEQUEUE_TAG_VERIFY @@ -1521,6 +1557,8 @@ static void merge_face_edge_data(BMesh &bm, } static void pbvh_bmesh_collapse_edge(Tree &pbvh, + const int cd_vert_node_offset, + const int cd_face_node_offset, BMLog &bm_log, BMEdge *e, BMVert *v1, @@ -1563,7 +1601,7 @@ static void pbvh_bmesh_collapse_edge(Tree &pbvh, } /* Remove the merge vertex from the Tree. */ - pbvh_bmesh_vert_remove(pbvh, v_del); + pbvh_bmesh_vert_remove(pbvh, cd_vert_node_offset, cd_face_node_offset, v_del); /* For all remaining faces of v_del, create a new face that is the * same except it uses v_conn instead of v_del */ @@ -1602,7 +1640,7 @@ static void pbvh_bmesh_collapse_edge(Tree &pbvh, while ((l_adj = e->l)) { BMFace *f_adj = l_adj->f; - pbvh_bmesh_face_remove(pbvh, bm_log, f_adj); + pbvh_bmesh_face_remove(pbvh, cd_vert_node_offset, cd_face_node_offset, bm_log, f_adj); BM_face_kill(&bm, f_adj); } @@ -1621,10 +1659,11 @@ static void pbvh_bmesh_collapse_edge(Tree &pbvh, const std::array v_tri{v_conn, l->next->v, l->prev->v}; BLI_assert(!BM_face_exists(v_tri.data(), 3)); - Node *n = pbvh_bmesh_node_from_face(pbvh, f); + Node *n = pbvh_bmesh_node_from_face(pbvh, cd_face_node_offset, f); int ni = n - pbvh.nodes_.data(); const std::array e_tri = bm_edges_from_tri(&bm, v_tri); - BMFace *new_face = pbvh_bmesh_face_create(pbvh, bm_log, ni, v_tri, e_tri, f); + BMFace *new_face = pbvh_bmesh_face_create( + pbvh, cd_face_node_offset, bm_log, ni, v_tri, e_tri, f); merge_face_edge_data(bm, f, new_face, v_del, l, v_conn); @@ -1650,7 +1689,7 @@ static void pbvh_bmesh_collapse_edge(Tree &pbvh, try_merge_flap_edge_data_before_dissolve(bm, *f_del); /* Remove the face */ - pbvh_bmesh_face_remove(pbvh, bm_log, f_del); + pbvh_bmesh_face_remove(pbvh, cd_vert_node_offset, cd_face_node_offset, bm_log, f_del); BM_face_kill(&bm, f_del); /* Check if any of the face's edges are now unused by any @@ -1665,7 +1704,7 @@ static void pbvh_bmesh_collapse_edge(Tree &pbvh, * remove them from the Tree */ for (const int j : IndexRange(3)) { if ((v_tri[j] != v_del) && (v_tri[j]->e == nullptr)) { - pbvh_bmesh_vert_remove(pbvh, v_tri[j]); + pbvh_bmesh_vert_remove(pbvh, cd_vert_node_offset, cd_face_node_offset, v_tri[j]); BM_log_vert_removed(&bm_log, v_tri[j], eq_ctx->cd_vert_mask_offset); @@ -1694,7 +1733,7 @@ static void pbvh_bmesh_collapse_edge(Tree &pbvh, /* Update bounding boxes attached to the connected vertex. * Note that we can often get-away without this but causes #48779. */ BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_conn) { - Node *f_node = pbvh_bmesh_node_from_face(pbvh, l->f); + Node *f_node = pbvh_bmesh_node_from_face(pbvh, cd_face_node_offset, l->f); f_node->flag_ |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_UpdateBB; } BM_LOOPS_OF_VERT_ITER_END; @@ -1708,7 +1747,11 @@ static void pbvh_bmesh_collapse_edge(Tree &pbvh, BM_vert_kill(&bm, v_del); } -static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx, Tree &pbvh, BMLog &bm_log) +static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx, + Tree &pbvh, + const int cd_vert_node_offset, + const int cd_face_node_offset, + BMLog &bm_log) { const double start_time = BLI_time_now_seconds(); @@ -1755,7 +1798,8 @@ static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx, Tree &pbvh any_collapsed = true; - pbvh_bmesh_collapse_edge(pbvh, bm_log, e, v1, v2, deleted_verts, eq_ctx); + pbvh_bmesh_collapse_edge( + pbvh, cd_vert_node_offset, cd_face_node_offset, bm_log, e, v1, v2, deleted_verts, eq_ctx); } BLI_ghash_free(deleted_verts, nullptr, nullptr); @@ -2060,6 +2104,8 @@ static void pbvh_bmesh_node_limit_ensure_fast(Tree *pbvh, } static void pbvh_bmesh_create_nodes_fast_recursive(Tree *pbvh, + const int cd_vert_node_offset, + const int cd_face_node_offset, const Span nodeinfo, const Span> face_bounds, FastNodeBuildInfo *node, @@ -2072,10 +2118,20 @@ static void pbvh_bmesh_create_nodes_fast_recursive(Tree *pbvh, n->children_offset_ = children_offset_; pbvh->nodes_.resize(pbvh->nodes_.size() + 2); - pbvh_bmesh_create_nodes_fast_recursive( - pbvh, nodeinfo, face_bounds, node->child1, children_offset_); - pbvh_bmesh_create_nodes_fast_recursive( - pbvh, nodeinfo, face_bounds, node->child2, children_offset_ + 1); + pbvh_bmesh_create_nodes_fast_recursive(pbvh, + cd_vert_node_offset, + cd_face_node_offset, + nodeinfo, + face_bounds, + node->child1, + children_offset_); + pbvh_bmesh_create_nodes_fast_recursive(pbvh, + cd_vert_node_offset, + cd_face_node_offset, + nodeinfo, + face_bounds, + node->child2, + children_offset_ + 1); n = &pbvh->nodes_[node_index]; @@ -2087,8 +2143,6 @@ static void pbvh_bmesh_create_nodes_fast_recursive(Tree *pbvh, else { /* Node does not have children so it's a leaf node, populate with faces and tag accordingly * this is an expensive part but it's not so easily thread-able due to vertex node indices. */ - const int cd_vert_node_offset = pbvh->cd_vert_node_offset_; - const int cd_face_node_offset = pbvh->cd_face_node_offset_; bool has_visible = false; @@ -2145,23 +2199,17 @@ static void pbvh_bmesh_create_nodes_fast_recursive(Tree *pbvh, /***************************** Public API *****************************/ -void update_bmesh_offsets(Tree &pbvh, int cd_vert_node_offset, int cd_face_node_offset) -{ - pbvh.cd_vert_node_offset_ = cd_vert_node_offset; - pbvh.cd_face_node_offset_ = cd_face_node_offset; -} - -std::unique_ptr build_bmesh(BMesh *bm, - const int cd_vert_node_offset, - const int cd_face_node_offset) +std::unique_ptr build_bmesh(BMesh *bm) { std::unique_ptr pbvh = std::make_unique(Type::BMesh); pbvh->bm_ = bm; BKE_pbvh_bmesh_detail_size_set(*pbvh, 0.75); - - pbvh::update_bmesh_offsets(*pbvh, cd_vert_node_offset, cd_face_node_offset); + const int cd_vert_node_offset = CustomData_get_offset_named( + &bm->vdata, CD_PROP_INT32, ".sculpt_dyntopo_node_id_vertex"); + const int cd_face_node_offset = CustomData_get_offset_named( + &bm->pdata, CD_PROP_INT32, ".sculpt_dyntopo_node_id_face"); if (bm->totface == 0) { return pbvh; @@ -2211,7 +2259,8 @@ std::unique_ptr build_bmesh(BMesh *bm, pbvh->nodes_.append({}); /* Take root node and visit and populate children recursively. */ - pbvh_bmesh_create_nodes_fast_recursive(pbvh.get(), nodeinfo, face_bounds, &rootnode, 0); + pbvh_bmesh_create_nodes_fast_recursive( + pbvh.get(), cd_vert_node_offset, cd_face_node_offset, nodeinfo, face_bounds, &rootnode, 0); BLI_memarena_free(arena); return pbvh; @@ -2226,10 +2275,12 @@ bool bmesh_update_topology(Tree &pbvh, const bool use_frontface, const bool use_projected) { + const int cd_vert_node_offset = CustomData_get_offset_named( + &pbvh.bm_->vdata, CD_PROP_INT32, ".sculpt_dyntopo_node_id_vertex"); + const int cd_face_node_offset = CustomData_get_offset_named( + &pbvh.bm_->pdata, CD_PROP_INT32, ".sculpt_dyntopo_node_id_face"); const int cd_vert_mask_offset = CustomData_get_offset_named( &pbvh.bm_->vdata, CD_PROP_FLOAT, ".sculpt_mask"); - const int cd_vert_node_offset = pbvh.cd_vert_node_offset_; - const int cd_face_node_offset = pbvh.cd_face_node_offset_; bool modified = false; @@ -2251,7 +2302,8 @@ bool bmesh_update_topology(Tree &pbvh, short_edge_queue_create( &eq_ctx, pbvh, center, view_normal, radius, use_frontface, use_projected); - modified |= pbvh_bmesh_collapse_short_edges(&eq_ctx, pbvh, bm_log); + modified |= pbvh_bmesh_collapse_short_edges( + &eq_ctx, pbvh, cd_vert_node_offset, cd_face_node_offset, bm_log); BLI_heapsimple_free(q.heap, nullptr); BLI_mempool_destroy(queue_pool); } @@ -2270,7 +2322,8 @@ bool bmesh_update_topology(Tree &pbvh, long_edge_queue_create( &eq_ctx, pbvh, center, view_normal, radius, use_frontface, use_projected); - modified |= pbvh_bmesh_subdivide_long_edges(&eq_ctx, pbvh, bm_log); + modified |= pbvh_bmesh_subdivide_long_edges( + &eq_ctx, pbvh, cd_vert_node_offset, cd_face_node_offset, bm_log); BLI_heapsimple_free(q.heap, nullptr); BLI_mempool_destroy(queue_pool); } @@ -2375,6 +2428,10 @@ void BKE_pbvh_bmesh_node_save_orig(BMesh *bm, void BKE_pbvh_bmesh_after_stroke(blender::bke::pbvh::Tree &pbvh) { + const int cd_vert_node_offset = CustomData_get_offset_named( + &pbvh.bm_->vdata, CD_PROP_INT32, ".sculpt_dyntopo_node_id_vertex"); + const int cd_face_node_offset = CustomData_get_offset_named( + &pbvh.bm_->pdata, CD_PROP_INT32, ".sculpt_dyntopo_node_id_face"); const int totnode = pbvh.nodes_.size(); for (int i = 0; i < totnode; i++) { blender::bke::pbvh::Node *n = &pbvh.nodes_[i]; @@ -2383,7 +2440,7 @@ void BKE_pbvh_bmesh_after_stroke(blender::bke::pbvh::Tree &pbvh) pbvh_bmesh_node_drop_orig(n); /* Recursively split nodes that have gotten too many elements. */ - pbvh_bmesh_node_limit_ensure(pbvh, i); + pbvh_bmesh_node_limit_ensure(pbvh, cd_vert_node_offset, cd_face_node_offset, i); } } } @@ -2478,7 +2535,7 @@ static void pbvh_bmesh_verify(Tree *pbvh) { BMFace *f; BM_ITER_MESH (f, &iter, pbvh->header.bm, BM_FACES_OF_MESH) { - BLI_assert(BM_ELEM_CD_GET_INT(f, pbvh->cd_face_node_offset_) != DYNTOPO_NODE_NONE); + BLI_assert(BM_ELEM_CD_GET_INT(f, cd_face_node_offset) != DYNTOPO_NODE_NONE); BLI_gset_insert(faces_all, f); } } @@ -2487,7 +2544,7 @@ static void pbvh_bmesh_verify(Tree *pbvh) { BMVert *v; BM_ITER_MESH (v, &iter, pbvh->header.bm, BM_VERTS_OF_MESH) { - if (BM_ELEM_CD_GET_INT(v, pbvh->cd_vert_node_offset_) != DYNTOPO_NODE_NONE) { + if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) != DYNTOPO_NODE_NONE) { BLI_gset_insert(verts_all, v); } } @@ -2544,7 +2601,7 @@ static void pbvh_bmesh_verify(Tree *pbvh) BMVert *v; BM_ITER_MESH (v, &iter, pbvh->header.bm, BM_VERTS_OF_MESH) { /* Vertex isn't tracked. */ - if (BM_ELEM_CD_GET_INT(v, pbvh->cd_vert_node_offset_) == DYNTOPO_NODE_NONE) { + if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) == DYNTOPO_NODE_NONE) { continue; }