Blender V4.3
bmo_dissolve.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_math_vector.h"
14#include "BLI_stack.h"
15#include "BLI_vector.hh"
16
17#include "bmesh.hh"
18#include "bmesh_tools.hh"
19
21
22using blender::Vector;
23
24/* ***_ISGC: mark for garbage-collection */
25
26#define FACE_MARK 1
27#define FACE_ORIG 2
28#define FACE_NEW 4
29#define FACE_TAG 8
30
31#define EDGE_MARK 1
32#define EDGE_TAG 2
33#define EDGE_ISGC 8
34
35#define VERT_MARK 1
36#define VERT_MARK_PAIR 4
37#define VERT_TAG 2
38#define VERT_ISGC 8
39#define VERT_MARK_TEAR 16
40
42{
43 BMWalker regwalker;
44 BMIter liter2;
45 BMLoop *l2, *l3;
46 BMFace *f2;
47
48 /* Checks if there are any unmarked boundary edges in the face region. */
49
50 BMW_init(&regwalker,
51 bm,
58
59 for (f2 = static_cast<BMFace *>(BMW_begin(&regwalker, f)); f2;
60 f2 = static_cast<BMFace *>(BMW_step(&regwalker)))
61 {
62 BM_ITER_ELEM (l2, &liter2, f2, BM_LOOPS_OF_FACE) {
63 l3 = l2->radial_next;
65 if (!BMO_edge_flag_test(bm, l2->e, EDGE_MARK)) {
66 return false;
67 }
68 }
69 }
70 }
71 BMW_end(&regwalker);
72
73 return true;
74}
75
76static void bm_face_split(BMesh *bm, const short oflag, bool use_edge_delete)
77{
78 BLI_Stack *edge_delete_verts;
79 BMIter iter;
80 BMVert *v;
81
82 if (use_edge_delete) {
83 edge_delete_verts = BLI_stack_new(sizeof(BMVert *), __func__);
84 }
85
88 if (BM_vert_is_edge_pair(v) == false) {
89 BMIter liter;
90 BMLoop *l;
91 BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
92 if (l->f->len > 3) {
93 if (BMO_vert_flag_test(bm, l->next->v, oflag) == 0 &&
95 {
96 BM_face_split(bm, l->f, l->next, l->prev, nullptr, nullptr, true);
97 }
98 }
99 }
100
101 if (use_edge_delete) {
102 BLI_stack_push(edge_delete_verts, &v);
103 }
104 }
105 }
106 }
107
108 if (use_edge_delete) {
109 while (!BLI_stack_is_empty(edge_delete_verts)) {
110 /* remove surrounding edges & faces */
111 BLI_stack_pop(edge_delete_verts, &v);
112 while (v->e) {
113 BM_edge_kill(bm, v->e);
114 }
115 }
116 BLI_stack_free(edge_delete_verts);
117 }
118}
119
121{
122 BMOIter oiter;
123 BMFace *f;
124 BMFace *act_face = bm->act_face;
125 BMWalker regwalker;
126
127 const bool use_verts = BMO_slot_bool_get(op->slots_in, "use_verts");
128
129 if (use_verts) {
130 /* tag verts that start out with only 2 edges,
131 * don't remove these later */
132 BMIter viter;
133 BMVert *v;
134
135 BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
137 }
138 }
139
141
142 /* List of regions which are themselves a list of faces. */
144
145 /* collect region */
146 BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) {
147 if (!BMO_face_flag_test(bm, f, FACE_TAG)) {
148 continue;
149 }
150
151 BMW_init(&regwalker,
152 bm,
156 FACE_MARK,
157 /* no need to check BMW_FLAG_TEST_HIDDEN, faces are already marked by the bmo. */
160
161 /* Check there are at least two faces before creating the array. */
162 BMFace *faces_init[2];
163 if ((faces_init[0] = static_cast<BMFace *>(BMW_begin(&regwalker, f))) &&
164 (faces_init[1] = static_cast<BMFace *>(BMW_step(&regwalker))))
165 {
167 faces.append(faces_init[0]);
168 faces.append(faces_init[1]);
169
170 BMFace *f_iter;
171 while ((f_iter = static_cast<BMFace *>(BMW_step(&regwalker)))) {
172 faces.append(f_iter);
173 }
174
175 for (BMFace *face : faces) {
178 }
179
180 regions.append_as(std::move(faces));
181 }
182
183 BMW_end(&regwalker);
184 }
185
186 /* track how many faces we should end up with */
187 int totface_target = bm->totface;
188
189 for (Vector<BMFace *> &faces : regions) {
190 const int64_t faces_len = faces.size();
191
192 BMFace *f_new = BM_faces_join(bm, faces.data(), faces_len, true);
193 if (f_new != nullptr) {
194 /* Maintain the active face. */
195 if (act_face && bm->act_face == nullptr) {
196 bm->act_face = f_new;
197 }
198 totface_target -= faces_len - 1;
199
200 /* If making the new face failed (e.g. overlapping test)
201 * un-mark the original faces for deletion. */
204 }
205 else {
206 /* NOTE: prior to 3.0 this raised an error: "Could not create merged face".
207 * Change behavior since it's not useful to fail entirely when a single face-group
208 * can't be merged into one face. Continue with other face groups instead.
209 *
210 * This could optionally do a partial merge, where some faces are joined. */
211
212 /* Prevent these faces from being removed. */
213 for (BMFace *face : faces) {
215 }
216 }
217 }
218
219 /* Typically no faces need to be deleted */
220 if (totface_target != bm->totface) {
221 BMO_op_callf(bm, op->flag, "delete geom=%ff context=%i", FACE_ORIG, DEL_FACES);
222 }
223
224 if (use_verts) {
225 BMIter viter;
226 BMVert *v, *v_next;
227
228 BM_ITER_MESH_MUTABLE (v, v_next, &viter, bm, BM_VERTS_OF_MESH) {
230 if (BM_vert_is_edge_pair(v)) {
231 BM_vert_collapse_edge(bm, v->e, v, true, true, true);
232 }
233 }
234 }
235 }
236
238
240}
241
243{
244 // BMOperator fop;
245 BMFace *act_face = bm->act_face;
246 BMOIter eiter;
247 BMIter iter;
248 BMEdge *e, *e_next;
249 BMVert *v, *v_next;
250
251 const bool use_verts = BMO_slot_bool_get(op->slots_in, "use_verts");
252 const bool use_face_split = BMO_slot_bool_get(op->slots_in, "use_face_split");
253
254 if (use_face_split) {
256
257 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
258 BMIter itersub;
259 int untag_count = 0;
260 BM_ITER_ELEM (e, &itersub, v, BM_EDGES_OF_VERT) {
262 untag_count++;
263 }
264 }
265
266 /* check that we have 2 edges remaining after dissolve */
267 if (untag_count <= 2) {
269 }
270 }
271
272 bm_face_split(bm, VERT_TAG, false);
273 }
274
275 if (use_verts) {
276 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
278 }
279 }
280
281 /* tag all verts/edges connected to faces */
282 BMO_ITER (e, &eiter, op->slots_in, "edges", BM_EDGE) {
283 BMFace *f_pair[2];
284 if (BM_edge_face_pair(e, &f_pair[0], &f_pair[1])) {
285 uint j;
286 for (j = 0; j < 2; j++) {
287 BMLoop *l_first, *l_iter;
288 l_iter = l_first = BM_FACE_FIRST_LOOP(f_pair[j]);
289 do {
292 } while ((l_iter = l_iter->next) != l_first);
293 }
294 }
295 }
296
297 BMO_ITER (e, &eiter, op->slots_in, "edges", BM_EDGE) {
298 BMLoop *l_a, *l_b;
299 if (BM_edge_loop_pair(e, &l_a, &l_b)) {
300 BMFace *f_new;
301
302 /* join faces */
303 f_new = BM_faces_join_pair(bm, l_a, l_b, false);
304 if (f_new && BM_face_find_double(f_new)) {
305 BM_face_kill(bm, f_new);
306 f_new = nullptr;
307 }
308
309 if (f_new) {
310 /* maintain active face */
311 if (act_face && bm->act_face == nullptr) {
312 bm->act_face = f_new;
313 }
314 }
315 }
316 }
317
318 /* Cleanup geometry (#BM_faces_join_pair, but it removes geometry we're looping on)
319 * so do this in a separate pass instead. */
320 BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) {
321 if ((e->l == nullptr) && BMO_edge_flag_test(bm, e, EDGE_ISGC)) {
322 BM_edge_kill(bm, e);
323 }
324 }
325 BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) {
326 if ((v->e == nullptr) && BMO_vert_flag_test(bm, v, VERT_ISGC)) {
327 BM_vert_kill(bm, v);
328 }
329 }
330 /* done with cleanup */
331
332 if (use_verts) {
333 BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) {
335 if (BM_vert_is_edge_pair(v)) {
336 BM_vert_collapse_edge(bm, v->e, v, true, true, true);
337 }
338 }
339 }
340 }
341}
342
344{
345 BMOIter oiter;
346 BMIter iter;
347 BMVert *v, *v_next;
348 BMEdge *e, *e_next;
349 BMFace *act_face = bm->act_face;
350
351 const bool use_face_split = BMO_slot_bool_get(op->slots_in, "use_face_split");
352 const bool use_boundary_tear = BMO_slot_bool_get(op->slots_in, "use_boundary_tear");
353
354 BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
356 }
357
358 if (use_face_split) {
359 bm_face_split(bm, VERT_MARK, false);
360 }
361
362 if (use_boundary_tear) {
363 BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
364 if (!BM_vert_is_edge_pair(v)) {
365 BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
366 if (BM_edge_is_boundary(e)) {
368 break;
369 }
370 }
371 }
372 }
373
375 }
376
377 BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
378 BMIter itersub;
379 BMLoop *l_first;
380 BMEdge *e_first = nullptr;
381 BM_ITER_ELEM (l_first, &itersub, v, BM_LOOPS_OF_VERT) {
382 BMLoop *l_iter;
383 l_iter = l_first;
384 do {
387 } while ((l_iter = l_iter->next) != l_first);
388
389 e_first = l_first->e;
390 }
391
392 /* important e_first won't be deleted */
393 if (e_first) {
394 e = e_first;
395 do {
396 e_next = BM_DISK_EDGE_NEXT(e, v);
397 if (BM_edge_is_wire(e)) {
398 BM_edge_kill(bm, e);
399 }
400 } while ((e = e_next) != e_first);
401 }
402 }
403
404 BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
405 /* tag here so we avoid feedback loop (checking topology as we edit) */
406 if (BM_vert_is_edge_pair(v)) {
408 }
409 }
410
411 BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
412 BMIter itersub;
413
415 BM_ITER_ELEM (e, &itersub, v, BM_EDGES_OF_VERT) {
416 BMLoop *l_a, *l_b;
417 if (BM_edge_loop_pair(e, &l_a, &l_b)) {
418 BMFace *f_new;
419
420 /* join faces */
421 f_new = BM_faces_join_pair(bm, l_a, l_b, false);
422 if (f_new && BM_face_find_double(f_new)) {
423 BM_face_kill(bm, f_new);
424 f_new = nullptr;
425 }
426
427 if (f_new) {
428 /* maintain active face */
429 if (act_face && bm->act_face == nullptr) {
430 bm->act_face = f_new;
431 }
432 }
433 }
434 }
435 }
436 }
437
438 /* Cleanup geometry (#BM_faces_join_pair, but it removes geometry we're looping on)
439 * so do this in a separate pass instead. */
440 BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) {
441 if ((e->l == nullptr) && BMO_edge_flag_test(bm, e, EDGE_ISGC)) {
442 BM_edge_kill(bm, e);
443 }
444 }
445
446 /* final cleanup */
447 BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
448 if (BM_vert_is_edge_pair(v)) {
449 BM_vert_collapse_edge(bm, v->e, v, false, true, true);
450 }
451 }
452
453 BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) {
454 if ((v->e == nullptr) && BMO_vert_flag_test(bm, v, VERT_ISGC)) {
455 BM_vert_kill(bm, v);
456 }
457 }
458 /* done with cleanup */
459}
460
462{
463 BMOpSlot *einput = BMO_slot_get(op->slots_in, "edges");
464 BMOpSlot *vinput = BMO_slot_get(op->slots_in, "verts");
465 const float angle_max = M_PI_2;
466 const float angle_limit = min_ff(angle_max, BMO_slot_float_get(op->slots_in, "angle_limit"));
467 const bool do_dissolve_boundaries = BMO_slot_bool_get(op->slots_in, "use_dissolve_boundaries");
468 const BMO_Delimit delimit = BMO_Delimit(BMO_slot_int_get(op->slots_in, "delimit"));
469
471 angle_limit,
472 do_dissolve_boundaries,
473 delimit,
474 (BMVert **)BMO_SLOT_AS_BUFFER(vinput),
475 vinput->len,
476 (BMEdge **)BMO_SLOT_AS_BUFFER(einput),
477 einput->len,
478 FACE_NEW);
479
481}
482
483#define EDGE_MARK 1
484#define EDGE_COLLAPSE 2
485
486static void bm_mesh_edge_collapse_flagged(BMesh *bm, const int flag, const short oflag)
487{
488 BMO_op_callf(bm, flag, "collapse edges=%fe uvs=%b", oflag, true);
489}
490
492{
493 const float dist = BMO_slot_float_get(op->slots_in, "dist");
494 const float dist_sq = dist * dist;
495
496 bool found;
497 BMIter eiter;
498 BMEdge *e;
499
501
502 /* collapse zero length edges, this accounts for zero area faces too */
503 found = false;
504 BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
506 if (BM_edge_calc_length_squared(e) < dist_sq) {
508 found = true;
509 }
510 }
511
512 /* clear all loop tags (checked later) */
513 if (e->l) {
514 BMLoop *l_iter, *l_first;
515 l_iter = l_first = e->l;
516 do {
518 } while ((l_iter = l_iter->radial_next) != l_first);
519 }
520 }
521
522 if (found) {
524 }
525
526 /* clip degenerate ears from the face */
527 found = false;
528 BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
529 if (e->l && BMO_edge_flag_test(bm, e, EDGE_MARK)) {
530 BMLoop *l_iter, *l_first;
531 l_iter = l_first = e->l;
532 do {
533 if (
534 /* check the loop hasn't already been tested (and flag not to test again) */
535 !BM_elem_flag_test(l_iter, BM_ELEM_TAG) &&
536 ((void)BM_elem_flag_enable(l_iter, BM_ELEM_TAG),
537
538 /* check we're marked to tested (radial edge already tested) */
539 BMO_edge_flag_test(bm, l_iter->prev->e, EDGE_MARK) &&
540
541 /* check edges are not already going to be collapsed */
542 !BMO_edge_flag_test(bm, l_iter->e, EDGE_COLLAPSE) &&
544 {
545 /* test if the faces loop (ear) is degenerate */
546 float dir_prev[3], len_prev;
547 float dir_next[3], len_next;
548
549 sub_v3_v3v3(dir_prev, l_iter->prev->v->co, l_iter->v->co);
550 sub_v3_v3v3(dir_next, l_iter->next->v->co, l_iter->v->co);
551
552 len_prev = normalize_v3(dir_prev);
553 len_next = normalize_v3(dir_next);
554
555 if ((len_v3v3(dir_prev, dir_next) * min_ff(len_prev, len_next)) <= dist) {
556 bool reset = false;
557
558 if (fabsf(len_prev - len_next) <= dist) {
559 /* both edges the same length */
560 if (l_iter->f->len == 3) {
561 /* ideally this would have been discovered with short edge test above */
563 found = true;
564 }
565 else {
566 /* add a joining edge and tag for removal */
567 BMLoop *l_split;
568 if (BM_face_split(
569 bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, nullptr, true))
570 {
572 found = true;
573 reset = true;
574 }
575 }
576 }
577 else if (len_prev < len_next) {
578 /* split 'l_iter->e', then join the vert with next */
579 BMVert *v_new;
580 BMEdge *e_new;
581 BMLoop *l_split;
582 v_new = BM_edge_split(bm, l_iter->e, l_iter->v, &e_new, len_prev / len_next);
583 BLI_assert(v_new == l_iter->next->v);
584 (void)v_new;
585 if (BM_face_split(
586 bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, nullptr, true))
587 {
589 found = true;
590 }
591 reset = true;
592 }
593 else if (len_next < len_prev) {
594 /* split 'l_iter->prev->e', then join the vert with next */
595 BMVert *v_new;
596 BMEdge *e_new;
597 BMLoop *l_split;
598 v_new = BM_edge_split(bm, l_iter->prev->e, l_iter->v, &e_new, len_next / len_prev);
599 BLI_assert(v_new == l_iter->prev->v);
600 (void)v_new;
601 if (BM_face_split(
602 bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, nullptr, true))
603 {
605 found = true;
606 }
607 reset = true;
608 }
609
610 if (reset) {
611 /* we can't easily track where we are on the radial edge, reset! */
612 l_first = l_iter;
613 }
614 }
615 }
616 } while ((l_iter = l_iter->radial_next) != l_first);
617 }
618 }
619
620 if (found) {
622 }
623}
#define BLI_assert(a)
Definition BLI_assert.h:50
MINLINE float min_ff(float a, float b)
#define M_PI_2
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float normalize_v3(float n[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
#define BLI_stack_new(esize, descr)
unsigned int uint
#define UNUSED_FUNCTION(x)
Read Guarded memory(de)allocation.
#define BM_DISK_EDGE_NEXT(e, v)
@ BM_ELEM_TAG
#define BM_FACE_FIRST_LOOP(p)
BMFace * BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
Join Connected Faces.
void BM_vert_kill(BMesh *bm, BMVert *v)
void BM_face_kill(BMesh *bm, BMFace *f)
void BM_edge_kill(BMesh *bm, BMEdge *e)
void BM_mesh_decimate_dissolve_ex(BMesh *bm, float angle_limit, bool do_dissolve_boundaries, BMO_Delimit delimit, BMVert **vinput_arr, int vinput_len, BMEdge **einput_arr, int einput_len, short oflag_out)
@ BMO_ERROR_FATAL
bool BMO_error_occurred_at_level(BMesh *bm, eBMOpErrorLevel level)
#define BM_elem_flag_disable(ele, hflag)
#define BM_elem_flag_test(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)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_LOOPS_OF_VERT
@ BM_EDGES_OF_VERT
@ BM_LOOPS_OF_FACE
#define BM_ITER_MESH_MUTABLE(ele, ele_next, iter, bm, itype)
ATTR_WARN_UNUSED_RESULT BMesh * bm
BMVert * BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
Edge Split.
BMEdge * BM_vert_collapse_edge(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool do_del, const bool kill_degenerate_faces, const bool kill_duplicate_faces)
Vert Collapse Faces.
BMFace * BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del)
Faces Join Pair.
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_FACE
#define BM_EDGE
#define BM_VERT
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_edge_flag_test(bm, e, oflag)
#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)
BMOpSlot * BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
BMESH OPSTACK GET SLOT.
#define BMO_vert_flag_set(bm, e, oflag, val)
#define BMO_SLOT_AS_BUFFER(slot)
void BMO_slot_buffer_from_enabled_flag(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, short oflag)
#define BMO_face_flag_enable(bm, e, oflag)
#define BMO_ITER(ele, iter, slot_args, slot_name, restrict_flag)
#define BMO_vert_flag_test(bm, e, oflag)
int BMO_slot_int_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
bool BMO_op_callf(BMesh *bm, int flag, const char *fmt,...)
#define BMO_face_flag_disable(bm, e, oflag)
#define BMO_face_flag_test(bm, e, oflag)
bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
ATTR_WARN_UNUSED_RESULT const BMFlagLayer const short oflag
bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb)
float BM_edge_calc_length_squared(const BMEdge *e)
bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb)
BMFace * BM_face_find_double(BMFace *f)
bool BM_vert_is_edge_pair(const BMVert *v)
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) 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 BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMLoop * l_b
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_ISLAND_MANIFOLD
@ BMW_ISLAND
#define VERT_MARK
void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
#define VERT_MARK_TEAR
#define FACE_ORIG
#define FACE_NEW
void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op)
static void bm_mesh_edge_collapse_flagged(BMesh *bm, const int flag, const short oflag)
#define FACE_TAG
static bool UNUSED_FUNCTION check_hole_in_region(BMesh *bm, BMFace *f)
void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
#define VERT_TAG
#define FACE_MARK
#define EDGE_TAG
#define EDGE_ISGC
void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op)
#define EDGE_MARK
#define VERT_ISGC
void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op)
static void bm_face_split(BMesh *bm, const short oflag, bool use_edge_delete)
#define EDGE_COLLAPSE
#define VERT_MARK_PAIR
void reset()
clear internal cached data and reset random seed
void append(const T &value)
#define fabsf(x)
static char faces[256]
__int64 int64_t
Definition stdint.h:89
struct BMVert * v
struct BMEdge * e
struct BMLoop * radial_next
struct BMLoop * prev
struct BMFace * f
struct BMLoop * next
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
float co[3]
struct BMEdge * e
BMFace * act_face
int totface
uint8_t flag
Definition wm_window.cc:138