diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index efa7ed1be41..b0d2a72870a 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -429,11 +429,6 @@ void CustomData_bmesh_interp(struct CustomData *data, */ void CustomData_swap_corners(struct CustomData *data, int index, const int *corner_indices); -/** - * Swap two items of given custom data, in all available layers. - */ -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 * \a index, if it exists. diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 7ea8987185c..767817f052f 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -537,42 +537,6 @@ void BKE_mesh_calc_volume(const float (*vert_positions)[3], */ void BKE_mesh_mdisp_flip(struct MDisps *md, bool use_loop_mdisp_flip); -/** - * Flip (invert winding of) the given \a face, i.e. reverse order of its loops - * (keeping the same vertex as 'start point'). - * - * \param face: the face to flip. - * \param mloop: the full loops array. - * \param loop_data: the loops custom data. - */ -void BKE_mesh_face_flip_ex(int face_offset, - int face_size, - int *corner_verts, - int *corner_edges, - struct CustomData *loop_data, - int tot_loop, - float (*lnors)[3], - struct MDisps *mdisp, - bool use_loop_mdisp_flip); -void BKE_mesh_face_flip(int face_offset, - int face_size, - int *corner_verts, - int *corner_edges, - struct CustomData *loop_data, - int totloop); - -/** - * Flip (invert winding of) all faces (used to inverse their normals). - * - * \note Invalidates tessellation, caller must handle that. - */ -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); - /** * Account for custom-data such as UVs becoming detached because of imprecision * in custom-data interpolation. diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index a90ab6e4004..d1c1bd5ea6f 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -3505,32 +3505,6 @@ 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, const int totelem) -{ - char buff_static[256]; - - if (index_a == index_b) { - return; - } - - for (int i = 0; i < data->totlayer; i++) { - 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(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); - } - } -} void *CustomData_get_for_write(CustomData *data, const int index, diff --git a/source/blender/blenkernel/intern/mesh_evaluate.cc b/source/blender/blenkernel/intern/mesh_evaluate.cc index 7e1f2d772dd..e4971c7d310 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.cc +++ b/source/blender/blenkernel/intern/mesh_evaluate.cc @@ -501,99 +501,6 @@ void BKE_mesh_mdisp_flip(MDisps *md, const bool use_loop_mdisp_flip) } } -void BKE_mesh_face_flip_ex(const int face_offset, - const int face_size, - int *corner_verts, - int *corner_edges, - CustomData *loop_data, - int tot_loop, - float (*lnors)[3], - MDisps *mdisp, - const bool use_loop_mdisp_flip) -{ - int loopstart = face_offset; - int loopend = loopstart + face_size - 1; - const bool corner_verts_in_data = - (CustomData_get_layer_named(loop_data, CD_PROP_INT32, ".corner_vert") == corner_verts); - const bool corner_edges_in_data = - (CustomData_get_layer_named(loop_data, CD_PROP_INT32, ".corner_edge") == corner_edges); - - if (mdisp) { - for (int i = loopstart; i <= loopend; i++) { - BKE_mesh_mdisp_flip(&mdisp[i], use_loop_mdisp_flip); - } - } - - /* Note that we keep same start vertex for flipped face. */ - - /* We also have to update loops edge - * (they will get their original 'other edge', that is, - * the original edge of their original previous loop)... */ - int prev_edge_index = corner_edges[loopstart]; - corner_edges[loopstart] = corner_edges[loopend]; - - for (loopstart++; loopend > loopstart; loopstart++, loopend--) { - corner_edges[loopend] = corner_edges[loopend - 1]; - std::swap(corner_edges[loopstart], prev_edge_index); - - if (!corner_verts_in_data) { - std::swap(corner_verts[loopstart], corner_verts[loopend]); - } - if (!corner_edges_in_data) { - std::swap(corner_edges[loopstart], corner_edges[loopend]); - } - if (lnors) { - swap_v3_v3(lnors[loopstart], lnors[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) { - corner_edges[loopstart] = prev_edge_index; - } -} - -void BKE_mesh_face_flip(const int face_offset, - const int face_size, - int *corner_verts, - int *corner_edges, - CustomData *loop_data, - 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, - 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)); - MDisps *mdisp = (MDisps *)CustomData_get_layer_for_write(loop_data, CD_MDISPS, faces_num); - for (const int i : faces.index_range()) { - BKE_mesh_face_flip_ex(faces[i].start(), - faces[i].size(), - corner_verts, - corner_edges, - loop_data, - loops_num, - nullptr, - mdisp, - true); - } -} - /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/mesh_flip_faces.cc b/source/blender/blenkernel/intern/mesh_flip_faces.cc index 0fe26583d04..b227f82242b 100644 --- a/source/blender/blenkernel/intern/mesh_flip_faces.cc +++ b/source/blender/blenkernel/intern/mesh_flip_faces.cc @@ -12,6 +12,29 @@ namespace blender::bke { +template +static void flip_corner_data(const OffsetIndices faces, + const IndexMask &face_selection, + MutableSpan data) +{ + face_selection.foreach_index(GrainSize(1024), + [&](const int i) { data.slice(faces[i].drop_front(1)).reverse(); }); +} + +template +static void flip_custom_data_type(const OffsetIndices faces, + CustomData &loop_data, + const IndexMask &face_selection, + const eCustomDataType data_type) +{ + BLI_assert(sizeof(T) == CustomData_sizeof(data_type)); + for (const int i : IndexRange(CustomData_number_of_layers(&loop_data, data_type))) { + T *data = static_cast( + CustomData_get_layer_n_for_write(&loop_data, data_type, i, faces.total_size())); + flip_corner_data(faces, face_selection, MutableSpan(data, faces.total_size())); + } +} + void mesh_flip_faces(Mesh &mesh, const IndexMask &selection) { if (mesh.faces_num == 0 || selection.is_empty()) { @@ -32,6 +55,23 @@ void mesh_flip_faces(Mesh &mesh, const IndexMask &selection) } }); + flip_custom_data_type(faces, mesh.loop_data, selection, CD_TANGENT); + flip_custom_data_type(faces, mesh.loop_data, selection, CD_MLOOPTANGENT); + flip_custom_data_type(faces, mesh.loop_data, selection, CD_CUSTOMLOOPNORMAL); + flip_custom_data_type(faces, mesh.loop_data, selection, CD_PAINT_MASK); + flip_custom_data_type(faces, mesh.loop_data, selection, CD_GRID_PAINT_MASK); + flip_custom_data_type(faces, mesh.loop_data, selection, CD_ORIGSPACE_MLOOP); + flip_custom_data_type(faces, mesh.loop_data, selection, CD_MDISPS); + if (MDisps *mdisp = static_cast( + CustomData_get_layer_for_write(&mesh.loop_data, CD_MDISPS, mesh.totloop))) + { + selection.foreach_index(GrainSize(512), [&](const int i) { + for (const int corner : faces[i]) { + BKE_mesh_mdisp_flip(&mdisp[corner], true); + } + }); + } + bke::MutableAttributeAccessor attributes = mesh.attributes_for_write(); attributes.for_all( [&](const bke::AttributeIDRef &attribute_id, const bke::AttributeMetaData &meta_data) { @@ -47,10 +87,7 @@ void mesh_flip_faces(Mesh &mesh, const IndexMask &selection) bke::GSpanAttributeWriter attribute = attributes.lookup_for_write_span(attribute_id); bke::attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) { using T = decltype(dummy); - MutableSpan dst_span = attribute.span.typed(); - selection.foreach_index(GrainSize(1024), [&](const int i) { - dst_span.slice(faces[i].drop_front(1)).reverse(); - }); + flip_corner_data(faces, selection, attribute.span.typed()); }); attribute.finish(); return true; diff --git a/source/blender/makesrna/intern/rna_mesh.cc b/source/blender/makesrna/intern/rna_mesh.cc index ba9a08afced..0cc2ef6cdc1 100644 --- a/source/blender/makesrna/intern/rna_mesh.cc +++ b/source/blender/makesrna/intern/rna_mesh.cc @@ -671,13 +671,10 @@ static float rna_MeshPolygon_area_get(PointerRNA *ptr) static void rna_MeshPolygon_flip(ID *id, MIntProperty *poly_offset_p) { + using namespace blender; Mesh *me = (Mesh *)id; - const int poly_start = *((const int *)poly_offset_p); - const int poly_size = *(((const int *)poly_offset_p) + 1) - poly_start; - int *corner_verts = me->corner_verts_for_write().data(); - int *corner_edges = me->corner_edges_for_write().data(); - BKE_mesh_face_flip( - poly_start, poly_size, corner_verts, corner_edges, &me->loop_data, me->totloop); + const int index = reinterpret_cast(poly_offset_p) - me->faces().data(); + bke::mesh_flip_faces(*me, IndexMask(IndexRange(index, 1))); BKE_mesh_tessface_clear(me); BKE_mesh_runtime_clear_geometry(me); } diff --git a/source/blender/makesrna/intern/rna_mesh_api.cc b/source/blender/makesrna/intern/rna_mesh_api.cc index 7c18c2a1000..eaa95d41e14 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.cc +++ b/source/blender/makesrna/intern/rna_mesh_api.cc @@ -160,15 +160,10 @@ static void rna_Mesh_transform(Mesh *mesh, const float mat[16], bool shape_keys) static void rna_Mesh_flip_normals(Mesh *mesh) { - BKE_mesh_faces_flip(BKE_mesh_face_offsets(mesh), - mesh->corner_verts_for_write().data(), - mesh->corner_edges_for_write().data(), - &mesh->loop_data, - mesh->totloop, - mesh->faces_num); + using namespace blender; + bke::mesh_flip_faces(*mesh, IndexMask(mesh->faces_num)); BKE_mesh_tessface_clear(mesh); BKE_mesh_runtime_clear_geometry(mesh); - DEG_id_tag_update(&mesh->id, 0); } diff --git a/source/blender/modifiers/intern/MOD_normal_edit.cc b/source/blender/modifiers/intern/MOD_normal_edit.cc index 3fb8141ebf2..6520cac74cb 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.cc +++ b/source/blender/modifiers/intern/MOD_normal_edit.cc @@ -182,44 +182,34 @@ static void mix_normals(const float mix_factor, /* Check face normals and new loop normals are compatible, otherwise flip faces * (and invert matching face normals). */ -static bool faces_check_flip(blender::MutableSpan corner_verts, - blender::MutableSpan corner_edges, - blender::float3 *nos, - CustomData *ldata, - const blender::OffsetIndices faces, +static void faces_check_flip(Mesh &mesh, + blender::MutableSpan nos, const blender::Span face_normals) { - MDisps *mdisp = static_cast( - CustomData_get_layer_for_write(ldata, CD_MDISPS, corner_verts.size())); - bool flipped = false; + using namespace blender; + const OffsetIndices faces = mesh.faces(); + IndexMaskMemory memory; + const IndexMask faces_to_flip = IndexMask::from_predicate( + faces.index_range(), GrainSize(1024), memory, [&](const int i) { + const blender::IndexRange face = faces[i]; + float norsum[3] = {0.0f}; - for (const int i : faces.index_range()) { - const blender::IndexRange face = faces[i]; - float norsum[3] = {0.0f}; + for (const int64_t j : face) { + add_v3_v3(norsum, nos[j]); + } + if (!normalize_v3(norsum)) { + return false; + } - for (const int64_t j : face) { - add_v3_v3(norsum, nos[j]); - } - if (!normalize_v3(norsum)) { - continue; - } + /* If average of new loop normals is opposed to face normal, flip face. */ + if (dot_v3v3(face_normals[i], norsum) < 0.0f) { + nos.slice(faces[i].drop_front(1)).reverse(); + return true; + } + return false; + }); - /* If average of new loop normals is opposed to face normal, flip face. */ - if (dot_v3v3(face_normals[i], norsum) < 0.0f) { - BKE_mesh_face_flip_ex(face.start(), - face.size(), - corner_verts.data(), - corner_edges.data(), - ldata, - corner_edges.size(), - reinterpret_cast(nos), - mdisp, - true); - flipped = true; - } - } - - return flipped; + bke::mesh_flip_faces(mesh, faces_to_flip); } static void normalEditModifier_do_radial(NormalEditModifierData *enmd, @@ -327,11 +317,8 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd, nos.data()); } - if (do_facenors_fix && - faces_check_flip( - corner_verts, corner_edges, nos.data(), &mesh->loop_data, faces, mesh->face_normals())) - { - BKE_mesh_tag_face_winding_changed(mesh); + if (do_facenors_fix) { + faces_check_flip(*mesh, nos, mesh->face_normals()); } const bool *sharp_faces = static_cast( CustomData_get_layer_named(&mesh->face_data, CD_PROP_BOOL, "sharp_face")); @@ -435,11 +422,8 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd, nos.data()); } - if (do_facenors_fix && - faces_check_flip( - corner_verts, corner_edges, nos.data(), &mesh->loop_data, faces, mesh->face_normals())) - { - BKE_mesh_tag_face_winding_changed(mesh); + if (do_facenors_fix) { + faces_check_flip(*mesh, nos, mesh->face_normals()); } const bool *sharp_faces = static_cast( CustomData_get_layer_named(&mesh->face_data, CD_PROP_BOOL, "sharp_face"));