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