Blender V4.5
bmesh_mesh_convert.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
73
74#include "DNA_key_types.h"
75#include "DNA_mesh_types.h"
76#include "DNA_meshdata_types.h"
77#include "DNA_modifier_types.h"
78#include "DNA_object_types.h"
79
80#include "MEM_guardedalloc.h"
81
82#include "BLI_alloca.h"
83#include "BLI_array.hh"
84#include "BLI_index_range.hh"
85#include "BLI_listbase.h"
86#include "BLI_math_vector.h"
87#include "BLI_span.hh"
88#include "BLI_string_ref.hh"
89#include "BLI_task.hh"
90#include "BLI_vector.hh"
91
92#include "BKE_attribute.hh"
93#include "BKE_customdata.hh"
94#include "BKE_mesh.hh"
95#include "BKE_mesh_runtime.hh"
96#include "BKE_multires.hh"
97
98#include "BKE_key.hh"
99#include "BKE_main.hh"
100
101#include "DEG_depsgraph_query.hh"
102
103#include "bmesh.hh"
104
105#include "CLG_log.h"
106
107static CLG_LogRef LOG = {"bmesh.mesh.convert"};
108
109using blender::Array;
110using blender::float3;
113using blender::Span;
115using blender::Vector;
117
119{
120 return ELEM(name,
121 "position",
122 ".edge_verts",
123 ".corner_vert",
124 ".corner_edge",
125 ".hide_vert",
126 ".hide_edge",
127 ".hide_poly",
128 "uv_seam",
129 ".select_vert",
130 ".select_edge",
131 ".select_poly",
132 "material_index",
133 "sharp_face",
134 "sharp_edge");
135}
136
138 Span<int> face_verts,
139 Span<int> face_edges,
140 Span<BMVert *> vtable,
141 Span<BMEdge *> etable)
142{
143 const int size = face_verts.size();
146
147 for (const int i : IndexRange(size)) {
148 verts[i] = vtable[face_verts[i]];
149 edges[i] = etable[face_edges[i]];
150 }
151
152 return BM_face_create(&bm, verts.data(), edges.data(), size, nullptr, BM_CREATE_SKIP_CD);
153}
154
164
169 CustomData &bm_data)
170{
172 std::array<int, CD_NUMTYPES> per_type_index;
173 per_type_index.fill(0);
174 for (const int i : IndexRange(bm_data.totlayer)) {
175 const CustomDataLayer &bm_layer = bm_data.layers[i];
176 const eCustomDataType type = eCustomDataType(bm_layer.type);
177 const int mesh_layer_index =
178 bm_layer.name[0] == '\0' ?
179 CustomData_get_layer_index_n(&mesh_data, type, per_type_index[type]) :
180 CustomData_get_named_layer_index(&mesh_data, type, bm_layer.name);
181
183 info.type = type;
184 info.bmesh_offset = bm_layer.offset;
185 info.mesh_data = (mesh_layer_index == -1) ? nullptr : mesh_data.layers[mesh_layer_index].data;
186 info.elem_size = CustomData_get_elem_size(&bm_layer);
187 infos.append(info);
188
189 per_type_index[type]++;
190 }
191 return infos;
192}
193
195 const Span<MeshToBMeshLayerInfo> copy_info,
196 const int mesh_index,
197 BMHeader &header)
198{
200 for (const MeshToBMeshLayerInfo &info : copy_info) {
201 if (info.mesh_data) {
203 POINTER_OFFSET(info.mesh_data, info.elem_size * mesh_index),
204 POINTER_OFFSET(header.data, info.bmesh_offset));
205 }
206 else {
207 CustomData_data_set_default_value(info.type, POINTER_OFFSET(header.data, info.bmesh_offset));
208 }
209 }
210}
211
213{
214 using namespace blender;
215 if (!mesh) {
216 /* Sanity check. */
217 return;
218 }
219 const bool is_new = !(bm->totvert || (bm->vdata.totlayer || bm->edata.totlayer ||
220 bm->pdata.totlayer || bm->ldata.totlayer));
221 KeyBlock *actkey;
222 float(*keyco)[3] = nullptr;
224 CustomData_MeshMasks_update(&mask, &params->cd_mask_extra);
225
227 mask.vmask);
229 mask.emask);
231 mask.pmask);
233 mask.lmask);
234
235 blender::Vector<std::string> temporary_layers_to_delete;
236
237 for (const int layer_index :
239 {
240 char buffer[MAX_CUSTOMDATA_LAYER_NAME];
241 {
243 CustomData_get_layer_name(&mesh_ldata, CD_PROP_FLOAT2, layer_index), buffer);
244 if (CustomData_get_named_layer_index(&mesh_ldata, CD_PROP_BOOL, name) < 0) {
246 &mesh_ldata, CD_PROP_BOOL, CD_SET_DEFAULT, mesh->corners_num, name);
247 temporary_layers_to_delete.append(std::string(name));
248 }
249 }
250 {
252 CustomData_get_layer_name(&mesh_ldata, CD_PROP_FLOAT2, layer_index), buffer);
253 if (CustomData_get_named_layer_index(&mesh_ldata, CD_PROP_BOOL, name) < 0) {
255 &mesh_ldata, CD_PROP_BOOL, CD_SET_DEFAULT, mesh->corners_num, name);
256 temporary_layers_to_delete.append(std::string(name));
257 }
258 }
259 {
261 CustomData_get_layer_name(&mesh_ldata, CD_PROP_FLOAT2, layer_index), buffer);
262 if (CustomData_get_named_layer_index(&mesh_ldata, CD_PROP_BOOL, name) < 0) {
264 &mesh_ldata, CD_PROP_BOOL, CD_SET_DEFAULT, mesh->corners_num, name);
265 temporary_layers_to_delete.append(std::string(name));
266 }
267 }
268 }
269
270 BLI_SCOPED_DEFER([&]() {
271 for (const std::string &name : temporary_layers_to_delete) {
272 CustomData_free_layer_named(&mesh_ldata, name);
273 }
274
275 MEM_SAFE_FREE(mesh_vdata.layers);
276 MEM_SAFE_FREE(mesh_edata.layers);
277 MEM_SAFE_FREE(mesh_pdata.layers);
278 MEM_SAFE_FREE(mesh_ldata.layers);
279 });
280
281 if (mesh->verts_num == 0) {
282 if (is_new) {
283 /* No verts? still copy custom-data layout. */
284 CustomData_init_layout_from(&mesh_vdata, &bm->vdata, mask.vmask, CD_CONSTRUCT, 0);
285 CustomData_init_layout_from(&mesh_edata, &bm->edata, mask.emask, CD_CONSTRUCT, 0);
286 CustomData_init_layout_from(&mesh_pdata, &bm->pdata, mask.pmask, CD_CONSTRUCT, 0);
287 CustomData_init_layout_from(&mesh_ldata, &bm->ldata, mask.lmask, CD_CONSTRUCT, 0);
288
293 }
294 return;
295 }
296
298 if (params->calc_vert_normal) {
299 vert_normals = mesh->vert_normals();
300 }
301
302 if (is_new) {
303 CustomData_init_layout_from(&mesh_vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, 0);
304 CustomData_init_layout_from(&mesh_edata, &bm->edata, mask.emask, CD_SET_DEFAULT, 0);
305 CustomData_init_layout_from(&mesh_pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, 0);
306 CustomData_init_layout_from(&mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, 0);
307 }
308 else {
310 &mesh_vdata, &bm->vdata, mask.vmask, CD_SET_DEFAULT, bm, BM_VERT);
312 &mesh_edata, &bm->edata, mask.emask, CD_SET_DEFAULT, bm, BM_EDGE);
314 &mesh_pdata, &bm->pdata, mask.pmask, CD_SET_DEFAULT, bm, BM_FACE);
316 &mesh_ldata, &bm->ldata, mask.lmask, CD_SET_DEFAULT, bm, BM_LOOP);
317 }
318
319 /* -------------------------------------------------------------------- */
320 /* Shape Key */
321 int tot_shape_keys = 0;
322 if (mesh->key != nullptr && DEG_is_original(mesh)) {
323 /* Evaluated meshes can be topologically inconsistent with their shape keys.
324 * Shape keys are also already integrated into the state of the evaluated
325 * mesh, so considering them here would kind of apply them twice. */
326 tot_shape_keys = BLI_listbase_count(&mesh->key->block);
327
328 /* Original meshes must never contain a shape-key custom-data layers.
329 *
330 * This may happen if and object's mesh data is accidentally
331 * set to the output from the modifier stack, causing it to be an "original" ID,
332 * even though the data isn't fully compatible (hence this assert).
333 *
334 * This results in:
335 * - The newly created #BMesh having twice the number of custom-data layers.
336 * - When converting the #BMesh back to a regular mesh,
337 * At least one of the extra shape-key blocks will be created in #Mesh.key
338 * depending on the value of #CustomDataLayer.uid.
339 *
340 * We could support mixing both kinds of data if there is a compelling use-case for it.
341 * At the moment it's simplest to assume all original meshes use the key-block and meshes
342 * that are evaluated (through the modifier stack for example) use custom-data layers.
343 */
345 }
346 if (is_new == false) {
347 tot_shape_keys = min_ii(tot_shape_keys, CustomData_number_of_layers(&bm->vdata, CD_SHAPEKEY));
348 }
349 const float(**shape_key_table)[3] = tot_shape_keys ? (const float(**)[3])BLI_array_alloca(
350 shape_key_table, tot_shape_keys) :
351 nullptr;
352
353 if ((params->active_shapekey != 0) && tot_shape_keys > 0) {
354 actkey = static_cast<KeyBlock *>(BLI_findlink(&mesh->key->block, params->active_shapekey - 1));
355 }
356 else {
357 actkey = nullptr;
358 }
359
360 if (is_new) {
361 if (tot_shape_keys || params->add_key_index) {
363 }
364 }
365
366 if (tot_shape_keys) {
367 if (is_new) {
368 /* Check if we need to generate unique ids for the shape-keys.
369 * This also exists in the file reading code, but is here for a sanity check. */
370 if (!mesh->key->uidgen) {
371 fprintf(stderr,
372 "%s had to generate shape key uid's in a situation we shouldn't need to! "
373 "(bmesh internal error)\n",
374 __func__);
375
376 mesh->key->uidgen = 1;
377 LISTBASE_FOREACH (KeyBlock *, block, &mesh->key->block) {
378 block->uid = mesh->key->uidgen++;
379 }
380 }
381 }
382
383 if (actkey && actkey->totelem == mesh->verts_num) {
384 keyco = params->use_shapekey ? static_cast<float(*)[3]>(actkey->data) : nullptr;
385 if (is_new) {
386 bm->shapenr = params->active_shapekey;
387 }
388 }
389
390 int i;
391 KeyBlock *block;
392 for (i = 0, block = static_cast<KeyBlock *>(mesh->key->block.first); i < tot_shape_keys;
393 block = block->next, i++)
394 {
395 if (is_new) {
397 int j = CustomData_get_layer_index_n(&bm->vdata, CD_SHAPEKEY, i);
398 bm->vdata.layers[j].uid = block->uid;
399 }
400 shape_key_table[i] = static_cast<const float(*)[3]>(block->data);
401 }
402 }
403
404 const Vector<MeshToBMeshLayerInfo> vert_info = mesh_to_bm_copy_info_calc(mesh_vdata, bm->vdata);
405 const Vector<MeshToBMeshLayerInfo> edge_info = mesh_to_bm_copy_info_calc(mesh_edata, bm->edata);
406 const Vector<MeshToBMeshLayerInfo> poly_info = mesh_to_bm_copy_info_calc(mesh_pdata, bm->pdata);
407 const Vector<MeshToBMeshLayerInfo> loop_info = mesh_to_bm_copy_info_calc(mesh_ldata, bm->ldata);
408 if (is_new) {
413 }
414
415 /* Only copy these values over if the source mesh is flagged to be using them.
416 * Even if `bm` has these layers, they may have been added from another mesh, when `!is_new`. */
417 const int cd_shape_key_offset = tot_shape_keys ? CustomData_get_offset(&bm->vdata, CD_SHAPEKEY) :
418 -1;
419 const int cd_shape_keyindex_offset = is_new && (tot_shape_keys || params->add_key_index) ?
421 -1;
422
423 const bke::AttributeAccessor attributes = mesh->attributes();
424 const VArraySpan select_vert = *attributes.lookup<bool>(".select_vert", AttrDomain::Point);
425 const VArraySpan select_edge = *attributes.lookup<bool>(".select_edge", AttrDomain::Edge);
426 const VArraySpan select_poly = *attributes.lookup<bool>(".select_poly", AttrDomain::Face);
427 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", AttrDomain::Point);
428 const VArraySpan hide_edge = *attributes.lookup<bool>(".hide_edge", AttrDomain::Edge);
429 const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", AttrDomain::Face);
430 const VArraySpan material_indices = *attributes.lookup<int>("material_index", AttrDomain::Face);
431 const VArraySpan sharp_faces = *attributes.lookup<bool>("sharp_face", AttrDomain::Face);
432 const VArraySpan sharp_edges = *attributes.lookup<bool>("sharp_edge", AttrDomain::Edge);
433 const VArraySpan uv_seams = *attributes.lookup<bool>("uv_seam", AttrDomain::Edge);
434
435 const Span<float3> positions = mesh->vert_positions();
436 Array<BMVert *> vtable(mesh->verts_num);
437 for (const int i : positions.index_range()) {
438 BMVert *v = vtable[i] = BM_vert_create(
439 bm, keyco ? keyco[i] : positions[i], nullptr, BM_CREATE_SKIP_CD);
440 BM_elem_index_set(v, i); /* set_ok */
441
442 if (!hide_vert.is_empty() && hide_vert[i]) {
444 }
445 if (!select_vert.is_empty() && select_vert[i]) {
446 BM_vert_select_set(bm, v, true);
447 }
448
449 if (!vert_normals.is_empty()) {
450 copy_v3_v3(v->no, vert_normals[i]);
451 }
452
453 mesh_attributes_copy_to_bmesh_block(bm->vdata, vert_info, i, v->head);
454
455 /* Set shape key original index. */
456 if (cd_shape_keyindex_offset != -1) {
457 BM_ELEM_CD_SET_INT(v, cd_shape_keyindex_offset, i);
458 }
459
460 /* Set shape-key data. */
461 if (tot_shape_keys) {
462 float(*co_dst)[3] = (float(*)[3])BM_ELEM_CD_GET_VOID_P(v, cd_shape_key_offset);
463 for (int j = 0; j < tot_shape_keys; j++, co_dst++) {
464 copy_v3_v3(*co_dst, shape_key_table[j][i]);
465 }
466 }
467 }
468 if (is_new) {
469 bm->elem_index_dirty &= ~BM_VERT; /* Added in order, clear dirty flag. */
470 }
471
472 const Span<blender::int2> edges = mesh->edges();
473 Array<BMEdge *> etable(mesh->edges_num);
474 for (const int i : edges.index_range()) {
475 BMEdge *e = etable[i] = BM_edge_create(
476 bm, vtable[edges[i][0]], vtable[edges[i][1]], nullptr, BM_CREATE_SKIP_CD);
477 BM_elem_index_set(e, i); /* set_ok */
478
479 e->head.hflag = 0;
480 if (!uv_seams.is_empty() && uv_seams[i]) {
482 }
483 if (!hide_edge.is_empty() && hide_edge[i]) {
485 }
486 if (!select_edge.is_empty() && select_edge[i]) {
487 BM_edge_select_set(bm, e, true);
488 }
489 if (!(!sharp_edges.is_empty() && sharp_edges[i])) {
491 }
492
493 mesh_attributes_copy_to_bmesh_block(bm->edata, edge_info, i, e->head);
494 }
495 if (is_new) {
496 bm->elem_index_dirty &= ~BM_EDGE; /* Added in order, clear dirty flag. */
497 }
498
499 const blender::OffsetIndices faces = mesh->faces();
500 const Span<int> corner_verts = mesh->corner_verts();
501 const Span<int> corner_edges = mesh->corner_edges();
502
503 /* Only needed for selection. */
504
505 Array<BMFace *> ftable;
506 if (mesh->mselect && mesh->totselect != 0) {
507 ftable.reinitialize(mesh->faces_num);
508 }
509
510 int totloops = 0;
511 for (const int i : faces.index_range()) {
512 const IndexRange face = faces[i];
514 *bm, corner_verts.slice(face), corner_edges.slice(face), vtable, etable);
515 if (!ftable.is_empty()) {
516 ftable[i] = f;
517 }
518
519 if (UNLIKELY(f == nullptr)) {
520 printf(
521 "%s: Warning! Bad face in mesh"
522 " \"%s\" at index %d!, skipping\n",
523 __func__,
524 mesh->id.name + 2,
525 i);
526 continue;
527 }
528
529 /* Don't use 'i' since we may have skipped the face. */
530 BM_elem_index_set(f, bm->totface - 1); /* set_ok */
531
532 /* Transfer flag. */
533 if (!(!sharp_faces.is_empty() && sharp_faces[i])) {
535 }
536 if (!hide_poly.is_empty() && hide_poly[i]) {
538 }
539 if (!select_poly.is_empty() && select_poly[i]) {
540 BM_face_select_set(bm, f, true);
541 }
542
543 f->mat_nr = material_indices.is_empty() ? 0 : material_indices[i];
544 if (i == mesh->act_face) {
545 bm->act_face = f;
546 }
547
548 int j = face.start();
549 BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
550 BMLoop *l_iter = l_first;
551 do {
552 /* Don't use 'j' since we may have skipped some faces, hence some loops. */
553 BM_elem_index_set(l_iter, totloops++); /* set_ok */
554
555 mesh_attributes_copy_to_bmesh_block(bm->ldata, loop_info, j, l_iter->head);
556 j++;
557 } while ((l_iter = l_iter->next) != l_first);
558
559 mesh_attributes_copy_to_bmesh_block(bm->pdata, poly_info, i, f->head);
560
561 if (params->calc_face_normal) {
563 }
564 }
565 if (is_new) {
566 bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); /* Added in order, clear dirty flag. */
567 }
568
569 /* -------------------------------------------------------------------- */
570 /* MSelect clears the array elements (to avoid adding multiple times).
571 *
572 * Take care to keep this last and not use (v/e/ftable) after this.
573 */
574
575 if (mesh->mselect && mesh->totselect != 0) {
576 for (const int i : IndexRange(mesh->totselect)) {
577 const MSelect &msel = mesh->mselect[i];
578
579 BMElem **ele_p;
580 switch (msel.type) {
581 case ME_VSEL:
582 ele_p = (BMElem **)&vtable[msel.index];
583 break;
584 case ME_ESEL:
585 ele_p = (BMElem **)&etable[msel.index];
586 break;
587 case ME_FSEL:
588 ele_p = (BMElem **)&ftable[msel.index];
589 break;
590 default:
591 continue;
592 }
593
594 if (*ele_p != nullptr) {
596 *ele_p = nullptr;
597 }
598 }
599 }
600 else {
602 }
603}
604
608static BMVert **bm_to_mesh_vertex_map(BMesh *bm, const int old_verts_num)
609{
610 const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX);
611 BMVert **vertMap = nullptr;
612 BMVert *eve;
613 int i = 0;
614 BMIter iter;
615
616 /* Caller needs to ensure this. */
617 BLI_assert(old_verts_num > 0);
618
619 vertMap = MEM_calloc_arrayN<BMVert *>(old_verts_num, "vertMap");
620 if (cd_shape_keyindex_offset != -1) {
621 BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
622 const int keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset);
623 if ((keyi != ORIGINDEX_NONE) && (keyi < old_verts_num) &&
624 /* Not fool-proof, but chances are if we have many verts with the same index,
625 * we will want to use the first one,
626 * since the second is more likely to be a duplicate. */
627 (vertMap[keyi] == nullptr))
628 {
629 vertMap[keyi] = eve;
630 }
631 }
632 }
633 else {
634 BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
635 if (i < old_verts_num) {
636 vertMap[i] = eve;
637 }
638 else {
639 break;
640 }
641 }
642 }
643
644 return vertMap;
645}
646
647/* -------------------------------------------------------------------- */
727
733{
734 int i;
735 int j = 0;
736
737 for (i = 0; i < bm->vdata.totlayer; i++) {
738 if (bm->vdata.layers[i].type == CD_SHAPEKEY) {
739 if (currkey->uid == bm->vdata.layers[i].uid) {
740 return j;
741 }
742 j++;
743 }
744 }
745 return -1;
746}
747
761 Key *key,
762 MutableSpan<float3> positions,
763 const bool active_shapekey_to_mvert)
764{
765 KeyBlock *actkey = static_cast<KeyBlock *>(BLI_findlink(&key->block, bm->shapenr - 1));
766
767 /* It's unlikely this ever remains false, check for correctness. */
768 bool actkey_has_layer = false;
769
770 /* Go through and find any shape-key custom-data layers
771 * that might not have corresponding KeyBlocks, and add them if necessary. */
772 for (int i = 0; i < bm->vdata.totlayer; i++) {
773 if (bm->vdata.layers[i].type != CD_SHAPEKEY) {
774 continue;
775 }
776
777 KeyBlock *currkey;
778 for (currkey = (KeyBlock *)key->block.first; currkey; currkey = currkey->next) {
779 if (currkey->uid == bm->vdata.layers[i].uid) {
780 break;
781 }
782 }
783
784 if (currkey) {
785 if (currkey == actkey) {
786 actkey_has_layer = true;
787 }
788 }
789 else {
790 currkey = BKE_keyblock_add(key, bm->vdata.layers[i].name);
791 currkey->uid = bm->vdata.layers[i].uid;
792 }
793 }
794
795 const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX);
796 BMIter iter;
797 BMVert *eve;
798 float(*ofs)[3] = nullptr;
799 std::optional<Array<bool>> dependent;
800
801 /* Editing the basis key updates others. */
802 if ((key->type == KEY_RELATIVE) &&
803 /* The shape-key coordinates used from entering edit-mode are used. */
804 (actkey_has_layer == true) &&
805 /* Original key-indices are only used to check the vertex existed when entering edit-mode. */
806 (cd_shape_keyindex_offset != -1) &&
807 /* Offsets are only needed if the current shape is a basis for others. */
808 (dependent = BKE_keyblock_get_dependent_keys(key, bm->shapenr - 1)).has_value())
809 {
810
811 BLI_assert(actkey != nullptr); /* Assured by `actkey_has_layer` check. */
812 const int actkey_uuid = bm_to_mesh_shape_layer_index_from_kb(bm, actkey);
813
814 /* Since `actkey_has_layer == true`, this must never fail. */
815 BLI_assert(actkey_uuid != -1);
816
817 const int cd_shape_offset = CustomData_get_n_offset(&bm->vdata, CD_SHAPEKEY, actkey_uuid);
818
819 ofs = static_cast<float(*)[3]>(MEM_mallocN(sizeof(float[3]) * bm->totvert, __func__));
820 int i;
821 BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
822 const int keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset);
823 /* Check the vertex existed when entering edit-mode (otherwise don't apply an offset). */
824 if (keyi != ORIGINDEX_NONE) {
825 float *co_orig = (float *)BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset);
826 /* Could use 'eve->co' or the destination position, they're the same at this point. */
827 sub_v3_v3v3(ofs[i], eve->co, co_orig);
828 }
829 else {
830 /* If there are new vertices in the mesh, we can't propagate the offset
831 * because it will only work for the existing vertices and not the new
832 * ones, creating a mess when doing e.g. subdivide + translate. */
833 MEM_freeN(ofs);
834 ofs = nullptr;
835 dependent.reset();
836 break;
837 }
838 }
839 }
840
841 /* Without this, the real mesh coordinates (uneditable) as soon as you create the Basis shape.
842 * while users might not notice since the shape-key is applied in the viewport,
843 * exporters for example may still use the underlying coordinates, see: #30771 & #96135.
844 *
845 * Needed when editing any shape that isn't the (`key->refkey`), the vertices in mesh positions
846 * currently have vertex coordinates set from the current-shape (initialized from #BMVert.co).
847 * In this case it's important to overwrite these coordinates with the basis-keys coordinates. */
848 bool update_vertex_coords_from_refkey = false;
849 int cd_shape_offset_refkey = -1;
850 if (active_shapekey_to_mvert == false) {
851 if ((actkey != key->refkey) && (cd_shape_keyindex_offset != -1)) {
852 const int refkey_uuid = bm_to_mesh_shape_layer_index_from_kb(bm, key->refkey);
853 if (refkey_uuid != -1) {
854 cd_shape_offset_refkey = CustomData_get_n_offset(&bm->vdata, CD_SHAPEKEY, refkey_uuid);
855 if (cd_shape_offset_refkey != -1) {
856 update_vertex_coords_from_refkey = true;
857 }
858 }
859 }
860 }
861
862 int currkey_i;
863 LISTBASE_FOREACH_INDEX (KeyBlock *, currkey, &key->block, currkey_i) {
864 int keyi;
865 float(*currkey_data)[3];
866
867 const int currkey_uuid = bm_to_mesh_shape_layer_index_from_kb(bm, currkey);
868 const int cd_shape_offset = (currkey_uuid == -1) ?
869 -1 :
870 CustomData_get_n_offset(&bm->vdata, CD_SHAPEKEY, currkey_uuid);
871
872 /* Common case, the layer data is available, use it where possible. */
873 if (cd_shape_offset != -1) {
874 const bool apply_offset = (ofs != nullptr) && (currkey != actkey) && (*dependent)[currkey_i];
875
876 if (currkey->data && (currkey->totelem == bm->totvert)) {
877 /* Use memory in-place. */
878 }
879 else {
880 currkey->data = MEM_reallocN(currkey->data, key->elemsize * bm->totvert);
881 currkey->totelem = bm->totvert;
882 }
883 currkey_data = (float(*)[3])currkey->data;
884
885 int i;
886 BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
887 float *co_orig = (float *)BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset);
888
889 if (currkey == actkey) {
890 copy_v3_v3(currkey_data[i], eve->co);
891
892 if (update_vertex_coords_from_refkey) {
893 BLI_assert(actkey != key->refkey);
894 keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset);
895 if (keyi != ORIGINDEX_NONE) {
896 float *co_refkey = (float *)BM_ELEM_CD_GET_VOID_P(eve, cd_shape_offset_refkey);
897 copy_v3_v3(positions[i], co_refkey);
898 }
899 }
900 }
901 else {
902 copy_v3_v3(currkey_data[i], co_orig);
903 }
904
905 /* Propagate edited basis offsets to other shapes. */
906 if (apply_offset) {
907 add_v3_v3(currkey_data[i], ofs[i]);
908 }
909
910 /* Apply back new coordinates shape-keys that have offset into #BMesh.
911 * Otherwise, in case we call again #BM_mesh_bm_to_me on same #BMesh,
912 * we'll apply diff from previous call to #BM_mesh_bm_to_me,
913 * to shape-key values from original creation of the #BMesh. See #50524. */
914 copy_v3_v3(co_orig, currkey_data[i]);
915 }
916 }
917 else {
918 /* No original layer data, use fallback information. */
919 if (currkey->data && (cd_shape_keyindex_offset != -1)) {
920 CLOG_WARN(&LOG,
921 "Found shape-key but no CD_SHAPEKEY layers to read from, "
922 "using existing shake-key data where possible");
923 }
924 else {
925 CLOG_WARN(&LOG,
926 "Found shape-key but no CD_SHAPEKEY layers to read from, "
927 "using basis shape-key data");
928 }
929
930 currkey_data = static_cast<float(*)[3]>(
931 MEM_mallocN(key->elemsize * bm->totvert, "currkey->data"));
932
933 int i;
934 BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
935
936 if ((currkey->data != nullptr) && (cd_shape_keyindex_offset != -1) &&
937 ((keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset)) != ORIGINDEX_NONE) &&
938 (keyi < currkey->totelem))
939 {
940 /* Reconstruct keys via vertices original key indices.
941 * WARNING(@ideasman42): `currkey->data` is known to be unreliable as the edit-mesh
942 * coordinates may be flushed back to the shape-key when exporting or rendering.
943 * This is a last resort! If this branch is running as part of regular usage
944 * it can be considered a bug. */
945 const float(*oldkey)[3] = static_cast<const float(*)[3]>(currkey->data);
946 copy_v3_v3(currkey_data[i], oldkey[keyi]);
947 }
948 else {
949 /* Fail! fill in with dummy value. */
950 copy_v3_v3(currkey_data[i], eve->co);
951 }
952 }
953
954 currkey->totelem = bm->totvert;
955 if (currkey->data) {
956 MEM_freeN(currkey->data);
957 }
958 currkey->data = currkey_data;
959 }
960 }
961
962 MEM_SAFE_FREE(ofs);
963}
964
966
968{
969 (void)bm; /* Unused in the release builds. */
971 BLI_assert(!CustomData_has_layer_named(&bm.ldata, CD_PROP_FLOAT3, ".corner_vert"));
972 BLI_assert(!CustomData_has_layer_named(&bm.ldata, CD_PROP_FLOAT3, ".corner_edge"));
973
974 /* The "hide" attributes are stored as flags on #BMesh. */
975 BLI_assert(!CustomData_has_layer_named(&bm.vdata, CD_PROP_BOOL, ".hide_vert"));
976 BLI_assert(!CustomData_has_layer_named(&bm.edata, CD_PROP_BOOL, ".hide_edge"));
977 BLI_assert(!CustomData_has_layer_named(&bm.pdata, CD_PROP_BOOL, ".hide_poly"));
978 /* The "selection" attributes are stored as flags on #BMesh. */
979 BLI_assert(!CustomData_has_layer_named(&bm.vdata, CD_PROP_BOOL, ".select_vert"));
980 BLI_assert(!CustomData_has_layer_named(&bm.edata, CD_PROP_BOOL, ".select_edge"));
981 BLI_assert(!CustomData_has_layer_named(&bm.pdata, CD_PROP_BOOL, ".select_poly"));
982}
983
985 Mesh &mesh,
986 BMesh &bm,
987 const int old_totvert)
988{
989 BMVert **vertMap = nullptr;
990 BMVert *eve;
991
992 LISTBASE_FOREACH (Object *, ob, &bmain.objects) {
993 if ((ob->parent) && (ob->parent->data == &mesh) && ELEM(ob->partype, PARVERT1, PARVERT3)) {
994
995 if (vertMap == nullptr) {
996 vertMap = bm_to_mesh_vertex_map(&bm, old_totvert);
997 }
998
999 if (ob->par1 < old_totvert) {
1000 eve = vertMap[ob->par1];
1001 if (eve) {
1002 ob->par1 = BM_elem_index_get(eve);
1003 }
1004 }
1005 if (ob->par2 < old_totvert) {
1006 eve = vertMap[ob->par2];
1007 if (eve) {
1008 ob->par2 = BM_elem_index_get(eve);
1009 }
1010 }
1011 if (ob->par3 < old_totvert) {
1012 eve = vertMap[ob->par3];
1013 if (eve) {
1014 ob->par3 = BM_elem_index_get(eve);
1015 }
1016 }
1017 }
1018 if (ob->data == &mesh) {
1019 LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
1020 if (md->type == eModifierType_Hook) {
1022
1023 if (vertMap == nullptr) {
1024 vertMap = bm_to_mesh_vertex_map(&bm, old_totvert);
1025 }
1026 int i, j;
1027 for (i = j = 0; i < hmd->indexar_num; i++) {
1028 if (hmd->indexar[i] < old_totvert) {
1029 eve = vertMap[hmd->indexar[i]];
1030
1031 if (eve) {
1032 hmd->indexar[j++] = BM_elem_index_get(eve);
1033 }
1034 }
1035 else {
1036 j++;
1037 }
1038 }
1039
1040 hmd->indexar_num = j;
1041 }
1042 }
1043 }
1044 }
1045
1046 if (vertMap) {
1047 MEM_freeN(vertMap);
1048 }
1049}
1050
1060
1065 CustomData &mesh_data)
1066{
1068 std::array<int, CD_NUMTYPES> per_type_index;
1069 per_type_index.fill(0);
1070 for (const int i : IndexRange(mesh_data.totlayer)) {
1071 const CustomDataLayer &mesh_layer = mesh_data.layers[i];
1072 const eCustomDataType type = eCustomDataType(mesh_layer.type);
1073 const int bm_layer_index =
1074 mesh_layer.name[0] == '\0' ?
1075 CustomData_get_layer_index_n(&bm_data, type, per_type_index[type]) :
1076 CustomData_get_named_layer_index(&bm_data, type, mesh_layer.name);
1077
1078 /* Skip layers that don't exist in `bm_data` or are explicitly set to not be
1079 * copied. The layers are either set separately or shouldn't exist on the mesh. */
1080 if (bm_layer_index == -1) {
1081 continue;
1082 }
1083 const CustomDataLayer &bm_layer = bm_data.layers[bm_layer_index];
1084 if (bm_layer.flag & CD_FLAG_NOCOPY) {
1085 continue;
1086 }
1087
1088 BMeshToMeshLayerInfo info{};
1089 info.type = type;
1090 info.bmesh_offset = bm_layer.offset;
1091 info.mesh_data = mesh_layer.data;
1092 info.elem_size = CustomData_get_elem_size(&mesh_layer);
1093 infos.append(info);
1094
1095 per_type_index[type]++;
1096 }
1097 return infos;
1098}
1099
1100namespace blender {
1101
1104 bool &need_select_vert,
1105 bool &need_hide_vert)
1106{
1107 char hflag = 0;
1108 BMIter iter;
1109 int i;
1110 BMVert *vert;
1111 BM_ITER_MESH_INDEX (vert, &iter, &bm, BM_VERTS_OF_MESH, i) {
1112 BM_elem_index_set(vert, i); /* set_inline */
1113 table[i] = vert;
1114 hflag |= vert->head.hflag;
1115 }
1116 need_select_vert = (hflag & BM_ELEM_SELECT) != 0;
1117 need_hide_vert = (hflag & BM_ELEM_HIDDEN) != 0;
1118}
1119
1122 bool &need_select_edge,
1123 bool &need_hide_edge,
1124 bool &need_sharp_edge,
1125 bool &need_uv_seams)
1126{
1127 char hflag = 0;
1128 BMIter iter;
1129 int i;
1130 BMEdge *edge;
1131 BM_ITER_MESH_INDEX (edge, &iter, &bm, BM_EDGES_OF_MESH, i) {
1132 BM_elem_index_set(edge, i); /* set_inline */
1133 table[i] = edge;
1134 hflag |= edge->head.hflag;
1135 need_sharp_edge |= (edge->head.hflag & BM_ELEM_SMOOTH) == 0;
1136 }
1137 need_select_edge = (hflag & BM_ELEM_SELECT) != 0;
1138 need_hide_edge = (hflag & BM_ELEM_HIDDEN) != 0;
1139 need_uv_seams = (hflag & BM_ELEM_SEAM) != 0;
1140}
1141
1149 MutableSpan<const BMFace *> face_table,
1150 MutableSpan<const BMLoop *> loop_table,
1151 bool &need_select_poly,
1152 bool &need_hide_poly,
1153 bool &need_sharp_face,
1154 bool &need_material_index,
1155 Vector<int> &loop_layers_not_to_copy)
1156{
1157 const CustomData &ldata = bm.ldata;
1158 Vector<int> vert_sel_layers;
1159 Vector<int> edge_sel_layers;
1160 Vector<int> pin_layers;
1161 for (const int i : IndexRange(CustomData_number_of_layers(&ldata, CD_PROP_FLOAT2))) {
1162 char const *layer_name = CustomData_get_layer_name(&ldata, CD_PROP_FLOAT2, i);
1163 char sub_layer_name[MAX_CUSTOMDATA_LAYER_NAME];
1164 auto add_bool_layer = [&](Vector<int> &layers, const StringRef name) {
1165 const int layer_index = CustomData_get_named_layer_index(&ldata, CD_PROP_BOOL, name);
1166 if (layer_index != -1) {
1167 layers.append(layer_index);
1168 }
1169 };
1170 add_bool_layer(vert_sel_layers, BKE_uv_map_vert_select_name_get(layer_name, sub_layer_name));
1171 add_bool_layer(edge_sel_layers, BKE_uv_map_edge_select_name_get(layer_name, sub_layer_name));
1172 add_bool_layer(pin_layers, BKE_uv_map_pin_name_get(layer_name, sub_layer_name));
1173 }
1174 Array<int> vert_sel_offsets(vert_sel_layers.size());
1175 Array<int> edge_sel_offsets(edge_sel_layers.size());
1176 Array<int> pin_offsets(pin_layers.size());
1177 for (const int i : vert_sel_layers.index_range()) {
1178 vert_sel_offsets[i] = ldata.layers[vert_sel_layers[i]].offset;
1179 }
1180 for (const int i : edge_sel_layers.index_range()) {
1181 edge_sel_offsets[i] = ldata.layers[edge_sel_layers[i]].offset;
1182 }
1183 for (const int i : pin_layers.index_range()) {
1184 pin_offsets[i] = ldata.layers[pin_layers[i]].offset;
1185 }
1186
1187 Array<bool> need_vert_sel(vert_sel_layers.size(), false);
1188 Array<bool> need_edge_sel(edge_sel_layers.size(), false);
1189 Array<bool> need_pin(pin_layers.size(), false);
1190 char hflag = 0;
1191 BMIter iter;
1192 int face_i = 0;
1193 int loop_i = 0;
1194 BMFace *face;
1195 BM_ITER_MESH_INDEX (face, &iter, &bm, BM_FACES_OF_MESH, face_i) {
1196 BM_elem_index_set(face, face_i); /* set_inline */
1197 face_table[face_i] = face;
1198 hflag |= face->head.hflag;
1199 need_sharp_face |= (face->head.hflag & BM_ELEM_SMOOTH) == 0;
1200 need_material_index |= face->mat_nr != 0;
1201
1202 BMLoop *loop = BM_FACE_FIRST_LOOP(face);
1203 for ([[maybe_unused]] const int i : IndexRange(face->len)) {
1204 BM_elem_index_set(loop, loop_i); /* set_inline */
1205 loop_table[loop_i] = loop;
1206 for (const int i : vert_sel_offsets.index_range()) {
1207 if (BM_ELEM_CD_GET_BOOL(loop, vert_sel_offsets[i])) {
1208 need_vert_sel[i] = true;
1209 }
1210 }
1211 for (const int i : edge_sel_offsets.index_range()) {
1212 if (BM_ELEM_CD_GET_BOOL(loop, edge_sel_offsets[i])) {
1213 need_edge_sel[i] = true;
1214 }
1215 }
1216 for (const int i : pin_offsets.index_range()) {
1217 if (BM_ELEM_CD_GET_BOOL(loop, pin_offsets[i])) {
1218 need_pin[i] = true;
1219 }
1220 }
1221 loop = loop->next;
1222 loop_i++;
1223 }
1224 }
1225 need_select_poly = (hflag & BM_ELEM_SELECT) != 0;
1226 need_hide_poly = (hflag & BM_ELEM_HIDDEN) != 0;
1227
1228 for (const int i : vert_sel_layers.index_range()) {
1229 if (!need_vert_sel[i]) {
1230 loop_layers_not_to_copy.append(vert_sel_layers[i]);
1231 }
1232 }
1233 for (const int i : edge_sel_layers.index_range()) {
1234 if (!need_edge_sel[i]) {
1235 loop_layers_not_to_copy.append(edge_sel_layers[i]);
1236 }
1237 }
1238 for (const int i : pin_layers.index_range()) {
1239 if (!need_pin[i]) {
1240 loop_layers_not_to_copy.append(pin_layers[i]);
1241 }
1242 }
1243}
1244
1246 const int mesh_index,
1247 const void *block)
1248{
1249 for (const BMeshToMeshLayerInfo &info : copy_info) {
1251 POINTER_OFFSET(block, info.bmesh_offset),
1252 POINTER_OFFSET(info.mesh_data, info.elem_size * mesh_index));
1253 }
1254}
1255
1256static void bm_to_mesh_verts(const BMesh &bm,
1257 const Span<const BMVert *> bm_verts,
1258 Mesh &mesh,
1259 MutableSpan<bool> select_vert,
1260 MutableSpan<bool> hide_vert)
1261{
1262 CustomData_free_layer_named(&mesh.vert_data, "position");
1264 &mesh.vert_data, CD_PROP_FLOAT3, CD_CONSTRUCT, mesh.verts_num, "position");
1266 MutableSpan<float3> dst_vert_positions = mesh.vert_positions_for_write();
1267
1268 std::atomic<bool> any_loose_vert = false;
1269 threading::parallel_for(dst_vert_positions.index_range(), 1024, [&](const IndexRange range) {
1270 bool any_loose_vert_local = false;
1271 for (const int vert_i : range) {
1272 const BMVert &src_vert = *bm_verts[vert_i];
1273 copy_v3_v3(dst_vert_positions[vert_i], src_vert.co);
1274 bmesh_block_copy_to_mesh_attributes(info, vert_i, src_vert.head.data);
1275 any_loose_vert_local = any_loose_vert_local || src_vert.e == nullptr;
1276 }
1277 if (any_loose_vert_local) {
1278 any_loose_vert.store(true, std::memory_order_relaxed);
1279 }
1280 if (!select_vert.is_empty()) {
1281 for (const int vert_i : range) {
1282 select_vert[vert_i] = BM_elem_flag_test(bm_verts[vert_i], BM_ELEM_SELECT);
1283 }
1284 }
1285 if (!hide_vert.is_empty()) {
1286 for (const int vert_i : range) {
1287 hide_vert[vert_i] = BM_elem_flag_test(bm_verts[vert_i], BM_ELEM_HIDDEN);
1288 }
1289 }
1290 });
1291
1292 if (!any_loose_vert) {
1293 mesh.tag_loose_verts_none();
1294 }
1295}
1296
1297static void bm_to_mesh_edges(const BMesh &bm,
1298 const Span<const BMEdge *> bm_edges,
1299 Mesh &mesh,
1300 MutableSpan<bool> select_edge,
1301 MutableSpan<bool> hide_edge,
1302 MutableSpan<bool> sharp_edge,
1303 MutableSpan<bool> uv_seams)
1304{
1305 CustomData_free_layer_named(&mesh.edge_data, ".edge_verts");
1307 &mesh.edge_data, CD_PROP_INT32_2D, CD_CONSTRUCT, mesh.edges_num, ".edge_verts");
1309 MutableSpan<int2> dst_edges = mesh.edges_for_write();
1310
1311 std::atomic<bool> any_loose_edge = false;
1312 threading::parallel_for(dst_edges.index_range(), 512, [&](const IndexRange range) {
1313 bool any_loose_edge_local = false;
1314 for (const int edge_i : range) {
1315 const BMEdge &src_edge = *bm_edges[edge_i];
1316 dst_edges[edge_i] = int2(BM_elem_index_get(src_edge.v1), BM_elem_index_get(src_edge.v2));
1317 bmesh_block_copy_to_mesh_attributes(info, edge_i, src_edge.head.data);
1318 any_loose_edge_local |= BM_edge_is_wire(&src_edge);
1319 }
1320 if (any_loose_edge_local) {
1321 any_loose_edge.store(true, std::memory_order_relaxed);
1322 }
1323 if (!select_edge.is_empty()) {
1324 for (const int edge_i : range) {
1325 select_edge[edge_i] = BM_elem_flag_test(bm_edges[edge_i], BM_ELEM_SELECT);
1326 }
1327 }
1328 if (!hide_edge.is_empty()) {
1329 for (const int edge_i : range) {
1330 hide_edge[edge_i] = BM_elem_flag_test(bm_edges[edge_i], BM_ELEM_HIDDEN);
1331 }
1332 }
1333 if (!sharp_edge.is_empty()) {
1334 for (const int edge_i : range) {
1335 sharp_edge[edge_i] = !BM_elem_flag_test(bm_edges[edge_i], BM_ELEM_SMOOTH);
1336 }
1337 }
1338 if (!uv_seams.is_empty()) {
1339 for (const int edge_i : range) {
1340 uv_seams[edge_i] = BM_elem_flag_test(bm_edges[edge_i], BM_ELEM_SEAM);
1341 }
1342 }
1343 });
1344
1345 if (!any_loose_edge) {
1346 mesh.tag_loose_edges_none();
1347 }
1348}
1349
1350static void bm_to_mesh_faces(const BMesh &bm,
1351 const Span<const BMFace *> bm_faces,
1352 Mesh &mesh,
1353 MutableSpan<bool> select_poly,
1354 MutableSpan<bool> hide_poly,
1355 MutableSpan<bool> sharp_faces,
1356 MutableSpan<int> material_indices)
1357{
1360 MutableSpan<int> dst_face_offsets = mesh.face_offsets_for_write();
1361 threading::parallel_for(bm_faces.index_range(), 1024, [&](const IndexRange range) {
1362 for (const int face_i : range) {
1363 const BMFace &src_face = *bm_faces[face_i];
1364 dst_face_offsets[face_i] = BM_elem_index_get(BM_FACE_FIRST_LOOP(&src_face));
1365 bmesh_block_copy_to_mesh_attributes(info, face_i, src_face.head.data);
1366 }
1367 if (!select_poly.is_empty()) {
1368 for (const int face_i : range) {
1369 select_poly[face_i] = BM_elem_flag_test(bm_faces[face_i], BM_ELEM_SELECT);
1370 }
1371 }
1372 if (!hide_poly.is_empty()) {
1373 for (const int face_i : range) {
1374 hide_poly[face_i] = BM_elem_flag_test(bm_faces[face_i], BM_ELEM_HIDDEN);
1375 }
1376 }
1377 if (!material_indices.is_empty()) {
1378 for (const int face_i : range) {
1379 material_indices[face_i] = bm_faces[face_i]->mat_nr;
1380 }
1381 }
1382 if (!sharp_faces.is_empty()) {
1383 for (const int face_i : range) {
1384 sharp_faces[face_i] = !BM_elem_flag_test(bm_faces[face_i], BM_ELEM_SMOOTH);
1385 }
1386 }
1387 });
1388}
1389
1390static void bm_to_mesh_loops(const BMesh &bm, const Span<const BMLoop *> bm_loops, Mesh &mesh)
1391{
1392 CustomData_free_layer_named(&mesh.corner_data, ".corner_vert");
1393 CustomData_free_layer_named(&mesh.corner_data, ".corner_edge");
1395 &mesh.corner_data, CD_PROP_INT32, CD_CONSTRUCT, mesh.corners_num, ".corner_vert");
1397 &mesh.corner_data, CD_PROP_INT32, CD_CONSTRUCT, mesh.corners_num, ".corner_edge");
1399 MutableSpan<int> dst_corner_verts = mesh.corner_verts_for_write();
1400 MutableSpan<int> dst_corner_edges = mesh.corner_edges_for_write();
1401 threading::parallel_for(dst_corner_verts.index_range(), 1024, [&](const IndexRange range) {
1402 for (const int loop_i : range) {
1403 const BMLoop &src_loop = *bm_loops[loop_i];
1404 dst_corner_verts[loop_i] = BM_elem_index_get(src_loop.v);
1405 dst_corner_edges[loop_i] = BM_elem_index_get(src_loop.e);
1406 bmesh_block_copy_to_mesh_attributes(info, loop_i, src_loop.head.data);
1407 }
1408 });
1409}
1410
1411} // namespace blender
1412
1414{
1415 using namespace blender;
1416 const int old_verts_num = mesh->verts_num;
1417
1419
1420 mesh->verts_num = bm->totvert;
1421 mesh->edges_num = bm->totedge;
1422 mesh->totface_legacy = 0;
1423 mesh->corners_num = bm->totloop;
1424 mesh->faces_num = bm->totface;
1425 mesh->act_face = -1;
1426
1427 bool need_select_vert = false;
1428 bool need_select_edge = false;
1429 bool need_select_poly = false;
1430 bool need_hide_vert = false;
1431 bool need_hide_edge = false;
1432 bool need_hide_poly = false;
1433 bool need_material_index = false;
1434 bool need_sharp_edge = false;
1435 bool need_sharp_face = false;
1436 bool need_uv_seams = false;
1437 Array<const BMVert *> vert_table;
1438 Array<const BMEdge *> edge_table;
1439 Array<const BMFace *> face_table;
1440 Array<const BMLoop *> loop_table;
1441 Vector<int> loop_layers_not_to_copy;
1443 (mesh->faces_num + mesh->edges_num) > 1024,
1444 [&]() {
1445 vert_table.reinitialize(bm->totvert);
1446 bm_vert_table_build(*bm, vert_table, need_select_vert, need_hide_vert);
1447 },
1448 [&]() {
1449 edge_table.reinitialize(bm->totedge);
1450 bm_edge_table_build(
1451 *bm, edge_table, need_select_edge, need_hide_edge, need_sharp_edge, need_uv_seams);
1452 },
1453 [&]() {
1454 face_table.reinitialize(bm->totface);
1455 loop_table.reinitialize(bm->totloop);
1456 bm_face_loop_table_build(*bm,
1457 face_table,
1458 loop_table,
1459 need_select_poly,
1460 need_hide_poly,
1461 need_sharp_face,
1462 need_material_index,
1463 loop_layers_not_to_copy);
1464 for (const int i : loop_layers_not_to_copy) {
1465 bm->ldata.layers[i].flag |= CD_FLAG_NOCOPY;
1466 }
1467 });
1468 bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE | BM_LOOP);
1469
1470 {
1472 CustomData_MeshMasks_update(&mask, &params->cd_mask_extra);
1474 &bm->vdata, &mesh->vert_data, mask.vmask, CD_CONSTRUCT, mesh->verts_num);
1476 &bm->edata, &mesh->edge_data, mask.emask, CD_CONSTRUCT, mesh->edges_num);
1478 &bm->ldata, &mesh->corner_data, mask.lmask, CD_CONSTRUCT, mesh->corners_num);
1480 &bm->pdata, &mesh->face_data, mask.pmask, CD_CONSTRUCT, mesh->faces_num);
1481 }
1482
1483 /* Add optional mesh attributes before parallel iteration. */
1485 bke::MutableAttributeAccessor attrs = mesh->attributes_for_write();
1495 bke::SpanAttributeWriter<int> material_index;
1496 if (need_select_vert) {
1497 select_vert = attrs.lookup_or_add_for_write_only_span<bool>(".select_vert", AttrDomain::Point);
1498 }
1499 if (need_hide_vert) {
1500 hide_vert = attrs.lookup_or_add_for_write_only_span<bool>(".hide_vert", AttrDomain::Point);
1501 }
1502 if (need_select_edge) {
1503 select_edge = attrs.lookup_or_add_for_write_only_span<bool>(".select_edge", AttrDomain::Edge);
1504 }
1505 if (need_sharp_edge) {
1506 sharp_edge = attrs.lookup_or_add_for_write_only_span<bool>("sharp_edge", AttrDomain::Edge);
1507 }
1508 if (need_uv_seams) {
1509 uv_seams = attrs.lookup_or_add_for_write_only_span<bool>("uv_seam", AttrDomain::Edge);
1510 }
1511 if (need_hide_edge) {
1512 hide_edge = attrs.lookup_or_add_for_write_only_span<bool>(".hide_edge", AttrDomain::Edge);
1513 }
1514 if (need_select_poly) {
1515 select_poly = attrs.lookup_or_add_for_write_only_span<bool>(".select_poly", AttrDomain::Face);
1516 }
1517 if (need_hide_poly) {
1518 hide_poly = attrs.lookup_or_add_for_write_only_span<bool>(".hide_poly", AttrDomain::Face);
1519 }
1520 if (need_sharp_face) {
1521 sharp_face = attrs.lookup_or_add_for_write_only_span<bool>("sharp_face", AttrDomain::Face);
1522 }
1523 if (need_material_index) {
1524 material_index = attrs.lookup_or_add_for_write_only_span<int>("material_index",
1526 }
1527
1528 /* Loop over all elements in parallel, copying attributes and building the Mesh topology. */
1530 (mesh->faces_num + mesh->edges_num) > 1024,
1531 [&]() {
1532 bm_to_mesh_verts(*bm, vert_table, *mesh, select_vert.span, hide_vert.span);
1533 if (mesh->key) {
1534 bm_to_mesh_shape(
1535 bm, mesh->key, mesh->vert_positions_for_write(), params->active_shapekey_to_mvert);
1536 }
1537 },
1538 [&]() {
1540 edge_table,
1541 *mesh,
1542 select_edge.span,
1543 hide_edge.span,
1544 sharp_edge.span,
1545 uv_seams.span);
1546 },
1547 [&]() {
1549 face_table,
1550 *mesh,
1551 select_poly.span,
1552 hide_poly.span,
1553 sharp_face.span,
1554 material_index.span);
1555 if (bm->act_face) {
1556 mesh->act_face = BM_elem_index_get(bm->act_face);
1557 }
1558 },
1559 [&]() {
1560 bm_to_mesh_loops(*bm, loop_table, *mesh);
1561 /* Topology could be changed, ensure #CD_MDISPS are ok. */
1563 for (const int i : loop_layers_not_to_copy) {
1564 bm->ldata.layers[i].flag &= ~CD_FLAG_NOCOPY;
1565 }
1566 },
1567 [&]() {
1568 /* Patch hook indices and vertex parents. */
1569 if (params->calc_object_remap && (old_verts_num > 0)) {
1570 bmesh_to_mesh_calc_object_remap(*bmain, *mesh, *bm, old_verts_num);
1571 }
1572 },
1573 [&]() {
1574 mesh->totselect = BLI_listbase_count(&(bm->selected));
1575
1576 MEM_SAFE_FREE(mesh->mselect);
1577 if (mesh->totselect != 0) {
1578 mesh->mselect = MEM_malloc_arrayN<MSelect>(mesh->totselect, "Mesh selection history");
1579 }
1580 int i;
1581 LISTBASE_FOREACH_INDEX (BMEditSelection *, selected, &bm->selected, i) {
1582 if (selected->htype == BM_VERT) {
1583 mesh->mselect[i].type = ME_VSEL;
1584 }
1585 else if (selected->htype == BM_EDGE) {
1586 mesh->mselect[i].type = ME_ESEL;
1587 }
1588 else if (selected->htype == BM_FACE) {
1589 mesh->mselect[i].type = ME_FSEL;
1590 }
1591
1592 mesh->mselect[i].index = BM_elem_index_get(selected->ele);
1593 }
1594 },
1595 [&]() {
1596 /* Run this even when shape keys aren't used since it may be used for hooks or vertex
1597 * parents. */
1598 if (params->update_shapekey_indices) {
1599 /* We have written a new shape key, if this mesh is _not_ going to be freed,
1600 * update the shape key indices to match the newly updated. */
1601 const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata,
1603 if (cd_shape_keyindex_offset != -1) {
1604 BMIter iter;
1605 BMVert *vert;
1606 int i;
1607 BM_ITER_MESH_INDEX (vert, &iter, bm, BM_VERTS_OF_MESH, i) {
1608 BM_ELEM_CD_SET_INT(vert, cd_shape_keyindex_offset, i);
1609 }
1610 }
1611 }
1612 });
1613
1614 select_vert.finish();
1615 hide_vert.finish();
1616 select_edge.finish();
1617 hide_edge.finish();
1618 sharp_edge.finish();
1619 uv_seams.finish();
1620 select_poly.finish();
1621 hide_poly.finish();
1622 sharp_face.finish();
1623 material_index.finish();
1624}
1625
1627 Mesh &mesh,
1629 const bool add_mesh_attributes)
1630{
1631 /* NOTE: The function is called from multiple threads with the same input BMesh and different
1632 * mesh objects. */
1633
1634 using namespace blender;
1635 /* Must be an empty mesh. */
1636 BLI_assert(mesh.verts_num == 0);
1637 /* Just in case, clear the derived geometry caches from the input mesh. */
1639
1640 mesh.verts_num = bm.totvert;
1641 mesh.edges_num = bm.totedge;
1642 mesh.totface_legacy = 0;
1643 mesh.corners_num = bm.totloop;
1644 mesh.faces_num = bm.totface;
1645
1646 mesh.runtime->deformed_only = true;
1647
1648 const bool use_threading = (mesh.faces_num + mesh.edges_num) > 1024;
1649
1650 /* In a first pass, update indices of BMesh elements and build tables for easy iteration later.
1651 * Also check if some optional mesh attributes should be added in the next step. Since each
1652 * domain has no effect on others, process the independent domains on separate threads. */
1653 bool need_select_vert = false;
1654 bool need_select_edge = false;
1655 bool need_select_poly = false;
1656 bool need_hide_vert = false;
1657 bool need_hide_edge = false;
1658 bool need_hide_poly = false;
1659 bool need_material_index = false;
1660 bool need_sharp_edge = false;
1661 bool need_sharp_face = false;
1662 bool need_uv_seams = false;
1663
1664 Array<const BMVert *> vert_table;
1665 Array<const BMEdge *> edge_table;
1666 Array<const BMFace *> face_table;
1667 Array<const BMLoop *> loop_table;
1668 Vector<int> loop_layers_not_to_copy;
1670 use_threading,
1671 [&]() {
1672 vert_table.reinitialize(bm.totvert);
1673 bm_vert_table_build(bm, vert_table, need_select_vert, need_hide_vert);
1674 },
1675 [&]() {
1676 edge_table.reinitialize(bm.totedge);
1678 bm, edge_table, need_select_edge, need_hide_edge, need_sharp_edge, need_uv_seams);
1679 },
1680 [&]() {
1681 face_table.reinitialize(bm.totface);
1682 loop_table.reinitialize(bm.totloop);
1684 face_table,
1685 loop_table,
1686 need_select_poly,
1687 need_hide_poly,
1688 need_sharp_face,
1689 need_material_index,
1690 loop_layers_not_to_copy);
1691 for (const int i : loop_layers_not_to_copy) {
1692 bm.ldata.layers[i].flag |= CD_FLAG_NOCOPY;
1693 }
1694 });
1695 bm.elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE | BM_LOOP);
1696
1697 if (mask) {
1698 CustomData_merge_layout(&bm.vdata, &mesh.vert_data, mask->vmask, CD_CONSTRUCT, mesh.verts_num);
1699 CustomData_merge_layout(&bm.edata, &mesh.edge_data, mask->emask, CD_CONSTRUCT, mesh.edges_num);
1701 &bm.ldata, &mesh.corner_data, mask->lmask, CD_CONSTRUCT, mesh.corners_num);
1702 CustomData_merge_layout(&bm.pdata, &mesh.face_data, mask->pmask, CD_CONSTRUCT, mesh.faces_num);
1703 }
1704
1705 /* Add optional mesh attributes before parallel iteration. */
1716 bke::SpanAttributeWriter<int> material_index;
1717
1718 if (add_mesh_attributes) {
1719 bke::MutableAttributeAccessor attrs = mesh.attributes_for_write();
1720 if (need_select_vert) {
1721 select_vert = attrs.lookup_or_add_for_write_only_span<bool>(".select_vert",
1723 }
1724 if (need_hide_vert) {
1725 hide_vert = attrs.lookup_or_add_for_write_only_span<bool>(".hide_vert", AttrDomain::Point);
1726 }
1727 if (need_select_edge) {
1728 select_edge = attrs.lookup_or_add_for_write_only_span<bool>(".select_edge",
1730 }
1731 if (need_sharp_edge) {
1732 sharp_edge = attrs.lookup_or_add_for_write_only_span<bool>("sharp_edge", AttrDomain::Edge);
1733 }
1734 if (need_uv_seams) {
1735 uv_seams = attrs.lookup_or_add_for_write_only_span<bool>("uv_seam", AttrDomain::Edge);
1736 }
1737 if (need_hide_edge) {
1738 hide_edge = attrs.lookup_or_add_for_write_only_span<bool>(".hide_edge", AttrDomain::Edge);
1739 }
1740 if (need_select_poly) {
1741 select_poly = attrs.lookup_or_add_for_write_only_span<bool>(".select_poly",
1743 }
1744 if (need_hide_poly) {
1745 hide_poly = attrs.lookup_or_add_for_write_only_span<bool>(".hide_poly", AttrDomain::Face);
1746 }
1747 if (need_sharp_face) {
1748 sharp_face = attrs.lookup_or_add_for_write_only_span<bool>("sharp_face", AttrDomain::Face);
1749 }
1750 if (need_material_index) {
1751 material_index = attrs.lookup_or_add_for_write_only_span<int>("material_index",
1753 }
1754 }
1755
1756 /* Loop over all elements in parallel, copying attributes and building the Mesh topology. */
1758 use_threading,
1759 [&]() { bm_to_mesh_verts(bm, vert_table, mesh, select_vert.span, hide_vert.span); },
1760 [&]() {
1762 edge_table,
1763 mesh,
1764 select_edge.span,
1765 hide_edge.span,
1766 sharp_edge.span,
1767 uv_seams.span);
1768 },
1769 [&]() {
1771 face_table,
1772 mesh,
1773 select_poly.span,
1774 hide_poly.span,
1775 sharp_face.span,
1776 material_index.span);
1777 if (bm.act_face) {
1778 mesh.act_face = BM_elem_index_get(bm.act_face);
1779 }
1780 },
1781 [&]() {
1782 bm_to_mesh_loops(bm, loop_table, mesh);
1783 for (const int i : loop_layers_not_to_copy) {
1784 bm.ldata.layers[i].flag &= ~CD_FLAG_NOCOPY;
1785 }
1786 });
1787
1788 if (add_mesh_attributes) {
1789 select_vert.finish();
1790 hide_vert.finish();
1791 select_edge.finish();
1792 hide_edge.finish();
1793 sharp_edge.finish();
1794 uv_seams.finish();
1795 select_poly.finish();
1796 hide_poly.finish();
1797 sharp_face.finish();
1798 material_index.finish();
1799 }
1800}
1801
1803{
1804 /* Don't process shape-keys. We only feed them through the modifier stack as needed,
1805 * e.g. for applying modifiers or the like. */
1807 if (cd_mask_extra != nullptr) {
1808 CustomData_MeshMasks_update(&mask, cd_mask_extra);
1809 }
1810 mask.vmask &= ~CD_MASK_SHAPEKEY;
1811
1812 BM_mesh_bm_to_me_compact(bm, mesh, &mask, true);
1813}
blender::StringRef BKE_uv_map_pin_name_get(blender::StringRef uv_map_name, char *buffer)
blender::StringRef BKE_uv_map_edge_select_name_get(blender::StringRef uv_map_name, char *buffer)
blender::StringRef BKE_uv_map_vert_select_name_get(blender::StringRef uv_map_name, char *buffer)
CustomData interface, see also DNA_customdata_types.h.
void CustomData_data_set_default_value(eCustomDataType type, void *elem)
int CustomData_get_offset(const CustomData *data, eCustomDataType type)
int CustomData_get_layer_index_n(const CustomData *data, eCustomDataType type, int n)
bool CustomData_bmesh_merge_layout(const CustomData *source, CustomData *dest, eCustomDataMask mask, eCDAllocType alloctype, BMesh *bm, char htype)
int CustomData_get_n_offset(const CustomData *data, eCustomDataType type, int n)
@ CD_SET_DEFAULT
@ CD_CONSTRUCT
void * CustomData_add_layer_named(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem, blender::StringRef name)
void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst, const CustomData_MeshMasks *mask_src)
Definition customdata.cc:94
void CustomData_bmesh_init_pool(CustomData *data, int totelem, char htype)
int CustomData_get_named_layer_index(const CustomData *data, eCustomDataType type, blender::StringRef name)
bool CustomData_has_layer_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
const char * CustomData_get_layer_name(const CustomData *data, eCustomDataType type, int n)
void CustomData_data_copy_value(eCustomDataType type, const void *source, void *dest)
const CustomData_MeshMasks CD_MASK_BMESH
#define ORIGINDEX_NONE
void CustomData_init_layout_from(const CustomData *source, CustomData *dest, eCustomDataMask mask, eCDAllocType alloctype, int totelem)
CustomData CustomData_shallow_copy_remove_non_bmesh_attributes(const CustomData *src, eCustomDataMask mask)
bool CustomData_has_layer(const CustomData *data, eCustomDataType type)
size_t CustomData_get_elem_size(const CustomDataLayer *layer)
void * CustomData_add_layer(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem)
const CustomData_MeshMasks CD_MASK_DERIVEDMESH
bool CustomData_merge_layout(const CustomData *source, CustomData *dest, eCustomDataMask mask, eCDAllocType alloctype, int totelem)
int CustomData_number_of_layers(const CustomData *data, eCustomDataType type)
bool CustomData_free_layer_named(CustomData *data, blender::StringRef name)
void CustomData_bmesh_alloc_block(CustomData *data, void **block)
const CustomData_MeshMasks CD_MASK_MESH
KeyBlock * BKE_keyblock_add(Key *key, const char *name)
Definition key.cc:1835
std::optional< blender::Array< bool > > BKE_keyblock_get_dependent_keys(const Key *key, int index)
Definition key.cc:2404
void BKE_mesh_clear_geometry(Mesh *mesh)
void BKE_mesh_face_offsets_ensure_alloc(Mesh *mesh)
void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
void multires_topology_changed(Mesh *mesh)
Definition multires.cc:1430
#define BLI_array_alloca(arr, realsize)
Definition BLI_alloca.h:18
#define BLI_assert(a)
Definition BLI_assert.h:46
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
MINLINE int min_ii(int a, int b)
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
#define BLI_SCOPED_DEFER(function_to_defer)
#define UNLIKELY(x)
#define ELEM(...)
#define POINTER_OFFSET(v, ofs)
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
bool DEG_is_original(const T *id)
@ CD_PROP_FLOAT3
@ CD_PROP_INT32_2D
@ CD_PROP_INT32
@ CD_PROP_FLOAT2
@ CD_SHAPE_KEYINDEX
@ CD_FLAG_NOCOPY
@ KEY_RELATIVE
@ ME_VSEL
@ ME_FSEL
@ ME_ESEL
@ eModifierType_Hook
Object is a sort of wrapper for general info.
@ PARVERT1
@ PARVERT3
Read Guarded memory(de)allocation.
#define BM_ELEM_CD_GET_BOOL(ele, offset)
@ BM_ELEM_HIDDEN
@ BM_ELEM_SEAM
@ BM_ELEM_SELECT
@ BM_ELEM_SMOOTH
#define BM_ELEM_CD_GET_INT(ele, offset)
#define BM_ELEM_CD_SET_INT(ele, offset, f)
#define BM_FACE_FIRST_LOOP(p)
@ BM_LOOP
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
BMFace * BM_face_create(BMesh *bm, BMVert *const *verts, BMEdge *const *edges, const int len, const BMFace *f_example, const eBMCreateFlag create_flag)
BMVert * BM_vert_create(BMesh *bm, const float co[3], const BMVert *v_example, const eBMCreateFlag create_flag)
Main function for creating a new vertex.
Definition bmesh_core.cc:41
BMEdge * BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag)
Main function for creating a new edge.
@ BM_CREATE_SKIP_CD
Definition bmesh_core.hh:36
#define BM_elem_index_get(ele)
#define BM_elem_index_set(ele, index)
#define BM_elem_flag_enable(ele, hflag)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
BMesh const char void * data
BMesh * bm
void BM_select_history_clear(BMesh *bm)
void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
Select Face.
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
Select Vert.
void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
Select Edge.
#define BM_select_history_store_notest(bm, ele)
static Vector< MeshToBMeshLayerInfo > mesh_to_bm_copy_info_calc(const CustomData &mesh_data, CustomData &bm_data)
static int bm_to_mesh_shape_layer_index_from_kb(BMesh *bm, KeyBlock *currkey)
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *mesh, const BMeshFromMeshParams *params)
void BM_mesh_bm_to_me_for_eval(BMesh &bm, Mesh &mesh, const CustomData_MeshMasks *cd_mask_extra)
static void bm_to_mesh_shape(BMesh *bm, Key *key, MutableSpan< float3 > positions, const bool active_shapekey_to_mvert)
static BMFace * bm_face_create_from_mpoly(BMesh &bm, Span< int > face_verts, Span< int > face_edges, Span< BMVert * > vtable, Span< BMEdge * > etable)
static void bmesh_to_mesh_calc_object_remap(Main &bmain, Mesh &mesh, BMesh &bm, const int old_totvert)
void BM_mesh_bm_to_me_compact(BMesh &bm, Mesh &mesh, const CustomData_MeshMasks *mask, const bool add_mesh_attributes)
static BMVert ** bm_to_mesh_vertex_map(BMesh *bm, const int old_verts_num)
BMesh -> Mesh.
static Vector< BMeshToMeshLayerInfo > bm_to_mesh_copy_info_calc(const CustomData &bm_data, CustomData &mesh_data)
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *mesh, const BMeshToMeshParams *params)
static void mesh_attributes_copy_to_bmesh_block(CustomData &data, const Span< MeshToBMeshLayerInfo > copy_info, const int mesh_index, BMHeader &header)
bool BM_attribute_stored_in_bmesh_builtin(const StringRef name)
static void assert_bmesh_has_no_mesh_only_attributes(const BMesh &bm)
#define BM_FACE
#define BM_EDGE
#define BM_VERT
void BM_face_normal_update(BMFace *f)
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
AttributeSet attributes
const T * data() const
Definition BLI_array.hh:301
IndexRange index_range() const
Definition BLI_array.hh:349
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:398
bool is_empty() const
Definition BLI_array.hh:253
constexpr int64_t start() const
constexpr bool is_empty() const
Definition BLI_span.hh:509
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
Definition BLI_span.hh:260
int64_t size() const
void append(const T &value)
IndexRange index_range() const
void fill(const T &value) const
GAttributeReader lookup(const StringRef attribute_id) const
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type)
static float verts[][3]
#define printf(...)
#define MAX_CUSTOMDATA_LAYER_NAME
#define MEM_SAFE_FREE(v)
#define MEM_reallocN(vmemh, len)
#define CD_MASK_SHAPEKEY
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define LOG(severity)
Definition log.h:32
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
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
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static char faces[256]
void parallel_invoke(Functions &&...functions)
Definition BLI_task.hh:221
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
static void bm_to_mesh_loops(const BMesh &bm, const Span< const BMLoop * > bm_loops, Mesh &mesh)
static void bm_to_mesh_verts(const BMesh &bm, const Span< const BMVert * > bm_verts, Mesh &mesh, MutableSpan< bool > select_vert, MutableSpan< bool > hide_vert)
static void bm_to_mesh_edges(const BMesh &bm, const Span< const BMEdge * > bm_edges, Mesh &mesh, MutableSpan< bool > select_edge, MutableSpan< bool > hide_edge, MutableSpan< bool > sharp_edge, MutableSpan< bool > uv_seams)
static void bm_vert_table_build(BMesh &bm, MutableSpan< const BMVert * > table, bool &need_select_vert, bool &need_hide_vert)
static void bm_edge_table_build(BMesh &bm, MutableSpan< const BMEdge * > table, bool &need_select_edge, bool &need_hide_edge, bool &need_sharp_edge, bool &need_uv_seams)
static void bmesh_block_copy_to_mesh_attributes(const Span< BMeshToMeshLayerInfo > copy_info, const int mesh_index, const void *block)
static void bm_face_loop_table_build(BMesh &bm, MutableSpan< const BMFace * > face_table, MutableSpan< const BMLoop * > loop_table, bool &need_select_poly, bool &need_hide_poly, bool &need_sharp_face, bool &need_material_index, Vector< int > &loop_layers_not_to_copy)
VecBase< float, 3 > float3
static void bm_to_mesh_faces(const BMesh &bm, const Span< const BMFace * > bm_faces, Mesh &mesh, MutableSpan< bool > select_poly, MutableSpan< bool > hide_poly, MutableSpan< bool > sharp_faces, MutableSpan< int > material_indices)
BMHeader head
short mat_nr
BMHeader head
void * data
BMHeader head
struct BMLoop * next
float co[3]
BMHeader head
CustomDataLayer * layers
char name[66]
Definition DNA_ID.h:415
char name[64]
struct KeyBlock * next
void * data
int uidgen
int elemsize
char type
ListBase block
KeyBlock * refkey
void * first
ListBase objects
Definition BKE_main.hh:247
int corners_num
CustomData edge_data
int edges_num
MeshRuntimeHandle * runtime
CustomData corner_data
CustomData face_data
int act_face
CustomData vert_data
struct Key * key
int totselect
int totface_legacy
int faces_num
struct MSelect * mselect
int verts_num
i
Definition text_draw.cc:230