diff options
Diffstat (limited to 'source/blender/blenkernel/intern/geometry_component_mesh.cc')
-rw-r--r-- | source/blender/blenkernel/intern/geometry_component_mesh.cc | 285 |
1 files changed, 155 insertions, 130 deletions
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index 436868ba375..bf1dc1453c2 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -14,6 +14,8 @@ #include "BKE_lib_id.h" #include "BKE_mesh.h" +#include "FN_multi_function_builder.hh" + #include "attribute_access_intern.hh" extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id); @@ -115,8 +117,7 @@ void MeshComponent::ensure_owns_direct_data() namespace blender::bke { -VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component, - const Mesh &mesh, +VArray<float3> mesh_normals_varray(const Mesh &mesh, const IndexMask mask, const eAttrDomain domain) { @@ -135,8 +136,8 @@ VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component, * instead of the GeometryComponent API to avoid calculating unnecessary values and to * allow normalizing the result more simply. */ Span<float3> vert_normals{(float3 *)BKE_mesh_vertex_normals_ensure(&mesh), mesh.totvert}; + const Span<MEdge> edges = mesh.edges(); Array<float3> edge_normals(mask.min_array_size()); - Span<MEdge> edges{mesh.medge, mesh.totedge}; for (const int i : mask) { const MEdge &edge = edges[i]; edge_normals[i] = math::normalize( @@ -150,7 +151,7 @@ VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component, * array and copy the face normal for each of its corners. In this case using the mesh * component's generic domain interpolation is fine, the data will still be normalized, * since the face normal is just copied to every corner. */ - return mesh_component.attributes()->adapt_domain( + return mesh.attributes().adapt_domain( VArray<float3>::ForSpan({(float3 *)BKE_mesh_poly_normals_ensure(&mesh), mesh.totpoly}), ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER); @@ -176,11 +177,13 @@ static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh, MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totvert); + const Span<MLoop> loops = mesh.loops(); + attribute_math::DefaultMixer<T> mixer(r_values); for (const int loop_index : IndexRange(mesh.totloop)) { const T value = old_values[loop_index]; - const MLoop &loop = mesh.mloop[loop_index]; + const MLoop &loop = loops[loop_index]; const int point_index = loop.v; mixer.mix_in(point_index, value); } @@ -194,11 +197,13 @@ void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh, MutableSpan<bool> r_values) { BLI_assert(r_values.size() == mesh.totvert); + const Span<MLoop> loops = mesh.loops(); + Array<bool> loose_verts(mesh.totvert, true); r_values.fill(true); for (const int loop_index : IndexRange(mesh.totloop)) { - const MLoop &loop = mesh.mloop[loop_index]; + const MLoop &loop = loops[loop_index]; const int point_index = loop.v; loose_verts[point_index] = false; @@ -236,12 +241,14 @@ static GVArray adapt_mesh_domain_corner_to_point(const Mesh &mesh, const GVArray */ static GVArray adapt_mesh_domain_point_to_corner(const Mesh &mesh, const GVArray &varray) { + const Span<MLoop> loops = mesh.loops(); + GVArray new_varray; attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); new_varray = VArray<T>::ForFunc(mesh.totloop, - [&mesh, varray = varray.typed<T>()](const int64_t loop_index) { - const int vertex_index = mesh.mloop[loop_index].v; + [loops, varray = varray.typed<T>()](const int64_t loop_index) { + const int vertex_index = loops[loop_index].v; return varray[vertex_index]; }); }); @@ -250,15 +257,17 @@ static GVArray adapt_mesh_domain_point_to_corner(const Mesh &mesh, const GVArray static GVArray adapt_mesh_domain_corner_to_face(const Mesh &mesh, const GVArray &varray) { + const Span<MPoly> polys = mesh.polys(); + GVArray new_varray; attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { if constexpr (std::is_same_v<T, bool>) { new_varray = VArray<T>::ForFunc( - mesh.totpoly, [&mesh, varray = varray.typed<bool>()](const int face_index) { + polys.size(), [polys, varray = varray.typed<bool>()](const int face_index) { /* A face is selected if all of its corners were selected. */ - const MPoly &poly = mesh.mpoly[face_index]; + const MPoly &poly = polys[face_index]; for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { if (!varray[loop_index]) { return false; @@ -269,10 +278,10 @@ static GVArray adapt_mesh_domain_corner_to_face(const Mesh &mesh, const GVArray } else { new_varray = VArray<T>::ForFunc( - mesh.totpoly, [&mesh, varray = varray.typed<T>()](const int face_index) { + polys.size(), [polys, varray = varray.typed<T>()](const int face_index) { T return_value; attribute_math::DefaultMixer<T> mixer({&return_value, 1}); - const MPoly &poly = mesh.mpoly[face_index]; + const MPoly &poly = polys[face_index]; for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { const T value = varray[loop_index]; mixer.mix_in(0, value); @@ -292,17 +301,20 @@ static void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh, MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totedge); + const Span<MPoly> polys = mesh.polys(); + const Span<MLoop> loops = mesh.loops(); + attribute_math::DefaultMixer<T> mixer(r_values); - for (const int poly_index : IndexRange(mesh.totpoly)) { - const MPoly &poly = mesh.mpoly[poly_index]; + for (const int poly_index : polys.index_range()) { + const MPoly &poly = polys[poly_index]; /* For every edge, mix values from the two adjacent corners (the current and next corner). */ for (const int i : IndexRange(poly.totloop)) { const int next_i = (i + 1) % poly.totloop; const int loop_i = poly.loopstart + i; const int next_loop_i = poly.loopstart + next_i; - const MLoop &loop = mesh.mloop[loop_i]; + const MLoop &loop = loops[loop_i]; const int edge_index = loop.e; mixer.mix_in(edge_index, old_values[loop_i]); mixer.mix_in(edge_index, old_values[next_loop_i]); @@ -319,19 +331,21 @@ void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh, MutableSpan<bool> r_values) { BLI_assert(r_values.size() == mesh.totedge); + const Span<MPoly> polys = mesh.polys(); + const Span<MLoop> loops = mesh.loops(); /* It may be possible to rely on the #ME_LOOSEEDGE flag, but that seems error-prone. */ Array<bool> loose_edges(mesh.totedge, true); r_values.fill(true); - for (const int poly_index : IndexRange(mesh.totpoly)) { - const MPoly &poly = mesh.mpoly[poly_index]; + for (const int poly_index : polys.index_range()) { + const MPoly &poly = polys[poly_index]; for (const int i : IndexRange(poly.totloop)) { const int next_i = (i + 1) % poly.totloop; const int loop_i = poly.loopstart + i; const int next_loop_i = poly.loopstart + next_i; - const MLoop &loop = mesh.mloop[loop_i]; + const MLoop &loop = loops[loop_i]; const int edge_index = loop.e; loose_edges[edge_index] = false; @@ -372,13 +386,16 @@ void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh, MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totvert); + const Span<MPoly> polys = mesh.polys(); + const Span<MLoop> loops = mesh.loops(); + attribute_math::DefaultMixer<T> mixer(r_values); - for (const int poly_index : IndexRange(mesh.totpoly)) { - const MPoly &poly = mesh.mpoly[poly_index]; + for (const int poly_index : polys.index_range()) { + const MPoly &poly = polys[poly_index]; const T value = old_values[poly_index]; for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { - const MLoop &loop = mesh.mloop[loop_index]; + const MLoop &loop = loops[loop_index]; const int point_index = loop.v; mixer.mix_in(point_index, value); } @@ -394,13 +411,15 @@ void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh, MutableSpan<bool> r_values) { BLI_assert(r_values.size() == mesh.totvert); + const Span<MPoly> polys = mesh.polys(); + const Span<MLoop> loops = mesh.loops(); r_values.fill(false); - for (const int poly_index : IndexRange(mesh.totpoly)) { - const MPoly &poly = mesh.mpoly[poly_index]; + for (const int poly_index : polys.index_range()) { + const MPoly &poly = polys[poly_index]; if (old_values[poly_index]) { for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { - const MLoop &loop = mesh.mloop[loop_index]; + const MLoop &loop = loops[loop_index]; const int vert_index = loop.v; r_values[vert_index] = true; } @@ -429,10 +448,11 @@ void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh, MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totloop); + const Span<MPoly> polys = mesh.polys(); - threading::parallel_for(IndexRange(mesh.totpoly), 1024, [&](const IndexRange range) { + threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) { for (const int poly_index : range) { - const MPoly &poly = mesh.mpoly[poly_index]; + const MPoly &poly = polys[poly_index]; MutableSpan<T> poly_corner_values = r_values.slice(poly.loopstart, poly.totloop); poly_corner_values.fill(old_values[poly_index]); } @@ -459,13 +479,16 @@ void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh, MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totedge); + const Span<MPoly> polys = mesh.polys(); + const Span<MLoop> loops = mesh.loops(); + attribute_math::DefaultMixer<T> mixer(r_values); - for (const int poly_index : IndexRange(mesh.totpoly)) { - const MPoly &poly = mesh.mpoly[poly_index]; + for (const int poly_index : polys.index_range()) { + const MPoly &poly = polys[poly_index]; const T value = old_values[poly_index]; for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { - const MLoop &loop = mesh.mloop[loop_index]; + const MLoop &loop = loops[loop_index]; mixer.mix_in(loop.e, value); } } @@ -479,13 +502,15 @@ void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh, MutableSpan<bool> r_values) { BLI_assert(r_values.size() == mesh.totedge); + const Span<MPoly> polys = mesh.polys(); + const Span<MLoop> loops = mesh.loops(); r_values.fill(false); - for (const int poly_index : IndexRange(mesh.totpoly)) { - const MPoly &poly = mesh.mpoly[poly_index]; + for (const int poly_index : polys.index_range()) { + const MPoly &poly = polys[poly_index]; if (old_values[poly_index]) { for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { - const MLoop &loop = mesh.mloop[loop_index]; + const MLoop &loop = loops[loop_index]; const int edge_index = loop.e; r_values[edge_index] = true; } @@ -509,17 +534,20 @@ static GVArray adapt_mesh_domain_face_to_edge(const Mesh &mesh, const GVArray &v static GVArray adapt_mesh_domain_point_to_face(const Mesh &mesh, const GVArray &varray) { + const Span<MPoly> polys = mesh.polys(); + const Span<MLoop> loops = mesh.loops(); + GVArray new_varray; attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { if constexpr (std::is_same_v<T, bool>) { new_varray = VArray<T>::ForFunc( - mesh.totpoly, [&mesh, varray = varray.typed<bool>()](const int face_index) { + mesh.totpoly, [loops, polys, varray = varray.typed<bool>()](const int face_index) { /* A face is selected if all of its vertices were selected. */ - const MPoly &poly = mesh.mpoly[face_index]; + const MPoly &poly = polys[face_index]; for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { - const MLoop &loop = mesh.mloop[loop_index]; + const MLoop &loop = loops[loop_index]; if (!varray[loop.v]) { return false; } @@ -529,12 +557,12 @@ static GVArray adapt_mesh_domain_point_to_face(const Mesh &mesh, const GVArray & } else { new_varray = VArray<T>::ForFunc( - mesh.totpoly, [&mesh, varray = varray.typed<T>()](const int face_index) { + mesh.totpoly, [loops, polys, varray = varray.typed<T>()](const int face_index) { T return_value; attribute_math::DefaultMixer<T> mixer({&return_value, 1}); - const MPoly &poly = mesh.mpoly[face_index]; + const MPoly &poly = polys[face_index]; for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { - const MLoop &loop = mesh.mloop[loop_index]; + const MLoop &loop = loops[loop_index]; const T value = varray[loop.v]; mixer.mix_in(0, value); } @@ -549,6 +577,8 @@ static GVArray adapt_mesh_domain_point_to_face(const Mesh &mesh, const GVArray & static GVArray adapt_mesh_domain_point_to_edge(const Mesh &mesh, const GVArray &varray) { + const Span<MEdge> edges = mesh.edges(); + GVArray new_varray; attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); @@ -556,17 +586,17 @@ static GVArray adapt_mesh_domain_point_to_edge(const Mesh &mesh, const GVArray & if constexpr (std::is_same_v<T, bool>) { /* An edge is selected if both of its vertices were selected. */ new_varray = VArray<bool>::ForFunc( - mesh.totedge, [&mesh, varray = varray.typed<bool>()](const int edge_index) { - const MEdge &edge = mesh.medge[edge_index]; + edges.size(), [edges, varray = varray.typed<bool>()](const int edge_index) { + const MEdge &edge = edges[edge_index]; return varray[edge.v1] && varray[edge.v2]; }); } else { new_varray = VArray<T>::ForFunc( - mesh.totedge, [&mesh, varray = varray.typed<T>()](const int edge_index) { + edges.size(), [edges, varray = varray.typed<T>()](const int edge_index) { T return_value; attribute_math::DefaultMixer<T> mixer({&return_value, 1}); - const MEdge &edge = mesh.medge[edge_index]; + const MEdge &edge = edges[edge_index]; mixer.mix_in(0, varray[edge.v1]); mixer.mix_in(0, varray[edge.v2]); mixer.finalize(); @@ -584,16 +614,19 @@ void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh, MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totloop); + const Span<MPoly> polys = mesh.polys(); + const Span<MLoop> loops = mesh.loops(); + attribute_math::DefaultMixer<T> mixer(r_values); - for (const int poly_index : IndexRange(mesh.totpoly)) { - const MPoly &poly = mesh.mpoly[poly_index]; + for (const int poly_index : polys.index_range()) { + const MPoly &poly = polys[poly_index]; /* For every corner, mix the values from the adjacent edges on the face. */ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { const int loop_index_prev = loop_index - 1 + (loop_index == poly.loopstart) * poly.totloop; - const MLoop &loop = mesh.mloop[loop_index]; - const MLoop &loop_prev = mesh.mloop[loop_index_prev]; + const MLoop &loop = loops[loop_index]; + const MLoop &loop_prev = loops[loop_index_prev]; mixer.mix_in(loop_index, old_values[loop.e]); mixer.mix_in(loop_index, old_values[loop_prev.e]); } @@ -609,15 +642,17 @@ void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh, MutableSpan<bool> r_values) { BLI_assert(r_values.size() == mesh.totloop); + const Span<MPoly> polys = mesh.polys(); + const Span<MLoop> loops = mesh.loops(); r_values.fill(false); - for (const int poly_index : IndexRange(mesh.totpoly)) { - const MPoly &poly = mesh.mpoly[poly_index]; + for (const int poly_index : polys.index_range()) { + const MPoly &poly = polys[poly_index]; for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { const int loop_index_prev = loop_index - 1 + (loop_index == poly.loopstart) * poly.totloop; - const MLoop &loop = mesh.mloop[loop_index]; - const MLoop &loop_prev = mesh.mloop[loop_index_prev]; + const MLoop &loop = loops[loop_index]; + const MLoop &loop_prev = loops[loop_index_prev]; if (old_values[loop.e] && old_values[loop_prev.e]) { r_values[loop_index] = true; } @@ -645,10 +680,12 @@ static void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh, MutableSpan<T> r_values) { BLI_assert(r_values.size() == mesh.totvert); + const Span<MEdge> edges = mesh.edges(); + attribute_math::DefaultMixer<T> mixer(r_values); for (const int edge_index : IndexRange(mesh.totedge)) { - const MEdge &edge = mesh.medge[edge_index]; + const MEdge &edge = edges[edge_index]; const T value = old_values[edge_index]; mixer.mix_in(edge.v1, value); mixer.mix_in(edge.v2, value); @@ -664,10 +701,11 @@ void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh, MutableSpan<bool> r_values) { BLI_assert(r_values.size() == mesh.totvert); + const Span<MEdge> edges = mesh.edges(); r_values.fill(false); - for (const int edge_index : IndexRange(mesh.totedge)) { - const MEdge &edge = mesh.medge[edge_index]; + for (const int edge_index : edges.index_range()) { + const MEdge &edge = edges[edge_index]; if (old_values[edge_index]) { r_values[edge.v1] = true; r_values[edge.v2] = true; @@ -691,6 +729,9 @@ static GVArray adapt_mesh_domain_edge_to_point(const Mesh &mesh, const GVArray & static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &varray) { + const Span<MPoly> polys = mesh.polys(); + const Span<MLoop> loops = mesh.loops(); + GVArray new_varray; attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); @@ -698,10 +739,10 @@ static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &v if constexpr (std::is_same_v<T, bool>) { /* A face is selected if all of its edges are selected. */ new_varray = VArray<bool>::ForFunc( - mesh.totpoly, [&mesh, varray = varray.typed<T>()](const int face_index) { - const MPoly &poly = mesh.mpoly[face_index]; + polys.size(), [loops, polys, varray = varray.typed<T>()](const int face_index) { + const MPoly &poly = polys[face_index]; for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { - const MLoop &loop = mesh.mloop[loop_index]; + const MLoop &loop = loops[loop_index]; if (!varray[loop.e]) { return false; } @@ -711,12 +752,12 @@ static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &v } else { new_varray = VArray<T>::ForFunc( - mesh.totpoly, [&mesh, varray = varray.typed<T>()](const int face_index) { + polys.size(), [loops, polys, varray = varray.typed<T>()](const int face_index) { T return_value; attribute_math::DefaultMixer<T> mixer({&return_value, 1}); - const MPoly &poly = mesh.mpoly[face_index]; + const MPoly &poly = polys[face_index]; for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { - const MLoop &loop = mesh.mloop[loop_index]; + const MLoop &loop = loops[loop_index]; const T value = varray[loop.e]; mixer.mix_in(0, value); } @@ -843,16 +884,6 @@ static void tag_component_positions_changed(void *owner) } } -static int get_material_index(const MPoly &mpoly) -{ - return static_cast<int>(mpoly.mat_nr); -} - -static void set_material_index(MPoly &mpoly, int index) -{ - mpoly.mat_nr = static_cast<short>(std::clamp(index, 0, SHRT_MAX)); -} - static bool get_shade_smooth(const MPoly &mpoly) { return mpoly.flag & ME_SMOOTH; @@ -873,14 +904,14 @@ static void set_loop_uv(MLoopUV &uv, float2 co) copy_v2_v2(uv.uv, co); } -static float get_crease(const MEdge &edge) +static float get_crease(const float &crease) { - return edge.crease / 255.0f; + return crease; } -static void set_crease(MEdge &edge, float value) +static void set_crease(float &crease, const float value) { - edge.crease = round_fl_to_uchar_clamp(value * 255.0f); + crease = std::clamp(value, 0.0f, 1.0f); } class VArrayImpl_For_VertexWeights final : public VMutableArrayImpl<float> { @@ -889,8 +920,15 @@ class VArrayImpl_For_VertexWeights final : public VMutableArrayImpl<float> { const int dvert_index_; public: - VArrayImpl_For_VertexWeights(MDeformVert *dverts, const int totvert, const int dvert_index) - : VMutableArrayImpl<float>(totvert), dverts_(dverts), dvert_index_(dvert_index) + VArrayImpl_For_VertexWeights(MutableSpan<MDeformVert> dverts, const int dvert_index) + : VMutableArrayImpl<float>(dverts.size()), dverts_(dverts.data()), dvert_index_(dvert_index) + { + } + + VArrayImpl_For_VertexWeights(Span<MDeformVert> dverts, const int dvert_index) + : VMutableArrayImpl<float>(dverts.size()), + dverts_(const_cast<MDeformVert *>(dverts.data())), + dvert_index_(dvert_index) { } @@ -988,12 +1026,12 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { if (vertex_group_index < 0) { return {}; } - if (mesh->dvert == nullptr) { + const Span<MDeformVert> dverts = mesh->deform_verts(); + if (dverts.is_empty()) { static const float default_value = 0.0f; return {VArray<float>::ForSingle(default_value, mesh->totvert), ATTR_DOMAIN_POINT}; } - return {VArray<float>::For<VArrayImpl_For_VertexWeights>( - mesh->dvert, mesh->totvert, vertex_group_index), + return {VArray<float>::For<VArrayImpl_For_VertexWeights>(dverts, vertex_group_index), ATTR_DOMAIN_POINT}; } @@ -1013,16 +1051,8 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { if (vertex_group_index < 0) { return {}; } - if (mesh->dvert == nullptr) { - BKE_object_defgroup_data_create(&mesh->id); - } - else { - /* Copy the data layer if it is shared with some other mesh. */ - mesh->dvert = (MDeformVert *)CustomData_duplicate_referenced_layer( - &mesh->vdata, CD_MDEFORMVERT, mesh->totvert); - } - return {VMutableArray<float>::For<VArrayImpl_For_VertexWeights>( - mesh->dvert, mesh->totvert, vertex_group_index), + MutableSpan<MDeformVert> dverts = mesh->deform_verts_for_write(); + return {VMutableArray<float>::For<VArrayImpl_For_VertexWeights>(dverts, vertex_group_index), ATTR_DOMAIN_POINT}; } @@ -1045,15 +1075,11 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { } BLI_remlink(&mesh->vertex_group_names, group); MEM_freeN(group); - if (mesh->dvert == nullptr) { + if (mesh->deform_verts().is_empty()) { return true; } - /* Copy the data layer if it is shared with some other mesh. */ - mesh->dvert = (MDeformVert *)CustomData_duplicate_referenced_layer( - &mesh->vdata, CD_MDEFORMVERT, mesh->totvert); - - for (MDeformVert &dvert : MutableSpan(mesh->dvert, mesh->totvert)) { + for (MDeformVert &dvert : mesh->deform_verts_for_write()) { MDeformWeight *weight = BKE_defvert_find_index(&dvert, index); BKE_defvert_remove_group(&dvert, weight); for (MDeformWeight &weight : MutableSpan(dvert.dw, dvert.totweight)) { @@ -1134,11 +1160,6 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider { */ static ComponentAttributeProviders create_attribute_providers_for_mesh() { - static auto update_custom_data_pointers = [](void *owner) { - Mesh *mesh = static_cast<Mesh *>(owner); - BKE_mesh_update_customdata_pointers(mesh, false); - }; - #define MAKE_MUTABLE_CUSTOM_DATA_GETTER(NAME) \ [](void *owner) -> CustomData * { \ Mesh *mesh = static_cast<Mesh *>(owner); \ @@ -1157,20 +1178,16 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() static CustomDataAccessInfo corner_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(ldata), MAKE_CONST_CUSTOM_DATA_GETTER(ldata), - MAKE_GET_ELEMENT_NUM_GETTER(totloop), - update_custom_data_pointers}; + MAKE_GET_ELEMENT_NUM_GETTER(totloop)}; static CustomDataAccessInfo point_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(vdata), MAKE_CONST_CUSTOM_DATA_GETTER(vdata), - MAKE_GET_ELEMENT_NUM_GETTER(totvert), - update_custom_data_pointers}; + MAKE_GET_ELEMENT_NUM_GETTER(totvert)}; static CustomDataAccessInfo edge_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(edata), MAKE_CONST_CUSTOM_DATA_GETTER(edata), - MAKE_GET_ELEMENT_NUM_GETTER(totedge), - update_custom_data_pointers}; + MAKE_GET_ELEMENT_NUM_GETTER(totedge)}; static CustomDataAccessInfo face_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(pdata), MAKE_CONST_CUSTOM_DATA_GETTER(pdata), - MAKE_GET_ELEMENT_NUM_GETTER(totpoly), - update_custom_data_pointers}; + MAKE_GET_ELEMENT_NUM_GETTER(totpoly)}; #undef MAKE_CONST_CUSTOM_DATA_GETTER #undef MAKE_MUTABLE_CUSTOM_DATA_GETTER @@ -1202,18 +1219,25 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() make_array_write_attribute<int>, nullptr); - static BuiltinCustomDataLayerProvider material_index( - "material_index", - ATTR_DOMAIN_FACE, - CD_PROP_INT32, - CD_MPOLY, - BuiltinAttributeProvider::NonCreatable, - BuiltinAttributeProvider::Writable, - BuiltinAttributeProvider::NonDeletable, - face_access, - make_derived_read_attribute<MPoly, int, get_material_index>, - make_derived_write_attribute<MPoly, int, get_material_index, set_material_index>, - nullptr); + static const fn::CustomMF_SI_SO<int, int> material_index_clamp{ + "Material Index Validate", + [](int value) { + /* Use #short for the maximum since many areas still use that type for indices. */ + return std::clamp<int>(value, 0, std::numeric_limits<short>::max()); + }, + fn::CustomMF_presets::AllSpanOrSingle()}; + static BuiltinCustomDataLayerProvider material_index("material_index", + ATTR_DOMAIN_FACE, + CD_PROP_INT32, + CD_PROP_INT32, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::Deletable, + face_access, + make_array_read_attribute<int>, + make_array_write_attribute<int>, + nullptr, + AttributeValidator{&material_index_clamp}); static BuiltinCustomDataLayerProvider shade_smooth( "shade_smooth", @@ -1232,13 +1256,13 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() "crease", ATTR_DOMAIN_EDGE, CD_PROP_FLOAT, - CD_MEDGE, - BuiltinAttributeProvider::NonCreatable, + CD_CREASE, + BuiltinAttributeProvider::Creatable, BuiltinAttributeProvider::Writable, - BuiltinAttributeProvider::NonDeletable, + BuiltinAttributeProvider::Deletable, edge_access, - make_derived_read_attribute<MEdge, float, get_crease>, - make_derived_write_attribute<MEdge, float, get_crease, set_crease>, + make_array_read_attribute<float>, + make_derived_write_attribute<float, float, get_crease, set_crease>, nullptr); static NamedLegacyCustomDataProvider uvs( @@ -1310,18 +1334,19 @@ static const AttributeAccessorFunctions &get_mesh_accessor_functions_ref() return fn; } -AttributeAccessor mesh_attributes(const Mesh &mesh) +} // namespace blender::bke + +blender::bke::AttributeAccessor Mesh::attributes() const { - return AttributeAccessor(&mesh, get_mesh_accessor_functions_ref()); + return blender::bke::AttributeAccessor(this, blender::bke::get_mesh_accessor_functions_ref()); } -MutableAttributeAccessor mesh_attributes_for_write(Mesh &mesh) +blender::bke::MutableAttributeAccessor Mesh::attributes_for_write() { - return MutableAttributeAccessor(&mesh, get_mesh_accessor_functions_ref()); + return blender::bke::MutableAttributeAccessor(this, + blender::bke::get_mesh_accessor_functions_ref()); } -} // namespace blender::bke - std::optional<blender::bke::AttributeAccessor> MeshComponent::attributes() const { return blender::bke::AttributeAccessor(mesh_, blender::bke::get_mesh_accessor_functions_ref()); |