Blender V5.0
bmo_inset.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11
12#include "MEM_guardedalloc.h"
13
14#include "BLI_alloca.h"
15#include "BLI_math_geom.h"
16#include "BLI_math_matrix.h"
17#include "BLI_math_vector.h"
18#include "BLI_memarena.h"
20
21#include "DNA_modifier_enums.h"
22
23#include "BKE_customdata.hh"
24
25#include "bmesh.hh"
26
27#include "intern/bmesh_operators_private.hh" /* own include */
28
29/* Merge loop-data that diverges, see: #41445 */
30#define USE_LOOP_CUSTOMDATA_MERGE
31
32#define ELE_NEW 1
33
34/* -------------------------------------------------------------------- */
46
47/* just enough of a face to store interpolation data we can use once the inset is done */
48struct InterpFace {
50 void **blocks_l;
51 void **blocks_v;
53 float axis_mat[3][3];
54};
55
56/* basically a clone of #BM_vert_interp_from_face */
57static void bm_interp_face_store(InterpFace *iface, BMesh *bm, BMFace *f, MemArena *interp_arena)
58{
59 BMLoop *l_iter, *l_first;
60 void **blocks_l = iface->blocks_l = static_cast<void **>(
61 BLI_memarena_alloc(interp_arena, sizeof(*iface->blocks_l) * f->len));
62 void **blocks_v = iface->blocks_v = static_cast<void **>(
63 BLI_memarena_alloc(interp_arena, sizeof(*iface->blocks_v) * f->len));
64 float (*cos_2d)[2] = iface->cos_2d = static_cast<float (*)[2]>(
65 BLI_memarena_alloc(interp_arena, sizeof(*iface->cos_2d) * f->len));
66 void *axis_mat = iface->axis_mat;
67 int i;
68
70
71 axis_dominant_v3_to_m3(static_cast<float (*)[3]>(axis_mat), f->no);
72
73 iface->f = f;
74
75 i = 0;
76 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
77 do {
78 mul_v2_m3v3(cos_2d[i], static_cast<const float (*)[3]>(axis_mat), l_iter->v->co);
79 blocks_l[i] = nullptr;
80 CustomData_bmesh_copy_block(bm->ldata, l_iter->head.data, &blocks_l[i]);
81 /* if we were not modifying the loops later we would do... */
82 // blocks[i] = l_iter->head.data;
83
84 blocks_v[i] = nullptr;
85 CustomData_bmesh_copy_block(bm->vdata, l_iter->v->head.data, &blocks_v[i]);
86
87 /* use later for index lookups */
88 BM_elem_index_set(l_iter, i); /* set_dirty */
89 } while ((void)i++, (l_iter = l_iter->next) != l_first);
90 bm->elem_index_dirty |= BM_LOOP;
91}
93{
94 void **blocks_l = iface->blocks_l;
95 void **blocks_v = iface->blocks_v;
96 int i;
97
98 for (i = 0; i < iface->f->len; i++) {
99 CustomData_bmesh_free_block(&bm->ldata, &blocks_l[i]);
100 CustomData_bmesh_free_block(&bm->vdata, &blocks_v[i]);
101 }
102}
103
104#ifdef USE_LOOP_CUSTOMDATA_MERGE
110 BMEdge *e_connect,
111 BMLoop *l_a_outer,
112 BMLoop *l_b_outer,
113 BMLoop *l_a_inner,
114 BMLoop *l_b_inner)
115{
137
138 const bool is_flip = (l_a_inner->next == l_a_outer);
139 BMLoop *l_a_inner_inset, *l_b_inner_inset;
140 BMEdge *e_a, *e_b;
141 int layer_n;
142
143 /* paranoid sanity checks */
144 BLI_assert(l_a_outer->v == l_b_outer->v);
145 BLI_assert(l_a_inner->v == l_b_inner->v);
146
147 BLI_assert(l_b_inner->f != l_a_inner->f);
148
149 BLI_assert(l_a_outer->f == l_a_inner->f);
150 BLI_assert(l_b_outer->f == l_b_inner->f);
151
152 (void)e_connect;
153 BLI_assert(BM_edge_in_face(e_connect, l_a_inner->f));
154 BLI_assert(BM_edge_in_face(e_connect, l_b_inner->f));
155
156 if (is_flip) {
157 e_a = l_a_inner->prev->e;
158 e_b = l_b_inner->e;
159 }
160 else {
161 e_a = l_a_inner->e;
162 e_b = l_b_inner->prev->e;
163 }
164
165 l_a_inner_inset = BM_edge_other_loop(e_a, l_a_inner);
166 l_b_inner_inset = BM_edge_other_loop(e_b, l_b_inner);
167 BLI_assert(l_a_inner_inset->v == l_b_inner_inset->v);
168
169 /* check if there is no chance of diversion */
170 if (l_a_inner_inset->f == l_b_inner_inset->f) {
171 return;
172 }
173
174 for (layer_n = 0; layer_n < bm->ldata.totlayer; layer_n++) {
175 const int type = bm->ldata.layers[layer_n].type;
176 const int offset = bm->ldata.layers[layer_n].offset;
177 if (!CustomData_layer_has_math(&bm->ldata, layer_n)) {
178 continue;
179 }
180
181 /* check we begin with merged data */
183 BM_ELEM_CD_GET_VOID_P(l_a_outer, offset),
184 BM_ELEM_CD_GET_VOID_P(l_b_outer, offset)) == true)
185
186/* Epsilon for comparing UVs is too big, gives noticeable problems. */
187# if 0
188 &&
189 /* check if the data ends up diverged */
191 BM_ELEM_CD_GET_VOID_P(l_a_inner, offset),
192 BM_ELEM_CD_GET_VOID_P(l_b_inner, offset)) == false)
193# endif
194 )
195 {
196 /* no need to allocate a temp block:
197 * a = (a + b);
198 * a *= 0.5f;
199 * b = a;
200 */
201 const void *data_src;
202
204 BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset),
205 BM_ELEM_CD_GET_VOID_P(l_b_inner_inset, offset),
207 0.5f);
209 BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset),
210 BM_ELEM_CD_GET_VOID_P(l_b_inner_inset, offset));
211
212 /* use this as a reference (could be 'l_b_inner_inset' too) */
213 data_src = BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset);
214
215 /* check if the 2 faces share an edge */
216 if (is_flip ? (l_b_inner_inset->e == l_a_inner_inset->prev->e) :
217 (l_a_inner_inset->e == l_b_inner_inset->prev->e))
218 {
219 /* simple case, we have all loops already */
220 }
221 else {
222 /* compare with (l_a_inner / l_b_inner) and assign the blended value if they match */
223 BMIter iter;
224 BMLoop *l_iter;
225 const void *data_cmp_a = BM_ELEM_CD_GET_VOID_P(l_b_inner, offset);
226 const void *data_cmp_b = BM_ELEM_CD_GET_VOID_P(l_a_inner, offset);
227 BM_ITER_ELEM (l_iter, &iter, l_a_inner_inset->v, BM_LOOPS_OF_VERT) {
228 if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) {
229 if (!ELEM(l_iter, l_a_inner, l_b_inner, l_a_inner_inset, l_b_inner_inset)) {
230 void *data_dst = BM_ELEM_CD_GET_VOID_P(l_iter, offset);
231
232 if (CustomData_data_equals(eCustomDataType(type), data_dst, data_cmp_a) ||
233 CustomData_data_equals(eCustomDataType(type), data_dst, data_cmp_b))
234 {
235 CustomData_data_copy_value(eCustomDataType(type), data_src, data_dst);
236 }
237 }
238 }
239 }
240 }
241
243 eCustomDataType(type), data_src, BM_ELEM_CD_GET_VOID_P(l_b_inner, offset));
245 eCustomDataType(type), data_src, BM_ELEM_CD_GET_VOID_P(l_a_inner, offset));
246 }
247 }
248}
249#endif /* USE_LOOP_CUSTOMDATA_MERGE */
250
252
253/* -------------------------------------------------------------------- */
258
260 BMFace *f,
261 MemArena *interp_arena,
262 const float thickness,
263 const float depth,
264 const bool use_even_offset,
265 const bool use_relative_offset,
266 const bool use_interpolate)
267{
268 InterpFace *iface = nullptr;
269
270 /* stores verts split away from the face (aligned with face verts) */
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 uint 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 /* build rim faces */
299 l_iter = l_first;
300 i = 0;
301 do {
302 BMFace *f_new_outer;
303 BMVert *v_other = verts[i];
304 BMVert *v_other_next = verts[(i + 1) % f->len];
305
306 BMEdge *e_other = BM_edge_create(bm, v_other, v_other_next, l_iter->e, BM_CREATE_NO_DOUBLE);
307 (void)e_other;
308
309 f_new_outer = BM_face_create_quad_tri(
310 bm, v_other, v_other_next, l_iter->next->v, l_iter->v, f, BM_CREATE_NOP);
311 BMO_face_flag_enable(bm, f_new_outer, ELE_NEW);
312
313 /* copy loop data */
314 l_other = l_iter->radial_next;
315 BM_elem_attrs_copy(bm, l_iter->next, l_other->prev);
316 BM_elem_attrs_copy(bm, l_iter, l_other->next->next);
317
318 if (use_interpolate == false) {
319 BM_elem_attrs_copy(bm, l_iter->next, l_other);
320 BM_elem_attrs_copy(bm, l_iter, l_other->next);
321 }
322 } while ((void)i++, ((l_iter = l_iter->next) != l_first));
323
324 /* hold interpolation values */
325 if (use_interpolate) {
326 iface = static_cast<InterpFace *>(BLI_memarena_alloc(interp_arena, sizeof(*iface)));
327 bm_interp_face_store(iface, bm, f, interp_arena);
328 }
329
330 /* Calculate translation vector for new */
331 l_iter = l_first;
332 i = 0;
333
334 if (depth != 0.0f) {
335 e_length_prev = BM_edge_calc_length(l_iter->prev->e);
336 }
337
338 do {
339 const float *eno_prev = edge_nors[(i ? i : f->len) - 1];
340 const float *eno_next = edge_nors[i];
341 float tvec[3];
342 float v_new_co[3];
343
344 add_v3_v3v3(tvec, eno_prev, eno_next);
345 normalize_v3(tvec);
346
347 copy_v3_v3(v_new_co, l_iter->v->co);
348
349 if (use_even_offset) {
350 mul_v3_fl(tvec, shell_v3v3_mid_normalized_to_dist(eno_prev, eno_next));
351 }
352
353 /* Modify vertices and their normals */
354 if (use_relative_offset) {
355 mul_v3_fl(tvec,
356 (BM_edge_calc_length(l_iter->e) + BM_edge_calc_length(l_iter->prev->e)) / 2.0f);
357 }
358
359 madd_v3_v3fl(v_new_co, tvec, thickness);
360
361 /* Set normal, add depth and write new vertex position. */
362 copy_v3_v3(l_iter->v->no, f->no);
363
364 if (depth != 0.0f) {
365 const float e_length = BM_edge_calc_length(l_iter->e);
366 const float fac = depth * (use_relative_offset ? ((e_length_prev + e_length) * 0.5f) : 1.0f);
367 e_length_prev = e_length;
368
369 madd_v3_v3fl(v_new_co, f->no, fac);
370 }
371
372 copy_v3_v3(coords[i], v_new_co);
373 } while ((void)i++, ((l_iter = l_iter->next) != l_first));
374
375 /* update the coords */
376 l_iter = l_first;
377 i = 0;
378 do {
379 copy_v3_v3(l_iter->v->co, coords[i]);
380 } while ((void)i++, ((l_iter = l_iter->next) != l_first));
381
382 if (use_interpolate) {
384 iface->f,
385 iface->f,
386 true,
387 (const void **)iface->blocks_l,
388 (const void **)iface->blocks_v,
389 iface->cos_2d,
390 iface->axis_mat);
391
392 /* build rim faces */
393 l_iter = l_first;
394 do {
395 /* copy loop data */
396 l_other = l_iter->radial_next;
397
398 BM_elem_attrs_copy(bm, l_iter->next, l_other);
399 BM_elem_attrs_copy(bm, l_iter, l_other->next);
400 } while ((l_iter = l_iter->next) != l_first);
401
402 bm_interp_face_free(iface, bm);
403 }
404}
405
413{
414 BMFace *f;
415
416 BMOIter oiter;
417 MemArena *interp_arena = nullptr;
418
419 const float thickness = BMO_slot_float_get(op->slots_in, "thickness");
420 const float depth = BMO_slot_float_get(op->slots_in, "depth");
421 const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset");
422 const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset");
423 const bool use_interpolate = BMO_slot_bool_get(op->slots_in, "use_interpolate");
424
425 /* Only tag faces in slot */
427
429
430 if (use_interpolate) {
431 interp_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
432 }
433
434 BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) {
436 f,
437 interp_arena,
438 thickness,
439 depth,
440 use_even_offset,
441 use_relative_offset,
442 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? */
451
452 if (use_interpolate) {
453 BLI_memarena_free(interp_arena);
454 }
455}
456
458
459/* -------------------------------------------------------------------- */
464
472
482{
483 if (LIKELY(l != nullptr)) {
484 int tot_tag = 0;
485 int tot_untag = 0;
486 BMLoop *l_iter;
487 BMLoop *l_tag = nullptr;
488 l_iter = l;
489 do {
490 if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) {
491 /* more than one tagged face - bail out early! */
492 if (tot_tag == 1) {
493 return nullptr;
494 }
495 l_tag = l_iter;
496 tot_tag++;
497 }
498 else {
499 tot_untag++;
500 }
501
502 } while ((l_iter = l_iter->radial_next) != l);
503
504 return ((tot_tag == 1) && (tot_untag >= 1)) ? l_tag : nullptr;
505 }
506 return nullptr;
507}
508
510{
511 BMIter iter;
512 BMEdge *e;
513
514 float len = 0.0f;
515 int tot = 0;
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 if (tot != 0) {
526 return len / float(tot);
527 }
528 return -1.0f;
529}
530
546 SplitEdgeInfo *edge_info,
547 BMesh *bm,
548 void **vert_lengths_p)
549{
550 struct VertLengths {
558 float length_accum;
567 int count;
568 } *vert_lengths = static_cast<VertLengths *>(*vert_lengths_p);
569
570 /* Only run this once, if needed. */
571 if (UNLIKELY(vert_lengths == nullptr)) {
572 BMVert **vert_stack = static_cast<BMVert **>(
573 MEM_mallocN(sizeof(*vert_stack) * bm->totvert, __func__));
574 STACK_DECLARE(vert_stack);
575 STACK_INIT(vert_stack, bm->totvert);
576
577 vert_lengths = MEM_calloc_arrayN<VertLengths>(bm->totvert, __func__);
578
579 /* Needed for 'vert_lengths' lookup from connected vertices. */
581
582 {
583 BMIter iter;
584 BMEdge *e;
585 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
586 if (BM_elem_index_get(e) != -1) {
587 for (int i = 0; i < 2; i++) {
588 BMVert *v = *((&e->v1) + i);
590 const int v_index = BM_elem_index_get(v);
591 if (vert_lengths[v_index].count == 0) {
592 STACK_PUSH(vert_stack, v);
593 /* Needed for the first pass, avoid a separate loop to handle the first pass. */
594 vert_lengths[v_index].count = 1;
595 /* We know the edge lengths exist in this case, should never be -1. */
596 vert_lengths[v_index].length_accum = bm_edge_info_average_length(v, edge_info);
597 BLI_assert(vert_lengths[v_index].length_accum != -1.0f);
598 }
599 }
600 }
601 }
602 }
603 }
604
605 /* While there are vertices without their accumulated lengths divided by the count. */
606 while (STACK_SIZE(vert_stack) != 0) {
607 int stack_index = STACK_SIZE(vert_stack);
608 while (stack_index--) {
609 BMVert *v = vert_stack[stack_index];
610 STACK_REMOVE(vert_stack, stack_index);
611 const int v_index = BM_elem_index_get(v);
612
613 BLI_assert(vert_lengths[v_index].count > 0);
614 vert_lengths[v_index].length_accum /= float(vert_lengths[v_index].count);
615 vert_lengths[v_index].count = -1; /* Ignore in future passes. */
616
617 BMIter iter;
618 BMEdge *e;
619 BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
621 continue;
622 }
623 BMVert *v_other = BM_edge_other_vert(e, v);
624 if (!BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
625 continue;
626 }
627 int v_other_index = BM_elem_index_get(v_other);
628 if (vert_lengths[v_other_index].count >= 0) {
629 if (vert_lengths[v_other_index].count == 0) {
630 STACK_PUSH(vert_stack, v_other);
631 }
632 BLI_assert(vert_lengths[v_index].length_accum >= 0.0f);
633 vert_lengths[v_other_index].count += 1;
634 vert_lengths[v_other_index].length_accum += vert_lengths[v_index].length_accum;
635 }
636 }
637 }
638 }
639 MEM_freeN(vert_stack);
640 *vert_lengths_p = vert_lengths;
641 }
642
643 BLI_assert(vert_lengths[BM_elem_index_get(v_lookup)].length_accum >= 0.0f);
644 return vert_lengths[BM_elem_index_get(v_lookup)].length_accum;
645}
646
648 BMVert *v,
649 SplitEdgeInfo *edge_info,
650
651 /* Needed for 'bm_edge_info_average_length_fallback' */
652 BMesh *bm,
653 void **vert_lengths_p)
654{
655
656 const float length = bm_edge_info_average_length(v, edge_info);
657 if (length != -1.0f) {
658 return length;
659 }
660 return bm_edge_info_average_length_fallback(v, edge_info, bm, vert_lengths_p);
661}
662
664{
665 /*
666 * Implementation:
667 *
668 * - Set all faces as tagged/untagged based on selection.
669 * - Find all edges that have 1 tagged, 1 untagged face.
670 * - Separate these edges and tag vertices, set their index to point to the original edge.
671 * - Build faces between old/new edges.
672 * - Inset the new edges into their faces.
673 */
674
675 const bool use_outset = BMO_slot_bool_get(op->slots_in, "use_outset");
676 const bool use_boundary = BMO_slot_bool_get(op->slots_in, "use_boundary") &&
677 (use_outset == false);
678 const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset");
679 const bool use_even_boundary = use_even_offset; /* could make own option */
680 const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset");
681 const bool use_edge_rail = BMO_slot_bool_get(op->slots_in, "use_edge_rail");
682 const bool use_interpolate = BMO_slot_bool_get(op->slots_in, "use_interpolate");
683 const float thickness = BMO_slot_float_get(op->slots_in, "thickness");
684 const float depth = BMO_slot_float_get(op->slots_in, "depth");
685#ifdef USE_LOOP_CUSTOMDATA_MERGE
686 const bool has_math_ldata = (use_interpolate && CustomData_has_math(&bm->ldata));
687#endif
688
689 int edge_info_len = 0;
690
691 BMIter iter;
692 SplitEdgeInfo *edge_info;
693 SplitEdgeInfo *es;
694
695 /* Interpolation Vars */
696 /* an array aligned with faces but only fill items which are used. */
697 InterpFace **iface_array = nullptr;
698 int iface_array_len;
699 MemArena *interp_arena = nullptr;
700
701 /* BMVert original location storage */
702 const bool use_vert_coords_orig = use_edge_rail;
703 MemArena *vert_coords_orig = nullptr;
704 GHash *vert_coords = nullptr;
705
706 BMVert *v;
707 BMEdge *e;
708 BMFace *f;
709 int i, k;
710
711 if (use_interpolate) {
712 interp_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
713 /* warning, we could be more clever here and not over alloc */
714 iface_array = static_cast<InterpFace **>(
715 MEM_callocN(sizeof(*iface_array) * bm->totface, __func__));
716 iface_array_len = bm->totface;
717 }
718
719 if (use_outset == false) {
722 }
723 else {
726 BMO_slot_buffer_hflag_disable(bm, op->slots_in, "faces_exclude", BM_FACE, BM_ELEM_TAG, false);
727 }
728
729 /* first count all inset edges we will split */
730 /* fill in array and initialize tagging */
731 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
732 if (
733 /* tag if boundary is enabled */
734 (use_boundary && BM_edge_is_boundary(e) && BM_elem_flag_test(e->l->f, BM_ELEM_TAG)) ||
735
736 /* tag if edge is an interior edge in between a tagged and untagged face */
738 {
739 /* tag */
743
744 BM_elem_index_set(e, edge_info_len); /* set_dirty! */
745 edge_info_len++;
746 }
747 else {
751
752 BM_elem_index_set(e, -1); /* set_dirty! */
753 }
754 }
755 bm->elem_index_dirty |= BM_EDGE;
756
757 edge_info = MEM_malloc_arrayN<SplitEdgeInfo>(edge_info_len, __func__);
758
759 /* fill in array and initialize tagging */
760 es = edge_info;
761 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
763 if (i != -1) {
764 /* calc edge-split info */
766 es->e_old = e;
767 es++;
768 /* initialize no and e_new after */
769 }
770 }
771
772 if (use_vert_coords_orig) {
773 vert_coords_orig = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
774 vert_coords = BLI_ghash_ptr_new(__func__);
775 }
776
777/* Utility macros. */
778#define VERT_ORIG_STORE(_v) \
779 { \
780 float *_co = static_cast<float *>(BLI_memarena_alloc(vert_coords_orig, sizeof(float[3]))); \
781 copy_v3_v3(_co, (_v)->co); \
782 BLI_ghash_insert(vert_coords, _v, _co); \
783 } \
784 (void)0
785#define VERT_ORIG_GET(_v) (const float *)BLI_ghash_lookup_default(vert_coords, (_v), (_v)->co)
786/* memory for the coords isn't given back to the arena,
787 * acceptable in this case since it runs a fixed number of times. */
788#define VERT_ORIG_REMOVE(_v) BLI_ghash_remove(vert_coords, (_v), nullptr, nullptr)
789
790 for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
791 if ((es->l = bm_edge_is_mixed_face_tag(es->e_old->l))) {
792 /* do nothing */
793 }
794 else {
795 es->l = es->e_old->l; /* must be a boundary */
796 }
797
798 /* run the separate arg */
799 if (!BM_edge_is_boundary(es->e_old)) {
800 bmesh_kernel_edge_separate(bm, es->e_old, es->l, false);
801 }
802
803 /* calc edge-split info */
804 es->e_new = es->l->e;
805 BM_edge_calc_face_tangent(es->e_new, es->l, es->no);
806
807 if (es->e_new == es->e_old) { /* happens on boundary edges */
808 /* Take care here, we're creating this double edge which _must_
809 * have its verts replaced later on. */
810 es->e_old = BM_edge_create(bm, es->e_new->v1, es->e_new->v2, es->e_new, BM_CREATE_NOP);
811 }
812
813 /* store index back to original in 'edge_info' */
816
817 /* important to tag again here */
820
821 /* initialize interpolation vars */
822 /* this could go in its own loop,
823 * only use the 'es->l->f' so we don't store loops for faces which have no mixed selection
824 *
825 * NOTE: faces on the other side of the inset will be interpolated too since this is hard to
826 * detect, just allow it even though it will cause some redundant interpolation */
827 if (use_interpolate) {
828 BMIter viter;
829 BM_ITER_ELEM (v, &viter, es->l->e, BM_VERTS_OF_EDGE) {
830 BMIter fiter;
831 BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
832 const int j = BM_elem_index_get(f);
833 if (iface_array[j] == nullptr) {
834 InterpFace *iface = static_cast<InterpFace *>(
835 BLI_memarena_alloc(interp_arena, sizeof(*iface)));
836 bm_interp_face_store(iface, bm, f, interp_arena);
837 iface_array[j] = iface;
838 }
839 }
840 }
841 }
842 /* done interpolation */
843 }
844
845/* show edge normals for debugging */
846#if 0
847 for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
848 float tvec[3];
849 BMVert *v1, *v2;
850
851 mid_v3_v3v3(tvec, es->e_new->v1->co, es->e_new->v2->co);
852
853 v1 = BM_vert_create(bm, tvec, nullptr, BM_CREATE_NOP);
854 v2 = BM_vert_create(bm, tvec, nullptr, BM_CREATE_NOP);
855 madd_v3_v3fl(v2->co, es->no, 0.1f);
856 BM_edge_create(bm, v1, v2, nullptr, 0);
857 }
858#endif
859
860 /* Execute the split and position verts, it would be most obvious to loop
861 * over verts here but don't do this since we will be splitting them off
862 * (iterating stuff you modify is bad juju)
863 * instead loop over edges then their verts. */
864 for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
865 for (int j = 0; j < 2; j++) {
866 v = (j == 0) ? es->e_new->v1 : es->e_new->v2;
867
868 /* end confusing part - just pretend this is a typical loop on verts */
869
870 /* only split of tagged verts - used by separated edges */
871
872 /* comment the first part because we know this verts in a tagged face */
873 if (/* v->e && */ BM_elem_flag_test(v, BM_ELEM_TAG)) {
874 BMVert **vout;
875 int vout_len;
876 BMVert *v_glue = nullptr;
877
878 /* disable touching twice, this _will_ happen if the flags not disabled */
880
881 bmesh_kernel_vert_separate(bm, v, &vout, &vout_len, false);
882 v = nullptr; /* don't use again */
883
884 /* in some cases the edge doesn't split off */
885 if (vout_len == 1) {
886 if (use_vert_coords_orig) {
887 VERT_ORIG_STORE(vout[0]);
888 }
889 MEM_freeN(vout);
890 continue;
891 }
892
893 for (k = 0; k < vout_len; k++) {
894 BMVert *v_split = vout[k]; /* only to avoid vout[k] all over */
895
896 /* need to check if this vertex is from a */
897 int vert_edge_tag_tot = 0;
898 int vecpair[2];
899
900 if (use_vert_coords_orig) {
901 VERT_ORIG_STORE(v_split);
902 }
903
904 /* find adjacent */
905 BM_ITER_ELEM (e, &iter, v_split, BM_EDGES_OF_VERT) {
906 if (BM_elem_flag_test(e, BM_ELEM_TAG) && e->l &&
908 {
909 if (vert_edge_tag_tot < 2) {
910 vecpair[vert_edge_tag_tot] = BM_elem_index_get(e);
911 BLI_assert(vecpair[vert_edge_tag_tot] != -1);
912 }
913
914 vert_edge_tag_tot++;
915 }
916 }
917
918 if (vert_edge_tag_tot != 0) {
919 float tvec[3];
920
921 if (vert_edge_tag_tot >= 2) { /* 2 edge users - common case */
922 /* now there are 2 cases to check for,
923 *
924 * if both edges use the same face OR both faces have the same normal,
925 * ...then we can calculate an edge that fits nicely between the 2 edge normals.
926 *
927 * Otherwise use the shared edge OR the corner defined by these 2 face normals,
928 * when both edges faces are adjacent this works best but even when this vertex
929 * fans out faces it should work ok.
930 */
931
932 SplitEdgeInfo *e_info_a = &edge_info[vecpair[0]];
933 SplitEdgeInfo *e_info_b = &edge_info[vecpair[1]];
934
935 BMFace *f_a = e_info_a->l->f;
936 BMFace *f_b = e_info_b->l->f;
937
938 /* set to true when we're not in-between (e_info_a->no, e_info_b->no) exactly
939 * in this case use a check the angle of the tvec when calculating shell thickness */
940 bool is_mid = true;
941
942 /* we use this as either the normal OR to find the right direction for the
943 * cross product between both face normals */
944 add_v3_v3v3(tvec, e_info_a->no, e_info_b->no);
945
946 if (use_edge_rail == false) {
947 /* pass */
948 }
949 else if (f_a != f_b) {
950 /* these lookups are very quick */
951 BMLoop *l_other_a = BM_loop_other_vert_loop(e_info_a->l, v_split);
952 BMLoop *l_other_b = BM_loop_other_vert_loop(e_info_b->l, v_split);
953
954 if (l_other_a->v == l_other_b->v) {
955 /* both edges faces are adjacent, but we don't need to know the shared edge
956 * having both verts is enough. */
957 const float *co_other;
958
959 /* note that we can't use 'l_other_a->v' directly since it
960 * may be inset and give a feedback loop. */
961 if (use_vert_coords_orig) {
962 co_other = VERT_ORIG_GET(l_other_a->v);
963 }
964 else {
965 co_other = l_other_a->v->co;
966 }
967
968 sub_v3_v3v3(tvec, co_other, v_split->co);
969 is_mid = false;
970 }
971
972/* Disable since this gives odd results at times, see #39288. */
973#if 0
974 else if (compare_v3v3(f_a->no, f_b->no, 0.001f) == false) {
975 /* epsilon increased to fix #32329. */
976
977 /* faces don't touch,
978 * just get cross product of their normals, its *good enough*
979 */
980 float tno[3];
981 cross_v3_v3v3(tno, f_a->no, f_b->no);
982 if (dot_v3v3(tvec, tno) < 0.0f) {
983 negate_v3(tno);
984 }
985 copy_v3_v3(tvec, tno);
986 is_mid = false;
987 }
988#endif
989 }
990 normalize_v3(tvec);
991
992 /* scale by edge angle */
993 if (use_even_offset) {
994 if (is_mid) {
995 mul_v3_fl(tvec, shell_v3v3_mid_normalized_to_dist(e_info_a->no, e_info_b->no));
996 }
997 else {
998 /* use the largest angle */
999 mul_v3_fl(
1000 tvec,
1002 len_squared_v3v3(tvec, e_info_a->no) >
1003 len_squared_v3v3(tvec, e_info_b->no) ?
1004 e_info_a->no :
1005 e_info_b->no));
1006 }
1007 }
1008
1009 /* scale relative to edge lengths */
1010 if (use_relative_offset) {
1011 mul_v3_fl(tvec,
1012 (edge_info[vecpair[0]].length + edge_info[vecpair[1]].length) / 2.0f);
1013 }
1014 }
1015 else if (vert_edge_tag_tot == 1) { /* 1 edge user - boundary vert, not so common */
1016 const float *e_no_a = edge_info[vecpair[0]].no;
1017
1018 if (use_even_boundary) {
1019
1044
1045 BMEdge *e_other;
1046 BMVert *v_other;
1047 /* loop will always be either next of prev */
1048 BMLoop *l = v_split->e->l;
1049 if (l->prev->v == v_split) {
1050 l = l->prev;
1051 }
1052 else if (l->next->v == v_split) {
1053 l = l->next;
1054 }
1055 else if (l->v == v_split) {
1056 /* pass */
1057 }
1058 else {
1059 /* should never happen */
1060 BLI_assert(0);
1061 }
1062
1063 /* find the edge which is _not_ being split here */
1064 if (!BM_elem_flag_test(l->e, BM_ELEM_TAG)) {
1065 e_other = l->e;
1066 }
1067 else if (!BM_elem_flag_test(l->prev->e, BM_ELEM_TAG)) {
1068 e_other = l->prev->e;
1069 }
1070 else {
1071 BLI_assert(0);
1072 e_other = nullptr;
1073 }
1074
1075 v_other = BM_edge_other_vert(e_other, v_split);
1076 sub_v3_v3v3(tvec, v_other->co, v_split->co);
1077 normalize_v3(tvec);
1078
1079 if (use_even_offset) {
1080 mul_v3_fl(tvec, shell_v3v3_normalized_to_dist(e_no_a, tvec));
1081 }
1082 }
1083 else {
1084 copy_v3_v3(tvec, e_no_a);
1085 }
1086
1087 /* use_even_offset - doesn't apply here */
1088
1089 /* scale relative to edge length */
1090 if (use_relative_offset) {
1091 mul_v3_fl(tvec, edge_info[vecpair[0]].length);
1092 }
1093 }
1094 else {
1095 /* should never happen */
1096 BLI_assert(0);
1097 zero_v3(tvec);
1098 }
1099
1100 /* apply the offset */
1101 madd_v3_v3fl(v_split->co, tvec, thickness);
1102 }
1103
1104 /* this saves expensive/slow glue check for common cases */
1105 if (vout_len > 2) {
1106 bool ok = true;
1107 /* last step, nullptr this vertex if has a tagged face */
1108 BM_ITER_ELEM (f, &iter, v_split, BM_FACES_OF_VERT) {
1110 ok = false;
1111 break;
1112 }
1113 }
1114
1115 if (ok) {
1116 if (v_glue == nullptr) {
1117 v_glue = v_split;
1118 }
1119 else {
1120 if (BM_vert_splice(bm, v_glue, v_split)) {
1121 if (use_vert_coords_orig) {
1122 VERT_ORIG_REMOVE(v_split);
1123 }
1124 }
1125 }
1126 }
1127 }
1128 /* end glue */
1129 }
1130 MEM_freeN(vout);
1131 }
1132 }
1133 }
1134
1135 if (use_vert_coords_orig) {
1136 BLI_memarena_free(vert_coords_orig);
1137 BLI_ghash_free(vert_coords, nullptr, nullptr);
1138 }
1139
1140 if (use_interpolate) {
1141 for (i = 0; i < iface_array_len; i++) {
1142 if (iface_array[i]) {
1143 InterpFace *iface = iface_array[i];
1145 iface->f,
1146 iface->f,
1147 true,
1148 (const void **)iface->blocks_l,
1149 (const void **)iface->blocks_v,
1150 iface->cos_2d,
1151 iface->axis_mat);
1152 }
1153 }
1154 }
1155
1156 /* create faces */
1157 for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
1158 BMVert *varr[4] = {nullptr};
1159 int j;
1160 /* get the verts in the correct order */
1161 BM_edge_ordered_verts_ex(es->e_new, &varr[1], &varr[0], es->l);
1162#if 0
1163 if (varr[0] == es->e_new->v1) {
1164 varr[2] = es->e_old->v2;
1165 varr[3] = es->e_old->v1;
1166 }
1167 else {
1168 varr[2] = es->e_old->v1;
1169 varr[3] = es->e_old->v2;
1170 }
1171 j = 4;
1172#else
1173 /* slightly trickier check - since we can't assume the verts are split */
1174 j = 2; /* 2 edges are set */
1175 if (varr[0] == es->e_new->v1) {
1176 if (es->e_old->v2 != es->e_new->v2) {
1177 varr[j++] = es->e_old->v2;
1178 }
1179 if (es->e_old->v1 != es->e_new->v1) {
1180 varr[j++] = es->e_old->v1;
1181 }
1182 }
1183 else {
1184 if (es->e_old->v1 != es->e_new->v1) {
1185 varr[j++] = es->e_old->v1;
1186 }
1187 if (es->e_old->v2 != es->e_new->v2) {
1188 varr[j++] = es->e_old->v2;
1189 }
1190 }
1191
1192 if (j == 2) {
1193 /* can't make face! */
1194 continue;
1195 }
1196#endif
1197 /* no need to check doubles, we KNOW there won't be any */
1198 /* yes - reverse face is correct in this case */
1199 f = BM_face_create_verts(bm, varr, j, es->l->f, BM_CREATE_NOP, true);
1201
1202 /* Copy for loop data, otherwise UVs and vertex-colors are no good.
1203 * tiny speedup here we could be more clever and copy from known adjacent data
1204 * also - we could attempt to interpolate the loop data,
1205 * this would be much slower but more useful too. */
1206 if (false) {
1207 /* Don't use this because face boundaries have no adjacent loops and won't be filled in.
1208 * instead copy from the opposite side with the code below */
1209 BM_face_copy_shared(bm, f, nullptr, nullptr);
1210 }
1211 else {
1212 /* 2 inner loops on the edge between the new face and the original */
1213 BMLoop *l_a;
1214 BMLoop *l_b;
1215 BMLoop *l_a_other;
1216 BMLoop *l_b_other;
1217
1218 l_a = BM_FACE_FIRST_LOOP(f);
1219 l_b = l_a->next;
1220
1221 /* we know this side has a radial_next because of the order of created verts in the quad */
1222 l_a_other = BM_edge_other_loop(l_a->e, l_a);
1223 l_b_other = BM_edge_other_loop(l_a->e, l_b);
1224 BM_elem_attrs_copy(bm, l_a_other, l_a);
1225 BM_elem_attrs_copy(bm, l_b_other, l_b);
1226
1227 BLI_assert(l_a->f != l_a_other->f);
1228 BLI_assert(l_b->f != l_b_other->f);
1229
1230 /* step around to the opposite side of the quad - warning, this may have no other edges! */
1231 l_a = l_a->next->next;
1232 l_b = l_a->next;
1233
1254
1255 /* swap a<->b intentionally */
1256 if (use_interpolate) {
1257 InterpFace *iface = iface_array[BM_elem_index_get(es->l->f)];
1258 const int i_a = BM_elem_index_get(l_a_other);
1259 const int i_b = BM_elem_index_get(l_b_other);
1260 CustomData_bmesh_free_block_data(&bm->ldata, l_b->head.data);
1262 CustomData_bmesh_copy_block(bm->ldata, iface->blocks_l[i_a], &l_b->head.data);
1263 CustomData_bmesh_copy_block(bm->ldata, iface->blocks_l[i_b], &l_a->head.data);
1264
1265#ifdef USE_LOOP_CUSTOMDATA_MERGE
1266 if (has_math_ldata) {
1267 BMEdge *e_connect;
1268
1269 /* connecting edge 'a' */
1270 e_connect = l_a->prev->e;
1271 if (BM_edge_is_manifold(e_connect)) {
1273 e_connect,
1274 l_a,
1275 BM_edge_other_loop(e_connect, l_a),
1276 l_a->prev,
1277 BM_edge_other_loop(e_connect, l_a->prev));
1278 }
1279
1280 /* connecting edge 'b' */
1281 e_connect = l_b->e;
1282 if (BM_edge_is_manifold(e_connect)) {
1283 /* swap arg order to maintain winding */
1285 e_connect,
1286 l_b,
1287 BM_edge_other_loop(e_connect, l_b),
1288 l_b->next,
1289 BM_edge_other_loop(e_connect, l_b->next));
1290 }
1291 }
1292#endif /* USE_LOOP_CUSTOMDATA_MERGE */
1293 }
1294 else {
1295 BM_elem_attrs_copy(bm, l_a_other, l_b);
1296 BM_elem_attrs_copy(bm, l_b_other, l_a);
1297 }
1298 }
1299 }
1300
1301 if (use_interpolate) {
1302 for (i = 0; i < iface_array_len; i++) {
1303 if (iface_array[i]) {
1304 bm_interp_face_free(iface_array[i], bm);
1305 }
1306 }
1307
1308 BLI_memarena_free(interp_arena);
1309 MEM_freeN(iface_array);
1310 }
1311
1312 /* we could flag new edges/verts too, is it useful? */
1314
1315 /* cheap feature to add depth to the inset */
1316 if (depth != 0.0f) {
1317 float (*varr_co)[3];
1318 BMOIter oiter;
1319
1320 /* We need to re-calculate tagged normals,
1321 * but for this purpose we can copy tagged verts from the faces they inset from. */
1322 for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
1323 zero_v3(es->e_new->v1->no);
1324 zero_v3(es->e_new->v2->no);
1325 }
1326 for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
1327 const float *no = es->l->f->no;
1328 add_v3_v3(es->e_new->v1->no, no);
1329 add_v3_v3(es->e_new->v2->no, no);
1330 }
1331 for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
1332 /* annoying, avoid normalizing twice */
1333 if (len_squared_v3(es->e_new->v1->no) != 1.0f) {
1334 normalize_v3(es->e_new->v1->no);
1335 }
1336 if (len_squared_v3(es->e_new->v2->no) != 1.0f) {
1337 normalize_v3(es->e_new->v2->no);
1338 }
1339 }
1340 /* done correcting edge verts normals */
1341
1342 /* untag verts */
1344
1345 /* tag face verts */
1346 BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) {
1347 BMLoop *l_iter, *l_first;
1348 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1349 do {
1352 } while ((l_iter = l_iter->next) != l_first);
1353 }
1354
1355 /* do in 2 passes so moving the verts doesn't feed back into face angle checks
1356 * which BM_vert_calc_shell_factor uses. */
1357
1358 /* over allocate */
1359 varr_co = MEM_calloc_arrayN<float[3]>(bm->totvert, __func__);
1360 void *vert_lengths_p = nullptr;
1361
1364 const float fac =
1365 depth *
1366 (use_relative_offset ?
1368 v,
1369 edge_info,
1370 /* Variables needed for filling interior values for vertex lengths. */
1371 bm,
1372 &vert_lengths_p) :
1373 1.0f) *
1374 (use_even_boundary ? BM_vert_calc_shell_factor(v) : 1.0f);
1375 madd_v3_v3v3fl(varr_co[i], v->co, v->no, fac);
1376 }
1377 }
1378
1379 if (vert_lengths_p != nullptr) {
1380 MEM_freeN(vert_lengths_p);
1381 }
1382
1385 copy_v3_v3(v->co, varr_co[i]);
1386 }
1387 }
1388 MEM_freeN(varr_co);
1389 }
1390
1391 MEM_freeN(edge_info);
1392}
1393
CustomData interface, see also DNA_customdata_types.h.
void CustomData_bmesh_free_block(CustomData *data, void **block)
bool CustomData_layer_has_math(const CustomData *data, int layer_n)
void CustomData_data_copy_value(eCustomDataType type, const void *source, void *dest)
void CustomData_bmesh_copy_block(CustomData &data, void *src_block, void **dst_block)
bool CustomData_data_equals(eCustomDataType type, const void *data1, const void *data2)
bool CustomData_has_math(const CustomData *data)
void CustomData_data_mix_value(eCustomDataType type, const void *source, void *dest, int mixmode, float mixfactor)
void CustomData_bmesh_free_block_data(CustomData *data, void *block)
#define BLI_array_alloca(arr, realsize)
Definition BLI_alloca.h:18
#define BLI_assert(a)
Definition BLI_assert.h:46
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:860
MINLINE float shell_v3v3_normalized_to_dist(const float a[3], const float b[3])
MINLINE float shell_v3v3_mid_normalized_to_dist(const float a[3], const float b[3])
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
Normal to x,y matrix.
void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3])
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void negate_v3(float r[3])
MINLINE bool compare_v3v3(const float v1[3], const float v2[3], float limit) ATTR_WARN_UNUSED_RESULT
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
#define BLI_MEMARENA_STD_BUFSIZE
MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
void BLI_memarena_free(MemArena *ma) ATTR_NONNULL(1)
void * BLI_memarena_alloc(MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1)
unsigned int uint
#define UNLIKELY(x)
#define ELEM(...)
#define LIKELY(x)
#define STACK_PUSH(stack, val)
#define STACK_DECLARE(stack)
#define STACK_SIZE(stack)
#define STACK_INIT(stack, stack_num)
#define STACK_REMOVE(stack, i)
@ CDT_MIX_MIX
Read Guarded memory(de)allocation.
#define BM_FACE_FIRST_LOOP(p)
@ BM_ELEM_TAG
@ BM_LOOP
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
void BM_face_copy_shared(BMesh *bm, BMFace *f, BMLoopFilterFunc filter_fn, void *user_data)
copies face loop data from shared adjacent faces.
void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMVert *src, BMVert *dst)
BMFace * BM_face_create_quad_tri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4, const BMFace *f_example, const eBMCreateFlag create_flag)
Make Quad/Triangle.
void bmesh_kernel_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep, const bool copy_select)
Separate Edge.
bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src)
Splice Vert.
BMFace * BM_face_create_verts(BMesh *bm, BMVert **vert_arr, const int len, const BMFace *f_example, const eBMCreateFlag create_flag, const bool create_edges)
BMVert * BM_vert_create(BMesh *bm, const float co[3], const BMVert *v_example, const eBMCreateFlag create_flag)
Main function for creating a new vertex.
Definition bmesh_core.cc:41
void bmesh_kernel_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len, const bool copy_select)
Separate Vert.
BMEdge * BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag)
Main function for creating a new edge.
@ BM_CREATE_NOP
Definition bmesh_core.hh:28
@ BM_CREATE_NO_DOUBLE
Definition bmesh_core.hh:30
#define BM_elem_index_get(ele)
#define BM_elem_flag_disable(ele, hflag)
#define BM_elem_index_set(ele, index)
#define BM_elem_flag_test(ele, hflag)
#define BM_elem_flag_enable(ele, hflag)
void BM_face_interp_from_face_ex(BMesh *bm, BMFace *f_dst, const BMFace *f_src, const bool do_vertex, const void **blocks_l, const void **blocks_v, float(*cos_2d)[2], float axis_mat[3][3])
Data Interpolate From Face.
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_FACES_OF_VERT
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_VERTS_OF_EDGE
@ BM_LOOPS_OF_VERT
@ BM_EDGES_OF_VERT
BMesh * bm
void BM_mesh_elem_hflag_enable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
BMVert * BM_face_loop_separate(BMesh *bm, BMLoop *l_sep)
Rip a single face from a vertex fan.
#define BM_FACE
#define BM_EDGE
#define BM_VERT
void BMO_slot_buffer_hflag_enable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, char hflag, bool do_flush)
BMO_FLAG_BUFFER.
void BMO_slot_buffer_hflag_disable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, char hflag, bool do_flush)
BMO_FLAG_BUFFER.
float BMO_slot_float_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
void BMO_slot_buffer_from_enabled_flag(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, short oflag)
#define BMO_face_flag_enable(bm, e, oflag)
#define BMO_ITER(ele, iter, slot_args, slot_name, restrict_flag)
bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
void BM_edge_ordered_verts_ex(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2, const BMLoop *edge_loop)
bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
float BM_vert_calc_shell_factor(const BMVert *v)
bool BM_face_is_normal_valid(const BMFace *f)
BMLoop * BM_edge_other_loop(BMEdge *e, BMLoop *l)
float BM_edge_calc_length(const BMEdge *e)
void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_tangent[3])
BMESH EDGE/FACE TANGENT.
BMLoop * BM_loop_other_vert_loop(BMLoop *l, BMVert *v)
Other Loop in Face Sharing a Vert.
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMLoop * l_b
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define ELE_NEW
static void bm_loop_customdata_merge(BMesh *bm, BMEdge *e_connect, BMLoop *l_a_outer, BMLoop *l_b_outer, BMLoop *l_a_inner, BMLoop *l_b_inner)
Definition bmo_inset.cc:109
void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
Definition bmo_inset.cc:663
static void bm_interp_face_store(InterpFace *iface, BMesh *bm, BMFace *f, MemArena *interp_arena)
Definition bmo_inset.cc:57
#define VERT_ORIG_REMOVE(_v)
static void bm_interp_face_free(InterpFace *iface, BMesh *bm)
Definition bmo_inset.cc:92
static float bm_edge_info_average_length_with_fallback(BMVert *v, SplitEdgeInfo *edge_info, BMesh *bm, void **vert_lengths_p)
Definition bmo_inset.cc:647
void bmo_inset_individual_exec(BMesh *bm, BMOperator *op)
Definition bmo_inset.cc:412
static float bm_edge_info_average_length_fallback(BMVert *v_lookup, SplitEdgeInfo *edge_info, BMesh *bm, void **vert_lengths_p)
Definition bmo_inset.cc:545
static BMLoop * bm_edge_is_mixed_face_tag(BMLoop *l)
Definition bmo_inset.cc:481
static float bm_edge_info_average_length(BMVert *v, SplitEdgeInfo *edge_info)
Definition bmo_inset.cc:509
#define VERT_ORIG_GET(_v)
static void bmo_face_inset_individual(BMesh *bm, BMFace *f, MemArena *interp_arena, const float thickness, const float depth, const bool use_even_offset, const bool use_relative_offset, const bool use_interpolate)
Definition bmo_inset.cc:259
#define VERT_ORIG_STORE(_v)
nullptr float
static float verts[][3]
float length(VecOp< float, D >) RET
int count
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
BMVert * v1
BMVert * v2
struct BMLoop * l
float no[3]
void * data
BMHeader head
struct BMVert * v
struct BMEdge * e
struct BMLoop * radial_next
struct BMLoop * prev
struct BMFace * f
struct BMLoop * next
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
float co[3]
struct BMEdge * e
float no[3]
BMHeader head
float axis_mat[3][3]
Definition bmo_inset.cc:53
void ** blocks_v
Definition bmo_inset.cc:51
void ** blocks_l
Definition bmo_inset.cc:50
BMFace * f
Definition bmo_inset.cc:49
float(* cos_2d)[2]
Definition bmo_inset.cc:52
float no[3]
Definition bmo_inset.cc:466
BMEdge * e_new
Definition bmo_inset.cc:469
BMEdge * e_old
Definition bmo_inset.cc:468
i
Definition text_draw.cc:230
uint len