Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/pbvh_bmesh.c')
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c497
1 files changed, 344 insertions, 153 deletions
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 88dc63d6cb2..55f9f384081 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -69,11 +69,134 @@
static void pbvh_bmesh_verify(PBVH *bvh);
#endif
+/** \name BMesh Utility API
+ *
+ * Use some local functions which assume triangles.
+ * \{ */
+
+/**
+ * Typically using BM_LOOPS_OF_VERT and BM_FACES_OF_VERT iterators are fine,
+ * however this is an area where performance matters so do it in-line.
+ *
+ * Take care since 'break' won't works as expected within these macros!
+ */
+
+#define BM_LOOPS_OF_VERT_ITER_BEGIN(l_iter_radial_, v_) \
+{ \
+ struct { BMVert *v; BMEdge *e_iter, *e_first; BMLoop *l_iter_radial; } _iter; \
+ _iter.v = v_; \
+ if (_iter.v->e) { \
+ _iter.e_iter = _iter.e_first = _iter.v->e; \
+ do { \
+ if (_iter.e_iter->l) { \
+ _iter.l_iter_radial = _iter.e_iter->l; \
+ do { \
+ if (_iter.l_iter_radial->v == _iter.v) { \
+ l_iter_radial_ = _iter.l_iter_radial;
+
+#define BM_LOOPS_OF_VERT_ITER_END \
+ } \
+ } while ((_iter.l_iter_radial = _iter.l_iter_radial->radial_next) != _iter.e_iter->l); \
+ } \
+ } while ((_iter.e_iter = BM_DISK_EDGE_NEXT(_iter.e_iter, _iter.v)) != _iter.e_first); \
+ } \
+} ((void)0)
+
+#define BM_FACES_OF_VERT_ITER_BEGIN(f_iter_, v_) \
+{ \
+ BMLoop *l_iter_radial_; \
+ BM_LOOPS_OF_VERT_ITER_BEGIN(l_iter_radial_, v_) { \
+ f_iter_ = l_iter_radial_->f; \
+
+#define BM_FACES_OF_VERT_ITER_END \
+ } \
+ BM_LOOPS_OF_VERT_ITER_END; \
+}
+
+static void bm_edges_from_tri(BMesh *bm, BMVert *v_tri[3], BMEdge *e_tri[3])
+{
+ e_tri[0] = BM_edge_create(bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE);
+ e_tri[1] = BM_edge_create(bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE);
+ e_tri[2] = BM_edge_create(bm, v_tri[2], v_tri[0], NULL, BM_CREATE_NO_DOUBLE);
+}
+
+BLI_INLINE void bm_face_as_array_index_tri(BMFace *f, int r_index[3])
+{
+ BMLoop *l = BM_FACE_FIRST_LOOP(f);
+
+ BLI_assert(f->len == 3);
+
+ r_index[0] = BM_elem_index_get(l->v); l = l->next;
+ r_index[1] = BM_elem_index_get(l->v); l = l->next;
+ r_index[2] = BM_elem_index_get(l->v);
+}
+
+/**
+ * A version of #BM_face_exists, optimized for triangles
+ * when we know the loop and the opposite vertex.
+ *
+ * Check if any triangle is formed by (l_radial_first->v, l_radial_first->next->v, v_opposite),
+ * at either winding (since its a triangle no special checks are needed).
+ *
+ * <pre>
+ * l_radial_first->v & l_radial_first->next->v
+ * +---+
+ * | /
+ * | /
+ * + v_opposite
+ * </pre>
+ *
+ * Its assumed that \a l_radial_first is never forming the target face.
+ */
+static bool bm_face_exists_tri_from_loop_vert(
+ BMLoop *l_radial_first, BMVert *v_opposite, BMFace **r_face_existing)
+{
+ BLI_assert(!ELEM(v_opposite, l_radial_first->v, l_radial_first->next->v, l_radial_first->prev->v));
+ if (l_radial_first->radial_next != l_radial_first) {
+ BMLoop *l_radial_iter = l_radial_first->radial_next;
+ do {
+ BLI_assert(l_radial_iter->f->len == 3);
+ if (l_radial_iter->prev->v == v_opposite) {
+ *r_face_existing = l_radial_iter->f;
+ return true;
+ }
+ } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
+ }
+ return false;
+}
+
+/**
+ * Uses a map of vertices to lookup the final target.
+ * References can't point to previous items (would cause infinite loop).
+ */
+static BMVert *bm_vert_hash_lookup_chain(GHash *deleted_verts, BMVert *v)
+{
+ while (true) {
+ BMVert **v_next_p = (BMVert **)BLI_ghash_lookup_p(deleted_verts, v);
+ if (v_next_p == NULL) {
+ /* not remapped*/
+ return v;
+ }
+ else if (*v_next_p == NULL) {
+ /* removed and not remapped */
+ return NULL;
+ }
+ else {
+ /* remapped */
+ v = *v_next_p;
+ }
+ }
+}
+
+/** \} */
+
/****************************** Building ******************************/
/* Update node data after splitting */
-static void pbvh_bmesh_node_finalize(PBVH *bvh, int node_index, const int cd_vert_node_offset, const int cd_face_node_offset)
+static void pbvh_bmesh_node_finalize(
+ PBVH *bvh, const int node_index,
+ const int cd_vert_node_offset, const int cd_face_node_offset)
{
GSetIterator gs_iter;
PBVHNode *n = &bvh->nodes[node_index];
@@ -200,7 +323,7 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde
break;
}
}
-
+
/* Clear this node */
/* Mark this node's unique verts as unclaimed */
@@ -224,18 +347,18 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde
if (n->layer_disp)
MEM_freeN(n->layer_disp);
-
+
n->bm_faces = NULL;
n->bm_unique_verts = NULL;
n->bm_other_verts = NULL;
n->layer_disp = NULL;
-
+
if (n->draw_buffers) {
GPU_free_pbvh_buffers(n->draw_buffers);
n->draw_buffers = NULL;
}
n->flag &= ~PBVH_Leaf;
-
+
/* Recurse */
pbvh_bmesh_node_split(bvh, bbc_array, children);
pbvh_bmesh_node_split(bvh, bbc_array, children + 1);
@@ -292,6 +415,7 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index)
/**********************************************************************/
+#if 0
static int pbvh_bmesh_node_offset_from_elem(PBVH *bvh, BMElem *ele)
{
switch (ele->head.htype) {
@@ -304,7 +428,7 @@ static int pbvh_bmesh_node_offset_from_elem(PBVH *bvh, BMElem *ele)
}
-static int pbvh_bmesh_node_lookup_index(PBVH *bvh, void *key)
+static int pbvh_bmesh_node_index_from_elem(PBVH *bvh, void *key)
{
const int cd_node_offset = pbvh_bmesh_node_offset_from_elem(bvh, key);
const int node_index = BM_ELEM_CD_GET_INT((BMElem *)key, cd_node_offset);
@@ -316,18 +440,45 @@ static int pbvh_bmesh_node_lookup_index(PBVH *bvh, void *key)
return node_index;
}
-static PBVHNode *pbvh_bmesh_node_lookup(PBVH *bvh, void *key)
+static PBVHNode *pbvh_bmesh_node_from_elem(PBVH *bvh, void *key)
{
- return &bvh->nodes[pbvh_bmesh_node_lookup_index(bvh, key)];
+ return &bvh->nodes[pbvh_bmesh_node_index_from_elem(bvh, key)];
}
/* typecheck */
-#define pbvh_bmesh_node_lookup_index(bvh, key) ( \
+#define pbvh_bmesh_node_index_from_elem(bvh, key) ( \
CHECK_TYPE_ANY(key, BMFace *, BMVert *), \
- pbvh_bmesh_node_lookup_index(bvh, key))
-#define pbvh_bmesh_node_lookup(bvh, key) ( \
+ pbvh_bmesh_node_index_from_elem(bvh, key))
+#define pbvh_bmesh_node_from_elem(bvh, key) ( \
CHECK_TYPE_ANY(key, BMFace *, BMVert *), \
- pbvh_bmesh_node_lookup(bvh, key))
+ pbvh_bmesh_node_from_elem(bvh, key))
+#endif
+
+BLI_INLINE int pbvh_bmesh_node_index_from_vert(PBVH *bvh, const BMVert *key)
+{
+ const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, bvh->cd_vert_node_offset);
+ BLI_assert(node_index != DYNTOPO_NODE_NONE);
+ BLI_assert(node_index < bvh->totnode);
+ return node_index;
+}
+
+BLI_INLINE int pbvh_bmesh_node_index_from_face(PBVH *bvh, const BMFace *key)
+{
+ const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, bvh->cd_face_node_offset);
+ BLI_assert(node_index != DYNTOPO_NODE_NONE);
+ BLI_assert(node_index < bvh->totnode);
+ return node_index;
+}
+
+BLI_INLINE PBVHNode *pbvh_bmesh_node_from_vert(PBVH *bvh, const BMVert *key)
+{
+ return &bvh->nodes[pbvh_bmesh_node_index_from_vert(bvh, key)];
+}
+
+BLI_INLINE PBVHNode *pbvh_bmesh_node_from_face(PBVH *bvh, const BMFace *key)
+{
+ return &bvh->nodes[pbvh_bmesh_node_index_from_face(bvh, key)];
+}
static BMVert *pbvh_bmesh_vert_create(
@@ -357,6 +508,9 @@ static BMVert *pbvh_bmesh_vert_create(
return v;
}
+/**
+ * \note Callers are responsible for checking if the face exists before adding.
+ */
static BMFace *pbvh_bmesh_face_create(
PBVH *bvh, int node_index,
BMVert *v_tri[3], BMEdge *e_tri[3],
@@ -367,7 +521,7 @@ static BMFace *pbvh_bmesh_face_create(
/* ensure we never add existing face */
BLI_assert(BM_face_exists(v_tri, 3, NULL) == false);
- BMFace *f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NO_DOUBLE);
+ BMFace *f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP);
f->head.hflag = f_example->head.hflag;
BLI_gset_insert(node->bm_faces, f);
@@ -387,16 +541,16 @@ static BMFace *pbvh_bmesh_face_create(
#if 0
static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v)
{
- BMIter bm_iter;
BMFace *f;
int count = 0;
- BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
- PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f);
+ BM_FACES_OF_VERT_ITER_BEGIN(f, v) {
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
if (f_node == node) {
count++;
}
}
+ BM_FACES_OF_VERT_ITER_END;
return count;
}
@@ -407,19 +561,19 @@ static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v)
static int pbvh_bmesh_node_vert_use_count_ex(PBVH *bvh, PBVHNode *node, BMVert *v, const int count_max)
{
- BMIter bm_iter;
- BMFace *f;
int count = 0;
+ BMFace *f;
- BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
- PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f);
+ BM_FACES_OF_VERT_ITER_BEGIN(f, v) {
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
if (f_node == node) {
count++;
if (count == count_max) {
- break;
+ return count;
}
}
}
+ BM_FACES_OF_VERT_ITER_END;
return count;
}
@@ -427,16 +581,17 @@ static int pbvh_bmesh_node_vert_use_count_ex(PBVH *bvh, PBVHNode *node, BMVert *
/* Return a node that uses vertex 'v' other than its current owner */
static PBVHNode *pbvh_bmesh_vert_other_node_find(PBVH *bvh, BMVert *v)
{
- BMIter bm_iter;
+ PBVHNode *current_node = pbvh_bmesh_node_from_vert(bvh, v);
BMFace *f;
- PBVHNode *current_node = pbvh_bmesh_node_lookup(bvh, v);
- BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
- PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f);
+ BM_FACES_OF_VERT_ITER_BEGIN(f, v) {
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
- if (f_node != current_node)
+ if (f_node != current_node) {
return f_node;
+ }
}
+ BM_FACES_OF_VERT_ITER_END;
return NULL;
}
@@ -445,7 +600,7 @@ static void pbvh_bmesh_vert_ownership_transfer(
PBVH *bvh, PBVHNode *new_owner,
BMVert *v)
{
- PBVHNode *current_owner = pbvh_bmesh_node_lookup(bvh, v);
+ PBVHNode *current_owner = pbvh_bmesh_node_from_vert(bvh, v);
/* mark node for update */
current_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
@@ -469,36 +624,36 @@ static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v)
/* never match for first time */
int f_node_index_prev = DYNTOPO_NODE_NONE;
- PBVHNode *v_node = pbvh_bmesh_node_lookup(bvh, v);
+ PBVHNode *v_node = pbvh_bmesh_node_from_vert(bvh, v);
BLI_gset_remove(v_node->bm_unique_verts, v, NULL);
BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, DYNTOPO_NODE_NONE);
/* Have to check each neighboring face's node */
- BMIter bm_iter;
BMFace *f;
- BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
- const int f_node_index = pbvh_bmesh_node_lookup_index(bvh, f);
+ BM_FACES_OF_VERT_ITER_BEGIN(f, v) {
+ const int f_node_index = pbvh_bmesh_node_index_from_face(bvh, f);
/* faces often share the same node,
* quick check to avoid redundant #BLI_gset_remove calls */
- if (f_node_index_prev == f_node_index)
- continue;
- f_node_index_prev = f_node_index;
+ if (f_node_index_prev != f_node_index) {
+ f_node_index_prev = f_node_index;
- PBVHNode *f_node = &bvh->nodes[f_node_index];
- f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
+ PBVHNode *f_node = &bvh->nodes[f_node_index];
+ f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
- /* Remove current ownership */
- BLI_gset_remove(f_node->bm_other_verts, v, NULL);
+ /* Remove current ownership */
+ BLI_gset_remove(f_node->bm_other_verts, v, NULL);
- BLI_assert(!BLI_gset_haskey(f_node->bm_unique_verts, v));
- BLI_assert(!BLI_gset_haskey(f_node->bm_other_verts, v));
+ BLI_assert(!BLI_gset_haskey(f_node->bm_unique_verts, v));
+ BLI_assert(!BLI_gset_haskey(f_node->bm_other_verts, v));
+ }
}
+ BM_FACES_OF_VERT_ITER_END;
}
static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f)
{
- PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f);
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f);
/* Check if any of this face's vertices need to be removed
* from the node */
@@ -923,13 +1078,6 @@ static void short_edge_queue_create(
/*************************** Topology update **************************/
-static void bm_edges_from_tri(BMesh *bm, BMVert *v_tri[3], BMEdge *e_tri[3])
-{
- e_tri[0] = BM_edge_create(bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE);
- e_tri[1] = BM_edge_create(bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE);
- e_tri[2] = BM_edge_create(bm, v_tri[2], v_tri[0], NULL, BM_CREATE_NO_DOUBLE);
-}
-
static void pbvh_bmesh_split_edge(
EdgeQueueContext *eq_ctx, PBVH *bvh,
BMEdge *e, BLI_Buffer *edge_loops)
@@ -1101,15 +1249,16 @@ static bool pbvh_bmesh_subdivide_long_edges(
static void pbvh_bmesh_collapse_edge(
PBVH *bvh, BMEdge *e,
BMVert *v1, BMVert *v2,
- GSet *deleted_verts,
+ GHash *deleted_verts,
BLI_Buffer *deleted_faces,
EdgeQueueContext *eq_ctx)
{
BMVert *v_del, *v_conn;
- float mask_v1 = BM_ELEM_CD_GET_FLOAT(v1, eq_ctx->cd_vert_mask_offset);
/* one of the two vertices may be masked, select the correct one for deletion */
- if (mask_v1 < 1.0f) {
+ if (BM_ELEM_CD_GET_FLOAT(v1, eq_ctx->cd_vert_mask_offset) <
+ BM_ELEM_CD_GET_FLOAT(v2, eq_ctx->cd_vert_mask_offset))
+ {
v_del = v1;
v_conn = v2;
}
@@ -1141,33 +1290,43 @@ static void pbvh_bmesh_collapse_edge(
* really buy anything. */
BLI_buffer_empty(deleted_faces);
- BMIter bm_iter;
- BMFace *f;
+ BMLoop *l;
- BM_ITER_ELEM (f, &bm_iter, v_del, BM_FACES_OF_VERT) {
- BMVert *v_tri[3];
+ BM_LOOPS_OF_VERT_ITER_BEGIN(l, v_del) {
BMFace *existing_face;
/* Get vertices, replace use of v_del with v_conn */
// BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v_tri, 3);
+ BMFace *f = l->f;
+#if 0
+ BMVert *v_tri[3];
BM_face_as_array_vert_tri(f, v_tri);
for (int i = 0; i < 3; i++) {
if (v_tri[i] == v_del) {
v_tri[i] = v_conn;
}
}
+#endif
/* Check if a face using these vertices already exists. If so,
* skip adding this face and mark the existing one for
* deletion as well. Prevents extraneous "flaps" from being
* created. */
- if (BM_face_exists(v_tri, 3, &existing_face)) {
+#if 0
+ if (UNLIKELY(BM_face_exists(v_tri, 3, &existing_face)))
+#else
+ if (UNLIKELY(bm_face_exists_tri_from_loop_vert(l->next, v_conn, &existing_face)))
+#endif
+ {
BLI_assert(existing_face);
BLI_buffer_append(deleted_faces, BMFace *, existing_face);
}
else {
+ BMVert *v_tri[3] = {v_conn, l->next->v, l->prev->v};
+
+ BLI_assert(BM_face_exists(v_tri, 3, NULL) == false);
BMEdge *e_tri[3];
- PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f);
+ PBVHNode *n = pbvh_bmesh_node_from_face(bvh, f);
int ni = n - bvh->nodes;
bm_edges_from_tri(bvh->bm, v_tri, e_tri);
pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f);
@@ -1180,6 +1339,7 @@ static void pbvh_bmesh_collapse_edge(
BLI_buffer_append(deleted_faces, BMFace *, f);
}
+ BM_LOOPS_OF_VERT_ITER_END;
/* Delete the tagged faces */
for (int i = 0; i < deleted_faces->count; i++) {
@@ -1209,10 +1369,14 @@ static void pbvh_bmesh_collapse_edge(
* remove them from the PBVH */
for (int j = 0; j < 3; j++) {
if ((v_tri[j] != v_del) && (v_tri[j]->e == NULL)) {
- BLI_gset_insert(deleted_verts, v_tri[j]);
pbvh_bmesh_vert_remove(bvh, v_tri[j]);
BM_log_vert_removed(bvh->bm_log, v_tri[j], eq_ctx->cd_vert_mask_offset);
+
+ if (v_tri[j] == v_conn) {
+ v_conn = NULL;
+ }
+ BLI_ghash_insert(deleted_verts, v_tri[j], NULL);
BM_vert_kill(bvh->bm, v_tri[j]);
}
}
@@ -1220,17 +1384,26 @@ static void pbvh_bmesh_collapse_edge(
/* Move v_conn to the midpoint of v_conn and v_del (if v_conn still exists, it
* may have been deleted above) */
- if (!BLI_gset_haskey(deleted_verts, v_conn)) {
+ if (v_conn != NULL) {
BM_log_vert_before_modified(bvh->bm_log, v_conn, eq_ctx->cd_vert_mask_offset);
mid_v3_v3v3(v_conn->co, v_conn->co, v_del->co);
add_v3_v3(v_conn->no, v_del->no);
normalize_v3(v_conn->no);
+
+ /* update boundboxes attached to the connected vertex
+ * note that we can often get-away without this but causes T48779 */
+ BM_LOOPS_OF_VERT_ITER_BEGIN(l, v_conn) {
+ PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, l->f);
+ f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_UpdateBB;
+ }
+ BM_LOOPS_OF_VERT_ITER_END;
}
/* Delete v_del */
BLI_assert(!BM_vert_face_check(v_del));
- BLI_gset_insert(deleted_verts, v_del);
BM_log_vert_removed(bvh->bm_log, v_del, eq_ctx->cd_vert_mask_offset);
+ /* v_conn == NULL is OK */
+ BLI_ghash_insert(deleted_verts, v_del, v_conn);
BM_vert_kill(bvh->bm, v_del);
}
@@ -1241,17 +1414,19 @@ static bool pbvh_bmesh_collapse_short_edges(
{
const float min_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len;
bool any_collapsed = false;
- GSet *deleted_verts = BLI_gset_ptr_new("deleted_verts");
+ /* deleted verts point to vertices they were merged into, or NULL when removed. */
+ GHash *deleted_verts = BLI_ghash_ptr_new("deleted_verts");
while (!BLI_heap_is_empty(eq_ctx->q->heap)) {
BMVert **pair = BLI_heap_popmin(eq_ctx->q->heap);
- BMVert *v1 = pair[0], *v2 = pair[1];
+ BMVert *v1 = pair[0], *v2 = pair[1];
BLI_mempool_free(eq_ctx->pool, pair);
pair = NULL;
/* Check the verts still exist */
- if (BLI_gset_haskey(deleted_verts, v1) ||
- BLI_gset_haskey(deleted_verts, v2))
+ if (!(v1 = bm_vert_hash_lookup_chain(deleted_verts, v1)) ||
+ !(v2 = bm_vert_hash_lookup_chain(deleted_verts, v2)) ||
+ (v1 == v2))
{
continue;
}
@@ -1285,7 +1460,7 @@ static bool pbvh_bmesh_collapse_short_edges(
deleted_faces, eq_ctx);
}
- BLI_gset_free(deleted_verts, NULL);
+ BLI_ghash_free(deleted_verts, NULL, NULL);
return any_collapsed;
}
@@ -1406,18 +1581,23 @@ void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode)
}
}
-typedef struct FastNodeBuildInfo {
+struct FastNodeBuildInfo {
int totface; /* number of faces */
int start; /* start of faces in array */
struct FastNodeBuildInfo *child1;
struct FastNodeBuildInfo *child2;
-} FastNodeBuildInfo;
+};
-/* Recursively split the node if it exceeds the leaf_limit. This function is multithreadabe since each invocation applies
- * to a sub part of the arrays */
-static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, MemArena *arena)
+/**
+ * Recursively split the node if it exceeds the leaf_limit.
+ * This function is multithreadabe since each invocation applies
+ * to a sub part of the arrays
+ */
+static void pbvh_bmesh_node_limit_ensure_fast(
+ PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, struct FastNodeBuildInfo *node,
+ MemArena *arena)
{
- FastNodeBuildInfo *child1, *child2;
+ struct FastNodeBuildInfo *child1, *child2;
if (node->totface <= bvh->leaf_limit) {
return;
@@ -1497,8 +1677,8 @@ static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC
* each sequential part belonging to one node only */
BLI_assert((num_child1 + num_child2) == node->totface);
- node->child1 = child1 = BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo));
- node->child2 = child2 = BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo));
+ node->child1 = child1 = BLI_memarena_alloc(arena, sizeof(struct FastNodeBuildInfo));
+ node->child2 = child2 = BLI_memarena_alloc(arena, sizeof(struct FastNodeBuildInfo));
child1->totface = num_child1;
child1->start = node->start;
@@ -1510,7 +1690,9 @@ static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC
pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child2, arena);
}
-static void pbvh_bmesh_create_nodes_fast_recursive(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, int node_index)
+static void pbvh_bmesh_create_nodes_fast_recursive(
+ PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array,
+ struct FastNodeBuildInfo *node, int node_index)
{
PBVHNode *n = bvh->nodes + node_index;
/* two cases, node does not have children or does have children */
@@ -1651,7 +1833,7 @@ void BKE_pbvh_build_bmesh(
bm->elem_index_dirty |= BM_FACE;
/* setup root node */
- FastNodeBuildInfo rootnode = {0};
+ struct FastNodeBuildInfo rootnode = {0};
rootnode.totface = bm->totface;
/* start recursion, assign faces to nodes accordingly */
@@ -1693,12 +1875,14 @@ bool BKE_pbvh_bmesh_update_topology(
if (mode & PBVH_Collapse) {
EdgeQueue q;
BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP);
- EdgeQueueContext eq_ctx = {&q, queue_pool, bvh->bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset};
+ EdgeQueueContext eq_ctx = {
+ &q, queue_pool, bvh->bm,
+ cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset,
+ };
short_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius);
- modified |= !BLI_heap_is_empty(q.heap);
- pbvh_bmesh_collapse_short_edges(&eq_ctx, bvh,
- &deleted_faces);
+ modified |= pbvh_bmesh_collapse_short_edges(
+ &eq_ctx, bvh, &deleted_faces);
BLI_heap_free(q.heap, NULL);
BLI_mempool_destroy(queue_pool);
}
@@ -1706,15 +1890,18 @@ bool BKE_pbvh_bmesh_update_topology(
if (mode & PBVH_Subdivide) {
EdgeQueue q;
BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP);
- EdgeQueueContext eq_ctx = {&q, queue_pool, bvh->bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset};
+ EdgeQueueContext eq_ctx = {
+ &q, queue_pool, bvh->bm,
+ cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset,
+ };
long_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius);
- modified |= !BLI_heap_is_empty(q.heap);
- pbvh_bmesh_subdivide_long_edges(&eq_ctx, bvh, &edge_loops);
+ modified |= pbvh_bmesh_subdivide_long_edges(
+ &eq_ctx, bvh, &edge_loops);
BLI_heap_free(q.heap, NULL);
BLI_mempool_destroy(queue_pool);
}
-
+
/* Unmark nodes */
for (int n = 0; n < bvh->totnode; n++) {
PBVHNode *node = &bvh->nodes[n];
@@ -1735,16 +1922,6 @@ bool BKE_pbvh_bmesh_update_topology(
return modified;
}
-BLI_INLINE void bm_face_as_array_index_tri(BMFace *f, int r_index[3])
-{
- BMLoop *l = BM_FACE_FIRST_LOOP(f);
-
- BLI_assert(f->len == 3);
-
- r_index[0] = BM_elem_index_get(l->v); l = l->next;
- r_index[1] = BM_elem_index_get(l->v); l = l->next;
- r_index[2] = BM_elem_index_get(l->v);
-}
/* In order to perform operations on the original node coordinates
* (currently just raycast), store the node's triangles and vertices.
@@ -1858,8 +2035,8 @@ static void pbvh_bmesh_print(PBVH *bvh)
BMFace *f;
BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
fprintf(stderr, " %d -> %d\n",
- BM_elem_index_get(v),
- pbvh_bmesh_node_lookup_index(bvh, f));
+ BM_elem_index_get(f),
+ pbvh_bmesh_node_index_from_face(bvh, f));
}
fprintf(stderr, "bm_vert_to_node:\n");
@@ -1867,7 +2044,7 @@ static void pbvh_bmesh_print(PBVH *bvh)
BM_ITER_MESH(v, &iter, bvh->bm, BM_FACES_OF_MESH) {
fprintf(stderr, " %d -> %d\n",
BM_elem_index_get(v),
- pbvh_bmesh_node_lookup_index(bvh, v));
+ pbvh_bmesh_node_index_from_vert(bvh, v));
}
for (int n = 0; n < bvh->totnode; n++) {
@@ -1909,17 +2086,23 @@ static void pbvh_bmesh_verify(PBVH *bvh)
{
/* build list of faces & verts to lookup */
GSet *faces_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totface);
- BMFace *f;
BMIter iter;
- BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
- BLI_gset_insert(faces_all, f);
+
+ {
+ BMFace *f;
+ BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
+ BLI_assert(BM_ELEM_CD_GET_INT(f, bvh->cd_face_node_offset) != DYNTOPO_NODE_NONE);
+ BLI_gset_insert(faces_all, f);
+ }
}
GSet *verts_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totvert);
- BMVert *v;
- BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
- if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
- BLI_gset_insert(verts_all, v);
+ {
+ BMVert *v;
+ BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
+ if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
+ BLI_gset_insert(verts_all, v);
+ }
}
}
@@ -1936,76 +2119,83 @@ static void pbvh_bmesh_verify(PBVH *bvh)
BLI_assert(totvert == BLI_gset_size(verts_all));
}
- BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
- BMIter bm_iter;
- BMVert *v;
- PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f);
+ {
+ BMFace *f;
+ BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
+ BMIter bm_iter;
+ BMVert *v;
+ PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f);
- /* Check that the face's node is a leaf */
- BLI_assert(n->flag & PBVH_Leaf);
+ /* Check that the face's node is a leaf */
+ BLI_assert(n->flag & PBVH_Leaf);
- /* Check that the face's node knows it owns the face */
- BLI_assert(BLI_gset_haskey(n->bm_faces, f));
+ /* Check that the face's node knows it owns the face */
+ BLI_assert(BLI_gset_haskey(n->bm_faces, f));
- /* Check the face's vertices... */
- BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) {
- PBVHNode *nv;
+ /* Check the face's vertices... */
+ BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) {
+ PBVHNode *nv;
- /* Check that the vertex is in the node */
- BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v) ^
- BLI_gset_haskey(n->bm_other_verts, v));
+ /* Check that the vertex is in the node */
+ BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v) ^
+ BLI_gset_haskey(n->bm_other_verts, v));
- /* Check that the vertex has a node owner */
- nv = pbvh_bmesh_node_lookup(bvh, v);
+ /* Check that the vertex has a node owner */
+ nv = pbvh_bmesh_node_lookup(bvh, v);
- /* Check that the vertex's node knows it owns the vert */
- BLI_assert(BLI_gset_haskey(nv->bm_unique_verts, v));
+ /* Check that the vertex's node knows it owns the vert */
+ BLI_assert(BLI_gset_haskey(nv->bm_unique_verts, v));
- /* Check that the vertex isn't duplicated as an 'other' vert */
- BLI_assert(!BLI_gset_haskey(nv->bm_other_verts, v));
+ /* Check that the vertex isn't duplicated as an 'other' vert */
+ BLI_assert(!BLI_gset_haskey(nv->bm_other_verts, v));
+ }
}
}
/* Check verts */
- BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
- /* vertex isn't tracked */
- if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) {
- continue;
- }
+ {
+ BMVert *v;
+ BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
+ /* vertex isn't tracked */
+ if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) {
+ continue;
+ }
- PBVHNode *n = pbvh_bmesh_node_lookup(bvh, v);
+ PBVHNode *n = pbvh_bmesh_node_lookup(bvh, v);
- /* Check that the vert's node is a leaf */
- BLI_assert(n->flag & PBVH_Leaf);
+ /* Check that the vert's node is a leaf */
+ BLI_assert(n->flag & PBVH_Leaf);
- /* Check that the vert's node knows it owns the vert */
- BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v));
+ /* Check that the vert's node knows it owns the vert */
+ BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v));
- /* Check that the vertex isn't duplicated as an 'other' vert */
- BLI_assert(!BLI_gset_haskey(n->bm_other_verts, v));
+ /* Check that the vertex isn't duplicated as an 'other' vert */
+ BLI_assert(!BLI_gset_haskey(n->bm_other_verts, v));
- /* Check that the vert's node also contains one of the vert's
- * adjacent faces */
- bool found = false;
- BMIter bm_iter;
- BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
- if (pbvh_bmesh_node_lookup(bvh, f) == n) {
- found = true;
- break;
+ /* Check that the vert's node also contains one of the vert's
+ * adjacent faces */
+ bool found = false;
+ BMIter bm_iter;
+ BMFace *f = NULL;
+ BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
+ if (pbvh_bmesh_node_lookup(bvh, f) == n) {
+ found = true;
+ break;
+ }
}
- }
- BLI_assert(found);
+ BLI_assert(found || f == NULL);
#if 1
- /* total freak stuff, check if node exists somewhere else */
- /* Slow */
- for (int i = 0; i < bvh->totnode; i++) {
- PBVHNode *n_other = &bvh->nodes[i];
- if ((n != n_other) && (n_other->bm_unique_verts)) {
- BLI_assert(!BLI_gset_haskey(n_other->bm_unique_verts, v));
+ /* total freak stuff, check if node exists somewhere else */
+ /* Slow */
+ for (int i = 0; i < bvh->totnode; i++) {
+ PBVHNode *n_other = &bvh->nodes[i];
+ if ((n != n_other) && (n_other->bm_unique_verts)) {
+ BLI_assert(!BLI_gset_haskey(n_other->bm_unique_verts, v));
+ }
}
- }
#endif
+ }
}
#if 0
@@ -2049,7 +2239,8 @@ static void pbvh_bmesh_verify(PBVH *bvh)
GSET_ITER (gs_iter, n->bm_other_verts) {
BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
- BLI_assert(!BM_vert_face_check(v));
+ /* this happens sometimes and seems harmless */
+ // BLI_assert(!BM_vert_face_check(v));
BLI_assert(BLI_gset_haskey(verts_all, v));
}
}