Blender V5.0
bmesh_construct.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2007 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_listbase.h"
15#include "BLI_math_vector.h"
16#include "BLI_sort_utils.h"
17
18#include "BKE_customdata.hh"
19
20#include "DNA_mesh_types.h"
21
22#include "bmesh.hh"
24
25bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len)
26{
27 int i, i_prev = len - 1;
28 for (i = 0; i < len; i++) {
29 vert_arr[i] = BM_edge_share_vert(edge_arr[i_prev], edge_arr[i]);
30 if (vert_arr[i] == nullptr) {
31 return false;
32 }
33 i_prev = i;
34 }
35 return true;
36}
37
38bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len)
39{
40 int i, i_prev = len - 1;
41 for (i = 0; i < len; i++) {
42 edge_arr[i_prev] = BM_edge_exists(vert_arr[i_prev], vert_arr[i]);
43 if (edge_arr[i_prev] == nullptr) {
44 return false;
45 }
46 i_prev = i;
47 }
48 return true;
49}
50
51void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, const int len)
52{
53 int i, i_prev = len - 1;
54 for (i = 0; i < len; i++) {
55 edge_arr[i_prev] = BM_edge_create(
56 bm, vert_arr[i_prev], vert_arr[i], nullptr, BM_CREATE_NO_DOUBLE);
57 i_prev = i;
58 }
59}
60
62 BMVert *v1,
63 BMVert *v2,
64 BMVert *v3,
65 BMVert *v4,
66 const BMFace *f_example,
67 const eBMCreateFlag create_flag)
68{
69 BMVert *vtar[4] = {v1, v2, v3, v4};
70 return BM_face_create_verts(bm, vtar, v4 ? 4 : 3, f_example, create_flag, true);
71}
72
73void BM_face_copy_shared(BMesh *bm, BMFace *f, BMLoopFilterFunc filter_fn, void *user_data)
74{
75 BMLoop *l_first;
76 BMLoop *l_iter;
77
78#ifndef NDEBUG
79 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
80 do {
82 } while ((l_iter = l_iter->next) != l_first);
83#endif
84
85 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
86 do {
87 BMLoop *l_other = l_iter->radial_next;
88
89 if (l_other && l_other != l_iter) {
90 BMLoop *l_src[2];
91 BMLoop *l_dst[2] = {l_iter, l_iter->next};
92 uint j;
93
94 if (l_other->v == l_iter->v) {
95 l_src[0] = l_other;
96 l_src[1] = l_other->next;
97 }
98 else {
99 l_src[0] = l_other->next;
100 l_src[1] = l_other;
101 }
102
103 for (j = 0; j < 2; j++) {
104 BLI_assert(l_dst[j]->v == l_src[j]->v);
105 if (BM_ELEM_API_FLAG_TEST(l_dst[j], _FLAG_OVERLAP) == 0) {
106 if ((filter_fn == nullptr) || filter_fn(l_src[j], user_data)) {
107 CustomData_bmesh_copy_block(bm->ldata, l_src[j]->head.data, &l_dst[j]->head.data);
109 }
110 }
111 }
112 }
113 } while ((l_iter = l_iter->next) != l_first);
114
115 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
116 do {
118 } while ((l_iter = l_iter->next) != l_first);
119}
120
129 BMVert *v2,
130 BMEdge **edges,
131 const int len,
132 BMEdge **edges_sort,
133 BMVert **verts_sort)
134{
135 BMEdge *e_iter, *e_first;
136 BMVert *v_iter;
137 int i;
138
139 /* all flags _must_ be cleared on exit! */
140 for (i = 0; i < len; i++) {
144 }
145
146 /* find first edge */
147 i = 0;
148 v_iter = v1;
149 e_iter = e_first = v1->e;
150 do {
151 if (BM_ELEM_API_FLAG_TEST(e_iter, _FLAG_MF) && (BM_edge_other_vert(e_iter, v_iter) == v2)) {
152 i = 1;
153 break;
154 }
155 } while ((e_iter = bmesh_disk_edge_next(e_iter, v_iter)) != e_first);
156 if (i == 0) {
157 goto error;
158 }
159
160 i = 0;
161 do {
162 /* entering loop will always succeed */
163 if (BM_ELEM_API_FLAG_TEST(e_iter, _FLAG_MF)) {
164 if (UNLIKELY(BM_ELEM_API_FLAG_TEST(v_iter, _FLAG_MV) == false)) {
165 /* vert is in loop multiple times */
166 goto error;
167 }
168
170 edges_sort[i] = e_iter;
171
173 verts_sort[i] = v_iter;
174
175 i += 1;
176
177 /* walk onto the next vertex */
178 v_iter = BM_edge_other_vert(e_iter, v_iter);
179 if (i == len) {
180 if (UNLIKELY(v_iter != verts_sort[0])) {
181 goto error;
182 }
183 break;
184 }
185
186 e_first = e_iter;
187 }
188 } while ((e_iter = bmesh_disk_edge_next(e_iter, v_iter)) != e_first);
189
190 if (i == len) {
191 return true;
192 }
193
194error:
195 for (i = 0; i < len; i++) {
199 }
200
201 return false;
202}
203
205 BMVert *v1,
206 BMVert *v2,
207 BMEdge **edges,
208 const int len,
209 const BMFace *f_example,
210 const eBMCreateFlag create_flag)
211{
212 BMEdge **edges_sort = BLI_array_alloca(edges_sort, len);
213 BMVert **verts_sort = BLI_array_alloca(verts_sort, len);
214
215 BLI_assert(len && v1 && v2 && edges && bm);
216
217 if (bm_edges_sort_winding(v1, v2, edges, len, edges_sort, verts_sort)) {
218 return BM_face_create(bm, verts_sort, edges_sort, len, f_example, create_flag);
219 }
220
221 return nullptr;
222}
223
225 BMVert **vert_arr,
226 const int len,
227 const BMFace *f_example,
228 const eBMCreateFlag create_flag,
229 const bool calc_winding,
230 const bool create_edges)
231{
232 BMEdge **edge_arr = BLI_array_alloca(edge_arr, len);
233 uint winding[2] = {0, 0};
234 int i, i_prev = len - 1;
235 BMVert *v_winding[2] = {vert_arr[i_prev], vert_arr[0]};
236
237 BLI_assert(len > 2);
238
239 for (i = 0; i < len; i++) {
240 if (create_edges) {
241 edge_arr[i] = BM_edge_create(
242 bm, vert_arr[i_prev], vert_arr[i], nullptr, BM_CREATE_NO_DOUBLE);
243 }
244 else {
245 edge_arr[i] = BM_edge_exists(vert_arr[i_prev], vert_arr[i]);
246 if (edge_arr[i] == nullptr) {
247 return nullptr;
248 }
249 }
250
251 if (calc_winding) {
252 /* the edge may exist already and be attached to a face
253 * in this case we can find the best winding to use for the new face */
254 if (edge_arr[i]->l) {
255 BMVert *test_v1, *test_v2;
256 /* we want to use the reverse winding to the existing order */
257 BM_edge_ordered_verts(edge_arr[i], &test_v2, &test_v1);
258 winding[(vert_arr[i_prev] == test_v2)]++;
259 BLI_assert(ELEM(vert_arr[i_prev], test_v2, test_v1));
260 }
261 }
262
263 i_prev = i;
264 }
265
266 /* --- */
267
268 if (calc_winding) {
269 if (winding[0] < winding[1]) {
270 winding[0] = 1;
271 winding[1] = 0;
272 }
273 else {
274 winding[0] = 0;
275 winding[1] = 1;
276 }
277 }
278 else {
279 winding[0] = 0;
280 winding[1] = 1;
281 }
282
283 /* --- */
284
285 /* create the face */
286 return BM_face_create_ngon(
287 bm, v_winding[winding[0]], v_winding[winding[1]], edge_arr, len, f_example, create_flag);
288}
289
291{
292 SortIntByFloat *vang = BLI_array_alloca(vang, len);
293 BMVert **vert_arr_map = BLI_array_alloca(vert_arr_map, len);
294
295 float nor[3], cent[3];
296 int index_tangent = 0;
297 BM_verts_calc_normal_from_cloud_ex(vert_arr, len, nor, cent, &index_tangent);
298 const float *far = vert_arr[index_tangent]->co;
299
300 /* Now calculate every points angle around the normal (signed). */
301 for (int i = 0; i < len; i++) {
302 vang[i].sort_value = angle_signed_on_axis_v3v3v3_v3(far, cent, vert_arr[i]->co, nor);
303 vang[i].data = i;
304 vert_arr_map[i] = vert_arr[i];
305 }
306
307 /* sort by angle and magic! - we have our ngon */
308 qsort(vang, len, sizeof(*vang), BLI_sortutil_cmp_float);
309
310 /* --- */
311
312 for (int i = 0; i < len; i++) {
313 vert_arr[i] = vert_arr_map[vang[i].data];
314 }
315}
316
317/*************************************************************/
318
319void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMVert *src, BMVert *dst)
320{
321 BLI_assert(src != dst);
322 CustomData_bmesh_copy_block(bm->vdata, map, src->head.data, &dst->head.data);
323 constexpr char hflag_mask = BM_ELEM_SELECT;
324 dst->head.hflag = (dst->head.hflag & hflag_mask) | (src->head.hflag & ~hflag_mask);
325 copy_v3_v3(dst->no, src->no);
326}
327void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMEdge *src, BMEdge *dst)
328{
329 BLI_assert(src != dst);
330 CustomData_bmesh_copy_block(bm->edata, map, src->head.data, &dst->head.data);
331 constexpr char hflag_mask = BM_ELEM_SELECT;
332 dst->head.hflag = (dst->head.hflag & hflag_mask) | (src->head.hflag & ~hflag_mask);
333}
334void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMFace *src, BMFace *dst)
335{
336 BLI_assert(src != dst);
337 CustomData_bmesh_copy_block(bm->pdata, map, src->head.data, &dst->head.data);
338 constexpr char hflag_mask = BM_ELEM_SELECT | BM_ELEM_SELECT_UV;
339 dst->head.hflag = (dst->head.hflag & hflag_mask) | (src->head.hflag & ~hflag_mask);
340 copy_v3_v3(dst->no, src->no);
341 dst->mat_nr = src->mat_nr;
342}
343void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMLoop *src, BMLoop *dst)
344{
345 BLI_assert(src != dst);
346 CustomData_bmesh_copy_block(bm->ldata, map, src->head.data, &dst->head.data);
347 constexpr char hflag_mask = BM_ELEM_SELECT | BM_ELEM_SELECT_UV | BM_ELEM_SELECT_UV_EDGE;
348 dst->head.hflag = (dst->head.hflag & hflag_mask) | (src->head.hflag & ~hflag_mask);
349}
350
351void BM_elem_attrs_copy(BMesh *bm, const BMVert *src, BMVert *dst)
352{
353 BLI_assert(src != dst);
354 CustomData_bmesh_copy_block(bm->vdata, src->head.data, &dst->head.data);
355 constexpr char hflag_mask = BM_ELEM_SELECT;
356 dst->head.hflag = (dst->head.hflag & hflag_mask) | (src->head.hflag & ~hflag_mask);
357 copy_v3_v3(dst->no, src->no);
358}
359void BM_elem_attrs_copy(BMesh *bm, const BMEdge *src, BMEdge *dst)
360{
361 BLI_assert(src != dst);
362 CustomData_bmesh_copy_block(bm->edata, src->head.data, &dst->head.data);
363 constexpr char hflag_mask = BM_ELEM_SELECT;
364 dst->head.hflag = (dst->head.hflag & hflag_mask) | (src->head.hflag & ~hflag_mask);
365}
366void BM_elem_attrs_copy(BMesh *bm, const BMFace *src, BMFace *dst)
367{
368 BLI_assert(src != dst);
369 constexpr char hflag_mask = BM_ELEM_SELECT | BM_ELEM_SELECT_UV;
370 CustomData_bmesh_copy_block(bm->pdata, src->head.data, &dst->head.data);
371 dst->head.hflag = (dst->head.hflag & hflag_mask) | (src->head.hflag & ~hflag_mask);
372 copy_v3_v3(dst->no, src->no);
373 dst->mat_nr = src->mat_nr;
374}
375void BM_elem_attrs_copy(BMesh *bm, const BMLoop *src, BMLoop *dst)
376{
377 BLI_assert(src != dst);
378 constexpr char hflag_mask = BM_ELEM_SELECT | BM_ELEM_SELECT_UV | BM_ELEM_SELECT_UV_EDGE;
379 CustomData_bmesh_copy_block(bm->ldata, src->head.data, &dst->head.data);
380 dst->head.hflag = (dst->head.hflag & hflag_mask) | (src->head.hflag & ~hflag_mask);
381}
382
383void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v)
384{
385 BMHeader *ele_dst = static_cast<BMHeader *>(ele_dst_v);
386 const BMHeader *ele_src = static_cast<const BMHeader *>(ele_src_v);
387
388 BLI_assert(ele_src->htype == ele_dst->htype);
389
390 if ((ele_src->hflag & BM_ELEM_SELECT) != (ele_dst->hflag & BM_ELEM_SELECT)) {
391 BM_elem_select_set(bm_dst, (BMElem *)ele_dst, (ele_src->hflag & BM_ELEM_SELECT) != 0);
392 }
393}
394
395/* helper function for 'BM_mesh_copy' */
397 const BMCustomDataCopyMap &face_map,
398 const BMCustomDataCopyMap &loop_map,
399 BMVert **vtable,
400 BMEdge **etable,
401 BMFace *f)
402{
403 BMLoop **loops = BLI_array_alloca(loops, f->len);
405 BMEdge **edges = BLI_array_alloca(edges, f->len);
406
407 BMFace *f_new;
408 BMLoop *l_iter, *l_first;
409 int j;
410
411 j = 0;
412 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
413 do {
414 loops[j] = l_iter;
415 verts[j] = vtable[BM_elem_index_get(l_iter->v)];
416 edges[j] = etable[BM_elem_index_get(l_iter->e)];
417 j++;
418 } while ((l_iter = l_iter->next) != l_first);
419
420 f_new = BM_face_create(bm_new, verts, edges, f->len, nullptr, BM_CREATE_SKIP_CD);
421
422 if (UNLIKELY(f_new == nullptr)) {
423 return nullptr;
424 }
425
426 /* use totface in case adding some faces fails */
427 BM_elem_index_set(f_new, (bm_new->totface - 1)); /* set_inline */
428
429 CustomData_bmesh_copy_block(bm_new->pdata, face_map, f->head.data, &f_new->head.data);
430 copy_v3_v3(f_new->no, f->no);
431 f_new->mat_nr = f->mat_nr;
432 f_new->head.hflag = f->head.hflag; /* Low level! don't do this for normal API use. */
433
434 j = 0;
435 l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
436 do {
437 CustomData_bmesh_copy_block(bm_new->ldata, loop_map, loops[j]->head.data, &l_iter->head.data);
438 l_iter->head.hflag = loops[j]->head.hflag & ~BM_ELEM_SELECT;
439 j++;
440 } while ((l_iter = l_iter->next) != l_first);
441
442 return f_new;
443}
444
446 const Mesh *me_src_array[],
447 const int me_src_array_len,
448 const BMAllocTemplate *allocsize)
449
450{
451 if (allocsize == nullptr) {
452 allocsize = &bm_mesh_allocsize_default;
453 }
454
455 for (int i = 0; i < me_src_array_len; i++) {
456 const Mesh *me_src = me_src_array[i];
458 &me_src->vert_data, CD_MASK_BMESH.vmask);
460 &me_src->edge_data, CD_MASK_BMESH.emask);
462 &me_src->face_data, CD_MASK_BMESH.pmask);
464 &me_src->corner_data, CD_MASK_BMESH.lmask);
465
466 if (i == 0) {
468 &mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0);
470 &mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0);
472 &mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0);
474 &mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0);
475 }
476 else {
477 CustomData_merge_layout(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0);
478 CustomData_merge_layout(&mesh_edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0);
479 CustomData_merge_layout(&mesh_pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0);
480 CustomData_merge_layout(&mesh_ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0);
481 }
482
483 MEM_SAFE_FREE(mesh_vdata.layers);
484 MEM_SAFE_FREE(mesh_edata.layers);
485 MEM_SAFE_FREE(mesh_pdata.layers);
486 MEM_SAFE_FREE(mesh_ldata.layers);
487 }
488
489 CustomData_bmesh_init_pool(&bm_dst->vdata, allocsize->totvert, BM_VERT);
490 CustomData_bmesh_init_pool(&bm_dst->edata, allocsize->totedge, BM_EDGE);
491 CustomData_bmesh_init_pool(&bm_dst->ldata, allocsize->totloop, BM_LOOP);
492 CustomData_bmesh_init_pool(&bm_dst->pdata, allocsize->totface, BM_FACE);
493}
494
496 const Mesh *me_src,
497 const BMAllocTemplate *allocsize)
498{
499 BM_mesh_copy_init_customdata_from_mesh_array(bm_dst, &me_src, 1, allocsize);
500}
501
502void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const BMAllocTemplate *allocsize)
503{
504 if (allocsize == nullptr) {
505 allocsize = &bm_mesh_allocsize_default;
506 }
507
509 &bm_src->vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0);
511 &bm_src->edata, &bm_dst->edata, CD_MASK_BMESH.emask, CD_SET_DEFAULT, 0);
513 &bm_src->ldata, &bm_dst->ldata, CD_MASK_BMESH.lmask, CD_SET_DEFAULT, 0);
515 &bm_src->pdata, &bm_dst->pdata, CD_MASK_BMESH.pmask, CD_SET_DEFAULT, 0);
516
517 CustomData_bmesh_init_pool(&bm_dst->vdata, allocsize->totvert, BM_VERT);
518 CustomData_bmesh_init_pool(&bm_dst->edata, allocsize->totedge, BM_EDGE);
519 CustomData_bmesh_init_pool(&bm_dst->ldata, allocsize->totloop, BM_LOOP);
520 CustomData_bmesh_init_pool(&bm_dst->pdata, allocsize->totface, BM_FACE);
521}
522
524 BMesh *bm_src,
525 const char htype,
526 const BMAllocTemplate *allocsize)
527{
528 if (allocsize == nullptr) {
529 allocsize = &bm_mesh_allocsize_default;
530 }
531
532 const char htypes[4] = {BM_VERT, BM_EDGE, BM_LOOP, BM_FACE};
533 BLI_assert(((&bm_dst->vdata + 1) == &bm_dst->edata) &&
534 ((&bm_dst->vdata + 2) == &bm_dst->ldata) && ((&bm_dst->vdata + 3) == &bm_dst->pdata));
535
536 BLI_assert(((&allocsize->totvert + 1) == &allocsize->totedge) &&
537 ((&allocsize->totvert + 2) == &allocsize->totloop) &&
538 ((&allocsize->totvert + 3) == &allocsize->totface));
539
540 for (int i = 0; i < 4; i++) {
541 if (!(htypes[i] & htype)) {
542 continue;
543 }
544 CustomData *dst = &bm_dst->vdata + i;
545 CustomData *src = &bm_src->vdata + i;
546 const int size = *(&allocsize->totvert + i);
547
548 for (int l = 0; l < src->totlayer; l++) {
550 dst, eCustomDataType(src->layers[l].type), CD_SET_DEFAULT, 0, src->layers[l].name);
551 }
552 CustomData_bmesh_init_pool(dst, size, htypes[i]);
553 }
554}
555
557{
558 BMesh *bm_new;
559 BMVert *v, *v_new, **vtable = nullptr;
560 BMEdge *e, *e_new, **etable = nullptr;
561 BMFace *f, *f_new, **ftable = nullptr;
562 BMElem **eletable;
563 BMIter iter;
564 int i;
565 const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_BM(bm_old);
566
567 /* allocate a bmesh */
569 params.use_toolflags = bm_old->use_toolflags;
570 bm_new = BM_mesh_create(&allocsize, &params);
571
572 BM_mesh_copy_init_customdata(bm_new, bm_old, &allocsize);
573
575 bm_new->vdata);
577 bm_new->edata);
579 bm_new->pdata);
581 bm_new->ldata);
582
583 vtable = MEM_malloc_arrayN<BMVert *>(bm_old->totvert, "BM_mesh_copy vtable");
584 etable = MEM_malloc_arrayN<BMEdge *>(bm_old->totedge, "BM_mesh_copy etable");
585 ftable = MEM_malloc_arrayN<BMFace *>(bm_old->totface, "BM_mesh_copy ftable");
586
587 BM_ITER_MESH_INDEX (v, &iter, bm_old, BM_VERTS_OF_MESH, i) {
588 /* copy between meshes so can't use 'example' argument */
589 v_new = BM_vert_create(bm_new, v->co, nullptr, BM_CREATE_SKIP_CD);
590 CustomData_bmesh_copy_block(bm_new->vdata, vert_map, v->head.data, &v_new->head.data);
591 copy_v3_v3(v_new->no, v->no);
592 v_new->head.hflag = v->head.hflag; /* Low level! don't do this for normal API use. */
593 vtable[i] = v_new;
594 BM_elem_index_set(v, i); /* set_inline */
595 BM_elem_index_set(v_new, i); /* set_inline */
596 }
597 bm_old->elem_index_dirty &= ~BM_VERT;
598 bm_new->elem_index_dirty &= ~BM_VERT;
599
600 /* safety check */
601 BLI_assert(i == bm_old->totvert);
602
603 BM_ITER_MESH_INDEX (e, &iter, bm_old, BM_EDGES_OF_MESH, i) {
604 e_new = BM_edge_create(bm_new,
605 vtable[BM_elem_index_get(e->v1)],
606 vtable[BM_elem_index_get(e->v2)],
607 e,
609
610 CustomData_bmesh_copy_block(bm_new->edata, edge_map, e->head.data, &e_new->head.data);
611 e_new->head.hflag = e->head.hflag; /* Low level! don't do this for normal API use. */
612 etable[i] = e_new;
613 BM_elem_index_set(e, i); /* set_inline */
614 BM_elem_index_set(e_new, i); /* set_inline */
615 }
616 bm_old->elem_index_dirty &= ~BM_EDGE;
617 bm_new->elem_index_dirty &= ~BM_EDGE;
618
619 /* safety check */
620 BLI_assert(i == bm_old->totedge);
621
622 BM_ITER_MESH_INDEX (f, &iter, bm_old, BM_FACES_OF_MESH, i) {
623 BM_elem_index_set(f, i); /* set_inline */
624
625 f_new = bm_mesh_copy_new_face(bm_new, face_map, loop_map, vtable, etable, f);
626
627 ftable[i] = f_new;
628
629 if (f == bm_old->act_face) {
630 bm_new->act_face = f_new;
631 }
632 }
633 bm_old->elem_index_dirty &= ~BM_FACE;
634 bm_new->elem_index_dirty &= ~BM_FACE;
635
636 /* Low level! don't do this for normal API use. */
637 bm_new->totvertsel = bm_old->totvertsel;
638 bm_new->totedgesel = bm_old->totedgesel;
639 bm_new->totfacesel = bm_old->totfacesel;
640
641 /* safety check */
642 BLI_assert(i == bm_old->totface);
643
644 /* copy over edit selection history */
645 LISTBASE_FOREACH (BMEditSelection *, ese, &bm_old->selected) {
646 BMElem *ele = nullptr;
647
648 switch (ese->htype) {
649 case BM_VERT:
650 eletable = (BMElem **)vtable;
651 break;
652 case BM_EDGE:
653 eletable = (BMElem **)etable;
654 break;
655 case BM_FACE:
656 eletable = (BMElem **)ftable;
657 break;
658 default:
659 eletable = nullptr;
660 break;
661 }
662
663 if (eletable) {
664 ele = eletable[BM_elem_index_get(ese->ele)];
665 if (ele) {
666 BM_select_history_store(bm_new, ele);
667 }
668 }
669 }
670
671 MEM_freeN(etable);
672 MEM_freeN(vtable);
673 MEM_freeN(ftable);
674
675 /* Copy various settings. */
676 bm_new->shapenr = bm_old->shapenr;
677 bm_new->selectmode = bm_old->selectmode;
678
679 return bm_new;
680}
CustomData interface, see also DNA_customdata_types.h.
@ CD_SET_DEFAULT
void * CustomData_add_layer_named(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem, blender::StringRef name)
BMCustomDataCopyMap CustomData_bmesh_copy_map_calc(const CustomData &src, const CustomData &dst, eCustomDataMask mask_exclude=0)
void CustomData_bmesh_init_pool(CustomData *data, int totelem, char htype)
const CustomData_MeshMasks CD_MASK_BMESH
void CustomData_bmesh_copy_block(CustomData &data, void *src_block, void **dst_block)
void CustomData_init_layout_from(const CustomData *source, CustomData *dest, eCustomDataMask mask, eCDAllocType alloctype, int totelem)
CustomData CustomData_shallow_copy_remove_non_bmesh_attributes(const CustomData *src, eCustomDataMask mask)
bool CustomData_merge_layout(const CustomData *source, CustomData *dest, eCustomDataMask mask, eCDAllocType alloctype, int totelem)
#define BLI_array_alloca(arr, realsize)
Definition BLI_alloca.h:18
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
float angle_signed_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v3_v3(float r[3], const float a[3])
int BLI_sortutil_cmp_float(const void *a_, const void *b_)
Definition sort_utils.cc:25
unsigned int uint
#define UNLIKELY(x)
#define ELEM(...)
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
bool(*)(const BMLoop *, void *user_data) BMLoopFilterFunc
#define BM_ELEM_SELECT_UV_EDGE
#define BM_FACE_FIRST_LOOP(p)
@ BM_ELEM_SELECT
@ BM_ELEM_SELECT_UV
@ BM_LOOP
void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const BMAllocTemplate *allocsize)
void BM_verts_sort_radial_plane(BMVert **vert_arr, int len)
static bool bm_edges_sort_winding(BMVert *v1, BMVert *v2, BMEdge **edges, const int len, BMEdge **edges_sort, BMVert **verts_sort)
void BM_face_copy_shared(BMesh *bm, BMFace *f, BMLoopFilterFunc filter_fn, void *user_data)
copies face loop data from shared adjacent faces.
bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len)
void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v)
void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMVert *src, BMVert *dst)
void BM_mesh_copy_init_customdata_from_mesh_array(BMesh *bm_dst, const Mesh *me_src_array[], const int me_src_array_len, const BMAllocTemplate *allocsize)
void BM_mesh_copy_init_customdata_from_mesh(BMesh *bm_dst, const Mesh *me_src, const BMAllocTemplate *allocsize)
BMFace * BM_face_create_ngon_verts(BMesh *bm, BMVert **vert_arr, const int len, const BMFace *f_example, const eBMCreateFlag create_flag, const bool calc_winding, const bool create_edges)
void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, const int len)
static BMFace * bm_mesh_copy_new_face(BMesh *bm_new, const BMCustomDataCopyMap &face_map, const BMCustomDataCopyMap &loop_map, BMVert **vtable, BMEdge **etable, BMFace *f)
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 BM_mesh_copy_init_customdata_all_layers(BMesh *bm_dst, BMesh *bm_src, const char htype, const BMAllocTemplate *allocsize)
BMesh * BM_mesh_copy(BMesh *bm_old)
bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len)
BMFace * BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, const int len, const BMFace *f_example, const eBMCreateFlag create_flag)
Make NGon.
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)
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.
eBMCreateFlag
Definition bmesh_core.hh:27
@ BM_CREATE_SKIP_CD
Definition bmesh_core.hh:36
@ BM_CREATE_NO_DOUBLE
Definition bmesh_core.hh:30
#define BM_elem_index_get(ele)
#define BM_elem_index_set(ele, index)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
BMesh * bm
void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select)
#define BM_select_history_store(bm, ele)
const BMAllocTemplate bm_mesh_allocsize_default
Definition bmesh_mesh.cc:30
BMesh * BM_mesh_create(const BMAllocTemplate *allocsize, const BMeshCreateParams *params)
BMesh Make Mesh.
#define BMALLOC_TEMPLATE_FROM_BM(bm)
#define BM_FACE
#define BM_EDGE
#define BM_VERT
void BM_verts_calc_normal_from_cloud_ex(BMVert **varr, int varr_len, float r_normal[3], float r_center[3], int *r_index_tangent)
#define BM_ELEM_API_FLAG_DISABLE(element, f)
#define BM_ELEM_API_FLAG_TEST(element, f)
#define BM_ELEM_API_FLAG_ENABLE(element, f)
@ _FLAG_MV
@ _FLAG_MF
@ _FLAG_OVERLAP
BMVert * BM_edge_share_vert(BMEdge *e1, BMEdge *e2)
void BM_edge_ordered_verts(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
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 BMVert * v
BLI_INLINE BMEdge * bmesh_disk_edge_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static float verts[][3]
uint nor
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
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
static void error(const char *str)
BMHeader head
short mat_nr
BMHeader head
float no[3]
void * data
BMHeader head
struct BMVert * v
struct BMEdge * e
struct BMLoop * radial_next
struct BMLoop * next
float co[3]
struct BMEdge * e
float no[3]
BMHeader head
int totvert
int totfacesel
int shapenr
char elem_index_dirty
CustomData vdata
int totedge
ListBase selected
CustomData edata
int totvertsel
BMFace * act_face
short selectmode
bool use_toolflags
int totedgesel
CustomData pdata
CustomData ldata
int totface
CustomDataLayer * layers
CustomData edge_data
CustomData corner_data
CustomData face_data
CustomData vert_data
i
Definition text_draw.cc:230
uint len