Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/geometry_component_mesh.cc
| Show First 20 Lines • Show All 169 Lines • ▼ Show 20 Lines | int MeshComponent::attribute_domain_size(const AttributeDomain domain) const | ||||
| } | } | ||||
| switch (domain) { | switch (domain) { | ||||
| case ATTR_DOMAIN_CORNER: | case ATTR_DOMAIN_CORNER: | ||||
| return mesh_->totloop; | return mesh_->totloop; | ||||
| case ATTR_DOMAIN_POINT: | case ATTR_DOMAIN_POINT: | ||||
| return mesh_->totvert; | return mesh_->totvert; | ||||
| case ATTR_DOMAIN_EDGE: | case ATTR_DOMAIN_EDGE: | ||||
| return mesh_->totedge; | return mesh_->totedge; | ||||
| case ATTR_DOMAIN_POLYGON: | case ATTR_DOMAIN_FACE: | ||||
| return mesh_->totpoly; | return mesh_->totpoly; | ||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| namespace blender::bke { | namespace blender::bke { | ||||
| ▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| /** | /** | ||||
| * \note Theoretically this interpolation does not need to compute all values at once. | * \note Theoretically this interpolation does not need to compute all values at once. | ||||
| * However, doing that makes the implementation simpler, and this can be optimized in the future if | * However, doing that makes the implementation simpler, and this can be optimized in the future if | ||||
| * only some values are required. | * only some values are required. | ||||
| */ | */ | ||||
| template<typename T> | template<typename T> | ||||
| static void adapt_mesh_domain_corner_to_polygon_impl(const Mesh &mesh, | static void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh, | ||||
| Span<T> old_values, | Span<T> old_values, | ||||
| MutableSpan<T> r_values) | MutableSpan<T> r_values) | ||||
| { | { | ||||
| BLI_assert(r_values.size() == mesh.totpoly); | BLI_assert(r_values.size() == mesh.totpoly); | ||||
| attribute_math::DefaultMixer<T> mixer(r_values); | attribute_math::DefaultMixer<T> mixer(r_values); | ||||
| for (const int poly_index : IndexRange(mesh.totpoly)) { | for (const int poly_index : IndexRange(mesh.totpoly)) { | ||||
| const MPoly &poly = mesh.mpoly[poly_index]; | const MPoly &poly = mesh.mpoly[poly_index]; | ||||
| for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { | for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { | ||||
| const T value = old_values[loop_index]; | const T value = old_values[loop_index]; | ||||
| mixer.mix_in(poly_index, value); | mixer.mix_in(poly_index, value); | ||||
| } | } | ||||
| } | } | ||||
| mixer.finalize(); | mixer.finalize(); | ||||
| } | } | ||||
| static ReadAttributePtr adapt_mesh_domain_corner_to_polygon(const Mesh &mesh, | static ReadAttributePtr adapt_mesh_domain_corner_to_face(const Mesh &mesh, | ||||
| ReadAttributePtr attribute) | ReadAttributePtr attribute) | ||||
| { | { | ||||
| ReadAttributePtr new_attribute; | ReadAttributePtr new_attribute; | ||||
| const CustomDataType data_type = attribute->custom_data_type(); | const CustomDataType data_type = attribute->custom_data_type(); | ||||
| attribute_math::convert_to_static_type(data_type, [&](auto dummy) { | attribute_math::convert_to_static_type(data_type, [&](auto dummy) { | ||||
| using T = decltype(dummy); | using T = decltype(dummy); | ||||
| if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { | if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { | ||||
| Array<T> values(mesh.totpoly); | Array<T> values(mesh.totpoly); | ||||
| adapt_mesh_domain_corner_to_polygon_impl<T>(mesh, attribute->get_span<T>(), values); | adapt_mesh_domain_corner_to_face_impl<T>(mesh, attribute->get_span<T>(), values); | ||||
| new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, | new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, | ||||
| std::move(values)); | std::move(values)); | ||||
| } | } | ||||
| }); | }); | ||||
| return new_attribute; | return new_attribute; | ||||
| } | } | ||||
| template<typename T> | template<typename T> | ||||
| Show All 33 Lines | if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { | ||||
| new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, | new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, | ||||
| std::move(values)); | std::move(values)); | ||||
| } | } | ||||
| }); | }); | ||||
| return new_attribute; | return new_attribute; | ||||
| } | } | ||||
| template<typename T> | template<typename T> | ||||
| void adapt_mesh_domain_polygon_to_point_impl(const Mesh &mesh, | void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh, | ||||
| Span<T> old_values, | Span<T> old_values, | ||||
| MutableSpan<T> r_values) | MutableSpan<T> r_values) | ||||
| { | { | ||||
| BLI_assert(r_values.size() == mesh.totvert); | BLI_assert(r_values.size() == mesh.totvert); | ||||
| attribute_math::DefaultMixer<T> mixer(r_values); | attribute_math::DefaultMixer<T> mixer(r_values); | ||||
| for (const int poly_index : IndexRange(mesh.totpoly)) { | for (const int poly_index : IndexRange(mesh.totpoly)) { | ||||
| const MPoly &poly = mesh.mpoly[poly_index]; | const MPoly &poly = mesh.mpoly[poly_index]; | ||||
| const T value = old_values[poly_index]; | const T value = old_values[poly_index]; | ||||
| for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { | for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { | ||||
| const MLoop &loop = mesh.mloop[loop_index]; | const MLoop &loop = mesh.mloop[loop_index]; | ||||
| const int point_index = loop.v; | const int point_index = loop.v; | ||||
| mixer.mix_in(point_index, value); | mixer.mix_in(point_index, value); | ||||
| } | } | ||||
| } | } | ||||
| mixer.finalize(); | mixer.finalize(); | ||||
| } | } | ||||
| static ReadAttributePtr adapt_mesh_domain_polygon_to_point(const Mesh &mesh, | static ReadAttributePtr adapt_mesh_domain_face_to_point(const Mesh &mesh, | ||||
| ReadAttributePtr attribute) | ReadAttributePtr attribute) | ||||
| { | { | ||||
| ReadAttributePtr new_attribute; | ReadAttributePtr new_attribute; | ||||
| const CustomDataType data_type = attribute->custom_data_type(); | const CustomDataType data_type = attribute->custom_data_type(); | ||||
| attribute_math::convert_to_static_type(data_type, [&](auto dummy) { | attribute_math::convert_to_static_type(data_type, [&](auto dummy) { | ||||
| using T = decltype(dummy); | using T = decltype(dummy); | ||||
| if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { | if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { | ||||
| Array<T> values(mesh.totvert); | Array<T> values(mesh.totvert); | ||||
| adapt_mesh_domain_polygon_to_point_impl<T>(mesh, attribute->get_span<T>(), values); | adapt_mesh_domain_face_to_point_impl<T>(mesh, attribute->get_span<T>(), values); | ||||
| new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, | new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, | ||||
| std::move(values)); | std::move(values)); | ||||
| } | } | ||||
| }); | }); | ||||
| return new_attribute; | return new_attribute; | ||||
| } | } | ||||
| template<typename T> | template<typename T> | ||||
| void adapt_mesh_domain_polygon_to_corner_impl(const Mesh &mesh, | void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh, | ||||
| const Span<T> old_values, | const Span<T> old_values, | ||||
| MutableSpan<T> r_values) | MutableSpan<T> r_values) | ||||
| { | { | ||||
| BLI_assert(r_values.size() == mesh.totloop); | BLI_assert(r_values.size() == mesh.totloop); | ||||
| for (const int poly_index : IndexRange(mesh.totpoly)) { | for (const int poly_index : IndexRange(mesh.totpoly)) { | ||||
| const MPoly &poly = mesh.mpoly[poly_index]; | const MPoly &poly = mesh.mpoly[poly_index]; | ||||
| MutableSpan<T> poly_corner_values = r_values.slice(poly.loopstart, poly.totloop); | MutableSpan<T> poly_corner_values = r_values.slice(poly.loopstart, poly.totloop); | ||||
| poly_corner_values.fill(old_values[poly_index]); | poly_corner_values.fill(old_values[poly_index]); | ||||
| } | } | ||||
| } | } | ||||
| static ReadAttributePtr adapt_mesh_domain_polygon_to_corner(const Mesh &mesh, | static ReadAttributePtr adapt_mesh_domain_face_to_corner(const Mesh &mesh, | ||||
| ReadAttributePtr attribute) | ReadAttributePtr attribute) | ||||
| { | { | ||||
| ReadAttributePtr new_attribute; | ReadAttributePtr new_attribute; | ||||
| const CustomDataType data_type = attribute->custom_data_type(); | const CustomDataType data_type = attribute->custom_data_type(); | ||||
| attribute_math::convert_to_static_type(data_type, [&](auto dummy) { | attribute_math::convert_to_static_type(data_type, [&](auto dummy) { | ||||
| using T = decltype(dummy); | using T = decltype(dummy); | ||||
| if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { | if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { | ||||
| Array<T> values(mesh.totloop); | Array<T> values(mesh.totloop); | ||||
| adapt_mesh_domain_polygon_to_corner_impl<T>(mesh, attribute->get_span<T>(), values); | adapt_mesh_domain_face_to_corner_impl<T>(mesh, attribute->get_span<T>(), values); | ||||
| new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, | new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, | ||||
| std::move(values)); | std::move(values)); | ||||
| } | } | ||||
| }); | }); | ||||
| return new_attribute; | return new_attribute; | ||||
| } | } | ||||
| template<typename T> | template<typename T> | ||||
| void adapt_mesh_domain_polygon_to_edge_impl(const Mesh &mesh, | void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh, | ||||
| const Span<T> old_values, | const Span<T> old_values, | ||||
| MutableSpan<T> r_values) | MutableSpan<T> r_values) | ||||
| { | { | ||||
| BLI_assert(r_values.size() == mesh.totedge); | BLI_assert(r_values.size() == mesh.totedge); | ||||
| attribute_math::DefaultMixer<T> mixer(r_values); | attribute_math::DefaultMixer<T> mixer(r_values); | ||||
| for (const int poly_index : IndexRange(mesh.totpoly)) { | for (const int poly_index : IndexRange(mesh.totpoly)) { | ||||
| const MPoly &poly = mesh.mpoly[poly_index]; | const MPoly &poly = mesh.mpoly[poly_index]; | ||||
| const T value = old_values[poly_index]; | const T value = old_values[poly_index]; | ||||
| for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { | for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { | ||||
| const MLoop &loop = mesh.mloop[loop_index]; | const MLoop &loop = mesh.mloop[loop_index]; | ||||
| mixer.mix_in(loop.e, value); | mixer.mix_in(loop.e, value); | ||||
| } | } | ||||
| } | } | ||||
| mixer.finalize(); | mixer.finalize(); | ||||
| } | } | ||||
| static ReadAttributePtr adapt_mesh_domain_polygon_to_edge(const Mesh &mesh, | static ReadAttributePtr adapt_mesh_domain_face_to_edge(const Mesh &mesh, | ||||
| ReadAttributePtr attribute) | ReadAttributePtr attribute) | ||||
| { | { | ||||
| ReadAttributePtr new_attribute; | ReadAttributePtr new_attribute; | ||||
| const CustomDataType data_type = attribute->custom_data_type(); | const CustomDataType data_type = attribute->custom_data_type(); | ||||
| attribute_math::convert_to_static_type(data_type, [&](auto dummy) { | attribute_math::convert_to_static_type(data_type, [&](auto dummy) { | ||||
| using T = decltype(dummy); | using T = decltype(dummy); | ||||
| if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { | if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { | ||||
| Array<T> values(mesh.totedge); | Array<T> values(mesh.totedge); | ||||
| adapt_mesh_domain_polygon_to_edge_impl<T>(mesh, attribute->get_span<T>(), values); | adapt_mesh_domain_face_to_edge_impl<T>(mesh, attribute->get_span<T>(), values); | ||||
| new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, | new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, | ||||
| std::move(values)); | std::move(values)); | ||||
| } | } | ||||
| }); | }); | ||||
| return new_attribute; | return new_attribute; | ||||
| } | } | ||||
| /** | /** | ||||
| * \note Theoretically this interpolation does not need to compute all values at once. | * \note Theoretically this interpolation does not need to compute all values at once. | ||||
| * However, doing that makes the implementation simpler, and this can be optimized in the future if | * However, doing that makes the implementation simpler, and this can be optimized in the future if | ||||
| * only some values are required. | * only some values are required. | ||||
| */ | */ | ||||
| template<typename T> | template<typename T> | ||||
| static void adapt_mesh_domain_point_to_polygon_impl(const Mesh &mesh, | static void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh, | ||||
| const Span<T> old_values, | const Span<T> old_values, | ||||
| MutableSpan<T> r_values) | MutableSpan<T> r_values) | ||||
| { | { | ||||
| BLI_assert(r_values.size() == mesh.totpoly); | BLI_assert(r_values.size() == mesh.totpoly); | ||||
| attribute_math::DefaultMixer<T> mixer(r_values); | attribute_math::DefaultMixer<T> mixer(r_values); | ||||
| for (const int poly_index : IndexRange(mesh.totpoly)) { | for (const int poly_index : IndexRange(mesh.totpoly)) { | ||||
| const MPoly &poly = mesh.mpoly[poly_index]; | const MPoly &poly = mesh.mpoly[poly_index]; | ||||
| for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { | for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { | ||||
| MLoop &loop = mesh.mloop[loop_index]; | MLoop &loop = mesh.mloop[loop_index]; | ||||
| const int point_index = loop.v; | const int point_index = loop.v; | ||||
| mixer.mix_in(poly_index, old_values[point_index]); | mixer.mix_in(poly_index, old_values[point_index]); | ||||
| } | } | ||||
| } | } | ||||
| mixer.finalize(); | mixer.finalize(); | ||||
| } | } | ||||
| static ReadAttributePtr adapt_mesh_domain_point_to_polygon(const Mesh &mesh, | static ReadAttributePtr adapt_mesh_domain_point_to_face(const Mesh &mesh, | ||||
| ReadAttributePtr attribute) | ReadAttributePtr attribute) | ||||
| { | { | ||||
| ReadAttributePtr new_attribute; | ReadAttributePtr new_attribute; | ||||
| const CustomDataType data_type = attribute->custom_data_type(); | const CustomDataType data_type = attribute->custom_data_type(); | ||||
| attribute_math::convert_to_static_type(data_type, [&](auto dummy) { | attribute_math::convert_to_static_type(data_type, [&](auto dummy) { | ||||
| using T = decltype(dummy); | using T = decltype(dummy); | ||||
| if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { | if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { | ||||
| Array<T> values(mesh.totpoly); | Array<T> values(mesh.totpoly); | ||||
| adapt_mesh_domain_point_to_polygon_impl<T>(mesh, attribute->get_span<T>(), values); | adapt_mesh_domain_point_to_face_impl<T>(mesh, attribute->get_span<T>(), values); | ||||
| new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, | new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, | ||||
| std::move(values)); | std::move(values)); | ||||
| } | } | ||||
| }); | }); | ||||
| return new_attribute; | return new_attribute; | ||||
| } | } | ||||
| /** | /** | ||||
| ▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh, | ||||
| MutableSpan<T> r_values) | MutableSpan<T> r_values) | ||||
| { | { | ||||
| BLI_assert(r_values.size() == mesh.totloop); | BLI_assert(r_values.size() == mesh.totloop); | ||||
| attribute_math::DefaultMixer<T> mixer(r_values); | attribute_math::DefaultMixer<T> mixer(r_values); | ||||
| for (const int poly_index : IndexRange(mesh.totpoly)) { | for (const int poly_index : IndexRange(mesh.totpoly)) { | ||||
| const MPoly &poly = mesh.mpoly[poly_index]; | const MPoly &poly = mesh.mpoly[poly_index]; | ||||
| /* For every corner, mix the values from the adjacent edges on the polygon. */ | /* For every corner, mix the values from the adjacent edges on the face. */ | ||||
| for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { | for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { | ||||
| const int loop_index_prev = (loop_index - 1) % poly.totloop; | const int loop_index_prev = (loop_index - 1) % poly.totloop; | ||||
| const MLoop &loop = mesh.mloop[loop_index]; | const MLoop &loop = mesh.mloop[loop_index]; | ||||
| const MLoop &loop_prev = mesh.mloop[loop_index_prev]; | const MLoop &loop_prev = mesh.mloop[loop_index_prev]; | ||||
| mixer.mix_in(loop_index, old_values[loop.e]); | mixer.mix_in(loop_index, old_values[loop.e]); | ||||
| mixer.mix_in(loop_index, old_values[loop_prev.e]); | mixer.mix_in(loop_index, old_values[loop_prev.e]); | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| /** | /** | ||||
| * \note Theoretically this interpolation does not need to compute all values at once. | * \note Theoretically this interpolation does not need to compute all values at once. | ||||
| * However, doing that makes the implementation simpler, and this can be optimized in the future if | * However, doing that makes the implementation simpler, and this can be optimized in the future if | ||||
| * only some values are required. | * only some values are required. | ||||
| */ | */ | ||||
| template<typename T> | template<typename T> | ||||
| static void adapt_mesh_domain_edge_to_polygon_impl(const Mesh &mesh, | static void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh, | ||||
| const Span<T> old_values, | const Span<T> old_values, | ||||
| MutableSpan<T> r_values) | MutableSpan<T> r_values) | ||||
| { | { | ||||
| BLI_assert(r_values.size() == mesh.totpoly); | BLI_assert(r_values.size() == mesh.totpoly); | ||||
| attribute_math::DefaultMixer<T> mixer(r_values); | attribute_math::DefaultMixer<T> mixer(r_values); | ||||
| for (const int poly_index : IndexRange(mesh.totpoly)) { | for (const int poly_index : IndexRange(mesh.totpoly)) { | ||||
| const MPoly &poly = mesh.mpoly[poly_index]; | const MPoly &poly = mesh.mpoly[poly_index]; | ||||
| for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { | for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { | ||||
| const MLoop &loop = mesh.mloop[loop_index]; | const MLoop &loop = mesh.mloop[loop_index]; | ||||
| mixer.mix_in(poly_index, old_values[loop.e]); | mixer.mix_in(poly_index, old_values[loop.e]); | ||||
| } | } | ||||
| } | } | ||||
| mixer.finalize(); | mixer.finalize(); | ||||
| } | } | ||||
| static ReadAttributePtr adapt_mesh_domain_edge_to_polygon(const Mesh &mesh, | static ReadAttributePtr adapt_mesh_domain_edge_to_face(const Mesh &mesh, | ||||
| ReadAttributePtr attribute) | ReadAttributePtr attribute) | ||||
| { | { | ||||
| ReadAttributePtr new_attribute; | ReadAttributePtr new_attribute; | ||||
| const CustomDataType data_type = attribute->custom_data_type(); | const CustomDataType data_type = attribute->custom_data_type(); | ||||
| attribute_math::convert_to_static_type(data_type, [&](auto dummy) { | attribute_math::convert_to_static_type(data_type, [&](auto dummy) { | ||||
| using T = decltype(dummy); | using T = decltype(dummy); | ||||
| if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { | if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { | ||||
| Array<T> values(mesh.totpoly); | Array<T> values(mesh.totpoly); | ||||
| adapt_mesh_domain_edge_to_polygon_impl<T>(mesh, attribute->get_span<T>(), values); | adapt_mesh_domain_edge_to_face_impl<T>(mesh, attribute->get_span<T>(), values); | ||||
| new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, | new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, | ||||
| std::move(values)); | std::move(values)); | ||||
| } | } | ||||
| }); | }); | ||||
| return new_attribute; | return new_attribute; | ||||
| } | } | ||||
| } // namespace blender::bke | } // namespace blender::bke | ||||
| Show All 12 Lines | if (old_domain == new_domain) { | ||||
| return attribute; | return attribute; | ||||
| } | } | ||||
| switch (old_domain) { | switch (old_domain) { | ||||
| case ATTR_DOMAIN_CORNER: { | case ATTR_DOMAIN_CORNER: { | ||||
| switch (new_domain) { | switch (new_domain) { | ||||
| case ATTR_DOMAIN_POINT: | case ATTR_DOMAIN_POINT: | ||||
| return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(attribute)); | return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(attribute)); | ||||
| case ATTR_DOMAIN_POLYGON: | case ATTR_DOMAIN_FACE: | ||||
| return blender::bke::adapt_mesh_domain_corner_to_polygon(*mesh_, std::move(attribute)); | return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, std::move(attribute)); | ||||
| case ATTR_DOMAIN_EDGE: | case ATTR_DOMAIN_EDGE: | ||||
| return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, std::move(attribute)); | return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, std::move(attribute)); | ||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case ATTR_DOMAIN_POINT: { | case ATTR_DOMAIN_POINT: { | ||||
| switch (new_domain) { | switch (new_domain) { | ||||
| case ATTR_DOMAIN_CORNER: | case ATTR_DOMAIN_CORNER: | ||||
| return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(attribute)); | return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(attribute)); | ||||
| case ATTR_DOMAIN_POLYGON: | case ATTR_DOMAIN_FACE: | ||||
| return blender::bke::adapt_mesh_domain_point_to_polygon(*mesh_, std::move(attribute)); | return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, std::move(attribute)); | ||||
| case ATTR_DOMAIN_EDGE: | case ATTR_DOMAIN_EDGE: | ||||
| return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, std::move(attribute)); | return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, std::move(attribute)); | ||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case ATTR_DOMAIN_POLYGON: { | case ATTR_DOMAIN_FACE: { | ||||
| switch (new_domain) { | switch (new_domain) { | ||||
| case ATTR_DOMAIN_POINT: | case ATTR_DOMAIN_POINT: | ||||
| return blender::bke::adapt_mesh_domain_polygon_to_point(*mesh_, std::move(attribute)); | return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, std::move(attribute)); | ||||
| case ATTR_DOMAIN_CORNER: | case ATTR_DOMAIN_CORNER: | ||||
| return blender::bke::adapt_mesh_domain_polygon_to_corner(*mesh_, std::move(attribute)); | return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, std::move(attribute)); | ||||
| case ATTR_DOMAIN_EDGE: | case ATTR_DOMAIN_EDGE: | ||||
| return blender::bke::adapt_mesh_domain_polygon_to_edge(*mesh_, std::move(attribute)); | return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, std::move(attribute)); | ||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case ATTR_DOMAIN_EDGE: { | case ATTR_DOMAIN_EDGE: { | ||||
| switch (new_domain) { | switch (new_domain) { | ||||
| case ATTR_DOMAIN_CORNER: | case ATTR_DOMAIN_CORNER: | ||||
| return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, std::move(attribute)); | return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, std::move(attribute)); | ||||
| case ATTR_DOMAIN_POINT: | case ATTR_DOMAIN_POINT: | ||||
| return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, std::move(attribute)); | return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, std::move(attribute)); | ||||
| case ATTR_DOMAIN_POLYGON: | case ATTR_DOMAIN_FACE: | ||||
| return blender::bke::adapt_mesh_domain_edge_to_polygon(*mesh_, std::move(attribute)); | return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, std::move(attribute)); | ||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | |||||
| static void set_material_index(MPoly &mpoly, const int &index) | static void set_material_index(MPoly &mpoly, const int &index) | ||||
| { | { | ||||
| mpoly.mat_nr = static_cast<short>(std::clamp(index, 0, SHRT_MAX)); | mpoly.mat_nr = static_cast<short>(std::clamp(index, 0, SHRT_MAX)); | ||||
| } | } | ||||
| static ReadAttributePtr make_material_index_read_attribute(const void *data, const int domain_size) | static ReadAttributePtr make_material_index_read_attribute(const void *data, const int domain_size) | ||||
| { | { | ||||
| return std::make_unique<DerivedArrayReadAttribute<MPoly, int, get_material_index>>( | return std::make_unique<DerivedArrayReadAttribute<MPoly, int, get_material_index>>( | ||||
| ATTR_DOMAIN_POLYGON, Span<MPoly>((const MPoly *)data, domain_size)); | ATTR_DOMAIN_FACE, Span<MPoly>((const MPoly *)data, domain_size)); | ||||
| } | } | ||||
| static WriteAttributePtr make_material_index_write_attribute(void *data, const int domain_size) | static WriteAttributePtr make_material_index_write_attribute(void *data, const int domain_size) | ||||
| { | { | ||||
| return std::make_unique< | return std::make_unique< | ||||
| DerivedArrayWriteAttribute<MPoly, int, get_material_index, set_material_index>>( | DerivedArrayWriteAttribute<MPoly, int, get_material_index, set_material_index>>( | ||||
| ATTR_DOMAIN_POLYGON, MutableSpan<MPoly>((MPoly *)data, domain_size)); | ATTR_DOMAIN_FACE, MutableSpan<MPoly>((MPoly *)data, domain_size)); | ||||
| } | } | ||||
| static bool get_shade_smooth(const MPoly &mpoly) | static bool get_shade_smooth(const MPoly &mpoly) | ||||
| { | { | ||||
| return mpoly.flag & ME_SMOOTH; | return mpoly.flag & ME_SMOOTH; | ||||
| } | } | ||||
| static void set_shade_smooth(MPoly &mpoly, const bool &value) | static void set_shade_smooth(MPoly &mpoly, const bool &value) | ||||
| { | { | ||||
| SET_FLAG_FROM_TEST(mpoly.flag, value, ME_SMOOTH); | SET_FLAG_FROM_TEST(mpoly.flag, value, ME_SMOOTH); | ||||
| } | } | ||||
| static ReadAttributePtr make_shade_smooth_read_attribute(const void *data, const int domain_size) | static ReadAttributePtr make_shade_smooth_read_attribute(const void *data, const int domain_size) | ||||
| { | { | ||||
| return std::make_unique<DerivedArrayReadAttribute<MPoly, bool, get_shade_smooth>>( | return std::make_unique<DerivedArrayReadAttribute<MPoly, bool, get_shade_smooth>>( | ||||
| ATTR_DOMAIN_POLYGON, Span<MPoly>((const MPoly *)data, domain_size)); | ATTR_DOMAIN_FACE, Span<MPoly>((const MPoly *)data, domain_size)); | ||||
| } | } | ||||
| static WriteAttributePtr make_shade_smooth_write_attribute(void *data, const int domain_size) | static WriteAttributePtr make_shade_smooth_write_attribute(void *data, const int domain_size) | ||||
| { | { | ||||
| return std::make_unique< | return std::make_unique< | ||||
| DerivedArrayWriteAttribute<MPoly, bool, get_shade_smooth, set_shade_smooth>>( | DerivedArrayWriteAttribute<MPoly, bool, get_shade_smooth, set_shade_smooth>>( | ||||
| ATTR_DOMAIN_POLYGON, MutableSpan<MPoly>((MPoly *)data, domain_size)); | ATTR_DOMAIN_FACE, MutableSpan<MPoly>((MPoly *)data, domain_size)); | ||||
| } | } | ||||
| static float2 get_loop_uv(const MLoopUV &uv) | static float2 get_loop_uv(const MLoopUV &uv) | ||||
| { | { | ||||
| return float2(uv.uv); | return float2(uv.uv); | ||||
| } | } | ||||
| static void set_loop_uv(MLoopUV &uv, const float2 &co) | static void set_loop_uv(MLoopUV &uv, const float2 &co) | ||||
| ▲ Show 20 Lines • Show All 224 Lines • ▼ Show 20 Lines | |||||
| /** | /** | ||||
| * This provider makes face normals available as a read-only float3 attribute. | * This provider makes face normals available as a read-only float3 attribute. | ||||
| */ | */ | ||||
| class NormalAttributeProvider final : public BuiltinAttributeProvider { | class NormalAttributeProvider final : public BuiltinAttributeProvider { | ||||
| public: | public: | ||||
| NormalAttributeProvider() | NormalAttributeProvider() | ||||
| : BuiltinAttributeProvider( | : BuiltinAttributeProvider( | ||||
| "normal", ATTR_DOMAIN_POLYGON, CD_PROP_FLOAT3, NonCreatable, Readonly, NonDeletable) | "normal", ATTR_DOMAIN_FACE, CD_PROP_FLOAT3, NonCreatable, Readonly, NonDeletable) | ||||
| { | { | ||||
| } | } | ||||
| ReadAttributePtr try_get_for_read(const GeometryComponent &component) const final | ReadAttributePtr try_get_for_read(const GeometryComponent &component) const final | ||||
| { | { | ||||
| const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); | const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); | ||||
| const Mesh *mesh = mesh_component.get_for_read(); | const Mesh *mesh = mesh_component.get_for_read(); | ||||
| if (mesh == nullptr) { | if (mesh == nullptr) { | ||||
| return {}; | return {}; | ||||
| } | } | ||||
| /* Use existing normals if possible. */ | /* Use existing normals if possible. */ | ||||
| if (!(mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL) && | if (!(mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL) && | ||||
| CustomData_has_layer(&mesh->pdata, CD_NORMAL)) { | CustomData_has_layer(&mesh->pdata, CD_NORMAL)) { | ||||
| const void *data = CustomData_get_layer(&mesh->pdata, CD_NORMAL); | const void *data = CustomData_get_layer(&mesh->pdata, CD_NORMAL); | ||||
| return std::make_unique<ArrayReadAttribute<float3>>( | return std::make_unique<ArrayReadAttribute<float3>>( | ||||
| ATTR_DOMAIN_POLYGON, Span<float3>((const float3 *)data, mesh->totpoly)); | ATTR_DOMAIN_FACE, Span<float3>((const float3 *)data, mesh->totpoly)); | ||||
| } | } | ||||
| Array<float3> normals(mesh->totpoly); | Array<float3> normals(mesh->totpoly); | ||||
| for (const int i : IndexRange(mesh->totpoly)) { | for (const int i : IndexRange(mesh->totpoly)) { | ||||
| const MPoly *poly = &mesh->mpoly[i]; | const MPoly *poly = &mesh->mpoly[i]; | ||||
| BKE_mesh_calc_poly_normal(poly, &mesh->mloop[poly->loopstart], mesh->mvert, normals[i]); | BKE_mesh_calc_poly_normal(poly, &mesh->mloop[poly->loopstart], mesh->mvert, normals[i]); | ||||
| } | } | ||||
| return std::make_unique<OwnedArrayReadAttribute<float3>>(ATTR_DOMAIN_POLYGON, | return std::make_unique<OwnedArrayReadAttribute<float3>>(ATTR_DOMAIN_FACE, std::move(normals)); | ||||
| std::move(normals)); | |||||
| } | } | ||||
| WriteAttributePtr try_get_for_write(GeometryComponent &UNUSED(component)) const final | WriteAttributePtr try_get_for_write(GeometryComponent &UNUSED(component)) const final | ||||
| { | { | ||||
| return {}; | return {}; | ||||
| } | } | ||||
| bool try_delete(GeometryComponent &UNUSED(component)) const final | bool try_delete(GeometryComponent &UNUSED(component)) const final | ||||
| { | { | ||||
| return false; | return false; | ||||
| } | } | ||||
| bool try_create(GeometryComponent &UNUSED(component)) const final | bool try_create(GeometryComponent &UNUSED(component)) const final | ||||
| { | { | ||||
| return false; | return false; | ||||
| } | } | ||||
| bool exists(const GeometryComponent &component) const final | bool exists(const GeometryComponent &component) const final | ||||
| { | { | ||||
| return component.attribute_domain_size(ATTR_DOMAIN_POLYGON) != 0; | return component.attribute_domain_size(ATTR_DOMAIN_FACE) != 0; | ||||
| } | } | ||||
| }; | }; | ||||
| /** | /** | ||||
| * In this function all the attribute providers for a mesh component are created. Most data in this | * In this function all the attribute providers for a mesh component are created. Most data in this | ||||
| * function is statically allocated, because it does not change over time. | * function is statically allocated, because it does not change over time. | ||||
| */ | */ | ||||
| static ComponentAttributeProviders create_attribute_providers_for_mesh() | static ComponentAttributeProviders create_attribute_providers_for_mesh() | ||||
| Show All 20 Lines | static CustomDataAccessInfo corner_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(ldata), | ||||
| MAKE_CONST_CUSTOM_DATA_GETTER(ldata), | MAKE_CONST_CUSTOM_DATA_GETTER(ldata), | ||||
| update_custom_data_pointers}; | update_custom_data_pointers}; | ||||
| static CustomDataAccessInfo point_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(vdata), | static CustomDataAccessInfo point_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(vdata), | ||||
| MAKE_CONST_CUSTOM_DATA_GETTER(vdata), | MAKE_CONST_CUSTOM_DATA_GETTER(vdata), | ||||
| update_custom_data_pointers}; | update_custom_data_pointers}; | ||||
| static CustomDataAccessInfo edge_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(edata), | static CustomDataAccessInfo edge_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(edata), | ||||
| MAKE_CONST_CUSTOM_DATA_GETTER(edata), | MAKE_CONST_CUSTOM_DATA_GETTER(edata), | ||||
| update_custom_data_pointers}; | update_custom_data_pointers}; | ||||
| static CustomDataAccessInfo polygon_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(pdata), | static CustomDataAccessInfo face_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(pdata), | ||||
| MAKE_CONST_CUSTOM_DATA_GETTER(pdata), | MAKE_CONST_CUSTOM_DATA_GETTER(pdata), | ||||
| update_custom_data_pointers}; | update_custom_data_pointers}; | ||||
| #undef MAKE_CONST_CUSTOM_DATA_GETTER | #undef MAKE_CONST_CUSTOM_DATA_GETTER | ||||
| #undef MAKE_MUTABLE_CUSTOM_DATA_GETTER | #undef MAKE_MUTABLE_CUSTOM_DATA_GETTER | ||||
| static BuiltinCustomDataLayerProvider position("position", | static BuiltinCustomDataLayerProvider position("position", | ||||
| ATTR_DOMAIN_POINT, | ATTR_DOMAIN_POINT, | ||||
| CD_PROP_FLOAT3, | CD_PROP_FLOAT3, | ||||
| CD_MVERT, | CD_MVERT, | ||||
| BuiltinAttributeProvider::NonCreatable, | BuiltinAttributeProvider::NonCreatable, | ||||
| BuiltinAttributeProvider::Writable, | BuiltinAttributeProvider::Writable, | ||||
| BuiltinAttributeProvider::NonDeletable, | BuiltinAttributeProvider::NonDeletable, | ||||
| point_access, | point_access, | ||||
| make_vertex_position_read_attribute, | make_vertex_position_read_attribute, | ||||
| make_vertex_position_write_attribute, | make_vertex_position_write_attribute, | ||||
| tag_normals_dirty_when_writing_position); | tag_normals_dirty_when_writing_position); | ||||
| static NormalAttributeProvider normal; | static NormalAttributeProvider normal; | ||||
| static BuiltinCustomDataLayerProvider material_index("material_index", | static BuiltinCustomDataLayerProvider material_index("material_index", | ||||
| ATTR_DOMAIN_POLYGON, | ATTR_DOMAIN_FACE, | ||||
| CD_PROP_INT32, | CD_PROP_INT32, | ||||
| CD_MPOLY, | CD_MPOLY, | ||||
| BuiltinAttributeProvider::NonCreatable, | BuiltinAttributeProvider::NonCreatable, | ||||
| BuiltinAttributeProvider::Writable, | BuiltinAttributeProvider::Writable, | ||||
| BuiltinAttributeProvider::NonDeletable, | BuiltinAttributeProvider::NonDeletable, | ||||
| polygon_access, | face_access, | ||||
| make_material_index_read_attribute, | make_material_index_read_attribute, | ||||
| make_material_index_write_attribute, | make_material_index_write_attribute, | ||||
| nullptr); | nullptr); | ||||
| static BuiltinCustomDataLayerProvider shade_smooth("shade_smooth", | static BuiltinCustomDataLayerProvider shade_smooth("shade_smooth", | ||||
| ATTR_DOMAIN_POLYGON, | ATTR_DOMAIN_FACE, | ||||
| CD_PROP_BOOL, | CD_PROP_BOOL, | ||||
| CD_MPOLY, | CD_MPOLY, | ||||
| BuiltinAttributeProvider::NonCreatable, | BuiltinAttributeProvider::NonCreatable, | ||||
| BuiltinAttributeProvider::Writable, | BuiltinAttributeProvider::Writable, | ||||
| BuiltinAttributeProvider::NonDeletable, | BuiltinAttributeProvider::NonDeletable, | ||||
| polygon_access, | face_access, | ||||
| make_shade_smooth_read_attribute, | make_shade_smooth_read_attribute, | ||||
| make_shade_smooth_write_attribute, | make_shade_smooth_write_attribute, | ||||
| nullptr); | nullptr); | ||||
| static BuiltinCustomDataLayerProvider crease("crease", | static BuiltinCustomDataLayerProvider crease("crease", | ||||
| ATTR_DOMAIN_EDGE, | ATTR_DOMAIN_EDGE, | ||||
| CD_PROP_FLOAT, | CD_PROP_FLOAT, | ||||
| CD_MEDGE, | CD_MEDGE, | ||||
| Show All 18 Lines | static NamedLegacyCustomDataProvider vertex_colors(ATTR_DOMAIN_CORNER, | ||||
| corner_access, | corner_access, | ||||
| make_vertex_color_read_attribute, | make_vertex_color_read_attribute, | ||||
| make_vertex_color_write_attribute); | make_vertex_color_write_attribute); | ||||
| static VertexGroupsAttributeProvider vertex_groups; | static VertexGroupsAttributeProvider vertex_groups; | ||||
| static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access); | static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access); | ||||
| static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access); | static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access); | ||||
| static CustomDataAttributeProvider edge_custom_data(ATTR_DOMAIN_EDGE, edge_access); | static CustomDataAttributeProvider edge_custom_data(ATTR_DOMAIN_EDGE, edge_access); | ||||
| static CustomDataAttributeProvider polygon_custom_data(ATTR_DOMAIN_POLYGON, polygon_access); | static CustomDataAttributeProvider face_custom_data(ATTR_DOMAIN_FACE, face_access); | ||||
| return ComponentAttributeProviders({&position, &material_index, &shade_smooth, &normal, &crease}, | return ComponentAttributeProviders({&position, &material_index, &shade_smooth, &normal, &crease}, | ||||
| {&uvs, | {&uvs, | ||||
| &vertex_colors, | &vertex_colors, | ||||
| &corner_custom_data, | &corner_custom_data, | ||||
| &vertex_groups, | &vertex_groups, | ||||
| &point_custom_data, | &point_custom_data, | ||||
| &edge_custom_data, | &edge_custom_data, | ||||
| &polygon_custom_data}); | &face_custom_data}); | ||||
| } | } | ||||
| } // namespace blender::bke | } // namespace blender::bke | ||||
| const blender::bke::ComponentAttributeProviders *MeshComponent::get_attribute_providers() const | const blender::bke::ComponentAttributeProviders *MeshComponent::get_attribute_providers() const | ||||
| { | { | ||||
| static blender::bke::ComponentAttributeProviders providers = | static blender::bke::ComponentAttributeProviders providers = | ||||
| blender::bke::create_attribute_providers_for_mesh(); | blender::bke::create_attribute_providers_for_mesh(); | ||||
| return &providers; | return &providers; | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||