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