Cleanup: misc spelling fixes
[blender.git] / source / blender / bmesh / operators / bmo_bridge.c
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
17 /** \file
18  * \ingroup bmesh
19  *
20  * Connect verts across faces (splits faces) and bridge tool.
21  */
22
23 #include "BLI_math.h"
24 #include "BLI_utildefines.h"
25 #include "BLI_listbase.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 */
36 static void bm_bridge_splice_loops(BMesh *bm,
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 {
65   BMEdge *e = BM_edge_exists(v1, v2);
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 */
80     *l1 = BM_iter_at_index(bm, BM_LOOPS_OF_VERT, v1, 0);
81     *l2 = BM_iter_at_index(bm, BM_LOOPS_OF_VERT, v2, 0);
82   }
83 }
84
85 /* el_b can have any offset */
86 static float bm_edgeloop_offset_length(LinkData *el_a,
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
125 static void bm_face_edges_tag_out(BMesh *bm, BMFace *f)
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) {
168     BM_mesh_elem_hflag_disable_all(bm, BM_FACE | BM_EDGE, BM_ELEM_TAG, false);
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 {
206       /**
207        * This is a corner case:
208        *
209        * <pre>
210        *  (loop a)    (loop b)
211        * +--------+  +--------+
212        * </pre>
213        *
214        * When loops are aligned to the direction between
215        * the loops values of 'dir_a/b' is degenerate,
216        * in this case compare the original directions
217        * (before they were corrected by 'el_dir'),
218        * see: T43013
219        */
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_a, v_b, v_b_next, v_a_next};
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_a, v_b, v_a_next};
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       }
452       BMO_face_flag_enable(bm, f, FACE_OUT);
453       BM_elem_flag_enable(f, BM_ELEM_TAG);
454
455       /* tag all edges of the face, untag the loop edges after */
456       if (use_edgeout) {
457         bm_face_edges_tag_out(bm, f);
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
473     BMOperator op_sub;
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) {
484         BM_face_normal_update(f);
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);
490     BMO_op_finish(bm, &op_sub);
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) {
496         BM_elem_flag_set((BMVert *)el->data, BM_ELEM_TAG, i);
497       }
498     }
499
500     BMO_op_initf(bm,
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) {
512         BMO_face_flag_enable(bm, f, FACE_OUT);
513         bm_face_edges_tag_out(bm, f);
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) {
524         BMO_face_flag_enable(bm, f, FACE_OUT);
525         bm_face_edges_tag_out(bm, f);
526       }
527     }
528     else {
529       BMO_slot_buffer_flag_enable(bm, op_sub.slots_out, "geom.out", BM_FACE, FACE_OUT);
530     }
531
532     BMO_op_finish(bm, &op_sub);
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);
546             BMO_edge_flag_disable(bm, e, EDGE_OUT);
547           }
548         }
549       }
550     }
551   }
552
553   if (el_store_b_free) {
554     BM_edgeloop_free(el_store_b);
555   }
556 }
557
558 void bmo_bridge_loops_exec(BMesh *bm, BMOperator *op)
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
572   BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_MARK);
573
574   count = BM_mesh_edgeloops_find(bm, &eloops, bm_edge_test_cb, bm);
575
576   BM_mesh_edgeloops_calc_center(bm, &eloops);
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)) {
584     BMO_error_raise(
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) {
599       BMO_error_raise(
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) {
607       BM_mesh_edgeloops_calc_normal(bm, &eloops);
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
624     bridge_loop_pair(bm,
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) {
641       BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_OUT);
642       BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EDGE_OUT);
643     }
644   }
645 }