Blender V4.3
bmo_removedoubles.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
11#include "MEM_guardedalloc.h"
12
13#include "BLI_alloca.h"
14#include "BLI_kdtree.h"
15#include "BLI_listbase.h"
16#include "BLI_math_vector.h"
17#include "BLI_stack.h"
19
20#include "BKE_customdata.hh"
21
22#include "bmesh.hh"
24
25static void remdoubles_splitface(BMFace *f, BMesh *bm, BMOperator *op, BMOpSlot *slot_targetmap)
26{
27 BMIter liter;
28 BMLoop *l, *l_tar, *l_double;
29 bool split = false;
30
31 BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
32 BMVert *v_tar = static_cast<BMVert *>(BMO_slot_map_elem_get(slot_targetmap, l->v));
33 /* ok: if v_tar is nullptr (e.g. not in the map) then it's
34 * a target vert, otherwise it's a double */
35 if (v_tar) {
36 l_tar = BM_face_vert_share_loop(f, v_tar);
37
38 if (l_tar && (l_tar != l) && !BM_loop_is_adjacent(l_tar, l)) {
39 l_double = l;
40 split = true;
41 break;
42 }
43 }
44 }
45
46 if (split) {
47 BMLoop *l_new;
48 BMFace *f_new;
49
50 f_new = BM_face_split(bm, f, l_double, l_tar, &l_new, nullptr, false);
51
52 remdoubles_splitface(f, bm, op, slot_targetmap);
53 remdoubles_splitface(f_new, bm, op, slot_targetmap);
54 }
55}
56
57#define ELE_DEL 1
58#define EDGE_COL 2
59#define VERT_IN_FACE 4
60
65 BMFace *f,
66 BMOpSlot *slot_targetmap,
67 bool *r_created)
68{
69 BMEdge *e_new;
70
71 /* New ordered edges. */
72 BMEdge **edges = BLI_array_alloca(edges, f->len);
73 /* New ordered verts. */
75 /* Original ordered loops to copy attributes into the new face. */
76 BMLoop **loops = BLI_array_alloca(loops, f->len);
77
78 STACK_DECLARE(edges);
79 STACK_DECLARE(loops);
81
82 STACK_INIT(edges, f->len);
83 STACK_INIT(loops, f->len);
84 STACK_INIT(verts, f->len);
85
86 *r_created = false;
87
88 {
89#define LOOP_MAP_VERT_INIT(l_init, v_map, is_del) \
90 v_map = l_init->v; \
91 is_del = BMO_vert_flag_test_bool(bm, v_map, ELE_DEL); \
92 if (is_del) { \
93 v_map = static_cast<BMVert *>(BMO_slot_map_elem_get(slot_targetmap, v_map)); \
94 } \
95 ((void)0)
96
97 BMLoop *l_first, *l_curr, *l_next;
98 BMVert *v_curr;
99 bool is_del_v_curr;
100
101 l_curr = l_first = BM_FACE_FIRST_LOOP(f);
102 LOOP_MAP_VERT_INIT(l_curr, v_curr, is_del_v_curr);
103
104 do {
105 BMVert *v_next;
106 bool is_del_v_next;
107
108 l_next = l_curr->next;
109 LOOP_MAP_VERT_INIT(l_next, v_next, is_del_v_next);
110
111 /* only search for a new edge if one of the verts is mapped */
112 if ((is_del_v_curr || is_del_v_next) == 0) {
113 e_new = l_curr->e;
114 }
115 else if (v_curr == v_next) {
116 e_new = nullptr; /* skip */
117 }
118 else {
119 e_new = BM_edge_exists(v_curr, v_next);
120 BLI_assert(e_new); /* never fails */
121 }
122
123 if (e_new) {
125 /* we can't make the face, bail out */
126 STACK_CLEAR(edges);
127 goto finally;
128 }
130
131 STACK_PUSH(edges, e_new);
132 STACK_PUSH(loops, l_curr);
133 STACK_PUSH(verts, v_curr);
134 }
135
136 v_curr = v_next;
137 is_del_v_curr = is_del_v_next;
138 } while ((l_curr = l_next) != l_first);
139
140#undef LOOP_MAP_VERT_INIT
141 }
142
143finally: {
144 uint i;
145 for (i = 0; i < STACK_SIZE(verts); i++) {
147 }
148}
149
150 if (STACK_SIZE(edges) >= 3) {
152 if (f_new) {
153 return f_new;
154 }
155 f_new = BM_face_create(bm, verts, edges, STACK_SIZE(edges), f, BM_CREATE_NOP);
156 BLI_assert(f_new != f);
157
158 if (f_new) {
159 uint i = 0;
160 BMLoop *l_iter, *l_first;
161 l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
162 do {
163 BM_elem_attrs_copy(bm, loops[i], l_iter);
164 } while ((void)i++, (l_iter = l_iter->next) != l_first);
165
166 *r_created = true;
167 return f_new;
168 }
169 }
170
171 return nullptr;
172}
173
180{
181 BMIter iter, liter;
182 BMVert *v;
183 BMEdge *e;
184 BMLoop *l;
185 BMFace *f;
186 BMOpSlot *slot_targetmap = BMO_slot_get(op->slots_in, "targetmap");
187
188 /* Maintain selection history. */
189 const bool has_selected = !BLI_listbase_is_empty(&bm->selected);
190 const bool use_targetmap_all = has_selected;
191 GHash *targetmap_all = nullptr;
192 if (use_targetmap_all) {
193 /* Map deleted to keep elem. */
194 targetmap_all = BLI_ghash_ptr_new(__func__);
195 }
196
197 /* mark merge verts for deletion */
198 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
199 BMVert *v_dst = static_cast<BMVert *>(BMO_slot_map_elem_get(slot_targetmap, v));
200 if (v_dst != nullptr) {
202
203 /* merge the vertex flags, else we get randomly selected/unselected verts */
205
206 if (use_targetmap_all) {
207 BLI_assert(v != v_dst);
208 BLI_ghash_insert(targetmap_all, v, v_dst);
209 }
210 }
211 }
212
213 /* check if any faces are getting their own corners merged
214 * together, split face if so */
215 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
216 remdoubles_splitface(f, bm, op, slot_targetmap);
217 }
218
219 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
220 BMVert *v1, *v2;
221 const bool is_del_v1 = BMO_vert_flag_test_bool(bm, (v1 = e->v1), ELE_DEL);
222 const bool is_del_v2 = BMO_vert_flag_test_bool(bm, (v2 = e->v2), ELE_DEL);
223
224 if (is_del_v1 || is_del_v2) {
225 if (is_del_v1) {
226 v1 = static_cast<BMVert *>(BMO_slot_map_elem_get(slot_targetmap, v1));
227 }
228 if (is_del_v2) {
229 v2 = static_cast<BMVert *>(BMO_slot_map_elem_get(slot_targetmap, v2));
230 }
231
232 if (v1 == v2) {
234 }
235 else {
236 /* always merge flags, even for edges we already created */
237 BMEdge *e_new = BM_edge_exists(v1, v2);
238 if (e_new == nullptr) {
239 e_new = BM_edge_create(bm, v1, v2, e, BM_CREATE_NOP);
240 }
242 if (use_targetmap_all) {
243 BLI_assert(e != e_new);
244 BLI_ghash_insert(targetmap_all, e, e_new);
245 }
246 }
247
249 }
250 }
251
252 /* faces get "modified" by creating new faces here, then at the
253 * end the old faces are deleted */
254 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
255 bool vert_delete = false;
256 int edge_collapse = 0;
257
258 BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
259 if (BMO_vert_flag_test(bm, l->v, ELE_DEL)) {
260 vert_delete = true;
261 }
262 if (BMO_edge_flag_test(bm, l->e, EDGE_COL)) {
263 edge_collapse++;
264 }
265 }
266
267 if (vert_delete) {
268 bool use_in_place = false;
269 BMFace *f_new = nullptr;
271
272 if (f->len - edge_collapse >= 3) {
273 bool created;
274 f_new = remdoubles_createface(bm, f, slot_targetmap, &created);
275 /* do this so we don't need to return a list of created faces */
276 if (f_new) {
277 if (created) {
278 bmesh_face_swap_data(f_new, f);
279
280 if (bm->use_toolflags) {
281 std::swap(((BMFace_OFlag *)f)->oflags, ((BMFace_OFlag *)f_new)->oflags);
282 }
283
285 BM_face_kill(bm, f_new);
286 use_in_place = true;
287 }
288 else {
290 }
291 }
292 }
293
294 if ((use_in_place == false) && (f_new != nullptr)) {
295 BLI_assert(f != f_new);
296 if (use_targetmap_all) {
297 BLI_ghash_insert(targetmap_all, f, f_new);
298 }
299 if (bm->act_face && (f == bm->act_face)) {
300 bm->act_face = f_new;
301 }
302 }
303 }
304 }
305
306 if (has_selected) {
307 BM_select_history_merge_from_targetmap(bm, targetmap_all, targetmap_all, targetmap_all, true);
308 }
309
310 if (use_targetmap_all) {
311 BLI_ghash_free(targetmap_all, nullptr, nullptr);
312 }
313
315}
316
317#define VERT_KEEP 8
318
319#define EDGE_MARK 1
320
322{
323 BMOIter siter;
324 BMIter iter;
325 BMVert *v, *vert_snap;
326 BMLoop *l, *l_first = nullptr;
327 float fac;
328 int i, tot;
329
330 vert_snap = static_cast<BMVert *>(
332 tot = BM_vert_face_count(vert_snap);
333
334 if (!tot) {
335 return;
336 }
337
338 fac = 1.0f / tot;
339 BM_ITER_ELEM (l, &iter, vert_snap, BM_LOOPS_OF_VERT) {
340 if (l_first == nullptr) {
341 l_first = l;
342 }
343
344 for (i = 0; i < bm->ldata.totlayer; i++) {
346 const int type = bm->ldata.layers[i].type;
347 const int offset = bm->ldata.layers[i].offset;
348 void *e1, *e2;
349
350 e1 = BM_ELEM_CD_GET_VOID_P(l_first, offset);
351 e2 = BM_ELEM_CD_GET_VOID_P(l, offset);
352
354
355 if (l != l_first) {
357 }
358 }
359 }
360 }
361
362 BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) {
363 BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
364 if (l == l_first) {
365 continue;
366 }
367
369 }
370 }
371}
372
374{
375 BMOIter siter;
376 BMIter iter;
377 BMVert *v;
378 BMLoop *l;
380 int i;
381
382 for (i = 0; i < bm->ldata.totlayer; i++) {
383 const int type = bm->ldata.layers[i].type;
384 const int offset = bm->ldata.layers[i].offset;
385
387 continue;
388 }
389
391
392 BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) {
393 BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
394 void *block = BM_ELEM_CD_GET_VOID_P(l, offset);
395 CustomData_data_dominmax(eCustomDataType(type), block, &min, &max);
396 }
397 }
398
400 CustomData_data_multiply(eCustomDataType(type), &max, 0.5f);
402
403 BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) {
404 BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
405 void *block = BM_ELEM_CD_GET_VOID_P(l, offset);
407 }
408 }
409 }
410}
411
413{
414 BMOperator weldop;
415 BMOIter siter;
416 BMVert *v, *vert_snap = nullptr;
417 float vec[3];
418 BMOpSlot *slot_targetmap;
419
420 BMO_slot_vec_get(op->slots_in, "merge_co", vec);
421
422 // BMO_op_callf(bm, op->flag, "collapse_uvs edges=%s", op, "edges");
423 BMO_op_init(bm, &weldop, op->flag, "weld_verts");
424
425 slot_targetmap = BMO_slot_get(weldop.slots_in, "targetmap");
426
427 BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) {
428 if (!vert_snap) {
429 vert_snap = v;
430 copy_v3_v3(vert_snap->co, vec);
431 }
432 else {
433 BMO_slot_map_elem_insert(&weldop, slot_targetmap, v, vert_snap);
434 }
435 }
436
437 BMO_op_exec(bm, &weldop);
438 BMO_op_finish(bm, &weldop);
439}
440
442{
443 BMOperator weldop;
444 BMWalker walker;
445 BMIter iter;
446 BMEdge *e;
447 BLI_Stack *edge_stack;
448 BMOpSlot *slot_targetmap;
449
450 if (BMO_slot_bool_get(op->slots_in, "uvs")) {
451 BMO_op_callf(bm, op->flag, "collapse_uvs edges=%s", op, "edges");
452 }
453
454 BMO_op_init(bm, &weldop, op->flag, "weld_verts");
455 slot_targetmap = BMO_slot_get(weldop.slots_in, "targetmap");
456
458
459 BMW_init(&walker,
460 bm,
463 EDGE_MARK,
465 BMW_FLAG_NOP, /* no need to use BMW_FLAG_TEST_HIDDEN, already marked data */
467
468 edge_stack = BLI_stack_new(sizeof(BMEdge *), __func__);
469
470 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
471 float center[3];
472 int count = 0;
473 BMVert *v_tar;
474
475 zero_v3(center);
476
478 continue;
479 }
480
481 BLI_assert(BLI_stack_is_empty(edge_stack));
482
483 for (e = static_cast<BMEdge *>(BMW_begin(&walker, e->v1)); e;
484 e = static_cast<BMEdge *>(BMW_step(&walker)))
485 {
486 BLI_stack_push(edge_stack, &e);
487
488 add_v3_v3(center, e->v1->co);
489 add_v3_v3(center, e->v2->co);
490
491 count += 2;
492
493 /* prevent adding to slot_targetmap multiple times */
496 }
497
498 if (!BLI_stack_is_empty(edge_stack)) {
499 mul_v3_fl(center, 1.0f / count);
500
501 /* snap edges to a point. for initial testing purposes anyway */
502 e = *(BMEdge **)BLI_stack_peek(edge_stack);
503 v_tar = e->v1;
504
505 while (!BLI_stack_is_empty(edge_stack)) {
506 uint j;
507 BLI_stack_pop(edge_stack, &e);
508
509 for (j = 0; j < 2; j++) {
510 BMVert *v_src = *((&e->v1) + j);
511
512 copy_v3_v3(v_src->co, center);
513 if ((v_src != v_tar) && !BM_elem_flag_test(v_src, BM_ELEM_TAG)) {
515 BMO_slot_map_elem_insert(&weldop, slot_targetmap, v_src, v_tar);
516 }
517 }
518 }
519 }
520 }
521
522 BLI_stack_free(edge_stack);
523
524 BMO_op_exec(bm, &weldop);
525 BMO_op_finish(bm, &weldop);
526
527 BMW_end(&walker);
528}
529
530/* uv collapse function */
531static void bmo_collapsecon_do_layer(BMesh *bm, const int layer, const short oflag)
532{
533 const int type = bm->ldata.layers[layer].type;
534 const int offset = bm->ldata.layers[layer].offset;
535 BMIter iter, liter;
536 BMFace *f;
537 BMLoop *l, *l2;
538 BMWalker walker;
539 BLI_Stack *block_stack;
541
542 BMW_init(&walker,
543 bm,
546 oflag,
548 BMW_FLAG_NOP, /* no need to use BMW_FLAG_TEST_HIDDEN, already marked data */
549 layer);
550
551 block_stack = BLI_stack_new(sizeof(void *), __func__);
552
553 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
554 BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
555 if (BMO_edge_flag_test(bm, l->e, oflag)) {
556 /* walk */
557 BLI_assert(BLI_stack_is_empty(block_stack));
558
560 for (l2 = static_cast<BMLoop *>(BMW_begin(&walker, l)); l2;
561 l2 = static_cast<BMLoop *>(BMW_step(&walker)))
562 {
563 void *block = BM_ELEM_CD_GET_VOID_P(l2, offset);
564 CustomData_data_dominmax(eCustomDataType(type), block, &min, &max);
565 BLI_stack_push(block_stack, &block);
566 }
567
568 if (!BLI_stack_is_empty(block_stack)) {
570 CustomData_data_multiply(eCustomDataType(type), &max, 0.5f);
572
573 /* Snap custom-data (UV, vertex-colors) points to their centroid. */
574 while (!BLI_stack_is_empty(block_stack)) {
575 void *block;
576 BLI_stack_pop(block_stack, &block);
578 }
579 }
580 }
581 }
582 }
583
584 BLI_stack_free(block_stack);
585
586 BMW_end(&walker);
587}
588
590{
591 const short oflag = EDGE_MARK;
592 int i;
593
594/* Check flags don't change once set. */
595#ifndef NDEBUG
596 int tot_test;
597#endif
598
599 if (!CustomData_has_math(&bm->ldata)) {
600 return;
601 }
602
604
605#ifndef NDEBUG
607#endif
608
609 for (i = 0; i < bm->ldata.totlayer; i++) {
612 }
613 }
614
615#ifndef NDEBUG
617#endif
618}
619
621 BMOperator *op,
622 BMOperator *optarget,
623 BMOpSlot *optarget_slot)
624{
625 const BMOpSlot *slot_verts = BMO_slot_get(op->slots_in, "verts");
626 BMVert *const *verts = (BMVert **)slot_verts->data.buf;
627 const int verts_len = slot_verts->len;
628
629 bool has_keep_vert = false;
630 bool found_duplicates = false;
631
632 const float dist = BMO_slot_float_get(op->slots_in, "dist");
633
634 /* Test whether keep_verts arg exists and is non-empty */
635 if (BMO_slot_exists(op->slots_in, "keep_verts")) {
636 BMOIter oiter;
637 has_keep_vert = BMO_iter_new(&oiter, op->slots_in, "keep_verts", BM_VERT) != nullptr;
638 }
639
640 /* Flag keep_verts */
641 if (has_keep_vert) {
643 }
644
645 int *duplicates = static_cast<int *>(MEM_mallocN(sizeof(int) * verts_len, __func__));
646 {
647 KDTree_3d *tree = BLI_kdtree_3d_new(verts_len);
648 for (int i = 0; i < verts_len; i++) {
649 BLI_kdtree_3d_insert(tree, i, verts[i]->co);
650 if (has_keep_vert && BMO_vert_flag_test(bm, verts[i], VERT_KEEP)) {
651 duplicates[i] = i;
652 }
653 else {
654 duplicates[i] = -1;
655 }
656 }
657
658 BLI_kdtree_3d_balance(tree);
659 found_duplicates = BLI_kdtree_3d_calc_duplicates_fast(tree, dist, false, duplicates) != 0;
660 BLI_kdtree_3d_free(tree);
661 }
662
663 if (found_duplicates) {
664 for (int i = 0; i < verts_len; i++) {
665 BMVert *v_check = verts[i];
666 if (duplicates[i] == -1) {
667 /* NOP (others can use as target). */
668 }
669 else if (duplicates[i] == i) {
670 /* Keep (others can use as target). */
671 }
672 else {
673 BMVert *v_other = verts[duplicates[i]];
674 BLI_assert(ELEM(duplicates[duplicates[i]], -1, duplicates[i]));
675 BMO_slot_map_elem_insert(optarget, optarget_slot, v_check, v_other);
676 }
677 }
678 }
679
680 MEM_freeN(duplicates);
681}
682
684{
685 BMOperator weldop;
686 BMOpSlot *slot_targetmap;
687
688 BMO_op_init(bm, &weldop, op->flag, "weld_verts");
689 slot_targetmap = BMO_slot_get(weldop.slots_in, "targetmap");
690 bmesh_find_doubles_common(bm, op, &weldop, slot_targetmap);
691 BMO_op_exec(bm, &weldop);
692 BMO_op_finish(bm, &weldop);
693}
694
696{
697 BMOpSlot *slot_targetmap_out;
698 slot_targetmap_out = BMO_slot_get(op->slots_out, "targetmap.out");
699 bmesh_find_doubles_common(bm, op, op, slot_targetmap_out);
700}
CustomData interface, see also DNA_customdata_types.h.
void CustomData_data_initminmax(eCustomDataType type, void *min, void *max)
bool CustomData_layer_has_math(const CustomData *data, int layer_n)
void CustomData_data_copy_value(eCustomDataType type, const void *source, void *dest)
void CustomData_bmesh_copy_block(CustomData &data, void *src_block, void **dst_block)
void CustomData_data_dominmax(eCustomDataType type, const void *data, void *min, void *max)
void CustomData_data_multiply(eCustomDataType type, void *data, float fac)
void CustomData_data_add(eCustomDataType type, void *data1, const void *data2)
bool CustomData_has_math(const CustomData *data)
#define BLI_array_alloca(arr, realsize)
Definition BLI_alloca.h:25
#define BLI_assert(a)
Definition BLI_assert.h:50
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
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
A KD-tree for nearest neighbor search.
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
void BLI_stack_pop(BLI_Stack *stack, void *dst) ATTR_NONNULL()
Definition stack.c:137
void BLI_stack_push(BLI_Stack *stack, const void *src) ATTR_NONNULL()
Definition stack.c:131
bool BLI_stack_is_empty(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition stack.c:249
void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL()
Definition stack.c:96
void * BLI_stack_peek(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition stack.c:168
#define BLI_stack_new(esize, descr)
unsigned int uint
#define UNLIKELY(x)
#define ELEM(...)
#define STACK_CLEAR(stack)
#define STACK_PUSH(stack, val)
#define STACK_DECLARE(stack)
#define STACK_SIZE(stack)
#define STACK_INIT(stack, stack_num)
Read Guarded memory(de)allocation.
@ BM_ELEM_HIDDEN
@ BM_ELEM_TAG
#define BM_FACE_FIRST_LOOP(p)
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMVert *src, BMVert *dst)
void bmesh_face_swap_data(BMFace *f_a, BMFace *f_b)
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)
BMEdge * BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag)
Main function for creating a new edge.
@ BM_CREATE_NOP
Definition bmesh_core.hh:24
void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type)
#define BM_elem_flag_merge_ex(ele_a, ele_b, hflag_and)
#define BM_elem_flag_disable(ele, hflag)
#define BM_elem_flag_test(ele, hflag)
#define BM_elem_flag_enable(ele, hflag)
int BM_iter_mesh_count_flag(const char itype, BMesh *bm, const char hflag, const bool value)
Mesh Iter Flag Count.
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_VERT
@ BM_LOOPS_OF_FACE
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_select_history_merge_from_targetmap(BMesh *bm, GHash *vert_map, GHash *edge_map, GHash *face_map, const bool use_chain)
BMFace * BM_face_split(BMesh *bm, BMFace *f, BMLoop *l_a, BMLoop *l_b, BMLoop **r_l, BMEdge *example, const bool no_double)
Face Split.
#define BM_EDGE
#define BM_VERT
void * BMO_slot_buffer_get_single(BMOpSlot *slot)
void BMO_slot_buffer_flag_enable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, short oflag)
BMO_FLAG_BUFFER.
#define BMO_vert_flag_disable(bm, e, oflag)
#define BMO_edge_flag_test(bm, e, oflag)
void BMO_slot_vec_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, float r_vec[3])
#define BMO_edge_flag_enable(bm, e, oflag)
float BMO_slot_float_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
#define BMO_vert_flag_enable(bm, e, oflag)
void * BMO_iter_new(BMOIter *iter, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char restrictmask)
New Iterator.
BMOpSlot * BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
BMESH OPSTACK GET SLOT.
void BMO_op_exec(BMesh *bm, BMOperator *op)
BMESH OPSTACK EXEC OP.
#define BMO_face_flag_enable(bm, e, oflag)
void BMO_op_init(BMesh *bm, BMOperator *op, int flag, const char *opname)
BMESH OPSTACK INIT OP.
#define BMO_ITER(ele, iter, slot_args, slot_name, restrict_flag)
#define BMO_vert_flag_test(bm, e, oflag)
void BMO_op_finish(BMesh *bm, BMOperator *op)
BMESH OPSTACK FINISH OP.
bool BMO_op_callf(BMesh *bm, int flag, const char *fmt,...)
@ DEL_ONLYTAGGED
#define BMO_vert_flag_test_bool(bm, e, oflag)
#define BMO_face_flag_disable(bm, e, oflag)
bool BMO_slot_exists(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
BMESH OPSTACK HAS SLOT.
bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
BLI_INLINE void BMO_slot_map_elem_insert(BMOperator *op, BMOpSlot *slot, const void *element, void *val)
ATTR_WARN_UNUSED_RESULT const BMFlagLayer const short oflag
ATTR_WARN_UNUSED_RESULT const BMFlagLayer * oflags
BMFace * BM_face_exists(BMVert *const *varr, int len)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
int BM_vert_face_count(const BMVert *v)
BMLoop * BM_face_vert_share_loop(BMFace *f, BMVert *v)
Return the Loop Shared by Face and Vertex.
BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b) 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 * BMW_begin(BMWalker *walker, void *start)
void BMW_init(BMWalker *walker, BMesh *bm, int type, short mask_vert, short mask_edge, short mask_face, BMWFlag flag, int layer)
Init Walker.
void BMW_end(BMWalker *walker)
End Walker.
void * BMW_step(BMWalker *walker)
Step Walker.
#define BMW_NIL_LAY
@ BMW_FLAG_NOP
#define BMW_MASK_NOP
@ BMW_VERT_SHELL
@ BMW_LOOPDATA_ISLAND
#define ELE_DEL
static void bmesh_find_doubles_common(BMesh *bm, BMOperator *op, BMOperator *optarget, BMOpSlot *optarget_slot)
#define VERT_KEEP
void bmo_collapse_exec(BMesh *bm, BMOperator *op)
void bmo_average_vert_facedata_exec(BMesh *bm, BMOperator *op)
void bmo_remove_doubles_exec(BMesh *bm, BMOperator *op)
#define LOOP_MAP_VERT_INIT(l_init, v_map, is_del)
static void remdoubles_splitface(BMFace *f, BMesh *bm, BMOperator *op, BMOpSlot *slot_targetmap)
static BMFace * remdoubles_createface(BMesh *bm, BMFace *f, BMOpSlot *slot_targetmap, bool *r_created)
void bmo_pointmerge_exec(BMesh *bm, BMOperator *op)
#define EDGE_MARK
void bmo_pointmerge_facedata_exec(BMesh *bm, BMOperator *op)
#define EDGE_COL
void bmo_find_doubles_exec(BMesh *bm, BMOperator *op)
static void bmo_collapsecon_do_layer(BMesh *bm, const int layer, const short oflag)
#define VERT_IN_FACE
void bmo_collapse_uvs_exec(BMesh *bm, BMOperator *op)
void bmo_weld_verts_exec(BMesh *bm, BMOperator *op)
KDTree_3d * tree
static float verts[][3]
int count
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
#define min(a, b)
Definition sort.c:32
void * data
BMHeader head
struct BMVert * v
struct BMEdge * e
struct BMLoop * next
union BMOpSlot::@139 data
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
float co[3]
ListBase selected
uint use_toolflags
BMFace * act_face
CustomData ldata
CustomDataLayer * layers
float max