Cleanup: remove redundant, invalid info from headers
[blender.git] / source / blender / bmesh / operators / bmo_inset.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 blender/bmesh/operators/bmo_inset.c
18  *  \ingroup bmesh
19  *
20  * Inset face regions.
21  * Inset individual faces.
22  */
23
24 #include "MEM_guardedalloc.h"
25
26 #include "BLI_math.h"
27 #include "BLI_alloca.h"
28 #include "BLI_memarena.h"
29 #include "BKE_customdata.h"
30
31 #include "bmesh.h"
32
33 #include "intern/bmesh_operators_private.h" /* own include */
34
35 /* Merge loop-data that diverges, see: T41445 */
36 #define USE_LOOP_CUSTOMDATA_MERGE
37
38 #define ELE_NEW         1
39
40
41 /* -------------------------------------------------------------------- */
42 /* Generic Interp Face (use for both types of inset) */
43
44 /**
45  * Interpolation, this is more complex for regions since we're not creating new faces
46  * and throwing away old ones, so instead, store face data needed for interpolation.
47  *
48  * \note This uses CustomData functions in quite a low-level way which should be
49  * avoided, but in this case its hard to do without storing a duplicate mesh. */
50
51 /* just enough of a face to store interpolation data we can use once the inset is done */
52 typedef struct InterpFace {
53         BMFace *f;
54         void **blocks_l;
55         void **blocks_v;
56         float (*cos_2d)[2];
57         float axis_mat[3][3];
58 } InterpFace;
59
60 /* basically a clone of #BM_vert_interp_from_face */
61 static void bm_interp_face_store(InterpFace *iface, BMesh *bm, BMFace *f, MemArena *interp_arena)
62 {
63         BMLoop *l_iter, *l_first;
64         void **blocks_l    = iface->blocks_l = BLI_memarena_alloc(interp_arena, sizeof(*iface->blocks_l) * f->len);
65         void **blocks_v    = iface->blocks_v = BLI_memarena_alloc(interp_arena, sizeof(*iface->blocks_v) * f->len);
66         float (*cos_2d)[2] = iface->cos_2d = BLI_memarena_alloc(interp_arena, sizeof(*iface->cos_2d) * f->len);
67         void *axis_mat     = iface->axis_mat;
68         int i;
69
70         BLI_assert(BM_face_is_normal_valid(f));
71
72         axis_dominant_v3_to_m3(axis_mat, f->no);
73
74         iface->f = f;
75
76         i = 0;
77         l_iter = l_first = BM_FACE_FIRST_LOOP(f);
78         do {
79                 mul_v2_m3v3(cos_2d[i], axis_mat, l_iter->v->co);
80                 blocks_l[i] = NULL;
81                 CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, l_iter->head.data, &blocks_l[i]);
82                 /* if we were not modifying the loops later we would do... */
83                 // blocks[i] = l_iter->head.data;
84
85                 blocks_v[i] = NULL;
86                 CustomData_bmesh_copy_data(&bm->vdata, &bm->vdata, l_iter->v->head.data, &blocks_v[i]);
87
88                 /* use later for index lookups */
89                 BM_elem_index_set(l_iter, i); /* set_dirty */
90         } while ((void)i++, (l_iter = l_iter->next) != l_first);
91         bm->elem_index_dirty |= BM_LOOP;
92 }
93 static void bm_interp_face_free(InterpFace *iface, BMesh *bm)
94 {
95         void **blocks_l = iface->blocks_l;
96         void **blocks_v = iface->blocks_v;
97         int i;
98
99         for (i = 0; i < iface->f->len; i++) {
100                 CustomData_bmesh_free_block(&bm->ldata, &blocks_l[i]);
101                 CustomData_bmesh_free_block(&bm->vdata, &blocks_v[i]);
102         }
103 }
104
105 #ifdef USE_LOOP_CUSTOMDATA_MERGE
106 /**
107  * This function merges loop customdata (UV's)
108  * where interpolating the values across the face causes values to diverge.
109  */
110 static void bm_loop_customdata_merge(
111         BMesh *bm,
112         BMEdge *e_connect,
113         BMLoop *l_a_outer, BMLoop *l_b_outer,
114         BMLoop *l_a_inner, BMLoop *l_b_inner)
115 {
116         /**
117          * Check for diverged values at the vert shared by
118          * \a l_a_inner & \a l_b_inner.
119          *
120          * <pre>
121          *  -----------------------+
122          *           l_a_outer--> /|<--l_b_outer
123          *                       / |
124          *      (face a)        /  |
125          *                     / <--e_connect
126          *                    /    |
127          * e_a  l_a_inner--> / <--l_b_inner
128          * -----------------+      |
129          *                 /|      |
130          * l_a/b_inner_inset| (face b)
131          *               /  |      |
132          *              /   |e_b   |
133          *  (inset face(s)) |      |
134          *            /     |      |
135          * </pre>
136          */
137
138         const bool is_flip = (l_a_inner->next == l_a_outer);
139         BMLoop *l_a_inner_inset, *l_b_inner_inset;
140         BMEdge *e_a, *e_b;
141         int layer_n;
142
143         /* paranoid sanity checks */
144         BLI_assert(l_a_outer->v == l_b_outer->v);
145         BLI_assert(l_a_inner->v == l_b_inner->v);
146
147         BLI_assert(l_b_inner->f != l_a_inner->f);
148
149         BLI_assert(l_a_outer->f == l_a_inner->f);
150         BLI_assert(l_b_outer->f == l_b_inner->f);
151
152         (void) e_connect;
153         BLI_assert(BM_edge_in_face(e_connect, l_a_inner->f));
154         BLI_assert(BM_edge_in_face(e_connect, l_b_inner->f));
155
156         if (is_flip) {
157                 e_a = l_a_inner->prev->e;
158                 e_b = l_b_inner->e;
159         }
160         else {
161                 e_a = l_a_inner->e;
162                 e_b = l_b_inner->prev->e;
163         }
164
165         l_a_inner_inset = BM_edge_other_loop(e_a, l_a_inner);
166         l_b_inner_inset = BM_edge_other_loop(e_b, l_b_inner);
167         BLI_assert(l_a_inner_inset->v == l_b_inner_inset->v);
168
169         /* check if there is no chance of diversion */
170         if (l_a_inner_inset->f == l_b_inner_inset->f) {
171                 return;
172         }
173
174         for (layer_n = 0; layer_n < bm->ldata.totlayer; layer_n++) {
175                 const int type = bm->ldata.layers[layer_n].type;
176                 const int offset = bm->ldata.layers[layer_n].offset;
177                 if (!CustomData_layer_has_math(&bm->ldata, layer_n))
178                         continue;
179
180                 /* check we begin with merged data */
181                 if ((CustomData_data_equals(
182                          type,
183                          BM_ELEM_CD_GET_VOID_P(l_a_outer, offset),
184                          BM_ELEM_CD_GET_VOID_P(l_b_outer, offset))  == true)
185
186                     /* epsilon for comparing UV's is too big, gives noticable problems */
187 #if 0
188                     &&
189                     /* check if the data ends up diverged */
190                     (CustomData_data_equals(
191                          type,
192                          BM_ELEM_CD_GET_VOID_P(l_a_inner, offset),
193                          BM_ELEM_CD_GET_VOID_P(l_b_inner, offset)) == false)
194 #endif
195                     )
196                 {
197                         /* no need to allocate a temp block:
198                          * a = (a + b);
199                          * a *= 0.5f;
200                          * b = a;
201                          */
202                         const void *data_src;
203
204                         CustomData_data_mix_value(
205                                 type,
206                                 BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset),
207                                 BM_ELEM_CD_GET_VOID_P(l_b_inner_inset, offset),
208                                 CDT_MIX_MIX, 0.5f);
209                         CustomData_data_copy_value(
210                                 type,
211                                 BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset),
212                                 BM_ELEM_CD_GET_VOID_P(l_b_inner_inset, offset));
213
214                         /* use this as a reference (could be 'l_b_inner_inset' too) */
215                         data_src = BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset);
216
217                         /* check if the 2 faces share an edge */
218                         if (is_flip ?
219                             (l_b_inner_inset->e == l_a_inner_inset->prev->e) :
220                             (l_a_inner_inset->e == l_b_inner_inset->prev->e))
221                         {
222                                 /* simple case, we have all loops already */
223                         }
224                         else {
225                                 /* compare with (l_a_inner / l_b_inner) and assign the blended value if they match */
226                                 BMIter iter;
227                                 BMLoop *l_iter;
228                                 const void *data_cmp_a = BM_ELEM_CD_GET_VOID_P(l_b_inner, offset);
229                                 const void *data_cmp_b = BM_ELEM_CD_GET_VOID_P(l_a_inner, offset);
230                                 BM_ITER_ELEM (l_iter, &iter, l_a_inner_inset->v, BM_LOOPS_OF_VERT) {
231                                         if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) {
232                                                 if (!ELEM(l_iter, l_a_inner, l_b_inner, l_a_inner_inset, l_b_inner_inset)) {
233                                                         void *data_dst = BM_ELEM_CD_GET_VOID_P(l_iter, offset);
234
235                                                         if (CustomData_data_equals(type, data_dst, data_cmp_a) ||
236                                                             CustomData_data_equals(type, data_dst, data_cmp_b))
237                                                         {
238                                                                 CustomData_data_copy_value(type, data_src, data_dst);
239                                                         }
240                                                 }
241                                         }
242                                 }
243                         }
244
245                         CustomData_data_copy_value(type, data_src, BM_ELEM_CD_GET_VOID_P(l_b_inner, offset));
246                         CustomData_data_copy_value(type, data_src, BM_ELEM_CD_GET_VOID_P(l_a_inner, offset));
247                 }
248         }
249 }
250 #endif  /* USE_LOOP_CUSTOMDATA_MERGE */
251
252
253 /* -------------------------------------------------------------------- */
254 /* Inset Individual */
255
256 static void bmo_face_inset_individual(
257         BMesh *bm, BMFace *f, MemArena *interp_arena,
258         const float thickness, const float depth,
259         const bool use_even_offset, const bool use_relative_offset, const bool use_interpolate)
260 {
261         InterpFace *iface = NULL;
262
263         /* stores verts split away from the face (aligned with face verts) */
264         BMVert **verts = BLI_array_alloca(verts, f->len);
265         /* store edge normals (aligned with face-loop-edges) */
266         float (*edge_nors)[3] = BLI_array_alloca(edge_nors, f->len);
267         float (*coords)[3] = BLI_array_alloca(coords, f->len);
268
269         BMLoop *l_iter, *l_first;
270         BMLoop *l_other;
271         uint i;
272         float e_length_prev;
273
274         l_first = BM_FACE_FIRST_LOOP(f);
275
276         /* split off all loops */
277         l_iter = l_first;
278         i = 0;
279         do {
280                 BMVert *v_other = l_iter->v;
281                 BMVert *v_sep = BM_face_loop_separate(bm, l_iter);
282                 if (v_sep == v_other) {
283                         v_other = BM_vert_create(bm, l_iter->v->co, l_iter->v, BM_CREATE_NOP);
284                 }
285                 verts[i] = v_other;
286
287                 /* unrelated to splitting, but calc here */
288                 BM_edge_calc_face_tangent(l_iter->e, l_iter, edge_nors[i]);
289         } while ((void)i++, ((l_iter = l_iter->next) != l_first));
290
291
292         /* build rim faces */
293         l_iter = l_first;
294         i = 0;
295         do {
296                 BMFace *f_new_outer;
297                 BMVert *v_other = verts[i];
298                 BMVert *v_other_next = verts[(i + 1) % f->len];
299
300                 BMEdge *e_other = BM_edge_create(bm, v_other, v_other_next, l_iter->e, BM_CREATE_NO_DOUBLE);
301                 (void)e_other;
302
303                 f_new_outer = BM_face_create_quad_tri(bm,
304                                                       v_other,
305                                                       v_other_next,
306                                                       l_iter->next->v,
307                                                       l_iter->v,
308                                                       f, BM_CREATE_NOP);
309                 BMO_face_flag_enable(bm, f_new_outer, ELE_NEW);
310
311                 /* copy loop data */
312                 l_other = l_iter->radial_next;
313                 BM_elem_attrs_copy(bm, bm, l_iter->next, l_other->prev);
314                 BM_elem_attrs_copy(bm, bm, l_iter, l_other->next->next);
315
316                 if (use_interpolate == false) {
317                         BM_elem_attrs_copy(bm, bm, l_iter->next, l_other);
318                         BM_elem_attrs_copy(bm, bm, l_iter, l_other->next);
319                 }
320         } while ((void)i++, ((l_iter = l_iter->next) != l_first));
321
322         /* hold interpolation values */
323         if (use_interpolate) {
324                 iface = BLI_memarena_alloc(interp_arena, sizeof(*iface));
325                 bm_interp_face_store(iface, bm, f, interp_arena);
326         }
327
328         /* Calculate translation vector for new */
329         l_iter = l_first;
330         i = 0;
331
332         if (depth != 0.0f) {
333                 e_length_prev = BM_edge_calc_length(l_iter->prev->e);
334         }
335
336         do {
337                 const float *eno_prev = edge_nors[(i ? i : f->len) - 1];
338                 const float *eno_next = edge_nors[i];
339                 float tvec[3];
340                 float v_new_co[3];
341
342                 add_v3_v3v3(tvec, eno_prev, eno_next);
343                 normalize_v3(tvec);
344
345                 copy_v3_v3(v_new_co, l_iter->v->co);
346
347                 if (use_even_offset) {
348                         mul_v3_fl(tvec, shell_v3v3_mid_normalized_to_dist(eno_prev,  eno_next));
349                 }
350
351                 /* Modify vertices and their normals */
352                 if (use_relative_offset) {
353                         mul_v3_fl(tvec, (BM_edge_calc_length(l_iter->e) + BM_edge_calc_length(l_iter->prev->e)) / 2.0f);
354                 }
355
356                 madd_v3_v3fl(v_new_co, tvec, thickness);
357
358                 /* Set normal, add depth and write new vertex position*/
359                 copy_v3_v3(l_iter->v->no, f->no);
360
361                 if (depth != 0.0f) {
362                         const float e_length = BM_edge_calc_length(l_iter->e);
363                         const float fac = depth * (use_relative_offset ? ((e_length_prev + e_length) * 0.5f) : 1.0f);
364                         e_length_prev = e_length;
365
366                         madd_v3_v3fl(v_new_co, f->no, fac);
367                 }
368
369
370
371                 copy_v3_v3(coords[i], v_new_co);
372         } while ((void)i++, ((l_iter = l_iter->next) != l_first));
373
374         /* update the coords */
375         l_iter = l_first;
376         i = 0;
377         do {
378                 copy_v3_v3(l_iter->v->co, coords[i]);
379         } while ((void)i++, ((l_iter = l_iter->next) != l_first));
380
381
382         if (use_interpolate) {
383                 BM_face_interp_from_face_ex(
384                         bm, iface->f, iface->f, true,
385                         (const void **)iface->blocks_l, (const void **)iface->blocks_v,
386                         iface->cos_2d, iface->axis_mat);
387
388                 /* build rim faces */
389                 l_iter = l_first;
390                 do {
391                         /* copy loop data */
392                         l_other = l_iter->radial_next;
393
394                         BM_elem_attrs_copy(bm, bm, l_iter->next, l_other);
395                         BM_elem_attrs_copy(bm, bm, l_iter, l_other->next);
396                 } while ((l_iter = l_iter->next) != l_first);
397
398                 bm_interp_face_free(iface, bm);
399         }
400 }
401
402
403 /**
404  * Individual Face Inset.
405  * Find all tagged faces (f), duplicate edges around faces, inset verts of
406  * created edges, create new faces between old and new edges, fill face
407  * between connected new edges, kill old face (f).
408  */
409 void bmo_inset_individual_exec(BMesh *bm, BMOperator *op)
410 {
411         BMFace *f;
412
413         BMOIter oiter;
414         MemArena *interp_arena = NULL;
415
416         const float thickness = BMO_slot_float_get(op->slots_in, "thickness");
417         const float depth = BMO_slot_float_get(op->slots_in, "depth");
418         const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset");
419         const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset");
420         const bool use_interpolate = BMO_slot_bool_get(op->slots_in, "use_interpolate");
421
422         /* Only tag faces in slot */
423         BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false);
424
425         BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false);
426
427         if (use_interpolate) {
428                 interp_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
429         }
430
431         BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) {
432                 bmo_face_inset_individual(
433                         bm, f, interp_arena,
434                         thickness, depth,
435                         use_even_offset, use_relative_offset, use_interpolate);
436
437                 if (use_interpolate) {
438                         BLI_memarena_clear(interp_arena);
439                 }
440         }
441
442         /* we could flag new edges/verts too, is it useful? */
443         BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_NEW);
444
445         if (use_interpolate) {
446                 BLI_memarena_free(interp_arena);
447         }
448 }
449
450
451
452 /* -------------------------------------------------------------------- */
453 /* Inset Region */
454
455 typedef struct SplitEdgeInfo {
456         float   no[3];
457         float   length;
458         BMEdge *e_old;
459         BMEdge *e_new;
460         BMLoop *l;
461 } SplitEdgeInfo;
462
463 /**
464  * return the tag loop where there is...
465  * - only 1 tagged face attached to this edge.
466  * - 1 or more untagged faces.
467  *
468  * \note this function looks to be expensive
469  * but in most cases it will only do 2 iterations.
470  */
471 static BMLoop *bm_edge_is_mixed_face_tag(BMLoop *l)
472 {
473         if (LIKELY(l != NULL)) {
474                 int tot_tag = 0;
475                 int tot_untag = 0;
476                 BMLoop *l_iter;
477                 BMLoop *l_tag = NULL;
478                 l_iter = l;
479                 do {
480                         if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) {
481                                 /* more than one tagged face - bail out early! */
482                                 if (tot_tag == 1) {
483                                         return NULL;
484                                 }
485                                 l_tag = l_iter;
486                                 tot_tag++;
487                         }
488                         else {
489                                 tot_untag++;
490                         }
491
492                 } while ((l_iter = l_iter->radial_next) != l);
493
494                 return ((tot_tag == 1) && (tot_untag >= 1)) ? l_tag : NULL;
495         }
496         else {
497                 return NULL;
498         }
499 }
500
501 static float bm_edge_info_average_length(BMVert *v, SplitEdgeInfo *edge_info)
502 {
503         BMIter iter;
504         BMEdge *e;
505
506         float len = 0.0f;
507         int tot = 0;
508
509
510         BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
511                 const int i = BM_elem_index_get(e);
512                 if (i != -1) {
513                         len += edge_info[i].length;
514                         tot++;
515                 }
516         }
517
518         BLI_assert(tot != 0);
519         return len / (float)tot;
520 }
521
522 /**
523  * implementation is as follows...
524  *
525  * - set all faces as tagged/untagged based on selection.
526  * - find all edges that have 1 tagged, 1 untagged face.
527  * - separate these edges and tag vertices, set their index to point to the original edge.
528  * - build faces between old/new edges.
529  * - inset the new edges into their faces.
530  */
531
532 void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
533 {
534         const bool use_outset          = BMO_slot_bool_get(op->slots_in, "use_outset");
535         const bool use_boundary        = BMO_slot_bool_get(op->slots_in, "use_boundary") && (use_outset == false);
536         const bool use_even_offset     = BMO_slot_bool_get(op->slots_in, "use_even_offset");
537         const bool use_even_boundary   = use_even_offset; /* could make own option */
538         const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset");
539         const bool use_edge_rail       = BMO_slot_bool_get(op->slots_in, "use_edge_rail");
540         const bool use_interpolate     = BMO_slot_bool_get(op->slots_in, "use_interpolate");
541         const float thickness          = BMO_slot_float_get(op->slots_in, "thickness");
542         const float depth              = BMO_slot_float_get(op->slots_in, "depth");
543 #ifdef USE_LOOP_CUSTOMDATA_MERGE
544         const bool has_math_ldata      = (use_interpolate && CustomData_has_math(&bm->ldata));
545 #endif
546
547         int edge_info_len = 0;
548
549         BMIter iter;
550         SplitEdgeInfo *edge_info;
551         SplitEdgeInfo *es;
552
553         /* Interpolation Vars */
554         /* an array alligned with faces but only fill items which are used. */
555         InterpFace **iface_array = NULL;
556         int          iface_array_len;
557         MemArena *interp_arena = NULL;
558
559         /* BMVert original location storage */
560         const bool use_vert_coords_orig = use_edge_rail;
561         MemArena *vert_coords_orig = NULL;
562         GHash *vert_coords = NULL;
563
564         BMVert *v;
565         BMEdge *e;
566         BMFace *f;
567         int i, k;
568
569         if (use_interpolate) {
570                 interp_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
571                 /* warning, we could be more clever here and not over alloc */
572                 iface_array = MEM_callocN(sizeof(*iface_array) * bm->totface, __func__);
573                 iface_array_len = bm->totface;
574         }
575
576         if (use_outset == false) {
577                 BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false);
578                 BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false);
579         }
580         else {
581                 BM_mesh_elem_hflag_enable_all(bm, BM_FACE, BM_ELEM_TAG, false);
582                 BMO_slot_buffer_hflag_disable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false);
583                 BMO_slot_buffer_hflag_disable(bm, op->slots_in, "faces_exclude", BM_FACE, BM_ELEM_TAG, false);
584         }
585
586         /* first count all inset edges we will split */
587         /* fill in array and initialize tagging */
588         BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
589                 if (
590                     /* tag if boundary is enabled */
591                     (use_boundary && BM_edge_is_boundary(e) && BM_elem_flag_test(e->l->f, BM_ELEM_TAG)) ||
592
593                     /* tag if edge is an interior edge inbetween a tagged and untagged face */
594                     (bm_edge_is_mixed_face_tag(e->l)))
595                 {
596                         /* tag */
597                         BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
598                         BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
599                         BM_elem_flag_enable(e, BM_ELEM_TAG);
600
601                         BM_elem_index_set(e, edge_info_len); /* set_dirty! */
602                         edge_info_len++;
603                 }
604                 else {
605                         BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
606                         BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
607                         BM_elem_flag_disable(e, BM_ELEM_TAG);
608
609                         BM_elem_index_set(e, -1); /* set_dirty! */
610                 }
611         }
612         bm->elem_index_dirty |= BM_EDGE;
613
614         edge_info = MEM_mallocN(edge_info_len * sizeof(SplitEdgeInfo), __func__);
615
616         /* fill in array and initialize tagging */
617         es = edge_info;
618         BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
619                 i = BM_elem_index_get(e);
620                 if (i != -1) {
621                         /* calc edge-split info */
622                         es->length = BM_edge_calc_length(e);
623                         es->e_old = e;
624                         es++;
625                         /* initialize no and e_new after */
626                 }
627         }
628
629
630         if (use_vert_coords_orig) {
631                 vert_coords_orig = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
632                 vert_coords = BLI_ghash_ptr_new(__func__);
633         }
634
635         /* util macros */
636 #define VERT_ORIG_STORE(_v)  { \
637                 float *_co = BLI_memarena_alloc(vert_coords_orig, sizeof(float[3])); \
638                 copy_v3_v3(_co, (_v)->co); \
639                 BLI_ghash_insert(vert_coords, _v, _co); \
640         } (void)0
641 #define VERT_ORIG_GET(_v)  \
642         (const float *)BLI_ghash_lookup_default(vert_coords, (_v), (_v)->co)
643         /* memory for the coords isn't given back to the arena,
644          * acceptable in this case since it runs a fixed number of times. */
645 #define VERT_ORIG_REMOVE(_v)  \
646         BLI_ghash_remove(vert_coords, (_v), NULL, NULL)
647
648
649         for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
650                 if ((es->l = bm_edge_is_mixed_face_tag(es->e_old->l))) {
651                         /* do nothing */
652                 }
653                 else {
654                         es->l = es->e_old->l; /* must be a boundary */
655                 }
656
657                 /* run the separate arg */
658                 if (!BM_edge_is_boundary(es->e_old)) {
659                         bmesh_kernel_edge_separate(bm, es->e_old, es->l, false);
660                 }
661
662                 /* calc edge-split info */
663                 es->e_new = es->l->e;
664                 BM_edge_calc_face_tangent(es->e_new, es->l, es->no);
665
666                 if (es->e_new == es->e_old) { /* happens on boundary edges */
667                         /* take care here, we're creating this double edge which _must_ have its verts replaced later on */
668                         es->e_old = BM_edge_create(bm, es->e_new->v1, es->e_new->v2, es->e_new, BM_CREATE_NOP);
669                 }
670
671                 /* store index back to original in 'edge_info' */
672                 BM_elem_index_set(es->e_new, i);
673                 BM_elem_flag_enable(es->e_new, BM_ELEM_TAG);
674
675                 /* important to tag again here */
676                 BM_elem_flag_enable(es->e_new->v1, BM_ELEM_TAG);
677                 BM_elem_flag_enable(es->e_new->v2, BM_ELEM_TAG);
678
679
680                 /* initialize interpolation vars */
681                 /* this could go in its own loop,
682                  * only use the 'es->l->f' so we don't store loops for faces which have no mixed selection
683                  *
684                  * note: faces on the other side of the inset will be interpolated too since this is hard to
685                  * detect, just allow it even though it will cause some redundant interpolation */
686                 if (use_interpolate) {
687                         BMIter viter;
688                         BM_ITER_ELEM (v, &viter, es->l->e, BM_VERTS_OF_EDGE) {
689                                 BMIter fiter;
690                                 BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
691                                         const int j = BM_elem_index_get(f);
692                                         if (iface_array[j] == NULL) {
693                                                 InterpFace *iface = BLI_memarena_alloc(interp_arena, sizeof(*iface));
694                                                 bm_interp_face_store(iface, bm, f, interp_arena);
695                                                 iface_array[j] = iface;
696                                         }
697                                 }
698                         }
699                 }
700                 /* done interpolation */
701         }
702
703         /* show edge normals for debugging */
704 #if 0
705         for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
706                 float tvec[3];
707                 BMVert *v1, *v2;
708
709                 mid_v3_v3v3(tvec, es->e_new->v1->co, es->e_new->v2->co);
710
711                 v1 = BM_vert_create(bm, tvec, NULL, BM_CREATE_NOP);
712                 v2 = BM_vert_create(bm, tvec, NULL, BM_CREATE_NOP);
713                 madd_v3_v3fl(v2->co, es->no, 0.1f);
714                 BM_edge_create(bm, v1, v2, NULL, 0);
715         }
716 #endif
717
718         /* execute the split and position verts, it would be most obvious to loop over verts
719          * here but don't do this since we will be splitting them off (iterating stuff you modify is bad juju)
720          * instead loop over edges then their verts */
721         for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
722                 for (int j = 0; j < 2; j++) {
723                         v = (j == 0) ? es->e_new->v1 : es->e_new->v2;
724
725                         /* end confusing part - just pretend this is a typical loop on verts */
726
727                         /* only split of tagged verts - used by separated edges */
728
729                         /* comment the first part because we know this verts in a tagged face */
730                         if (/* v->e && */BM_elem_flag_test(v, BM_ELEM_TAG)) {
731                                 BMVert **vout;
732                                 int r_vout_len;
733                                 BMVert *v_glue = NULL;
734
735                                 /* disable touching twice, this _will_ happen if the flags not disabled */
736                                 BM_elem_flag_disable(v, BM_ELEM_TAG);
737
738                                 bmesh_kernel_vert_separate(bm, v, &vout, &r_vout_len, false);
739                                 v = NULL; /* don't use again */
740
741                                 /* in some cases the edge doesn't split off */
742                                 if (r_vout_len == 1) {
743                                         if (use_vert_coords_orig) {
744                                                 VERT_ORIG_STORE(vout[0]);
745                                         }
746                                         MEM_freeN(vout);
747                                         continue;
748                                 }
749
750                                 for (k = 0; k < r_vout_len; k++) {
751                                         BMVert *v_split = vout[k]; /* only to avoid vout[k] all over */
752
753                                         /* need to check if this vertex is from a */
754                                         int vert_edge_tag_tot = 0;
755                                         int vecpair[2];
756
757                                         if (use_vert_coords_orig) {
758                                                 VERT_ORIG_STORE(v_split);
759                                         }
760
761                                         /* find adjacent */
762                                         BM_ITER_ELEM (e, &iter, v_split, BM_EDGES_OF_VERT) {
763                                                 if (BM_elem_flag_test(e, BM_ELEM_TAG) &&
764                                                     e->l && BM_elem_flag_test(e->l->f, BM_ELEM_TAG))
765                                                 {
766                                                         if (vert_edge_tag_tot < 2) {
767                                                                 vecpair[vert_edge_tag_tot] = BM_elem_index_get(e);
768                                                                 BLI_assert(vecpair[vert_edge_tag_tot] != -1);
769                                                         }
770
771                                                         vert_edge_tag_tot++;
772                                                 }
773                                         }
774
775                                         if (vert_edge_tag_tot != 0) {
776                                                 float tvec[3];
777
778                                                 if (vert_edge_tag_tot >= 2) { /* 2 edge users - common case */
779                                                         /* now there are 2 cases to check for,
780                                                          *
781                                                          * if both edges use the same face OR both faces have the same normal,
782                                                          * ...then we can calculate an edge that fits nicely between the 2 edge normals.
783                                                          *
784                                                          * Otherwise use the shared edge OR the corner defined by these 2 face normals,
785                                                          * when both edges faces are adjacent this works best but even when this vertex
786                                                          * fans out faces it should work ok.
787                                                          */
788
789                                                         SplitEdgeInfo *e_info_a = &edge_info[vecpair[0]];
790                                                         SplitEdgeInfo *e_info_b = &edge_info[vecpair[1]];
791
792                                                         BMFace *f_a = e_info_a->l->f;
793                                                         BMFace *f_b = e_info_b->l->f;
794
795                                                         /* set to true when we're not in-between (e_info_a->no, e_info_b->no) exactly
796                                                          * in this case use a check the angle of the tvec when calculating shell thickness */
797                                                         bool is_mid = true;
798
799                                                         /* we use this as either the normal OR to find the right direction for the
800                                                          * cross product between both face normals */
801                                                         add_v3_v3v3(tvec, e_info_a->no, e_info_b->no);
802
803                                                         if (use_edge_rail == false) {
804                                                                 /* pass */
805                                                         }
806                                                         else if (f_a != f_b) {
807                                                                 /* these lookups are very quick */
808                                                                 BMLoop *l_other_a = BM_loop_other_vert_loop(e_info_a->l, v_split);
809                                                                 BMLoop *l_other_b = BM_loop_other_vert_loop(e_info_b->l, v_split);
810
811                                                                 if (l_other_a->v == l_other_b->v) {
812                                                                         /* both edges faces are adjacent, but we don't need to know the shared edge
813                                                                          * having both verts is enough. */
814                                                                         const float *co_other;
815
816                                                                         /* note that we can't use 'l_other_a->v' directly since it
817                                                                          * may be inset and give a feedback loop. */
818                                                                         if (use_vert_coords_orig) {
819                                                                                 co_other = VERT_ORIG_GET(l_other_a->v);
820                                                                         }
821                                                                         else {
822                                                                                 co_other = l_other_a->v->co;
823                                                                         }
824
825                                                                         sub_v3_v3v3(tvec, co_other, v_split->co);
826                                                                         is_mid = false;
827                                                                 }
828
829                                                                 /* distable gives odd results at times, see [#39288] */
830 #if 0
831                                                                 else if (compare_v3v3(f_a->no, f_b->no, 0.001f) == false) {
832                                                                         /* epsilon increased to fix [#32329] */
833
834                                                                         /* faces don't touch,
835                                                                          * just get cross product of their normals, its *good enough*
836                                                                          */
837                                                                         float tno[3];
838                                                                         cross_v3_v3v3(tno, f_a->no, f_b->no);
839                                                                         if (dot_v3v3(tvec, tno) < 0.0f) {
840                                                                                 negate_v3(tno);
841                                                                         }
842                                                                         copy_v3_v3(tvec, tno);
843                                                                         is_mid = false;
844                                                                 }
845 #endif
846                                                         }
847                                                         normalize_v3(tvec);
848
849                                                         /* scale by edge angle */
850                                                         if (use_even_offset) {
851                                                                 if (is_mid) {
852                                                                         mul_v3_fl(tvec, shell_v3v3_mid_normalized_to_dist(e_info_a->no,
853                                                                                                                           e_info_b->no));
854                                                                 }
855                                                                 else {
856                                                                         /* use the largest angle */
857                                                                         mul_v3_fl(tvec,
858                                                                                   shell_v3v3_normalized_to_dist(tvec,
859                                                                                                                 len_squared_v3v3(tvec, e_info_a->no) >
860                                                                                                                 len_squared_v3v3(tvec, e_info_b->no) ?
861                                                                                                                     e_info_a->no : e_info_b->no));
862                                                                 }
863                                                         }
864
865                                                         /* scale relative to edge lengths */
866                                                         if (use_relative_offset) {
867                                                                 mul_v3_fl(tvec, (edge_info[vecpair[0]].length + edge_info[vecpair[1]].length) / 2.0f);
868                                                         }
869                                                 }
870                                                 else if (vert_edge_tag_tot == 1) { /* 1 edge user - boundary vert, not so common */
871                                                         const float *e_no_a = edge_info[vecpair[0]].no;
872
873                                                         if (use_even_boundary) {
874
875                                                                 /* This case where only one edge attached to v_split
876                                                                  * is used - ei - the face to inset is on a boundary.
877                                                                  *
878                                                                  *                  We want the inset to align flush with the
879                                                                  *                  boundary edge, not the normal of the interior
880                                                                  *             <--- edge which would give an unsightly bump.
881                                                                  * --+-------------------------+---------------+--
882                                                                  *   |^v_other    ^e_other    /^v_split        |
883                                                                  *   |                       /                 |
884                                                                  *   |                      /                  |
885                                                                  *   |                     / <- tag split edge |
886                                                                  *   |                    /                    |
887                                                                  *   |                   /                     |
888                                                                  *   |                  /                      |
889                                                                  * --+-----------------+-----------------------+--
890                                                                  *   |                                         |
891                                                                  *   |                                         |
892                                                                  *
893                                                                  * note, the fact we are doing location comparisons on verts that are moved about
894                                                                  * doesn't matter because the direction will remain the same in this case.
895                                                                  */
896
897                                                                 BMEdge *e_other;
898                                                                 BMVert *v_other;
899                                                                 /* loop will always be either next of prev */
900                                                                 BMLoop *l = v_split->e->l;
901                                                                 if (l->prev->v == v_split) {
902                                                                         l = l->prev;
903                                                                 }
904                                                                 else if (l->next->v == v_split) {
905                                                                         l = l->next;
906                                                                 }
907                                                                 else if (l->v == v_split) {
908                                                                         /* pass */
909                                                                 }
910                                                                 else {
911                                                                         /* should never happen */
912                                                                         BLI_assert(0);
913                                                                 }
914
915                                                                 /* find the edge which is _not_ being split here */
916                                                                 if (!BM_elem_flag_test(l->e, BM_ELEM_TAG)) {
917                                                                         e_other = l->e;
918                                                                 }
919                                                                 else if (!BM_elem_flag_test(l->prev->e, BM_ELEM_TAG)) {
920                                                                         e_other = l->prev->e;
921                                                                 }
922                                                                 else {
923                                                                         BLI_assert(0);
924                                                                         e_other = NULL;
925                                                                 }
926
927                                                                 v_other = BM_edge_other_vert(e_other, v_split);
928                                                                 sub_v3_v3v3(tvec, v_other->co, v_split->co);
929                                                                 normalize_v3(tvec);
930
931                                                                 if (use_even_offset) {
932                                                                         mul_v3_fl(tvec, shell_v3v3_normalized_to_dist(e_no_a, tvec));
933                                                                 }
934                                                         }
935                                                         else {
936                                                                 copy_v3_v3(tvec, e_no_a);
937                                                         }
938
939                                                         /* use_even_offset - doesn't apply here */
940
941                                                         /* scale relative to edge length */
942                                                         if (use_relative_offset) {
943                                                                 mul_v3_fl(tvec, edge_info[vecpair[0]].length);
944                                                         }
945                                                 }
946                                                 else {
947                                                         /* should never happen */
948                                                         BLI_assert(0);
949                                                         zero_v3(tvec);
950                                                 }
951
952                                                 /* apply the offset */
953                                                 madd_v3_v3fl(v_split->co, tvec, thickness);
954                                         }
955
956                                         /* this saves expensive/slow glue check for common cases */
957                                         if (r_vout_len > 2) {
958                                                 bool ok = true;
959                                                 /* last step, NULL this vertex if has a tagged face */
960                                                 BM_ITER_ELEM (f, &iter, v_split, BM_FACES_OF_VERT) {
961                                                         if (BM_elem_flag_test(f, BM_ELEM_TAG)) {
962                                                                 ok = false;
963                                                                 break;
964                                                         }
965                                                 }
966
967                                                 if (ok) {
968                                                         if (v_glue == NULL) {
969                                                                 v_glue = v_split;
970                                                         }
971                                                         else {
972                                                                 if (BM_vert_splice(bm, v_glue, v_split)) {
973                                                                         if (use_vert_coords_orig) {
974                                                                                 VERT_ORIG_REMOVE(v_split);
975                                                                         }
976                                                                 }
977                                                         }
978                                                 }
979                                         }
980                                         /* end glue */
981
982                                 }
983                                 MEM_freeN(vout);
984                         }
985                 }
986         }
987
988         if (use_vert_coords_orig) {
989                 BLI_memarena_free(vert_coords_orig);
990                 BLI_ghash_free(vert_coords, NULL, NULL);
991         }
992
993         if (use_interpolate) {
994                 for (i = 0; i < iface_array_len; i++) {
995                         if (iface_array[i]) {
996                                 InterpFace *iface = iface_array[i];
997                                 BM_face_interp_from_face_ex(
998                                         bm, iface->f, iface->f, true,
999                                         (const void **)iface->blocks_l, (const void **)iface->blocks_v,
1000                                         iface->cos_2d, iface->axis_mat);
1001                         }
1002                 }
1003         }
1004
1005         /* create faces */
1006         for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
1007                 BMVert *varr[4] = {NULL};
1008                 int j;
1009                 /* get the verts in the correct order */
1010                 BM_edge_ordered_verts_ex(es->e_new, &varr[1], &varr[0], es->l);
1011 #if 0
1012                 if (varr[0] == es->e_new->v1) {
1013                         varr[2] = es->e_old->v2;
1014                         varr[3] = es->e_old->v1;
1015                 }
1016                 else {
1017                         varr[2] = es->e_old->v1;
1018                         varr[3] = es->e_old->v2;
1019                 }
1020                 j = 4;
1021 #else
1022                 /* slightly trickier check - since we can't assume the verts are split */
1023                 j = 2; /* 2 edges are set */
1024                 if (varr[0] == es->e_new->v1) {
1025                         if (es->e_old->v2 != es->e_new->v2) { varr[j++] = es->e_old->v2; }
1026                         if (es->e_old->v1 != es->e_new->v1) { varr[j++] = es->e_old->v1; }
1027                 }
1028                 else {
1029                         if (es->e_old->v1 != es->e_new->v1) { varr[j++] = es->e_old->v1; }
1030                         if (es->e_old->v2 != es->e_new->v2) { varr[j++] = es->e_old->v2; }
1031                 }
1032
1033                 if (j == 2) {
1034                         /* can't make face! */
1035                         continue;
1036                 }
1037 #endif
1038                 /* no need to check doubles, we KNOW there won't be any */
1039                 /* yes - reverse face is correct in this case */
1040                 f = BM_face_create_verts(bm, varr, j, es->l->f, BM_CREATE_NOP, true);
1041                 BMO_face_flag_enable(bm, f, ELE_NEW);
1042
1043                 /* copy for loop data, otherwise UV's and vcols are no good.
1044                  * tiny speedup here we could be more clever and copy from known adjacent data
1045                  * also - we could attempt to interpolate the loop data, this would be much slower but more useful too */
1046 #if 0
1047                 /* don't use this because face boundaries have no adjacent loops and won't be filled in.
1048                  * instead copy from the opposite side with the code below */
1049                 BM_face_copy_shared(bm, f, NULL, NULL);
1050 #else
1051                 {
1052                         /* 2 inner loops on the edge between the new face and the original */
1053                         BMLoop *l_a;
1054                         BMLoop *l_b;
1055                         BMLoop *l_a_other;
1056                         BMLoop *l_b_other;
1057
1058                         l_a = BM_FACE_FIRST_LOOP(f);
1059                         l_b = l_a->next;
1060
1061                         /* we know this side has a radial_next because of the order of created verts in the quad */
1062                         l_a_other = BM_edge_other_loop(l_a->e, l_a);
1063                         l_b_other = BM_edge_other_loop(l_a->e, l_b);
1064                         BM_elem_attrs_copy(bm, bm, l_a_other, l_a);
1065                         BM_elem_attrs_copy(bm, bm, l_b_other, l_b);
1066
1067                         BLI_assert(l_a->f != l_a_other->f);
1068                         BLI_assert(l_b->f != l_b_other->f);
1069
1070                         /* step around to the opposite side of the quad - warning, this may have no other edges! */
1071                         l_a = l_a->next->next;
1072                         l_b = l_a->next;
1073
1074                         /**
1075                          * Loops vars from newly created face (face_a/b)
1076                          * <pre>
1077                          *              l_a->e & l_b->prev->e
1078                          * +------------------------------------+
1079                          * |\ l_a                          l_b /|
1080                          * | \ l_a->prev->e            l_b->e / |
1081                          * |  \ l_a->prev          l_b->next /  |
1082                          * |   +----------------------------+   |
1083                          * |   |l_a_other    ^     l_b_other|   |
1084                          * |   |        l_b->next->e &...   |   |
1085                          * |   |        l_a->prev->prev->e  |   |
1086                          * |   |        (inset face)        |   |
1087                          * |   +----------------------------+   |
1088                          * |  /                              \  |
1089                          * | /                                \ |
1090                          * |/                                  \|
1091                          * +------------------------------------+
1092                          * </pre>
1093                          */
1094
1095                         /* swap a<->b intentionally */
1096                         if (use_interpolate) {
1097                                 InterpFace *iface = iface_array[BM_elem_index_get(es->l->f)];
1098                                 const int i_a = BM_elem_index_get(l_a_other);
1099                                 const int i_b = BM_elem_index_get(l_b_other);
1100                                 CustomData_bmesh_free_block_data(&bm->ldata, l_b->head.data);
1101                                 CustomData_bmesh_free_block_data(&bm->ldata, l_a->head.data);
1102                                 CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, iface->blocks_l[i_a], &l_b->head.data);
1103                                 CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, iface->blocks_l[i_b], &l_a->head.data);
1104
1105 #ifdef USE_LOOP_CUSTOMDATA_MERGE
1106                                 if (has_math_ldata) {
1107                                         BMEdge *e_connect;
1108
1109                                         /* connecting edge 'a' */
1110                                         e_connect = l_a->prev->e;
1111                                         if (BM_edge_is_manifold(e_connect)) {
1112                                                 bm_loop_customdata_merge(
1113                                                         bm, e_connect,
1114                                                         l_a,       BM_edge_other_loop(e_connect, l_a),
1115                                                         l_a->prev, BM_edge_other_loop(e_connect, l_a->prev));
1116                                         }
1117
1118                                         /* connecting edge 'b' */
1119                                         e_connect = l_b->e;
1120                                         if (BM_edge_is_manifold(e_connect)) {
1121                                                 /* swap arg order to maintain winding */
1122                                                 bm_loop_customdata_merge(
1123                                                         bm, e_connect,
1124                                                         l_b,       BM_edge_other_loop(e_connect, l_b),
1125                                                         l_b->next, BM_edge_other_loop(e_connect, l_b->next));
1126                                         }
1127                                 }
1128 #endif  /* USE_LOOP_CUSTOMDATA_MERGE */
1129                         }
1130                         else {
1131                                 BM_elem_attrs_copy(bm, bm, l_a_other, l_b);
1132                                 BM_elem_attrs_copy(bm, bm, l_b_other, l_a);
1133                         }
1134                 }
1135         }
1136 #endif
1137
1138         if (use_interpolate) {
1139                 for (i = 0; i < iface_array_len; i++) {
1140                         if (iface_array[i]) {
1141                                 bm_interp_face_free(iface_array[i], bm);
1142                         }
1143                 }
1144
1145                 BLI_memarena_free(interp_arena);
1146                 MEM_freeN(iface_array);
1147         }
1148
1149         /* we could flag new edges/verts too, is it useful? */
1150         BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_NEW);
1151
1152         /* cheap feature to add depth to the inset */
1153         if (depth != 0.0f) {
1154                 float (*varr_co)[3];
1155                 BMOIter oiter;
1156
1157                 /* we need to re-calculate tagged normals, but for this purpose we can copy tagged verts from the
1158                  * faces they inset from,  */
1159                 for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
1160                         zero_v3(es->e_new->v1->no);
1161                         zero_v3(es->e_new->v2->no);
1162                 }
1163                 for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
1164                         const float *no = es->l->f->no;
1165                         add_v3_v3(es->e_new->v1->no, no);
1166                         add_v3_v3(es->e_new->v2->no, no);
1167                 }
1168                 for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
1169                         /* annoying, avoid normalizing twice */
1170                         if (len_squared_v3(es->e_new->v1->no) != 1.0f) {
1171                                 normalize_v3(es->e_new->v1->no);
1172                         }
1173                         if (len_squared_v3(es->e_new->v2->no) != 1.0f) {
1174                                 normalize_v3(es->e_new->v2->no);
1175                         }
1176                 }
1177                 /* done correcting edge verts normals */
1178
1179                 /* untag verts */
1180                 BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false);
1181
1182                 /* tag face verts */
1183                 BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) {
1184                         BM_ITER_ELEM (v, &iter, f, BM_VERTS_OF_FACE) {
1185                                 BM_elem_flag_enable(v, BM_ELEM_TAG);
1186                         }
1187                 }
1188
1189                 /* do in 2 passes so moving the verts doesn't feed back into face angle checks
1190                  * which BM_vert_calc_shell_factor uses. */
1191
1192                 /* over allocate */
1193                 varr_co = MEM_callocN(sizeof(*varr_co) * bm->totvert, __func__);
1194
1195                 BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
1196                         if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
1197                                 const float fac = (depth *
1198                                                    (use_relative_offset ? bm_edge_info_average_length(v, edge_info) : 1.0f) *
1199                                                    (use_even_boundary   ? BM_vert_calc_shell_factor(v) : 1.0f));
1200                                 madd_v3_v3v3fl(varr_co[i], v->co, v->no, fac);
1201                         }
1202                 }
1203
1204                 BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
1205                         if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
1206                                 copy_v3_v3(v->co, varr_co[i]);
1207                         }
1208                 }
1209                 MEM_freeN(varr_co);
1210         }
1211
1212         MEM_freeN(edge_info);
1213 }