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