Blender V5.0
bmo_dupe.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
10
11#include "MEM_guardedalloc.h"
12
13#include "BLI_alloca.h"
14#include "BLI_math_matrix.h"
15#include "BLI_math_rotation.h"
16#include "BLI_math_vector.h"
17
18#include "bmesh.hh"
19
20#include "intern/bmesh_operators_private.hh" /* own include */
21
22/* local flag define */
23#define DUPE_INPUT 1 /* input from operator */
24#define DUPE_NEW 2
25#define DUPE_DONE 4
26// #define DUPE_MAPPED 8 // UNUSED
27
34 BMOpSlot *slot_vertmap_out,
35 BMesh *bm_dst,
36 const std::optional<BMCustomDataCopyMap> &cd_vert_map,
37 BMVert *v_src,
38 GHash *vhash)
39{
40 BMVert *v_dst;
41
42 /* Create a new vertex */
43 v_dst = BM_vert_create(bm_dst, v_src->co, nullptr, BM_CREATE_SKIP_CD);
44 BMO_slot_map_elem_insert(op, slot_vertmap_out, v_src, v_dst);
45 BMO_slot_map_elem_insert(op, slot_vertmap_out, v_dst, v_src);
46
47 /* Insert new vertex into the vert hash */
48 BLI_ghash_insert(vhash, v_src, v_dst);
49
50 /* Copy attributes */
51 if (cd_vert_map.has_value()) {
52 BM_elem_attrs_copy(bm_dst, cd_vert_map.value(), v_src, v_dst);
53 }
54 else {
55 BM_elem_attrs_copy(bm_dst, v_src, v_dst);
56 }
57
58 /* Mark the vert for output */
59 BMO_vert_flag_enable(bm_dst, v_dst, DUPE_NEW);
60
61 return v_dst;
62}
63
70 BMOpSlot *slot_edgemap_out,
71 BMOpSlot *slot_boundarymap_out,
72 BMesh *bm_dst,
73 BMesh *bm_src,
74 const std::optional<BMCustomDataCopyMap> &cd_edge_map,
75 BMEdge *e_src,
76 GHash *vhash,
77 GHash *ehash,
78 const bool use_edge_flip_from_face)
79{
80 BMEdge *e_dst;
81 BMVert *e_dst_v1, *e_dst_v2;
82 uint rlen;
83
84 /* see if any of the neighboring faces are
85 * not being duplicated. in that case,
86 * add it to the new/old map. */
87 /* lookup edge */
88 rlen = 0;
89 if (e_src->l) {
90 BMLoop *l_iter_src, *l_first_src;
91 l_iter_src = l_first_src = e_src->l;
92 do {
93 if (BMO_face_flag_test(bm_src, l_iter_src->f, DUPE_INPUT)) {
94 rlen++;
95 }
96 } while ((l_iter_src = l_iter_src->radial_next) != l_first_src);
97 }
98
99 /* Lookup v1 and v2 */
100 e_dst_v1 = static_cast<BMVert *>(BLI_ghash_lookup(vhash, e_src->v1));
101 e_dst_v2 = static_cast<BMVert *>(BLI_ghash_lookup(vhash, e_src->v2));
102
103 /* Create a new edge */
104 e_dst = BM_edge_create(bm_dst, e_dst_v1, e_dst_v2, nullptr, BM_CREATE_SKIP_CD);
105 BMO_slot_map_elem_insert(op, slot_edgemap_out, e_src, e_dst);
106 BMO_slot_map_elem_insert(op, slot_edgemap_out, e_dst, e_src);
107
108 /* Add to new/old edge map if necessary. */
109 if (rlen < 2) {
110 /* not sure what non-manifold cases of greater than three
111 * radial should do. */
112 BMO_slot_map_elem_insert(op, slot_boundarymap_out, e_src, e_dst);
113 }
114
115 /* Insert new edge into the edge hash */
116 BLI_ghash_insert(ehash, e_src, e_dst);
117
118 /* Copy attributes */
119 if (cd_edge_map.has_value()) {
120 BM_elem_attrs_copy(bm_dst, cd_edge_map.value(), e_src, e_dst);
121 }
122 else {
123 BM_elem_attrs_copy(bm_dst, e_src, e_dst);
124 }
125
126 /* Mark the edge for output */
127 BMO_edge_flag_enable(bm_dst, e_dst, DUPE_NEW);
128
129 if (use_edge_flip_from_face) {
130 /* Take winding from previous face (if we had one),
131 * otherwise extruding a duplicated edges gives bad normals, see: #62487. */
132 if (BM_edge_is_boundary(e_src) && (e_src->l->v == e_src->v1)) {
133 BM_edge_verts_swap(e_dst);
134 }
135 }
136
137 return e_dst;
138}
139
146 BMOpSlot *slot_facemap_out,
147 BMesh *bm_dst,
148 const std::optional<BMCustomDataCopyMap> &cd_face_map,
149 const std::optional<BMCustomDataCopyMap> &cd_loop_map,
150 BMFace *f_src,
151 GHash *vhash,
152 GHash *ehash)
153{
154 BMFace *f_dst;
155 BMVert **vtar = BLI_array_alloca(vtar, f_src->len);
156 BMEdge **edar = BLI_array_alloca(edar, f_src->len);
157 BMLoop *l_iter_src, *l_iter_dst, *l_first_src;
158 int i;
159
160 l_first_src = BM_FACE_FIRST_LOOP(f_src);
161
162 /* lookup edge */
163 l_iter_src = l_first_src;
164 i = 0;
165 do {
166 vtar[i] = static_cast<BMVert *>(BLI_ghash_lookup(vhash, l_iter_src->v));
167 edar[i] = static_cast<BMEdge *>(BLI_ghash_lookup(ehash, l_iter_src->e));
168 i++;
169 } while ((l_iter_src = l_iter_src->next) != l_first_src);
170
171 /* create new face */
172 f_dst = BM_face_create(bm_dst, vtar, edar, f_src->len, nullptr, BM_CREATE_SKIP_CD);
173 BMO_slot_map_elem_insert(op, slot_facemap_out, f_src, f_dst);
174 BMO_slot_map_elem_insert(op, slot_facemap_out, f_dst, f_src);
175
176 /* Copy attributes */
177 if (cd_face_map.has_value()) {
178 BM_elem_attrs_copy(bm_dst, cd_face_map.value(), f_src, f_dst);
179 }
180 else {
181 BM_elem_attrs_copy(bm_dst, f_src, f_dst);
182 }
183
184 /* copy per-loop custom data */
185 l_iter_src = l_first_src;
186 l_iter_dst = BM_FACE_FIRST_LOOP(f_dst);
187 do {
188 if (cd_loop_map.has_value()) {
189 BM_elem_attrs_copy(bm_dst, cd_loop_map.value(), l_iter_src, l_iter_dst);
190 }
191 else {
192 BM_elem_attrs_copy(bm_dst, l_iter_src, l_iter_dst);
193 }
194 } while ((void)(l_iter_dst = l_iter_dst->next), (l_iter_src = l_iter_src->next) != l_first_src);
195
196 /* Mark the face for output */
197 BMO_face_flag_enable(bm_dst, f_dst, DUPE_NEW);
198
199 return f_dst;
200}
201
207static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src)
208{
209 const bool use_select_history = BMO_slot_bool_get(op->slots_in, "use_select_history");
210 const bool use_edge_flip_from_face = BMO_slot_bool_get(op->slots_in, "use_edge_flip_from_face");
211
212 BMVert *v = nullptr, *v2;
213 BMEdge *e = nullptr;
214 BMFace *f = nullptr;
215
216 BMIter viter, eiter, fiter;
217 GHash *vhash, *ehash;
218
219 BMOpSlot *slot_boundary_map_out = BMO_slot_get(op->slots_out, "boundary_map.out");
220 BMOpSlot *slot_isovert_map_out = BMO_slot_get(op->slots_out, "isovert_map.out");
221
222 BMOpSlot *slot_vert_map_out = BMO_slot_get(op->slots_out, "vert_map.out");
223 BMOpSlot *slot_edge_map_out = BMO_slot_get(op->slots_out, "edge_map.out");
224 BMOpSlot *slot_face_map_out = BMO_slot_get(op->slots_out, "face_map.out");
225
226 /* initialize pointer hashes */
227 vhash = BLI_ghash_ptr_new("bmesh dupeops v");
228 ehash = BLI_ghash_ptr_new("bmesh dupeops e");
229
230 const std::optional<BMCustomDataCopyMap> cd_vert_map =
231 (bm_src == bm_dst) ? std::nullopt :
232 std::optional<BMCustomDataCopyMap>{
233 CustomData_bmesh_copy_map_calc(bm_src->vdata, bm_dst->vdata)};
234 const std::optional<BMCustomDataCopyMap> cd_edge_map =
235 (bm_src == bm_dst) ? std::nullopt :
236 std::optional<BMCustomDataCopyMap>{
237 CustomData_bmesh_copy_map_calc(bm_src->edata, bm_dst->edata)};
238 const std::optional<BMCustomDataCopyMap> cd_face_map =
239 (bm_src == bm_dst) ? std::nullopt :
240 std::optional<BMCustomDataCopyMap>{
241 CustomData_bmesh_copy_map_calc(bm_src->pdata, bm_dst->pdata)};
242 const std::optional<BMCustomDataCopyMap> cd_loop_map =
243 (bm_src == bm_dst) ? std::nullopt :
244 std::optional<BMCustomDataCopyMap>{
245 CustomData_bmesh_copy_map_calc(bm_src->ldata, bm_dst->ldata)};
246
247 /* duplicate flagged vertices */
248 BM_ITER_MESH (v, &viter, bm_src, BM_VERTS_OF_MESH) {
249 if (BMO_vert_flag_test(bm_src, v, DUPE_INPUT) &&
250 BMO_vert_flag_test(bm_src, v, DUPE_DONE) == false)
251 {
252 BMIter iter;
253 bool isolated = true;
254
255 v2 = bmo_vert_copy(op, slot_vert_map_out, bm_dst, cd_vert_map, v, vhash);
256
257 BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
258 if (BMO_face_flag_test(bm_src, f, DUPE_INPUT)) {
259 isolated = false;
260 break;
261 }
262 }
263
264 if (isolated) {
265 BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
266 if (BMO_edge_flag_test(bm_src, e, DUPE_INPUT)) {
267 isolated = false;
268 break;
269 }
270 }
271 }
272
273 if (isolated) {
274 BMO_slot_map_elem_insert(op, slot_isovert_map_out, v, v2);
275 }
276
278 }
279 }
280
281 /* now we dupe all the edges */
282 BM_ITER_MESH (e, &eiter, bm_src, BM_EDGES_OF_MESH) {
283 if (BMO_edge_flag_test(bm_src, e, DUPE_INPUT) &&
284 BMO_edge_flag_test(bm_src, e, DUPE_DONE) == false)
285 {
286 /* make sure that verts are copied */
287 if (!BMO_vert_flag_test(bm_src, e->v1, DUPE_DONE)) {
288 bmo_vert_copy(op, slot_vert_map_out, bm_dst, cd_vert_map, e->v1, vhash);
289 BMO_vert_flag_enable(bm_src, e->v1, DUPE_DONE);
290 }
291 if (!BMO_vert_flag_test(bm_src, e->v2, DUPE_DONE)) {
292 bmo_vert_copy(op, slot_vert_map_out, bm_dst, cd_vert_map, e->v2, vhash);
293 BMO_vert_flag_enable(bm_src, e->v2, DUPE_DONE);
294 }
295 /* now copy the actual edge */
296 bmo_edge_copy(op,
297 slot_edge_map_out,
298 slot_boundary_map_out,
299 bm_dst,
300 bm_src,
301 cd_edge_map,
302 e,
303 vhash,
304 ehash,
305 use_edge_flip_from_face);
307 }
308 }
309
310 /* first we dupe all flagged faces and their elements from source */
311 BM_ITER_MESH (f, &fiter, bm_src, BM_FACES_OF_MESH) {
312 if (BMO_face_flag_test(bm_src, f, DUPE_INPUT)) {
313 /* vertex pass */
314 BM_ITER_ELEM (v, &viter, f, BM_VERTS_OF_FACE) {
315 if (!BMO_vert_flag_test(bm_src, v, DUPE_DONE)) {
316 bmo_vert_copy(op, slot_vert_map_out, bm_dst, cd_vert_map, v, vhash);
318 }
319 }
320
321 /* edge pass */
322 BM_ITER_ELEM (e, &eiter, f, BM_EDGES_OF_FACE) {
323 if (!BMO_edge_flag_test(bm_src, e, DUPE_DONE)) {
324 bmo_edge_copy(op,
325 slot_edge_map_out,
326 slot_boundary_map_out,
327 bm_dst,
328 bm_src,
329 cd_edge_map,
330 e,
331 vhash,
332 ehash,
333 use_edge_flip_from_face);
335 }
336 }
337 bmo_face_copy(op, slot_face_map_out, bm_dst, cd_face_map, cd_loop_map, f, vhash, ehash);
339 }
340 }
341
342 /* free pointer hashes */
343 BLI_ghash_free(vhash, nullptr, nullptr);
344 BLI_ghash_free(ehash, nullptr, nullptr);
345
346 if (use_select_history) {
347 BLI_assert(bm_src == bm_dst);
349 bm_dst, slot_vert_map_out, slot_edge_map_out, slot_face_map_out, false);
350 }
351}
352
374{
375 BMOperator *dupeop = op;
376 BMesh *bm_dst = static_cast<BMesh *>(BMO_slot_ptr_get(op->slots_in, "dest"));
377
378 if (!bm_dst) {
379 bm_dst = bm;
380 }
381
382 /* flag input */
384
385 /* use the internal copy function */
386 bmo_mesh_copy(dupeop, bm_dst, bm);
387
388 /* Output */
389 /* First copy the input buffers to output buffers - original data */
390 BMO_slot_copy(dupeop, slots_in, "geom", dupeop, slots_out, "geom_orig.out");
391
392 /* Now alloc the new output buffers */
394 bm, dupeop, dupeop->slots_out, "geom.out", BM_ALL_NOLOOP, DUPE_NEW);
395}
396
397#if 0 /* UNUSED */
404void BMO_dupe_from_flag(BMesh *bm, int htype, const char hflag)
405{
406 BMOperator dupeop;
407
408 BMO_op_init(bm, &dupeop, "duplicate");
409 BMO_slot_buffer_from_enabled_hflag(bm, &dupeop, "geom", htype, hflag);
410
411 BMO_op_exec(bm, &dupeop);
412 BMO_op_finish(bm, &dupeop);
413}
414#endif
415
437{
438#define SPLIT_INPUT 1
439
440 BMOperator *splitop = op;
441 BMOperator dupeop;
442 const bool use_only_faces = BMO_slot_bool_get(op->slots_in, "use_only_faces");
443
444 /* initialize our sub-operator */
445 BMO_op_init(bm, &dupeop, op->flag, "duplicate");
446
447 BMO_slot_copy(splitop, slots_in, "geom", &dupeop, slots_in, "geom");
448 BMO_op_exec(bm, &dupeop);
449
450 BMFace *new_act_face = static_cast<BMFace *>(
451 BMO_slot_map_elem_get(BMO_slot_get(dupeop.slots_out, "face_map.out"), bm->act_face));
452 if (new_act_face) {
453 bm->act_face = new_act_face;
454 }
455
457
458 if (use_only_faces) {
459 BMVert *v;
460 BMEdge *e;
461 BMFace *f;
462 BMIter iter, iter2;
463
464 /* make sure to remove edges and verts we don't need */
465 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
466 bool found = false;
467 BM_ITER_ELEM (f, &iter2, e, BM_FACES_OF_EDGE) {
469 found = true;
470 break;
471 }
472 }
473 if (found == false) {
475 }
476 }
477
478 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
479 bool found = false;
480 BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) {
482 found = true;
483 break;
484 }
485 }
486 if (found == false) {
488 }
489 }
490 }
491
492 BMO_slot_copy(&dupeop, slots_out, "geom.out", splitop, slots_out, "geom.out");
493 BMO_slot_copy(&dupeop, slots_out, "isovert_map.out", splitop, slots_out, "isovert_map.out");
494
495 /* connect outputs of dupe to delete, excluding keep geometry */
497 bm,
499 DEL_FACES,
500 /* Call before deletion so deleted geometry isn't copied. */
501 [&bm, &dupeop, &splitop]() {
502 /* Now we make our outputs by copying the dupe output. */
503
504 /* NOTE: `boundary_map.out` can't use #BMO_slot_copy because some of the "source"
505 * geometry has been removed. In this case the (source -> destination) map doesn't work.
506 * In this case there isn't an especially good option.
507 * The geometry needs to be included so the boundary is accessible.
508 * Use the "destination" as the key and the value since it avoids adding freed
509 * geometry into the map and can be easily detected by other operators.
510 * See: #142633. */
511 const char *slot_name_boundary_map = "boundary_map.out";
512 BMOpSlot *splitop_boundary_map = BMO_slot_get(splitop->slots_out, slot_name_boundary_map);
513 BMOIter siter;
514 BMElem *ele_key;
515 BMO_ITER (ele_key, &siter, dupeop.slots_out, slot_name_boundary_map, 0) {
516 BMElem *ele_val = static_cast<BMElem *>(BMO_iter_map_value_ptr(&siter));
517 if (BMO_elem_flag_test(bm, ele_key, SPLIT_INPUT)) {
518 ele_key = ele_val;
519 }
520 BMO_slot_map_elem_insert(splitop, splitop_boundary_map, ele_key, ele_val);
521 }
522 });
523
524 /* cleanup */
525 BMO_op_finish(bm, &dupeop);
526
527#undef SPLIT_INPUT
528}
529
531{
532#define DEL_INPUT 1
533
534 BMOperator *delop = op;
535
536 /* Mark Buffer */
538
540
541#undef DEL_INPUT
542}
543
551{
552 BMOperator dupop, extop;
553 float cent[3], dvec[3];
554 float axis[3];
555 float rmat[3][3];
556 float phi;
557 int steps, do_dupli, a;
558 bool use_dvec;
559
560 BMO_slot_vec_get(op->slots_in, "cent", cent);
561 BMO_slot_vec_get(op->slots_in, "axis", axis);
562 normalize_v3(axis);
563 BMO_slot_vec_get(op->slots_in, "dvec", dvec);
564 use_dvec = !is_zero_v3(dvec);
565 steps = BMO_slot_int_get(op->slots_in, "steps");
566 phi = BMO_slot_float_get(op->slots_in, "angle") / steps;
567 do_dupli = BMO_slot_bool_get(op->slots_in, "use_duplicate");
568 const bool use_normal_flip = BMO_slot_bool_get(op->slots_in, "use_normal_flip");
569 /* Caller needs to perform other sanity checks (such as the spin being 360d). */
570 const bool use_merge = BMO_slot_bool_get(op->slots_in, "use_merge") && steps >= 3;
571
572 axis_angle_normalized_to_mat3(rmat, axis, phi);
573
574 BMVert **vtable = nullptr;
575 if (use_merge) {
576 vtable = MEM_malloc_arrayN<BMVert *>(bm->totvert, __func__);
577 int i = 0;
578 BMIter iter;
579 BMVert *v;
581 vtable[i] = v;
582 /* Evil! store original index in normal,
583 * this is duplicated into every other vertex.
584 * So we can read the original from the final.
585 *
586 * The normals must be recalculated anyway. */
587 *((int *)&v->no[0]) = i;
588 }
589 }
590
591 BMO_slot_copy(op, slots_in, "geom", op, slots_out, "geom_last.out");
592 for (a = 0; a < steps; a++) {
593 if (do_dupli) {
594 BMO_op_initf(bm, &dupop, op->flag, "duplicate geom=%S", op, "geom_last.out");
595 BMO_op_exec(bm, &dupop);
597 op->flag,
598 "rotate cent=%v matrix=%m3 space=%s verts=%S",
599 cent,
600 rmat,
601 op,
602 "space",
603 &dupop,
604 "geom.out");
605 BMO_slot_copy(&dupop, slots_out, "geom.out", op, slots_out, "geom_last.out");
606 BMO_op_finish(bm, &dupop);
607 }
608 else {
610 &extop,
611 op->flag,
612 "extrude_face_region "
613 "geom=%S "
614 "use_keep_orig=%b "
615 "use_normal_flip=%b "
616 "use_normal_from_adjacent=%b "
617 "skip_input_flip=%b",
618 op,
619 "geom_last.out",
620 use_merge,
621 use_normal_flip && (a == 0),
622 (a != 0),
623 true);
624 BMO_op_exec(bm, &extop);
625 if ((use_merge && (a == steps - 1)) == false) {
627 op->flag,
628 "rotate cent=%v matrix=%m3 space=%s verts=%S",
629 cent,
630 rmat,
631 op,
632 "space",
633 &extop,
634 "geom.out");
635 BMO_slot_copy(&extop, slots_out, "geom.out", op, slots_out, "geom_last.out");
636 }
637 else {
638 /* Merge first/last vertices and edges (maintaining 'geom.out' state). */
639 BMOpSlot *slot_geom_out = BMO_slot_get(extop.slots_out, "geom.out");
640 BMElem **elem_array = (BMElem **)slot_geom_out->data.buf;
641 int elem_array_len = slot_geom_out->len;
642 for (int i = 0; i < elem_array_len;) {
643 if (elem_array[i]->head.htype == BM_VERT) {
644 BMVert *v_src = (BMVert *)elem_array[i];
645 BMVert *v_dst = vtable[*((const int *)&v_src->no[0])];
646 BM_vert_splice(bm, v_dst, v_src);
647 elem_array_len--;
648 elem_array[i] = elem_array[elem_array_len];
649 }
650 else {
651 i++;
652 }
653 }
654 for (int i = 0; i < elem_array_len;) {
655 if (elem_array[i]->head.htype == BM_EDGE) {
656 BMEdge *e_src = (BMEdge *)elem_array[i];
657 BMEdge *e_dst = BM_edge_find_double(e_src);
658 if (e_dst != nullptr) {
659 BM_edge_splice(bm, e_dst, e_src);
660 elem_array_len--;
661 elem_array[i] = elem_array[elem_array_len];
662 continue;
663 }
664 }
665 i++;
666 }
667 /* Full copies of faces may cause overlap. */
668 for (int i = 0; i < elem_array_len;) {
669 if (elem_array[i]->head.htype == BM_FACE) {
670 BMFace *f_src = (BMFace *)elem_array[i];
671 BMFace *f_dst = BM_face_find_double(f_src);
672 if (f_dst != nullptr) {
673 BM_face_kill(bm, f_src);
674 elem_array_len--;
675 elem_array[i] = elem_array[elem_array_len];
676 continue;
677 }
678 }
679 i++;
680 }
681 slot_geom_out->len = elem_array_len;
682 }
683 BMO_op_finish(bm, &extop);
684 }
685
686 if (use_dvec) {
687 mul_m3_v3(rmat, dvec);
689 op->flag,
690 "translate vec=%v space=%s verts=%S",
691 dvec,
692 op,
693 "space",
694 op,
695 "geom_last.out");
696 }
697 }
698
699 if (vtable) {
700 MEM_freeN(vtable);
701 }
702}
BMCustomDataCopyMap CustomData_bmesh_copy_map_calc(const CustomData &src, const CustomData &dst, eCustomDataMask mask_exclude=0)
#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_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.cc:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:860
void mul_m3_v3(const float M[3][3], float r[3])
void axis_angle_normalized_to_mat3(float R[3][3], const float axis[3], float angle)
MINLINE bool is_zero_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v3(float n[3])
unsigned int uint
Read Guarded memory(de)allocation.
#define BM_ALL_NOLOOP
#define BM_FACE_FIRST_LOOP(p)
void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMVert *src, BMVert *dst)
bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src)
Splice Edge.
bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src)
Splice Vert.
void BM_face_kill(BMesh *bm, BMFace *f)
BMFace * BM_face_create(BMesh *bm, BMVert *const *verts, BMEdge *const *edges, const int len, const BMFace *f_example, const eBMCreateFlag create_flag)
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
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_SKIP_CD
Definition bmesh_core.hh:36
void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type, blender::FunctionRef< void()> prepare_fn)
#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_EDGE
@ BM_FACES_OF_VERT
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_VERTS_OF_FACE
@ BM_FACES_OF_MESH
@ BM_EDGES_OF_VERT
@ BM_EDGES_OF_FACE
BMesh * bm
void BM_edge_verts_swap(BMEdge *e)
#define BM_FACE
#define BM_EDGE
#define BM_VERT
void BMO_slot_buffer_flag_enable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, short oflag)
BMO_FLAG_BUFFER.
void * BMO_slot_ptr_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
#define BMO_edge_flag_test(bm, e, oflag)
void * BMO_iter_map_value_ptr(BMOIter *iter)
void BMO_slot_vec_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, float r_vec[3])
#define BMO_edge_flag_enable(bm, e, oflag)
void BMO_mesh_selected_remap(BMesh *bm, BMOpSlot *slot_vert_map, BMOpSlot *slot_edge_map, BMOpSlot *slot_face_map, bool check_select)
float BMO_slot_float_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
void BMO_slot_buffer_from_enabled_hflag(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, char hflag)
#define BMO_vert_flag_enable(bm, e, oflag)
BMOpSlot * BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
BMESH OPSTACK GET SLOT.
void BMO_op_exec(BMesh *bm, BMOperator *op)
BMESH OPSTACK EXEC OP.
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_slot_copy(op_src, slots_src, slot_name_src, op_dst, slots_dst, slot_name_dst)
void BMO_op_init(BMesh *bm, BMOperator *op, int flag, const char *opname)
BMESH OPSTACK INIT OP.
#define BMO_ITER(ele, iter, slot_args, slot_name, restrict_flag)
#define BMO_vert_flag_test(bm, e, oflag)
bool BMO_op_initf(BMesh *bm, BMOperator *op, int flag, const char *fmt,...)
int BMO_slot_int_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
void BMO_op_finish(BMesh *bm, BMOperator *op)
BMESH OPSTACK FINISH OP.
bool BMO_op_callf(BMesh *bm, int flag, const char *fmt,...)
#define BMO_elem_flag_test(bm, ele, oflag)
#define BMO_face_flag_test(bm, e, oflag)
bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
BLI_INLINE void BMO_slot_map_elem_insert(BMOperator *op, BMOpSlot *slot, const void *element, void *val)
BMEdge * BM_edge_find_double(BMEdge *e)
BMFace * BM_face_find_double(BMFace *f)
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define DUPE_NEW
Definition bmo_dupe.cc:24
static BMFace * bmo_face_copy(BMOperator *op, BMOpSlot *slot_facemap_out, BMesh *bm_dst, const std::optional< BMCustomDataCopyMap > &cd_face_map, const std::optional< BMCustomDataCopyMap > &cd_loop_map, BMFace *f_src, GHash *vhash, GHash *ehash)
Definition bmo_dupe.cc:145
#define DUPE_INPUT
Definition bmo_dupe.cc:23
#define SPLIT_INPUT
void bmo_split_exec(BMesh *bm, BMOperator *op)
Definition bmo_dupe.cc:436
static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src)
Definition bmo_dupe.cc:207
#define DUPE_DONE
Definition bmo_dupe.cc:25
#define DEL_INPUT
static BMVert * bmo_vert_copy(BMOperator *op, BMOpSlot *slot_vertmap_out, BMesh *bm_dst, const std::optional< BMCustomDataCopyMap > &cd_vert_map, BMVert *v_src, GHash *vhash)
Definition bmo_dupe.cc:33
void bmo_duplicate_exec(BMesh *bm, BMOperator *op)
Definition bmo_dupe.cc:373
void bmo_spin_exec(BMesh *bm, BMOperator *op)
Definition bmo_dupe.cc:550
static BMEdge * bmo_edge_copy(BMOperator *op, BMOpSlot *slot_edgemap_out, BMOpSlot *slot_boundarymap_out, BMesh *bm_dst, BMesh *bm_src, const std::optional< BMCustomDataCopyMap > &cd_edge_map, BMEdge *e_src, GHash *vhash, GHash *ehash, const bool use_edge_flip_from_face)
Definition bmo_dupe.cc:69
void bmo_delete_exec(BMesh *bm, BMOperator *op)
Definition bmo_dupe.cc:530
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
struct BMVert * v
struct BMEdge * e
struct BMLoop * radial_next
struct BMFace * f
struct BMLoop * next
union BMOpSlot::@313121210037300127305053354046356312170117023254 data
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
float co[3]
float no[3]
CustomData vdata
CustomData edata
CustomData pdata
CustomData ldata
i
Definition text_draw.cc:230