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