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