bmesh operator rename inset -> inset_region
[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_array.h"
35
36 #include "bmesh.h"
37
38 #include "intern/bmesh_operators_private.h" /* own include */
39
40 #define ELE_NEW         1
41
42
43
44 /* -------------------------------------------------------------------- */
45 /* Inset Individual */
46
47
48 /* Holds Per-Face Inset Edge Data */
49 typedef struct EdgeInsetInfo {
50         float no[3];
51         BMEdge *e_old;
52         BMEdge *e_new;
53 } EdgeInsetInfo;
54
55 /**
56  * Individual Face Inset.
57  * Find all tagged faces (f), duplicate edges around faces, inset verts of
58  * created edges, create new faces between old and new edges, fill face
59  * between connected new edges, kill old face (f).
60  */
61 void bmo_inset_individual_exec(BMesh *bm, BMOperator *op)
62 {
63         BMEdge **f_edges = NULL;
64         BMVert **f_verts = NULL;
65         BMFace *f;
66
67         BMOIter oiter;
68         EdgeInsetInfo *eiinfo_arr = NULL;
69
70         BLI_array_declare(eiinfo_arr);
71         BLI_array_declare(f_edges);
72         BLI_array_declare(f_verts);
73
74         const float thickness = BMO_slot_float_get(op->slots_in, "thickness");
75         const float depth = BMO_slot_float_get(op->slots_in, "depth");
76         const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset");
77
78         /* Only tag faces in slot */
79         BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false);
80
81         BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false);
82
83         BMO_ITER(f, &oiter, op->slots_in, "faces", BM_FACE) {
84                 BMLoop *l_iter, *l_first;
85                 BMLoop *l_iter_inner = NULL;
86                 int i;
87
88                 BLI_array_empty(f_verts);
89                 BLI_array_empty(f_edges);
90                 BLI_array_empty(eiinfo_arr);
91                 BLI_array_grow_items(f_verts, f->len);
92                 BLI_array_grow_items(f_edges, f->len);
93                 BLI_array_grow_items(eiinfo_arr, f->len);
94
95                 /* create verts */
96                 i = 0;
97                 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
98                 do {
99                         f_verts[i] = BM_vert_create(bm, l_iter->v->co, l_iter->v, 0);
100                         i++;
101                 } while ((l_iter = l_iter->next) != l_first);
102
103                 /* make edges */
104                 i = 0;
105                 l_iter = l_first;
106                 do {
107                         f_edges[i] = BM_edge_create(bm, f_verts[i], f_verts[(i + 1) % f->len], l_iter->e, 0);
108
109                         eiinfo_arr[i].e_new = f_edges[i];
110                         eiinfo_arr[i].e_old = l_iter->e;
111                         BM_edge_calc_face_tangent(l_iter->e, l_iter, eiinfo_arr[i].no);
112
113                         /* Tagging (old elements) required when iterating over edges
114                          * connected to verts for translation vector calculation */
115                         BM_elem_flag_enable(l_iter->e, BM_ELEM_TAG);
116                         BM_elem_index_set(l_iter->e, i);  /* set_dirty! */
117                         i++;
118                 } while ((l_iter = l_iter->next) != l_first);
119                 /* done with edges */
120
121                 bm->elem_index_dirty |= BM_EDGE;
122
123                 /* Calculate translation vector for new  */
124                 l_iter = l_first;
125                 do {
126                         EdgeInsetInfo *ei_prev = &eiinfo_arr[BM_elem_index_get(l_iter->prev->e)];
127                         EdgeInsetInfo *ei_next = &eiinfo_arr[BM_elem_index_get(l_iter->e)];
128                         float tvec[3];
129                         float v_new_co[3];
130                         int index = 0;
131
132                         add_v3_v3v3(tvec, ei_prev->no, ei_next->no);
133                         normalize_v3(tvec);
134
135                         /* l->e is traversed in order */
136                         index = BM_elem_index_get(l_iter->e);
137
138                         copy_v3_v3(v_new_co, eiinfo_arr[index].e_new->v1->co);
139
140                         if (use_even_offset) {
141                                 mul_v3_fl(tvec, shell_angle_to_dist(angle_normalized_v3v3(ei_prev->no,  ei_next->no) / 2.0f));
142                         }
143
144                         /* Modify vertices and their normals */
145                         madd_v3_v3fl(v_new_co, tvec, thickness);
146
147                         /* Set normal, add depth and write new vertex position*/
148                         copy_v3_v3(eiinfo_arr[index].e_new->v1->no, f->no);
149
150                         madd_v3_v3fl(v_new_co, f->no, depth);
151
152                         copy_v3_v3(eiinfo_arr[index].e_new->v1->co, v_new_co);
153                 } while ((l_iter = l_iter->next) != l_first);
154
155                 {
156                         BMFace *f_new_inner;
157                         /* Create New Inset Faces */
158                         f_new_inner = BM_face_create(bm, f_verts, f_edges, f->len, 0);
159                         if (UNLIKELY(f_new_inner == NULL)) {
160                                 BMO_error_raise(bm, op, BMERR_MESH_ERROR, "Inset failed: could not create inner face.");
161                                 BLI_array_free(f_edges);
162                                 BLI_array_free(f_verts);
163                                 BLI_array_free(eiinfo_arr);
164                                 return;
165                         }
166
167                         /* Copy Face Data */
168                         BM_elem_attrs_copy(bm, bm, f, f_new_inner);
169                         // Don't tag, gives more useful inner/outer select option
170                         // BMO_elem_flag_enable(bm, f_new_inner, ELE_NEW);
171
172                         l_iter_inner = BM_FACE_FIRST_LOOP(f_new_inner);
173                 }
174
175                 l_iter = l_first;
176                 do {
177                         BMFace *f_new_outer;
178
179                         BMLoop *l_iter_sub;
180                         BMLoop *l_a = NULL;
181                         BMLoop *l_b = NULL;
182                         BMLoop *l_a_other = NULL;
183                         BMLoop *l_b_other = NULL;
184                         BMLoop *l_shared = NULL;
185
186                         BM_elem_attrs_copy(bm, bm, l_iter, l_iter_inner);
187
188                         f_new_outer = BM_face_create_quad_tri(bm,
189                                                               l_iter->v,
190                                                               l_iter->next->v,
191                                                               l_iter_inner->next->v,
192                                                               l_iter_inner->v,
193                                                               f, false);
194
195                         if (UNLIKELY(f_new_outer == NULL)) {
196                                 BMO_error_raise(bm, op, BMERR_MESH_ERROR, "Inset failed: could not create an outer face.");
197                                 BLI_array_free(f_edges);
198                                 BLI_array_free(f_verts);
199                                 BLI_array_free(eiinfo_arr);
200                                 return;
201                         }
202
203                         BM_elem_attrs_copy(bm, bm, f, f_new_outer);
204                         BMO_elem_flag_enable(bm, f_new_outer, ELE_NEW);
205                         BM_elem_flag_enable(f_new_outer, BM_ELEM_TAG);
206
207                         /* Copy Loop Data */
208                         l_a = BM_FACE_FIRST_LOOP(f_new_outer);
209                         l_b = l_a->next;
210
211                         l_iter_sub = l_iter;
212
213                         /* Skip old face f and new inset face.
214                          * If loop if found we are a boundary. This
215                          * is required as opposed to BM_edge_is_boundary()
216                          * Because f_new_outer shares an edge with f */
217                         do {
218                                 if (l_iter_sub->f != f && l_iter_sub->f != f_new_outer) {
219                                         l_shared = l_iter_sub;
220                                         break;
221                                 }
222                         } while ((l_iter_sub = l_iter_sub->radial_next) != l_iter);
223
224                         if (l_shared) {
225                                 BM_elem_attrs_copy(bm, bm, l_shared, l_a->next);
226                                 BM_elem_attrs_copy(bm, bm, l_shared->next, l_a);
227                         }
228                         else {
229                                 l_a_other = BM_edge_other_loop(l_a->e, l_a);
230                                 l_b_other = l_a_other->next;
231                                 BM_elem_attrs_copy(bm, bm, l_a_other, l_a);
232                                 BM_elem_attrs_copy(bm, bm, l_b_other, l_b);
233                         }
234
235                         /* Move to the last two loops in new face */
236                         l_a = l_b->next;
237                         l_b = l_a->next;
238
239                         /* This loop should always have >1 radials
240                          * (associated edge connects new and old face) */
241                         BM_elem_attrs_copy(bm, bm, l_iter, l_b);
242                         BM_elem_attrs_copy(bm, bm, l_iter->next, l_a);
243
244                 } while ((l_iter_inner = l_iter_inner->next),
245                          (l_iter = l_iter->next) != l_first);
246
247                 BM_face_kill(bm, f);
248         }
249
250         /* we could flag new edges/verts too, is it useful? */
251         BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_NEW);
252
253         BLI_array_free(f_verts);
254         BLI_array_free(f_edges);
255         BLI_array_free(eiinfo_arr);
256 }
257
258
259
260 /* -------------------------------------------------------------------- */
261 /* Inset Region */
262
263 typedef struct SplitEdgeInfo {
264         float   no[3];
265         float   length;
266         BMEdge *e_old;
267         BMEdge *e_new;
268         BMLoop *l;
269 } SplitEdgeInfo;
270
271 /**
272  * return the tag loop where there is...
273  * - only 1 tagged face attached to this edge.
274  * - 1 or more untagged faces.
275  *
276  * \note this function looks to be expensive
277  * but in most cases it will only do 2 iterations.
278  */
279 static BMLoop *bm_edge_is_mixed_face_tag(BMLoop *l)
280 {
281         if (LIKELY(l != NULL)) {
282                 int tot_tag = 0;
283                 int tot_untag = 0;
284                 BMLoop *l_iter;
285                 BMLoop *l_tag = NULL;
286                 l_iter = l;
287                 do {
288                         if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) {
289                                 /* more then one tagged face - bail out early! */
290                                 if (tot_tag == 1) {
291                                         return NULL;
292                                 }
293                                 l_tag = l_iter;
294                                 tot_tag++;
295                         }
296                         else {
297                                 tot_untag++;
298                         }
299
300                 } while ((l_iter = l_iter->radial_next) != l);
301
302                 return ((tot_tag == 1) && (tot_untag >= 1)) ? l_tag : NULL;
303         }
304         else {
305                 return NULL;
306         }
307 }
308
309 /**
310  * implementation is as follows...
311  *
312  * - set all faces as tagged/untagged based on selection.
313  * - find all edges that have 1 tagged, 1 untagged face.
314  * - separate these edges and tag vertices, set their index to point to the original edge.
315  * - build faces between old/new edges.
316  * - inset the new edges into their faces.
317  */
318
319 void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
320 {
321         const bool use_outset          = BMO_slot_bool_get(op->slots_in, "use_outset");
322         const bool use_boundary        = BMO_slot_bool_get(op->slots_in, "use_boundary") && (use_outset == false);
323         const bool use_even_offset     = BMO_slot_bool_get(op->slots_in, "use_even_offset");
324         const bool use_even_boundry    = use_even_offset; /* could make own option */
325         const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset");
326         const float thickness          = BMO_slot_float_get(op->slots_in, "thickness");
327         const float depth              = BMO_slot_float_get(op->slots_in, "depth");
328
329         int edge_info_len = 0;
330
331         BMIter iter;
332         SplitEdgeInfo *edge_info;
333         SplitEdgeInfo *es;
334
335         BMVert *v;
336         BMEdge *e;
337         BMFace *f;
338         int i, j, k;
339
340         if (use_outset == false) {
341                 BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false);
342                 BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false);
343         }
344         else {
345                 BM_mesh_elem_hflag_enable_all(bm, BM_FACE, BM_ELEM_TAG, false);
346                 BMO_slot_buffer_hflag_disable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false);
347         }
348
349         /* first count all inset edges we will split */
350         /* fill in array and initialize tagging */
351         BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
352                 if (
353                     /* tag if boundary is enabled */
354                     (use_boundary && BM_edge_is_boundary(e) && BM_elem_flag_test(e->l->f, BM_ELEM_TAG)) ||
355
356                     /* tag if edge is an interior edge inbetween a tagged and untagged face */
357                     (bm_edge_is_mixed_face_tag(e->l)))
358                 {
359                         /* tag */
360                         BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
361                         BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
362                         BM_elem_flag_enable(e, BM_ELEM_TAG);
363
364                         BM_elem_index_set(e, edge_info_len); /* set_dirty! */
365                         edge_info_len++;
366                 }
367                 else {
368                         BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
369                         BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
370                         BM_elem_flag_disable(e, BM_ELEM_TAG);
371
372                         BM_elem_index_set(e, -1); /* set_dirty! */
373                 }
374         }
375         bm->elem_index_dirty |= BM_EDGE;
376
377         edge_info = MEM_mallocN(edge_info_len * sizeof(SplitEdgeInfo), __func__);
378
379         /* fill in array and initialize tagging */
380         es = edge_info;
381         BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
382                 i = BM_elem_index_get(e);
383                 if (i != -1) {
384                         /* calc edge-split info */
385                         es->length = BM_edge_calc_length(e);
386                         es->e_old = e;
387                         es++;
388                         /* initialize no and e_new after */
389                 }
390         }
391
392         for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
393                 if ((es->l = bm_edge_is_mixed_face_tag(es->e_old->l))) {
394                         /* do nothing */
395                 }
396                 else {
397                         es->l = es->e_old->l; /* must be a boundary */
398                 }
399
400
401                 /* run the separate arg */
402                 bmesh_edge_separate(bm, es->e_old, es->l);
403
404                 /* calc edge-split info */
405                 es->e_new = es->l->e;
406                 BM_edge_calc_face_tangent(es->e_new, es->l, es->no);
407
408                 if (es->e_new == es->e_old) { /* happens on boundary edges */
409                         /* take care here, we're creating this double edge which _must_ have its verts replaced later on */
410                         es->e_old = BM_edge_create(bm, es->e_new->v1, es->e_new->v2, es->e_new, 0);
411                 }
412
413                 /* store index back to original in 'edge_info' */
414                 BM_elem_index_set(es->e_new, i);
415                 BM_elem_flag_enable(es->e_new, BM_ELEM_TAG);
416
417                 /* important to tag again here */
418                 BM_elem_flag_enable(es->e_new->v1, BM_ELEM_TAG);
419                 BM_elem_flag_enable(es->e_new->v2, BM_ELEM_TAG);
420         }
421
422
423         /* show edge normals for debugging */
424 #if 0
425         for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
426                 float tvec[3];
427                 BMVert *v1, *v2;
428
429                 mid_v3_v3v3(tvec, es->e_new->v1->co, es->e_new->v2->co);
430
431                 v1 = BM_vert_create(bm, tvec, NULL);
432                 v2 = BM_vert_create(bm, tvec, NULL);
433                 madd_v3_v3fl(v2->co, es->no, 0.1f);
434                 BM_edge_create(bm, v1, v2, NULL, 0);
435         }
436 #endif
437
438         /* execute the split and position verts, it would be most obvious to loop over verts
439          * here but don't do this since we will be splitting them off (iterating stuff you modify is bad juju)
440          * instead loop over edges then their verts */
441         for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
442                 for (j = 0; j < 2; j++) {
443                         v = (j == 0) ? es->e_new->v1 : es->e_new->v2;
444
445                         /* end confusing part - just pretend this is a typical loop on verts */
446
447                         /* only split of tagged verts - used by separated edges */
448
449                         /* comment the first part because we know this verts in a tagged face */
450                         if (/* v->e && */BM_elem_flag_test(v, BM_ELEM_TAG)) {
451                                 BMVert **vout;
452                                 int r_vout_len;
453                                 BMVert *v_glue = NULL;
454
455                                 /* disable touching twice, this _will_ happen if the flags not disabled */
456                                 BM_elem_flag_disable(v, BM_ELEM_TAG);
457
458                                 bmesh_vert_separate(bm, v, &vout, &r_vout_len);
459                                 v = NULL; /* don't use again */
460
461                                 /* in some cases the edge doesn't split off */
462                                 if (r_vout_len == 1) {
463                                         MEM_freeN(vout);
464                                         continue;
465                                 }
466
467                                 for (k = 0; k < r_vout_len; k++) {
468                                         BMVert *v_split = vout[k]; /* only to avoid vout[k] all over */
469
470                                         /* need to check if this vertex is from a */
471                                         int vert_edge_tag_tot = 0;
472                                         int vecpair[2];
473
474                                         /* find adjacent */
475                                         BM_ITER_ELEM (e, &iter, v_split, BM_EDGES_OF_VERT) {
476                                                 if (BM_elem_flag_test(e, BM_ELEM_TAG) &&
477                                                     e->l && BM_elem_flag_test(e->l->f, BM_ELEM_TAG))
478                                                 {
479                                                         if (vert_edge_tag_tot < 2) {
480                                                                 vecpair[vert_edge_tag_tot] = BM_elem_index_get(e);
481                                                                 BLI_assert(vecpair[vert_edge_tag_tot] != -1);
482                                                         }
483
484                                                         vert_edge_tag_tot++;
485                                                 }
486                                         }
487
488                                         if (vert_edge_tag_tot != 0) {
489                                                 float tvec[3];
490
491                                                 if (vert_edge_tag_tot >= 2) { /* 2 edge users - common case */
492                                                         /* now there are 2 cases to check for,
493                                                          *
494                                                          * if both edges use the same face OR both faces have the same normal,
495                                                          * ...then we can calculate an edge that fits nicely between the 2 edge normals.
496                                                          *
497                                                          * Otherwise use the shared edge OR the corner defined by these 2 face normals,
498                                                          * when both edges faces are adjacent this works best but even when this vertex
499                                                          * fans out faces it should work ok.
500                                                          */
501
502                                                         SplitEdgeInfo *e_info_a = &edge_info[vecpair[0]];
503                                                         SplitEdgeInfo *e_info_b = &edge_info[vecpair[1]];
504
505                                                         BMFace *f_a = e_info_a->l->f;
506                                                         BMFace *f_b = e_info_b->l->f;
507
508                                                         /* we use this as either the normal OR to find the right direction for the
509                                                          * cross product between both face normals */
510                                                         add_v3_v3v3(tvec, e_info_a->no, e_info_b->no);
511
512                                                         /* epsilon increased to fix [#32329] */
513                                                         if ((f_a == f_b) || compare_v3v3(f_a->no, f_b->no, 0.001f)) {
514                                                                 normalize_v3(tvec);
515                                                         }
516                                                         else {
517                                                                 /* these lookups are very quick */
518                                                                 BMLoop *l_other_a = BM_loop_other_vert_loop(e_info_a->l, v_split);
519                                                                 BMLoop *l_other_b = BM_loop_other_vert_loop(e_info_b->l, v_split);
520
521                                                                 if (l_other_a->v == l_other_b->v) {
522                                                                         /* both edges faces are adjacent, but we don't need to know the shared edge
523                                                                          * having both verts is enough. */
524                                                                         sub_v3_v3v3(tvec, l_other_a->v->co, v_split->co);
525                                                                 }
526                                                                 else {
527                                                                         /* faces don't touch,
528                                                                          * just get cross product of their normals, its *good enough*
529                                                                          */
530                                                                         float tno[3];
531                                                                         cross_v3_v3v3(tno, f_a->no, f_b->no);
532                                                                         if (dot_v3v3(tvec, tno) < 0.0f) {
533                                                                                 negate_v3(tno);
534                                                                         }
535                                                                         copy_v3_v3(tvec, tno);
536                                                                 }
537
538                                                                 normalize_v3(tvec);
539                                                         }
540
541                                                         /* scale by edge angle */
542                                                         if (use_even_offset) {
543                                                                 mul_v3_fl(tvec, shell_angle_to_dist(angle_normalized_v3v3(e_info_a->no,
544                                                                                                                           e_info_b->no) / 2.0f));
545                                                         }
546
547                                                         /* scale relative to edge lengths */
548                                                         if (use_relative_offset) {
549                                                                 mul_v3_fl(tvec, (edge_info[vecpair[0]].length + edge_info[vecpair[1]].length) / 2.0f);
550                                                         }
551                                                 }
552                                                 else if (vert_edge_tag_tot == 1) { /* 1 edge user - boundary vert, not so common */
553                                                         const float *e_no_a = edge_info[vecpair[0]].no;
554
555                                                         if (use_even_boundry) {
556
557                                                                 /* This case where only one edge attached to v_split
558                                                                  * is used - ei - the face to inset is on a boundary.
559                                                                  *
560                                                                  *                  We want the inset to align flush with the
561                                                                  *                  boundary edge, not the normal of the interior
562                                                                  *             <--- edge which would give an unsightly bump.
563                                                                  * --+-------------------------+---------------+--
564                                                                  *   |^v_other    ^e_other    /^v_split        |
565                                                                  *   |                       /                 |
566                                                                  *   |                      /                  |
567                                                                  *   |                     / <- tag split edge |
568                                                                  *   |                    /                    |
569                                                                  *   |                   /                     |
570                                                                  *   |                  /                      |
571                                                                  * --+-----------------+-----------------------+--
572                                                                  *   |                                         |
573                                                                  *   |                                         |
574                                                                  *
575                                                                  * note, the fact we are doing location comparisons on verts that are moved about
576                                                                  * doesn't matter because the direction will remain the same in this case.
577                                                                  */
578
579                                                                 BMEdge *e_other;
580                                                                 BMVert *v_other;
581                                                                 /* loop will always be either next of prev */
582                                                                 BMLoop *l = v_split->e->l;
583                                                                 if (l->prev->v == v_split) {
584                                                                         l = l->prev;
585                                                                 }
586                                                                 else if (l->next->v == v_split) {
587                                                                         l = l->next;
588                                                                 }
589                                                                 else if (l->v == v_split) {
590                                                                         /* pass */
591                                                                 }
592                                                                 else {
593                                                                         /* should never happen */
594                                                                         BLI_assert(0);
595                                                                 }
596
597                                                                 /* find the edge which is _not_ being split here */
598                                                                 if (!BM_elem_flag_test(l->e, BM_ELEM_TAG)) {
599                                                                         e_other = l->e;
600                                                                 }
601                                                                 else if (!BM_elem_flag_test(l->prev->e, BM_ELEM_TAG)) {
602                                                                         e_other = l->prev->e;
603                                                                 }
604                                                                 else {
605                                                                         BLI_assert(0);
606                                                                         e_other = NULL;
607                                                                 }
608
609                                                                 v_other = BM_edge_other_vert(e_other, v_split);
610                                                                 sub_v3_v3v3(tvec, v_other->co, v_split->co);
611                                                                 normalize_v3(tvec);
612
613                                                                 if (use_even_offset) {
614                                                                         mul_v3_fl(tvec, shell_angle_to_dist(angle_normalized_v3v3(e_no_a, tvec)));
615                                                                 }
616                                                         }
617                                                         else {
618                                                                 copy_v3_v3(tvec, e_no_a);
619                                                         }
620
621                                                         /* use_even_offset - doesn't apply here */
622
623                                                         /* scale relative to edge length */
624                                                         if (use_relative_offset) {
625                                                                 mul_v3_fl(tvec, edge_info[vecpair[0]].length);
626                                                         }
627                                                 }
628                                                 else {
629                                                         /* should never happen */
630                                                         BLI_assert(0);
631                                                         zero_v3(tvec);
632                                                 }
633
634                                                 /* apply the offset */
635                                                 madd_v3_v3fl(v_split->co, tvec, thickness);
636                                         }
637
638                                         /* this saves expensive/slow glue check for common cases */
639                                         if (r_vout_len > 2) {
640                                                 bool ok = true;
641                                                 /* last step, NULL this vertex if has a tagged face */
642                                                 BM_ITER_ELEM (f, &iter, v_split, BM_FACES_OF_VERT) {
643                                                         if (BM_elem_flag_test(f, BM_ELEM_TAG)) {
644                                                                 ok = false;
645                                                                 break;
646                                                         }
647                                                 }
648
649                                                 if (ok) {
650                                                         if (v_glue == NULL) {
651                                                                 v_glue = v_split;
652                                                         }
653                                                         else {
654                                                                 BM_vert_splice(bm, v_split, v_glue);
655                                                         }
656                                                 }
657                                         }
658                                         /* end glue */
659
660                                 }
661                                 MEM_freeN(vout);
662                         }
663                 }
664         }
665
666         /* create faces */
667         for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
668                 BMVert *varr[4] = {NULL};
669                 /* get the verts in the correct order */
670                 BM_edge_ordered_verts_ex(es->e_new, &varr[1], &varr[0], es->l);
671 #if 0
672                 if (varr[0] == es->e_new->v1) {
673                         varr[2] = es->e_old->v2;
674                         varr[3] = es->e_old->v1;
675                 }
676                 else {
677                         varr[2] = es->e_old->v1;
678                         varr[3] = es->e_old->v2;
679                 }
680                 j = 4;
681 #else
682                 /* slightly trickier check - since we can't assume the verts are split */
683                 j = 2; /* 2 edges are set */
684                 if (varr[0] == es->e_new->v1) {
685                         if (es->e_old->v2 != es->e_new->v2) { varr[j++] = es->e_old->v2; }
686                         if (es->e_old->v1 != es->e_new->v1) { varr[j++] = es->e_old->v1; }
687                 }
688                 else {
689                         if (es->e_old->v1 != es->e_new->v1) { varr[j++] = es->e_old->v1; }
690                         if (es->e_old->v2 != es->e_new->v2) { varr[j++] = es->e_old->v2; }
691                 }
692
693                 if (j == 2) {
694                         /* can't make face! */
695                         continue;
696                 }
697 #endif
698                 /* no need to check doubles, we KNOW there won't be any */
699                 /* yes - reverse face is correct in this case */
700                 f = BM_face_create_quad_tri_v(bm, varr, j, es->l->f, false);
701                 BMO_elem_flag_enable(bm, f, ELE_NEW);
702
703                 /* copy for loop data, otherwise UV's and vcols are no good.
704                  * tiny speedup here we could be more clever and copy from known adjacent data
705                  * also - we could attempt to interpolate the loop data, this would be much slower but more useful too */
706 #if 0
707                 /* don't use this because face boundaries have no adjacent loops and won't be filled in.
708                  * instead copy from the opposite side with the code below */
709                 BM_face_copy_shared(bm, f);
710 #else
711                 {
712                         /* 2 inner loops on the edge between the new face and the original */
713                         BMLoop *l_a;
714                         BMLoop *l_b;
715                         BMLoop *l_a_other;
716                         BMLoop *l_b_other;
717
718                         l_a = BM_FACE_FIRST_LOOP(f);
719                         l_b = l_a->next;
720
721                         /* we know this side has a radial_next because of the order of created verts in the quad */
722                         l_a_other = BM_edge_other_loop(l_a->e, l_a);
723                         l_b_other = BM_edge_other_loop(l_a->e, l_b);
724                         BM_elem_attrs_copy(bm, bm, l_a_other, l_a);
725                         BM_elem_attrs_copy(bm, bm, l_b_other, l_b);
726
727                         /* step around to the opposite side of the quad - warning, this may have no other edges! */
728                         l_a = l_a->next->next;
729                         l_b = l_a->next;
730                         if (!BM_edge_is_boundary(l_a->e)) {
731                                 /* same as above */
732                                 l_a_other = BM_edge_other_loop(l_a->e, l_a);
733                                 l_b_other = BM_edge_other_loop(l_a->e, l_b);
734                                 BM_elem_attrs_copy(bm, bm, l_a_other, l_a);
735                                 BM_elem_attrs_copy(bm, bm, l_b_other, l_b);
736                         }
737                         else {  /* boundary edges have no useful data to copy from, use opposite side of face */
738                                 /* swap a<->b intentionally */
739                                 BM_elem_attrs_copy(bm, bm, l_a_other, l_b);
740                                 BM_elem_attrs_copy(bm, bm, l_b_other, l_a);
741                         }
742                 }
743 #endif
744         }
745
746         /* we could flag new edges/verts too, is it useful? */
747         BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_NEW);
748
749         /* cheap feature to add depth to the inset */
750         if (depth != 0.0f) {
751                 float (*varr_co)[3];
752                 BMOIter oiter;
753
754                 /* we need to re-calculate tagged normals, but for this purpose we can copy tagged verts from the
755                  * faces they inset from,  */
756                 for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
757                         zero_v3(es->e_new->v1->no);
758                         zero_v3(es->e_new->v2->no);
759                 }
760                 for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
761                         float *no = es->l->f->no;
762                         add_v3_v3(es->e_new->v1->no, no);
763                         add_v3_v3(es->e_new->v2->no, no);
764                 }
765                 for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
766                         /* annoying, avoid normalizing twice */
767                         if (len_squared_v3(es->e_new->v1->no) != 1.0f) {
768                                 normalize_v3(es->e_new->v1->no);
769                         }
770                         if (len_squared_v3(es->e_new->v2->no) != 1.0f) {
771                                 normalize_v3(es->e_new->v2->no);
772                         }
773                 }
774                 /* done correcting edge verts normals */
775
776                 /* untag verts */
777                 BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_TAG, false);
778
779                 /* tag face verts */
780                 BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) {
781                         BM_ITER_ELEM (v, &iter, f, BM_VERTS_OF_FACE) {
782                                 BM_elem_flag_enable(v, BM_ELEM_TAG);
783                         }
784                 }
785
786                 /* do in 2 passes so moving the verts doesn't feed back into face angle checks
787                  * which BM_vert_calc_shell_factor uses. */
788
789                 /* over allocate */
790                 varr_co = MEM_callocN(sizeof(*varr_co) * bm->totvert, __func__);
791
792                 BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
793                         if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
794                                 const float fac = (depth *
795                                                    (use_relative_offset ? BM_vert_calc_mean_tagged_edge_length(v) : 1.0f) *
796                                                    (use_even_boundry    ? BM_vert_calc_shell_factor(v) : 1.0f));
797                                 madd_v3_v3v3fl(varr_co[i], v->co, v->no, fac);
798                         }
799                 }
800
801                 BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
802                         if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
803                                 copy_v3_v3(v->co, varr_co[i]);
804                         }
805                 }
806                 MEM_freeN(varr_co);
807         }
808
809         MEM_freeN(edge_info);
810 }