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