Blender V4.3
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
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 "BKE_customdata.hh"
22
23#include "bmesh.hh"
24
25#include "intern/bmesh_operators_private.hh" /* own include */
26
27/* Merge loop-data that diverges, see: #41445 */
28#define USE_LOOP_CUSTOMDATA_MERGE
29
30#define ELE_NEW 1
31
32/* -------------------------------------------------------------------- */
45/* just enough of a face to store interpolation data we can use once the inset is done */
46struct InterpFace {
48 void **blocks_l;
49 void **blocks_v;
51 float axis_mat[3][3];
52};
53
54/* basically a clone of #BM_vert_interp_from_face */
55static void bm_interp_face_store(InterpFace *iface, BMesh *bm, BMFace *f, MemArena *interp_arena)
56{
57 BMLoop *l_iter, *l_first;
58 void **blocks_l = iface->blocks_l = static_cast<void **>(
59 BLI_memarena_alloc(interp_arena, sizeof(*iface->blocks_l) * f->len));
60 void **blocks_v = iface->blocks_v = static_cast<void **>(
61 BLI_memarena_alloc(interp_arena, sizeof(*iface->blocks_v) * f->len));
62 float(*cos_2d)[2] = iface->cos_2d = static_cast<float(*)[2]>(
63 BLI_memarena_alloc(interp_arena, sizeof(*iface->cos_2d) * f->len));
64 void *axis_mat = iface->axis_mat;
65 int i;
66
68
69 axis_dominant_v3_to_m3(static_cast<float(*)[3]>(axis_mat), f->no);
70
71 iface->f = f;
72
73 i = 0;
74 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
75 do {
76 mul_v2_m3v3(cos_2d[i], static_cast<const float(*)[3]>(axis_mat), l_iter->v->co);
77 blocks_l[i] = nullptr;
78 CustomData_bmesh_copy_block(bm->ldata, l_iter->head.data, &blocks_l[i]);
79 /* if we were not modifying the loops later we would do... */
80 // blocks[i] = l_iter->head.data;
81
82 blocks_v[i] = nullptr;
83 CustomData_bmesh_copy_block(bm->vdata, l_iter->v->head.data, &blocks_v[i]);
84
85 /* use later for index lookups */
86 BM_elem_index_set(l_iter, i); /* set_dirty */
87 } while ((void)i++, (l_iter = l_iter->next) != l_first);
89}
91{
92 void **blocks_l = iface->blocks_l;
93 void **blocks_v = iface->blocks_v;
94 int i;
95
96 for (i = 0; i < iface->f->len; i++) {
97 CustomData_bmesh_free_block(&bm->ldata, &blocks_l[i]);
98 CustomData_bmesh_free_block(&bm->vdata, &blocks_v[i]);
99 }
100}
101
102#ifdef USE_LOOP_CUSTOMDATA_MERGE
108 BMEdge *e_connect,
109 BMLoop *l_a_outer,
110 BMLoop *l_b_outer,
111 BMLoop *l_a_inner,
112 BMLoop *l_b_inner)
113{
136 const bool is_flip = (l_a_inner->next == l_a_outer);
137 BMLoop *l_a_inner_inset, *l_b_inner_inset;
138 BMEdge *e_a, *e_b;
139 int layer_n;
140
141 /* paranoid sanity checks */
142 BLI_assert(l_a_outer->v == l_b_outer->v);
143 BLI_assert(l_a_inner->v == l_b_inner->v);
144
145 BLI_assert(l_b_inner->f != l_a_inner->f);
146
147 BLI_assert(l_a_outer->f == l_a_inner->f);
148 BLI_assert(l_b_outer->f == l_b_inner->f);
149
150 (void)e_connect;
151 BLI_assert(BM_edge_in_face(e_connect, l_a_inner->f));
152 BLI_assert(BM_edge_in_face(e_connect, l_b_inner->f));
153
154 if (is_flip) {
155 e_a = l_a_inner->prev->e;
156 e_b = l_b_inner->e;
157 }
158 else {
159 e_a = l_a_inner->e;
160 e_b = l_b_inner->prev->e;
161 }
162
163 l_a_inner_inset = BM_edge_other_loop(e_a, l_a_inner);
164 l_b_inner_inset = BM_edge_other_loop(e_b, l_b_inner);
165 BLI_assert(l_a_inner_inset->v == l_b_inner_inset->v);
166
167 /* check if there is no chance of diversion */
168 if (l_a_inner_inset->f == l_b_inner_inset->f) {
169 return;
170 }
171
172 for (layer_n = 0; layer_n < bm->ldata.totlayer; layer_n++) {
173 const int type = bm->ldata.layers[layer_n].type;
174 const int offset = bm->ldata.layers[layer_n].offset;
175 if (!CustomData_layer_has_math(&bm->ldata, layer_n)) {
176 continue;
177 }
178
179 /* check we begin with merged data */
181 BM_ELEM_CD_GET_VOID_P(l_a_outer, offset),
182 BM_ELEM_CD_GET_VOID_P(l_b_outer, offset)) == true)
183
184/* Epsilon for comparing UVs is too big, gives noticeable problems. */
185# if 0
186 &&
187 /* check if the data ends up diverged */
189 BM_ELEM_CD_GET_VOID_P(l_a_inner, offset),
190 BM_ELEM_CD_GET_VOID_P(l_b_inner, offset)) == false)
191# endif
192 )
193 {
194 /* no need to allocate a temp block:
195 * a = (a + b);
196 * a *= 0.5f;
197 * b = a;
198 */
199 const void *data_src;
200
202 BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset),
203 BM_ELEM_CD_GET_VOID_P(l_b_inner_inset, offset),
205 0.5f);
207 BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset),
208 BM_ELEM_CD_GET_VOID_P(l_b_inner_inset, offset));
209
210 /* use this as a reference (could be 'l_b_inner_inset' too) */
211 data_src = BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset);
212
213 /* check if the 2 faces share an edge */
214 if (is_flip ? (l_b_inner_inset->e == l_a_inner_inset->prev->e) :
215 (l_a_inner_inset->e == l_b_inner_inset->prev->e))
216 {
217 /* simple case, we have all loops already */
218 }
219 else {
220 /* compare with (l_a_inner / l_b_inner) and assign the blended value if they match */
221 BMIter iter;
222 BMLoop *l_iter;
223 const void *data_cmp_a = BM_ELEM_CD_GET_VOID_P(l_b_inner, offset);
224 const void *data_cmp_b = BM_ELEM_CD_GET_VOID_P(l_a_inner, offset);
225 BM_ITER_ELEM (l_iter, &iter, l_a_inner_inset->v, BM_LOOPS_OF_VERT) {
226 if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) {
227 if (!ELEM(l_iter, l_a_inner, l_b_inner, l_a_inner_inset, l_b_inner_inset)) {
228 void *data_dst = BM_ELEM_CD_GET_VOID_P(l_iter, offset);
229
230 if (CustomData_data_equals(eCustomDataType(type), data_dst, data_cmp_a) ||
231 CustomData_data_equals(eCustomDataType(type), data_dst, data_cmp_b))
232 {
233 CustomData_data_copy_value(eCustomDataType(type), data_src, data_dst);
234 }
235 }
236 }
237 }
238 }
239
241 eCustomDataType(type), data_src, BM_ELEM_CD_GET_VOID_P(l_b_inner, offset));
243 eCustomDataType(type), data_src, BM_ELEM_CD_GET_VOID_P(l_a_inner, offset));
244 }
245 }
246}
247#endif /* USE_LOOP_CUSTOMDATA_MERGE */
248
251/* -------------------------------------------------------------------- */
258 BMFace *f,
259 MemArena *interp_arena,
260 const float thickness,
261 const float depth,
262 const bool use_even_offset,
263 const bool use_relative_offset,
264 const bool use_interpolate)
265{
266 InterpFace *iface = nullptr;
267
268 /* stores verts split away from the face (aligned with face verts) */
270 /* store edge normals (aligned with face-loop-edges) */
271 float(*edge_nors)[3] = BLI_array_alloca(edge_nors, f->len);
272 float(*coords)[3] = BLI_array_alloca(coords, f->len);
273
274 BMLoop *l_iter, *l_first;
275 BMLoop *l_other;
276 uint i;
277 float e_length_prev;
278
279 l_first = BM_FACE_FIRST_LOOP(f);
280
281 /* split off all loops */
282 l_iter = l_first;
283 i = 0;
284 do {
285 BMVert *v_other = l_iter->v;
286 BMVert *v_sep = BM_face_loop_separate(bm, l_iter);
287 if (v_sep == v_other) {
288 v_other = BM_vert_create(bm, l_iter->v->co, l_iter->v, BM_CREATE_NOP);
289 }
290 verts[i] = v_other;
291
292 /* unrelated to splitting, but calc here */
293 BM_edge_calc_face_tangent(l_iter->e, l_iter, edge_nors[i]);
294 } while ((void)i++, ((l_iter = l_iter->next) != l_first));
295
296 /* build rim faces */
297 l_iter = l_first;
298 i = 0;
299 do {
300 BMFace *f_new_outer;
301 BMVert *v_other = verts[i];
302 BMVert *v_other_next = verts[(i + 1) % f->len];
303
304 BMEdge *e_other = BM_edge_create(bm, v_other, v_other_next, l_iter->e, BM_CREATE_NO_DOUBLE);
305 (void)e_other;
306
307 f_new_outer = BM_face_create_quad_tri(
308 bm, v_other, v_other_next, l_iter->next->v, l_iter->v, f, BM_CREATE_NOP);
309 BMO_face_flag_enable(bm, f_new_outer, ELE_NEW);
310
311 /* copy loop data */
312 l_other = l_iter->radial_next;
313 BM_elem_attrs_copy(bm, l_iter->next, l_other->prev);
314 BM_elem_attrs_copy(bm, l_iter, l_other->next->next);
315
316 if (use_interpolate == false) {
317 BM_elem_attrs_copy(bm, l_iter->next, l_other);
318 BM_elem_attrs_copy(bm, l_iter, l_other->next);
319 }
320 } while ((void)i++, ((l_iter = l_iter->next) != l_first));
321
322 /* hold interpolation values */
323 if (use_interpolate) {
324 iface = static_cast<InterpFace *>(BLI_memarena_alloc(interp_arena, sizeof(*iface)));
325 bm_interp_face_store(iface, bm, f, interp_arena);
326 }
327
328 /* Calculate translation vector for new */
329 l_iter = l_first;
330 i = 0;
331
332 if (depth != 0.0f) {
333 e_length_prev = BM_edge_calc_length(l_iter->prev->e);
334 }
335
336 do {
337 const float *eno_prev = edge_nors[(i ? i : f->len) - 1];
338 const float *eno_next = edge_nors[i];
339 float tvec[3];
340 float v_new_co[3];
341
342 add_v3_v3v3(tvec, eno_prev, eno_next);
343 normalize_v3(tvec);
344
345 copy_v3_v3(v_new_co, l_iter->v->co);
346
347 if (use_even_offset) {
348 mul_v3_fl(tvec, shell_v3v3_mid_normalized_to_dist(eno_prev, eno_next));
349 }
350
351 /* Modify vertices and their normals */
352 if (use_relative_offset) {
353 mul_v3_fl(tvec,
354 (BM_edge_calc_length(l_iter->e) + BM_edge_calc_length(l_iter->prev->e)) / 2.0f);
355 }
356
357 madd_v3_v3fl(v_new_co, tvec, thickness);
358
359 /* Set normal, add depth and write new vertex position. */
360 copy_v3_v3(l_iter->v->no, f->no);
361
362 if (depth != 0.0f) {
363 const float e_length = BM_edge_calc_length(l_iter->e);
364 const float fac = depth * (use_relative_offset ? ((e_length_prev + e_length) * 0.5f) : 1.0f);
365 e_length_prev = e_length;
366
367 madd_v3_v3fl(v_new_co, f->no, fac);
368 }
369
370 copy_v3_v3(coords[i], v_new_co);
371 } while ((void)i++, ((l_iter = l_iter->next) != l_first));
372
373 /* update the coords */
374 l_iter = l_first;
375 i = 0;
376 do {
377 copy_v3_v3(l_iter->v->co, coords[i]);
378 } while ((void)i++, ((l_iter = l_iter->next) != l_first));
379
380 if (use_interpolate) {
382 iface->f,
383 iface->f,
384 true,
385 (const void **)iface->blocks_l,
386 (const void **)iface->blocks_v,
387 iface->cos_2d,
388 iface->axis_mat);
389
390 /* build rim faces */
391 l_iter = l_first;
392 do {
393 /* copy loop data */
394 l_other = l_iter->radial_next;
395
396 BM_elem_attrs_copy(bm, l_iter->next, l_other);
397 BM_elem_attrs_copy(bm, l_iter, l_other->next);
398 } while ((l_iter = l_iter->next) != l_first);
399
400 bm_interp_face_free(iface, bm);
401 }
402}
403
411{
412 BMFace *f;
413
414 BMOIter oiter;
415 MemArena *interp_arena = nullptr;
416
417 const float thickness = BMO_slot_float_get(op->slots_in, "thickness");
418 const float depth = BMO_slot_float_get(op->slots_in, "depth");
419 const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset");
420 const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset");
421 const bool use_interpolate = BMO_slot_bool_get(op->slots_in, "use_interpolate");
422
423 /* Only tag faces in slot */
425
427
428 if (use_interpolate) {
429 interp_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
430 }
431
432 BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) {
434 f,
435 interp_arena,
436 thickness,
437 depth,
438 use_even_offset,
439 use_relative_offset,
440 use_interpolate);
441
442 if (use_interpolate) {
443 BLI_memarena_clear(interp_arena);
444 }
445 }
446
447 /* we could flag new edges/verts too, is it useful? */
449
450 if (use_interpolate) {
451 BLI_memarena_free(interp_arena);
452 }
453}
454
457/* -------------------------------------------------------------------- */
464 float no[3];
465 float length;
469};
470
480{
481 if (LIKELY(l != nullptr)) {
482 int tot_tag = 0;
483 int tot_untag = 0;
484 BMLoop *l_iter;
485 BMLoop *l_tag = nullptr;
486 l_iter = l;
487 do {
488 if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) {
489 /* more than one tagged face - bail out early! */
490 if (tot_tag == 1) {
491 return nullptr;
492 }
493 l_tag = l_iter;
494 tot_tag++;
495 }
496 else {
497 tot_untag++;
498 }
499
500 } while ((l_iter = l_iter->radial_next) != l);
501
502 return ((tot_tag == 1) && (tot_untag >= 1)) ? l_tag : nullptr;
503 }
504 return nullptr;
505}
506
508{
509 BMIter iter;
510 BMEdge *e;
511
512 float len = 0.0f;
513 int tot = 0;
514
515 BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
516 const int i = BM_elem_index_get(e);
517 if (i != -1) {
518 len += edge_info[i].length;
519 tot++;
520 }
521 }
522
523 if (tot != 0) {
524 return len / float(tot);
525 }
526 return -1.0f;
527}
528
544 SplitEdgeInfo *edge_info,
545 BMesh *bm,
546 void **vert_lengths_p)
547{
548 struct VertLengths {
556 float length_accum;
565 int count;
566 } *vert_lengths = static_cast<VertLengths *>(*vert_lengths_p);
567
568 /* Only run this once, if needed. */
569 if (UNLIKELY(vert_lengths == nullptr)) {
570 BMVert **vert_stack = static_cast<BMVert **>(
571 MEM_mallocN(sizeof(*vert_stack) * bm->totvert, __func__));
572 STACK_DECLARE(vert_stack);
573 STACK_INIT(vert_stack, bm->totvert);
574
575 vert_lengths = static_cast<VertLengths *>(
576 MEM_callocN(sizeof(*vert_lengths) * bm->totvert, __func__));
577
578 /* Needed for 'vert_lengths' lookup from connected vertices. */
580
581 {
582 BMIter iter;
583 BMEdge *e;
584 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
585 if (BM_elem_index_get(e) != -1) {
586 for (int i = 0; i < 2; i++) {
587 BMVert *v = *((&e->v1) + i);
589 const int v_index = BM_elem_index_get(v);
590 if (vert_lengths[v_index].count == 0) {
591 STACK_PUSH(vert_stack, v);
592 /* Needed for the first pass, avoid a separate loop to handle the first pass. */
593 vert_lengths[v_index].count = 1;
594 /* We know the edge lengths exist in this case, should never be -1. */
595 vert_lengths[v_index].length_accum = bm_edge_info_average_length(v, edge_info);
596 BLI_assert(vert_lengths[v_index].length_accum != -1.0f);
597 }
598 }
599 }
600 }
601 }
602 }
603
604 /* While there are vertices without their accumulated lengths divided by the count. */
605 while (STACK_SIZE(vert_stack) != 0) {
606 int stack_index = STACK_SIZE(vert_stack);
607 while (stack_index--) {
608 BMVert *v = vert_stack[stack_index];
609 STACK_REMOVE(vert_stack, stack_index);
610 const int v_index = BM_elem_index_get(v);
611
612 BLI_assert(vert_lengths[v_index].count > 0);
613 vert_lengths[v_index].length_accum /= float(vert_lengths[v_index].count);
614 vert_lengths[v_index].count = -1; /* Ignore in future passes. */
615
616 BMIter iter;
617 BMEdge *e;
618 BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
620 continue;
621 }
622 BMVert *v_other = BM_edge_other_vert(e, v);
623 if (!BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
624 continue;
625 }
626 int v_other_index = BM_elem_index_get(v_other);
627 if (vert_lengths[v_other_index].count >= 0) {
628 if (vert_lengths[v_other_index].count == 0) {
629 STACK_PUSH(vert_stack, v_other);
630 }
631 BLI_assert(vert_lengths[v_index].length_accum >= 0.0f);
632 vert_lengths[v_other_index].count += 1;
633 vert_lengths[v_other_index].length_accum += vert_lengths[v_index].length_accum;
634 }
635 }
636 }
637 }
638 MEM_freeN(vert_stack);
639 *vert_lengths_p = vert_lengths;
640 }
641
642 BLI_assert(vert_lengths[BM_elem_index_get(v_lookup)].length_accum >= 0.0f);
643 return vert_lengths[BM_elem_index_get(v_lookup)].length_accum;
644}
645
647 BMVert *v,
648 SplitEdgeInfo *edge_info,
649
650 /* Needed for 'bm_edge_info_average_length_fallback' */
651 BMesh *bm,
652 void **vert_lengths_p)
653{
654
655 const float length = bm_edge_info_average_length(v, edge_info);
656 if (length != -1.0f) {
657 return length;
658 }
659 return bm_edge_info_average_length_fallback(v, edge_info, bm, vert_lengths_p);
660}
661
663{
664 /*
665 * Implementation:
666 *
667 * - Set all faces as tagged/untagged based on selection.
668 * - Find all edges that have 1 tagged, 1 untagged face.
669 * - Separate these edges and tag vertices, set their index to point to the original edge.
670 * - Build faces between old/new edges.
671 * - Inset the new edges into their faces.
672 */
673
674 const bool use_outset = BMO_slot_bool_get(op->slots_in, "use_outset");
675 const bool use_boundary = BMO_slot_bool_get(op->slots_in, "use_boundary") &&
676 (use_outset == false);
677 const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset");
678 const bool use_even_boundary = use_even_offset; /* could make own option */
679 const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset");
680 const bool use_edge_rail = BMO_slot_bool_get(op->slots_in, "use_edge_rail");
681 const bool use_interpolate = BMO_slot_bool_get(op->slots_in, "use_interpolate");
682 const float thickness = BMO_slot_float_get(op->slots_in, "thickness");
683 const float depth = BMO_slot_float_get(op->slots_in, "depth");
684#ifdef USE_LOOP_CUSTOMDATA_MERGE
685 const bool has_math_ldata = (use_interpolate && CustomData_has_math(&bm->ldata));
686#endif
687
688 int edge_info_len = 0;
689
690 BMIter iter;
691 SplitEdgeInfo *edge_info;
692 SplitEdgeInfo *es;
693
694 /* Interpolation Vars */
695 /* an array aligned with faces but only fill items which are used. */
696 InterpFace **iface_array = nullptr;
697 int iface_array_len;
698 MemArena *interp_arena = nullptr;
699
700 /* BMVert original location storage */
701 const bool use_vert_coords_orig = use_edge_rail;
702 MemArena *vert_coords_orig = nullptr;
703 GHash *vert_coords = nullptr;
704
705 BMVert *v;
706 BMEdge *e;
707 BMFace *f;
708 int i, k;
709
710 if (use_interpolate) {
711 interp_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
712 /* warning, we could be more clever here and not over alloc */
713 iface_array = static_cast<InterpFace **>(
714 MEM_callocN(sizeof(*iface_array) * bm->totface, __func__));
715 iface_array_len = bm->totface;
716 }
717
718 if (use_outset == false) {
721 }
722 else {
725 BMO_slot_buffer_hflag_disable(bm, op->slots_in, "faces_exclude", BM_FACE, BM_ELEM_TAG, false);
726 }
727
728 /* first count all inset edges we will split */
729 /* fill in array and initialize tagging */
730 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
731 if (
732 /* tag if boundary is enabled */
733 (use_boundary && BM_edge_is_boundary(e) && BM_elem_flag_test(e->l->f, BM_ELEM_TAG)) ||
734
735 /* tag if edge is an interior edge in between a tagged and untagged face */
737 {
738 /* tag */
742
743 BM_elem_index_set(e, edge_info_len); /* set_dirty! */
744 edge_info_len++;
745 }
746 else {
750
751 BM_elem_index_set(e, -1); /* set_dirty! */
752 }
753 }
755
756 edge_info = static_cast<SplitEdgeInfo *>(
757 MEM_mallocN(edge_info_len * sizeof(SplitEdgeInfo), __func__));
758
759 /* fill in array and initialize tagging */
760 es = edge_info;
761 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
762 i = BM_elem_index_get(e);
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' */
814 BM_elem_index_set(es->e_new, i);
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 r_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, &r_vout_len, false);
882 v = nullptr; /* don't use again */
883
884 /* in some cases the edge doesn't split off */
885 if (r_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 < r_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
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 (r_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
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);
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 = static_cast<float(*)[3]>(MEM_callocN(sizeof(*varr_co) * bm->totvert, __func__));
1360 void *vert_lengths_p = nullptr;
1361
1362 BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
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
1383 BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
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.
@ CDT_MIX_MIX
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:25
#define BLI_assert(a)
Definition BLI_assert.h:50
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.c: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])
void * BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
struct MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
#define BLI_MEMARENA_STD_BUFSIZE
void 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)
Read Guarded memory(de)allocation.
@ BM_LOOP
@ BM_ELEM_TAG
#define BM_FACE_FIRST_LOOP(p)
#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:43
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:24
@ BM_CREATE_NO_DOUBLE
Definition bmesh_core.hh:26
#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
ATTR_WARN_UNUSED_RESULT 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
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:107
void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
Definition bmo_inset.cc:662
#define ELE_NEW
Definition bmo_inset.cc:30
static void bm_interp_face_store(InterpFace *iface, BMesh *bm, BMFace *f, MemArena *interp_arena)
Definition bmo_inset.cc:55
#define VERT_ORIG_REMOVE(_v)
static void bm_interp_face_free(InterpFace *iface, BMesh *bm)
Definition bmo_inset.cc:90
static float bm_edge_info_average_length_with_fallback(BMVert *v, SplitEdgeInfo *edge_info, BMesh *bm, void **vert_lengths_p)
Definition bmo_inset.cc:646
void bmo_inset_individual_exec(BMesh *bm, BMOperator *op)
Definition bmo_inset.cc:410
static float bm_edge_info_average_length_fallback(BMVert *v_lookup, SplitEdgeInfo *edge_info, BMesh *bm, void **vert_lengths_p)
Definition bmo_inset.cc:543
static BMLoop * bm_edge_is_mixed_face_tag(BMLoop *l)
Definition bmo_inset.cc:479
static float bm_edge_info_average_length(BMVert *v, SplitEdgeInfo *edge_info)
Definition bmo_inset.cc:507
#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:257
#define VERT_ORIG_STORE(_v)
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
Definition btVector3.h:257
int len
draw_view in_light_buf[] float
static float verts[][3]
int count
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
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
int totvert
char elem_index_dirty
CustomData vdata
CustomData ldata
int totface
CustomDataLayer * layers
float axis_mat[3][3]
Definition bmo_inset.cc:51
void ** blocks_v
Definition bmo_inset.cc:49
void ** blocks_l
Definition bmo_inset.cc:48
BMFace * f
Definition bmo_inset.cc:47
float(* cos_2d)[2]
Definition bmo_inset.cc:50
float no[3]
Definition bmo_inset.cc:464
BMEdge * e_new
Definition bmo_inset.cc:467
BMEdge * e_old
Definition bmo_inset.cc:466