Blender V4.3
pbvh_bmesh.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "MEM_guardedalloc.h"
10
11#include "BLI_bounds.hh"
12#include "BLI_ghash.h"
13#include "BLI_heap_simple.h"
14#include "BLI_math_geom.h"
15#include "BLI_math_vector.h"
16#include "BLI_math_vector.hh"
17#include "BLI_memarena.h"
18#include "BLI_span.hh"
19#include "BLI_time.h"
20#include "BLI_utildefines.h"
21
22#include "BKE_ccg.hh"
23#include "BKE_pbvh_api.hh"
24
25#include "bmesh.hh"
26#include "pbvh_intern.hh"
27
28#include "CLG_log.h"
29
30static CLG_LogRef LOG = {"pbvh.bmesh"};
31
32/* Avoid skinny faces */
33#define USE_EDGEQUEUE_EVEN_SUBDIV
34#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
35# include "BKE_global.hh"
36#endif
37
38namespace blender::bke::pbvh {
39
40/* Support for only operating on front-faces. */
41#define USE_EDGEQUEUE_FRONTFACE
42
43/* Don't add edges into the queue multiple times. */
44#define USE_EDGEQUEUE_TAG
49#if defined(USE_EDGEQUEUE_TAG) && 0
50# if !defined(NDEBUG)
51# define USE_EDGEQUEUE_TAG_VERIFY
52# endif
53#endif
54
55// #define USE_VERIFY
56
57#ifdef USE_VERIFY
58static void pbvh_bmesh_verify(Tree *pbvh);
59#endif
60
61/* TODO: choose leaf limit better. */
62constexpr int leaf_limit = 400;
63
64/* -------------------------------------------------------------------- */
77#define BM_LOOPS_OF_VERT_ITER_BEGIN(l_iter_radial_, v_) \
78 { \
79 struct { \
80 BMVert *v; \
81 BMEdge *e_iter, *e_first; \
82 BMLoop *l_iter_radial; \
83 } _iter; \
84 _iter.v = v_; \
85 if (_iter.v->e) { \
86 _iter.e_iter = _iter.e_first = _iter.v->e; \
87 do { \
88 if (_iter.e_iter->l) { \
89 _iter.l_iter_radial = _iter.e_iter->l; \
90 do { \
91 if (_iter.l_iter_radial->v == _iter.v) { \
92 l_iter_radial_ = _iter.l_iter_radial;
93
94#define BM_LOOPS_OF_VERT_ITER_END \
95 } \
96 } \
97 while ((_iter.l_iter_radial = _iter.l_iter_radial->radial_next) != _iter.e_iter->l) \
98 ; \
99 } \
100 } \
101 while ((_iter.e_iter = BM_DISK_EDGE_NEXT(_iter.e_iter, _iter.v)) != _iter.e_first) \
102 ; \
103 } \
104 } \
105 ((void)0)
106
107#define BM_FACES_OF_VERT_ITER_BEGIN(f_iter_, v_) \
108 { \
109 BMLoop *l_iter_radial_; \
110 BM_LOOPS_OF_VERT_ITER_BEGIN (l_iter_radial_, v_) { \
111 f_iter_ = l_iter_radial_->f;
112
113#define BM_FACES_OF_VERT_ITER_END \
114 } \
115 BM_LOOPS_OF_VERT_ITER_END; \
116 } \
117 ((void)0)
118
120{
121 return {float3(std::numeric_limits<float>::max()), float3(std::numeric_limits<float>::lowest())};
122}
123
124static std::array<BMEdge *, 3> bm_edges_from_tri(BMesh &bm, const Span<BMVert *> v_tri)
125{
126 return {
127 BM_edge_create(&bm, v_tri[0], v_tri[1], nullptr, BM_CREATE_NO_DOUBLE),
128 BM_edge_create(&bm, v_tri[1], v_tri[2], nullptr, BM_CREATE_NO_DOUBLE),
129 BM_edge_create(&bm, v_tri[2], v_tri[0], nullptr, BM_CREATE_NO_DOUBLE),
130 };
131}
132
133BLI_INLINE std::array<BMVert *, 3> bm_face_as_array(BMFace *f)
134{
136
137 BLI_assert(f->len == 3);
138
139 std::array<BMVert *, 3> result;
140 result[0] = l->v;
141 l = l->next;
142 result[1] = l->v;
143 l = l->next;
144 result[2] = l->v;
145 return result;
146}
147
165static BMFace *bm_face_exists_tri_from_loop_vert(BMLoop *l_radial_first, BMVert *v_opposite)
166{
168 !ELEM(v_opposite, l_radial_first->v, l_radial_first->next->v, l_radial_first->prev->v));
169 if (l_radial_first->radial_next != l_radial_first) {
170 BMLoop *l_radial_iter = l_radial_first->radial_next;
171 do {
172 BLI_assert(l_radial_iter->f->len == 3);
173 if (l_radial_iter->prev->v == v_opposite) {
174 return l_radial_iter->f;
175 }
176 } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first);
177 }
178 return nullptr;
179}
180
186{
187 while (true) {
188 BMVert **v_next_p = (BMVert **)BLI_ghash_lookup_p(deleted_verts, v);
189 if (v_next_p == nullptr) {
190 /* Not remapped. */
191 return v;
192 }
193 if (*v_next_p == nullptr) {
194 /* Removed and not remapped. */
195 return nullptr;
196 }
197
198 /* Remapped. */
199 v = *v_next_p;
200 }
201}
202
205/****************************** Building ******************************/
206
209 const int node_index,
210 const int cd_vert_node_offset,
211 const int cd_face_node_offset)
212{
213 bool has_visible = false;
214
216
217 for (BMFace *f : n->bm_faces_) {
218 /* Update ownership of faces. */
219 BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index);
220
221 /* Update vertices. */
222 BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
223 BMLoop *l_iter = l_first;
224
225 do {
226 BMVert *v = l_iter->v;
227 if (!n->bm_unique_verts_.contains(v)) {
228 if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
230 }
231 else {
233 BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, node_index);
234 }
235 }
236 /* Update node bounding box. */
237 math::min_max(float3(v->co), n->bounds_.min, n->bounds_.max);
238 } while ((l_iter = l_iter->next) != l_first);
239
241 has_visible = true;
242 }
243 }
244
245 BLI_assert(n->bounds_.min[0] <= n->bounds_.max[0] && n->bounds_.min[1] <= n->bounds_.max[1] &&
246 n->bounds_.min[2] <= n->bounds_.max[2]);
247
248 n->bounds_orig_ = n->bounds_;
249
250 BKE_pbvh_node_fully_hidden_set(*n, !has_visible);
251}
252
255 Vector<bool> &node_changed,
256 const int cd_vert_node_offset,
257 const int cd_face_node_offset,
258 const Span<Bounds<float3>> face_bounds,
259 int node_index)
260{
261 BMeshNode *n = &nodes[node_index];
262
263 if (n->bm_faces_.size() <= leaf_limit) {
264 /* Node limit not exceeded. */
265 pbvh_bmesh_node_finalize(n, node_index, cd_vert_node_offset, cd_face_node_offset);
266 return;
267 }
268
269 /* Calculate bounding box around primitive centroids. */
271 for (BMFace *f : n->bm_faces_) {
272 const int i = BM_elem_index_get(f);
273 const float3 center = math::midpoint(face_bounds[i].min, face_bounds[i].max);
274 math::min_max(center, cb.min, cb.max);
275 }
276
277 /* Find widest axis and its midpoint. */
278 const int axis = math::dominant_axis(cb.max - cb.min);
279 const float mid = math::midpoint(cb.max[axis], cb.min[axis]);
280
281 /* Add two new child nodes. */
282 const int children = nodes.size();
283 n->children_offset_ = children;
284 nodes.resize(nodes.size() + 2);
285 node_changed.resize(node_changed.size() + 2, true);
286
287 /* Array reallocated, update current node pointer. */
288 n = &nodes[node_index];
289
290 /* Initialize children */
291 BMeshNode *c1 = &nodes[children], *c2 = &nodes[children + 1];
292 c1->flag_ |= PBVH_Leaf;
293 c2->flag_ |= PBVH_Leaf;
294 c1->bm_faces_.reserve(n->bm_faces_.size() / 2);
295 c2->bm_faces_.reserve(n->bm_faces_.size() / 2);
296
297 /* Partition the parent node's faces between the two children. */
298 for (BMFace *f : n->bm_faces_) {
299 const int i = BM_elem_index_get(f);
300 if (math::midpoint(face_bounds[i].min[axis], face_bounds[i].max[axis]) < mid) {
301 c1->bm_faces_.add(f);
302 }
303 else {
304 c2->bm_faces_.add(f);
305 }
306 }
307
308 /* Enforce at least one primitive in each node */
309 Set<BMFace *, 0> *empty = nullptr;
310 Set<BMFace *, 0> *other;
311 if (c1->bm_faces_.is_empty()) {
312 empty = &c1->bm_faces_;
313 other = &c2->bm_faces_;
314 }
315 else if (c2->bm_faces_.is_empty()) {
316 empty = &c2->bm_faces_;
317 other = &c1->bm_faces_;
318 }
319 if (empty) {
320 for (BMFace *f : *other) {
321 empty->add(f);
322 other->remove(f);
323 break;
324 }
325 }
326
327 /* Clear this node */
328
329 /* Mark this node's unique verts as unclaimed. */
330 for (BMVert *v : n->bm_unique_verts_) {
331 BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE);
332 }
333
334 /* Unclaim faces. */
335 for (BMFace *f : n->bm_faces_) {
336 BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE);
337 }
339
340 n->flag_ &= ~PBVH_Leaf;
341 node_changed[node_index] = true;
342
343 /* Recurse. */
345 nodes, node_changed, cd_vert_node_offset, cd_face_node_offset, face_bounds, children);
347 nodes, node_changed, cd_vert_node_offset, cd_face_node_offset, face_bounds, children + 1);
348
349 /* Array maybe reallocated, update current node pointer */
350 n = &nodes[node_index];
351
352 /* Update bounding box. */
353 n->bounds_ = bounds::merge(nodes[n->children_offset_].bounds_,
354 nodes[n->children_offset_ + 1].bounds_);
355 n->bounds_orig_ = n->bounds_;
356}
357
360 Vector<BMeshNode> &nodes,
361 Vector<bool> &node_changed,
362 const int cd_vert_node_offset,
363 const int cd_face_node_offset,
364 int node_index)
365{
366 BMeshNode &node = nodes[node_index];
367 const int faces_num = node.bm_faces_.size();
368 if (faces_num <= leaf_limit) {
369 /* Node limit not exceeded */
370 return false;
371 }
372
373 /* For each BMFace, store the AABB and AABB centroid. */
374 Array<Bounds<float3>> face_bounds(faces_num);
375
376 int i = 0;
377 for (BMFace *f : node.bm_faces_) {
378 face_bounds[i] = negative_bounds();
379
380 BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
381 BMLoop *l_iter = l_first;
382 do {
383 math::min_max(float3(l_iter->v->co), face_bounds[i].min, face_bounds[i].max);
384 } while ((l_iter = l_iter->next) != l_first);
385
386 /* So we can do direct lookups on 'face_bounds'. */
387 BM_elem_index_set(f, i); /* set_dirty! */
388 i++;
389 }
390
391 /* Likely this is already dirty. */
393
395 nodes, node_changed, cd_vert_node_offset, cd_face_node_offset, face_bounds, node_index);
396
397 return true;
398}
399
400/**********************************************************************/
401
402BLI_INLINE int pbvh_bmesh_node_index_from_vert(const int cd_vert_node_offset, const BMVert *key)
403{
404 const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, cd_vert_node_offset);
405 BLI_assert(node_index != DYNTOPO_NODE_NONE);
406 return node_index;
407}
408
409BLI_INLINE int pbvh_bmesh_node_index_from_face(const int cd_face_node_offset, const BMFace *key)
410{
411 const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, cd_face_node_offset);
412 BLI_assert(node_index != DYNTOPO_NODE_NONE);
413 return node_index;
414}
415
417 const int cd_vert_node_offset,
418 const BMVert *key)
419{
420 return &nodes[pbvh_bmesh_node_index_from_vert(cd_vert_node_offset, key)];
421}
422
424 const int cd_face_node_offset,
425 const BMFace *key)
426{
427 return &nodes[pbvh_bmesh_node_index_from_face(cd_face_node_offset, key)];
428}
429
432 MutableSpan<bool> node_changed,
433 BMLog &bm_log,
434 const BMVert *v1,
435 const BMVert *v2,
436 const int node_index,
437 const float co[3],
438 const float no[3],
439 const int cd_vert_node_offset,
440 const int cd_vert_mask_offset)
441{
442 BMeshNode *node = &nodes[node_index];
443
444 BLI_assert((nodes.size() == 1 || node_index) && node_index <= nodes.size());
445
446 /* Avoid initializing custom-data because its quite involved. */
447 BMVert *v = BM_vert_create(&bm, co, nullptr, BM_CREATE_NOP);
448
449 BM_data_interp_from_verts(&bm, v1, v2, v, 0.5f);
450
451 /* This value is logged below. */
452 copy_v3_v3(v->no, no);
453
454 node->bm_unique_verts_.add(v);
455 BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, node_index);
456
457 node->flag_ |= PBVH_TopologyUpdated;
458 node_changed[node_index] = true;
459
460 /* Log the new vertex. */
461 BM_log_vert_added(&bm_log, v, cd_vert_mask_offset);
462
463 return v;
464}
465
471 MutableSpan<bool> node_changed,
472 const int cd_face_node_offset,
473 BMLog &bm_log,
474 int node_index,
475 const Span<BMVert *> v_tri,
476 const Span<BMEdge *> e_tri,
477 const BMFace *f_example)
478{
479 BMeshNode *node = &nodes[node_index];
480
481 /* Ensure we never add existing face. */
482 BLI_assert(!BM_face_exists(v_tri.data(), 3));
483
484 BMFace *f = BM_face_create(&bm, v_tri.data(), e_tri.data(), 3, f_example, BM_CREATE_NOP);
485 f->head.hflag = f_example->head.hflag;
486
487 node->bm_faces_.add(f);
488 BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index);
489
490 node->flag_ |= PBVH_TopologyUpdated;
491 node_changed[node_index] = true;
492 node->flag_ &= ~PBVH_FullyHidden;
493
494 /* Log the new face. */
495 BM_log_face_added(&bm_log, f);
496
497 return f;
498}
499
500#define pbvh_bmesh_node_vert_use_count_is_equal(nodes, cd_face_node_offset, node, v, n) \
501 (pbvh_bmesh_node_vert_use_count_at_most(nodes, cd_face_node_offset, node, v, (n) + 1) == n)
502
504 const int cd_face_node_offset,
505 BMeshNode *node,
506 BMVert *v,
507 const int count_max)
508{
509 int count = 0;
510 BMFace *f;
511
513 BMeshNode *f_node = pbvh_bmesh_node_from_face(nodes, cd_face_node_offset, f);
514 if (f_node == node) {
515 count++;
516 if (count == count_max) {
517 return count;
518 }
519 }
520 }
522
523 return count;
524}
525
527static std::optional<int> pbvh_bmesh_vert_other_node_find(const int cd_vert_node_offset,
528 const int cd_face_node_offset,
529 BMVert *v)
530{
531 const int current_node = pbvh_bmesh_node_index_from_vert(cd_vert_node_offset, v);
532 BMFace *f;
533
535 const int f_node = pbvh_bmesh_node_index_from_face(cd_face_node_offset, f);
536
537 if (f_node != current_node) {
538 return f_node;
539 }
540 }
542
543 return std::nullopt;
544}
545
547 MutableSpan<bool> node_changed,
548 const int cd_vert_node_offset,
549 const int new_owner_index,
550 BMVert *v)
551{
552 const int current_owner_index = pbvh_bmesh_node_index_from_vert(cd_vert_node_offset, v);
553 BMeshNode *current_owner = &nodes[current_owner_index];
554 current_owner->flag_ |= PBVH_TopologyUpdated;
555 node_changed[new_owner_index] = true;
556
557 BMeshNode *new_owner = &nodes[new_owner_index];
558
559 BLI_assert(current_owner != new_owner);
560
561 /* Remove current ownership. */
562 current_owner->bm_unique_verts_.remove(v);
563
564 /* Set new ownership */
565 BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, new_owner_index);
566 new_owner->bm_unique_verts_.add(v);
567 new_owner->bm_other_verts_.remove(v);
568 BLI_assert(!new_owner->bm_other_verts_.contains(v));
569
570 new_owner->flag_ |= PBVH_TopologyUpdated;
571 node_changed[new_owner_index] = true;
572}
573
575 MutableSpan<bool> node_changed,
576 const int cd_vert_node_offset,
577 const int cd_face_node_offset,
578 BMVert *v)
579{
580 /* Never match for first time. */
581 int f_node_index_prev = DYNTOPO_NODE_NONE;
582
583 BMeshNode *v_node = pbvh_bmesh_node_from_vert(nodes, cd_vert_node_offset, v);
584 v_node->bm_unique_verts_.remove(v);
585 BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE);
586
587 /* Have to check each neighboring face's node. */
588 BMFace *f;
590 const int f_node_index = pbvh_bmesh_node_index_from_face(cd_face_node_offset, f);
591
592 /* Faces often share the same node, quick check to avoid redundant #BLI_gset_remove calls. */
593 if (f_node_index_prev != f_node_index) {
594 f_node_index_prev = f_node_index;
595
596 BMeshNode *f_node = &nodes[f_node_index];
597 f_node->flag_ |= PBVH_TopologyUpdated;
598 node_changed[f_node_index] = true;
599
600 /* Remove current ownership. */
601 f_node->bm_other_verts_.remove(v);
602
605 }
606 }
608}
609
611 MutableSpan<bool> node_changed,
612 const int cd_vert_node_offset,
613 const int cd_face_node_offset,
614 BMLog &bm_log,
615 BMFace *f)
616{
617 const int node_index = pbvh_bmesh_node_index_from_face(cd_face_node_offset, f);
618 BMeshNode *f_node = &nodes[node_index];
619
620 /* Check if any of this face's vertices need to be removed from the node. */
621 BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
622 BMLoop *l_iter = l_first;
623 do {
624 BMVert *v = l_iter->v;
625 if (pbvh_bmesh_node_vert_use_count_is_equal(nodes, cd_face_node_offset, f_node, v, 1)) {
626 if (f_node->bm_unique_verts_.contains(v)) {
627 /* Find a different node that uses 'v'. */
628
629 const std::optional<int> new_node = pbvh_bmesh_vert_other_node_find(
630 cd_vert_node_offset, cd_face_node_offset, v);
632
633 if (new_node) {
635 nodes, node_changed, cd_vert_node_offset, *new_node, v);
636 }
637 }
638 else {
639 /* Remove from other verts. */
640 f_node->bm_other_verts_.remove(v);
641 }
642 }
643 } while ((l_iter = l_iter->next) != l_first);
644
645 /* Remove face from node and top level. */
646 f_node->bm_faces_.remove(f);
647 BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE);
648
649 /* Log removed face. */
650 BM_log_face_removed(&bm_log, f);
651
652 /* Mark node for update. */
653 f_node->flag_ |= PBVH_TopologyUpdated;
654 node_changed[node_index] = true;
655}
656
658{
659 /* Fast-path for most common case where an edge has 2 faces no need to iterate twice. */
660 std::array<BMLoop *, 2> manifold_loops;
661 if (LIKELY(BM_edge_loop_pair(e, &manifold_loops[0], &manifold_loops[1]))) {
662 return Array<BMLoop *>(Span(manifold_loops));
663 }
666 nullptr, BM_LOOPS_OF_EDGE, e, reinterpret_cast<void **>(loops.data()), loops.size());
667 return loops;
668}
669
671{
672 node->orig_positions_ = {};
673 node->orig_tris_ = {};
674 node->orig_verts_ = {};
675}
676
677/****************************** EdgeQueue *****************************/
678
679struct EdgeQueue {
681 const float *center;
682 float center_proj[3]; /* For when we use projected coords. */
685#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
687#endif
688
690
691 const float *view_normal;
692#ifdef USE_EDGEQUEUE_FRONTFACE
694#endif
695};
696
705
706/* Only tagged edges are in the queue. */
707#ifdef USE_EDGEQUEUE_TAG
708# define EDGE_QUEUE_TEST(e) BM_elem_flag_test((CHECK_TYPE_INLINE(e, BMEdge *), e), BM_ELEM_TAG)
709# define EDGE_QUEUE_ENABLE(e) \
710 BM_elem_flag_enable((CHECK_TYPE_INLINE(e, BMEdge *), e), BM_ELEM_TAG)
711# define EDGE_QUEUE_DISABLE(e) \
712 BM_elem_flag_disable((CHECK_TYPE_INLINE(e, BMEdge *), e), BM_ELEM_TAG)
713#endif
714
715#ifdef USE_EDGEQUEUE_TAG_VERIFY
716/* simply check no edges are tagged
717 * (it's a requirement that edges enter and leave a clean tag state) */
718static void pbvh_bmesh_edge_tag_verify(Tree *pbvh)
719{
720 for (int n = 0; n < pbvh->totnode; n++) {
721 Node *node = &pbvh->nodes_[n];
722 if (node->bm_faces_) {
723 GSetIterator gs_iter;
724 GSET_ITER (gs_iter, node->bm_faces_) {
725 BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
726 BMEdge *e_tri[3];
727 BMLoop *l_iter;
728
729 BLI_assert(f->len == 3);
730 l_iter = BM_FACE_FIRST_LOOP(f);
731 e_tri[0] = l_iter->e;
732 l_iter = l_iter->next;
733 e_tri[1] = l_iter->e;
734 l_iter = l_iter->next;
735 e_tri[2] = l_iter->e;
736
737 BLI_assert((EDGE_QUEUE_TEST(e_tri[0]) == false) && (EDGE_QUEUE_TEST(e_tri[1]) == false) &&
738 (EDGE_QUEUE_TEST(e_tri[2]) == false));
739 }
740 }
741 }
742}
743#endif
744
746{
747 BMVert *v_tri[3];
748 float c[3];
749
750 /* Get closest point in triangle to sphere center. */
752
753 closest_on_tri_to_point_v3(c, q->center, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co);
754
755 /* Check if triangle intersects the sphere. */
756 return len_squared_v3v3(q->center, c) <= q->radius_squared;
757}
758
760{
761 BMVert *v_tri[3];
762 float c[3];
763 float tri_proj[3][3];
764
765 /* Get closest point in triangle to sphere center. */
767
768 project_plane_normalized_v3_v3v3(tri_proj[0], v_tri[0]->co, q->view_normal);
769 project_plane_normalized_v3_v3v3(tri_proj[1], v_tri[1]->co, q->view_normal);
770 project_plane_normalized_v3_v3v3(tri_proj[2], v_tri[2]->co, q->view_normal);
771
772 closest_on_tri_to_point_v3(c, q->center_proj, tri_proj[0], tri_proj[1], tri_proj[2]);
773
774 /* Check if triangle intersects the sphere. */
775 return len_squared_v3v3(q->center_proj, c) <= q->radius_squared;
776}
777
779static bool check_mask(EdgeQueueContext *eq_ctx, BMVert *v)
780{
781 return BM_ELEM_CD_GET_FLOAT(v, eq_ctx->cd_vert_mask_offset) < 1.0f;
782}
783
784static void edge_queue_insert(EdgeQueueContext *eq_ctx, BMEdge *e, float priority)
785{
786 /* Don't let topology update affect fully masked vertices. This used to
787 * have a 50% mask cutoff, with the reasoning that you can't do a 50%
788 * topology update. But this gives an ugly border in the mesh. The mask
789 * should already make the brush move the vertices only 50%, which means
790 * that topology updates will also happen less frequent, that should be
791 * enough. */
792 if (((eq_ctx->cd_vert_mask_offset == -1) ||
793 (check_mask(eq_ctx, e->v1) || check_mask(eq_ctx, e->v2))) &&
796 {
797 BMVert **pair = static_cast<BMVert **>(BLI_mempool_alloc(eq_ctx->pool));
798 pair[0] = e->v1;
799 pair[1] = e->v2;
800 BLI_heapsimple_insert(eq_ctx->q->heap, priority, pair);
801#ifdef USE_EDGEQUEUE_TAG
802 BLI_assert(EDGE_QUEUE_TEST(e) == false);
804#endif
805 }
806}
807
809static bool is_boundary_edge(const BMEdge &edge)
810{
811 if (edge.head.hflag & BM_ELEM_SEAM) {
812 return true;
813 }
814 if ((edge.head.hflag & BM_ELEM_SMOOTH) == 0) {
815 return true;
816 }
817 if (!BM_edge_is_manifold(&edge)) {
818 return true;
819 }
820
821 /* TODO(@sergey): Other boundaries? For example, edges between two different face sets. */
822
823 return false;
824}
825
826/* Return true if the vertex is adjacent to a boundary edge. */
827static bool is_boundary_vert(const BMVert &vertex)
828{
829 BMEdge *edge = vertex.e;
830 BMEdge *first_edge = edge;
831 if (first_edge == nullptr) {
832 return false;
833 }
834 do {
835 if (is_boundary_edge(*edge)) {
836 return true;
837 }
838 } while ((edge = BM_DISK_EDGE_NEXT(edge, &vertex)) != first_edge);
839
840 return false;
841}
842
844static bool is_edge_adjacent_to_boundary(const BMEdge &edge)
845{
846 return is_boundary_vert(*edge.v1) || is_boundary_vert(*edge.v2);
847}
848
849/* Notes on edge priority.
850 *
851 * The priority is used to control the order in which edges are handled for both splitting of long
852 * edges and collapsing of short edges. For long edges we start by splitting the longest edge and
853 * for collapsing we start with the shortest.
854 *
855 * A heap-like data structure is used to accelerate such ordering. A bit confusingly, this data
856 * structure gives the higher priorities to elements with lower numbers.
857 *
858 * When edges do not belong to and are not adjacent to boundaries, their length is used as the
859 * priority directly. Prefer to handle those edges first. Modifying those edges leads to no
860 * distortion to the boundary.
861 *
862 * Edges adjacent to a boundary with one vertex are handled next, and the vertex which is
863 * on the boundary does not change position as part of the edge collapse algorithm.
864 *
865 * And last, the boundary edges are handled. While subdivision of boundary edges does not change
866 * the shape of the boundary, collapsing boundary edges distorts the boundary. Hence they are
867 * handled last. */
868
869static float long_edge_queue_priority(const BMEdge &edge)
870{
871 return -BM_edge_calc_length_squared(&edge);
872}
873
874static float short_edge_queue_priority(const BMEdge &edge)
875{
876 float priority = BM_edge_calc_length_squared(&edge);
877
878 if (is_boundary_edge(edge)) {
879 priority *= 1.5f;
880 }
881 else if (is_edge_adjacent_to_boundary(edge)) {
882 priority *= 1.25f;
883 }
884
885 return priority;
886}
887
889{
890#ifdef USE_EDGEQUEUE_TAG
891 if (EDGE_QUEUE_TEST(e) == false)
892#endif
893 {
894 const float len_sq = BM_edge_calc_length_squared(e);
895 if (len_sq > eq_ctx->q->limit_len_squared) {
897 }
898 }
899}
900
901#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
903 EdgeQueueContext *eq_ctx, BMLoop *l_edge, BMLoop *l_end, const float len_sq, float limit_len)
904{
905 BLI_assert(len_sq > square_f(limit_len));
906
907# ifdef USE_EDGEQUEUE_FRONTFACE
908 if (eq_ctx->q->use_view_normal) {
909 if (dot_v3v3(l_edge->f->no, eq_ctx->q->view_normal) < 0.0f) {
910 return;
911 }
912 }
913# endif
914
915# ifdef USE_EDGEQUEUE_TAG
916 if (EDGE_QUEUE_TEST(l_edge->e) == false)
917# endif
918 {
919 edge_queue_insert(eq_ctx, l_edge->e, long_edge_queue_priority(*l_edge->e));
920 }
921
922 /* temp support previous behavior! */
923 if (UNLIKELY(G.debug_value == 1234)) {
924 return;
925 }
926
927 if (l_edge->radial_next != l_edge) {
928 /* How much longer we need to be to consider for subdividing
929 * (avoids subdividing faces which are only *slightly* skinny). */
930# define EVEN_EDGELEN_THRESHOLD 1.2f
931 /* How much the limit increases per recursion
932 * (avoids performing subdivisions too far away). */
933# define EVEN_GENERATION_SCALE 1.6f
934
935 const float len_sq_cmp = len_sq * EVEN_EDGELEN_THRESHOLD;
936
937 limit_len *= EVEN_GENERATION_SCALE;
938 const float limit_len_sq = square_f(limit_len);
939
940 BMLoop *l_iter = l_edge;
941 do {
942 BMLoop *l_adjacent[2] = {l_iter->next, l_iter->prev};
943 for (int i = 0; i < ARRAY_SIZE(l_adjacent); i++) {
944 float len_sq_other = BM_edge_calc_length_squared(l_adjacent[i]->e);
945 if (len_sq_other > max_ff(len_sq_cmp, limit_len_sq)) {
946 // edge_queue_insert(eq_ctx, l_adjacent[i]->e, -len_sq_other);
948 eq_ctx, l_adjacent[i]->radial_next, l_adjacent[i], len_sq_other, limit_len);
949 }
950 }
951 } while ((l_iter = l_iter->radial_next) != l_end);
952
953# undef EVEN_EDGELEN_THRESHOLD
954# undef EVEN_GENERATION_SCALE
955 }
956}
957#endif /* USE_EDGEQUEUE_EVEN_SUBDIV */
958
960{
961#ifdef USE_EDGEQUEUE_TAG
962 if (EDGE_QUEUE_TEST(e) == false)
963#endif
964 {
965 const float len_sq = BM_edge_calc_length_squared(e);
966 if (len_sq < eq_ctx->q->limit_len_squared) {
968 }
969 }
970}
971
973{
974#ifdef USE_EDGEQUEUE_FRONTFACE
975 if (eq_ctx->q->use_view_normal) {
976 if (dot_v3v3(f->no, eq_ctx->q->view_normal) < 0.0f) {
977 return;
978 }
979 }
980#endif
981
982 if (eq_ctx->q->edge_queue_tri_in_range(eq_ctx->q, f)) {
983 /* Check each edge of the face. */
984 BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
985 BMLoop *l_iter = l_first;
986 do {
987#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
988 const float len_sq = BM_edge_calc_length_squared(l_iter->e);
989 if (len_sq > eq_ctx->q->limit_len_squared) {
991 eq_ctx, l_iter->radial_next, l_iter, len_sq, eq_ctx->q->limit_len);
992 }
993#else
994 long_edge_queue_edge_add(eq_ctx, l_iter->e);
995#endif
996 } while ((l_iter = l_iter->next) != l_first);
997 }
998}
999
1001{
1002#ifdef USE_EDGEQUEUE_FRONTFACE
1003 if (eq_ctx->q->use_view_normal) {
1004 if (dot_v3v3(f->no, eq_ctx->q->view_normal) < 0.0f) {
1005 return;
1006 }
1007 }
1008#endif
1009
1010 if (eq_ctx->q->edge_queue_tri_in_range(eq_ctx->q, f)) {
1011 BMLoop *l_iter;
1012 BMLoop *l_first;
1013
1014 /* Check each edge of the face. */
1015 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1016 do {
1017 short_edge_queue_edge_add(eq_ctx, l_iter->e);
1018 } while ((l_iter = l_iter->next) != l_first);
1019 }
1020}
1021
1033 const float max_edge_len,
1035 const float center[3],
1036 const float view_normal[3],
1037 float radius,
1038 const bool use_frontface,
1039 const bool use_projected)
1040{
1041 eq_ctx->q->heap = BLI_heapsimple_new();
1042 eq_ctx->q->center = center;
1043 eq_ctx->q->radius_squared = radius * radius;
1044 eq_ctx->q->limit_len_squared = max_edge_len * max_edge_len;
1045#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
1046 eq_ctx->q->limit_len = max_edge_len;
1047#endif
1048
1049 eq_ctx->q->view_normal = view_normal;
1050
1051#ifdef USE_EDGEQUEUE_FRONTFACE
1052 eq_ctx->q->use_view_normal = use_frontface;
1053#else
1054 UNUSED_VARS(use_frontface);
1055#endif
1056
1057 if (use_projected) {
1059 project_plane_normalized_v3_v3v3(eq_ctx->q->center_proj, center, view_normal);
1060 }
1061 else {
1063 }
1064
1065#ifdef USE_EDGEQUEUE_TAG_VERIFY
1066 pbvh_bmesh_edge_tag_verify(pbvh);
1067#endif
1068
1069 for (BMeshNode &node : nodes) {
1070 /* Check leaf nodes marked for topology update. */
1071 if ((node.flag_ & PBVH_Leaf) && (node.flag_ & PBVH_UpdateTopology) &&
1072 !(node.flag_ & PBVH_FullyHidden))
1073 {
1074 for (BMFace *f : node.bm_faces_) {
1075 long_edge_queue_face_add(eq_ctx, f);
1076 }
1077 }
1078 }
1079}
1080
1092 const float min_edge_len,
1094 const float center[3],
1095 const float view_normal[3],
1096 float radius,
1097 const bool use_frontface,
1098 const bool use_projected)
1099{
1100 eq_ctx->q->heap = BLI_heapsimple_new();
1101 eq_ctx->q->center = center;
1102 eq_ctx->q->radius_squared = radius * radius;
1103 eq_ctx->q->limit_len_squared = min_edge_len * min_edge_len;
1104#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
1105 eq_ctx->q->limit_len = min_edge_len;
1106#endif
1107
1108 eq_ctx->q->view_normal = view_normal;
1109
1110#ifdef USE_EDGEQUEUE_FRONTFACE
1111 eq_ctx->q->use_view_normal = use_frontface;
1112#else
1113 UNUSED_VARS(use_frontface);
1114#endif
1115
1116 if (use_projected) {
1118 project_plane_normalized_v3_v3v3(eq_ctx->q->center_proj, center, view_normal);
1119 }
1120 else {
1122 }
1123
1124 for (BMeshNode &node : nodes) {
1125 /* Check leaf nodes marked for topology update */
1126 if ((node.flag_ & PBVH_Leaf) && (node.flag_ & PBVH_UpdateTopology) &&
1127 !(node.flag_ & PBVH_FullyHidden))
1128 {
1129 for (BMFace *f : node.bm_faces_) {
1130 short_edge_queue_face_add(eq_ctx, f);
1131 }
1132 }
1133 }
1134}
1135
1136/*************************** Topology update **************************/
1137
1144static void copy_edge_data(BMesh &bm, BMEdge &dst, /*const*/ BMEdge &src)
1145{
1146 dst.head.hflag = src.head.hflag & ~BM_ELEM_TAG;
1148}
1149
1150/* Merge edge custom data from src to dst. */
1151static void merge_edge_data(BMesh &bm, BMEdge &dst, const BMEdge &src)
1152{
1153 dst.head.hflag |= (src.head.hflag & ~(BM_ELEM_TAG | BM_ELEM_SMOOTH));
1154
1155 /* If either of the src or dst is sharp the result is sharp. */
1156 if ((src.head.hflag & BM_ELEM_SMOOTH) == 0) {
1157 dst.head.hflag &= ~BM_ELEM_SMOOTH;
1158 }
1159
1160 BM_data_interp_from_edges(&bm, &src, &dst, &dst, 0.5f);
1161}
1162
1164 BMesh &bm,
1166 MutableSpan<bool> node_changed,
1167 const int cd_vert_node_offset,
1168 const int cd_face_node_offset,
1169 BMLog &bm_log,
1170 BMEdge *e)
1171{
1172 float co_mid[3], no_mid[3];
1173
1174 /* Get all faces adjacent to the edge. */
1176
1177 /* Create a new vertex in current node at the edge's midpoint. */
1178 mid_v3_v3v3(co_mid, e->v1->co, e->v2->co);
1179 mid_v3_v3v3(no_mid, e->v1->no, e->v2->no);
1180 normalize_v3(no_mid);
1181
1182 int node_index = BM_ELEM_CD_GET_INT(e->v1, eq_ctx->cd_vert_node_offset);
1184 nodes,
1185 node_changed,
1186 bm_log,
1187 e->v1,
1188 e->v2,
1189 node_index,
1190 co_mid,
1191 no_mid,
1192 cd_vert_node_offset,
1193 eq_ctx->cd_vert_mask_offset);
1194
1195 /* For each face, add two new triangles and delete the original. */
1196 for (const int i : edge_loops.index_range()) {
1197 BMLoop *l_adj = edge_loops[i];
1198 BMFace *f_adj = l_adj->f;
1199
1200 BLI_assert(f_adj->len == 3);
1201 int ni = BM_ELEM_CD_GET_INT(f_adj, eq_ctx->cd_face_node_offset);
1202
1203 /* Find the vertex not in the edge. */
1204 BMVert *v_opp = l_adj->prev->v;
1205
1206 /* Get e->v1 and e->v2 in the order they appear in the existing face so that the new faces'
1207 * winding orders match. */
1208 BMVert *v1 = l_adj->v;
1209 BMVert *v2 = l_adj->next->v;
1210
1211 if (ni != node_index && i == 0) {
1212 pbvh_bmesh_vert_ownership_transfer(nodes, node_changed, cd_vert_node_offset, ni, v_new);
1213 }
1214
1215 /* The 2 new faces created and assigned to `f_new` have their
1216 * verts & edges shuffled around.
1217 *
1218 * - faces wind anticlockwise in this example.
1219 * - original edge is `(v1, v2)`
1220 * - original face is `(v1, v2, v3)`
1221 *
1222 * <pre>
1223 * + v_opp
1224 * /|\
1225 * / | \
1226 * / | \
1227 * e4/ | \ e3
1228 * / |e5 \
1229 * / | \
1230 * / e1 | e2 \
1231 * +-------+-------+
1232 * v1 v_new v2
1233 * (first) (second)
1234 * </pre>
1235 *
1236 * - f_new (first): `v_tri=(v1, v_new, v_opp), e_tri=(e1, e5, e4)`
1237 * - f_new (second): `v_tri=(v_new, v2, v_opp), e_tri=(e2, e3, e5)`
1238 */
1239
1240 /* Create first face (v1, v_new, v_opp). */
1241 const std::array<BMVert *, 3> first_tri({v1, v_new, v_opp});
1242 const std::array<BMEdge *, 3> first_edges = bm_edges_from_tri(bm, first_tri);
1243 copy_edge_data(bm, *first_edges[0], *e);
1244
1245 BMFace *f_new_first = pbvh_bmesh_face_create(
1246 bm, nodes, node_changed, cd_face_node_offset, bm_log, ni, first_tri, first_edges, f_adj);
1247 long_edge_queue_face_add(eq_ctx, f_new_first);
1248
1249 /* Create second face (v_new, v2, v_opp). */
1250 const std::array<BMVert *, 3> second_tri({v_new, v2, v_opp});
1251 const std::array<BMEdge *, 3> second_edges{
1252 BM_edge_create(&bm, second_tri[0], second_tri[1], nullptr, BM_CREATE_NO_DOUBLE),
1253 BM_edge_create(&bm, second_tri[1], second_tri[2], nullptr, BM_CREATE_NO_DOUBLE),
1254 first_edges[1],
1255 };
1256 copy_edge_data(bm, *second_edges[0], *e);
1257
1258 BMFace *f_new_second = pbvh_bmesh_face_create(
1259 bm, nodes, node_changed, cd_face_node_offset, bm_log, ni, second_tri, second_edges, f_adj);
1260 long_edge_queue_face_add(eq_ctx, f_new_second);
1261
1262 /* Delete original */
1264 nodes, node_changed, cd_vert_node_offset, cd_face_node_offset, bm_log, f_adj);
1265 BM_face_kill(&bm, f_adj);
1266
1267 /* Ensure new vertex is in the node */
1268 if (!nodes[ni].bm_unique_verts_.contains(v_new)) {
1269 nodes[ni].bm_other_verts_.add(v_new);
1270 }
1271
1272 if (BM_vert_edge_count_is_over(v_opp, 8)) {
1273 BMIter bm_iter;
1274 BMEdge *e2;
1275 BM_ITER_ELEM (e2, &bm_iter, v_opp, BM_EDGES_OF_VERT) {
1276 long_edge_queue_edge_add(eq_ctx, e2);
1277 }
1278 }
1279 }
1280
1281 BM_edge_kill(&bm, e);
1282}
1283
1285 BMesh &bm,
1287 MutableSpan<bool> node_changed,
1288 const int cd_vert_node_offset,
1289 const int cd_face_node_offset,
1290 BMLog &bm_log)
1291{
1292 const double start_time = BLI_time_now_seconds();
1293
1294 bool any_subdivided = false;
1295
1296 while (!BLI_heapsimple_is_empty(eq_ctx->q->heap)) {
1297 BMVert **pair = static_cast<BMVert **>(BLI_heapsimple_pop_min(eq_ctx->q->heap));
1298 BMVert *v1 = pair[0];
1299 BMVert *v2 = pair[1];
1300
1301 BLI_mempool_free(eq_ctx->pool, pair);
1302 pair = nullptr;
1303
1304 /* Check that the edge still exists */
1305 BMEdge *e;
1306 if (!(e = BM_edge_exists(v1, v2))) {
1307 continue;
1308 }
1309#ifdef USE_EDGEQUEUE_TAG
1311#endif
1312
1314
1315 /* Check that the edge's vertices are still in the Tree. It's
1316 * possible that an edge collapse has deleted adjacent faces
1317 * and the node has been split, thus leaving wire edges and
1318 * associated vertices. */
1321 {
1322 continue;
1323 }
1324
1325 any_subdivided = true;
1326
1328 eq_ctx, bm, nodes, node_changed, cd_vert_node_offset, cd_face_node_offset, bm_log, e);
1329 }
1330
1331#ifdef USE_EDGEQUEUE_TAG_VERIFY
1332 pbvh_bmesh_edge_tag_verify(pbvh);
1333#endif
1334
1335 CLOG_INFO(
1336 &LOG, 2, "Long edge subdivision took %f seconds.", BLI_time_now_seconds() - start_time);
1337
1338 return any_subdivided;
1339}
1340
1343{
1344 BMIter bm_iter;
1345 BMFace *face;
1346 BM_ITER_ELEM (face, &bm_iter, &edge, BM_FACES_OF_EDGE) {
1347 if (BM_vert_in_face(&vert, face)) {
1348 return true;
1349 }
1350 }
1351 return false;
1352}
1353
1371 BMFace *del_face,
1372 BMFace *flap_face,
1373 BMEdge *e,
1374 BMVert *v_del,
1375 BMLoop *l_del,
1376 BMVert *v_conn)
1377{
1378 /*
1379 * v_del
1380 * +
1381 * del_face . / |
1382 * . / |
1383 * . / |
1384 * v1 +---------------------+ v2 |
1385 * . \ |
1386 * . \ |
1387 * . \ |
1388 * flap_face +
1389 * v_conn
1390 *
1391 *
1392 */
1393
1394 UNUSED_VARS_NDEBUG(del_face, flap_face);
1395
1396 /* Faces around `e` (which connects `v_del` to `v_conn`) are to the handled separately from this
1397 * function. Help troubleshooting cases where these faces are mistakenly considered flaps. */
1398 BLI_assert(!BM_edge_in_face(e, del_face));
1399 BLI_assert(!BM_edge_in_face(e, flap_face));
1400
1401 /* The `l_del->next->v` and `l_del->prev->v` are v1 and v2, but in an unknown order. */
1402 BMEdge *edge_v1_v2 = BM_edge_exists(l_del->next->v, l_del->prev->v);
1403 if (!edge_v1_v2) {
1404 CLOG_WARN(&LOG, "Unable to find edge shared between deleting and flap faces");
1405 return;
1406 }
1407
1408 BLI_assert(BM_edge_in_face(edge_v1_v2, del_face));
1409 BLI_assert(BM_edge_in_face(edge_v1_v2, flap_face));
1410
1411 /* Disambiguate v1 from v2: the v2 is adjacent to a face around #e. */
1412 BMVert *v2 = vert_in_face_adjacent_to_edge(*edge_v1_v2->v1, *e) ? edge_v1_v2->v1 :
1413 edge_v1_v2->v2;
1414 BMVert *v1 = BM_edge_other_vert(edge_v1_v2, v2);
1415
1416 /* Merge attributes into an edge (v1, v_conn). */
1417 BMEdge *dst_edge = BM_edge_exists(v1, v_conn);
1418
1419 const std::array<const BMEdge *, 4> source_edges{
1420 /* Edges of the `flap_face`.
1421 * The face will be deleted, effectively being "collapsed" into an edge. */
1422 edge_v1_v2,
1423 BM_edge_exists(v2, v_conn),
1424
1425 /* Edges of the `del_face`.
1426 * These edges are implicitly merged with the ones from the `flap_face` upon collapsing edge
1427 * `e`. */
1428 BM_edge_exists(v1, v_del),
1429 BM_edge_exists(v2, v_del),
1430 };
1431
1432 for (const BMEdge *src_edge : source_edges) {
1433 if (!src_edge) {
1434 CLOG_WARN(&LOG, "Unable to find source edge for flap attributes merge");
1435 continue;
1436 }
1437
1438 merge_edge_data(bm, *dst_edge, *src_edge);
1439 }
1440}
1441
1448{
1449 BMVert *flap_vert = nullptr;
1450
1451 BMIter bm_iter;
1452 BMVert *vert;
1453 BM_ITER_ELEM (vert, &bm_iter, &face, BM_VERTS_OF_FACE) {
1454 if (BM_vert_face_count_at_most(vert, 2) == 1) {
1455 if (flap_vert) {
1456 /* There are multiple vertices which become loose on removing the face and its edges. */
1457 return nullptr;
1458 }
1459 flap_vert = vert;
1460 }
1461 }
1462
1463 return flap_vert;
1464}
1465
1474{
1475 /*
1476 * v1 v2
1477 * ... ------ + ----------------- + ------ ...
1478 * \ /
1479 * \ /
1480 * \ /
1481 * \ /
1482 * \ /
1483 * + v_flap
1484 */
1485
1486 BMVert *v_flap = find_outer_flap_vert(face);
1487 if (!v_flap) {
1488 return;
1489 }
1490
1491 BMLoop *l_flap = BM_vert_find_first_loop(v_flap);
1492 BLI_assert(l_flap->v == v_flap);
1493
1494 /* Edges which are adjacent ot the v_flap. */
1495 BMEdge *edge_1 = l_flap->prev->e;
1496 BMEdge *edge_2 = l_flap->e;
1497
1498 BLI_assert(BM_edge_face_count(edge_1) == 1);
1499 BLI_assert(BM_edge_face_count(edge_2) == 1);
1500
1501 BMEdge *edge_v1_v2 = l_flap->next->e;
1502
1503 merge_edge_data(bm, *edge_v1_v2, *edge_1);
1504 merge_edge_data(bm, *edge_v1_v2, *edge_2);
1505}
1506
1522 BMFace * /*del_face*/,
1523 BMFace *new_face,
1524 BMVert *v_del,
1525 BMLoop *l_del,
1526 BMVert *v_conn)
1527{
1528 /* When collapsing an edge (v_conn, v_del) a face (v_conn, v2, v_del) is to be deleted and the
1529 * v_del reference in the face (v_del, v2, v1) is to be replaced with v_conn. Doing vertex
1530 * reference replacement in BMesh is not trivial. so for the simplicity the
1531 * #pbvh_bmesh_collapse_edge deletes both original faces and creates new one (c_conn, v2, v1).
1532 *
1533 * When doing such re-creating attributes from old edges are to be merged into the new ones:
1534 * - Attributes of (v_del, v1) needs to be merged into (v_conn, v1),
1535 * - Attributes of (v_del, v2) needs to be merged into (v_conn, v2),
1536 *
1537 * <pre>
1538 *
1539 * v2
1540 * +
1541 * /|\
1542 * / | \
1543 * / | \
1544 * / | \
1545 * / | \
1546 * / | \
1547 * / | \
1548 * +-------+-------+
1549 * v_conn v_del v1
1550 *
1551 * </pre>
1552 */
1553
1554 /* The l_del->next->v and l_del->prev->v are v1 and v2, but in an unknown order. */
1555 BMEdge *edge_v1_v2 = BM_edge_exists(l_del->next->v, l_del->prev->v);
1556 if (!edge_v1_v2) {
1557 CLOG_WARN(&LOG, "Unable to find edge shared between old and new faces");
1558 return;
1559 }
1560
1561 BMIter bm_iter;
1562 BMEdge *dst_edge;
1563 BM_ITER_ELEM (dst_edge, &bm_iter, new_face, BM_EDGES_OF_FACE) {
1564 if (dst_edge == edge_v1_v2) {
1565 continue;
1566 }
1567
1568 BLI_assert(BM_vert_in_edge(dst_edge, v_conn));
1569
1570 /* Depending on an edge v_other will be v1 or v2. */
1571 BMVert *v_other = BM_edge_other_vert(dst_edge, v_conn);
1572
1573 BMEdge *src_edge = BM_edge_exists(v_del, v_other);
1574 BLI_assert(src_edge);
1575
1576 if (src_edge) {
1577 merge_edge_data(bm, *dst_edge, *src_edge);
1578 }
1579 else {
1580 CLOG_WARN(&LOG, "Unable to find edge to merge attributes from");
1581 }
1582 }
1583}
1584
1587 MutableSpan<bool> node_changed,
1588 const int cd_vert_node_offset,
1589 const int cd_face_node_offset,
1590 BMLog &bm_log,
1591 BMEdge *e,
1592 BMVert *v1,
1593 BMVert *v2,
1594 GHash *deleted_verts,
1595 EdgeQueueContext *eq_ctx)
1596{
1597 const bool v1_on_boundary = is_boundary_vert(*v1);
1598 const bool v2_on_boundary = is_boundary_vert(*v2);
1599
1600 BMVert *v_del;
1601 BMVert *v_conn;
1602 if (v1_on_boundary || v2_on_boundary) {
1603 /* Boundary edges can be collapsed with minimal distortion. For those it does not
1604 * matter too much which vertex to keep and which one to remove.
1605 *
1606 * For edges which are adjacent to boundaries, keep the vertex which is on boundary and
1607 * dissolve the other one. */
1608 if (v1_on_boundary) {
1609 v_del = v2;
1610 v_conn = v1;
1611 }
1612 else {
1613 v_del = v1;
1614 v_conn = v2;
1615 }
1616 }
1617 else if (BM_ELEM_CD_GET_FLOAT(v1, eq_ctx->cd_vert_mask_offset) <
1619 {
1620 /* Prefer deleting the vertex that is less masked. */
1621 v_del = v1;
1622 v_conn = v2;
1623 }
1624 else {
1625 v_del = v2;
1626 v_conn = v1;
1627 }
1628
1629 /* Remove the merge vertex from the Tree. */
1630 pbvh_bmesh_vert_remove(nodes, node_changed, cd_vert_node_offset, cd_face_node_offset, v_del);
1631
1632 /* For all remaining faces of v_del, create a new face that is the
1633 * same except it uses v_conn instead of v_del */
1634 /* NOTE: this could be done with BM_vert_splice(), but that requires handling other issues like
1635 * duplicate edges, so it wouldn't really buy anything. */
1636 Vector<BMFace *, 16> deleted_faces;
1637
1638 BMLoop *l;
1640 BMFace *f_del = l->f;
1641
1642 /* Ignore faces around `e`: they will be deleted explicitly later on.
1643 * Without ignoring these faces the #bm_face_exists_tri_from_loop_vert() triggers an assert. */
1644 if (BM_edge_in_face(e, f_del)) {
1645 continue;
1646 }
1647
1648 /* Schedule the faces adjacent to the v_del for deletion first.
1649 * This way we know that it will be #existing_face which is deleted last when deleting faces
1650 * which forms a flap. */
1651 deleted_faces.append(f_del);
1652
1653 /* Check if a face using these vertices already exists. If so, skip adding this face and mark
1654 * the existing one for deletion as well. Prevents extraneous "flaps" from being created.
1655 * Check is similar to #BM_face_exists. */
1656 if (BMFace *existing_face = bm_face_exists_tri_from_loop_vert(l->next, v_conn)) {
1657 merge_flap_edge_data(bm, f_del, existing_face, e, v_del, l, v_conn);
1658
1659 deleted_faces.append(existing_face);
1660 }
1661 }
1663
1664 /* Remove all faces adjacent to the edge. */
1665 BMLoop *l_adj;
1666 while ((l_adj = e->l)) {
1667 BMFace *f_adj = l_adj->f;
1668
1670 nodes, node_changed, cd_vert_node_offset, cd_face_node_offset, bm_log, f_adj);
1671 BM_face_kill(&bm, f_adj);
1672 }
1673
1674 /* Kill the edge. */
1676 BM_edge_kill(&bm, e);
1677
1679 /* Get vertices, replace use of v_del with v_conn */
1680 BMFace *f = l->f;
1681
1683 /* This case is handled above. */
1684 }
1685 else {
1686 const std::array<BMVert *, 3> v_tri{v_conn, l->next->v, l->prev->v};
1687
1688 BLI_assert(!BM_face_exists(v_tri.data(), 3));
1689 BMeshNode *n = pbvh_bmesh_node_from_face(nodes, cd_face_node_offset, f);
1690 int ni = n - nodes.data();
1691 const std::array<BMEdge *, 3> e_tri = bm_edges_from_tri(bm, v_tri);
1692 BMFace *new_face = pbvh_bmesh_face_create(
1693 bm, nodes, node_changed, cd_face_node_offset, bm_log, ni, v_tri, e_tri, f);
1694
1695 merge_face_edge_data(bm, f, new_face, v_del, l, v_conn);
1696
1697 /* Ensure that v_conn is in the new face's node */
1698 if (!n->bm_unique_verts_.contains(v_conn)) {
1699 n->bm_other_verts_.add(v_conn);
1700 }
1701 }
1702 }
1704
1705 /* Delete the tagged faces. */
1706 for (BMFace *f_del : deleted_faces) {
1707 /* Get vertices and edges of face. */
1708 BLI_assert(f_del->len == 3);
1709 BMLoop *l_iter = BM_FACE_FIRST_LOOP(f_del);
1710 const std::array<BMVert *, 3> v_tri{l_iter->v, l_iter->next->v, l_iter->next->next->v};
1711 const std::array<BMEdge *, 3> e_tri{l_iter->e, l_iter->next->e, l_iter->next->next->e};
1712
1713 /* if its sa flap face merge its "outer" edge data into "base", so that boundary is propagated
1714 * from edges which are about to be deleted to the base of the triangle and will stay attached
1715 * to the mesh. */
1717
1718 /* Remove the face */
1720 nodes, node_changed, cd_vert_node_offset, cd_face_node_offset, bm_log, f_del);
1721 BM_face_kill(&bm, f_del);
1722
1723 /* Check if any of the face's edges are now unused by any
1724 * face, if so delete them */
1725 for (const int j : IndexRange(3)) {
1726 if (BM_edge_is_wire(e_tri[j])) {
1727 BM_edge_kill(&bm, e_tri[j]);
1728 }
1729 }
1730
1731 /* Check if any of the face's vertices are now unused, if so
1732 * remove them from the Tree */
1733 for (const int j : IndexRange(3)) {
1734 if ((v_tri[j] != v_del) && (v_tri[j]->e == nullptr)) {
1736 nodes, node_changed, cd_vert_node_offset, cd_face_node_offset, v_tri[j]);
1737
1738 BM_log_vert_removed(&bm_log, v_tri[j], eq_ctx->cd_vert_mask_offset);
1739
1740 if (v_tri[j] == v_conn) {
1741 v_conn = nullptr;
1742 }
1743 BLI_ghash_insert(deleted_verts, v_tri[j], nullptr);
1744 BM_vert_kill(&bm, v_tri[j]);
1745 }
1746 }
1747 }
1748
1749 /* If the v_conn was not removed above move it to the midpoint of v_conn and v_del. Doing so
1750 * helps avoiding long stretched and degenerated triangles.
1751 *
1752 * However, if the vertex is on a boundary, do not move it to preserve the shape of the
1753 * boundary. */
1754 if (v_conn != nullptr && !is_boundary_vert(*v_conn)) {
1755 BM_log_vert_before_modified(&bm_log, v_conn, eq_ctx->cd_vert_mask_offset);
1756 mid_v3_v3v3(v_conn->co, v_conn->co, v_del->co);
1757 add_v3_v3(v_conn->no, v_del->no);
1758 normalize_v3(v_conn->no);
1759 }
1760
1761 if (v_conn != nullptr) {
1762 /* Update bounding boxes attached to the connected vertex.
1763 * Note that we can often get-away without this but causes #48779. */
1764 BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_conn) {
1765 const int f_node = pbvh_bmesh_node_index_from_face(cd_face_node_offset, l->f);
1766 node_changed[f_node] = true;
1767 }
1769 }
1770
1771 /* Delete v_del */
1773 BM_log_vert_removed(&bm_log, v_del, eq_ctx->cd_vert_mask_offset);
1774 /* v_conn == nullptr is OK */
1775 BLI_ghash_insert(deleted_verts, v_del, v_conn);
1776 BM_vert_kill(&bm, v_del);
1777}
1778
1780 const float min_edge_len,
1781 BMesh &bm,
1783 MutableSpan<bool> node_changed,
1784 const int cd_vert_node_offset,
1785 const int cd_face_node_offset,
1786 BMLog &bm_log)
1787{
1788 const double start_time = BLI_time_now_seconds();
1789
1790 const float min_len_squared = min_edge_len * min_edge_len;
1791 bool any_collapsed = false;
1792 /* Deleted verts point to vertices they were merged into, or nullptr when removed. */
1793 GHash *deleted_verts = BLI_ghash_ptr_new("deleted_verts");
1794
1795 while (!BLI_heapsimple_is_empty(eq_ctx->q->heap)) {
1796 BMVert **pair = static_cast<BMVert **>(BLI_heapsimple_pop_min(eq_ctx->q->heap));
1797 BMVert *v1 = pair[0];
1798 BMVert *v2 = pair[1];
1799 BLI_mempool_free(eq_ctx->pool, pair);
1800 pair = nullptr;
1801
1802 /* Check the verts still exists. */
1803 if (!(v1 = bm_vert_hash_lookup_chain(deleted_verts, v1)) ||
1804 !(v2 = bm_vert_hash_lookup_chain(deleted_verts, v2)) || (v1 == v2))
1805 {
1806 continue;
1807 }
1808
1809 /* Check that the edge still exists. */
1810 BMEdge *e;
1811 if (!(e = BM_edge_exists(v1, v2))) {
1812 continue;
1813 }
1814#ifdef USE_EDGEQUEUE_TAG
1816#endif
1817
1818 if (len_squared_v3v3(v1->co, v2->co) >= min_len_squared) {
1819 continue;
1820 }
1821
1822 /* Check that the edge's vertices are still in the Tree. It's possible that
1823 * an edge collapse has deleted adjacent faces and the node has been split, thus leaving wire
1824 * edges and associated vertices. */
1827 {
1828 continue;
1829 }
1830
1831 any_collapsed = true;
1832
1834 nodes,
1835 node_changed,
1836 cd_vert_node_offset,
1837 cd_face_node_offset,
1838 bm_log,
1839 e,
1840 v1,
1841 v2,
1842 deleted_verts,
1843 eq_ctx);
1844 }
1845
1846 BLI_ghash_free(deleted_verts, nullptr, nullptr);
1847
1848 CLOG_INFO(&LOG, 2, "Short edge collapse took %f seconds.", BLI_time_now_seconds() - start_time);
1849
1850 return any_collapsed;
1851}
1852
1853/************************* Called from pbvh.cc *************************/
1854
1856 const float3 &ray_start,
1857 const float3 &ray_normal,
1858 IsectRayPrecalc *isect_precalc,
1859 float *depth,
1860 bool use_original,
1861 BMVert **r_active_vertex,
1862 float3 &r_face_normal)
1863{
1864 bool hit = false;
1865 float3 nearest_vertex_co(0.0f);
1866
1867 use_original = use_original && !node.orig_tris_.is_empty();
1868
1869 if (use_original) {
1870 for (const int tri_idx : node.orig_tris_.index_range()) {
1871 float *cos[3];
1872
1873 cos[0] = node.orig_positions_[node.orig_tris_[tri_idx][0]];
1874 cos[1] = node.orig_positions_[node.orig_tris_[tri_idx][1]];
1875 cos[2] = node.orig_positions_[node.orig_tris_[tri_idx][2]];
1876
1877 if (ray_face_intersection_tri(ray_start, isect_precalc, cos[0], cos[1], cos[2], depth)) {
1878 hit = true;
1879
1880 normal_tri_v3(r_face_normal, cos[0], cos[1], cos[2]);
1881
1882 if (r_active_vertex) {
1883 float3 location(0.0f);
1884 madd_v3_v3v3fl(location, ray_start, ray_normal, *depth);
1885 for (const int i : IndexRange(3)) {
1886 if (i == 0 ||
1887 len_squared_v3v3(location, cos[i]) < len_squared_v3v3(location, nearest_vertex_co))
1888 {
1889 copy_v3_v3(nearest_vertex_co, cos[i]);
1890 *r_active_vertex = node.orig_verts_[node.orig_tris_[tri_idx][i]];
1891 }
1892 }
1893 }
1894 }
1895 }
1896 }
1897 else {
1898 for (BMFace *f : node.bm_faces_) {
1899 BLI_assert(f->len == 3);
1900
1902 BMVert *v_tri[3];
1903
1904 BM_face_as_array_vert_tri(f, v_tri);
1906 ray_start, isect_precalc, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co, depth))
1907 {
1908 hit = true;
1909
1910 normal_tri_v3(r_face_normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co);
1911
1912 if (r_active_vertex) {
1913 float3 location(0.0f);
1914 madd_v3_v3v3fl(location, ray_start, ray_normal, *depth);
1915 for (const int i : IndexRange(3)) {
1916 if (i == 0 || len_squared_v3v3(location, v_tri[i]->co) <
1917 len_squared_v3v3(location, nearest_vertex_co))
1918 {
1919 copy_v3_v3(nearest_vertex_co, v_tri[i]->co);
1920 *r_active_vertex = v_tri[i];
1921 }
1922 }
1923 }
1924 }
1925 }
1926 }
1927 }
1928
1929 return hit;
1930}
1931
1933 const float3 &ray_start,
1934 IsectRayPrecalc *isect_precalc,
1935 float *depth,
1936 float *r_edge_length)
1937{
1938 if (node.flag_ & PBVH_FullyHidden) {
1939 return false;
1940 }
1941
1942 bool hit = false;
1943 BMFace *f_hit = nullptr;
1944
1945 for (BMFace *f : node.bm_faces_) {
1946 BLI_assert(f->len == 3);
1948 BMVert *v_tri[3];
1949 bool hit_local;
1950 BM_face_as_array_vert_tri(f, v_tri);
1951 hit_local = ray_face_intersection_tri(
1952 ray_start, isect_precalc, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co, depth);
1953
1954 if (hit_local) {
1955 f_hit = f;
1956 hit = true;
1957 }
1958 }
1959 }
1960
1961 if (hit) {
1962 BMVert *v_tri[3];
1963 BM_face_as_array_vert_tri(f_hit, v_tri);
1964 float len1 = len_squared_v3v3(v_tri[0]->co, v_tri[1]->co);
1965 float len2 = len_squared_v3v3(v_tri[1]->co, v_tri[2]->co);
1966 float len3 = len_squared_v3v3(v_tri[2]->co, v_tri[0]->co);
1967
1968 /* Detail returned will be set to the maximum allowed size, so take max here. */
1969 *r_edge_length = sqrtf(max_fff(len1, len2, len3));
1970 }
1971
1972 return hit;
1973}
1974
1976 const float3 &ray_start,
1977 const float3 &ray_normal,
1978 float *r_depth,
1979 float *dist_sq,
1980 bool use_original)
1981{
1982 bool hit = false;
1983
1984 if (use_original && !node.orig_tris_.is_empty()) {
1985 for (const int i : node.orig_tris_.index_range()) {
1986 const int *t = node.orig_tris_[i];
1987 hit |= ray_face_nearest_tri(ray_start,
1988 ray_normal,
1989 node.orig_positions_[t[0]],
1990 node.orig_positions_[t[1]],
1991 node.orig_positions_[t[2]],
1992 r_depth,
1993 dist_sq);
1994 }
1995 }
1996 else {
1997 for (BMFace *f : node.bm_faces_) {
1998 BLI_assert(f->len == 3);
2000 BMVert *v_tri[3];
2001
2002 BM_face_as_array_vert_tri(f, v_tri);
2003 hit |= ray_face_nearest_tri(
2004 ray_start, ray_normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co, r_depth, dist_sq);
2005 }
2006 }
2007 }
2008
2009 return hit;
2010}
2011
2012void bmesh_normals_update(Tree &pbvh, const IndexMask &nodes_to_update)
2013{
2014 const MutableSpan<BMeshNode> nodes = pbvh.nodes<BMeshNode>();
2015 nodes_to_update.foreach_index([&](const int i) {
2016 BMeshNode &node = nodes[i];
2017 for (BMFace *face : node.bm_faces_) {
2019 }
2020 for (BMVert *vert : node.bm_unique_verts_) {
2022 }
2023 for (BMVert *vert : node.bm_other_verts_) {
2025 }
2026 });
2027}
2028
2030 int totface; /* Number of faces. */
2031 int start; /* Start of faces in array. */
2034};
2035
2042 const Span<Bounds<float3>> face_bounds,
2043 FastNodeBuildInfo *node,
2044 MemArena *arena)
2045{
2046 FastNodeBuildInfo *child1, *child2;
2047
2048 if (node->totface <= leaf_limit) {
2049 return;
2050 }
2051
2052 /* Calculate bounding box around primitive centroids. */
2054 for (int i = 0; i < node->totface; i++) {
2055 BMFace *f = nodeinfo[i + node->start];
2056 const int face_index = BM_elem_index_get(f);
2057 const float3 center = math::midpoint(face_bounds[face_index].min, face_bounds[face_index].max);
2058 math::min_max(center, cb.min, cb.max);
2059 }
2060
2061 /* Initialize the children. */
2062
2063 /* Find widest axis and its midpoint. */
2064 const int axis = math::dominant_axis(cb.max - cb.min);
2065 const float mid = math::midpoint(cb.max[axis], cb.min[axis]);
2066
2067 int num_child1 = 0, num_child2 = 0;
2068
2069 /* Split vertices along the middle line. */
2070 const int end = node->start + node->totface;
2071 for (int i = node->start; i < end - num_child2; i++) {
2072 BMFace *f = nodeinfo[i];
2073 const int face_i = BM_elem_index_get(f);
2074
2075 if (math::midpoint(face_bounds[face_i].min[axis], face_bounds[face_i].max[axis]) > mid) {
2076 int i_iter = end - num_child2 - 1;
2077 int candidate = -1;
2078 /* Found a face that should be part of another node, look for a face to substitute with. */
2079
2080 for (; i_iter > i; i_iter--) {
2081 BMFace *f_iter = nodeinfo[i_iter];
2082 const int face_iter_i = BM_elem_index_get(f_iter);
2083 if (math::midpoint(face_bounds[face_iter_i].min[axis],
2084 face_bounds[face_iter_i].max[axis]) <= mid)
2085 {
2086 candidate = i_iter;
2087 break;
2088 }
2089
2090 num_child2++;
2091 }
2092
2093 if (candidate != -1) {
2094 BMFace *tmp = nodeinfo[i];
2095 nodeinfo[i] = nodeinfo[candidate];
2096 nodeinfo[candidate] = tmp;
2097 /* Increase both counts. */
2098 num_child1++;
2099 num_child2++;
2100 }
2101 else {
2102 /* Not finding candidate means second half of array part is full of
2103 * second node parts, just increase the number of child nodes for it. */
2104 num_child2++;
2105 }
2106 }
2107 else {
2108 num_child1++;
2109 }
2110 }
2111
2112 /* Ensure at least one child in each node. */
2113 if (num_child2 == 0) {
2114 num_child2++;
2115 num_child1--;
2116 }
2117 else if (num_child1 == 0) {
2118 num_child1++;
2119 num_child2--;
2120 }
2121
2122 /* At this point, faces should have been split along the array range sequentially,
2123 * each sequential part belonging to one node only. */
2124 BLI_assert((num_child1 + num_child2) == node->totface);
2125
2126 node->child1 = child1 = static_cast<FastNodeBuildInfo *>(
2127 BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo)));
2128 node->child2 = child2 = static_cast<FastNodeBuildInfo *>(
2129 BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo)));
2130
2131 child1->totface = num_child1;
2132 child1->start = node->start;
2133 child2->totface = num_child2;
2134 child2->start = node->start + num_child1;
2135 child1->child1 = child1->child2 = child2->child1 = child2->child2 = nullptr;
2136
2137 pbvh_bmesh_node_limit_ensure_fast(nodeinfo, face_bounds, child1, arena);
2138 pbvh_bmesh_node_limit_ensure_fast(nodeinfo, face_bounds, child2, arena);
2139}
2140
2142 const int cd_vert_node_offset,
2143 const int cd_face_node_offset,
2144 const Span<BMFace *> nodeinfo,
2145 const Span<Bounds<float3>> face_bounds,
2146 FastNodeBuildInfo *node,
2147 int node_index)
2148{
2149 BMeshNode *n = &nodes[node_index];
2150 /* Two cases, node does not have children or does have children. */
2151 if (node->child1) {
2152 int children_offset_ = nodes.size();
2153
2154 n->children_offset_ = children_offset_;
2155 nodes.resize(nodes.size() + 2);
2157 cd_vert_node_offset,
2158 cd_face_node_offset,
2159 nodeinfo,
2160 face_bounds,
2161 node->child1,
2162 children_offset_);
2164 cd_vert_node_offset,
2165 cd_face_node_offset,
2166 nodeinfo,
2167 face_bounds,
2168 node->child2,
2169 children_offset_ + 1);
2170 }
2171 else {
2172 /* Node does not have children so it's a leaf node, populate with faces and tag accordingly
2173 * this is an expensive part but it's not so easily thread-able due to vertex node indices. */
2174
2175 n->flag_ |= PBVH_Leaf;
2176 n->bm_faces_.reserve(node->totface);
2177
2178 const int end = node->start + node->totface;
2179
2180 for (int i = node->start; i < end; i++) {
2181 BMFace *f = nodeinfo[i];
2182
2183 /* Update ownership of faces. */
2184 n->bm_faces_.add_new(f);
2185 BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index);
2186
2187 /* Update vertices. */
2188 BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
2189 BMLoop *l_iter = l_first;
2190 do {
2191 BMVert *v = l_iter->v;
2192 if (!n->bm_unique_verts_.contains(v)) {
2193 if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
2194 n->bm_other_verts_.add(v);
2195 }
2196 else {
2198 BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, node_index);
2199 }
2200 }
2201 } while ((l_iter = l_iter->next) != l_first);
2202 }
2203 }
2204}
2205
2206/***************************** Public API *****************************/
2207
2209{
2210 Tree pbvh(Type::BMesh);
2211 if (bm.totface == 0) {
2212 return pbvh;
2213 }
2214
2215 const int cd_vert_node_offset = CustomData_get_offset_named(
2216 &bm.vdata, CD_PROP_INT32, ".sculpt_dyntopo_node_id_vertex");
2217 const int cd_face_node_offset = CustomData_get_offset_named(
2218 &bm.pdata, CD_PROP_INT32, ".sculpt_dyntopo_node_id_face");
2219
2220 /* bounding box array of all faces, no need to recalculate every time. */
2221 Array<Bounds<float3>> face_bounds(bm.totface);
2222 Array<BMFace *> nodeinfo(bm.totface);
2223 MemArena *arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "fast Tree node storage");
2224
2225 BMIter iter;
2226 BMFace *f;
2227 int i;
2228 BM_ITER_MESH_INDEX (f, &iter, &bm, BM_FACES_OF_MESH, i) {
2229 face_bounds[i] = negative_bounds();
2230
2231 BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
2232 BMLoop *l_iter = l_first;
2233 do {
2234 math::min_max(float3(l_iter->v->co), face_bounds[i].min, face_bounds[i].max);
2235 } while ((l_iter = l_iter->next) != l_first);
2236
2237 /* so we can do direct lookups on 'face_bounds' */
2238 BM_elem_index_set(f, i); /* set_dirty! */
2239 nodeinfo[i] = f;
2240 BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE);
2241 }
2242 /* Likely this is already dirty. */
2244
2245 BMVert *v;
2246 BM_ITER_MESH (v, &iter, &bm, BM_VERTS_OF_MESH) {
2247 BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE);
2248 }
2249
2250 /* Set up root node. */
2251 FastNodeBuildInfo rootnode = {0};
2252 rootnode.totface = bm.totface;
2253
2254 /* Start recursion, assign faces to nodes accordingly. */
2255 pbvh_bmesh_node_limit_ensure_fast(nodeinfo, face_bounds, &rootnode, arena);
2256
2257 /* We now have all faces assigned to a node,
2258 * next we need to assign those to the gsets of the nodes. */
2259
2260 /* Start with all faces in the root node. */
2261 /* Take root node and visit and populate children recursively. */
2262 Vector<BMeshNode> &nodes = std::get<Vector<BMeshNode>>(pbvh.nodes_);
2263 nodes.resize(1);
2265 nodes, cd_vert_node_offset, cd_face_node_offset, nodeinfo, face_bounds, &rootnode, 0);
2266
2267 pbvh.tag_positions_changed(nodes.index_range());
2268 update_bounds_bmesh(bm, pbvh);
2269 store_bounds_orig(pbvh);
2270
2271 threading::parallel_for(nodes.index_range(), 8, [&](const IndexRange range) {
2272 for (const int i : range) {
2273 const Set<BMFace *, 0> &faces = BKE_pbvh_bmesh_node_faces(&nodes[i]);
2274 if (std::all_of(faces.begin(), faces.end(), [&](const BMFace *face) {
2275 return BM_elem_flag_test(face, BM_ELEM_HIDDEN);
2276 }))
2277 {
2278 nodes[i].flag_ |= PBVH_FullyHidden;
2279 }
2280 }
2281 });
2282
2283 update_mask_bmesh(bm, nodes.index_range(), pbvh);
2284
2285 BLI_memarena_free(arena);
2286 return pbvh;
2287}
2288
2290 Tree &pbvh,
2291 BMLog &bm_log,
2293 const float min_edge_len,
2294 const float max_edge_len,
2295 const float center[3],
2296 const float view_normal[3],
2297 float radius,
2298 const bool use_frontface,
2299 const bool use_projected)
2300{
2301 const int cd_vert_node_offset = CustomData_get_offset_named(
2302 &bm.vdata, CD_PROP_INT32, ".sculpt_dyntopo_node_id_vertex");
2303 const int cd_face_node_offset = CustomData_get_offset_named(
2304 &bm.pdata, CD_PROP_INT32, ".sculpt_dyntopo_node_id_face");
2305 const int cd_vert_mask_offset = CustomData_get_offset_named(
2306 &bm.vdata, CD_PROP_FLOAT, ".sculpt_mask");
2307
2308 bool modified = false;
2309
2310 if (view_normal) {
2311 BLI_assert(len_squared_v3(view_normal) != 0.0f);
2312 }
2313
2314 MutableSpan<BMeshNode> nodes = pbvh.nodes<BMeshNode>();
2315 Array<bool> node_changed(nodes.size(), false);
2316
2317 if (mode & PBVH_Collapse) {
2318 EdgeQueue q;
2319 BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *) * 2, 0, 128, BLI_MEMPOOL_NOP);
2320 EdgeQueueContext eq_ctx = {
2321 &q,
2322 queue_pool,
2323 &bm,
2324 cd_vert_mask_offset,
2325 cd_vert_node_offset,
2326 cd_face_node_offset,
2327 };
2328
2330 &eq_ctx, min_edge_len, nodes, center, view_normal, radius, use_frontface, use_projected);
2331 modified |= pbvh_bmesh_collapse_short_edges(&eq_ctx,
2332 min_edge_len,
2333 bm,
2334 nodes,
2335 node_changed,
2336 cd_vert_node_offset,
2337 cd_face_node_offset,
2338 bm_log);
2339 BLI_heapsimple_free(q.heap, nullptr);
2340 BLI_mempool_destroy(queue_pool);
2341 }
2342
2343 if (mode & PBVH_Subdivide) {
2344 EdgeQueue q;
2345 BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *) * 2, 0, 128, BLI_MEMPOOL_NOP);
2346 EdgeQueueContext eq_ctx = {
2347 &q,
2348 queue_pool,
2349 &bm,
2350 cd_vert_mask_offset,
2351 cd_vert_node_offset,
2352 cd_face_node_offset,
2353 };
2354
2356 &eq_ctx, max_edge_len, nodes, center, view_normal, radius, use_frontface, use_projected);
2358 &eq_ctx, bm, nodes, node_changed, cd_vert_node_offset, cd_face_node_offset, bm_log);
2359 BLI_heapsimple_free(q.heap, nullptr);
2360 BLI_mempool_destroy(queue_pool);
2361 }
2362
2363 IndexMaskMemory memory;
2364 const IndexMask node_mask = IndexMask::from_bools(node_changed, memory);
2365 pbvh.tag_positions_changed(node_mask);
2366 pbvh.tag_topology_changed(node_mask);
2367
2368 /* Unmark nodes. */
2369 for (Node &node : nodes) {
2370 if (node.flag_ & PBVH_Leaf && node.flag_ & PBVH_UpdateTopology) {
2371 node.flag_ &= ~PBVH_UpdateTopology;
2372 }
2373 }
2374
2375 /* Go over all changed nodes and check if anything needs to be updated. */
2376 for (BMeshNode &node : nodes) {
2377 if (node.flag_ & PBVH_Leaf && node.flag_ & PBVH_TopologyUpdated) {
2378 node.flag_ &= ~PBVH_TopologyUpdated;
2379
2380 if (!node.orig_tris_.is_empty()) {
2381 /* Reallocate original triangle data. */
2383 BKE_pbvh_bmesh_node_save_orig(&bm, &bm_log, &node, true);
2384 }
2385 }
2386 }
2387
2388#ifdef USE_VERIFY
2389 pbvh_bmesh_verify(pbvh);
2390#endif
2391
2392 return modified;
2393}
2394
2395/* Updates a given Tree Node with the original coordinates of the corresponding
2396 * BMesh vertex. Attempts to retrieve the value from the BMLog, falls back to the vertex's current
2397 * coordinates if it is either not found in the log or not requested. */
2398static void copy_original_vert(BMLog *log, BMeshNode *node, BMVert *v, int i, bool use_original)
2399{
2400 if (!use_original) {
2401 node->orig_positions_[i] = v->co;
2402 }
2403 else {
2404 const float *origco = BM_log_find_original_vert_co(log, v);
2405 if (origco) {
2406 node->orig_positions_[i] = origco;
2407 }
2408 else {
2409 node->orig_positions_[i] = v->co;
2410 }
2411 }
2412
2413 node->orig_verts_[i] = v;
2414}
2415
2416} // namespace blender::bke::pbvh
2417
2419 BMLog *log,
2421 bool use_original)
2422{
2423 using namespace blender;
2424 /* Skip if original coords/triangles are already saved. */
2425 if (!node->orig_tris_.is_empty()) {
2426 return;
2427 }
2428
2429 const int totvert = node->bm_unique_verts_.size() + node->bm_other_verts_.size();
2430
2431 node->orig_positions_.reinitialize(totvert);
2432 node->orig_verts_.reinitialize(totvert);
2433
2434 VectorSet<BMVert *> vert_map;
2435 vert_map.reserve(totvert);
2436
2437 /* Copy out the vertices and assign a temporary index. */
2438 int i = 0;
2439 for (BMVert *v : node->bm_unique_verts_) {
2440 bke::pbvh::copy_original_vert(log, node, v, i, use_original);
2441 vert_map.add(v);
2442 i++;
2443 }
2444 for (BMVert *v : node->bm_other_verts_) {
2445 bke::pbvh::copy_original_vert(log, node, v, i, use_original);
2446 vert_map.add(v);
2447 i++;
2448 }
2449 /* Likely this is already dirty. */
2451
2452 /* Copy the triangles */
2453 const int tris_num = std::count_if(
2454 node->bm_faces_.begin(), node->bm_faces_.end(), [&](const BMFace *face) {
2455 return !BM_elem_flag_test_bool(face, BM_ELEM_HIDDEN);
2456 });
2457 node->orig_tris_.reinitialize(tris_num);
2458 i = 0;
2459 for (BMFace *f : node->bm_faces_) {
2461 continue;
2462 }
2463 const std::array<BMVert *, 3> verts = bke::pbvh::bm_face_as_array(f);
2464 node->orig_tris_[i] = int3(
2465 vert_map.index_of(verts[0]), vert_map.index_of(verts[1]), vert_map.index_of(verts[2]));
2466 i++;
2467 }
2468}
2469
2471{
2472 using namespace blender;
2473 const int cd_vert_node_offset = CustomData_get_offset_named(
2474 &bm.vdata, CD_PROP_INT32, ".sculpt_dyntopo_node_id_vertex");
2475 const int cd_face_node_offset = CustomData_get_offset_named(
2476 &bm.pdata, CD_PROP_INT32, ".sculpt_dyntopo_node_id_face");
2477
2478 Vector<bke::pbvh::BMeshNode> &nodes = std::get<Vector<bke::pbvh::BMeshNode>>(pbvh.nodes_);
2479 Vector<bool> node_changed(nodes.size(), false);
2480 const IndexRange orig_range = nodes.index_range();
2481 for (const int i : orig_range) {
2482 bke::pbvh::BMeshNode *n = &nodes[i];
2483 if (n->flag_ & PBVH_Leaf) {
2484 /* Free `orco` / `ortri` data. */
2485 pbvh_bmesh_node_drop_orig(n);
2486
2487 /* Recursively split nodes that have gotten too many elements. */
2488 pbvh_bmesh_node_limit_ensure(
2489 bm, nodes, node_changed, cd_vert_node_offset, cd_face_node_offset, i);
2490 }
2491 }
2492
2493 IndexMaskMemory memory;
2494 const IndexMask node_mask = IndexMask::from_bools(node_changed, memory);
2495 pbvh.tag_positions_changed(node_mask);
2496 pbvh.tag_topology_changed(node_mask);
2497 update_mask_bmesh(bm, node_mask, pbvh);
2498}
2499
2504
2507{
2508 return node->bm_unique_verts_;
2509}
2510
2513{
2514 return node->bm_other_verts_;
2515}
2516
2518{
2519 return node->bm_faces_;
2520}
2521
2522/****************************** Debugging *****************************/
2523
2524#if 0
2525
2526static void pbvh_bmesh_print(Tree *pbvh)
2527{
2528 fprintf(stderr, "\npbvh=%p\n", pbvh);
2529 fprintf(stderr, "bm_face_to_node:\n");
2530
2531 BMIter iter;
2532 BMFace *f;
2533 BM_ITER_MESH (f, &iter, pbvh->header.bm, BM_FACES_OF_MESH) {
2534 fprintf(
2535 stderr, " %d -> %d\n", BM_elem_index_get(f), pbvh_bmesh_node_index_from_face(pbvh, f));
2536 }
2537
2538 fprintf(stderr, "bm_vert_to_node:\n");
2539 BMVert *v;
2540 BM_ITER_MESH (v, &iter, pbvh->header.bm, BM_FACES_OF_MESH) {
2541 fprintf(
2542 stderr, " %d -> %d\n", BM_elem_index_get(v), pbvh_bmesh_node_index_from_vert(pbvh, v));
2543 }
2544
2545 for (int n = 0; n < pbvh->totnode; n++) {
2546 Node *node = &pbvh->nodes_[n];
2547 if (!(node->flag & PBVH_Leaf)) {
2548 continue;
2549 }
2550
2551 GSetIterator gs_iter;
2552 fprintf(stderr, "node %d\n faces:\n", n);
2553 GSET_ITER (gs_iter, node->bm_faces_)
2554 fprintf(stderr, " %d\n", BM_elem_index_get((BMFace *)BLI_gsetIterator_getKey(&gs_iter)));
2555 fprintf(stderr, " unique verts:\n");
2556 GSET_ITER (gs_iter, node->bm_unique_verts_)
2557 fprintf(stderr, " %d\n", BM_elem_index_get((BMVert *)BLI_gsetIterator_getKey(&gs_iter)));
2558 fprintf(stderr, " other verts:\n");
2559 GSET_ITER (gs_iter, node->bm_other_verts_)
2560 fprintf(stderr, " %d\n", BM_elem_index_get((BMVert *)BLI_gsetIterator_getKey(&gs_iter)));
2561 }
2562}
2563
2564static void print_flag_factors(int flag)
2565{
2566 printf("flag=0x%x:\n", flag);
2567 for (int i = 0; i < 32; i++) {
2568 if (flag & (1 << i)) {
2569 printf(" %d (1 << %d)\n", 1 << i, i);
2570 }
2571 }
2572}
2573#endif
2574
2575#ifdef USE_VERIFY
2576
2577static void pbvh_bmesh_verify(Tree *pbvh)
2578{
2579 /* Build list of faces & verts to lookup. */
2580 GSet *faces_all = BLI_gset_ptr_new_ex(__func__, pbvh->header.bm->totface);
2581 BMIter iter;
2582
2583 {
2584 BMFace *f;
2585 BM_ITER_MESH (f, &iter, pbvh->header.bm, BM_FACES_OF_MESH) {
2586 BLI_assert(BM_ELEM_CD_GET_INT(f, cd_face_node_offset) != DYNTOPO_NODE_NONE);
2587 BLI_gset_insert(faces_all, f);
2588 }
2589 }
2590
2591 GSet *verts_all = BLI_gset_ptr_new_ex(__func__, pbvh->header.bm->totvert);
2592 {
2593 BMVert *v;
2594 BM_ITER_MESH (v, &iter, pbvh->header.bm, BM_VERTS_OF_MESH) {
2595 if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
2596 BLI_gset_insert(verts_all, v);
2597 }
2598 }
2599 }
2600
2601 /* Check vert/face counts. */
2602 {
2603 int totface = 0, totvert = 0;
2604 for (int i = 0; i < pbvh->totnode; i++) {
2605 Node *n = &pbvh->nodes_[i];
2606 totface += n->bm_faces_.is_empty() ? n->bm_faces_.size() : 0;
2607 totvert += n->bm_unique_verts_ ? n->bm_unique_verts_.size() : 0;
2608 }
2609
2610 BLI_assert(totface == BLI_gset_len(faces_all));
2611 BLI_assert(totvert == BLI_gset_len(verts_all));
2612 }
2613
2614 {
2615 BMFace *f;
2616 BM_ITER_MESH (f, &iter, pbvh->header.bm, BM_FACES_OF_MESH) {
2617 BMIter bm_iter;
2618 BMVert *v;
2619 Node *n = pbvh_bmesh_node_lookup(pbvh, f);
2620
2621 /* Check that the face's node is a leaf. */
2622 BLI_assert(n->flag & PBVH_Leaf);
2623
2624 /* Check that the face's node knows it owns the face. */
2625 BLI_assert(n->bm_faces_.contains(f));
2626
2627 /* Check the face's vertices... */
2628 BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) {
2629 Node *nv;
2630
2631 /* Check that the vertex is in the node. */
2632 BLI_assert(BLI_gset_haskey(n->bm_unique_verts_, v) ^
2633 BLI_gset_haskey(n->bm_other_verts_, v));
2634
2635 /* Check that the vertex has a node owner. */
2636 nv = pbvh_bmesh_node_lookup(pbvh, v);
2637
2638 /* Check that the vertex's node knows it owns the vert. */
2639 BLI_assert(BLI_gset_haskey(nv->bm_unique_verts_, v));
2640
2641 /* Check that the vertex isn't duplicated as an 'other' vert. */
2642 BLI_assert(!BLI_gset_haskey(nv->bm_other_verts_, v));
2643 }
2644 }
2645 }
2646
2647 /* Check verts */
2648 {
2649 BMVert *v;
2650 BM_ITER_MESH (v, &iter, pbvh->header.bm, BM_VERTS_OF_MESH) {
2651 /* Vertex isn't tracked. */
2652 if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) == DYNTOPO_NODE_NONE) {
2653 continue;
2654 }
2655
2656 Node *n = pbvh_bmesh_node_lookup(pbvh, v);
2657
2658 /* Check that the vert's node is a leaf. */
2659 BLI_assert(n->flag & PBVH_Leaf);
2660
2661 /* Check that the vert's node knows it owns the vert. */
2662 BLI_assert(BLI_gset_haskey(n->bm_unique_verts_, v));
2663
2664 /* Check that the vertex isn't duplicated as an 'other' vert. */
2665 BLI_assert(!BLI_gset_haskey(n->bm_other_verts_, v));
2666
2667 /* Check that the vert's node also contains one of the vert's adjacent faces. */
2668 bool found = false;
2669 BMIter bm_iter;
2670 BMFace *f = nullptr;
2671 BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
2672 if (pbvh_bmesh_node_lookup(pbvh, f) == n) {
2673 found = true;
2674 break;
2675 }
2676 }
2677 BLI_assert(found || f == nullptr);
2678
2679# if 1
2680 /* total freak stuff, check if node exists somewhere else */
2681 /* Slow */
2682 for (int i = 0; i < pbvh->totnode; i++) {
2683 Node *n_other = &pbvh->nodes_[i];
2684 if ((n != n_other) && (n_other->bm_unique_verts_)) {
2685 BLI_assert(!BLI_gset_haskey(n_other->bm_unique_verts_, v));
2686 }
2687 }
2688# endif
2689 }
2690 }
2691
2692# if 0
2693 /* check that every vert belongs somewhere */
2694 /* Slow */
2695 BM_ITER_MESH (vi, &iter, pbvh->header.bm, BM_VERTS_OF_MESH) {
2696 bool has_unique = false;
2697 for (int i = 0; i < pbvh->totnode; i++) {
2698 Node *n = &pbvh->nodes_[i];
2699 if ((n->bm_unique_verts_ != nullptr) && BLI_gset_haskey(n->bm_unique_verts_, vi)) {
2700 has_unique = true;
2701 }
2702 }
2703 BLI_assert(has_unique);
2704 vert_count++;
2705 }
2706
2707 /* If totvert differs from number of verts inside the hash. hash-totvert is checked above. */
2708 BLI_assert(vert_count == pbvh->header.bm->totvert);
2709# endif
2710
2711 /* Check that node elements are recorded in the top level */
2712 for (int i = 0; i < pbvh->totnode; i++) {
2713 Node *n = &pbvh->nodes_[i];
2714 if (n->flag & PBVH_Leaf) {
2715 GSetIterator gs_iter;
2716
2717 for (BMFace *f : n->bm_faces_) {
2718 Node *n_other = pbvh_bmesh_node_lookup(pbvh, f);
2719 BLI_assert(n == n_other);
2720 BLI_assert(BLI_gset_haskey(faces_all, f));
2721 }
2722
2723 GSET_ITER (gs_iter, n->bm_unique_verts_) {
2724 BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
2725 Node *n_other = pbvh_bmesh_node_lookup(pbvh, v);
2726 BLI_assert(!BLI_gset_haskey(n->bm_other_verts_, v));
2727 BLI_assert(n == n_other);
2728 BLI_assert(BLI_gset_haskey(verts_all, v));
2729 }
2730
2731 GSET_ITER (gs_iter, n->bm_other_verts_) {
2732 BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
2733 /* this happens sometimes and seems harmless */
2734 // BLI_assert(!BM_vert_face_check(v));
2735 BLI_assert(BLI_gset_haskey(verts_all, v));
2736 }
2737 }
2738 }
2739
2740 BLI_gset_free(faces_all, nullptr);
2741 BLI_gset_free(verts_all, nullptr);
2742}
2743
2744#endif
int CustomData_get_offset_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
void CustomData_bmesh_copy_block(CustomData &data, void *src_block, void **dst_block)
@ PBVH_TopologyUpdated
Definition BKE_pbvh.hh:42
@ PBVH_UpdateTopology
Definition BKE_pbvh.hh:38
@ PBVH_FullyHidden
Definition BKE_pbvh.hh:34
@ PBVH_Leaf
Definition BKE_pbvh.hh:30
A BVH for high poly meshes.
void BKE_pbvh_node_mark_topology_update(blender::bke::pbvh::Node &node)
void BKE_pbvh_bmesh_after_stroke(BMesh &bm, blender::bke::pbvh::Tree &pbvh)
void BKE_pbvh_node_fully_hidden_set(blender::bke::pbvh::Node &node, int fully_hidden)
Definition pbvh.cc:1530
const blender::Set< BMFace *, 0 > & BKE_pbvh_bmesh_node_faces(blender::bke::pbvh::BMeshNode *node)
PBVHTopologyUpdateMode
@ PBVH_Collapse
@ PBVH_Subdivide
const blender::Set< BMVert *, 0 > & BKE_pbvh_bmesh_node_unique_verts(blender::bke::pbvh::BMeshNode *node)
void BKE_pbvh_bmesh_node_save_orig(BMesh *bm, BMLog *log, blender::bke::pbvh::BMeshNode *node, bool use_original)
const blender::Set< BMVert *, 0 > & BKE_pbvh_bmesh_node_other_verts(blender::bke::pbvh::BMeshNode *node)
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_INLINE
struct GSet GSet
Definition BLI_ghash.h:341
bool BLI_gset_haskey(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:1004
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void ** BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:745
unsigned int BLI_gset_len(const GSet *gs) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:954
void BLI_gset_insert(GSet *gs, void *key)
Definition BLI_ghash.c:959
BLI_INLINE void * BLI_gsetIterator_getKey(GSetIterator *gsi)
Definition BLI_ghash.h:459
#define GSET_ITER(gs_iter_, gset_)
Definition BLI_ghash.h:472
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.c:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:860
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.c:1034
GSet * BLI_gset_ptr_new_ex(const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
A min-heap / priority queue ADT.
HeapSimple * BLI_heapsimple_new(void) ATTR_WARN_UNUSED_RESULT
void BLI_heapsimple_free(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp) ATTR_NONNULL(1)
void * BLI_heapsimple_pop_min(HeapSimple *heap) ATTR_NONNULL(1)
bool BLI_heapsimple_is_empty(const HeapSimple *heap) ATTR_NONNULL(1)
void BLI_heapsimple_insert(HeapSimple *heap, float value, void *ptr) ATTR_NONNULL(1)
MINLINE float max_fff(float a, float b, float c)
MINLINE float max_ff(float a, float b)
MINLINE float square_f(float a)
void closest_on_tri_to_point_v3(float r[3], const float p[3], const float v1[3], const float v2[3], const float v3[3])
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition math_geom.cc:39
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v3_v3(float r[3], const float a[3])
void project_plane_normalized_v3_v3v3(float out[3], const float p[3], const float v_plane[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
void * BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
struct MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
#define BLI_MEMARENA_STD_BUFSIZE
void * BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1)
void BLI_mempool_free(BLI_mempool *pool, void *addr) ATTR_NONNULL(1
BLI_mempool * BLI_mempool_create(unsigned int esize, unsigned int elem_num, unsigned int pchunk, unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
@ BLI_MEMPOOL_NOP
Definition BLI_mempool.h:86
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1)
unsigned int uint
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.c:65
#define ARRAY_SIZE(arr)
#define UNUSED_VARS(...)
#define UNUSED_VARS_NDEBUG(...)
#define UNLIKELY(x)
#define ELEM(...)
#define LIKELY(x)
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
#define CLOG_INFO(clg_ref, level,...)
Definition CLG_log.h:179
@ CD_PROP_FLOAT
@ CD_PROP_INT32
#define DYNTOPO_NODE_NONE
Read Guarded memory(de)allocation.
#define BM_ELEM_CD_GET_FLOAT(ele, offset)
#define BM_DISK_EDGE_NEXT(e, v)
#define BM_ELEM_CD_GET_INT(ele, offset)
#define BM_ELEM_CD_SET_INT(ele, offset, f)
@ BM_ELEM_HIDDEN
@ BM_ELEM_SEAM
@ BM_ELEM_SMOOTH
@ BM_ELEM_TAG
#define BM_FACE_FIRST_LOOP(p)
void BM_vert_kill(BMesh *bm, BMVert *v)
void BM_face_kill(BMesh *bm, BMFace *f)
BMFace * BM_face_create(BMesh *bm, BMVert *const *verts, BMEdge *const *edges, const int len, const BMFace *f_example, const eBMCreateFlag create_flag)
void BM_edge_kill(BMesh *bm, BMEdge *e)
BMVert * BM_vert_create(BMesh *bm, const float co[3], const BMVert *v_example, const eBMCreateFlag create_flag)
Main function for creating a new vertex.
Definition bmesh_core.cc:43
BMEdge * BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag)
Main function for creating a new edge.
@ BM_CREATE_NOP
Definition bmesh_core.hh:24
@ BM_CREATE_NO_DOUBLE
Definition bmesh_core.hh:26
#define BM_elem_index_get(ele)
#define BM_elem_index_set(ele, index)
#define BM_elem_flag_test(ele, hflag)
#define BM_elem_flag_test_bool(ele, hflag)
void BM_data_interp_from_edges(BMesh *bm, const BMEdge *e_src_1, const BMEdge *e_src_2, BMEdge *e_dst, const float fac)
Data, Interpolate From Edges.
void BM_data_interp_from_verts(BMesh *bm, const BMVert *v_src_1, const BMVert *v_src_2, BMVert *v_dst, const float fac)
Data, Interpolate From Verts.
int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, const int len)
Iterator as Array.
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_FACES_OF_EDGE
@ BM_FACES_OF_VERT
@ BM_VERTS_OF_MESH
@ BM_VERTS_OF_FACE
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_EDGE
@ BM_EDGES_OF_VERT
@ BM_EDGES_OF_FACE
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_log_face_added(BMLog *log, BMFace *f)
Definition bmesh_log.cc:811
void BM_log_face_removed(BMLog *log, BMFace *f)
Definition bmesh_log.cc:853
const float * BM_log_find_original_vert_co(BMLog *log, BMVert *v)
Definition bmesh_log.cc:921
void BM_log_vert_added(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
Definition bmesh_log.cc:790
void BM_log_vert_removed(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
Definition bmesh_log.cc:825
void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
Definition bmesh_log.cc:772
#define BM_FACE
#define BM_VERT
void BM_vert_normal_update(BMVert *v)
void BM_face_normal_update(BMFace *f)
void BM_face_as_array_vert_tri(BMFace *f, BMVert *r_verts[3])
bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb)
BMFace * BM_face_exists(BMVert *const *varr, int len)
float BM_edge_calc_length_squared(const BMEdge *e)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
BMLoop * BM_vert_find_first_loop(BMVert *v)
int BM_edge_face_count(const BMEdge *e)
bool BM_vert_in_face(BMVert *v, BMFace *f)
bool BM_vert_face_check(const BMVert *v)
int BM_vert_face_count_at_most(const BMVert *v, int count_max)
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
#define BM_vert_face_count_is_equal(v, n)
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
#define BM_vert_edge_count_is_over(v, n)
BLI_INLINE bool BM_vert_in_edge(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
IndexRange index_range() const
Definition BLI_array.hh:349
constexpr IndexRange index_range() const
void clear_and_shrink()
Definition BLI_set.hh:546
int64_t size() const
Definition BLI_set.hh:564
void reserve(const int64_t n)
Definition BLI_set.hh:614
bool contains(const Key &key) const
Definition BLI_set.hh:291
bool add(const Key &key)
Definition BLI_set.hh:248
bool is_empty() const
Definition BLI_set.hh:572
void add_new(const Key &key)
Definition BLI_set.hh:233
bool remove(const Key &key)
Definition BLI_set.hh:366
constexpr const T * data() const
Definition BLI_span.hh:216
int64_t index_of(const Key &key) const
void reserve(const int64_t n)
bool add(const Key &key)
int64_t size() const
void append(const T &value)
void resize(const int64_t new_size)
Bounds< float3 > bounds_
Bounds< float3 > bounds_orig_
void tag_positions_changed(const IndexMask &node_mask)
Definition pbvh.cc:549
static Tree from_bmesh(BMesh &bm)
Span< NodeT > nodes() const
void tag_topology_changed(const IndexMask &node_mask)
Definition pbvh.cc:572
std::variant< Vector< MeshNode >, Vector< GridsNode >, Vector< BMeshNode > > nodes_
static IndexMask from_bools(Span< bool > bools, IndexMaskMemory &memory)
void foreach_index(Fn &&fn) const
#define printf
#define sqrtf(x)
static float verts[][3]
int count
#define LOG(severity)
Definition log.h:33
ccl_device_inline float3 cos(float3 v)
ccl_device_inline float3 log(float3 v)
#define G(x, y, z)
static std::array< BMEdge *, 3 > bm_edges_from_tri(BMesh &bm, const Span< BMVert * > v_tri)
BLI_INLINE std::array< BMVert *, 3 > bm_face_as_array(BMFace *f)
static BMVert * bm_vert_hash_lookup_chain(GHash *deleted_verts, BMVert *v)
static void merge_flap_edge_data(BMesh &bm, BMFace *del_face, BMFace *flap_face, BMEdge *e, BMVert *v_del, BMLoop *l_del, BMVert *v_conn)
static void long_edge_queue_create(EdgeQueueContext *eq_ctx, const float max_edge_len, MutableSpan< BMeshNode > nodes, const float center[3], const float view_normal[3], float radius, const bool use_frontface, const bool use_projected)
static void pbvh_bmesh_vert_remove(MutableSpan< BMeshNode > nodes, MutableSpan< bool > node_changed, const int cd_vert_node_offset, const int cd_face_node_offset, BMVert *v)
bool raycast_node_detail_bmesh(BMeshNode &node, const float3 &ray_start, IsectRayPrecalc *isect_precalc, float *depth, float *r_edge_length)
static void pbvh_bmesh_collapse_edge(BMesh &bm, MutableSpan< BMeshNode > nodes, MutableSpan< bool > node_changed, const int cd_vert_node_offset, const int cd_face_node_offset, BMLog &bm_log, BMEdge *e, BMVert *v1, BMVert *v2, GHash *deleted_verts, EdgeQueueContext *eq_ctx)
static BMFace * pbvh_bmesh_face_create(BMesh &bm, MutableSpan< BMeshNode > nodes, MutableSpan< bool > node_changed, const int cd_face_node_offset, BMLog &bm_log, int node_index, const Span< BMVert * > v_tri, const Span< BMEdge * > e_tri, const BMFace *f_example)
void update_mask_bmesh(const BMesh &bm, const IndexMask &node_mask, Tree &pbvh)
Definition pbvh.cc:1294
static void short_edge_queue_face_add(EdgeQueueContext *eq_ctx, BMFace *f)
static void pbvh_bmesh_node_finalize(BMeshNode *n, const int node_index, const int cd_vert_node_offset, const int cd_face_node_offset)
static void edge_queue_insert(EdgeQueueContext *eq_ctx, BMEdge *e, float priority)
static void pbvh_bmesh_vert_ownership_transfer(MutableSpan< BMeshNode > nodes, MutableSpan< bool > node_changed, const int cd_vert_node_offset, const int new_owner_index, BMVert *v)
BLI_INLINE int pbvh_bmesh_node_index_from_face(const int cd_face_node_offset, const BMFace *key)
static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx, BMesh &bm, MutableSpan< BMeshNode > nodes, MutableSpan< bool > node_changed, const int cd_vert_node_offset, const int cd_face_node_offset, BMLog &bm_log)
static void merge_face_edge_data(BMesh &bm, BMFace *, BMFace *new_face, BMVert *v_del, BMLoop *l_del, BMVert *v_conn)
bool node_raycast_bmesh(BMeshNode &node, const float3 &ray_start, const float3 &ray_normal, IsectRayPrecalc *isect_precalc, float *depth, bool use_original, BMVert **r_active_vertex, float3 &r_face_normal)
static void short_edge_queue_edge_add(EdgeQueueContext *eq_ctx, BMEdge *e)
static void copy_original_vert(BMLog *log, BMeshNode *node, BMVert *v, int i, bool use_original)
static BMVert * find_outer_flap_vert(BMFace &face)
bool ray_face_nearest_tri(const float3 &ray_start, const float3 &ray_normal, const float3 &t0, const float3 &t1, const float3 &t2, float *r_depth, float *dist_sq)
Definition pbvh.cc:1753
static BMVert * pbvh_bmesh_vert_create(BMesh &bm, MutableSpan< BMeshNode > nodes, MutableSpan< bool > node_changed, BMLog &bm_log, const BMVert *v1, const BMVert *v2, const int node_index, const float co[3], const float no[3], const int cd_vert_node_offset, const int cd_vert_mask_offset)
void bmesh_normals_update(Tree &pbvh, const IndexMask &nodes_to_update)
static int pbvh_bmesh_node_vert_use_count_at_most(MutableSpan< BMeshNode > nodes, const int cd_face_node_offset, BMeshNode *node, BMVert *v, const int count_max)
static Bounds< float3 > negative_bounds()
Definition pbvh.cc:58
static bool is_boundary_edge(const BMEdge &edge)
static void merge_edge_data(BMesh &bm, BMEdge &dst, const BMEdge &src)
bool bmesh_node_nearest_to_ray(BMeshNode &node, const float3 &ray_start, const float3 &ray_normal, float *r_depth, float *dist_sq, bool use_original)
static bool edge_queue_tri_in_sphere(const EdgeQueue *q, BMFace *f)
static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, BMesh &bm, MutableSpan< BMeshNode > nodes, MutableSpan< bool > node_changed, const int cd_vert_node_offset, const int cd_face_node_offset, BMLog &bm_log, BMEdge *e)
static BMFace * bm_face_exists_tri_from_loop_vert(BMLoop *l_radial_first, BMVert *v_opposite)
static void try_merge_flap_edge_data_before_dissolve(BMesh &bm, BMFace &face)
static std::optional< int > pbvh_bmesh_vert_other_node_find(const int cd_vert_node_offset, const int cd_face_node_offset, BMVert *v)
BLI_INLINE BMeshNode * pbvh_bmesh_node_from_vert(MutableSpan< BMeshNode > nodes, const int cd_vert_node_offset, const BMVert *key)
static bool pbvh_bmesh_node_limit_ensure(BMesh &bm, Vector< BMeshNode > &nodes, Vector< bool > &node_changed, const int cd_vert_node_offset, const int cd_face_node_offset, int node_index)
static void long_edge_queue_edge_add_recursive(EdgeQueueContext *eq_ctx, BMLoop *l_edge, BMLoop *l_end, const float len_sq, float limit_len)
static bool check_mask(EdgeQueueContext *eq_ctx, BMVert *v)
static void pbvh_bmesh_node_drop_orig(BMeshNode *node)
static void pbvh_bmesh_node_limit_ensure_fast(const MutableSpan< BMFace * > nodeinfo, const Span< Bounds< float3 > > face_bounds, FastNodeBuildInfo *node, MemArena *arena)
BLI_INLINE int pbvh_bmesh_node_index_from_vert(const int cd_vert_node_offset, const BMVert *key)
void update_bounds_bmesh(const BMesh &bm, Tree &pbvh)
Definition pbvh.cc:1170
bool bmesh_update_topology(BMesh &bm, Tree &pbvh, BMLog &bm_log, PBVHTopologyUpdateMode mode, float min_edge_len, float max_edge_len, const float center[3], const float view_normal[3], float radius, bool use_frontface, bool use_projected)
bool ray_face_intersection_tri(const float3 &ray_start, const IsectRayPrecalc *isect_precalc, const float3 &t0, const float3 &t1, const float3 &t2, float *depth)
Definition pbvh.cc:1679
BLI_INLINE BMeshNode * pbvh_bmesh_node_from_face(MutableSpan< BMeshNode > nodes, const int cd_face_node_offset, const BMFace *key)
static bool vert_in_face_adjacent_to_edge(BMVert &vert, BMEdge &edge)
static void short_edge_queue_create(EdgeQueueContext *eq_ctx, const float min_edge_len, MutableSpan< BMeshNode > nodes, const float center[3], const float view_normal[3], float radius, const bool use_frontface, const bool use_projected)
static float long_edge_queue_priority(const BMEdge &edge)
static void copy_edge_data(BMesh &bm, BMEdge &dst, BMEdge &src)
static void pbvh_bmesh_node_split(Vector< BMeshNode > &nodes, Vector< bool > &node_changed, const int cd_vert_node_offset, const int cd_face_node_offset, const Span< Bounds< float3 > > face_bounds, int node_index)
static bool is_boundary_vert(const BMVert &vertex)
static void long_edge_queue_face_add(EdgeQueueContext *eq_ctx, BMFace *f)
static float short_edge_queue_priority(const BMEdge &edge)
void store_bounds_orig(Tree &pbvh)
Definition pbvh.cc:1206
constexpr int leaf_limit
Definition pbvh_bmesh.cc:62
static void pbvh_bmesh_face_remove(MutableSpan< BMeshNode > nodes, MutableSpan< bool > node_changed, const int cd_vert_node_offset, const int cd_face_node_offset, BMLog &bm_log, BMFace *f)
static void long_edge_queue_edge_add(EdgeQueueContext *eq_ctx, BMEdge *e)
static Array< BMLoop * > pbvh_bmesh_edge_loops(BMEdge *e)
static void pbvh_bmesh_create_nodes_fast_recursive(Vector< BMeshNode > &nodes, const int cd_vert_node_offset, const int cd_face_node_offset, const Span< BMFace * > nodeinfo, const Span< Bounds< float3 > > face_bounds, FastNodeBuildInfo *node, int node_index)
static bool is_edge_adjacent_to_boundary(const BMEdge &edge)
static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx, const float min_edge_len, BMesh &bm, MutableSpan< BMeshNode > nodes, MutableSpan< bool > node_changed, const int cd_vert_node_offset, const int cd_face_node_offset, BMLog &bm_log)
static bool edge_queue_tri_in_circle(const EdgeQueue *q, BMFace *f)
Bounds< T > merge(const Bounds< T > &a, const Bounds< T > &b)
Definition BLI_bounds.hh:24
T midpoint(const T &a, const T &b)
void min_max(const T &value, T &min, T &max)
int dominant_axis(const VecBase< T, 3 > &a)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:95
VecBase< int32_t, 3 > int3
VecBase< float, 3 > float3
#define BM_LOOPS_OF_VERT_ITER_END
Definition pbvh_bmesh.cc:94
#define BM_FACES_OF_VERT_ITER_BEGIN(f_iter_, v_)
#define pbvh_bmesh_node_vert_use_count_is_equal(nodes, cd_face_node_offset, node, v, n)
#define BM_LOOPS_OF_VERT_ITER_BEGIN(l_iter_radial_, v_)
Definition pbvh_bmesh.cc:77
#define EVEN_GENERATION_SCALE
#define EVEN_EDGELEN_THRESHOLD
#define BM_FACES_OF_VERT_ITER_END
#define EDGE_QUEUE_DISABLE(e)
#define EDGE_QUEUE_ENABLE(e)
static CLG_LogRef LOG
Definition pbvh_bmesh.cc:30
#define EDGE_QUEUE_TEST(e)
#define min(a, b)
Definition sort.c:32
BMHeader head
BMVert * v1
BMVert * v2
BMHeader head
float no[3]
void * data
struct BMVert * v
struct BMEdge * e
struct BMLoop * radial_next
struct BMLoop * prev
struct BMFace * f
struct BMLoop * next
float co[3]
float no[3]
char elem_index_dirty
CustomData vdata
CustomData edata
CustomData pdata
int totface
Set< BMVert *, 0 > bm_unique_verts_
Set< BMVert *, 0 > bm_other_verts_
bool(* edge_queue_tri_in_range)(const EdgeQueue *q, BMFace *f)
uint8_t flag
Definition wm_window.cc:138