Blender V4.3
bmesh_mesh.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 "DNA_listBase.h"
14
15#include "BLI_listbase.h"
16#include "BLI_math_matrix.h"
17#include "BLI_math_vector.h"
18#include "BLI_utildefines.h"
19
20#include "BKE_customdata.hh"
21#include "BKE_mesh.hh"
22
23#include "bmesh.hh"
24
25using blender::Array;
26using blender::float3;
28
29const BMAllocTemplate bm_mesh_allocsize_default = {512, 1024, 2048, 512};
30const BMAllocTemplate bm_mesh_chunksize_default = {512, 1024, 2048, 512};
31
32static void bm_mempool_init_ex(const BMAllocTemplate *allocsize,
33 const bool use_toolflags,
34 BLI_mempool **r_vpool,
35 BLI_mempool **r_epool,
36 BLI_mempool **r_lpool,
37 BLI_mempool **r_fpool)
38{
39 size_t vert_size, edge_size, loop_size, face_size;
40
41 if (use_toolflags == true) {
42 vert_size = sizeof(BMVert_OFlag);
43 edge_size = sizeof(BMEdge_OFlag);
44 loop_size = sizeof(BMLoop);
45 face_size = sizeof(BMFace_OFlag);
46 }
47 else {
48 vert_size = sizeof(BMVert);
49 edge_size = sizeof(BMEdge);
50 loop_size = sizeof(BMLoop);
51 face_size = sizeof(BMFace);
52 }
53
54 if (r_vpool) {
55 *r_vpool = BLI_mempool_create(
57 }
58 if (r_epool) {
59 *r_epool = BLI_mempool_create(
61 }
62 if (r_lpool) {
63 *r_lpool = BLI_mempool_create(
65 }
66 if (r_fpool) {
67 *r_fpool = BLI_mempool_create(
69 }
70}
71
72static void bm_mempool_init(BMesh *bm, const BMAllocTemplate *allocsize, const bool use_toolflags)
73{
74 bm_mempool_init_ex(allocsize, use_toolflags, &bm->vpool, &bm->epool, &bm->lpool, &bm->fpool);
75
76#ifdef USE_BMESH_HOLES
77 bm->looplistpool = BLI_mempool_create(sizeof(BMLoopList), 512, 512, BLI_MEMPOOL_NOP);
78#endif
79}
80
82{
84
86 return;
87 }
88
92
93 BMIter iter;
94 BMVert_OFlag *v_olfag;
95 BLI_mempool *toolflagpool = bm->vtoolflagpool;
96 BM_ITER_MESH (v_olfag, &iter, bm, BM_VERTS_OF_MESH) {
97 v_olfag->oflags = static_cast<BMFlagLayer *>(BLI_mempool_calloc(toolflagpool));
98 }
99
100 BMEdge_OFlag *e_olfag;
101 toolflagpool = bm->etoolflagpool;
102 BM_ITER_MESH (e_olfag, &iter, bm, BM_EDGES_OF_MESH) {
103 e_olfag->oflags = static_cast<BMFlagLayer *>(BLI_mempool_calloc(toolflagpool));
104 }
105
106 BMFace_OFlag *f_olfag;
107 toolflagpool = bm->ftoolflagpool;
108 BM_ITER_MESH (f_olfag, &iter, bm, BM_FACES_OF_MESH) {
109 f_olfag->oflags = static_cast<BMFlagLayer *>(BLI_mempool_calloc(toolflagpool));
110 }
111
112 bm->totflags = 1;
113}
114
116{
117 if (bm->vtoolflagpool) {
119 bm->vtoolflagpool = nullptr;
120 }
121 if (bm->etoolflagpool) {
123 bm->etoolflagpool = nullptr;
124 }
125 if (bm->ftoolflagpool) {
127 bm->ftoolflagpool = nullptr;
128 }
129}
130
132{
133 /* allocate the structure */
134 BMesh *bm = static_cast<BMesh *>(MEM_callocN(sizeof(BMesh), __func__));
135
136 /* allocate the memory pools for the mesh elements */
137 bm_mempool_init(bm, allocsize, params->use_toolflags);
138
139 /* allocate one flag pool that we don't get rid of. */
140 bm->use_toolflags = params->use_toolflags;
141 bm->toolflag_index = 0;
142 bm->totflags = 0;
143
148
149 return bm;
150}
151
153{
154 BMVert *v;
155 BMEdge *e;
156 BMLoop *l;
157 BMFace *f;
158
159 BMIter iter;
160 BMIter itersub;
161
162 const bool is_ldata_free = CustomData_bmesh_has_free(&bm->ldata);
163 const bool is_pdata_free = CustomData_bmesh_has_free(&bm->pdata);
164
165 /* Check if we have to call free, if not we can avoid a lot of looping */
167 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
169 }
170 }
172 BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
174 }
175 }
176
177 if (is_ldata_free || is_pdata_free) {
178 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
179 if (is_pdata_free) {
181 }
182 if (is_ldata_free) {
183 BM_ITER_ELEM (l, &itersub, f, BM_LOOPS_OF_FACE) {
185 }
186 }
187 }
188 }
189
190 /* Free custom data pools, This should probably go in CustomData_free? */
191 if (bm->vdata.totlayer) {
193 }
194 if (bm->edata.totlayer) {
196 }
197 if (bm->ldata.totlayer) {
199 }
200 if (bm->pdata.totlayer) {
202 }
203
204 /* free custom data */
209
210 /* destroy element pools */
215
216 if (bm->vtable) {
218 }
219 if (bm->etable) {
221 }
222 if (bm->ftable) {
224 }
225
226 /* destroy flag pool */
228
229#ifdef USE_BMESH_HOLES
230 BLI_mempool_destroy(bm->looplistpool);
231#endif
232
234
235 if (bm->lnor_spacearr) {
238 }
239
241}
242
244{
245 const bool use_toolflags = bm->use_toolflags;
246 void *py_handle = bm->py_handle;
247
248 /* free old mesh */
250 memset(bm, 0, sizeof(BMesh));
251
252 /* allocate the memory pools for the mesh elements */
254
255 bm->use_toolflags = use_toolflags;
256 bm->py_handle = py_handle;
257
258 bm->toolflag_index = 0;
259 bm->totflags = 0;
260
265}
266
268{
270
271 if (bm->py_handle) {
272 /* keep this out of 'BM_mesh_data_free' because we want python
273 * to be able to clear the mesh and maintain access. */
275 bm->py_handle = nullptr;
276 }
277
278 MEM_freeN(bm);
279}
280
281void bmesh_edit_begin(BMesh * /*bm*/, BMOpTypeFlag /*type_flag*/)
282{
283 /* Most operators seem to be using BMO_OPTYPE_FLAG_UNTAN_MULTIRES to change the MDisps to
284 * absolute space during mesh edits. With this enabled, changes to the topology
285 * (loop cuts, edge subdivides, etc) are not reflected in the higher levels of
286 * the mesh at all, which doesn't seem right. Turning off completely for now,
287 * until this is shown to be better for certain types of mesh edits. */
288#ifdef BMOP_UNTAN_MULTIRES_ENABLED
289 /* switch multires data out of tangent space */
291 {
292 bmesh_mdisps_space_set(bm, MULTIRES_SPACE_TANGENT, MULTIRES_SPACE_ABSOLUTE);
293
294 /* ensure correct normals, if possible */
295 bmesh_rationalize_normals(bm, 0);
297 }
298#endif
299}
300
302{
303 ListBase select_history;
304
305 /* BMO_OPTYPE_FLAG_UNTAN_MULTIRES disabled for now, see comment above in bmesh_edit_begin. */
306#ifdef BMOP_UNTAN_MULTIRES_ENABLED
307 /* switch multires data into tangent space */
309 /* set normals to their previous winding */
310 bmesh_rationalize_normals(bm, 1);
311 bmesh_mdisps_space_set(bm, MULTIRES_SPACE_ABSOLUTE, MULTIRES_SPACE_TANGENT);
312 }
313 else if (flag & BMO_OP_FLAG_RATIONALIZE_NORMALS) {
314 bmesh_rationalize_normals(bm, 1);
315 }
316#endif
317
318 /* compute normals, clear temp flags and flush selections */
319 if (type_flag & BMO_OPTYPE_FLAG_NORMALS_CALC) {
322 }
323
324 if ((type_flag & BMO_OPTYPE_FLAG_SELECT_VALIDATE) == 0) {
325 select_history = bm->selected;
327 }
328
329 if (type_flag & BMO_OPTYPE_FLAG_SELECT_FLUSH) {
331 }
332
333 if ((type_flag & BMO_OPTYPE_FLAG_SELECT_VALIDATE) == 0) {
334 bm->selected = select_history;
335 }
336 if (type_flag & BMO_OPTYPE_FLAG_INVALIDATE_CLNOR_ALL) {
338 }
339}
340
341void BM_mesh_elem_index_ensure_ex(BMesh *bm, const char htype, int elem_offset[4])
342{
343
344#ifndef NDEBUG
345 BM_ELEM_INDEX_VALIDATE(bm, "Should Never Fail!", __func__);
346#endif
347
348 if (elem_offset == nullptr) {
349 /* Simple case. */
350 const char htype_needed = bm->elem_index_dirty & htype;
351 if (htype_needed == 0) {
352 goto finally;
353 }
354 }
355
356 if (htype & BM_VERT) {
357 if ((bm->elem_index_dirty & BM_VERT) || (elem_offset && elem_offset[0])) {
358 BMIter iter;
359 BMElem *ele;
360
361 int index = elem_offset ? elem_offset[0] : 0;
362 BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
363 BM_elem_index_set(ele, index++); /* set_ok */
364 }
365 BLI_assert(elem_offset || index == bm->totvert);
366 }
367 else {
368 // printf("%s: skipping vert index calc!\n", __func__);
369 }
370 }
371
372 if (htype & BM_EDGE) {
373 if ((bm->elem_index_dirty & BM_EDGE) || (elem_offset && elem_offset[1])) {
374 BMIter iter;
375 BMElem *ele;
376
377 int index = elem_offset ? elem_offset[1] : 0;
378 BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
379 BM_elem_index_set(ele, index++); /* set_ok */
380 }
381 BLI_assert(elem_offset || index == bm->totedge);
382 }
383 else {
384 // printf("%s: skipping edge index calc!\n", __func__);
385 }
386 }
387
388 if (htype & (BM_FACE | BM_LOOP)) {
389 if ((bm->elem_index_dirty & (BM_FACE | BM_LOOP)) ||
390 (elem_offset && (elem_offset[2] || elem_offset[3])))
391 {
392 BMIter iter;
393 BMElem *ele;
394
395 const bool update_face = (htype & BM_FACE) && (bm->elem_index_dirty & BM_FACE);
396 const bool update_loop = (htype & BM_LOOP) && (bm->elem_index_dirty & BM_LOOP);
397
398 int index_loop = elem_offset ? elem_offset[2] : 0;
399 int index = elem_offset ? elem_offset[3] : 0;
400
401 BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
402 if (update_face) {
403 BM_elem_index_set(ele, index++); /* set_ok */
404 }
405
406 if (update_loop) {
407 BMLoop *l_iter, *l_first;
408
409 l_iter = l_first = BM_FACE_FIRST_LOOP((BMFace *)ele);
410 do {
411 BM_elem_index_set(l_iter, index_loop++); /* set_ok */
412 } while ((l_iter = l_iter->next) != l_first);
413 }
414 }
415
416 BLI_assert(elem_offset || !update_face || index == bm->totface);
417 if (update_loop) {
418 BLI_assert(elem_offset || !update_loop || index_loop == bm->totloop);
419 }
420 }
421 else {
422 // printf("%s: skipping face/loop index calc!\n", __func__);
423 }
424 }
425
426finally:
427 bm->elem_index_dirty &= ~htype;
428 if (elem_offset) {
429 if (htype & BM_VERT) {
430 elem_offset[0] += bm->totvert;
431 if (elem_offset[0] != bm->totvert) {
433 }
434 }
435 if (htype & BM_EDGE) {
436 elem_offset[1] += bm->totedge;
437 if (elem_offset[1] != bm->totedge) {
439 }
440 }
441 if (htype & BM_LOOP) {
442 elem_offset[2] += bm->totloop;
443 if (elem_offset[2] != bm->totloop) {
445 }
446 }
447 if (htype & BM_FACE) {
448 elem_offset[3] += bm->totface;
449 if (elem_offset[3] != bm->totface) {
451 }
452 }
453 }
454}
455
456void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
457{
458 BM_mesh_elem_index_ensure_ex(bm, htype, nullptr);
459}
460
462 BMesh *bm, const char *location, const char *func, const char *msg_a, const char *msg_b)
463{
464 const char iter_types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
465
466 const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE};
467 const char *type_names[3] = {"vert", "edge", "face"};
468
469 BMIter iter;
470 BMElem *ele;
471 int i;
472 bool is_any_error = false;
473
474 for (i = 0; i < 3; i++) {
475 const bool is_dirty = (flag_types[i] & bm->elem_index_dirty) != 0;
476 int index = 0;
477 bool is_error = false;
478 int err_val = 0;
479 int err_idx = 0;
480
481 BM_ITER_MESH (ele, &iter, bm, iter_types[i]) {
482 if (!is_dirty) {
483 if (BM_elem_index_get(ele) != index) {
484 err_val = BM_elem_index_get(ele);
485 err_idx = index;
486 is_error = true;
487 break;
488 }
489 }
490 index++;
491 }
492
493 if ((is_error == true) && (is_dirty == false)) {
494 is_any_error = true;
495 fprintf(stderr,
496 "Invalid Index: at %s, %s, %s[%d] invalid index %d, '%s', '%s'\n",
497 location,
498 func,
499 type_names[i],
500 err_idx,
501 err_val,
502 msg_a,
503 msg_b);
504 }
505 else if ((is_error == false) && (is_dirty == true)) {
506
507#if 0 /* mostly annoying */
508
509 /* dirty may have been incorrectly set */
510 fprintf(stderr,
511 "Invalid Dirty: at %s, %s (%s), dirty flag was set but all index values are "
512 "correct, '%s', '%s'\n",
513 location,
514 func,
515 type_names[i],
516 msg_a,
517 msg_b);
518#endif
519 }
520 }
521
522#if 0 /* mostly annoying, even in debug mode */
523# ifndef NDEBUG
524 if (is_any_error == 0) {
525 fprintf(stderr, "Valid Index Success: at %s, %s, '%s', '%s'\n", location, func, msg_a, msg_b);
526 }
527# endif
528#endif
529 (void)is_any_error; /* shut up the compiler */
530}
531
532/* debug check only - no need to optimize */
533#ifndef NDEBUG
535{
536 BMIter iter;
537 BMElem *ele;
538 int i;
539
540 if (bm->vtable && ((bm->elem_table_dirty & BM_VERT) == 0)) {
541 BM_ITER_MESH_INDEX (ele, &iter, bm, BM_VERTS_OF_MESH, i) {
542 if (ele != (BMElem *)bm->vtable[i]) {
543 return false;
544 }
545 }
546 }
547
548 if (bm->etable && ((bm->elem_table_dirty & BM_EDGE) == 0)) {
549 BM_ITER_MESH_INDEX (ele, &iter, bm, BM_EDGES_OF_MESH, i) {
550 if (ele != (BMElem *)bm->etable[i]) {
551 return false;
552 }
553 }
554 }
555
556 if (bm->ftable && ((bm->elem_table_dirty & BM_FACE) == 0)) {
557 BM_ITER_MESH_INDEX (ele, &iter, bm, BM_FACES_OF_MESH, i) {
558 if (ele != (BMElem *)bm->ftable[i]) {
559 return false;
560 }
561 }
562 }
563
564 return true;
565}
566#endif
567
568void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
569{
570 /* assume if the array is non-null then its valid and no need to recalc */
571 const char htype_needed =
572 (((bm->vtable && ((bm->elem_table_dirty & BM_VERT) == 0)) ? 0 : BM_VERT) |
573 ((bm->etable && ((bm->elem_table_dirty & BM_EDGE) == 0)) ? 0 : BM_EDGE) |
574 ((bm->ftable && ((bm->elem_table_dirty & BM_FACE) == 0)) ? 0 : BM_FACE)) &
575 htype;
576
577 BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
578
579 /* in debug mode double check we didn't need to recalculate */
581
582 if (htype_needed == 0) {
583 goto finally;
584 }
585
586 if (htype_needed & BM_VERT) {
587 if (bm->vtable && bm->totvert <= bm->vtable_tot && bm->totvert * 2 >= bm->vtable_tot) {
588 /* pass (re-use the array) */
589 }
590 else {
591 if (bm->vtable) {
593 }
594 bm->vtable = static_cast<BMVert **>(
595 MEM_mallocN(sizeof(void **) * bm->totvert, "bm->vtable"));
597 }
598 BM_iter_as_array(bm, BM_VERTS_OF_MESH, nullptr, (void **)bm->vtable, bm->totvert);
599 }
600 if (htype_needed & BM_EDGE) {
601 if (bm->etable && bm->totedge <= bm->etable_tot && bm->totedge * 2 >= bm->etable_tot) {
602 /* pass (re-use the array) */
603 }
604 else {
605 if (bm->etable) {
607 }
608 bm->etable = static_cast<BMEdge **>(
609 MEM_mallocN(sizeof(void **) * bm->totedge, "bm->etable"));
611 }
612 BM_iter_as_array(bm, BM_EDGES_OF_MESH, nullptr, (void **)bm->etable, bm->totedge);
613 }
614 if (htype_needed & BM_FACE) {
615 if (bm->ftable && bm->totface <= bm->ftable_tot && bm->totface * 2 >= bm->ftable_tot) {
616 /* pass (re-use the array) */
617 }
618 else {
619 if (bm->ftable) {
621 }
622 bm->ftable = static_cast<BMFace **>(
623 MEM_mallocN(sizeof(void **) * bm->totface, "bm->ftable"));
625 }
626 BM_iter_as_array(bm, BM_FACES_OF_MESH, nullptr, (void **)bm->ftable, bm->totface);
627 }
628
629finally:
630 /* Only clear dirty flags when all the pointers and data are actually valid.
631 * This prevents possible threading issues when dirty flag check failed but
632 * data wasn't ready still.
633 */
634 bm->elem_table_dirty &= ~htype_needed;
635}
636
637void BM_mesh_elem_table_init(BMesh *bm, const char htype)
638{
639 BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
640
641 /* force recalc */
644}
645
646void BM_mesh_elem_table_free(BMesh *bm, const char htype)
647{
648 if (htype & BM_VERT) {
650 }
651
652 if (htype & BM_EDGE) {
654 }
655
656 if (htype & BM_FACE) {
658 }
659}
660
662{
663 return static_cast<BMVert *>(BLI_mempool_findelem(bm->vpool, index));
664}
665
667{
668 return static_cast<BMEdge *>(BLI_mempool_findelem(bm->epool, index));
669}
670
672{
673 return static_cast<BMFace *>(BLI_mempool_findelem(bm->fpool, index));
674}
675
677{
678 BMIter iter;
679 BMFace *f;
680 int i = index;
681 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
682 if (i < f->len) {
683 BMLoop *l_first, *l_iter;
684 l_iter = l_first = BM_FACE_FIRST_LOOP(f);
685 do {
686 if (i == 0) {
687 return l_iter;
688 }
689 i -= 1;
690 } while ((l_iter = l_iter->next) != l_first);
691 }
692 i -= f->len;
693 }
694 return nullptr;
695}
696
698{
699 if ((bm->elem_table_dirty & BM_VERT) == 0) {
700 return (index < bm->totvert) ? bm->vtable[index] : nullptr;
701 }
702 return BM_vert_at_index_find(bm, index);
703}
704
706{
707 if ((bm->elem_table_dirty & BM_EDGE) == 0) {
708 return (index < bm->totedge) ? bm->etable[index] : nullptr;
709 }
710 return BM_edge_at_index_find(bm, index);
711}
712
714{
715 if ((bm->elem_table_dirty & BM_FACE) == 0) {
716 return (index < bm->totface) ? bm->ftable[index] : nullptr;
717 }
718 return BM_face_at_index_find(bm, index);
719}
720
721int BM_mesh_elem_count(BMesh *bm, const char htype)
722{
723 BLI_assert((htype & ~BM_ALL_NOLOOP) == 0);
724
725 switch (htype) {
726 case BM_VERT:
727 return bm->totvert;
728 case BM_EDGE:
729 return bm->totedge;
730 case BM_FACE:
731 return bm->totface;
732 default: {
733 BLI_assert(0);
734 return 0;
735 }
736 }
737}
738
739void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const uint *face_idx)
740{
741 /* Mapping old to new pointers. */
742 GHash *vptr_map = nullptr, *eptr_map = nullptr, *fptr_map = nullptr;
743 BMIter iter, iterl;
744 BMVert *ve;
745 BMEdge *ed;
746 BMFace *fa;
747 BMLoop *lo;
748
749 if (!(vert_idx || edge_idx || face_idx)) {
750 return;
751 }
752
754 bm, (vert_idx ? BM_VERT : 0) | (edge_idx ? BM_EDGE : 0) | (face_idx ? BM_FACE : 0));
755
756 /* Remap Verts */
757 if (vert_idx) {
758 BMVert **verts_pool, *verts_copy, **vep;
759 int i, totvert = bm->totvert;
760 const uint *new_idx;
761 /* Special case: Python uses custom data layers to hold PyObject references.
762 * These have to be kept in place, else the PyObjects we point to, won't point back to us. */
763 const int cd_vert_pyptr = CustomData_get_offset(&bm->vdata, CD_BM_ELEM_PYPTR);
764
765 /* Init the old-to-new vert pointers mapping */
766 vptr_map = BLI_ghash_ptr_new_ex("BM_mesh_remap vert pointers mapping", bm->totvert);
767
768 /* Make a copy of all vertices. */
769 verts_pool = bm->vtable;
770 verts_copy = static_cast<BMVert *>(
771 MEM_mallocN(sizeof(BMVert) * totvert, "BM_mesh_remap verts copy"));
772 void **pyptrs = (cd_vert_pyptr != -1) ?
773 static_cast<void **>(MEM_mallocN(sizeof(void *) * totvert, __func__)) :
774 nullptr;
775 for (i = totvert, ve = verts_copy + totvert - 1, vep = verts_pool + totvert - 1; i--;
776 ve--, vep--)
777 {
778 *ve = **vep;
779 // printf("*vep: %p, verts_pool[%d]: %p\n", *vep, i, verts_pool[i]);
780 if (cd_vert_pyptr != -1) {
781 void **pyptr = static_cast<void **>(BM_ELEM_CD_GET_VOID_P(((BMElem *)ve), cd_vert_pyptr));
782 pyptrs[i] = *pyptr;
783 }
784 }
785
786 /* Copy back verts to their new place, and update old2new pointers mapping. */
787 new_idx = vert_idx + totvert - 1;
788 ve = verts_copy + totvert - 1;
789 vep = verts_pool + totvert - 1; /* old, org pointer */
790 for (i = totvert; i--; new_idx--, ve--, vep--) {
791 BMVert *new_vep = verts_pool[*new_idx];
792 *new_vep = *ve;
793#if 0
794 printf(
795 "mapping vert from %d to %d (%p/%p to %p)\n", i, *new_idx, *vep, verts_pool[i], new_vep);
796#endif
797 BLI_ghash_insert(vptr_map, *vep, new_vep);
798 if (cd_vert_pyptr != -1) {
799 void **pyptr = static_cast<void **>(
800 BM_ELEM_CD_GET_VOID_P(((BMElem *)new_vep), cd_vert_pyptr));
801 *pyptr = pyptrs[*new_idx];
802 }
803 }
806
807 MEM_freeN(verts_copy);
808 if (pyptrs) {
809 MEM_freeN(pyptrs);
810 }
811 }
812
813 /* Remap Edges */
814 if (edge_idx) {
815 BMEdge **edges_pool, *edges_copy, **edp;
816 int i, totedge = bm->totedge;
817 const uint *new_idx;
818 /* Special case: Python uses custom data layers to hold PyObject references.
819 * These have to be kept in place, else the PyObjects we point to, won't point back to us. */
820 const int cd_edge_pyptr = CustomData_get_offset(&bm->edata, CD_BM_ELEM_PYPTR);
821
822 /* Init the old-to-new vert pointers mapping */
823 eptr_map = BLI_ghash_ptr_new_ex("BM_mesh_remap edge pointers mapping", bm->totedge);
824
825 /* Make a copy of all vertices. */
826 edges_pool = bm->etable;
827 edges_copy = static_cast<BMEdge *>(
828 MEM_mallocN(sizeof(BMEdge) * totedge, "BM_mesh_remap edges copy"));
829 void **pyptrs = (cd_edge_pyptr != -1) ?
830 static_cast<void **>(MEM_mallocN(sizeof(void *) * totedge, __func__)) :
831 nullptr;
832 for (i = totedge, ed = edges_copy + totedge - 1, edp = edges_pool + totedge - 1; i--;
833 ed--, edp--)
834 {
835 *ed = **edp;
836 if (cd_edge_pyptr != -1) {
837 void **pyptr = static_cast<void **>(BM_ELEM_CD_GET_VOID_P(((BMElem *)ed), cd_edge_pyptr));
838 pyptrs[i] = *pyptr;
839 }
840 }
841
842 /* Copy back verts to their new place, and update old2new pointers mapping. */
843 new_idx = edge_idx + totedge - 1;
844 ed = edges_copy + totedge - 1;
845 edp = edges_pool + totedge - 1; /* old, org pointer */
846 for (i = totedge; i--; new_idx--, ed--, edp--) {
847 BMEdge *new_edp = edges_pool[*new_idx];
848 *new_edp = *ed;
849 BLI_ghash_insert(eptr_map, *edp, new_edp);
850#if 0
851 printf(
852 "mapping edge from %d to %d (%p/%p to %p)\n", i, *new_idx, *edp, edges_pool[i], new_edp);
853#endif
854 if (cd_edge_pyptr != -1) {
855 void **pyptr = static_cast<void **>(
856 BM_ELEM_CD_GET_VOID_P(((BMElem *)new_edp), cd_edge_pyptr));
857 *pyptr = pyptrs[*new_idx];
858 }
859 }
862
863 MEM_freeN(edges_copy);
864 if (pyptrs) {
865 MEM_freeN(pyptrs);
866 }
867 }
868
869 /* Remap Faces */
870 if (face_idx) {
871 BMFace **faces_pool, *faces_copy, **fap;
872 int i, totface = bm->totface;
873 const uint *new_idx;
874 /* Special case: Python uses custom data layers to hold PyObject references.
875 * These have to be kept in place, else the PyObjects we point to, won't point back to us. */
876 const int cd_poly_pyptr = CustomData_get_offset(&bm->pdata, CD_BM_ELEM_PYPTR);
877
878 /* Init the old-to-new vert pointers mapping */
879 fptr_map = BLI_ghash_ptr_new_ex("BM_mesh_remap face pointers mapping", bm->totface);
880
881 /* Make a copy of all vertices. */
882 faces_pool = bm->ftable;
883 faces_copy = static_cast<BMFace *>(
884 MEM_mallocN(sizeof(BMFace) * totface, "BM_mesh_remap faces copy"));
885 void **pyptrs = (cd_poly_pyptr != -1) ?
886 static_cast<void **>(MEM_mallocN(sizeof(void *) * totface, __func__)) :
887 nullptr;
888 for (i = totface, fa = faces_copy + totface - 1, fap = faces_pool + totface - 1; i--;
889 fa--, fap--)
890 {
891 *fa = **fap;
892 if (cd_poly_pyptr != -1) {
893 void **pyptr = static_cast<void **>(BM_ELEM_CD_GET_VOID_P(((BMElem *)fa), cd_poly_pyptr));
894 pyptrs[i] = *pyptr;
895 }
896 }
897
898 /* Copy back verts to their new place, and update old2new pointers mapping. */
899 new_idx = face_idx + totface - 1;
900 fa = faces_copy + totface - 1;
901 fap = faces_pool + totface - 1; /* old, org pointer */
902 for (i = totface; i--; new_idx--, fa--, fap--) {
903 BMFace *new_fap = faces_pool[*new_idx];
904 *new_fap = *fa;
905 BLI_ghash_insert(fptr_map, *fap, new_fap);
906 if (cd_poly_pyptr != -1) {
907 void **pyptr = static_cast<void **>(
908 BM_ELEM_CD_GET_VOID_P(((BMElem *)new_fap), cd_poly_pyptr));
909 *pyptr = pyptrs[*new_idx];
910 }
911 }
912
915
916 MEM_freeN(faces_copy);
917 if (pyptrs) {
918 MEM_freeN(pyptrs);
919 }
920 }
921
922 /* And now, fix all vertices/edges/faces/loops pointers! */
923 /* Verts' pointers, only edge pointers... */
924 if (eptr_map) {
925 BM_ITER_MESH (ve, &iter, bm, BM_VERTS_OF_MESH) {
926 // printf("Vert e: %p -> %p\n", ve->e, BLI_ghash_lookup(eptr_map, ve->e));
927 if (ve->e) {
928 ve->e = static_cast<BMEdge *>(BLI_ghash_lookup(eptr_map, ve->e));
929 BLI_assert(ve->e);
930 }
931 }
932 }
933
934 /* Edges' pointers, only vert pointers (as we don't mess with loops!),
935 * and - ack! - edge pointers,
936 * as we have to handle disk-links. */
937 if (vptr_map || eptr_map) {
938 BM_ITER_MESH (ed, &iter, bm, BM_EDGES_OF_MESH) {
939 if (vptr_map) {
940#if 0
941 printf("Edge v1: %p -> %p\n", ed->v1, BLI_ghash_lookup(vptr_map, ed->v1));
942 printf("Edge v2: %p -> %p\n", ed->v2, BLI_ghash_lookup(vptr_map, ed->v2));
943#endif
944 ed->v1 = static_cast<BMVert *>(BLI_ghash_lookup(vptr_map, ed->v1));
945 ed->v2 = static_cast<BMVert *>(BLI_ghash_lookup(vptr_map, ed->v2));
946 BLI_assert(ed->v1);
947 BLI_assert(ed->v2);
948 }
949 if (eptr_map) {
950#if 0
951 printf("Edge v1_disk_link prev: %p -> %p\n",
952 ed->v1_disk_link.prev,
953 BLI_ghash_lookup(eptr_map, ed->v1_disk_link.prev));
954 printf("Edge v1_disk_link next: %p -> %p\n",
955 ed->v1_disk_link.next,
956 BLI_ghash_lookup(eptr_map, ed->v1_disk_link.next));
957 printf("Edge v2_disk_link prev: %p -> %p\n",
958 ed->v2_disk_link.prev,
959 BLI_ghash_lookup(eptr_map, ed->v2_disk_link.prev));
960 printf("Edge v2_disk_link next: %p -> %p\n",
961 ed->v2_disk_link.next,
962 BLI_ghash_lookup(eptr_map, ed->v2_disk_link.next));
963#endif
964 ed->v1_disk_link.prev = static_cast<BMEdge *>(
965 BLI_ghash_lookup(eptr_map, ed->v1_disk_link.prev));
966 ed->v1_disk_link.next = static_cast<BMEdge *>(
967 BLI_ghash_lookup(eptr_map, ed->v1_disk_link.next));
968 ed->v2_disk_link.prev = static_cast<BMEdge *>(
969 BLI_ghash_lookup(eptr_map, ed->v2_disk_link.prev));
970 ed->v2_disk_link.next = static_cast<BMEdge *>(
971 BLI_ghash_lookup(eptr_map, ed->v2_disk_link.next));
976 }
977 }
978 }
979
980 /* Faces' pointers (loops, in fact), always needed... */
981 BM_ITER_MESH (fa, &iter, bm, BM_FACES_OF_MESH) {
982 BM_ITER_ELEM (lo, &iterl, fa, BM_LOOPS_OF_FACE) {
983 if (vptr_map) {
984 // printf("Loop v: %p -> %p\n", lo->v, BLI_ghash_lookup(vptr_map, lo->v));
985 lo->v = static_cast<BMVert *>(BLI_ghash_lookup(vptr_map, lo->v));
986 BLI_assert(lo->v);
987 }
988 if (eptr_map) {
989 // printf("Loop e: %p -> %p\n", lo->e, BLI_ghash_lookup(eptr_map, lo->e));
990 lo->e = static_cast<BMEdge *>(BLI_ghash_lookup(eptr_map, lo->e));
991 BLI_assert(lo->e);
992 }
993 if (fptr_map) {
994 // printf("Loop f: %p -> %p\n", lo->f, BLI_ghash_lookup(fptr_map, lo->f));
995 lo->f = static_cast<BMFace *>(BLI_ghash_lookup(fptr_map, lo->f));
996 BLI_assert(lo->f);
997 }
998 }
999 }
1000
1001 /* Selection history */
1002 {
1004 switch (ese->htype) {
1005 case BM_VERT:
1006 if (vptr_map) {
1007 ese->ele = static_cast<BMElem *>(BLI_ghash_lookup(vptr_map, ese->ele));
1008 BLI_assert(ese->ele);
1009 }
1010 break;
1011 case BM_EDGE:
1012 if (eptr_map) {
1013 ese->ele = static_cast<BMElem *>(BLI_ghash_lookup(eptr_map, ese->ele));
1014 BLI_assert(ese->ele);
1015 }
1016 break;
1017 case BM_FACE:
1018 if (fptr_map) {
1019 ese->ele = static_cast<BMElem *>(BLI_ghash_lookup(fptr_map, ese->ele));
1020 BLI_assert(ese->ele);
1021 }
1022 break;
1023 }
1024 }
1025 }
1026
1027 if (fptr_map) {
1028 if (bm->act_face) {
1029 bm->act_face = static_cast<BMFace *>(BLI_ghash_lookup(fptr_map, bm->act_face));
1031 }
1032 }
1033
1034 if (vptr_map) {
1035 BLI_ghash_free(vptr_map, nullptr, nullptr);
1036 }
1037 if (eptr_map) {
1038 BLI_ghash_free(eptr_map, nullptr, nullptr);
1039 }
1040 if (fptr_map) {
1041 BLI_ghash_free(fptr_map, nullptr, nullptr);
1042 }
1043}
1044
1047 BLI_mempool *vpool_dst,
1048 BLI_mempool *epool_dst,
1049 BLI_mempool *lpool_dst,
1050 BLI_mempool *fpool_dst)
1051{
1052 const char remap = (vpool_dst ? BM_VERT : 0) | (epool_dst ? BM_EDGE : 0) |
1053 (lpool_dst ? BM_LOOP : 0) | (fpool_dst ? BM_FACE : 0);
1054
1055 BMVert **vtable_dst = (remap & BM_VERT) ? static_cast<BMVert **>(MEM_mallocN(
1056 sizeof(BMVert *) * bm->totvert, __func__)) :
1057 nullptr;
1058 BMEdge **etable_dst = (remap & BM_EDGE) ? static_cast<BMEdge **>(MEM_mallocN(
1059 sizeof(BMEdge *) * bm->totedge, __func__)) :
1060 nullptr;
1061 BMLoop **ltable_dst = (remap & BM_LOOP) ? static_cast<BMLoop **>(MEM_mallocN(
1062 sizeof(BMLoop *) * bm->totloop, __func__)) :
1063 nullptr;
1064 BMFace **ftable_dst = (remap & BM_FACE) ? static_cast<BMFace **>(MEM_mallocN(
1065 sizeof(BMFace *) * bm->totface, __func__)) :
1066 nullptr;
1067
1068 const bool use_toolflags = params->use_toolflags;
1069
1070 if (remap & BM_VERT) {
1071 BMIter iter;
1072 int index;
1073 BMVert *v_src;
1074 BM_ITER_MESH_INDEX (v_src, &iter, bm, BM_VERTS_OF_MESH, index) {
1075 BMVert *v_dst = static_cast<BMVert *>(BLI_mempool_alloc(vpool_dst));
1076 memcpy(v_dst, v_src, sizeof(BMVert));
1077 if (use_toolflags) {
1078 ((BMVert_OFlag *)v_dst)->oflags = bm->vtoolflagpool ?
1079 static_cast<BMFlagLayer *>(
1081 nullptr;
1082 }
1083
1084 vtable_dst[index] = v_dst;
1085 BM_elem_index_set(v_src, index); /* set_ok */
1086 }
1087 }
1088
1089 if (remap & BM_EDGE) {
1090 BMIter iter;
1091 int index;
1092 BMEdge *e_src;
1093 BM_ITER_MESH_INDEX (e_src, &iter, bm, BM_EDGES_OF_MESH, index) {
1094 BMEdge *e_dst = static_cast<BMEdge *>(BLI_mempool_alloc(epool_dst));
1095 memcpy(e_dst, e_src, sizeof(BMEdge));
1096 if (use_toolflags) {
1097 ((BMEdge_OFlag *)e_dst)->oflags = bm->etoolflagpool ?
1098 static_cast<BMFlagLayer *>(
1100 nullptr;
1101 }
1102
1103 etable_dst[index] = e_dst;
1104 BM_elem_index_set(e_src, index); /* set_ok */
1105 }
1106 }
1107
1108 if (remap & (BM_LOOP | BM_FACE)) {
1109 BMIter iter;
1110 int index, index_loop = 0;
1111 BMFace *f_src;
1112 BM_ITER_MESH_INDEX (f_src, &iter, bm, BM_FACES_OF_MESH, index) {
1113
1114 if (remap & BM_FACE) {
1115 BMFace *f_dst = static_cast<BMFace *>(BLI_mempool_alloc(fpool_dst));
1116 memcpy(f_dst, f_src, sizeof(BMFace));
1117 if (use_toolflags) {
1118 ((BMFace_OFlag *)f_dst)->oflags = bm->ftoolflagpool ?
1119 static_cast<BMFlagLayer *>(
1121 nullptr;
1122 }
1123
1124 ftable_dst[index] = f_dst;
1125 BM_elem_index_set(f_src, index); /* set_ok */
1126 }
1127
1128 /* handle loops */
1129 if (remap & BM_LOOP) {
1130 BMLoop *l_iter_src, *l_first_src;
1131 l_iter_src = l_first_src = BM_FACE_FIRST_LOOP((BMFace *)f_src);
1132 do {
1133 BMLoop *l_dst = static_cast<BMLoop *>(BLI_mempool_alloc(lpool_dst));
1134 memcpy(l_dst, l_iter_src, sizeof(BMLoop));
1135 ltable_dst[index_loop] = l_dst;
1136 BM_elem_index_set(l_iter_src, index_loop++); /* set_ok */
1137 } while ((l_iter_src = l_iter_src->next) != l_first_src);
1138 }
1139 }
1140 }
1141
1142#define MAP_VERT(ele) vtable_dst[BM_elem_index_get(ele)]
1143#define MAP_EDGE(ele) etable_dst[BM_elem_index_get(ele)]
1144#define MAP_LOOP(ele) ltable_dst[BM_elem_index_get(ele)]
1145#define MAP_FACE(ele) ftable_dst[BM_elem_index_get(ele)]
1146
1147#define REMAP_VERT(ele) \
1148 { \
1149 if (remap & BM_VERT) { \
1150 ele = MAP_VERT(ele); \
1151 } \
1152 } \
1153 ((void)0)
1154#define REMAP_EDGE(ele) \
1155 { \
1156 if (remap & BM_EDGE) { \
1157 ele = MAP_EDGE(ele); \
1158 } \
1159 } \
1160 ((void)0)
1161#define REMAP_LOOP(ele) \
1162 { \
1163 if (remap & BM_LOOP) { \
1164 ele = MAP_LOOP(ele); \
1165 } \
1166 } \
1167 ((void)0)
1168#define REMAP_FACE(ele) \
1169 { \
1170 if (remap & BM_FACE) { \
1171 ele = MAP_FACE(ele); \
1172 } \
1173 } \
1174 ((void)0)
1175
1176 /* verts */
1177 {
1178 for (int i = 0; i < bm->totvert; i++) {
1179 BMVert *v = vtable_dst[i];
1180 if (v->e) {
1181 REMAP_EDGE(v->e);
1182 }
1183 }
1184 }
1185
1186 /* edges */
1187 {
1188 for (int i = 0; i < bm->totedge; i++) {
1189 BMEdge *e = etable_dst[i];
1190 REMAP_VERT(e->v1);
1191 REMAP_VERT(e->v2);
1192 REMAP_EDGE(e->v1_disk_link.next);
1193 REMAP_EDGE(e->v1_disk_link.prev);
1194 REMAP_EDGE(e->v2_disk_link.next);
1195 REMAP_EDGE(e->v2_disk_link.prev);
1196 if (e->l) {
1197 REMAP_LOOP(e->l);
1198 }
1199 }
1200 }
1201
1202 /* faces */
1203 {
1204 for (int i = 0; i < bm->totface; i++) {
1205 BMFace *f = ftable_dst[i];
1206 REMAP_LOOP(f->l_first);
1207
1208 {
1209 BMLoop *l_iter, *l_first;
1210 l_iter = l_first = BM_FACE_FIRST_LOOP((BMFace *)f);
1211 do {
1212 REMAP_VERT(l_iter->v);
1213 REMAP_EDGE(l_iter->e);
1214 REMAP_FACE(l_iter->f);
1215
1216 REMAP_LOOP(l_iter->radial_next);
1217 REMAP_LOOP(l_iter->radial_prev);
1218 REMAP_LOOP(l_iter->next);
1219 REMAP_LOOP(l_iter->prev);
1220 } while ((l_iter = l_iter->next) != l_first);
1221 }
1222 }
1223 }
1224
1226 switch (ese->htype) {
1227 case BM_VERT:
1228 if (remap & BM_VERT) {
1229 ese->ele = (BMElem *)MAP_VERT(ese->ele);
1230 }
1231 break;
1232 case BM_EDGE:
1233 if (remap & BM_EDGE) {
1234 ese->ele = (BMElem *)MAP_EDGE(ese->ele);
1235 }
1236 break;
1237 case BM_FACE:
1238 if (remap & BM_FACE) {
1239 ese->ele = (BMElem *)MAP_FACE(ese->ele);
1240 }
1241 break;
1242 }
1243 }
1244
1245 if (bm->act_face) {
1247 }
1248
1249#undef MAP_VERT
1250#undef MAP_EDGE
1251#undef MAP_LOOP
1252#undef MAP_EDGE
1253
1254#undef REMAP_VERT
1255#undef REMAP_EDGE
1256#undef REMAP_LOOP
1257#undef REMAP_EDGE
1258
1259 /* Cleanup, re-use local tables if the current mesh had tables allocated.
1260 * could use irrespective but it may use more memory than the caller wants
1261 * (and not be needed). */
1262 if (remap & BM_VERT) {
1263 if (bm->vtable) {
1264 std::swap(vtable_dst, bm->vtable);
1265 bm->vtable_tot = bm->totvert;
1266 bm->elem_table_dirty &= ~BM_VERT;
1267 }
1268 MEM_freeN(vtable_dst);
1270 bm->vpool = vpool_dst;
1271 }
1272
1273 if (remap & BM_EDGE) {
1274 if (bm->etable) {
1275 std::swap(etable_dst, bm->etable);
1276 bm->etable_tot = bm->totedge;
1277 bm->elem_table_dirty &= ~BM_EDGE;
1278 }
1279 MEM_freeN(etable_dst);
1281 bm->epool = epool_dst;
1282 }
1283
1284 if (remap & BM_LOOP) {
1285 /* no loop table */
1286 MEM_freeN(ltable_dst);
1288 bm->lpool = lpool_dst;
1289 }
1290
1291 if (remap & BM_FACE) {
1292 if (bm->ftable) {
1293 std::swap(ftable_dst, bm->ftable);
1294 bm->ftable_tot = bm->totface;
1295 bm->elem_table_dirty &= ~BM_FACE;
1296 }
1297 MEM_freeN(ftable_dst);
1299 bm->fpool = fpool_dst;
1300 }
1301}
1302
1303void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags)
1304{
1305 if (bm->use_toolflags == use_toolflags) {
1306 return;
1307 }
1308
1309 const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_BM(bm);
1310
1311 BLI_mempool *vpool_dst = nullptr;
1312 BLI_mempool *epool_dst = nullptr;
1313 BLI_mempool *fpool_dst = nullptr;
1314
1315 bm_mempool_init_ex(&allocsize, use_toolflags, &vpool_dst, &epool_dst, nullptr, &fpool_dst);
1316
1317 if (use_toolflags == false) {
1321
1322 bm->vtoolflagpool = nullptr;
1323 bm->etoolflagpool = nullptr;
1324 bm->ftoolflagpool = nullptr;
1325 }
1327 params.use_toolflags = use_toolflags;
1328
1329 BM_mesh_rebuild(bm, &params, vpool_dst, epool_dst, nullptr, fpool_dst);
1330
1331 bm->use_toolflags = use_toolflags;
1332}
1333
1334/* -------------------------------------------------------------------- */
1339{
1340 BMIter iter;
1341 BMVert *v;
1342 int i;
1343 BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
1344 positions[i] = v->co;
1345 }
1346}
1347
1349{
1350 BMIter iter;
1351 BMVert *v;
1352 int i;
1353 BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
1354 normals[i] = v->no;
1355 }
1356}
1357
1359{
1360 Array<float3> positions(bm->totvert);
1361 BM_mesh_vert_coords_get(bm, positions);
1362 return positions;
1363}
1364
1365void BM_mesh_vert_coords_apply(BMesh *bm, const float (*vert_coords)[3])
1366{
1367 BMIter iter;
1368 BMVert *v;
1369 int i;
1370 BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
1371 copy_v3_v3(v->co, vert_coords[i]);
1372 }
1373}
1374
1376 const float (*vert_coords)[3],
1377 const float mat[4][4])
1378{
1379 BMIter iter;
1380 BMVert *v;
1381 int i;
1382 BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
1383 mul_v3_m4v3(v->co, mat, vert_coords[i]);
1384 }
1385}
1386
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_offset(const CustomData *data, eCustomDataType type)
void CustomData_bmesh_free_block(CustomData *data, void **block)
void CustomData_reset(CustomData *data)
void CustomData_free(CustomData *data, int totelem)
bool CustomData_bmesh_has_free(const CustomData *data)
bool CustomData_has_layer(const CustomData *data, eCustomDataType type)
void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr)
#define BLI_assert(a)
Definition BLI_assert.h:50
GHash * BLI_ghash_ptr_new_ex(const char *info, unsigned int nentries_reserve) 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
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
void * BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1)
BLI_mempool * BLI_mempool_create(unsigned int esize, unsigned int elem_num, unsigned int pchunk, unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
void * BLI_mempool_findelem(BLI_mempool *pool, unsigned int index) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
@ BLI_MEMPOOL_ALLOW_ITER
Definition BLI_mempool.h:95
@ BLI_MEMPOOL_NOP
Definition BLI_mempool.h:86
void * BLI_mempool_calloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1)
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1)
unsigned int uint
@ CD_BM_ELEM_PYPTR
These structs are the foundation for all linked lists in the library system.
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
struct BMFace BMFace
@ BM_LOOP
struct BMFace_OFlag BMFace_OFlag
#define BM_ALL_NOLOOP
struct BMEdge BMEdge
struct BMVert_OFlag BMVert_OFlag
struct BMLoop BMLoop
@ BM_SPACEARR_DIRTY_ALL
#define BM_FACE_FIRST_LOOP(p)
struct BMEdge_OFlag BMEdge_OFlag
struct BMVert BMVert
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
void BMO_error_clear(BMesh *bm)
#define BM_ELEM_INDEX_VALIDATE(_bm, _msg_a, _msg_b)
#define BM_elem_index_get(ele)
#define BM_elem_index_set(ele, index)
int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, const int len)
Iterator as Array.
#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_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_FACE
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_select_mode_flush(BMesh *bm)
void BM_mesh_elem_toolflags_clear(BMesh *bm)
void BM_mesh_vert_coords_apply_with_mat4(BMesh *bm, const float(*vert_coords)[3], const float mat[4][4])
const BMAllocTemplate bm_mesh_allocsize_default
Definition bmesh_mesh.cc:29
void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags)
void BM_mesh_data_free(BMesh *bm)
BMesh Free Mesh Data.
static void bm_mempool_init_ex(const BMAllocTemplate *allocsize, const bool use_toolflags, BLI_mempool **r_vpool, BLI_mempool **r_epool, BLI_mempool **r_lpool, BLI_mempool **r_fpool)
Definition bmesh_mesh.cc:32
void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const uint *face_idx)
void BM_mesh_vert_coords_apply(BMesh *bm, const float(*vert_coords)[3])
#define REMAP_VERT(ele)
void BM_mesh_clear(BMesh *bm)
BMesh Clear Mesh.
void bmesh_edit_begin(BMesh *, BMOpTypeFlag)
BMesh Begin Edit.
#define MAP_FACE(ele)
const BMAllocTemplate bm_mesh_chunksize_default
Definition bmesh_mesh.cc:30
#define REMAP_LOOP(ele)
static void bm_mempool_init(BMesh *bm, const BMAllocTemplate *allocsize, const bool use_toolflags)
Definition bmesh_mesh.cc:72
void BM_mesh_elem_toolflags_ensure(BMesh *bm)
Definition bmesh_mesh.cc:81
void BM_mesh_rebuild(BMesh *bm, const BMeshCreateParams *params, BLI_mempool *vpool_dst, BLI_mempool *epool_dst, BLI_mempool *lpool_dst, BLI_mempool *fpool_dst)
void BM_mesh_free(BMesh *bm)
BMesh Free Mesh.
BMLoop * BM_loop_at_index_find(BMesh *bm, const int index)
#define REMAP_EDGE(ele)
void BM_mesh_vert_coords_get(BMesh *bm, MutableSpan< float3 > positions)
Array< float3 > BM_mesh_vert_coords_alloc(BMesh *bm)
BMVert * BM_vert_at_index_find_or_table(BMesh *bm, const int index)
void BM_mesh_elem_table_free(BMesh *bm, const char htype)
#define MAP_EDGE(ele)
void BM_mesh_vert_normals_get(BMesh *bm, MutableSpan< float3 > normals)
int BM_mesh_elem_count(BMesh *bm, const char htype)
BMEdge * BM_edge_at_index_find(BMesh *bm, const int index)
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
void BM_mesh_elem_table_init(BMesh *bm, const char htype)
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
void BM_mesh_elem_index_validate(BMesh *bm, const char *location, const char *func, const char *msg_a, const char *msg_b)
BMEdge * BM_edge_at_index_find_or_table(BMesh *bm, const int index)
#define MAP_VERT(ele)
void bmesh_edit_end(BMesh *bm, BMOpTypeFlag type_flag)
BMesh End Edit.
bool BM_mesh_elem_table_check(BMesh *bm)
BMVert * BM_vert_at_index_find(BMesh *bm, const int index)
BMFace * BM_face_at_index_find(BMesh *bm, const int index)
#define REMAP_FACE(ele)
BMesh * BM_mesh_create(const BMAllocTemplate *allocsize, const BMeshCreateParams *params)
BMesh Make Mesh.
BMFace * BM_face_at_index_find_or_table(BMesh *bm, const int index)
void BM_mesh_elem_index_ensure_ex(BMesh *bm, const char htype, int elem_offset[4])
#define BMALLOC_TEMPLATE_FROM_BM(bm)
void BM_mesh_normals_update(BMesh *bm)
#define BM_FACE
#define BM_EDGE
#define BM_VERT
@ BMO_OPTYPE_FLAG_INVALIDATE_CLNOR_ALL
@ BMO_OPTYPE_FLAG_SELECT_VALIDATE
@ BMO_OPTYPE_FLAG_UNTAN_MULTIRES
@ BMO_OPTYPE_FLAG_NORMALS_CALC
@ BMO_OPTYPE_FLAG_SELECT_FLUSH
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define printf
void bpy_bm_generic_invalidate(struct BPy_BMGeneric *)
int len
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
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
struct BMFlagLayer * oflags
BMVert * v1
BMDiskLink v2_disk_link
BMDiskLink v1_disk_link
BMVert * v2
struct BMFlagLayer * oflags
BMHeader head
BMLoop * l_first
void * data
BMHeader head
struct BMVert * v
struct BMEdge * e
struct BMLoop * radial_prev
struct BMLoop * radial_next
struct BMLoop * prev
struct BMFace * f
struct BMLoop * next
struct BMFlagLayer * oflags
float co[3]
struct BMEdge * e
float no[3]
BMHeader head
int totvert
BMEdge ** etable
struct BLI_mempool * epool
int totflags
struct MLoopNorSpaceArray * lnor_spacearr
char elem_index_dirty
CustomData vdata
int totedge
char elem_table_dirty
struct BLI_mempool * vtoolflagpool
ListBase selected
CustomData edata
uint use_toolflags
int totloop
int ftable_tot
void * py_handle
struct BLI_mempool * etoolflagpool
BMFace * act_face
BMVert ** vtable
struct BLI_mempool * ftoolflagpool
char spacearr_dirty
CustomData pdata
CustomData ldata
int vtable_tot
BMFace ** ftable
int totface
int toolflag_index
int etable_tot
struct BLI_mempool * fpool
struct BLI_mempool * vpool
struct BLI_mempool * lpool
struct BLI_mempool * pool
uint8_t flag
Definition wm_window.cc:138