Blender V5.0
bmesh_iterators.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
12
13#include "MEM_guardedalloc.h"
14
15#include "bmesh.hh"
17
19 '\0',
20 BM_VERT, /* BM_VERTS_OF_MESH */
21 BM_EDGE, /* BM_EDGES_OF_MESH */
22 BM_FACE, /* BM_FACES_OF_MESH */
23 BM_EDGE, /* BM_EDGES_OF_VERT */
24 BM_FACE, /* BM_FACES_OF_VERT */
25 BM_LOOP, /* BM_LOOPS_OF_VERT */
26 BM_VERT, /* BM_VERTS_OF_EDGE */
27 BM_FACE, /* BM_FACES_OF_EDGE */
28 BM_VERT, /* BM_VERTS_OF_FACE */
29 BM_EDGE, /* BM_EDGES_OF_FACE */
30 BM_LOOP, /* BM_LOOPS_OF_FACE */
31 BM_LOOP, /* BM_LOOPS_OF_LOOP */
32 BM_LOOP, /* BM_LOOPS_OF_EDGE */
33};
34
36{
37 int count;
38
39 switch (itype) {
41 count = bm->totvert;
42 break;
44 count = bm->totedge;
45 break;
47 count = bm->totface;
48 break;
49 default:
50 count = 0;
51 BLI_assert(0);
52 break;
53 }
54
55 return count;
56}
57
58void *BM_iter_at_index(BMesh *bm, const char itype, void *data, int index)
59{
60 BMIter iter;
61 void *val;
62 int i;
63
64 /* sanity check */
65 if (index < 0) {
66 return nullptr;
67 }
68
69 val = BM_iter_new(&iter, bm, itype, data);
70
71 i = 0;
72 while (i < index) {
73 val = BM_iter_step(&iter);
74 i++;
75 }
76
77 return val;
78}
79
80int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, const int len)
81{
82 int i = 0;
83
84 /* sanity check */
85 if (len > 0) {
86 BMIter iter;
87 void *ele;
88
89 for (ele = BM_iter_new(&iter, bm, itype, data); ele; ele = BM_iter_step(&iter)) {
90 array[i] = ele;
91 i++;
92 if (i == len) {
93 return len;
94 }
95 }
96 }
97
98 return i;
99}
101 const char *slot_name,
102 const char restrictmask,
103 void **array,
104 const int len)
105{
106 int i = 0;
107
108 /* sanity check */
109 if (len > 0) {
110 BMOIter oiter;
111 void *ele;
112
113 for (ele = BMO_iter_new(&oiter, slot_args, slot_name, restrictmask); ele;
114 ele = BMO_iter_step(&oiter))
115 {
116 array[i] = ele;
117 i++;
118 if (i == len) {
119 return len;
120 }
121 }
122 }
123
124 return i;
125}
126
128 const char itype,
129 void *data,
130 int *r_len,
131 /* optional args to avoid an alloc (normally stack array) */
132 void **stack_array,
133 int stack_array_size)
134{
135 BMIter iter;
136
137 BLI_assert(stack_array_size == 0 || (stack_array_size && stack_array));
138
139 /* We can't rely on #BMIter.count being set. */
140 switch (itype) {
141 case BM_VERTS_OF_MESH:
142 iter.count = bm->totvert;
143 break;
144 case BM_EDGES_OF_MESH:
145 iter.count = bm->totedge;
146 break;
147 case BM_FACES_OF_MESH:
148 iter.count = bm->totface;
149 break;
150 default:
151 break;
152 }
153
154 if (BM_iter_init(&iter, bm, itype, data) && iter.count > 0) {
155 BMElem *ele;
156 BMElem **array = iter.count > stack_array_size ?
157 MEM_malloc_arrayN<BMElem *>(iter.count, __func__) :
158 reinterpret_cast<BMElem **>(stack_array);
159 int i = 0;
160
161 *r_len = iter.count; /* set before iterating */
162
163 while ((ele = static_cast<BMElem *>(BM_iter_step(&iter)))) {
164 array[i++] = ele;
165 }
166 return array;
167 }
168
169 *r_len = 0;
170 return nullptr;
171}
172
174 const char *slot_name,
175 const char restrictmask,
176 int *r_len,
177 /* optional args to avoid an alloc (normally stack array) */
178 void **stack_array,
179 int stack_array_size)
180{
181 BMOIter iter;
182 BMElem *ele;
183 const int slot_len = BMO_slot_buffer_len(slot_args, slot_name);
184
185 BLI_assert(stack_array_size == 0 || (stack_array_size && stack_array));
186
187 if ((ele = static_cast<BMElem *>(BMO_iter_new(&iter, slot_args, slot_name, restrictmask))) &&
188 slot_len > 0)
189 {
190 BMElem **array = slot_len > stack_array_size ?
191 MEM_malloc_arrayN<BMElem *>(slot_len, __func__) :
192 reinterpret_cast<BMElem **>(stack_array);
193 int i = 0;
194
195 do {
196 array[i++] = ele;
197 } while ((ele = static_cast<BMElem *>(BMO_iter_step(&iter))));
198 BLI_assert(i <= slot_len);
199
200 if (i != slot_len) {
201 if ((void **)array != stack_array) {
202 array = static_cast<BMElem **>(MEM_reallocN(array, sizeof(ele) * i));
203 }
204 }
205 *r_len = i;
206 return array;
207 }
208
209 *r_len = 0;
210 return nullptr;
211}
212
214 BMesh *bm,
216 bool (*test_fn)(BMElem *, void *user_data),
217 void *user_data)
218{
219 BMIter iter;
220 BMElem *ele;
221 int i;
222 int bitmap_enabled = 0;
223
224 BM_ITER_MESH_INDEX (ele, &iter, bm, itype, i) {
225 if (test_fn(ele, user_data)) {
226 bitmap[i].set();
227 bitmap_enabled++;
228 }
229 else {
230 bitmap[i].reset();
231 }
232 }
233
234 return bitmap_enabled;
235}
236
239 bool (*test_fn)(BMFace *, void *user_data),
240 void *user_data)
241{
242 BMIter iter;
243 BMFace *f;
244 int i;
245 int j = 0;
246 int bitmap_enabled = 0;
247
249 if (test_fn(f, user_data)) {
250 for (int tri = 2; tri < f->len; tri++) {
251 bitmap[j].set();
252 bitmap_enabled++;
253 j++;
254 }
255 }
256 else {
257 for (int tri = 2; tri < f->len; tri++) {
258 bitmap[j].reset();
259 j++;
260 }
261 }
262 }
263
264 return bitmap_enabled;
265}
266
267int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, const bool value)
268{
269 BMIter iter;
270 BMElem *ele;
271 int count = 0;
272
273 BM_ITER_ELEM (ele, &iter, data, itype) {
274 if (BM_elem_flag_test_bool(ele, hflag) == value) {
275 count++;
276 }
277 }
278
279 return count;
280}
281
283 BMesh *bm, const char itype, void *data, const short oflag, const bool value)
284{
285 BMIter iter;
286 int count = 0;
287
288 /* loops have no header flags */
290
292 case BM_VERT: {
293 BMVert *ele;
294 BM_ITER_ELEM (ele, &iter, data, itype) {
295 if (BMO_vert_flag_test_bool(bm, ele, oflag) == value) {
296 count++;
297 }
298 }
299 break;
300 }
301 case BM_EDGE: {
302 BMEdge *ele;
303 BM_ITER_ELEM (ele, &iter, data, itype) {
304 if (BMO_edge_flag_test_bool(bm, ele, oflag) == value) {
305 count++;
306 }
307 }
308 break;
309 }
310 case BM_FACE: {
311 BMFace *ele;
312 BM_ITER_ELEM (ele, &iter, data, itype) {
313 if (BMO_face_flag_test_bool(bm, ele, oflag) == value) {
314 count++;
315 }
316 }
317 break;
318 }
319 }
320 return count;
321}
322
323int BM_iter_mesh_count_flag(const char itype, BMesh *bm, const char hflag, const bool value)
324{
325 BMIter iter;
326 BMElem *ele;
327 int count = 0;
328
329 BM_ITER_MESH (ele, &iter, bm, itype) {
330 if (BM_elem_flag_test_bool(ele, hflag) == value) {
331 count++;
332 }
333 }
334
335 return count;
336}
337
351
352/*
353 * VERT OF MESH CALLBACKS
354 */
355
356/* see bug #36923 for why we need this,
357 * allow adding but not removing, this isn't _totally_ safe since
358 * you could add/remove within the same loop, but catches common cases
359 */
360#ifndef NDEBUG
361# define USE_IMMUTABLE_ASSERT
362#endif
363
365{
366#ifdef USE_IMMUTABLE_ASSERT
367 ((BMIter *)iter)->count = BLI_mempool_len(iter->pooliter.pool);
368#endif
370}
371
373{
374#ifdef USE_IMMUTABLE_ASSERT
375 BLI_assert(((BMIter *)iter)->count <= BLI_mempool_len(iter->pooliter.pool));
376#endif
377 return BLI_mempool_iterstep(&iter->pooliter);
378}
379
380#ifdef USE_IMMUTABLE_ASSERT
381# undef USE_IMMUTABLE_ASSERT
382#endif
383
384/*
385 * EDGE OF VERT CALLBACKS
386 */
387
389{
390 if (iter->vdata->e) {
391 iter->e_first = iter->vdata->e;
392 iter->e_next = iter->vdata->e;
393 }
394 else {
395 iter->e_first = nullptr;
396 iter->e_next = nullptr;
397 }
398}
399
401{
402 BMEdge *e_curr = iter->e_next;
403
404 if (iter->e_next) {
405 iter->e_next = bmesh_disk_edge_next(iter->e_next, iter->vdata);
406 if (iter->e_next == iter->e_first) {
407 iter->e_next = nullptr;
408 }
409 }
410
411 return e_curr;
412}
413
414/*
415 * FACE OF VERT CALLBACKS
416 */
417
419{
420 ((BMIter *)iter)->count = bmesh_disk_facevert_count(iter->vdata);
421 if (((BMIter *)iter)->count) {
422 iter->l_first = bmesh_disk_faceloop_find_first(iter->vdata->e, iter->vdata);
423 iter->e_first = iter->l_first->e;
424 iter->e_next = iter->e_first;
425 iter->l_next = iter->l_first;
426 }
427 else {
428 iter->l_first = iter->l_next = nullptr;
429 iter->e_first = iter->e_next = nullptr;
430 }
431}
433{
434 BMLoop *l_curr = iter->l_next;
435
436 if (((BMIter *)iter)->count && iter->l_next) {
437 ((BMIter *)iter)->count--;
439 if (iter->l_next == iter->l_first) {
440 iter->e_next = bmesh_disk_faceedge_find_next(iter->e_next, iter->vdata);
442 iter->l_next = iter->l_first;
443 }
444 }
445
446 if (!((BMIter *)iter)->count) {
447 iter->l_next = nullptr;
448 }
449
450 return l_curr ? l_curr->f : nullptr;
451}
452
453/*
454 * LOOP OF VERT CALLBACKS
455 */
456
458{
459 ((BMIter *)iter)->count = bmesh_disk_facevert_count(iter->vdata);
460 if (((BMIter *)iter)->count) {
461 iter->l_first = bmesh_disk_faceloop_find_first(iter->vdata->e, iter->vdata);
462 iter->e_first = iter->l_first->e;
463 iter->e_next = iter->e_first;
464 iter->l_next = iter->l_first;
465 }
466 else {
467 iter->l_first = iter->l_next = nullptr;
468 iter->e_first = iter->e_next = nullptr;
469 }
470}
472{
473 BMLoop *l_curr = iter->l_next;
474
475 if (((BMIter *)iter)->count) {
476 ((BMIter *)iter)->count--;
478 if (iter->l_next == iter->l_first) {
479 iter->e_next = bmesh_disk_faceedge_find_next(iter->e_next, iter->vdata);
481 iter->l_next = iter->l_first;
482 }
483 }
484
485 if (!((BMIter *)iter)->count) {
486 iter->l_next = nullptr;
487 }
488
489 /* nullptr on finish */
490 return l_curr;
491}
492
493/*
494 * LOOP OF EDGE CALLBACKS
495 */
496
498{
499 iter->l_first = iter->l_next = iter->edata->l;
500}
501
503{
504 BMLoop *l_curr = iter->l_next;
505
506 if (iter->l_next) {
507 iter->l_next = iter->l_next->radial_next;
508 if (iter->l_next == iter->l_first) {
509 iter->l_next = nullptr;
510 }
511 }
512
513 /* nullptr on finish */
514 return l_curr;
515}
516
517/*
518 * LOOP OF LOOP CALLBACKS
519 */
520
522{
523 iter->l_first = iter->ldata;
524 iter->l_next = iter->l_first->radial_next;
525
526 if (iter->l_next == iter->l_first) {
527 iter->l_next = nullptr;
528 }
529}
530
532{
533 BMLoop *l_curr = iter->l_next;
534
535 if (iter->l_next) {
536 iter->l_next = iter->l_next->radial_next;
537 if (iter->l_next == iter->l_first) {
538 iter->l_next = nullptr;
539 }
540 }
541
542 /* nullptr on finish */
543 return l_curr;
544}
545
546/*
547 * FACE OF EDGE CALLBACKS
548 */
549
551{
552 iter->l_first = iter->l_next = iter->edata->l;
553}
554
556{
557 BMLoop *current = iter->l_next;
558
559 if (iter->l_next) {
560 iter->l_next = iter->l_next->radial_next;
561 if (iter->l_next == iter->l_first) {
562 iter->l_next = nullptr;
563 }
564 }
565
566 return current ? current->f : nullptr;
567}
568
569/*
570 * VERTS OF EDGE CALLBACKS
571 */
572
574{
575 ((BMIter *)iter)->count = 0;
576}
577
579{
580 switch (((BMIter *)iter)->count++) {
581 case 0:
582 return iter->edata->v1;
583 case 1:
584 return iter->edata->v2;
585 default:
586 return nullptr;
587 }
588}
589
590/*
591 * VERT OF FACE CALLBACKS
592 */
593
598
600{
601 BMLoop *l_curr = iter->l_next;
602
603 if (iter->l_next) {
604 iter->l_next = iter->l_next->next;
605 if (iter->l_next == iter->l_first) {
606 iter->l_next = nullptr;
607 }
608 }
609
610 return l_curr ? l_curr->v : nullptr;
611}
612
613/*
614 * EDGE OF FACE CALLBACKS
615 */
616
621
623{
624 BMLoop *l_curr = iter->l_next;
625
626 if (iter->l_next) {
627 iter->l_next = iter->l_next->next;
628 if (iter->l_next == iter->l_first) {
629 iter->l_next = nullptr;
630 }
631 }
632
633 return l_curr ? l_curr->e : nullptr;
634}
635
636/*
637 * LOOP OF FACE CALLBACKS
638 */
639
644
646{
647 BMLoop *l_curr = iter->l_next;
648
649 if (iter->l_next) {
650 iter->l_next = iter->l_next->next;
651 if (iter->l_next == iter->l_first) {
652 iter->l_next = nullptr;
653 }
654 }
655
656 return l_curr;
657}
#define BLI_assert(a)
Definition BLI_assert.h:46
void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) ATTR_NONNULL()
void * BLI_mempool_iterstep(BLI_mempool_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
int BLI_mempool_len(const BLI_mempool *pool) ATTR_NONNULL(1)
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
#define BM_FACE_FIRST_LOOP(p)
@ BM_LOOP
#define BM_elem_flag_test_bool(ele, hflag)
int BMO_iter_elem_count_flag(BMesh *bm, const char itype, void *data, const short oflag, const bool value)
Elem Iter Tool Flag Count.
void * BM_iter_at_index(BMesh *bm, const char itype, void *data, int index)
void * bmiter__elem_of_mesh_step(BMIter__elem_of_mesh *iter)
void * bmiter__vert_of_edge_step(BMIter__vert_of_edge *iter)
int BMO_iter_as_array(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask, void **array, const int len)
Operator Iterator as Array.
void bmiter__edge_of_face_begin(BMIter__edge_of_face *iter)
void * BMO_iter_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char restrictmask, int *r_len, void **stack_array, int stack_array_size)
const char bm_iter_itype_htype_map[BM_ITYPE_MAX]
void * bmiter__face_of_vert_step(BMIter__face_of_vert *iter)
void bmiter__face_of_vert_begin(BMIter__face_of_vert *iter)
void * bmiter__loop_of_face_step(BMIter__loop_of_face *iter)
void bmiter__loop_of_edge_begin(BMIter__loop_of_edge *iter)
void bmiter__face_of_edge_begin(BMIter__face_of_edge *iter)
int BM_iter_mesh_bitmap_from_filter_tessface(BMesh *bm, blender::MutableBitSpan bitmap, bool(*test_fn)(BMFace *, void *user_data), void *user_data)
void bmiter__loop_of_face_begin(BMIter__loop_of_face *iter)
void * bmiter__edge_of_face_step(BMIter__edge_of_face *iter)
void bmiter__edge_of_vert_begin(BMIter__edge_of_vert *iter)
void bmiter__elem_of_mesh_begin(BMIter__elem_of_mesh *iter)
void * BM_iter_as_arrayN(BMesh *bm, const char itype, void *data, int *r_len, void **stack_array, int stack_array_size)
Iterator as Array.
void * bmiter__face_of_edge_step(BMIter__face_of_edge *iter)
void * bmiter__loop_of_edge_step(BMIter__loop_of_edge *iter)
void bmiter__vert_of_face_begin(BMIter__vert_of_face *iter)
int BM_iter_mesh_count_flag(const char itype, BMesh *bm, const char hflag, const bool value)
Mesh Iter Flag Count.
void * bmiter__loop_of_vert_step(BMIter__loop_of_vert *iter)
int BM_iter_mesh_bitmap_from_filter(const char itype, BMesh *bm, blender::MutableBitSpan bitmap, bool(*test_fn)(BMElem *, void *user_data), void *user_data)
int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, const int len)
Iterator as Array.
void * bmiter__loop_of_loop_step(BMIter__loop_of_loop *iter)
void bmiter__loop_of_loop_begin(BMIter__loop_of_loop *iter)
int BM_iter_mesh_count(const char itype, BMesh *bm)
int BM_iter_elem_count_flag(const char itype, void *data, const char hflag, const bool value)
Elem Iter Flag Count.
void * bmiter__vert_of_face_step(BMIter__vert_of_face *iter)
void * bmiter__edge_of_vert_step(BMIter__edge_of_vert *iter)
void bmiter__loop_of_vert_begin(BMIter__loop_of_vert *iter)
void bmiter__vert_of_edge_begin(BMIter__vert_of_edge *iter)
#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)
#define BM_iter_init(iter, bm, itype, data)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
#define BM_iter_new(iter, bm, itype, data)
#define BM_ITYPE_MAX
BMesh const char void * data
BMesh * bm
BMesh const char itype
#define BM_FACE
#define BM_EDGE
#define BM_VERT
#define BMO_edge_flag_test_bool(bm, e, oflag)
#define BMO_face_flag_test_bool(bm, e, oflag)
void * BMO_iter_new(BMOIter *iter, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char restrictmask)
New Iterator.
#define BMO_OP_MAX_SLOTS
int BMO_slot_buffer_len(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
#define BMO_vert_flag_test_bool(bm, e, oflag)
void * BMO_iter_step(BMOIter *iter)
ATTR_WARN_UNUSED_RESULT const BMFlagLayer const short oflag
BMLoop * bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v)
BMLoop * bmesh_radial_faceloop_find_first(const BMLoop *l, const BMVert *v)
BME RADIAL FIND FIRST FACE VERT.
BMLoop * bmesh_radial_faceloop_find_next(const BMLoop *l, const BMVert *v)
int bmesh_disk_facevert_count(const BMVert *v)
DISK COUNT FACE VERT.
BMEdge * bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v)
BLI_INLINE BMEdge * bmesh_disk_edge_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
int count
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
BLI_mempool * pool
Definition BLI_mempool.h:95
BMVert * v1
BMVert * v2
struct BMLoop * l
BLI_mempool_iter pooliter
struct BMVert * v
struct BMEdge * e
struct BMLoop * radial_next
struct BMFace * f
struct BMLoop * next
struct BMEdge * e
i
Definition text_draw.cc:230
uint len