From 5669c5a61b2f049ec1b55cf045221b24095b9df2 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Sun, 12 Mar 2023 21:50:14 +0100 Subject: [PATCH] Mesh: Parallelize BMesh to Mesh conversion This is very similar to ebe8f8ce719729eef40, but applies the same changes to conversions to non-evaluated meshes meant for original data. The function also handles shape keys, UVs, selection history, "scan the database" object vertex index remapping, and multires fixes. Those operations are handled in parallel with the other conversions now. Similar to before, the improvement is better the more attributes/data contained in the BMesh. This time I observed an improvement of 50% (182ms to 123ms) for a large grid mesh with many attributes, and 20% for a large grid mesh with less data. Shape keys, selection, hiding, and multires data should have less of a detriment to performance now too. One remaining thing to improve is the recently added UV selection/pin handling. This should be moved into the first single-threaded loop over faces, or changed further. Pull Request: https://projects.blender.org/blender/blender/pulls/105602 --- .../bmesh/intern/bmesh_mesh_convert.cc | 547 +++++++----------- 1 file changed, 224 insertions(+), 323 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc index 7267a86e432..7d44f75ad49 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc @@ -85,6 +85,7 @@ #include "BLI_span.hh" #include "BLI_string_ref.hh" #include "BLI_task.hh" +#include "BLI_timeit.hh" #include "BLI_vector.hh" #include "BKE_attribute.hh" @@ -949,23 +950,6 @@ static void bm_to_mesh_shape(BMesh *bm, /** \} */ -template -static void write_fn_to_attribute(blender::bke::MutableAttributeAccessor attributes, - const StringRef attribute_name, - const eAttrDomain domain, - const GetFn &get_fn) -{ - using namespace blender; - bke::SpanAttributeWriter attribute = attributes.lookup_or_add_for_write_only_span( - attribute_name, domain); - threading::parallel_for(attribute.span.index_range(), 4096, [&](IndexRange range) { - for (const int i : range) { - attribute.span[i] = get_fn(i); - } - }); - attribute.finish(); -} - static void assert_bmesh_has_no_mesh_only_attributes(const BMesh &bm) { (void)bm; /* Unused in the release builds. */ @@ -981,68 +965,70 @@ static void assert_bmesh_has_no_mesh_only_attributes(const BMesh &bm) BLI_assert(CustomData_get_layer_named(&bm.pdata, CD_PROP_BOOL, ".select_poly") == nullptr); } -static void convert_bmesh_hide_flags_to_mesh_attributes(BMesh &bm, - const bool need_hide_vert, - const bool need_hide_edge, - const bool need_hide_poly, - Mesh &mesh) +static void bmesh_to_mesh_calc_object_remap(Main &bmain, + Mesh &me, + BMesh &bm, + const int old_totvert) { - using namespace blender; - /* The "hide" attributes are stored as flags on #BMesh. */ - assert_bmesh_has_no_mesh_only_attributes(bm); + BMVert **vertMap = nullptr; + BMVert *eve; - if (!(need_hide_vert || need_hide_edge || need_hide_poly)) { - return; + LISTBASE_FOREACH (Object *, ob, &bmain.objects) { + if ((ob->parent) && (ob->parent->data == &me) && ELEM(ob->partype, PARVERT1, PARVERT3)) { + + if (vertMap == nullptr) { + vertMap = bm_to_mesh_vertex_map(&bm, old_totvert); + } + + if (ob->par1 < old_totvert) { + eve = vertMap[ob->par1]; + if (eve) { + ob->par1 = BM_elem_index_get(eve); + } + } + if (ob->par2 < old_totvert) { + eve = vertMap[ob->par2]; + if (eve) { + ob->par2 = BM_elem_index_get(eve); + } + } + if (ob->par3 < old_totvert) { + eve = vertMap[ob->par3]; + if (eve) { + ob->par3 = BM_elem_index_get(eve); + } + } + } + if (ob->data == &me) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_Hook) { + HookModifierData *hmd = (HookModifierData *)md; + + if (vertMap == nullptr) { + vertMap = bm_to_mesh_vertex_map(&bm, old_totvert); + } + int i, j; + for (i = j = 0; i < hmd->indexar_num; i++) { + if (hmd->indexar[i] < old_totvert) { + eve = vertMap[hmd->indexar[i]]; + + if (eve) { + hmd->indexar[j++] = BM_elem_index_get(eve); + } + } + else { + j++; + } + } + + hmd->indexar_num = j; + } + } + } } - bke::MutableAttributeAccessor attributes = mesh.attributes_for_write(); - BM_mesh_elem_table_ensure(&bm, BM_VERT | BM_EDGE | BM_FACE); - - if (need_hide_vert) { - write_fn_to_attribute(attributes, ".hide_vert", ATTR_DOMAIN_POINT, [&](const int i) { - return BM_elem_flag_test(BM_vert_at_index(&bm, i), BM_ELEM_HIDDEN); - }); - } - if (need_hide_edge) { - write_fn_to_attribute(attributes, ".hide_edge", ATTR_DOMAIN_EDGE, [&](const int i) { - return BM_elem_flag_test(BM_edge_at_index(&bm, i), BM_ELEM_HIDDEN); - }); - } - if (need_hide_poly) { - write_fn_to_attribute(attributes, ".hide_poly", ATTR_DOMAIN_FACE, [&](const int i) { - return BM_elem_flag_test(BM_face_at_index(&bm, i), BM_ELEM_HIDDEN); - }); - } -} - -static void convert_bmesh_selection_flags_to_mesh_attributes(BMesh &bm, - const bool need_select_vert, - const bool need_select_edge, - const bool need_select_poly, - Mesh &mesh) -{ - using namespace blender; - if (!(need_select_vert || need_select_edge || need_select_poly)) { - return; - } - - bke::MutableAttributeAccessor attributes = mesh.attributes_for_write(); - BM_mesh_elem_table_ensure(&bm, BM_VERT | BM_EDGE | BM_FACE); - - if (need_select_vert) { - write_fn_to_attribute(attributes, ".select_vert", ATTR_DOMAIN_POINT, [&](const int i) { - return BM_elem_flag_test(BM_vert_at_index(&bm, i), BM_ELEM_SELECT); - }); - } - if (need_select_edge) { - write_fn_to_attribute(attributes, ".select_edge", ATTR_DOMAIN_EDGE, [&](const int i) { - return BM_elem_flag_test(BM_edge_at_index(&bm, i), BM_ELEM_SELECT); - }); - } - if (need_select_poly) { - write_fn_to_attribute(attributes, ".select_poly", ATTR_DOMAIN_FACE, [&](const int i) { - return BM_elem_flag_test(BM_face_at_index(&bm, i), BM_ELEM_SELECT); - }); + if (vertMap) { + MEM_freeN(vertMap); } } @@ -1110,6 +1096,7 @@ static void bm_vert_table_build(BMesh &bm, BM_elem_index_set(vert, i); /* set_inline */ table[i] = vert; hflag |= vert->head.hflag; + BM_CHECK_ELEMENT(vert); } need_select_vert = (hflag & BM_ELEM_SELECT) != 0; need_hide_vert = (hflag & BM_ELEM_HIDDEN) != 0; @@ -1130,6 +1117,7 @@ static void bm_edge_table_build(BMesh &bm, BM_elem_index_set(edge, i); /* set_inline */ table[i] = edge; hflag |= edge->head.hflag; + BM_CHECK_ELEMENT(edge); } need_select_edge = (hflag & BM_ELEM_SELECT) != 0; need_hide_edge = (hflag & BM_ELEM_HIDDEN) != 0; @@ -1156,11 +1144,13 @@ static void bm_face_loop_table_build(BMesh &bm, hflag |= face->head.hflag; need_sharp_face |= (face->head.hflag & BM_ELEM_SMOOTH) == 0; need_material_index |= face->mat_nr != 0; + BM_CHECK_ELEMENT(face); BMLoop *loop = BM_FACE_FIRST_LOOP(face); for ([[maybe_unused]] const int i : IndexRange(face->len)) { BM_elem_index_set(loop, loop_i); /* set_inline */ loop_table[loop_i] = loop; + BM_CHECK_ELEMENT(loop); loop = loop->next; loop_i++; } @@ -1186,6 +1176,8 @@ static void bm_to_mesh_verts(const BMesh &bm, MutableSpan select_vert, MutableSpan hide_vert) { + CustomData_add_layer_named( + &mesh.vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, nullptr, mesh.totvert, "position"); const Vector info = bm_to_mesh_copy_info_calc(bm.vdata, mesh.vdata); MutableSpan dst_vert_positions = mesh.vert_positions_for_write(); threading::parallel_for(dst_vert_positions.index_range(), 1024, [&](const IndexRange range) { @@ -1215,6 +1207,7 @@ static void bm_to_mesh_edges(const BMesh &bm, MutableSpan sharp_edge, MutableSpan uv_seams) { + CustomData_add_layer(&mesh.edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, mesh.totedge); const Vector info = bm_to_mesh_copy_info_calc(bm.edata, mesh.edata); MutableSpan dst_edges = mesh.edges_for_write(); threading::parallel_for(dst_edges.index_range(), 512, [&](const IndexRange range) { @@ -1256,6 +1249,7 @@ static void bm_to_mesh_faces(const BMesh &bm, MutableSpan sharp_faces, MutableSpan material_indices) { + CustomData_add_layer(&mesh.pdata, CD_MPOLY, CD_CONSTRUCT, nullptr, mesh.totpoly); const Vector info = bm_to_mesh_copy_info_calc(bm.pdata, mesh.pdata); MutableSpan dst_polys = mesh.polys_for_write(); threading::parallel_for(dst_polys.index_range(), 1024, [&](const IndexRange range) { @@ -1291,6 +1285,7 @@ static void bm_to_mesh_faces(const BMesh &bm, static void bm_to_mesh_loops(const BMesh &bm, const Span bm_loops, Mesh &mesh) { + CustomData_add_layer(&mesh.ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, mesh.totloop); const Vector info = bm_to_mesh_copy_info_calc(bm.ldata, mesh.ldata); MutableSpan dst_loops = mesh.loops_for_write(); threading::parallel_for(dst_loops.index_range(), 1024, [&](const IndexRange range) { @@ -1309,13 +1304,8 @@ static void bm_to_mesh_loops(const BMesh &bm, const Span bm_loop void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params) { using namespace blender; - BMVert *v, *eve; - BMEdge *e; BMFace *f; BMIter iter; - int i, j; - - const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX); const int ototvert = me->totvert; @@ -1333,11 +1323,9 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh /* Add new custom data. */ me->totvert = bm->totvert; me->totedge = bm->totedge; + me->totface = 0; me->totloop = bm->totloop; me->totpoly = bm->totface; - /* Will be overwritten with a valid value if 'dotess' is set, otherwise we - * end up with 'me->totface' and `me->mface == nullptr` which can crash #28625. */ - me->totface = 0; me->act_face = -1; /* Mark UV selection layers which are all false as 'nocopy'. */ @@ -1418,26 +1406,6 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh CustomData_copy(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly); } - const Vector vert_info = bm_to_mesh_copy_info_calc(bm->vdata, me->vdata); - const Vector edge_info = bm_to_mesh_copy_info_calc(bm->edata, me->edata); - const Vector poly_info = bm_to_mesh_copy_info_calc(bm->pdata, me->pdata); - const Vector loop_info = bm_to_mesh_copy_info_calc(bm->ldata, me->ldata); - - /* Clear the CD_FLAG_NOCOPY flags for the layers they were temporarily set on */ - for (const int i : ldata_layers_marked_nocopy) { - bm->ldata.layers[i].flag &= ~CD_FLAG_NOCOPY; - } - - CustomData_add_layer_named( - &me->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, nullptr, me->totvert, "position"); - CustomData_add_layer(&me->edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, me->totedge); - CustomData_add_layer(&me->ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, me->totloop); - CustomData_add_layer(&me->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, me->totpoly); - MutableSpan positions = me->vert_positions_for_write(); - MutableSpan edges = me->edges_for_write(); - MutableSpan polys = me->polys_for_write(); - MutableSpan mloop = me->loops_for_write(); - bool need_select_vert = false; bool need_select_edge = false; bool need_select_poly = false; @@ -1445,239 +1413,180 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh bool need_hide_edge = false; bool need_hide_poly = false; bool need_material_index = false; - bool need_sharp_face = false; bool need_sharp_edge = false; - bool need_uv_seam = false; + bool need_sharp_face = false; + bool need_uv_seams = false; + Array vert_table; + Array edge_table; + Array face_table; + Array loop_table; + threading::parallel_invoke( + me->totface > 1024, + [&]() { + vert_table.reinitialize(bm->totvert); + bm_vert_table_build(*bm, vert_table, need_select_vert, need_hide_vert); + }, + [&]() { + edge_table.reinitialize(bm->totedge); + bm_edge_table_build( + *bm, edge_table, need_select_edge, need_hide_edge, need_sharp_edge, need_uv_seams); + }, + [&]() { + face_table.reinitialize(bm->totface); + loop_table.reinitialize(bm->totloop); + bm_face_loop_table_build(*bm, + face_table, + loop_table, + need_select_poly, + need_hide_poly, + need_sharp_face, + need_material_index); + }); + bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE | BM_LOOP); - i = 0; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - copy_v3_v3(positions[i], v->co); - - if (BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { - need_hide_vert = true; - } - if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { - need_select_vert = true; - } - - BM_elem_index_set(v, i); /* set_inline */ - - bmesh_block_copy_to_mesh_attributes(vert_info, i, v->head.data); - - i++; - - BM_CHECK_ELEMENT(v); + /* Add optional mesh attributes before parallel iteration. */ + assert_bmesh_has_no_mesh_only_attributes(*bm); + bke::MutableAttributeAccessor attrs = me->attributes_for_write(); + bke::SpanAttributeWriter select_vert; + bke::SpanAttributeWriter hide_vert; + bke::SpanAttributeWriter select_edge; + bke::SpanAttributeWriter hide_edge; + bke::SpanAttributeWriter sharp_edge; + bke::SpanAttributeWriter uv_seams; + bke::SpanAttributeWriter select_poly; + bke::SpanAttributeWriter hide_poly; + bke::SpanAttributeWriter sharp_face; + bke::SpanAttributeWriter material_index; + if (need_select_vert) { + select_vert = attrs.lookup_or_add_for_write_only_span(".select_vert", ATTR_DOMAIN_POINT); } - bm->elem_index_dirty &= ~BM_VERT; - - i = 0; - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - edges[i].v1 = BM_elem_index_get(e->v1); - edges[i].v2 = BM_elem_index_get(e->v2); - - if (BM_elem_flag_test(e, BM_ELEM_SEAM)) { - need_uv_seam = true; - } - if (BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { - need_hide_edge = true; - } - if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { - need_select_edge = true; - } - if (!BM_elem_flag_test(e, BM_ELEM_SMOOTH)) { - need_sharp_edge = true; - } - - BM_elem_index_set(e, i); /* set_inline */ - - bmesh_block_copy_to_mesh_attributes(edge_info, i, e->head.data); - - i++; - BM_CHECK_ELEMENT(e); + if (need_hide_vert) { + hide_vert = attrs.lookup_or_add_for_write_only_span(".hide_vert", ATTR_DOMAIN_POINT); } - bm->elem_index_dirty &= ~BM_EDGE; - - i = 0; - j = 0; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - BMLoop *l_iter, *l_first; - polys[i].loopstart = j; - polys[i].totloop = f->len; - if (f->mat_nr != 0) { - need_material_index = true; - } - if (!BM_elem_flag_test(f, BM_ELEM_SMOOTH)) { - need_sharp_face = true; - } - if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { - need_hide_poly = true; - } - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - need_select_poly = true; - } - - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - mloop[j].e = BM_elem_index_get(l_iter->e); - mloop[j].v = BM_elem_index_get(l_iter->v); - - bmesh_block_copy_to_mesh_attributes(loop_info, j, l_iter->head.data); - - j++; - BM_CHECK_ELEMENT(l_iter); - BM_CHECK_ELEMENT(l_iter->e); - BM_CHECK_ELEMENT(l_iter->v); - } while ((l_iter = l_iter->next) != l_first); - - if (f == bm->act_face) { - me->act_face = i; - } - - bmesh_block_copy_to_mesh_attributes(poly_info, i, f->head.data); - - i++; - BM_CHECK_ELEMENT(f); - } - - if (need_material_index) { - BM_mesh_elem_table_ensure(bm, BM_FACE); - write_fn_to_attribute(me->attributes_for_write(), - "material_index", - ATTR_DOMAIN_FACE, - [&](const int i) { return int(BM_face_at_index(bm, i)->mat_nr); }); + if (need_select_edge) { + select_edge = attrs.lookup_or_add_for_write_only_span(".select_edge", ATTR_DOMAIN_EDGE); } if (need_sharp_edge) { - BM_mesh_elem_table_ensure(bm, BM_EDGE); - write_fn_to_attribute( - me->attributes_for_write(), "sharp_edge", ATTR_DOMAIN_EDGE, [&](const int i) { - return !BM_elem_flag_test(BM_edge_at_index(bm, i), BM_ELEM_SMOOTH); - }); + sharp_edge = attrs.lookup_or_add_for_write_only_span("sharp_edge", ATTR_DOMAIN_EDGE); + } + if (need_uv_seams) { + uv_seams = attrs.lookup_or_add_for_write_only_span(".uv_seam", ATTR_DOMAIN_EDGE); + } + if (need_hide_edge) { + hide_edge = attrs.lookup_or_add_for_write_only_span(".hide_edge", ATTR_DOMAIN_EDGE); + } + if (need_select_poly) { + select_poly = attrs.lookup_or_add_for_write_only_span(".select_poly", ATTR_DOMAIN_FACE); + } + if (need_hide_poly) { + hide_poly = attrs.lookup_or_add_for_write_only_span(".hide_poly", ATTR_DOMAIN_FACE); } if (need_sharp_face) { - BM_mesh_elem_table_ensure(bm, BM_FACE); - write_fn_to_attribute( - me->attributes_for_write(), "sharp_face", ATTR_DOMAIN_FACE, [&](const int i) { - return !BM_elem_flag_test(BM_face_at_index(bm, i), BM_ELEM_SMOOTH); - }); + sharp_face = attrs.lookup_or_add_for_write_only_span("sharp_face", ATTR_DOMAIN_FACE); } - if (need_uv_seam) { - BM_mesh_elem_table_ensure(bm, BM_EDGE); - write_fn_to_attribute( - me->attributes_for_write(), ".uv_seam", ATTR_DOMAIN_EDGE, [&](const int i) { - return BM_elem_flag_test(BM_edge_at_index(bm, i), BM_ELEM_SEAM); - }); + if (need_material_index) { + material_index = attrs.lookup_or_add_for_write_only_span("material_index", + ATTR_DOMAIN_FACE); } - /* Patch hook indices and vertex parents. */ - if (params->calc_object_remap && (ototvert > 0)) { - BLI_assert(bmain != nullptr); - BMVert **vertMap = nullptr; - - LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - if ((ob->parent) && (ob->parent->data == me) && ELEM(ob->partype, PARVERT1, PARVERT3)) { - - if (vertMap == nullptr) { - vertMap = bm_to_mesh_vertex_map(bm, ototvert); + /* Loop over all elements in parallel, copying attributes and building the Mesh topology. */ + threading::parallel_invoke( + me->totvert > 1024, + [&]() { + bm_to_mesh_verts(*bm, vert_table, *me, select_vert.span, hide_vert.span); + if (me->key) { + bm_to_mesh_shape( + bm, me->key, me->vert_positions_for_write(), params->active_shapekey_to_mvert); } + }, + [&]() { + bm_to_mesh_edges(*bm, + edge_table, + *me, + select_edge.span, + hide_edge.span, + sharp_edge.span, + uv_seams.span); + }, + [&]() { + bm_to_mesh_faces(*bm, + face_table, + *me, + select_poly.span, + hide_poly.span, + sharp_face.span, + material_index.span); + if (bm->act_face) { + me->act_face = BM_elem_index_get(bm->act_face); + } + }, + [&]() { + bm_to_mesh_loops(*bm, loop_table, *me); + /* Topology could be changed, ensure #CD_MDISPS are ok. */ + multires_topology_changed(me); + /* Clear the CD_FLAG_NOCOPY flags for the layers they were temporarily set on */ + for (const int i : ldata_layers_marked_nocopy) { + bm->ldata.layers[i].flag &= ~CD_FLAG_NOCOPY; + } + }, + [&]() { + /* Patch hook indices and vertex parents. */ + if (params->calc_object_remap && (ototvert > 0)) { + bmesh_to_mesh_calc_object_remap(*bmain, *me, *bm, ototvert); + } + }, + [&]() { + me->totselect = BLI_listbase_count(&(bm->selected)); - if (ob->par1 < ototvert) { - eve = vertMap[ob->par1]; - if (eve) { - ob->par1 = BM_elem_index_get(eve); + MEM_SAFE_FREE(me->mselect); + if (me->totselect != 0) { + me->mselect = static_cast( + MEM_mallocN(sizeof(MSelect) * me->totselect, "Mesh selection history")); + } + int i; + LISTBASE_FOREACH_INDEX (BMEditSelection *, selected, &bm->selected, i) { + if (selected->htype == BM_VERT) { + me->mselect[i].type = ME_VSEL; } - } - if (ob->par2 < ototvert) { - eve = vertMap[ob->par2]; - if (eve) { - ob->par2 = BM_elem_index_get(eve); + else if (selected->htype == BM_EDGE) { + me->mselect[i].type = ME_ESEL; } - } - if (ob->par3 < ototvert) { - eve = vertMap[ob->par3]; - if (eve) { - ob->par3 = BM_elem_index_get(eve); + else if (selected->htype == BM_FACE) { + me->mselect[i].type = ME_FSEL; } - } - } - if (ob->data == me) { - LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { - if (md->type == eModifierType_Hook) { - HookModifierData *hmd = (HookModifierData *)md; - if (vertMap == nullptr) { - vertMap = bm_to_mesh_vertex_map(bm, ototvert); + me->mselect[i].index = BM_elem_index_get(selected->ele); + } + }, + [&]() { + /* Run this even when shape keys aren't used since it may be used for hooks or vertex + * parents. */ + if (params->update_shapekey_indices) { + /* We have written a new shape key, if this mesh is _not_ going to be freed, + * update the shape key indices to match the newly updated. */ + const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, + CD_SHAPE_KEYINDEX); + if (cd_shape_keyindex_offset != -1) { + BMIter iter; + BMVert *vert; + int i; + BM_ITER_MESH_INDEX (vert, &iter, bm, BM_VERTS_OF_MESH, i) { + BM_ELEM_CD_SET_INT(vert, cd_shape_keyindex_offset, i); } - - for (i = j = 0; i < hmd->indexar_num; i++) { - if (hmd->indexar[i] < ototvert) { - eve = vertMap[hmd->indexar[i]]; - - if (eve) { - hmd->indexar[j++] = BM_elem_index_get(eve); - } - } - else { - j++; - } - } - - hmd->indexar_num = j; } } - } - } + }); - if (vertMap) { - MEM_freeN(vertMap); - } - } - - convert_bmesh_hide_flags_to_mesh_attributes( - *bm, need_hide_vert, need_hide_edge, need_hide_poly, *me); - convert_bmesh_selection_flags_to_mesh_attributes( - *bm, need_select_vert, need_select_edge, need_select_poly, *me); - - { - me->totselect = BLI_listbase_count(&(bm->selected)); - - MEM_SAFE_FREE(me->mselect); - if (me->totselect != 0) { - me->mselect = static_cast( - MEM_mallocN(sizeof(MSelect) * me->totselect, "Mesh selection history")); - } - - LISTBASE_FOREACH_INDEX (BMEditSelection *, selected, &bm->selected, i) { - if (selected->htype == BM_VERT) { - me->mselect[i].type = ME_VSEL; - } - else if (selected->htype == BM_EDGE) { - me->mselect[i].type = ME_ESEL; - } - else if (selected->htype == BM_FACE) { - me->mselect[i].type = ME_FSEL; - } - - me->mselect[i].index = BM_elem_index_get(selected->ele); - } - } - - if (me->key) { - bm_to_mesh_shape(bm, me->key, positions, params->active_shapekey_to_mvert); - } - - /* Run this even when shape keys aren't used since it may be used for hooks or vertex parents. */ - if (params->update_shapekey_indices) { - /* We have written a new shape key, if this mesh is _not_ going to be freed, - * update the shape key indices to match the newly updated. */ - if (cd_shape_keyindex_offset != -1) { - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - BM_ELEM_CD_SET_INT(eve, cd_shape_keyindex_offset, i); - } - } - } - - /* Topology could be changed, ensure #CD_MDISPS are ok. */ - multires_topology_changed(me); + select_vert.finish(); + hide_vert.finish(); + select_edge.finish(); + hide_edge.finish(); + sharp_edge.finish(); + uv_seams.finish(); + select_poly.finish(); + hide_poly.finish(); + sharp_face.finish(); + material_index.finish(); } /* NOTE: The function is called from multiple threads with the same input BMesh and different @@ -1698,14 +1607,6 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * me->totloop = bm->totloop; me->totpoly = bm->totface; - if (!CustomData_get_layer_named(&me->vdata, CD_PROP_FLOAT3, "position")) { - CustomData_add_layer_named( - &me->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, nullptr, bm->totvert, "position"); - } - CustomData_add_layer(&me->edata, CD_MEDGE, CD_CONSTRUCT, nullptr, bm->totedge); - CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CONSTRUCT, nullptr, bm->totloop); - CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CONSTRUCT, nullptr, bm->totface); - /* Don't process shape-keys, we only feed them through the modifier stack as needed, * e.g. for applying modifiers or the like. */ CustomData_MeshMasks mask = CD_MASK_DERIVEDMESH;