Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/geometry_component_mesh.cc
| Show All 9 Lines | |||||
| * GNU General Public License for more details. | * GNU General Public License for more details. | ||||
| * | * | ||||
| * You should have received a copy of the GNU General Public License | * You should have received a copy of the GNU General Public License | ||||
| * along with this program; if not, write to the Free Software Foundation, | * along with this program; if not, write to the Free Software Foundation, | ||||
| * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
| */ | */ | ||||
| #include "BLI_listbase.h" | #include "BLI_listbase.h" | ||||
| #include "BLI_task.hh" | |||||
| #include "DNA_mesh_types.h" | #include "DNA_mesh_types.h" | ||||
| #include "DNA_meshdata_types.h" | #include "DNA_meshdata_types.h" | ||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| #include "BKE_attribute_access.hh" | #include "BKE_attribute_access.hh" | ||||
| #include "BKE_attribute_math.hh" | #include "BKE_attribute_math.hh" | ||||
| #include "BKE_deform.h" | #include "BKE_deform.h" | ||||
| ▲ Show 20 Lines • Show All 301 Lines • ▼ Show 20 Lines | if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { | ||||
| new_varray = VArray<T>::ForContainer(std::move(values)); | new_varray = VArray<T>::ForContainer(std::move(values)); | ||||
| } | } | ||||
| }); | }); | ||||
| return new_varray; | return new_varray; | ||||
| } | } | ||||
| /** | /** | ||||
| * Each corner's value is simply a copy of the value at its vertex. | * Each corner's value is simply a copy of the value at its vertex. | ||||
| * | |||||
| * \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 | |||||
| * only some values are required. | |||||
| */ | */ | ||||
| template<typename T> | |||||
| static void adapt_mesh_domain_point_to_corner_impl(const Mesh &mesh, | |||||
| const VArray<T> &old_values, | |||||
| MutableSpan<T> r_values) | |||||
| { | |||||
| BLI_assert(r_values.size() == mesh.totloop); | |||||
| for (const int loop_index : IndexRange(mesh.totloop)) { | |||||
| const int vertex_index = mesh.mloop[loop_index].v; | |||||
| r_values[loop_index] = old_values[vertex_index]; | |||||
| } | |||||
| } | |||||
| static GVArray adapt_mesh_domain_point_to_corner(const Mesh &mesh, const GVArray &varray) | static GVArray adapt_mesh_domain_point_to_corner(const Mesh &mesh, const GVArray &varray) | ||||
| { | { | ||||
| GVArray new_varray; | GVArray new_varray; | ||||
| attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { | attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { | ||||
| using T = decltype(dummy); | using T = decltype(dummy); | ||||
| Array<T> values(mesh.totloop); | new_varray = VArray<T>::ForFunc(mesh.totloop, | ||||
| adapt_mesh_domain_point_to_corner_impl<T>(mesh, varray.typed<T>(), values); | [mesh, varray = varray.typed<T>()](const int64_t loop_index) { | ||||
| new_varray = VArray<T>::ForContainer(std::move(values)); | const int vertex_index = mesh.mloop[loop_index].v; | ||||
| return varray[vertex_index]; | |||||
| }); | |||||
| }); | }); | ||||
| return new_varray; | return new_varray; | ||||
| } | } | ||||
| /** | static GVArray adapt_mesh_domain_corner_to_face(const Mesh &mesh, const GVArray &varray) | ||||
| * \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 | |||||
| * only some values are required. | |||||
| */ | |||||
| template<typename T> | |||||
| static void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh, | |||||
| const VArray<T> &old_values, | |||||
| MutableSpan<T> r_values) | |||||
| { | { | ||||
| BLI_assert(r_values.size() == mesh.totpoly); | GVArray new_varray; | ||||
| attribute_math::DefaultMixer<T> mixer(r_values); | attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { | ||||
| using T = decltype(dummy); | |||||
| for (const int poly_index : IndexRange(mesh.totpoly)) { | if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { | ||||
| const MPoly &poly = mesh.mpoly[poly_index]; | if constexpr (std::is_same_v<T, bool>) { | ||||
| new_varray = VArray<T>::ForFunc( | |||||
| mesh.totpoly, [mesh, 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]; | |||||
| 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]; | if (!varray[loop_index]) { | ||||
| mixer.mix_in(poly_index, value); | return false; | ||||
| } | } | ||||
| } | } | ||||
| return true; | |||||
| mixer.finalize(); | }); | ||||
| } | } | ||||
| else { | |||||
| /* A face is selected if all of its corners were selected. */ | new_varray = VArray<T>::ForFunc( | ||||
| template<> | mesh.totpoly, [mesh, varray = varray.typed<T>()](const int face_index) { | ||||
| void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh, | T return_value; | ||||
| const VArray<bool> &old_values, | attribute_math::DefaultMixer<T> mixer({&return_value, 1}); | ||||
| MutableSpan<bool> r_values) | const MPoly &poly = mesh.mpoly[face_index]; | ||||
| { | |||||
| BLI_assert(r_values.size() == mesh.totpoly); | |||||
| r_values.fill(true); | |||||
| for (const int poly_index : IndexRange(mesh.totpoly)) { | |||||
| 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)) { | ||||
| if (!old_values[loop_index]) { | const T value = varray[loop_index]; | ||||
| r_values[poly_index] = false; | mixer.mix_in(0, value); | ||||
| break; | |||||
| } | |||||
| } | |||||
| } | } | ||||
| mixer.finalize(); | |||||
| return return_value; | |||||
| }); | |||||
| } | } | ||||
| static GVArray adapt_mesh_domain_corner_to_face(const Mesh &mesh, const GVArray &varray) | |||||
| { | |||||
| 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>>) { | |||||
| Array<T> values(mesh.totpoly); | |||||
| adapt_mesh_domain_corner_to_face_impl<T>(mesh, varray.typed<T>(), values); | |||||
| new_varray = VArray<T>::ForContainer(std::move(values)); | |||||
| } | } | ||||
| }); | }); | ||||
| return new_varray; | return new_varray; | ||||
| } | } | ||||
| template<typename T> | template<typename T> | ||||
| static void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh, | static void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh, | ||||
| const VArray<T> &old_values, | const VArray<T> &old_values, | ||||
| ▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { | ||||
| if (!old_values[loop_index] || !old_values[loop_index_next]) { | if (!old_values[loop_index] || !old_values[loop_index_next]) { | ||||
| r_values[edge_index] = false; | r_values[edge_index] = false; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Deselect loose edges without corners that are still selected from the 'true' default. */ | /* Deselect loose edges without corners that are still selected from the 'true' default. */ | ||||
| for (const int edge_index : IndexRange(mesh.totedge)) { | threading::parallel_for(IndexRange(mesh.totedge), 2048, [&](const IndexRange range) { | ||||
| for (const int edge_index : range) { | |||||
| if (loose_edges[edge_index]) { | if (loose_edges[edge_index]) { | ||||
| r_values[edge_index] = false; | r_values[edge_index] = false; | ||||
| } | } | ||||
| } | } | ||||
| }); | |||||
| } | } | ||||
| static GVArray adapt_mesh_domain_corner_to_edge(const Mesh &mesh, const GVArray &varray) | static GVArray adapt_mesh_domain_corner_to_edge(const Mesh &mesh, const GVArray &varray) | ||||
| { | { | ||||
| GVArray new_varray; | GVArray new_varray; | ||||
| attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { | attribute_math::convert_to_static_type(varray.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>>) { | ||||
| ▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | |||||
| /* Each corner's value is simply a copy of the value at its face. */ | /* Each corner's value is simply a copy of the value at its face. */ | ||||
| template<typename T> | template<typename T> | ||||
| void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh, | void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh, | ||||
| const VArray<T> &old_values, | const VArray<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)) { | threading::parallel_for(IndexRange(mesh.totpoly), 1024, [&](const IndexRange range) { | ||||
| for (const int poly_index : range) { | |||||
| 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 GVArray adapt_mesh_domain_face_to_corner(const Mesh &mesh, const GVArray &varray) | static GVArray adapt_mesh_domain_face_to_corner(const Mesh &mesh, const GVArray &varray) | ||||
| { | { | ||||
| GVArray new_varray; | GVArray new_varray; | ||||
| attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { | attribute_math::convert_to_static_type(varray.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>>) { | ||||
| ▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { | ||||
| Array<T> values(mesh.totedge); | Array<T> values(mesh.totedge); | ||||
| adapt_mesh_domain_face_to_edge_impl<T>(mesh, varray.typed<T>(), values); | adapt_mesh_domain_face_to_edge_impl<T>(mesh, varray.typed<T>(), values); | ||||
| new_varray = VArray<T>::ForContainer(std::move(values)); | new_varray = VArray<T>::ForContainer(std::move(values)); | ||||
| } | } | ||||
| }); | }); | ||||
| return new_varray; | return new_varray; | ||||
| } | } | ||||
| /** | |||||
| * \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 | |||||
| * only some values are required. | |||||
| */ | |||||
| template<typename T> | |||||
| static void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh, | |||||
| const VArray<T> &old_values, | |||||
| MutableSpan<T> r_values) | |||||
| { | |||||
| BLI_assert(r_values.size() == mesh.totpoly); | |||||
| 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 loop_index : IndexRange(poly.loopstart, poly.totloop)) { | |||||
| MLoop &loop = mesh.mloop[loop_index]; | |||||
| const int point_index = loop.v; | |||||
| mixer.mix_in(poly_index, old_values[point_index]); | |||||
| } | |||||
| } | |||||
| mixer.finalize(); | |||||
| } | |||||
| /* A face is selected if all of its vertices were selected too. */ | |||||
| template<> | |||||
| void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh, | |||||
| const VArray<bool> &old_values, | |||||
| MutableSpan<bool> r_values) | |||||
| { | |||||
| BLI_assert(r_values.size() == mesh.totpoly); | |||||
| r_values.fill(true); | |||||
| for (const int poly_index : IndexRange(mesh.totpoly)) { | |||||
| const MPoly &poly = mesh.mpoly[poly_index]; | |||||
| for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { | |||||
| MLoop &loop = mesh.mloop[loop_index]; | |||||
| const int vert_index = loop.v; | |||||
| if (!old_values[vert_index]) { | |||||
| r_values[poly_index] = false; | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| static GVArray adapt_mesh_domain_point_to_face(const Mesh &mesh, const GVArray &varray) | static GVArray adapt_mesh_domain_point_to_face(const Mesh &mesh, const GVArray &varray) | ||||
| { | { | ||||
| GVArray new_varray; | GVArray new_varray; | ||||
| attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { | attribute_math::convert_to_static_type(varray.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); | if constexpr (std::is_same_v<T, bool>) { | ||||
| adapt_mesh_domain_point_to_face_impl<T>(mesh, varray.typed<T>(), values); | new_varray = VArray<T>::ForFunc( | ||||
| new_varray = VArray<T>::ForContainer(std::move(values)); | mesh.totpoly, [mesh, 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]; | |||||
| for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { | |||||
| const MLoop &loop = mesh.mloop[loop_index]; | |||||
| if (!varray[loop.v]) { | |||||
| return false; | |||||
| } | |||||
| } | } | ||||
| return true; | |||||
| }); | }); | ||||
| return new_varray; | |||||
| } | } | ||||
| else { | |||||
| /** | new_varray = VArray<T>::ForFunc( | ||||
| * \note Theoretically this interpolation does not need to compute all values at once. | mesh.totpoly, [mesh, varray = varray.typed<T>()](const int face_index) { | ||||
| * However, doing that makes the implementation simpler, and this can be optimized in the future if | T return_value; | ||||
| * only some values are required. | attribute_math::DefaultMixer<T> mixer({&return_value, 1}); | ||||
| */ | const MPoly &poly = mesh.mpoly[face_index]; | ||||
| template<typename T> | for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { | ||||
| static void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh, | const MLoop &loop = mesh.mloop[loop_index]; | ||||
| const VArray<T> &old_values, | const T value = varray[loop.v]; | ||||
| MutableSpan<T> r_values) | mixer.mix_in(0, value); | ||||
| { | |||||
| BLI_assert(r_values.size() == mesh.totedge); | |||||
| attribute_math::DefaultMixer<T> mixer(r_values); | |||||
| for (const int edge_index : IndexRange(mesh.totedge)) { | |||||
| const MEdge &edge = mesh.medge[edge_index]; | |||||
| mixer.mix_in(edge_index, old_values[edge.v1]); | |||||
| mixer.mix_in(edge_index, old_values[edge.v2]); | |||||
| } | } | ||||
| mixer.finalize(); | mixer.finalize(); | ||||
| return return_value; | |||||
| }); | |||||
| } | } | ||||
| /* An edge is selected if both of its vertices were selected. */ | |||||
| template<> | |||||
| void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh, | |||||
| const VArray<bool> &old_values, | |||||
| MutableSpan<bool> r_values) | |||||
| { | |||||
| BLI_assert(r_values.size() == mesh.totedge); | |||||
| for (const int edge_index : IndexRange(mesh.totedge)) { | |||||
| const MEdge &edge = mesh.medge[edge_index]; | |||||
| r_values[edge_index] = old_values[edge.v1] && old_values[edge.v2]; | |||||
| } | } | ||||
| }); | |||||
| return new_varray; | |||||
| } | } | ||||
| static GVArray adapt_mesh_domain_point_to_edge(const Mesh &mesh, const GVArray &varray) | static GVArray adapt_mesh_domain_point_to_edge(const Mesh &mesh, const GVArray &varray) | ||||
| { | { | ||||
| GVArray new_varray; | GVArray new_varray; | ||||
| attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { | attribute_math::convert_to_static_type(varray.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); | if constexpr (std::is_same_v<T, bool>) { | ||||
| adapt_mesh_domain_point_to_edge_impl<T>(mesh, varray.typed<T>(), values); | /* An edge is selected if both of its vertices were selected. */ | ||||
| new_varray = VArray<T>::ForContainer(std::move(values)); | new_varray = VArray<bool>::ForFunc( | ||||
| mesh.totedge, [mesh, varray = varray.typed<bool>()](const int edge_index) { | |||||
| const MEdge &edge = mesh.medge[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) { | |||||
| T return_value; | |||||
| attribute_math::DefaultMixer<T> mixer({&return_value, 1}); | |||||
| const MEdge &edge = mesh.medge[edge_index]; | |||||
| mixer.mix_in(0, varray[edge.v1]); | |||||
| mixer.mix_in(0, varray[edge.v2]); | |||||
| mixer.finalize(); | |||||
| return return_value; | |||||
| }); | |||||
| } | |||||
| } | } | ||||
| }); | }); | ||||
| return new_varray; | return new_varray; | ||||
| } | } | ||||
| template<typename T> | template<typename T> | ||||
| void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh, | void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh, | ||||
| const VArray<T> &old_values, | const VArray<T> &old_values, | ||||
| ▲ Show 20 Lines • Show All 100 Lines • ▼ Show 20 Lines | if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { | ||||
| Array<T> values(mesh.totvert); | Array<T> values(mesh.totvert); | ||||
| adapt_mesh_domain_edge_to_point_impl<T>(mesh, varray.typed<T>(), values); | adapt_mesh_domain_edge_to_point_impl<T>(mesh, varray.typed<T>(), values); | ||||
| new_varray = VArray<T>::ForContainer(std::move(values)); | new_varray = VArray<T>::ForContainer(std::move(values)); | ||||
| } | } | ||||
| }); | }); | ||||
| return new_varray; | return new_varray; | ||||
| } | } | ||||
| /** | static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &varray) | ||||
| * \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 | |||||
| * only some values are required. | |||||
| */ | |||||
| template<typename T> | |||||
| static void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh, | |||||
| const VArray<T> &old_values, | |||||
| MutableSpan<T> r_values) | |||||
| { | { | ||||
| BLI_assert(r_values.size() == mesh.totpoly); | GVArray new_varray; | ||||
| attribute_math::DefaultMixer<T> mixer(r_values); | attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { | ||||
| using T = decltype(dummy); | |||||
| for (const int poly_index : IndexRange(mesh.totpoly)) { | if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { | ||||
| const MPoly &poly = mesh.mpoly[poly_index]; | 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]; | |||||
| 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]); | if (!varray[loop.e]) { | ||||
| return false; | |||||
| } | } | ||||
| } | } | ||||
| return true; | |||||
| mixer.finalize(); | }); | ||||
| } | } | ||||
| else { | |||||
| /* A face is selected if all of its edges are selected. */ | new_varray = VArray<T>::ForFunc( | ||||
| template<> | mesh.totpoly, [mesh, varray = varray.typed<T>()](const int face_index) { | ||||
| void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh, | T return_value; | ||||
| const VArray<bool> &old_values, | attribute_math::DefaultMixer<T> mixer({&return_value, 1}); | ||||
| MutableSpan<bool> r_values) | const MPoly &poly = mesh.mpoly[face_index]; | ||||
| { | |||||
| BLI_assert(r_values.size() == mesh.totpoly); | |||||
| r_values.fill(true); | |||||
| for (const int poly_index : IndexRange(mesh.totpoly)) { | |||||
| 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]; | ||||
| const int edge_index = loop.e; | const T value = varray[loop.e]; | ||||
| if (!old_values[edge_index]) { | mixer.mix_in(0, value); | ||||
| r_values[poly_index] = false; | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | } | ||||
| mixer.finalize(); | |||||
| return return_value; | |||||
| }); | |||||
| } | } | ||||
| static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &varray) | |||||
| { | |||||
| 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>>) { | |||||
| Array<T> values(mesh.totpoly); | |||||
| adapt_mesh_domain_edge_to_face_impl<T>(mesh, varray.typed<T>(), values); | |||||
| new_varray = VArray<T>::ForContainer(std::move(values)); | |||||
| } | } | ||||
| }); | }); | ||||
| return new_varray; | return new_varray; | ||||
| } | } | ||||
| } // namespace blender::bke | } // namespace blender::bke | ||||
| blender::fn::GVArray MeshComponent::attribute_try_adapt_domain_impl( | blender::fn::GVArray MeshComponent::attribute_try_adapt_domain_impl( | ||||
| ▲ Show 20 Lines • Show All 552 Lines • Show Last 20 Lines | |||||