Blender V4.3
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
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
451
452 if (use_only_faces) {
453 BMVert *v;
454 BMEdge *e;
455 BMFace *f;
456 BMIter iter, iter2;
457
458 /* make sure to remove edges and verts we don't need */
459 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
460 bool found = false;
461 BM_ITER_ELEM (f, &iter2, e, BM_FACES_OF_EDGE) {
463 found = true;
464 break;
465 }
466 }
467 if (found == false) {
469 }
470 }
471
472 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
473 bool found = false;
474 BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) {
476 found = true;
477 break;
478 }
479 }
480 if (found == false) {
482 }
483 }
484 }
485
486 /* connect outputs of dupe to delete, excluding keep geometry */
488
489 /* now we make our outputs by copying the dupe output */
490 BMO_slot_copy(&dupeop, slots_out, "geom.out", splitop, slots_out, "geom.out");
491
492 /* cleanup */
493 BMO_op_finish(bm, &dupeop);
494
495#undef SPLIT_INPUT
496}
497
499{
500#define DEL_INPUT 1
501
502 BMOperator *delop = op;
503
504 /* Mark Buffer */
506
508
509#undef DEL_INPUT
510}
511
519{
520 BMOperator dupop, extop;
521 float cent[3], dvec[3];
522 float axis[3];
523 float rmat[3][3];
524 float phi;
525 int steps, do_dupli, a;
526 bool use_dvec;
527
528 BMO_slot_vec_get(op->slots_in, "cent", cent);
529 BMO_slot_vec_get(op->slots_in, "axis", axis);
530 normalize_v3(axis);
531 BMO_slot_vec_get(op->slots_in, "dvec", dvec);
532 use_dvec = !is_zero_v3(dvec);
533 steps = BMO_slot_int_get(op->slots_in, "steps");
534 phi = BMO_slot_float_get(op->slots_in, "angle") / steps;
535 do_dupli = BMO_slot_bool_get(op->slots_in, "use_duplicate");
536 const bool use_normal_flip = BMO_slot_bool_get(op->slots_in, "use_normal_flip");
537 /* Caller needs to perform other sanity checks (such as the spin being 360d). */
538 const bool use_merge = BMO_slot_bool_get(op->slots_in, "use_merge") && steps >= 3;
539
540 axis_angle_normalized_to_mat3(rmat, axis, phi);
541
542 BMVert **vtable = nullptr;
543 if (use_merge) {
544 vtable = static_cast<BMVert **>(MEM_mallocN(sizeof(BMVert *) * bm->totvert, __func__));
545 int i = 0;
546 BMIter iter;
547 BMVert *v;
549 vtable[i] = v;
550 /* Evil! store original index in normal,
551 * this is duplicated into every other vertex.
552 * So we can read the original from the final.
553 *
554 * The normals must be recalculated anyway. */
555 *((int *)&v->no[0]) = i;
556 }
557 }
558
559 BMO_slot_copy(op, slots_in, "geom", op, slots_out, "geom_last.out");
560 for (a = 0; a < steps; a++) {
561 if (do_dupli) {
562 BMO_op_initf(bm, &dupop, op->flag, "duplicate geom=%S", op, "geom_last.out");
563 BMO_op_exec(bm, &dupop);
565 op->flag,
566 "rotate cent=%v matrix=%m3 space=%s verts=%S",
567 cent,
568 rmat,
569 op,
570 "space",
571 &dupop,
572 "geom.out");
573 BMO_slot_copy(&dupop, slots_out, "geom.out", op, slots_out, "geom_last.out");
574 BMO_op_finish(bm, &dupop);
575 }
576 else {
578 &extop,
579 op->flag,
580 "extrude_face_region "
581 "geom=%S "
582 "use_keep_orig=%b "
583 "use_normal_flip=%b "
584 "use_normal_from_adjacent=%b",
585 op,
586 "geom_last.out",
587 use_merge,
588 use_normal_flip && (a == 0),
589 (a != 0));
590 BMO_op_exec(bm, &extop);
591 if ((use_merge && (a == steps - 1)) == false) {
593 op->flag,
594 "rotate cent=%v matrix=%m3 space=%s verts=%S",
595 cent,
596 rmat,
597 op,
598 "space",
599 &extop,
600 "geom.out");
601 BMO_slot_copy(&extop, slots_out, "geom.out", op, slots_out, "geom_last.out");
602 }
603 else {
604 /* Merge first/last vertices and edges (maintaining 'geom.out' state). */
605 BMOpSlot *slot_geom_out = BMO_slot_get(extop.slots_out, "geom.out");
606 BMElem **elem_array = (BMElem **)slot_geom_out->data.buf;
607 int elem_array_len = slot_geom_out->len;
608 for (int i = 0; i < elem_array_len;) {
609 if (elem_array[i]->head.htype == BM_VERT) {
610 BMVert *v_src = (BMVert *)elem_array[i];
611 BMVert *v_dst = vtable[*((const int *)&v_src->no[0])];
612 BM_vert_splice(bm, v_dst, v_src);
613 elem_array_len--;
614 elem_array[i] = elem_array[elem_array_len];
615 }
616 else {
617 i++;
618 }
619 }
620 for (int i = 0; i < elem_array_len;) {
621 if (elem_array[i]->head.htype == BM_EDGE) {
622 BMEdge *e_src = (BMEdge *)elem_array[i];
623 BMEdge *e_dst = BM_edge_find_double(e_src);
624 if (e_dst != nullptr) {
625 BM_edge_splice(bm, e_dst, e_src);
626 elem_array_len--;
627 elem_array[i] = elem_array[elem_array_len];
628 continue;
629 }
630 }
631 i++;
632 }
633 /* Full copies of faces may cause overlap. */
634 for (int i = 0; i < elem_array_len;) {
635 if (elem_array[i]->head.htype == BM_FACE) {
636 BMFace *f_src = (BMFace *)elem_array[i];
637 BMFace *f_dst = BM_face_find_double(f_src);
638 if (f_dst != nullptr) {
639 BM_face_kill(bm, f_src);
640 elem_array_len--;
641 elem_array[i] = elem_array[elem_array_len];
642 continue;
643 }
644 }
645 i++;
646 }
647 slot_geom_out->len = elem_array_len;
648 }
649 BMO_op_finish(bm, &extop);
650 }
651
652 if (use_dvec) {
653 mul_m3_v3(rmat, dvec);
655 op->flag,
656 "translate vec=%v space=%s verts=%S",
657 dvec,
658 op,
659 "space",
660 op,
661 "geom_last.out");
662 }
663 }
664
665 if (vtable) {
666 MEM_freeN(vtable);
667 }
668}
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: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_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.c:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c: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:43
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:32
void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type)
#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
ATTR_WARN_UNUSED_RESULT 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_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_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_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:518
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:498
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
static const int steps
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::@139 data
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
float co[3]
float no[3]
int totvert
CustomData vdata
CustomData edata
CustomData pdata
CustomData ldata