From 09b6eac5c4a0f17cb20e1be1cef3f9e551ebbfde Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 1 Aug 2023 14:27:16 +0200 Subject: [PATCH] Fix #110471: Normal Edit modifier screws up UVs The issue was that `CustomData_swap` modifies all layers, but does not ensure that the layers are actually mutable. This resulted in it modifying shared layers. Now it ensures that the layers are mutable first (which copies the layers if they are shared). Longer term, it would be good to remove `CustomData_swap` since it's not a good API performance wise, but that is outside of the scope of this patch. Pull Request: https://projects.blender.org/blender/blender/pulls/110678 --- source/blender/blenkernel/BKE_customdata.h | 2 +- source/blender/blenkernel/BKE_mesh.h | 2 ++ source/blender/blenkernel/intern/customdata.cc | 14 +++++++------- .../blender/blenkernel/intern/mesh_evaluate.cc | 16 +++++++++++++--- source/blender/makesrna/intern/rna_mesh_api.cc | 1 + .../blender/modifiers/intern/MOD_normal_edit.cc | 1 + 6 files changed, 25 insertions(+), 11 deletions(-) diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 6a1def301a5..efa7ed1be41 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -432,7 +432,7 @@ void CustomData_swap_corners(struct CustomData *data, int index, const int *corn /** * Swap two items of given custom data, in all available layers. */ -void CustomData_swap(struct CustomData *data, int index_a, int index_b); +void CustomData_swap(struct CustomData *data, int index_a, int index_b, const int totelem); /** * Retrieve a pointer to an element of the active layer of the given \a type, chosen by the diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 4e8c78cad36..7ea8987185c 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -550,6 +550,7 @@ void BKE_mesh_face_flip_ex(int face_offset, int *corner_verts, int *corner_edges, struct CustomData *loop_data, + int tot_loop, float (*lnors)[3], struct MDisps *mdisp, bool use_loop_mdisp_flip); @@ -569,6 +570,7 @@ void BKE_mesh_faces_flip(const int *face_offsets, int *corner_verts, int *corner_edges, struct CustomData *loop_data, + int loops_num, int faces_num); /** diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 8f044d80845..a90ab6e4004 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -3505,7 +3505,7 @@ void CustomData_swap_corners(CustomData *data, const int index, const int *corne } } -void CustomData_swap(CustomData *data, const int index_a, const int index_b) +void CustomData_swap(CustomData *data, const int index_a, const int index_b, const int totelem) { char buff_static[256]; @@ -3514,17 +3514,17 @@ void CustomData_swap(CustomData *data, const int index_a, const int index_b) } for (int i = 0; i < data->totlayer; i++) { - const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(data->layers[i].type)); + CustomDataLayer &layer = data->layers[i]; + ensure_layer_data_is_mutable(layer, totelem); + const LayerTypeInfo *typeInfo = layerType_getInfo(eCustomDataType(layer.type)); const size_t size = typeInfo->size; const size_t offset_a = size * index_a; const size_t offset_b = size * index_b; void *buff = size <= sizeof(buff_static) ? buff_static : MEM_mallocN(size, __func__); - memcpy(buff, POINTER_OFFSET(data->layers[i].data, offset_a), size); - memcpy(POINTER_OFFSET(data->layers[i].data, offset_a), - POINTER_OFFSET(data->layers[i].data, offset_b), - size); - memcpy(POINTER_OFFSET(data->layers[i].data, offset_b), buff, size); + memcpy(buff, POINTER_OFFSET(layer.data, offset_a), size); + memcpy(POINTER_OFFSET(layer.data, offset_a), POINTER_OFFSET(layer.data, offset_b), size); + memcpy(POINTER_OFFSET(layer.data, offset_b), buff, size); if (buff != buff_static) { MEM_freeN(buff); diff --git a/source/blender/blenkernel/intern/mesh_evaluate.cc b/source/blender/blenkernel/intern/mesh_evaluate.cc index 0206577a27a..47b00dceca3 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.cc +++ b/source/blender/blenkernel/intern/mesh_evaluate.cc @@ -503,6 +503,7 @@ void BKE_mesh_face_flip_ex(const int face_offset, int *corner_verts, int *corner_edges, CustomData *loop_data, + int tot_loop, float (*lnors)[3], MDisps *mdisp, const bool use_loop_mdisp_flip) @@ -541,7 +542,7 @@ void BKE_mesh_face_flip_ex(const int face_offset, if (lnors) { swap_v3_v3(lnors[loopstart], lnors[loopend]); } - CustomData_swap(loop_data, loopstart, loopend); + CustomData_swap(loop_data, loopstart, loopend, tot_loop); } /* Even if we did not swap the other 'pivot' loop, we need to set its swapped edge. */ if (loopstart == loopend) { @@ -557,14 +558,22 @@ void BKE_mesh_face_flip(const int face_offset, const int totloop) { MDisps *mdisp = (MDisps *)CustomData_get_layer_for_write(loop_data, CD_MDISPS, totloop); - BKE_mesh_face_flip_ex( - face_offset, face_size, corner_verts, corner_edges, loop_data, nullptr, mdisp, true); + BKE_mesh_face_flip_ex(face_offset, + face_size, + corner_verts, + corner_edges, + loop_data, + totloop, + nullptr, + mdisp, + true); } void BKE_mesh_faces_flip(const int *face_offsets, int *corner_verts, int *corner_edges, CustomData *loop_data, + int loops_num, int faces_num) { const blender::OffsetIndices faces(blender::Span(face_offsets, faces_num + 1)); @@ -575,6 +584,7 @@ void BKE_mesh_faces_flip(const int *face_offsets, corner_verts, corner_edges, loop_data, + loops_num, nullptr, mdisp, true); diff --git a/source/blender/makesrna/intern/rna_mesh_api.cc b/source/blender/makesrna/intern/rna_mesh_api.cc index 9313f898826..7c18c2a1000 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.cc +++ b/source/blender/makesrna/intern/rna_mesh_api.cc @@ -164,6 +164,7 @@ static void rna_Mesh_flip_normals(Mesh *mesh) mesh->corner_verts_for_write().data(), mesh->corner_edges_for_write().data(), &mesh->loop_data, + mesh->totloop, mesh->faces_num); BKE_mesh_tessface_clear(mesh); BKE_mesh_runtime_clear_geometry(mesh); diff --git a/source/blender/modifiers/intern/MOD_normal_edit.cc b/source/blender/modifiers/intern/MOD_normal_edit.cc index cc982dff4fd..3fb8141ebf2 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.cc +++ b/source/blender/modifiers/intern/MOD_normal_edit.cc @@ -211,6 +211,7 @@ static bool faces_check_flip(blender::MutableSpan corner_verts, corner_verts.data(), corner_edges.data(), ldata, + corner_edges.size(), reinterpret_cast(nos), mdisp, true);