From 8b416f7f609060fd8fca167bf6b82057b9df29eb Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 17 Feb 2023 13:41:44 -0500 Subject: [PATCH] Fix #104869: Crash converting UV maps to legacy format When the new UV to legacy format conversion happens, the mesh is in the middle of being written and is an at best "complicated", at worst invalid state. The attribute API looks at other domains and is a bit less forgiving in that respect, and shouldn't really be used here. Use the CustomData API instead. Also sort the layers the same way as b642dc7bc7d8db7a2fc3. --- .../blenkernel/intern/mesh_legacy_convert.cc | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc index 92197800aea..f43972f9883 100644 --- a/source/blender/blenkernel/intern/mesh_legacy_convert.cc +++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc @@ -1558,7 +1558,6 @@ void BKE_mesh_legacy_convert_uvs_to_struct( { using namespace blender; using namespace blender::bke; - const AttributeAccessor attributes = mesh->attributes(); Vector new_layer_to_write; /* Don't write the boolean UV map sublayers which will be written in the legacy #MLoopUV type. */ @@ -1591,24 +1590,30 @@ void BKE_mesh_legacy_convert_uvs_to_struct( mloopuv_layer.data = mloopuv.data(); char buffer[MAX_CUSTOMDATA_LAYER_NAME]; - const VArray vert_selection = attributes.lookup_or_default( - BKE_uv_map_vert_select_name_get(layer.name, buffer), ATTR_DOMAIN_CORNER, false); - const VArray edge_selection = attributes.lookup_or_default( - BKE_uv_map_edge_select_name_get(layer.name, buffer), ATTR_DOMAIN_CORNER, false); - const VArray pin = attributes.lookup_or_default( - BKE_uv_map_pin_name_get(layer.name, buffer), ATTR_DOMAIN_CORNER, false); + const bool *vert_selection = static_cast(CustomData_get_layer_named( + &mesh->ldata, CD_PROP_BOOL, BKE_uv_map_vert_select_name_get(layer.name, buffer))); + const bool *edge_selection = static_cast(CustomData_get_layer_named( + &mesh->ldata, CD_PROP_BOOL, BKE_uv_map_edge_select_name_get(layer.name, buffer))); + const bool *pin = static_cast(CustomData_get_layer_named( + &mesh->ldata, CD_PROP_BOOL, BKE_uv_map_pin_name_get(layer.name, buffer))); threading::parallel_for(mloopuv.index_range(), 2048, [&](IndexRange range) { for (const int i : range) { copy_v2_v2(mloopuv[i].uv, coords[i]); - SET_FLAG_FROM_TEST(mloopuv[i].flag, vert_selection[i], MLOOPUV_VERTSEL); - SET_FLAG_FROM_TEST(mloopuv[i].flag, edge_selection[i], MLOOPUV_EDGESEL); - SET_FLAG_FROM_TEST(mloopuv[i].flag, pin[i], MLOOPUV_PINNED); + SET_FLAG_FROM_TEST(mloopuv[i].flag, vert_selection && vert_selection[i], MLOOPUV_VERTSEL); + SET_FLAG_FROM_TEST(mloopuv[i].flag, edge_selection && edge_selection[i], MLOOPUV_EDGESEL); + SET_FLAG_FROM_TEST(mloopuv[i].flag, pin && pin[i], MLOOPUV_PINNED); } }); new_layer_to_write.append(mloopuv_layer); } + /* #CustomData expects the layers to be sorted in increasing order based on type. */ + std::stable_sort( + new_layer_to_write.begin(), + new_layer_to_write.end(), + [](const CustomDataLayer &a, const CustomDataLayer &b) { return a.type < b.type; }); + loop_layers_to_write = new_layer_to_write; mesh->ldata.totlayer = new_layer_to_write.size(); mesh->ldata.maxlayer = mesh->ldata.totlayer;