Blender  V3.3
bmo_bridge.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
9 #include "BLI_listbase.h"
10 #include "BLI_math.h"
11 #include "BLI_utildefines.h"
12 
13 #include "bmesh.h"
14 
15 #include "intern/bmesh_operators_private.h" /* own include */
16 
17 #define EDGE_MARK 4
18 #define EDGE_OUT 8
19 #define FACE_OUT 16
20 
21 /* el_a and el_b _must_ be same size */
23  LinkData *el_a,
24  LinkData *el_b,
25  const float merge_factor)
26 {
27  BMOperator op_weld;
28  BMOpSlot *slot_targetmap;
29 
30  BMO_op_init(bm, &op_weld, 0, "weld_verts");
31 
32  slot_targetmap = BMO_slot_get(op_weld.slots_in, "targetmap");
33 
34  do {
35  BMVert *v_a = el_a->data, *v_b = el_b->data;
36  BM_data_interp_from_verts(bm, v_a, v_b, v_b, merge_factor);
37  interp_v3_v3v3(v_b->co, v_a->co, v_b->co, merge_factor);
38  BLI_assert(v_a != v_b);
39  BMO_slot_map_elem_insert(&op_weld, slot_targetmap, v_a, v_b);
40  } while ((void)(el_b = el_b->next), (el_a = el_a->next));
41 
42  BMO_op_exec(bm, &op_weld);
43  BMO_op_finish(bm, &op_weld);
44 }
45 
46 /* get the 2 loops matching 2 verts.
47  * first attempt to get the face corners that use the edge defined by v1 & v2,
48  * if that fails just get any loop that's on the vert (the first one) */
49 static void bm_vert_loop_pair(BMesh *bm, BMVert *v1, BMVert *v2, BMLoop **l1, BMLoop **l2)
50 {
52  BMLoop *l = e->l;
53 
54  if (l) {
55  if (l->v == v1) {
56  *l1 = l;
57  *l2 = l->next;
58  }
59  else {
60  *l2 = l;
61  *l1 = l->next;
62  }
63  }
64  else {
65  /* fallback to _any_ loop */
68  }
69 }
70 
71 /* el_b can have any offset */
73  LinkData *el_b,
74  LinkData *el_b_first,
75  const float len_max)
76 {
77  float len = 0.0f;
78  BLI_assert(el_a->prev == NULL); /* must be first */
79  do {
80  len += len_v3v3(((BMVert *)el_a->data)->co, ((BMVert *)el_b->data)->co);
81  } while ((void)(el_b = el_b->next ? el_b->next : el_b_first),
82  (el_a = el_a->next) && (len < len_max));
83  return len;
84 }
85 
86 static void bm_bridge_best_rotation(struct BMEdgeLoopStore *el_store_a,
87  struct BMEdgeLoopStore *el_store_b)
88 {
89  ListBase *lb_a = BM_edgeloop_verts_get(el_store_a);
90  ListBase *lb_b = BM_edgeloop_verts_get(el_store_b);
91  LinkData *el_a = lb_a->first;
92  LinkData *el_b = lb_b->first;
93  LinkData *el_b_first = el_b;
94  LinkData *el_b_best = NULL;
95 
96  float len_best = FLT_MAX;
97 
98  for (; el_b; el_b = el_b->next) {
99  const float len = bm_edgeloop_offset_length(el_a, el_b, el_b_first, len_best);
100  if (len < len_best) {
101  el_b_best = el_b;
102  len_best = len;
103  }
104  }
105 
106  if (el_b_best) {
107  BLI_listbase_rotate_first(lb_b, el_b_best);
108  }
109 }
110 
112 {
113  BMLoop *l_iter, *l_first;
114  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
115  do {
116  BMO_edge_flag_enable(bm, l_iter->e, EDGE_OUT);
117  } while ((l_iter = l_iter->next) != l_first);
118 }
119 
120 static bool bm_edge_test_cb(BMEdge *e, void *bm_v)
121 {
122  return BMO_edge_flag_test((BMesh *)bm_v, e, EDGE_MARK);
123 }
124 
125 static void bridge_loop_pair(BMesh *bm,
126  struct BMEdgeLoopStore *el_store_a,
127  struct BMEdgeLoopStore *el_store_b,
128  const bool use_merge,
129  const float merge_factor,
130  const int twist_offset)
131 {
132  const float eps = 0.00001f;
133  LinkData *el_a_first, *el_b_first;
134  const bool is_closed = BM_edgeloop_is_closed(el_store_a) && BM_edgeloop_is_closed(el_store_b);
135  int el_store_a_len, el_store_b_len;
136  bool el_store_b_free = false;
137  float el_dir[3];
138  float dot_a, dot_b;
139  const bool use_edgeout = true;
140 
141  el_store_a_len = BM_edgeloop_length_get((struct BMEdgeLoopStore *)el_store_a);
142  el_store_b_len = BM_edgeloop_length_get((struct BMEdgeLoopStore *)el_store_b);
143 
144  if (el_store_a_len < el_store_b_len) {
145  SWAP(int, el_store_a_len, el_store_b_len);
146  SWAP(struct BMEdgeLoopStore *, el_store_a, el_store_b);
147  }
148 
149  if (use_merge) {
150  BLI_assert((el_store_a_len == el_store_b_len));
151  }
152 
153  if (el_store_a_len != el_store_b_len) {
155  }
156 
157  sub_v3_v3v3(el_dir, BM_edgeloop_center_get(el_store_a), BM_edgeloop_center_get(el_store_b));
158 
159  if (is_closed) {
160  /* if all loops are closed this will calculate twice for all loops */
161  BM_edgeloop_calc_normal(bm, el_store_a);
162  BM_edgeloop_calc_normal(bm, el_store_b);
163  }
164  else {
165  ListBase *lb_a = BM_edgeloop_verts_get(el_store_a);
166  ListBase *lb_b = BM_edgeloop_verts_get(el_store_b);
167 
168  /* normalizing isn't strictly needed but without we may get very large values */
169  float no[3];
170  float dir_a_orig[3], dir_b_orig[3];
171  float dir_a[3], dir_b[3];
172  const float *test_a, *test_b;
173 
174  sub_v3_v3v3(dir_a_orig,
175  ((BMVert *)(((LinkData *)lb_a->first)->data))->co,
176  ((BMVert *)(((LinkData *)lb_a->last)->data))->co);
177  sub_v3_v3v3(dir_b_orig,
178  ((BMVert *)(((LinkData *)lb_b->first)->data))->co,
179  ((BMVert *)(((LinkData *)lb_b->last)->data))->co);
180 
181  /* make the directions point out from the normals, 'no' is used as a temp var */
182  cross_v3_v3v3(no, dir_a_orig, el_dir);
183  cross_v3_v3v3(dir_a, no, el_dir);
184  cross_v3_v3v3(no, dir_b_orig, el_dir);
185  cross_v3_v3v3(dir_b, no, el_dir);
186 
187  if (LIKELY(!is_zero_v3(dir_a) && !is_zero_v3(dir_b))) {
188  test_a = dir_a;
189  test_b = dir_b;
190  }
191  else {
206  test_a = dir_a_orig;
207  test_b = dir_b_orig;
208  }
209 
210  if (dot_v3v3(test_a, test_b) < 0.0f) {
211  BM_edgeloop_flip(bm, el_store_b);
212  }
213 
214  normalize_v3_v3(no, el_dir);
215  BM_edgeloop_calc_normal_aligned(bm, el_store_a, no);
216  BM_edgeloop_calc_normal_aligned(bm, el_store_b, no);
217  }
218 
219  dot_a = dot_v3v3(BM_edgeloop_normal_get(el_store_a), el_dir);
220  dot_b = dot_v3v3(BM_edgeloop_normal_get(el_store_b), el_dir);
221 
222  if (UNLIKELY((len_squared_v3(el_dir) < eps) || ((fabsf(dot_a) < eps) && (fabsf(dot_b) < eps)))) {
223  /* in this case there is no depth between the two loops,
224  * eg: 2x 2d circles, one scaled smaller,
225  * in this case 'el_dir' can't be used, just ensure we have matching flipping. */
226  if (dot_v3v3(BM_edgeloop_normal_get(el_store_a), BM_edgeloop_normal_get(el_store_b)) < 0.0f) {
227  BM_edgeloop_flip(bm, el_store_b);
228  }
229  }
230  else if ((dot_a < 0.0f) != (dot_b < 0.0f)) {
231  BM_edgeloop_flip(bm, el_store_b);
232  }
233 
234  /* we only care about flipping if we make faces */
235  if (use_merge == false) {
236  float no[3];
237 
238  add_v3_v3v3(no, BM_edgeloop_normal_get(el_store_a), BM_edgeloop_normal_get(el_store_b));
239 
240  if (dot_v3v3(no, el_dir) < 0.0f) {
241  BM_edgeloop_flip(bm, el_store_a);
242  BM_edgeloop_flip(bm, el_store_b);
243  }
244 
245  /* vote on winding (so new face winding is based on existing connected faces) */
246  if (bm->totface) {
247  struct BMEdgeLoopStore *estore_pair[2] = {el_store_a, el_store_b};
248  int i;
249  int winding_votes[2] = {0, 0};
250  int winding_dir = 1;
251  for (i = 0; i < 2; i++, winding_dir = -winding_dir) {
252  LinkData *el;
253  for (el = BM_edgeloop_verts_get(estore_pair[i])->first; el; el = el->next) {
254  LinkData *el_next = BM_EDGELINK_NEXT(estore_pair[i], el);
255  if (el_next) {
256  BMEdge *e = BM_edge_exists(el->data, el_next->data);
257  if (e && BM_edge_is_boundary(e)) {
258  winding_votes[i] += ((e->l->v == el->data) ? winding_dir : -winding_dir);
259  }
260  }
261  }
262  }
263 
264  if (winding_votes[0] || winding_votes[1]) {
265  bool flip[2] = {false, false};
266 
267  /* for direction aligned loops we can't rely on the directly we have,
268  * use the winding defined by the connected faces (see T48356). */
269  if (fabsf(dot_a) < eps) {
270  if (winding_votes[0] < 0) {
271  flip[0] = !flip[0];
272  winding_votes[0] *= -1;
273  }
274  }
275  if (fabsf(dot_b) < eps) {
276  if (winding_votes[1] < 0) {
277  flip[1] = !flip[1];
278  winding_votes[1] *= -1;
279  }
280  }
281 
282  /* when both loops contradict the winding, flip them so surrounding geometry matches */
283  if ((winding_votes[0] + winding_votes[1]) < 0) {
284  flip[0] = !flip[0];
285  flip[1] = !flip[1];
286 
287  /* valid but unused */
288 #if 0
289  winding_votes[0] *= -1;
290  winding_votes[1] *= -1;
291 #endif
292  }
293 
294  if (flip[0]) {
295  BM_edgeloop_flip(bm, el_store_a);
296  }
297  if (flip[1]) {
298  BM_edgeloop_flip(bm, el_store_b);
299  }
300  }
301  }
302  }
303 
304  if (el_store_a_len > el_store_b_len) {
305  el_store_b = BM_edgeloop_copy(el_store_b);
306  BM_edgeloop_expand(bm, el_store_b, el_store_a_len, false, NULL);
307  el_store_b_free = true;
308  }
309 
310  if (is_closed) {
311  bm_bridge_best_rotation(el_store_a, el_store_b);
312 
313  /* add twist */
314  if (twist_offset != 0) {
315  const int len_b = BM_edgeloop_length_get(el_store_b);
316  ListBase *lb_b = BM_edgeloop_verts_get(el_store_b);
317  LinkData *el_b = BLI_rfindlink(lb_b, mod_i(twist_offset, len_b));
318  BLI_listbase_rotate_first(lb_b, el_b);
319  }
320  }
321 
322  /* Assign after flipping is finalized */
323  el_a_first = BM_edgeloop_verts_get(el_store_a)->first;
324  el_b_first = BM_edgeloop_verts_get(el_store_b)->first;
325 
326  if (use_merge) {
327  bm_bridge_splice_loops(bm, el_a_first, el_b_first, merge_factor);
328  }
329  else {
330  LinkData *el_a = el_a_first;
331  LinkData *el_b = el_b_first;
332 
333  LinkData *el_a_next;
334  LinkData *el_b_next;
335 
336  while (true) {
337  BMFace *f, *f_example;
338  BMLoop *l_iter;
339  BMVert *v_a, *v_b, *v_a_next, *v_b_next;
340 
341  BMLoop *l_a = NULL;
342  BMLoop *l_b = NULL;
343  BMLoop *l_a_next = NULL;
344  BMLoop *l_b_next = NULL;
345 
346  if (is_closed) {
347  el_a_next = BM_EDGELINK_NEXT(el_store_a, el_a);
348  el_b_next = BM_EDGELINK_NEXT(el_store_b, el_b);
349  }
350  else {
351  el_a_next = el_a->next;
352  el_b_next = el_b->next;
353  if (ELEM(NULL, el_a_next, el_b_next)) {
354  break;
355  }
356  }
357 
358  v_a = el_a->data;
359  v_b = el_b->data;
360  v_a_next = el_a_next->data;
361  v_b_next = el_b_next->data;
362 
363  /* get loop data - before making the face */
364  if (v_b != v_b_next) {
365  bm_vert_loop_pair(bm, v_a, v_a_next, &l_a, &l_a_next);
366  bm_vert_loop_pair(bm, v_b, v_b_next, &l_b, &l_b_next);
367  }
368  else {
369  /* lazy, could be more clever here */
370  bm_vert_loop_pair(bm, v_a, v_a_next, &l_a, &l_a_next);
371  l_b = l_b_next = BM_iter_at_index(bm, BM_LOOPS_OF_VERT, v_b, 0);
372  }
373 
374  if (l_a && l_a_next == NULL) {
375  l_a_next = l_a;
376  }
377  if (l_a_next && l_a == NULL) {
378  l_a = l_a_next;
379  }
380  if (l_b && l_b_next == NULL) {
381  l_b_next = l_b;
382  }
383  if (l_b_next && l_b == NULL) {
384  l_b = l_b_next;
385  }
386  f_example = l_a ? l_a->f : (l_b ? l_b->f : NULL);
387 
388  if (v_b != v_b_next) {
389  BMVert *v_arr[4] = {v_b, v_b_next, v_a_next, v_a};
390  f = BM_face_exists(v_arr, 4);
391  if (f == NULL) {
392  /* copy if loop data if its is missing on one ring */
393  f = BM_face_create_verts(bm, v_arr, 4, NULL, BM_CREATE_NOP, true);
394 
395  l_iter = BM_FACE_FIRST_LOOP(f);
396  if (l_b) {
397  BM_elem_attrs_copy(bm, bm, l_b, l_iter);
398  }
399  l_iter = l_iter->next;
400  if (l_b_next) {
401  BM_elem_attrs_copy(bm, bm, l_b_next, l_iter);
402  }
403  l_iter = l_iter->next;
404  if (l_a_next) {
405  BM_elem_attrs_copy(bm, bm, l_a_next, l_iter);
406  }
407  l_iter = l_iter->next;
408  if (l_a) {
409  BM_elem_attrs_copy(bm, bm, l_a, l_iter);
410  }
411  }
412  }
413  else {
414  BMVert *v_arr[3] = {v_b, v_a_next, v_a};
415  f = BM_face_exists(v_arr, 3);
416  if (f == NULL) {
417  /* fan-fill a triangle */
418  f = BM_face_create_verts(bm, v_arr, 3, NULL, BM_CREATE_NOP, true);
419 
420  l_iter = BM_FACE_FIRST_LOOP(f);
421  if (l_b) {
422  BM_elem_attrs_copy(bm, bm, l_b, l_iter);
423  }
424  l_iter = l_iter->next;
425  if (l_a_next) {
426  BM_elem_attrs_copy(bm, bm, l_a_next, l_iter);
427  }
428  l_iter = l_iter->next;
429  if (l_a) {
430  BM_elem_attrs_copy(bm, bm, l_a, l_iter);
431  }
432  }
433  }
434 
435  if (f_example && (f_example != f)) {
436  BM_elem_attrs_copy(bm, bm, f_example, f);
437  }
440 
441  /* tag all edges of the face, untag the loop edges after */
442  if (use_edgeout) {
444  }
445 
446  if (el_a_next == el_a_first) {
447  break;
448  }
449 
450  el_a = el_a_next;
451  el_b = el_b_next;
452  }
453  }
454 
455  if (el_store_a_len != el_store_b_len) {
456  struct BMEdgeLoopStore *estore_pair[2] = {el_store_a, el_store_b};
457  int i;
458 
460  /* when we have to bridge between different sized edge-loops,
461  * be clever and post-process for best results */
462 
463  /* triangulate inline */
464  BMO_op_initf(bm, &op_sub, 0, "triangulate faces=%hf", BM_ELEM_TAG, true);
465  /* calc normals for input faces before executing */
466  {
467  BMOIter siter;
468  BMFace *f;
469  BMO_ITER (f, &siter, op_sub.slots_in, "faces", BM_FACE) {
471  }
472  }
473  BMO_op_exec(bm, &op_sub);
474  BMO_slot_buffer_flag_enable(bm, op_sub.slots_out, "faces.out", BM_FACE, FACE_OUT);
475  BMO_slot_buffer_hflag_enable(bm, op_sub.slots_out, "faces.out", BM_FACE, BM_ELEM_TAG, false);
477 
478  /* tag verts on each side so we can restrict rotation of edges to verts on the same side */
479  for (i = 0; i < 2; i++) {
480  LinkData *el;
481  for (el = BM_edgeloop_verts_get(estore_pair[i])->first; el; el = el->next) {
483  }
484  }
485 
487  &op_sub,
488  0,
489  "beautify_fill faces=%hf edges=ae use_restrict_tag=%b method=%i",
490  BM_ELEM_TAG,
491  true,
492  1);
493 
494  if (use_edgeout) {
495  BMOIter siter;
496  BMFace *f;
497  BMO_ITER (f, &siter, op_sub.slots_in, "faces", BM_FACE) {
500  }
501  }
502 
503  BMO_op_exec(bm, &op_sub);
504  /* there may also be tagged faces that didn't rotate, mark input */
505 
506  if (use_edgeout) {
507  BMOIter siter;
508  BMFace *f;
509  BMO_ITER (f, &siter, op_sub.slots_out, "geom.out", BM_FACE) {
512  }
513  }
514  else {
515  BMO_slot_buffer_flag_enable(bm, op_sub.slots_out, "geom.out", BM_FACE, FACE_OUT);
516  }
517 
519  }
520 
521  if (use_edgeout && use_merge == false) {
522  /* we've enabled all face edges above, now disable all loop edges */
523  struct BMEdgeLoopStore *estore_pair[2] = {el_store_a, el_store_b};
524  int i;
525  for (i = 0; i < 2; i++) {
526  LinkData *el;
527  for (el = BM_edgeloop_verts_get(estore_pair[i])->first; el; el = el->next) {
528  LinkData *el_next = BM_EDGELINK_NEXT(estore_pair[i], el);
529  if (el_next) {
530  if (el->data != el_next->data) {
531  BMEdge *e = BM_edge_exists(el->data, el_next->data);
533  }
534  }
535  }
536  }
537  }
538 
539  if (el_store_b_free) {
540  BM_edgeloop_free(el_store_b);
541  }
542 }
543 
545 {
546  ListBase eloops = {NULL};
547  LinkData *el_store;
548 
549  /* merge-bridge support */
550  const bool use_pairs = BMO_slot_bool_get(op->slots_in, "use_pairs");
551  const bool use_merge = BMO_slot_bool_get(op->slots_in, "use_merge");
552  const float merge_factor = BMO_slot_float_get(op->slots_in, "merge_factor");
553  const bool use_cyclic = BMO_slot_bool_get(op->slots_in, "use_cyclic") && (use_merge == false);
554  const int twist_offset = BMO_slot_int_get(op->slots_in, "twist_offset");
555  int count;
556  bool changed = false;
557 
559 
561 
563 
564  if (count < 2) {
565  BMO_error_raise(bm, op, BMO_ERROR_CANCEL, "Select at least two edge loops");
566  goto cleanup;
567  }
568 
569  if (use_pairs && (count % 2)) {
570  BMO_error_raise(bm, op, BMO_ERROR_CANCEL, "Select an even number of loops to bridge pairs");
571  goto cleanup;
572  }
573 
574  if (use_merge) {
575  bool match = true;
576  const int eloop_len = BM_edgeloop_length_get(eloops.first);
577  for (el_store = eloops.first; el_store; el_store = el_store->next) {
578  if (eloop_len != BM_edgeloop_length_get((struct BMEdgeLoopStore *)el_store)) {
579  match = false;
580  break;
581  }
582  }
583  if (!match) {
584  BMO_error_raise(bm, op, BMO_ERROR_CANCEL, "Selected loops must have equal edge counts");
585  goto cleanup;
586  }
587  }
588 
589  if (count > 2) {
590  if (use_pairs) {
592  }
593  BM_mesh_edgeloops_calc_order(bm, &eloops, use_pairs);
594  }
595 
596  for (el_store = eloops.first; el_store; el_store = el_store->next) {
597  LinkData *el_store_next = el_store->next;
598 
599  if (el_store_next == NULL) {
600  if (use_cyclic && (count > 2)) {
601  el_store_next = eloops.first;
602  }
603  else {
604  break;
605  }
606  }
607 
609  (struct BMEdgeLoopStore *)el_store,
610  (struct BMEdgeLoopStore *)el_store_next,
611  use_merge,
612  merge_factor,
613  twist_offset);
614  if (use_pairs) {
615  el_store = el_store->next;
616  }
617  changed = true;
618  }
619 
620 cleanup:
621  BM_mesh_edgeloops_free(&eloops);
622 
623  if (changed) {
624  if (use_merge == false) {
627  }
628  }
629 }
#define BLI_assert(a)
Definition: BLI_assert.h:46
void * BLI_rfindlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_listbase_rotate_first(struct ListBase *lb, void *vlink) ATTR_NONNULL(1
MINLINE int mod_i(int i, int n)
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
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 bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition: math_vector.c:29
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
#define SWAP(type, a, b)
#define UNLIKELY(x)
#define ELEM(...)
#define LIKELY(x)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:622
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_EDGE
Definition: bmesh_class.h:384
@ BM_ELEM_TAG
Definition: bmesh_class.h:484
void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src, void *ele_dst)
BMFace * BM_face_create_verts(BMesh *bm, BMVert **vert_arr, const int len, const BMFace *f_example, const eBMCreateFlag create_flag, const bool create_edges)
Definition: bmesh_core.c:464
@ BM_CREATE_NOP
Definition: bmesh_core.h:12
BMEdgeLoopStore * BM_edgeloop_copy(BMEdgeLoopStore *el_store)
const float * BM_edgeloop_center_get(struct BMEdgeLoopStore *el_store)
void BM_edgeloop_expand(BMesh *bm, BMEdgeLoopStore *el_store, int el_store_len, bool split, GSet *split_edges)
void BM_mesh_edgeloops_free(ListBase *eloops)
void BM_edgeloop_free(BMEdgeLoopStore *el_store)
int BM_mesh_edgeloops_find(BMesh *bm, ListBase *r_eloops, bool(*test_fn)(BMEdge *, void *user_data), void *user_data)
int BM_edgeloop_length_get(BMEdgeLoopStore *el_store)
void BM_mesh_edgeloops_calc_order(BMesh *UNUSED(bm), ListBase *eloops, const bool use_normals)
bool BM_edgeloop_is_closed(BMEdgeLoopStore *el_store)
ListBase * BM_edgeloop_verts_get(BMEdgeLoopStore *el_store)
bool BM_edgeloop_calc_normal(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store)
bool BM_edgeloop_calc_normal_aligned(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store, const float no_align[3])
const float * BM_edgeloop_normal_get(struct BMEdgeLoopStore *el_store)
void BM_edgeloop_flip(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store)
void BM_mesh_edgeloops_calc_normal(BMesh *bm, ListBase *eloops)
void BM_mesh_edgeloops_calc_center(BMesh *bm, ListBase *eloops)
#define BM_EDGELINK_NEXT(el_store, elink)
@ BMO_ERROR_CANCEL
Definition: bmesh_error.h:21
void BMO_error_raise(BMesh *bm, BMOperator *owner, eBMOpErrorLevel level, const char *msg) ATTR_NONNULL(1
#define BM_elem_flag_set(ele, hflag, val)
Definition: bmesh_inline.h:16
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:14
void BM_data_interp_from_verts(BMesh *bm, const BMVert *v_src_1, const BMVert *v_src_2, BMVert *v_dst, const float fac)
Data, Interpolate From Verts.
Definition: bmesh_interp.c:68
void * BM_iter_at_index(BMesh *bm, const char itype, void *data, int index)
@ BM_LOOPS_OF_VERT
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
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.
void BMO_slot_buffer_hflag_enable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, char hflag, bool do_flush)
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)
void BMO_op_exec(BMesh *bm, BMOperator *op)
BMESH OPSTACK EXEC OP.
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)
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)
bool BMO_op_initf(BMesh *bm, BMOperator *op, int flag, const char *fmt,...)
int BMO_slot_int_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
void BMO_op_finish(BMesh *bm, BMOperator *op)
BMESH OPSTACK FINISH OP.
BMOpSlot * BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
BMESH OPSTACK GET SLOT.
#define BMO_edge_flag_disable(bm, e, oflag)
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)
void BM_face_normal_update(BMFace *f)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
Definition: bmesh_query.c:1553
BMFace * BM_face_exists(BMVert **varr, int len)
Definition: bmesh_query.c:1612
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) 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 BMLoop * l_b
static void bm_bridge_splice_loops(BMesh *bm, LinkData *el_a, LinkData *el_b, const float merge_factor)
Definition: bmo_bridge.c:22
void bmo_bridge_loops_exec(BMesh *bm, BMOperator *op)
Definition: bmo_bridge.c:544
#define FACE_OUT
Definition: bmo_bridge.c:19
static void bm_bridge_best_rotation(struct BMEdgeLoopStore *el_store_a, struct BMEdgeLoopStore *el_store_b)
Definition: bmo_bridge.c:86
static void bridge_loop_pair(BMesh *bm, struct BMEdgeLoopStore *el_store_a, struct BMEdgeLoopStore *el_store_b, const bool use_merge, const float merge_factor, const int twist_offset)
Definition: bmo_bridge.c:125
#define EDGE_OUT
Definition: bmo_bridge.c:18
static void bm_vert_loop_pair(BMesh *bm, BMVert *v1, BMVert *v2, BMLoop **l1, BMLoop **l2)
Definition: bmo_bridge.c:49
#define EDGE_MARK
Definition: bmo_bridge.c:17
static float bm_edgeloop_offset_length(LinkData *el_a, LinkData *el_b, LinkData *el_b_first, const float len_max)
Definition: bmo_bridge.c:72
static bool bm_edge_test_cb(BMEdge *e, void *bm_v)
Definition: bmo_bridge.c:120
static void bm_face_edges_tag_out(BMesh *bm, BMFace *f)
Definition: bmo_bridge.c:111
int len
Definition: draw_manager.c:108
static double op_sub(double a, double b)
int count
#define fabsf(x)
Definition: metal/compat.h:219
const btScalar eps
Definition: poly34.cpp:11
struct BMEdgeLoopStore * next
struct BMVert * v
Definition: bmesh_class.h:153
struct BMEdge * e
Definition: bmesh_class.h:164
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
int totface
Definition: bmesh_class.h:297
void * data
Definition: DNA_listBase.h:26
struct LinkData * next
Definition: DNA_listBase.h:25
struct LinkData * prev
Definition: DNA_listBase.h:25
void * last
Definition: DNA_listBase.h:31
void * first
Definition: DNA_listBase.h:31