Blender  V2.93
bmo_dissolve.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
23 #include "MEM_guardedalloc.h"
24 
25 #include "BLI_array.h"
26 #include "BLI_math.h"
27 #include "BLI_stack.h"
28 
29 #include "bmesh.h"
30 #include "bmesh_tools.h"
31 
33 
34 /* ***_ISGC: mark for garbage-collection */
35 
36 #define FACE_MARK 1
37 #define FACE_ORIG 2
38 #define FACE_NEW 4
39 #define FACE_TAG 8
40 
41 #define EDGE_MARK 1
42 #define EDGE_TAG 2
43 #define EDGE_ISGC 8
44 
45 #define VERT_MARK 1
46 #define VERT_MARK_PAIR 4
47 #define VERT_TAG 2
48 #define VERT_ISGC 8
49 #define VERT_MARK_TEAR 16
50 
52 {
53  BMWalker regwalker;
54  BMIter liter2;
55  BMLoop *l2, *l3;
56  BMFace *f2;
57 
58  /* Checks if there are any unmarked boundary edges in the face region. */
59 
60  BMW_init(&regwalker,
61  bm,
62  BMW_ISLAND,
65  FACE_MARK,
67  BMW_NIL_LAY);
68 
69  for (f2 = BMW_begin(&regwalker, f); f2; f2 = BMW_step(&regwalker)) {
70  BM_ITER_ELEM (l2, &liter2, f2, BM_LOOPS_OF_FACE) {
71  l3 = l2->radial_next;
73  if (!BMO_edge_flag_test(bm, l2->e, EDGE_MARK)) {
74  return false;
75  }
76  }
77  }
78  }
79  BMW_end(&regwalker);
80 
81  return true;
82 }
83 
84 static void bm_face_split(BMesh *bm, const short oflag, bool use_edge_delete)
85 {
86  BLI_Stack *edge_delete_verts;
87  BMIter iter;
88  BMVert *v;
89 
90  if (use_edge_delete) {
91  edge_delete_verts = BLI_stack_new(sizeof(BMVert *), __func__);
92  }
93 
94  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
95  if (BMO_vert_flag_test(bm, v, oflag)) {
96  if (BM_vert_is_edge_pair(v) == false) {
97  BMIter liter;
98  BMLoop *l;
99  BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
100  if (l->f->len > 3) {
101  if (BMO_vert_flag_test(bm, l->next->v, oflag) == 0 &&
102  BMO_vert_flag_test(bm, l->prev->v, oflag) == 0) {
103  BM_face_split(bm, l->f, l->next, l->prev, NULL, NULL, true);
104  }
105  }
106  }
107 
108  if (use_edge_delete) {
109  BLI_stack_push(edge_delete_verts, &v);
110  }
111  }
112  }
113  }
114 
115  if (use_edge_delete) {
116  while (!BLI_stack_is_empty(edge_delete_verts)) {
117  /* remove surrounding edges & faces */
118  BLI_stack_pop(edge_delete_verts, &v);
119  while (v->e) {
120  BM_edge_kill(bm, v->e);
121  }
122  }
123  BLI_stack_free(edge_delete_verts);
124  }
125 }
126 
128 {
129  BMOIter oiter;
130  BMFace *f;
131  BMFace ***regions = NULL;
132  BMFace **faces = NULL;
133  BLI_array_declare(regions);
135  BMFace *act_face = bm->act_face;
136  BMWalker regwalker;
137  int i;
138 
139  const bool use_verts = BMO_slot_bool_get(op->slots_in, "use_verts");
140 
141  if (use_verts) {
142  /* tag verts that start out with only 2 edges,
143  * don't remove these later */
144  BMIter viter;
145  BMVert *v;
146 
147  BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
149  }
150  }
151 
153 
154  /* collect region */
155  BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) {
156  BMFace *f_iter;
157  if (!BMO_face_flag_test(bm, f, FACE_TAG)) {
158  continue;
159  }
160 
162  faces = NULL; /* Forces different allocation. */
163 
164  BMW_init(&regwalker,
165  bm,
167  BMW_MASK_NOP,
168  BMW_MASK_NOP,
169  FACE_MARK,
170  /* no need to check BMW_FLAG_TEST_HIDDEN, faces are already marked by the bmo. */
171  BMW_FLAG_NOP,
172  BMW_NIL_LAY);
173 
174  for (f_iter = BMW_begin(&regwalker, f); f_iter; f_iter = BMW_step(&regwalker)) {
175  BLI_array_append(faces, f_iter);
176  }
177  BMW_end(&regwalker);
178 
179  for (i = 0; i < BLI_array_len(faces); i++) {
180  f_iter = faces[i];
183  }
184 
185  if (BMO_error_occurred(bm)) {
188  goto cleanup;
189  }
190 
192  BLI_array_append(regions, faces);
193  }
194 
195  /* track how many faces we should end up with */
196  int totface_target = bm->totface;
197 
198  for (i = 0; i < BLI_array_len(regions); i++) {
199  BMFace *f_new;
200  int tot = 0;
201 
202  faces = regions[i];
203  if (!faces[0]) {
205  bm, op, BMERR_DISSOLVEFACES_FAILED, "Could not find boundary of dissolve region");
206  goto cleanup;
207  }
208 
209  while (faces[tot]) {
210  tot++;
211  }
212 
213  f_new = BM_faces_join(bm, faces, tot, true);
214 
215  if (f_new) {
216  /* maintain active face */
217  if (act_face && bm->act_face == NULL) {
218  bm->act_face = f_new;
219  }
220  totface_target -= tot - 1;
221  }
222  else {
223  BMO_error_raise(bm, op, BMERR_DISSOLVEFACES_FAILED, "Could not create merged face");
224  goto cleanup;
225  }
226 
227  /* if making the new face failed (e.g. overlapping test)
228  * unmark the original faces for deletion */
231  }
232 
233  /* Typically no faces need to be deleted */
234  if (totface_target != bm->totface) {
235  BMO_op_callf(bm, op->flag, "delete geom=%ff context=%i", FACE_ORIG, DEL_FACES);
236  }
237 
238  if (use_verts) {
239  BMIter viter;
240  BMVert *v, *v_next;
241 
242  BM_ITER_MESH_MUTABLE (v, v_next, &viter, bm, BM_VERTS_OF_MESH) {
243  if (BMO_vert_flag_test(bm, v, VERT_MARK)) {
244  if (BM_vert_is_edge_pair(v)) {
245  BM_vert_collapse_edge(bm, v->e, v, true, true, true);
246  }
247  }
248  }
249  }
250 
251  if (BMO_error_occurred(bm)) {
252  goto cleanup;
253  }
254 
256 
257 cleanup:
258  /* free/cleanup */
259  for (i = 0; i < BLI_array_len(regions); i++) {
260  if (regions[i]) {
261  MEM_freeN(regions[i]);
262  }
263  }
264 
265  BLI_array_free(regions);
266 }
267 
269 {
270  /* BMOperator fop; */
271  BMFace *act_face = bm->act_face;
272  BMOIter eiter;
273  BMIter iter;
274  BMEdge *e, *e_next;
275  BMVert *v, *v_next;
276 
277  const bool use_verts = BMO_slot_bool_get(op->slots_in, "use_verts");
278  const bool use_face_split = BMO_slot_bool_get(op->slots_in, "use_face_split");
279 
280  if (use_face_split) {
282 
283  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
284  BMIter itersub;
285  int untag_count = 0;
286  BM_ITER_ELEM (e, &itersub, v, BM_EDGES_OF_VERT) {
287  if (!BMO_edge_flag_test(bm, e, EDGE_TAG)) {
288  untag_count++;
289  }
290  }
291 
292  /* check that we have 2 edges remaining after dissolve */
293  if (untag_count <= 2) {
295  }
296  }
297 
298  bm_face_split(bm, VERT_TAG, false);
299  }
300 
301  if (use_verts) {
302  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
304  }
305  }
306 
307  /* tag all verts/edges connected to faces */
308  BMO_ITER (e, &eiter, op->slots_in, "edges", BM_EDGE) {
309  BMFace *f_pair[2];
310  if (BM_edge_face_pair(e, &f_pair[0], &f_pair[1])) {
311  uint j;
312  for (j = 0; j < 2; j++) {
313  BMLoop *l_first, *l_iter;
314  l_iter = l_first = BM_FACE_FIRST_LOOP(f_pair[j]);
315  do {
316  BMO_vert_flag_enable(bm, l_iter->v, VERT_ISGC);
317  BMO_edge_flag_enable(bm, l_iter->e, EDGE_ISGC);
318  } while ((l_iter = l_iter->next) != l_first);
319  }
320  }
321  }
322 
323  BMO_ITER (e, &eiter, op->slots_in, "edges", BM_EDGE) {
324  BMLoop *l_a, *l_b;
325  if (BM_edge_loop_pair(e, &l_a, &l_b)) {
326  BMFace *f_new;
327 
328  /* join faces */
329  f_new = BM_faces_join_pair(bm, l_a, l_b, false);
330  if (f_new && BM_face_find_double(f_new)) {
331  BM_face_kill(bm, f_new);
332  f_new = NULL;
333  }
334 
335  if (f_new) {
336  /* maintain active face */
337  if (act_face && bm->act_face == NULL) {
338  bm->act_face = f_new;
339  }
340  }
341  }
342  }
343 
344  /* Cleanup geometry (#BM_faces_join_pair, but it removes geometry we're looping on)
345  * so do this in a separate pass instead. */
346  BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) {
347  if ((e->l == NULL) && BMO_edge_flag_test(bm, e, EDGE_ISGC)) {
348  BM_edge_kill(bm, e);
349  }
350  }
351  BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) {
352  if ((v->e == NULL) && BMO_vert_flag_test(bm, v, VERT_ISGC)) {
353  BM_vert_kill(bm, v);
354  }
355  }
356  /* done with cleanup */
357 
358  if (use_verts) {
359  BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) {
360  if (BMO_vert_flag_test(bm, v, VERT_MARK)) {
361  if (BM_vert_is_edge_pair(v)) {
362  BM_vert_collapse_edge(bm, v->e, v, true, true, true);
363  }
364  }
365  }
366  }
367 }
368 
370 {
371  BMOIter oiter;
372  BMIter iter;
373  BMVert *v, *v_next;
374  BMEdge *e, *e_next;
375  BMFace *act_face = bm->act_face;
376 
377  const bool use_face_split = BMO_slot_bool_get(op->slots_in, "use_face_split");
378  const bool use_boundary_tear = BMO_slot_bool_get(op->slots_in, "use_boundary_tear");
379 
380  BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
382  }
383 
384  if (use_face_split) {
385  bm_face_split(bm, VERT_MARK, false);
386  }
387 
388  if (use_boundary_tear) {
389  BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
390  if (!BM_vert_is_edge_pair(v)) {
391  BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
392  if (BM_edge_is_boundary(e)) {
394  break;
395  }
396  }
397  }
398  }
399 
401  }
402 
403  BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
404  BMIter itersub;
405  BMLoop *l_first;
406  BMEdge *e_first = NULL;
407  BM_ITER_ELEM (l_first, &itersub, v, BM_LOOPS_OF_VERT) {
408  BMLoop *l_iter;
409  l_iter = l_first;
410  do {
411  BMO_vert_flag_enable(bm, l_iter->v, VERT_ISGC);
412  BMO_edge_flag_enable(bm, l_iter->e, EDGE_ISGC);
413  } while ((l_iter = l_iter->next) != l_first);
414 
415  e_first = l_first->e;
416  }
417 
418  /* important e_first won't be deleted */
419  if (e_first) {
420  e = e_first;
421  do {
422  e_next = BM_DISK_EDGE_NEXT(e, v);
423  if (BM_edge_is_wire(e)) {
424  BM_edge_kill(bm, e);
425  }
426  } while ((e = e_next) != e_first);
427  }
428  }
429 
430  BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
431  /* tag here so we avoid feedback loop (checking topology as we edit) */
432  if (BM_vert_is_edge_pair(v)) {
434  }
435  }
436 
437  BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
438  BMIter itersub;
439 
441  BM_ITER_ELEM (e, &itersub, v, BM_EDGES_OF_VERT) {
442  BMLoop *l_a, *l_b;
443  if (BM_edge_loop_pair(e, &l_a, &l_b)) {
444  BMFace *f_new;
445 
446  /* join faces */
447  f_new = BM_faces_join_pair(bm, l_a, l_b, false);
448  if (f_new && BM_face_find_double(f_new)) {
449  BM_face_kill(bm, f_new);
450  f_new = NULL;
451  }
452 
453  if (f_new) {
454  /* maintain active face */
455  if (act_face && bm->act_face == NULL) {
456  bm->act_face = f_new;
457  }
458  }
459  }
460  }
461  }
462  }
463 
464  /* Cleanup geometry (#BM_faces_join_pair, but it removes geometry we're looping on)
465  * so do this in a separate pass instead. */
466  BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) {
467  if ((e->l == NULL) && BMO_edge_flag_test(bm, e, EDGE_ISGC)) {
468  BM_edge_kill(bm, e);
469  }
470  }
471 
472  /* final cleanup */
473  BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
474  if (BM_vert_is_edge_pair(v)) {
475  BM_vert_collapse_edge(bm, v->e, v, false, true, true);
476  }
477  }
478 
479  BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) {
480  if ((v->e == NULL) && BMO_vert_flag_test(bm, v, VERT_ISGC)) {
481  BM_vert_kill(bm, v);
482  }
483  }
484  /* done with cleanup */
485 }
486 
487 /* Limited Dissolve */
489 {
490  BMOpSlot *einput = BMO_slot_get(op->slots_in, "edges");
491  BMOpSlot *vinput = BMO_slot_get(op->slots_in, "verts");
492  const float angle_max = M_PI_2;
493  const float angle_limit = min_ff(angle_max, BMO_slot_float_get(op->slots_in, "angle_limit"));
494  const bool do_dissolve_boundaries = BMO_slot_bool_get(op->slots_in, "use_dissolve_boundaries");
495  const BMO_Delimit delimit = BMO_slot_int_get(op->slots_in, "delimit");
496 
498  angle_limit,
499  do_dissolve_boundaries,
500  delimit,
501  (BMVert **)BMO_SLOT_AS_BUFFER(vinput),
502  vinput->len,
503  (BMEdge **)BMO_SLOT_AS_BUFFER(einput),
504  einput->len,
505  FACE_NEW);
506 
508 }
509 
510 #define EDGE_MARK 1
511 #define EDGE_COLLAPSE 2
512 
513 static void bm_mesh_edge_collapse_flagged(BMesh *bm, const int flag, const short oflag)
514 {
515  BMO_op_callf(bm, flag, "collapse edges=%fe uvs=%b", oflag, true);
516 }
517 
519 {
520  const float dist = BMO_slot_float_get(op->slots_in, "dist");
521  const float dist_sq = dist * dist;
522 
523  bool found;
524  BMIter eiter;
525  BMEdge *e;
526 
528 
529  /* collapse zero length edges, this accounts for zero area faces too */
530  found = false;
531  BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
532  if (BMO_edge_flag_test(bm, e, EDGE_MARK)) {
533  if (BM_edge_calc_length_squared(e) < dist_sq) {
535  found = true;
536  }
537  }
538 
539  /* clear all loop tags (checked later) */
540  if (e->l) {
541  BMLoop *l_iter, *l_first;
542  l_iter = l_first = e->l;
543  do {
545  } while ((l_iter = l_iter->radial_next) != l_first);
546  }
547  }
548 
549  if (found) {
551  }
552 
553  /* clip degenerate ears from the face */
554  found = false;
555  BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
556  if (e->l && BMO_edge_flag_test(bm, e, EDGE_MARK)) {
557  BMLoop *l_iter, *l_first;
558  l_iter = l_first = e->l;
559  do {
560  if (
561  /* check the loop hasn't already been tested (and flag not to test again) */
562  !BM_elem_flag_test(l_iter, BM_ELEM_TAG) &&
563  ((void)BM_elem_flag_enable(l_iter, BM_ELEM_TAG),
564 
565  /* check we're marked to tested (radial edge already tested) */
566  BMO_edge_flag_test(bm, l_iter->prev->e, EDGE_MARK) &&
567 
568  /* check edges are not already going to be collapsed */
569  !BMO_edge_flag_test(bm, l_iter->e, EDGE_COLLAPSE) &&
570  !BMO_edge_flag_test(bm, l_iter->prev->e, EDGE_COLLAPSE))) {
571  /* test if the faces loop (ear) is degenerate */
572  float dir_prev[3], len_prev;
573  float dir_next[3], len_next;
574 
575  sub_v3_v3v3(dir_prev, l_iter->prev->v->co, l_iter->v->co);
576  sub_v3_v3v3(dir_next, l_iter->next->v->co, l_iter->v->co);
577 
578  len_prev = normalize_v3(dir_prev);
579  len_next = normalize_v3(dir_next);
580 
581  if ((len_v3v3(dir_prev, dir_next) * min_ff(len_prev, len_next)) <= dist) {
582  bool reset = false;
583 
584  if (fabsf(len_prev - len_next) <= dist) {
585  /* both edges the same length */
586  if (l_iter->f->len == 3) {
587  /* ideally this would have been discovered with short edge test above */
589  found = true;
590  }
591  else {
592  /* add a joining edge and tag for removal */
593  BMLoop *l_split;
594  if (BM_face_split(
595  bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) {
597  found = true;
598  reset = true;
599  }
600  }
601  }
602  else if (len_prev < len_next) {
603  /* split 'l_iter->e', then join the vert with next */
604  BMVert *v_new;
605  BMEdge *e_new;
606  BMLoop *l_split;
607  v_new = BM_edge_split(bm, l_iter->e, l_iter->v, &e_new, len_prev / len_next);
608  BLI_assert(v_new == l_iter->next->v);
609  (void)v_new;
610  if (BM_face_split(bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) {
612  found = true;
613  }
614  reset = true;
615  }
616  else if (len_next < len_prev) {
617  /* split 'l_iter->prev->e', then join the vert with next */
618  BMVert *v_new;
619  BMEdge *e_new;
620  BMLoop *l_split;
621  v_new = BM_edge_split(bm, l_iter->prev->e, l_iter->v, &e_new, len_next / len_prev);
622  BLI_assert(v_new == l_iter->prev->v);
623  (void)v_new;
624  if (BM_face_split(bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) {
626  found = true;
627  }
628  reset = true;
629  }
630 
631  if (reset) {
632  /* we can't easily track where we are on the radial edge, reset! */
633  l_first = l_iter;
634  }
635  }
636  }
637  } while ((l_iter = l_iter->radial_next) != l_first);
638  }
639  }
640 
641  if (found) {
643  }
644 }
A (mainly) macro array library.
#define BLI_array_append(arr, item)
Definition: BLI_array.h:104
#define BLI_array_declare(arr)
Definition: BLI_array.h:62
#define BLI_array_len(arr)
Definition: BLI_array.h:74
#define BLI_array_clear(arr)
Definition: BLI_array.h:130
#define BLI_array_free(arr)
Definition: BLI_array.h:116
#define BLI_assert(a)
Definition: BLI_assert.h:58
MINLINE float min_ff(float a, float b)
#define M_PI_2
Definition: BLI_math_base.h:41
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v3(float r[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
void BLI_stack_pop(BLI_Stack *stack, void *dst) ATTR_NONNULL()
Definition: stack.c:175
void BLI_stack_push(BLI_Stack *stack, const void *src) ATTR_NONNULL()
Definition: stack.c:163
bool BLI_stack_is_empty(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: stack.c:310
void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL()
Definition: stack.c:114
#define BLI_stack_new(esize, descr)
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNUSED_FUNCTION(x)
Read Guarded memory(de)allocation.
#define BM_DISK_EDGE_NEXT(e, v)
Definition: bmesh_class.h:556
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_EDGE
Definition: bmesh_class.h:384
@ BM_ELEM_TAG
Definition: bmesh_class.h:484
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:553
BMFace * BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
Join Connected Faces.
Definition: bmesh_core.c:1209
void BM_vert_kill(BMesh *bm, BMVert *v)
Definition: bmesh_core.c:1002
void BM_face_kill(BMesh *bm, BMFace *f)
Definition: bmesh_core.c:881
void BM_edge_kill(BMesh *bm, BMEdge *e)
Definition: bmesh_core.c:987
void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries, BMO_Delimit delimit, BMVert **vinput_arr, const int vinput_len, BMEdge **einput_arr, const int einput_len, const short oflag_out)
bool BMO_error_occurred(BMesh *bm)
void BMO_error_clear(BMesh *bm)
@ BMERR_DISSOLVEFACES_FAILED
Definition: bmesh_error.h:59
void BMO_error_raise(BMesh *bm, BMOperator *owner, int errcode, const char *msg)
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:29
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:28
#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
BMFace * BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del)
Faces Join Pair.
Definition: bmesh_mods.c:221
BMVert * BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
Edge Split.
Definition: bmesh_mods.c:591
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.
Definition: bmesh_mods.c:523
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.
Definition: bmesh_mods.c:252
void BMO_slot_buffer_flag_enable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char htype, const 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)
#define BMO_vert_flag_set(bm, e, oflag, val)
#define BMO_SLOT_AS_BUFFER(slot)
#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)
BMOpSlot * BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
BMESH OPSTACK GET SLOT.
@ DEL_FACES
#define BMO_face_flag_disable(bm, e, oflag)
#define BMO_face_flag_test(bm, e, oflag)
void BMO_slot_buffer_from_enabled_flag(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char htype, const short oflag)
bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
bool BMO_op_callf(BMesh *bm, const int flag, const char *fmt,...)
ATTR_WARN_UNUSED_RESULT const BMFlagLayer const short oflag
BMFace * BM_face_find_double(BMFace *f)
Definition: bmesh_query.c:2121
bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb)
Definition: bmesh_query.c:753
float BM_edge_calc_length_squared(const BMEdge *e)
Definition: bmesh_query.c:721
bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb)
Definition: bmesh_query.c:732
bool BM_vert_is_edge_pair(const BMVert *v)
Definition: bmesh_query.c:771
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_init(BMWalker *walker, BMesh *bm, int type, short mask_vert, short mask_edge, short mask_face, BMWFlag flag, int layer)
Init Walker.
Definition: bmesh_walkers.c:70
void BMW_end(BMWalker *walker)
End Walker.
void * BMW_begin(BMWalker *walker, void *start)
Definition: bmesh_walkers.c:55
void * BMW_step(BMWalker *walker)
Step Walker.
#define BMW_NIL_LAY
@ BMW_FLAG_NOP
Definition: bmesh_walkers.h:33
#define BMW_MASK_NOP
Definition: bmesh_walkers.h:68
@ BMW_ISLAND_MANIFOLD
@ BMW_ISLAND
#define VERT_MARK
Definition: bmo_dissolve.c:45
void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
Definition: bmo_dissolve.c:127
#define VERT_MARK_TEAR
Definition: bmo_dissolve.c:49
#define FACE_ORIG
Definition: bmo_dissolve.c:37
#define FACE_NEW
Definition: bmo_dissolve.c:38
static bool UNUSED_FUNCTION() check_hole_in_region(BMesh *bm, BMFace *f)
Definition: bmo_dissolve.c:51
void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op)
Definition: bmo_dissolve.c:488
static void bm_mesh_edge_collapse_flagged(BMesh *bm, const int flag, const short oflag)
Definition: bmo_dissolve.c:513
#define FACE_TAG
Definition: bmo_dissolve.c:39
void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
Definition: bmo_dissolve.c:369
#define VERT_TAG
Definition: bmo_dissolve.c:47
#define FACE_MARK
Definition: bmo_dissolve.c:36
#define EDGE_TAG
Definition: bmo_dissolve.c:42
#define EDGE_ISGC
Definition: bmo_dissolve.c:43
void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op)
Definition: bmo_dissolve.c:268
#define EDGE_MARK
Definition: bmo_dissolve.c:510
#define VERT_ISGC
Definition: bmo_dissolve.c:48
void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op)
Definition: bmo_dissolve.c:518
static void bm_face_split(BMesh *bm, const short oflag, bool use_edge_delete)
Definition: bmo_dissolve.c:84
#define EDGE_COLLAPSE
Definition: bmo_dissolve.c:511
#define VERT_MARK_PAIR
Definition: bmo_dissolve.c:46
void reset()
clear internal cached data and reset random seed
#define fabsf(x)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
static char faces[256]
int len
Definition: bmesh_class.h:279
struct BMVert * v
Definition: bmesh_class.h:165
struct BMEdge * e
Definition: bmesh_class.h:176
struct BMLoop * radial_next
Definition: bmesh_class.h:216
struct BMLoop * prev
Definition: bmesh_class.h:245
struct BMFace * f
Definition: bmesh_class.h:183
struct BMLoop * next
Definition: bmesh_class.h:245
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
float co[3]
Definition: bmesh_class.h:99
struct BMEdge * e
Definition: bmesh_class.h:109
BMFace * act_face
Definition: bmesh_class.h:366
int totface
Definition: bmesh_class.h:297