Blender V4.3
bmesh_region_match.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
22#include <cstring>
23
24#include "BLI_alloca.h"
25#include "BLI_ghash.h"
26#include "BLI_linklist.h"
27#include "BLI_linklist_stack.h"
28#include "BLI_listbase.h"
29#include "BLI_mempool.h"
30#include "MEM_guardedalloc.h"
31
32#include "bmesh.hh"
33
34#include "tools/bmesh_region_match.hh" /* own include */
35
36/* avoid re-creating ghash and pools for each search */
37#define USE_WALKER_REUSE
38
39/* do a first-pass id of all vertices,
40 * this avoids expensive checks on every item later on
41 * (works fine without, just slower) */
42#define USE_PIVOT_FASTMATCH
43
44/* otherwise use active element as pivot, for quick tests only */
45#define USE_PIVOT_SEARCH
46
47// #define DEBUG_TIME
48// #define DEBUG_PRINT
49
50#ifdef DEBUG_TIME
51# include "BLI_time.h"
52# include "BLI_time_utildefines.h"
53#endif
54
55#include "BLI_strict_flags.h" /* Keep last. */
56
57/* -------------------------------------------------------------------- */
61#define PRIME_VERT_INIT 100003
62
64
65struct UIDWalk {
66
67 /* List of faces we can step onto (UIDFaceStep's) */
69
70 /* Face & Vert UID's */
73
74 /* memory pool for LinkNode's */
76
77 /* memory pool for LinkBase's */
79
80 /* memory pool for UIDFaceStep's */
83
84 /* Optionally use face-tag to isolate search */
86
87 /* Increment for each pass added */
89
90 /* runtime vars, avoid re-creating each pass */
91 struct {
92 GHash *verts_uid; /* BMVert -> UID */
93 GSet *faces_step; /* BMFace */
94
95 GHash *faces_from_uid; /* UID -> UIDFaceStepItem */
96
100};
101
102/* stores a set of potential faces to step onto */
105
106 /* unsorted 'BMFace' */
108
109 /* faces sorted into 'UIDFaceStepItem' */
111};
112
113/* store face-lists with same HID. */
121
123{
124 if (uidwalk->use_face_isolate) {
126 }
127 return true;
128}
129
131{
132 void **ret;
133 ret = BLI_ghash_lookup_p(uidwalk->verts_uid, v);
134 if (ret) {
135 *r_uid = (UID_Int)(*ret);
136 return true;
137 }
138 return false;
139}
140
142{
143 void **ret;
144 ret = BLI_ghash_lookup_p(uidwalk->faces_uid, f);
145 if (ret) {
146 *r_uid = (UID_Int)(*ret);
147 return true;
148 }
149 return false;
150}
151
152static uint ghashutil_bmelem_indexhash(const void *key)
153{
154 const BMElem *ele = static_cast<const BMElem *>(key);
155 return uint(BM_elem_index_get(ele));
156}
157
158static bool ghashutil_bmelem_indexcmp(const void *a, const void *b)
159{
161 return (a != b);
162}
163
164static GHash *ghash_bmelem_new_ex(const char *info, const uint nentries_reserve)
165{
166 return BLI_ghash_new_ex(
168}
169
170static GSet *gset_bmelem_new_ex(const char *info, const uint nentries_reserve)
171{
172 return BLI_gset_new_ex(
174}
175
176static GHash *ghash_bmelem_new(const char *info)
177{
178 return ghash_bmelem_new_ex(info, 0);
179}
180
181static GSet *gset_bmelem_new(const char *info)
182{
183 return gset_bmelem_new_ex(info, 0);
184}
185
186static void bm_uidwalk_init(UIDWalk *uidwalk,
187 const uint faces_src_region_len,
188 const uint verts_src_region_len)
189{
191
192 uidwalk->verts_uid = ghash_bmelem_new_ex(__func__, verts_src_region_len);
193 uidwalk->faces_uid = ghash_bmelem_new_ex(__func__, faces_src_region_len);
194
195 uidwalk->cache.verts_uid = ghash_bmelem_new(__func__);
196 uidwalk->cache.faces_step = gset_bmelem_new(__func__);
197
198 /* works because 'int' ghash works for intptr_t too */
199 uidwalk->cache.faces_from_uid = BLI_ghash_int_new(__func__);
200
201 uidwalk->cache.rehash_store = nullptr;
202 uidwalk->cache.rehash_store_len = 0;
203
204 uidwalk->use_face_isolate = false;
205
206 /* smaller pool's for faster clearing */
207 uidwalk->link_pool = BLI_mempool_create(sizeof(LinkNode), 64, 64, BLI_MEMPOOL_NOP);
208 uidwalk->step_pool = BLI_mempool_create(sizeof(UIDFaceStep), 64, 64, BLI_MEMPOOL_NOP);
210
211 uidwalk->pass = 1;
212}
213
214static void bm_uidwalk_clear(UIDWalk *uidwalk)
215{
217
218 BLI_ghash_clear(uidwalk->verts_uid, nullptr, nullptr);
219 BLI_ghash_clear(uidwalk->faces_uid, nullptr, nullptr);
220
221 BLI_ghash_clear(uidwalk->cache.verts_uid, nullptr, nullptr);
222 BLI_gset_clear(uidwalk->cache.faces_step, nullptr);
223 BLI_ghash_clear(uidwalk->cache.faces_from_uid, nullptr, nullptr);
224
225 /* keep rehash_store as-is, for reuse */
226
227 uidwalk->use_face_isolate = false;
228
232
233 uidwalk->pass = 1;
234}
235
236static void bm_uidwalk_free(UIDWalk *uidwalk)
237{
244 BLI_ghash_free(uidwalk->verts_uid, nullptr, nullptr);
245 BLI_ghash_free(uidwalk->faces_uid, nullptr, nullptr);
246
247 /* cache */
248 BLI_ghash_free(uidwalk->cache.verts_uid, nullptr, nullptr);
249 BLI_gset_free(uidwalk->cache.faces_step, nullptr);
250 BLI_ghash_free(uidwalk->cache.faces_from_uid, nullptr, nullptr);
252
256}
257
259{
260#define PRIME_VERT_SMALL 7
261#define PRIME_VERT_MID 43
262#define PRIME_VERT_LARGE 1031
263
264#define PRIME_FACE_SMALL 13
265#define PRIME_FACE_MID 53
266
267 UID_Int uid;
268
269 uid = uidwalk->pass * PRIME_VERT_LARGE;
270
271 /* vert -> other */
272 {
273 uint tot = 0;
274 BMIter eiter;
275 BMEdge *e;
276 BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
277 BMVert *v_other = BM_edge_other_vert(e, v);
278 UID_Int uid_other;
279 if (bm_uidwalk_vert_lookup(uidwalk, v_other, &uid_other)) {
280 uid ^= (uid_other * PRIME_VERT_SMALL);
281 tot += 1;
282 }
283 }
284 uid ^= (tot * PRIME_VERT_MID);
285 }
286
287 /* faces */
288 {
289 uint tot = 0;
290 BMIter iter;
291 BMFace *f;
292
293 BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
294 UID_Int uid_other;
295 if (bm_uidwalk_face_lookup(uidwalk, f, &uid_other)) {
296 uid ^= (uid_other * PRIME_FACE_SMALL);
297 tot += 1;
298 }
299 }
300 uid ^= (tot * PRIME_FACE_MID);
301 }
302
303 return uid;
304
305#undef PRIME_VERT_SMALL
306#undef PRIME_VERT_MID
307#undef PRIME_VERT_LARGE
308
309#undef PRIME_FACE_SMALL
310#undef PRIME_FACE_MID
311}
312
314{
315#define PRIME_VERT_SMALL 11
316
317#define PRIME_FACE_SMALL 17
318#define PRIME_FACE_LARGE 1013
319
320 UID_Int uid;
321
322 uid = uidwalk->pass * uint(f->len) * PRIME_FACE_LARGE;
323
324 /* face-verts */
325 {
326 BMLoop *l_iter, *l_first;
327
328 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
329 do {
330 UID_Int uid_other;
331 if (bm_uidwalk_vert_lookup(uidwalk, l_iter->v, &uid_other)) {
332 uid ^= (uid_other * PRIME_VERT_SMALL);
333 }
334 } while ((l_iter = l_iter->next) != l_first);
335 }
336
337 /* face-faces (connected by edge) */
338 {
339 BMLoop *l_iter, *l_first;
340
341 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
342 do {
343 if (l_iter->radial_next != l_iter) {
344 BMLoop *l_iter_radial = l_iter->radial_next;
345 do {
346 UID_Int uid_other;
347 if (bm_uidwalk_face_lookup(uidwalk, l_iter_radial->f, &uid_other)) {
348 uid ^= (uid_other * PRIME_FACE_SMALL);
349 }
350 } while ((l_iter_radial = l_iter_radial->radial_next) != l_iter);
351 }
352 } while ((l_iter = l_iter->next) != l_first);
353 }
354
355 return uid;
356
357#undef PRIME_VERT_SMALL
358
359#undef PRIME_FACE_SMALL
360#undef PRIME_FACE_LARGE
361}
362
363static void bm_uidwalk_rehash_reserve(UIDWalk *uidwalk, uint rehash_store_len_new)
364{
365 if (UNLIKELY(rehash_store_len_new > uidwalk->cache.rehash_store_len)) {
366 /* Avoid re-allocations. */
367 rehash_store_len_new *= 2;
368 uidwalk->cache.rehash_store = static_cast<UID_Int *>(MEM_reallocN(
369 uidwalk->cache.rehash_store, rehash_store_len_new * sizeof(*uidwalk->cache.rehash_store)));
370 uidwalk->cache.rehash_store_len = rehash_store_len_new;
371 }
372}
373
377static void bm_uidwalk_rehash(UIDWalk *uidwalk)
378{
379 GHashIterator gh_iter;
380 UID_Int *uid_store;
381 uint i;
382
383 uint rehash_store_len_new = std::max(BLI_ghash_len(uidwalk->verts_uid),
384 BLI_ghash_len(uidwalk->faces_uid));
385
386 bm_uidwalk_rehash_reserve(uidwalk, rehash_store_len_new);
387 uid_store = uidwalk->cache.rehash_store;
388
389 /* verts */
390 i = 0;
391 GHASH_ITER (gh_iter, uidwalk->verts_uid) {
392 BMVert *v = static_cast<BMVert *>(BLI_ghashIterator_getKey(&gh_iter));
393 uid_store[i++] = bm_uidwalk_calc_vert_uid(uidwalk, v);
394 }
395 i = 0;
396 GHASH_ITER (gh_iter, uidwalk->verts_uid) {
397 void **uid_p = BLI_ghashIterator_getValue_p(&gh_iter);
398 *((UID_Int *)uid_p) = uid_store[i++];
399 }
400
401 /* faces */
402 i = 0;
403 GHASH_ITER (gh_iter, uidwalk->faces_uid) {
404 BMFace *f = static_cast<BMFace *>(BLI_ghashIterator_getKey(&gh_iter));
405 uid_store[i++] = bm_uidwalk_calc_face_uid(uidwalk, f);
406 }
407 i = 0;
408 GHASH_ITER (gh_iter, uidwalk->faces_uid) {
409 void **uid_p = BLI_ghashIterator_getValue_p(&gh_iter);
410 *((UID_Int *)uid_p) = uid_store[i++];
411 }
412}
413
415 LinkNode *faces,
416 const uint faces_len,
417 const bool is_init)
418{
419 UID_Int *uid_store;
420 LinkNode *f_link;
421 uint i;
422
423 bm_uidwalk_rehash_reserve(uidwalk, faces_len);
424 uid_store = uidwalk->cache.rehash_store;
425
426 i = 0;
427 for (f_link = faces; f_link; f_link = f_link->next) {
428 BMFace *f = static_cast<BMFace *>(f_link->link);
429 uid_store[i++] = bm_uidwalk_calc_face_uid(uidwalk, f);
430 }
431
432 i = 0;
433 if (is_init) {
434 for (f_link = faces; f_link; f_link = f_link->next) {
435 BMFace *f = static_cast<BMFace *>(f_link->link);
436 BLI_ghash_insert(uidwalk->faces_uid, f, (void *)uid_store[i++]);
437 }
438 }
439 else {
440 for (f_link = faces; f_link; f_link = f_link->next) {
441 BMFace *f = static_cast<BMFace *>(f_link->link);
442 void **uid_p = BLI_ghash_lookup_p(uidwalk->faces_uid, f);
443 *((UID_Int *)uid_p) = uid_store[i++];
444 }
445 }
446}
447
448static bool bm_vert_is_uid_connect(UIDWalk *uidwalk, BMVert *v)
449{
450 BMIter eiter;
451 BMEdge *e;
452
453 BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
454 BMVert *v_other = BM_edge_other_vert(e, v);
455 if (BLI_ghash_haskey(uidwalk->verts_uid, v_other)) {
456 return true;
457 }
458 }
459 return false;
460}
461
462static void bm_uidwalk_pass_add(UIDWalk *uidwalk, LinkNode *faces_pass, const uint faces_pass_len)
463{
464 GHashIterator gh_iter;
465 GHash *verts_uid_pass;
466 GSet *faces_step_next;
467 LinkNode *f_link;
468
469 UIDFaceStep *fstep;
470
471 BLI_assert(faces_pass_len == uint(BLI_linklist_count(faces_pass)));
472
473 /* rehash faces now all their verts have been added */
474 bm_uidwalk_rehash_facelinks(uidwalk, faces_pass, faces_pass_len, true);
475
476 /* create verts_new */
477 verts_uid_pass = uidwalk->cache.verts_uid;
478 faces_step_next = uidwalk->cache.faces_step;
479
480 BLI_assert(BLI_ghash_len(verts_uid_pass) == 0);
481 BLI_assert(BLI_gset_len(faces_step_next) == 0);
482
483 /* Add the face_step data from connected faces, creating new passes */
484 fstep = static_cast<UIDFaceStep *>(BLI_mempool_alloc(uidwalk->step_pool));
485 BLI_addhead(&uidwalk->faces_step, fstep);
486 fstep->faces = nullptr;
487 BLI_listbase_clear(&fstep->items);
488
489 for (f_link = faces_pass; f_link; f_link = f_link->next) {
490 BMFace *f = static_cast<BMFace *>(f_link->link);
491 BMLoop *l_iter, *l_first;
492
493 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
494 do {
495 /* fill verts_new */
496 void **val_p;
497 if (!BLI_ghash_haskey(uidwalk->verts_uid, l_iter->v) &&
498 !BLI_ghash_ensure_p(verts_uid_pass, l_iter->v, &val_p) &&
499 (bm_vert_is_uid_connect(uidwalk, l_iter->v) == true))
500 {
501 const UID_Int uid = bm_uidwalk_calc_vert_uid(uidwalk, l_iter->v);
502 *val_p = (void *)uid;
503 }
504
505 /* fill faces_step_next */
506 if (l_iter->radial_next != l_iter) {
507 BMLoop *l_iter_radial = l_iter->radial_next;
508 do {
509 if (!BLI_ghash_haskey(uidwalk->faces_uid, l_iter_radial->f) &&
510 !BLI_gset_haskey(faces_step_next, l_iter_radial->f) &&
511 bm_uidwalk_face_test(uidwalk, l_iter_radial->f))
512 {
513 BLI_gset_insert(faces_step_next, l_iter_radial->f);
514
515 /* add to fstep */
516 BLI_linklist_prepend_pool(&fstep->faces, l_iter_radial->f, uidwalk->link_pool);
517 }
518 } while ((l_iter_radial = l_iter_radial->radial_next) != l_iter);
519 }
520 } while ((l_iter = l_iter->next) != l_first);
521 }
522
523 /* faces_uid.update(verts_new) */
524 GHASH_ITER (gh_iter, verts_uid_pass) {
525 BMVert *v = static_cast<BMVert *>(BLI_ghashIterator_getKey(&gh_iter));
526 void *uid_p = BLI_ghashIterator_getValue(&gh_iter);
527 BLI_ghash_insert(uidwalk->verts_uid, v, uid_p);
528 }
529
530 /* rehash faces now all their verts have been added */
531 bm_uidwalk_rehash_facelinks(uidwalk, faces_pass, faces_pass_len, false);
532
533 uidwalk->pass += 1;
534
535 BLI_ghash_clear(uidwalk->cache.verts_uid, nullptr, nullptr);
536 BLI_gset_clear(uidwalk->cache.faces_step, nullptr);
537}
538
539static int bm_face_len_cmp(const void *v1, const void *v2)
540{
541 const BMFace *f1 = *((BMFace **)v1);
542 const BMFace *f2 = *((BMFace **)v2);
543
544 if (f1->len > f2->len) {
545 return 1;
546 }
547 if (f1->len < f2->len) {
548 return -1;
549 }
550 return 0;
551}
552
554{
555 BMLoop *l_iter = e->l;
556 uint f_arr_len = uint(BM_edge_face_count(e));
557 BMFace **f_arr = BLI_array_alloca(f_arr, f_arr_len);
558 uint fstep_num = 0, i = 0;
559
560 do {
561 BMFace *f = l_iter->f;
562 if (bm_uidwalk_face_test(uidwalk, f)) {
563 f_arr[i++] = f;
564 }
565 } while ((l_iter = l_iter->radial_next) != e->l);
566 BLI_assert(i <= f_arr_len);
567 f_arr_len = i;
568
569 qsort(f_arr, f_arr_len, sizeof(*f_arr), bm_face_len_cmp);
570
571 /* start us off! */
572 {
573 const UID_Int uid = PRIME_VERT_INIT;
574 BLI_ghash_insert(uidwalk->verts_uid, e->v1, (void *)uid);
575 BLI_ghash_insert(uidwalk->verts_uid, e->v2, (void *)uid);
576 }
577
578 /* turning an array into LinkNode's seems odd,
579 * but this is just for initialization,
580 * elsewhere using LinkNode's makes more sense */
581 for (i = 0; i < f_arr_len;) {
582 LinkNode *faces_pass = nullptr;
583 const uint i_init = i;
584 const int f_len = f_arr[i]->len;
585
586 do {
587 BLI_linklist_prepend_pool(&faces_pass, f_arr[i++], uidwalk->link_pool);
588 } while (i < f_arr_len && (f_len == f_arr[i]->len));
589
590 bm_uidwalk_pass_add(uidwalk, faces_pass, i - i_init);
591 BLI_linklist_free_pool(faces_pass, nullptr, uidwalk->link_pool);
592 fstep_num += 1;
593 }
594
595 return fstep_num;
596}
597
598#undef PRIME_VERT_INIT
599
602/* -------------------------------------------------------------------- */
606static int facestep_sort(const void *a, const void *b)
607{
608 const UIDFaceStepItem *fstep_a = static_cast<const UIDFaceStepItem *>(a);
609 const UIDFaceStepItem *fstep_b = static_cast<const UIDFaceStepItem *>(b);
610 return (fstep_a->uid > fstep_b->uid) ? 1 : 0;
611}
612
617static bool bm_uidwalk_facestep_begin(UIDWalk *uidwalk, UIDFaceStep *fstep)
618{
619 LinkNode *f_link, *f_link_next, **f_link_prev_p;
620 bool ok = false;
621
624
625 f_link_prev_p = &fstep->faces;
626 for (f_link = fstep->faces; f_link; f_link = f_link_next) {
627 BMFace *f = static_cast<BMFace *>(f_link->link);
628 f_link_next = f_link->next;
629
630 /* possible another pass added this face already, free in that case */
631 if (!BLI_ghash_haskey(uidwalk->faces_uid, f)) {
632 const UID_Int uid = bm_uidwalk_calc_face_uid(uidwalk, f);
633 UIDFaceStepItem *fstep_item;
634 void **val_p;
635
636 ok = true;
637
638 if (BLI_ghash_ensure_p(uidwalk->cache.faces_from_uid, (void *)uid, &val_p)) {
639 fstep_item = static_cast<UIDFaceStepItem *>(*val_p);
640 }
641 else {
642 fstep_item = static_cast<UIDFaceStepItem *>(*val_p = BLI_mempool_alloc(
643 uidwalk->step_pool_items));
644
645 /* add to start, so its handled on the next round of passes */
646 BLI_addhead(&fstep->items, fstep_item);
647 fstep_item->uid = uid;
648 fstep_item->list = nullptr;
649 fstep_item->list_len = 0;
650 }
651
652 BLI_linklist_prepend_pool(&fstep_item->list, f, uidwalk->link_pool);
653 fstep_item->list_len += 1;
654
655 f_link_prev_p = &f_link->next;
656 }
657 else {
658 *f_link_prev_p = f_link->next;
659 BLI_mempool_free(uidwalk->link_pool, f_link);
660 }
661 }
662
663 BLI_ghash_clear(uidwalk->cache.faces_from_uid, nullptr, nullptr);
664
666
667 return ok;
668}
669
673static void bm_uidwalk_facestep_end(UIDWalk *uidwalk, UIDFaceStep *fstep)
674{
675 while (UIDFaceStepItem *fstep_item = static_cast<UIDFaceStepItem *>(BLI_pophead(&fstep->items)))
676 {
677 BLI_mempool_free(uidwalk->step_pool_items, fstep_item);
678 }
679}
680
681static void bm_uidwalk_facestep_free(UIDWalk *uidwalk, UIDFaceStep *fstep)
682{
683 LinkNode *f_link, *f_link_next;
684
686
687 for (f_link = fstep->faces; f_link; f_link = f_link_next) {
688 f_link_next = f_link->next;
689 BLI_mempool_free(uidwalk->link_pool, f_link);
690 }
691
692 BLI_remlink(&uidwalk->faces_step, fstep);
693 BLI_mempool_free(uidwalk->step_pool, fstep);
694}
695
698/* -------------------------------------------------------------------- */
699/* Main Loop to match up regions */
700
706#ifdef USE_WALKER_REUSE
707 UIDWalk *w_src,
708 UIDWalk *w_dst,
709#endif
710 BMEdge *e_src,
711 BMEdge *e_dst,
712 const uint faces_src_region_len,
713 const uint verts_src_region_len,
714 uint *r_faces_result_len)
715{
716#ifndef USE_WALKER_REUSE
717 UIDWalk w_src_, w_dst_;
718 UIDWalk *w_src = &w_src_, *w_dst = &w_dst_;
719#endif
720 BMFace **faces_result = nullptr;
721 bool found = false;
722
723 BLI_assert(e_src != e_dst);
724
725#ifndef USE_WALKER_REUSE
726 bm_uidwalk_init(w_src, faces_src_region_len, verts_src_region_len);
727 bm_uidwalk_init(w_dst, faces_src_region_len, verts_src_region_len);
728#endif
729
730 w_src->use_face_isolate = true;
731
732 /* setup the initial state */
733 if (UNLIKELY(bm_uidwalk_init_from_edge(w_src, e_src) != bm_uidwalk_init_from_edge(w_dst, e_dst)))
734 {
735 /* should never happen, if verts passed are compatible, but to be safe... */
736 goto finally;
737 }
738
739 bm_uidwalk_rehash_reserve(w_src, std::max(faces_src_region_len, verts_src_region_len));
740 bm_uidwalk_rehash_reserve(w_dst, std::max(faces_src_region_len, verts_src_region_len));
741
742 while (true) {
743 bool ok = false;
744
745 UIDFaceStep *fstep_src = static_cast<UIDFaceStep *>(w_src->faces_step.first);
746 UIDFaceStep *fstep_dst = static_cast<UIDFaceStep *>(w_dst->faces_step.first);
747
748 BLI_assert(BLI_listbase_count(&w_src->faces_step) == BLI_listbase_count(&w_dst->faces_step));
749
750 while (fstep_src) {
751
752 /* even if the destination has faces,
753 * it's not important, since the source doesn't, free and move-on. */
754 if (fstep_src->faces == nullptr) {
755 UIDFaceStep *fstep_src_next = fstep_src->next;
756 UIDFaceStep *fstep_dst_next = fstep_dst->next;
757 bm_uidwalk_facestep_free(w_src, fstep_src);
758 bm_uidwalk_facestep_free(w_dst, fstep_dst);
759 fstep_src = fstep_src_next;
760 fstep_dst = fstep_dst_next;
761 continue;
762 }
763
764 if (bm_uidwalk_facestep_begin(w_src, fstep_src) &&
765 bm_uidwalk_facestep_begin(w_dst, fstep_dst))
766 {
767 /* Step over face-lists with matching UID's
768 * both lists are sorted, so no need for lookups.
769 * The data is created on 'begin' and cleared on 'end' */
770 UIDFaceStepItem *fstep_item_src;
771 UIDFaceStepItem *fstep_item_dst;
772 for (fstep_item_src = static_cast<UIDFaceStepItem *>(fstep_src->items.first),
773 fstep_item_dst = static_cast<UIDFaceStepItem *>(fstep_dst->items.first);
774 fstep_item_src && fstep_item_dst;
775 fstep_item_src = fstep_item_src->next, fstep_item_dst = fstep_item_dst->next)
776 {
777 while ((fstep_item_dst != nullptr) && (fstep_item_dst->uid < fstep_item_src->uid)) {
778 fstep_item_dst = fstep_item_dst->next;
779 }
780
781 if ((fstep_item_dst == nullptr) || (fstep_item_src->uid != fstep_item_dst->uid) ||
782 (fstep_item_src->list_len > fstep_item_dst->list_len))
783 {
784 /* if the target walker has less than the source
785 * then the islands don't match, bail early */
786 ok = false;
787 break;
788 }
789
790 if (fstep_item_src->list_len == fstep_item_dst->list_len) {
791 /* found a match */
792 bm_uidwalk_pass_add(w_src, fstep_item_src->list, fstep_item_src->list_len);
793 bm_uidwalk_pass_add(w_dst, fstep_item_dst->list, fstep_item_dst->list_len);
794
795 BLI_linklist_free_pool(fstep_item_src->list, nullptr, w_src->link_pool);
796 BLI_linklist_free_pool(fstep_item_dst->list, nullptr, w_dst->link_pool);
797
798 fstep_item_src->list = nullptr;
799 fstep_item_src->list_len = 0;
800
801 fstep_item_dst->list = nullptr;
802 fstep_item_dst->list_len = 0;
803
804 ok = true;
805 }
806 }
807 }
808
809 bm_uidwalk_facestep_end(w_src, fstep_src);
810 bm_uidwalk_facestep_end(w_dst, fstep_dst);
811
812 /* lock-step */
813 fstep_src = fstep_src->next;
814 fstep_dst = fstep_dst->next;
815 }
816
817 if (!ok) {
818 break;
819 }
820
821 found = (BLI_ghash_len(w_dst->faces_uid) == faces_src_region_len);
822 if (found) {
823 break;
824 }
825
826 /* Expensive! but some cases fails without.
827 * (also faster in other cases since it can rule-out invalid regions) */
828 bm_uidwalk_rehash(w_src);
829 bm_uidwalk_rehash(w_dst);
830 }
831
832 if (found) {
833 GHashIterator gh_iter;
834 const uint faces_result_len = BLI_ghash_len(w_dst->faces_uid);
835 uint i;
836
837 faces_result = static_cast<BMFace **>(
838 MEM_mallocN(sizeof(*faces_result) * (faces_result_len + 1), __func__));
839 GHASH_ITER_INDEX (gh_iter, w_dst->faces_uid, i) {
840 BMFace *f = static_cast<BMFace *>(BLI_ghashIterator_getKey(&gh_iter));
841 faces_result[i] = f;
842 }
843 faces_result[faces_result_len] = nullptr;
844 *r_faces_result_len = faces_result_len;
845 }
846 else {
847 *r_faces_result_len = 0;
848 }
849
850finally:
851
852#ifdef USE_WALKER_REUSE
853 bm_uidwalk_clear(w_src);
854 bm_uidwalk_clear(w_dst);
855#else
856 bm_uidwalk_free(w_src);
857 bm_uidwalk_free(w_dst);
858#endif
859
860 return faces_result;
861}
862
866static void bm_face_array_visit(BMFace **faces,
867 const uint faces_len,
868 uint *r_verts_len,
869 bool visit_faces)
870{
871 uint verts_len = 0;
872 uint i;
873 for (i = 0; i < faces_len; i++) {
874 BMFace *f = faces[i];
875 BMLoop *l_iter, *l_first;
876 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
877 do {
878 if (r_verts_len) {
879 if (!BM_elem_flag_test(l_iter->v, BM_ELEM_TAG)) {
880 verts_len += 1;
881 }
882 }
883
886 } while ((l_iter = l_iter->next) != l_first);
887
888 if (visit_faces) {
890 }
891 }
892
893 if (r_verts_len) {
894 *r_verts_len = verts_len;
895 }
896}
897
898#ifdef USE_PIVOT_SEARCH
899
900/* -------------------------------------------------------------------- */
904/* signed user id */
906
908{
909 return (a < 0) ? -a : a;
910}
911
913{
914 if (e->l->radial_next != e->l) {
915 BMLoop *l_iter = e->l;
916 do {
917 if (!BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) {
918 return true;
919 }
920 } while ((l_iter = l_iter->radial_next) != e->l);
921 return false;
922 }
923 /* boundary */
924 return true;
925}
926
928 BMEdge *e_test,
929 BMEdge **r_e_pivot_best,
930 SUID_Int e_pivot_best_id[2])
931{
932 SUID_Int e_pivot_test_id[2];
933
934 e_pivot_test_id[0] = (SUID_Int)BLI_ghash_lookup(gh, e_test->v1);
935 e_pivot_test_id[1] = (SUID_Int)BLI_ghash_lookup(gh, e_test->v2);
936 if (e_pivot_test_id[0] > e_pivot_test_id[1]) {
937 std::swap(e_pivot_test_id[0], e_pivot_test_id[1]);
938 }
939
940 if ((*r_e_pivot_best == nullptr) ||
941 ((e_pivot_best_id[0] != e_pivot_test_id[0]) ? (e_pivot_best_id[0] < e_pivot_test_id[0]) :
942 (e_pivot_best_id[1] < e_pivot_test_id[1])))
943 {
944 e_pivot_best_id[0] = e_pivot_test_id[0];
945 e_pivot_best_id[1] = e_pivot_test_id[1];
946
947 /* both verts are from the same pass, record this! */
948 *r_e_pivot_best = e_test;
949 }
950}
951
952/* quick id from a boundary vertex */
954{
955# define PRIME_VERT_SMALL_A 7
956# define PRIME_VERT_SMALL_B 13
957# define PRIME_VERT_MID_A 103
958# define PRIME_VERT_MID_B 131
959
960 int tot = 0;
961 BMIter iter;
962 BMLoop *l;
964
965 BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
966 const bool is_boundary_vert = (bm_edge_is_region_boundary(l->e) ||
968 id ^= l->f->len * (is_boundary_vert ? PRIME_VERT_SMALL_A : PRIME_VERT_SMALL_B);
969 tot += 1;
970 }
971
972 id ^= (tot * PRIME_VERT_MID_B);
973
974 return id ? abs_intptr(id) : 1;
975
976# undef PRIME_VERT_SMALL_A
977# undef PRIME_VERT_SMALL_B
978# undef PRIME_VERT_MID_A
979# undef PRIME_VERT_MID_B
980}
981
986{
987 BMIter eiter;
988 BMEdge *e;
989 SUID_Int tot = 0;
990 SUID_Int v_sum_face_len = 0;
991 SUID_Int v_sum_id = 0;
992 SUID_Int id;
993 SUID_Int id_min = INTPTR_MIN + 1;
994
995# define PRIME_VERT_MID_A 23
996# define PRIME_VERT_MID_B 31
997
998 BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
1000 BMVert *v_other = BM_edge_other_vert(e, v);
1001 if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
1002 /* non-zero values aren't allowed... so no need to check haskey */
1003 SUID_Int v_other_id = (SUID_Int)BLI_ghash_lookup(gh, v_other);
1004 if (v_other_id > 0) {
1005 v_sum_id += v_other_id;
1006 tot += 1;
1007
1008 /* face-count */
1009 {
1010 BMLoop *l_iter = e->l;
1011 do {
1012 if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) {
1013 v_sum_face_len += l_iter->f->len;
1014 }
1015 } while ((l_iter = l_iter->radial_next) != e->l);
1016 }
1017 }
1018 }
1019 }
1020 }
1021
1022 id = (tot * PRIME_VERT_MID_A);
1023 id ^= (v_sum_face_len * PRIME_VERT_MID_B);
1024 id ^= v_sum_id;
1025
1026 /* disallow 0 & min (since it can't be flipped) */
1027 id = (UNLIKELY(id == 0) ? 1 : UNLIKELY(id < id_min) ? id_min : id);
1028
1029 return abs_intptr(id);
1030
1031# undef PRIME_VERT_MID_A
1032# undef PRIME_VERT_MID_B
1033}
1034
1043 uint faces_region_len,
1044 uint verts_region_len,
1045 uint *r_depth)
1046{
1047 /* NOTE: keep deterministic where possible (geometry order independent)
1048 * this function assumed all visit faces & edges are tagged */
1049
1050 BLI_LINKSTACK_DECLARE(vert_queue_prev, BMVert *);
1051 BLI_LINKSTACK_DECLARE(vert_queue_next, BMVert *);
1052
1053 GHash *gh = BLI_ghash_ptr_new(__func__);
1054 uint i;
1055
1056 BMEdge *e_pivot = nullptr;
1057 /* pick any non-boundary edge (not ideal) */
1058 BMEdge *e_pivot_fallback = nullptr;
1059
1060 SUID_Int pass = 0;
1061
1062 /* total verts in 'gs' we have visited - aka - not v_init_none */
1063 uint vert_queue_used = 0;
1064
1065 BLI_LINKSTACK_INIT(vert_queue_prev);
1066 BLI_LINKSTACK_INIT(vert_queue_next);
1067
1068 /* face-verts */
1069 for (i = 0; i < faces_region_len; i++) {
1070 BMFace *f = faces_region[i];
1071
1072 BMLoop *l_iter, *l_first;
1073 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1074 do {
1075 BMEdge *e = l_iter->e;
1077 uint j;
1078 for (j = 0; j < 2; j++) {
1079 void **val_p;
1080 if (!BLI_ghash_ensure_p(gh, (&e->v1)[j], &val_p)) {
1081 SUID_Int v_id = bm_face_region_vert_boundary_id((&e->v1)[j]);
1082 *val_p = (void *)v_id;
1083 BLI_LINKSTACK_PUSH(vert_queue_prev, (&e->v1)[j]);
1084 vert_queue_used += 1;
1085 }
1086 }
1087 }
1088 else {
1089 /* Use in case (depth == 0), no interior verts. */
1090 e_pivot_fallback = e;
1091 }
1092 } while ((l_iter = l_iter->next) != l_first);
1093 }
1094
1095 while (BLI_LINKSTACK_SIZE(vert_queue_prev)) {
1096 BMVert *v;
1097 while ((v = BLI_LINKSTACK_POP(vert_queue_prev))) {
1098 BMIter eiter;
1099 BMEdge *e;
1102 BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
1104 BMVert *v_other = BM_edge_other_vert(e, v);
1105 if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
1106 void **val_p;
1107 if (!BLI_ghash_ensure_p(gh, v_other, &val_p)) {
1108 /* add as negative, so we know not to read from them this pass */
1109 const SUID_Int v_id_other = -bm_face_region_vert_pass_id(gh, v_other);
1110 *val_p = (void *)v_id_other;
1111 BLI_LINKSTACK_PUSH(vert_queue_next, v_other);
1112 vert_queue_used += 1;
1113 }
1114 }
1115 }
1116 }
1117 }
1118
1119 /* flip all the newly added hashes to positive */
1120 {
1121 LinkNode *v_link;
1122 for (v_link = vert_queue_next; v_link; v_link = v_link->next) {
1123 SUID_Int *v_id_p = (SUID_Int *)BLI_ghash_lookup_p(gh, v_link->link);
1124 *v_id_p = -(*v_id_p);
1125 BLI_assert(*v_id_p > 0);
1126 }
1127 }
1128
1129 BLI_LINKSTACK_SWAP(vert_queue_prev, vert_queue_next);
1130 pass += 1;
1131
1132 if (vert_queue_used == verts_region_len) {
1133 break;
1134 }
1135 }
1136
1137 if (BLI_LINKSTACK_SIZE(vert_queue_prev) >= 2) {
1138 /* common case - we managed to find some interior verts */
1139 LinkNode *v_link;
1140 BMEdge *e_pivot_best = nullptr;
1141 SUID_Int e_pivot_best_id[2] = {0, 0};
1142
1143 /* temp untag, so we can quickly know what other verts are in this last pass */
1144 for (v_link = vert_queue_prev; v_link; v_link = v_link->next) {
1145 BMVert *v = static_cast<BMVert *>(v_link->link);
1147 }
1148
1149 /* restore correct tagging */
1150 for (v_link = vert_queue_prev; v_link; v_link = v_link->next) {
1151 BMIter eiter;
1152 BMEdge *e_test;
1153
1154 BMVert *v = static_cast<BMVert *>(v_link->link);
1156
1157 BM_ITER_ELEM (e_test, &eiter, v, BM_EDGES_OF_VERT) {
1158 if (BM_elem_flag_test(e_test, BM_ELEM_TAG)) {
1159 BMVert *v_other = BM_edge_other_vert(e_test, v);
1160 if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == false) {
1161 bm_face_region_pivot_edge_use_best(gh, e_test, &e_pivot_best, e_pivot_best_id);
1162 }
1163 }
1164 }
1165 }
1166
1167 e_pivot = e_pivot_best;
1168 }
1169
1170 if ((e_pivot == nullptr) && BLI_LINKSTACK_SIZE(vert_queue_prev)) {
1171 /* find the best single edge */
1172 BMEdge *e_pivot_best = nullptr;
1173 SUID_Int e_pivot_best_id[2] = {0, 0};
1174
1175 LinkNode *v_link;
1176
1177 /* reduce a pass since we're having to step into a previous passes vert,
1178 * and will be closer to the boundary */
1179 BLI_assert(pass != 0);
1180 pass -= 1;
1181
1182 for (v_link = vert_queue_prev; v_link; v_link = v_link->next) {
1183 BMVert *v = static_cast<BMVert *>(v_link->link);
1184
1185 BMIter eiter;
1186 BMEdge *e_test;
1187 BM_ITER_ELEM (e_test, &eiter, v, BM_EDGES_OF_VERT) {
1188 if (BM_elem_flag_test(e_test, BM_ELEM_TAG)) {
1189 BMVert *v_other = BM_edge_other_vert(e_test, v);
1190 if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
1191 bm_face_region_pivot_edge_use_best(gh, e_test, &e_pivot_best, e_pivot_best_id);
1192 }
1193 }
1194 }
1195 }
1196
1197 e_pivot = e_pivot_best;
1198 }
1199
1200 BLI_LINKSTACK_FREE(vert_queue_prev);
1201 BLI_LINKSTACK_FREE(vert_queue_next);
1202
1203 BLI_ghash_free(gh, nullptr, nullptr);
1204
1205 if (e_pivot == nullptr) {
1206# ifdef DEBUG_PRINT
1207 printf("%s: using fallback edge!\n", __func__);
1208# endif
1209 e_pivot = e_pivot_fallback;
1210 pass = 0;
1211 }
1212
1213 *r_depth = uint(pass);
1214
1215 return e_pivot;
1216}
1217
1220#endif /* USE_PIVOT_SEARCH */
1221
1222/* Quick UID pass - identify candidates */
1223
1224#ifdef USE_PIVOT_FASTMATCH
1225
1226/* -------------------------------------------------------------------- */
1231
1233{
1234 BMIter eiter;
1235 BMEdge *e;
1236 UIDFashMatch e_num = 0, f_num = 0, l_num = 0;
1237
1238# define PRIME_EDGE 7
1239# define PRIME_FACE 31
1240# define PRIME_LOOP 61
1241
1242 BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
1243 if (!BM_edge_is_wire(e)) {
1244 BMLoop *l_iter = e->l;
1245 e_num += 1;
1246 do {
1247 f_num += 1;
1248 l_num += uint(l_iter->f->len);
1249 } while ((l_iter = l_iter->radial_next) != e->l);
1250 }
1251 }
1252
1253 return ((e_num * PRIME_EDGE) ^ (f_num * PRIME_FACE) * (l_num * PRIME_LOOP));
1254
1255# undef PRIME_EDGE
1256# undef PRIME_FACE
1257# undef PRIME_LOOP
1258}
1259
1261{
1262 UIDFashMatch *id_prev;
1263 UIDFashMatch *id_curr;
1264 uint pass, i;
1265 BMVert *v;
1266 BMIter iter;
1267
1268 id_prev = static_cast<UIDFashMatch *>(
1269 MEM_mallocN(sizeof(*id_prev) * uint(bm->totvert), __func__));
1270 id_curr = static_cast<UIDFashMatch *>(
1271 MEM_mallocN(sizeof(*id_curr) * uint(bm->totvert), __func__));
1272
1273 BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
1274 id_prev[i] = bm_vert_fasthash_single(v);
1275 }
1276
1277 for (pass = 0; pass < depth; pass++) {
1278 BMEdge *e;
1279
1280 memcpy(id_curr, id_prev, sizeof(*id_prev) * uint(bm->totvert));
1281
1282 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
1283 if (BM_edge_is_wire(e) == false) {
1284 const int i1 = BM_elem_index_get(e->v1);
1285 const int i2 = BM_elem_index_get(e->v2);
1286
1287 id_curr[i1] += id_prev[i2];
1288 id_curr[i2] += id_prev[i1];
1289 }
1290 }
1291 }
1292 MEM_freeN(id_prev);
1293
1294 return id_curr;
1295}
1296
1298 const BMEdge *e,
1299 UIDFashMatch e_fm[2])
1300{
1301 e_fm[0] = fm[BM_elem_index_get(e->v1)];
1302 e_fm[1] = fm[BM_elem_index_get(e->v2)];
1303
1304 if (e_fm[0] > e_fm[1]) {
1305 std::swap(e_fm[0], e_fm[1]);
1306 }
1307}
1308
1309static bool bm_vert_fasthash_edge_is_match(UIDFashMatch *fm, const BMEdge *e_a, const BMEdge *e_b)
1310{
1311 UIDFashMatch e_a_fm[2];
1312 UIDFashMatch e_b_fm[2];
1313
1314 bm_vert_fasthash_edge_order(fm, e_a, e_a_fm);
1315 bm_vert_fasthash_edge_order(fm, e_b, e_b_fm);
1316
1317 return ((e_a_fm[0] == e_b_fm[0]) && (e_a_fm[1] == e_b_fm[1]));
1318}
1319
1321{
1322 MEM_freeN(fm);
1323}
1324
1327#endif /* USE_PIVOT_FASTMATCH */
1328
1330 BMFace **faces_region,
1331 uint faces_region_len,
1332 ListBase *r_face_regions)
1333{
1334 BMEdge *e_src;
1335 BMEdge *e_dst;
1336 BMIter iter;
1337 uint verts_region_len = 0;
1338 uint faces_result_len = 0;
1339 /* number of steps from e_src to a boundary vert */
1340 uint depth;
1341
1342#ifdef USE_WALKER_REUSE
1343 UIDWalk w_src, w_dst;
1344#endif
1345
1346#ifdef USE_PIVOT_FASTMATCH
1347 UIDFashMatch *fm;
1348#endif
1349
1350#ifdef DEBUG_PRINT
1351 int search_num = 0;
1352#endif
1353
1354#ifdef DEBUG_TIME
1355 TIMEIT_START(region_match);
1356#endif
1357
1358 /* initialize visited verts */
1360 bm_face_array_visit(faces_region, faces_region_len, &verts_region_len, true);
1361
1362 /* needed for 'ghashutil_bmelem_indexhash' */
1364
1365#ifdef USE_PIVOT_SEARCH
1366 e_src = bm_face_region_pivot_edge_find(faces_region, faces_region_len, verts_region_len, &depth);
1367
1368/* see which edge is added */
1369# if 0
1371 if (e_src) {
1373 }
1374# endif
1375
1376#else
1377 /* quick test only! */
1378 e_src = BM_mesh_active_edge_get(bm);
1379#endif
1380
1381 if (e_src == nullptr) {
1382#ifdef DEBUG_PRINT
1383 printf("Couldn't find 'e_src'");
1384#endif
1385 return 0;
1386 }
1387
1388 BLI_listbase_clear(r_face_regions);
1389
1390#ifdef USE_PIVOT_FASTMATCH
1391 if (depth > 0) {
1392 fm = bm_vert_fasthash_create(bm, depth);
1393 }
1394 else {
1395 fm = nullptr;
1396 }
1397#endif
1398
1399#ifdef USE_WALKER_REUSE
1400 bm_uidwalk_init(&w_src, faces_region_len, verts_region_len);
1401 bm_uidwalk_init(&w_dst, faces_region_len, verts_region_len);
1402#endif
1403
1404 BM_ITER_MESH (e_dst, &iter, bm, BM_EDGES_OF_MESH) {
1405 BMFace **faces_result;
1406 uint faces_result_len_out;
1407
1408 if (BM_elem_flag_test(e_dst, BM_ELEM_TAG) || BM_edge_is_wire(e_dst)) {
1409 continue;
1410 }
1411
1412#ifdef USE_PIVOT_FASTMATCH
1413 if (fm && !bm_vert_fasthash_edge_is_match(fm, e_src, e_dst)) {
1414 continue;
1415 }
1416#endif
1417
1418#ifdef DEBUG_PRINT
1419 search_num += 1;
1420#endif
1421
1422 faces_result = bm_mesh_region_match_pair(
1423#ifdef USE_WALKER_REUSE
1424 &w_src,
1425 &w_dst,
1426#endif
1427 e_src,
1428 e_dst,
1429 faces_region_len,
1430 verts_region_len,
1431 &faces_result_len_out);
1432
1433 /* tag verts as visited */
1434 if (faces_result) {
1435 LinkData *link;
1436
1437 bm_face_array_visit(faces_result, faces_result_len_out, nullptr, false);
1438
1439 link = BLI_genericNodeN(faces_result);
1440 BLI_addtail(r_face_regions, link);
1441 faces_result_len += 1;
1442 }
1443 }
1444
1445#ifdef USE_WALKER_REUSE
1446 bm_uidwalk_free(&w_src);
1447 bm_uidwalk_free(&w_dst);
1448#else
1449 (void)bm_uidwalk_clear;
1450#endif
1451
1452#ifdef USE_PIVOT_FASTMATCH
1453 if (fm) {
1455 }
1456#endif
1457
1458#ifdef DEBUG_PRINT
1459 printf("%s: search: %d, found %d\n", __func__, search_num, faces_result_len);
1460#endif
1461
1462#ifdef DEBUG_TIME
1463 TIMEIT_END(region_match);
1464#endif
1465
1466 return int(faces_result_len);
1467}
#define BLI_array_alloca(arr, realsize)
Definition BLI_alloca.h:25
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_INLINE
struct GSet GSet
Definition BLI_ghash.h:341
BLI_INLINE void * BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:299
bool BLI_ghash_haskey(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:819
bool BLI_gset_haskey(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:1004
void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:855
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:303
BLI_INLINE void ** BLI_ghashIterator_getValue_p(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:307
#define GHASH_ITER(gh_iter_, ghash_)
Definition BLI_ghash.h:322
GSet * BLI_gset_new_ex(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:936
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.c:1029
void ** BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:745
unsigned int BLI_gset_len(const GSet *gs) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:954
void BLI_gset_insert(GSet *gs, void *key)
Definition BLI_ghash.c:959
GHash * BLI_ghash_new_ex(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:678
unsigned int BLI_ghash_len(const GHash *gh) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:702
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.c:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:860
GHash * BLI_ghash_int_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.c:1034
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:752
#define GHASH_ITER_INDEX(gh_iter_, ghash_, i_)
Definition BLI_ghash.h:326
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:90
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void void BLI_listbase_sort(struct ListBase *listbase, int(*cmp)(const void *, const void *)) ATTR_NONNULL(1
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
struct LinkData * BLI_genericNodeN(void *data)
Definition listbase.cc:909
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:251
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1)
void BLI_mempool_free(BLI_mempool *pool, void *addr) ATTR_NONNULL(1
BLI_mempool * BLI_mempool_create(unsigned int esize, unsigned int elem_num, unsigned int pchunk, unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
@ BLI_MEMPOOL_NOP
Definition BLI_mempool.h:86
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1)
void BLI_mempool_clear(BLI_mempool *pool) ATTR_NONNULL(1)
unsigned int uint
Platform independent time functions.
Utility defines for timing/benchmarks.
#define TIMEIT_START(var)
#define TIMEIT_END(var)
#define UNLIKELY(x)
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define MEM_reallocN(vmemh, len)
@ BM_ELEM_TAG
#define BM_FACE_FIRST_LOOP(p)
#define BM_elem_index_get(ele)
#define BM_elem_flag_disable(ele, hflag)
#define BM_elem_flag_test(ele, hflag)
#define BM_elem_flag_test_bool(ele, hflag)
#define BM_elem_flag_enable(ele, hflag)
#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_VERT
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_LOOPS_OF_VERT
@ BM_EDGES_OF_VERT
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_select_history_clear(BMesh *bm)
BMEdge * BM_mesh_active_edge_get(BMesh *bm)
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
#define BM_select_history_store(bm, ele)
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
#define BM_FACE
#define BM_EDGE
#define BM_VERT
int BM_edge_face_count(const BMEdge *e)
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) 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
static GSet * gset_bmelem_new_ex(const char *info, const uint nentries_reserve)
#define PRIME_LOOP
static void bm_face_region_pivot_edge_use_best(GHash *gh, BMEdge *e_test, BMEdge **r_e_pivot_best, SUID_Int e_pivot_best_id[2])
BLI_INLINE bool bm_uidwalk_face_lookup(UIDWalk *uidwalk, BMFace *f, UID_Int *r_uid)
#define PRIME_VERT_MID_B
static bool bm_vert_is_uid_connect(UIDWalk *uidwalk, BMVert *v)
static bool bm_uidwalk_facestep_begin(UIDWalk *uidwalk, UIDFaceStep *fstep)
static int bm_face_len_cmp(const void *v1, const void *v2)
static bool ghashutil_bmelem_indexcmp(const void *a, const void *b)
static UIDFashMatch * bm_vert_fasthash_create(BMesh *bm, const uint depth)
#define PRIME_FACE_MID
BLI_INLINE bool bm_uidwalk_vert_lookup(UIDWalk *uidwalk, BMVert *v, UID_Int *r_uid)
uintptr_t UIDFashMatch
static UID_Int bm_uidwalk_calc_face_uid(UIDWalk *uidwalk, BMFace *f)
BLI_INLINE bool bm_uidwalk_face_test(UIDWalk *uidwalk, BMFace *f)
static void bm_uidwalk_free(UIDWalk *uidwalk)
intptr_t SUID_Int
static UIDFashMatch bm_vert_fasthash_single(BMVert *v)
static void bm_uidwalk_pass_add(UIDWalk *uidwalk, LinkNode *faces_pass, const uint faces_pass_len)
static UID_Int bm_uidwalk_calc_vert_uid(UIDWalk *uidwalk, BMVert *v)
#define USE_WALKER_REUSE
static void bm_uidwalk_clear(UIDWalk *uidwalk)
static GSet * gset_bmelem_new(const char *info)
#define PRIME_VERT_MID
#define PRIME_FACE
BLI_INLINE intptr_t abs_intptr(intptr_t a)
static void bm_uidwalk_init(UIDWalk *uidwalk, const uint faces_src_region_len, const uint verts_src_region_len)
#define PRIME_EDGE
static uint bm_uidwalk_init_from_edge(UIDWalk *uidwalk, BMEdge *e)
static void bm_uidwalk_rehash_reserve(UIDWalk *uidwalk, uint rehash_store_len_new)
#define PRIME_FACE_SMALL
static void bm_uidwalk_facestep_free(UIDWalk *uidwalk, UIDFaceStep *fstep)
static SUID_Int bm_face_region_vert_pass_id(GHash *gh, BMVert *v)
static bool bm_vert_fasthash_edge_is_match(UIDFashMatch *fm, const BMEdge *e_a, const BMEdge *e_b)
static int facestep_sort(const void *a, const void *b)
#define PRIME_VERT_LARGE
#define PRIME_VERT_SMALL
static BMEdge * bm_face_region_pivot_edge_find(BMFace **faces_region, uint faces_region_len, uint verts_region_len, uint *r_depth)
static void bm_vert_fasthash_destroy(UIDFashMatch *fm)
static uint ghashutil_bmelem_indexhash(const void *key)
static void bm_uidwalk_rehash(UIDWalk *uidwalk)
#define PRIME_VERT_MID_A
uintptr_t UID_Int
static void bm_uidwalk_facestep_end(UIDWalk *uidwalk, UIDFaceStep *fstep)
#define PRIME_VERT_INIT
static GHash * ghash_bmelem_new(const char *info)
static void bm_vert_fasthash_edge_order(const UIDFashMatch *fm, const BMEdge *e, UIDFashMatch e_fm[2])
#define PRIME_VERT_SMALL_A
static void bm_uidwalk_rehash_facelinks(UIDWalk *uidwalk, LinkNode *faces, const uint faces_len, const bool is_init)
static SUID_Int bm_face_region_vert_boundary_id(BMVert *v)
static bool bm_edge_is_region_boundary(BMEdge *e)
static GHash * ghash_bmelem_new_ex(const char *info, const uint nentries_reserve)
#define PRIME_FACE_LARGE
static BMFace ** bm_mesh_region_match_pair(UIDWalk *w_src, UIDWalk *w_dst, BMEdge *e_src, BMEdge *e_dst, const uint faces_src_region_len, const uint verts_src_region_len, uint *r_faces_result_len)
#define PRIME_VERT_SMALL_B
int BM_mesh_region_match(BMesh *bm, BMFace **faces_region, uint faces_region_len, ListBase *r_face_regions)
static void bm_face_array_visit(BMFace **faces, const uint faces_len, uint *r_verts_len, bool visit_faces)
local_group_size(16, 16) .push_constant(Type b
#define printf
int len
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
return ret
#define INTPTR_MIN
Definition stdint.h:179
_W64 unsigned int uintptr_t
Definition stdint.h:119
_W64 int intptr_t
Definition stdint.h:118
BMVert * v1
BMVert * v2
struct BMVert * v
struct BMEdge * e
struct BMLoop * radial_next
struct BMLoop * prev
struct BMFace * f
struct BMLoop * next
int totvert
void * link
struct LinkNode * next
void * first
UIDFaceStepItem * prev
UIDFaceStepItem * next
UIDFaceStep * next
UIDFaceStep * prev
GHash * faces_from_uid
BLI_mempool * link_pool
ListBase faces_step
BLI_mempool * step_pool_items
BLI_mempool * step_pool
GHash * faces_uid
BLI_mempool * lbase_pool
GHash * verts_uid
UID_Int * rehash_store
struct UIDWalk::@169 cache