Cleanup: Reduce binary size by deduplicating attribute processing #107823
|
@ -5,6 +5,8 @@
|
||||||
#include "BLI_array.hh"
|
#include "BLI_array.hh"
|
||||||
#include "BLI_color.hh"
|
#include "BLI_color.hh"
|
||||||
#include "BLI_cpp_type.hh"
|
#include "BLI_cpp_type.hh"
|
||||||
|
#include "BLI_generic_span.hh"
|
||||||
|
#include "BLI_generic_virtual_array.hh"
|
||||||
#include "BLI_math_color.hh"
|
#include "BLI_math_color.hh"
|
||||||
#include "BLI_math_vector.h"
|
#include "BLI_math_vector.h"
|
||||||
#include "BLI_math_vector.hh"
|
#include "BLI_math_vector.hh"
|
||||||
|
@ -587,4 +589,16 @@ template<typename T> using DefaultMixer = typename DefaultMixerStruct<T>::type;
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Generic Array Utils Implementations
|
||||||
|
*
|
||||||
|
* Extra implementations of functions from #BLI_array_utils.hh for all attribute types,
|
||||||
|
* used to avoid templating the same logic for each type in many places.
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
void gather(GSpan src, Span<int> map, GMutableSpan dst);
|
||||||
|
void gather(const GVArray &src, Span<int> map, GMutableSpan dst);
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
|
||||||
} // namespace blender::bke::attribute_math
|
} // namespace blender::bke::attribute_math
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
#include "BLI_array_utils.hh"
|
||||||
|
|
||||||
#include "BKE_attribute_math.hh"
|
#include "BKE_attribute_math.hh"
|
||||||
|
|
||||||
namespace blender::bke::attribute_math {
|
namespace blender::bke::attribute_math {
|
||||||
|
@ -128,4 +130,20 @@ void ColorGeometry4bMixer::finalize(const IndexMask mask)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gather(const GSpan src, const Span<int> map, GMutableSpan dst)
|
||||||
|
{
|
||||||
|
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
|
||||||
|
using T = decltype(dummy);
|
||||||
|
array_utils::gather(src.typed<T>(), map, dst.typed<T>());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void gather(const GVArray &src, const Span<int> map, GMutableSpan dst)
|
||||||
|
{
|
||||||
|
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
|
||||||
|
using T = decltype(dummy);
|
||||||
|
array_utils::gather(src.typed<T>(), map, dst.typed<T>());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace blender::bke::attribute_math
|
} // namespace blender::bke::attribute_math
|
||||||
|
|
|
@ -1124,14 +1124,6 @@ static void copy_construct_data(const GSpan src, GMutableSpan dst)
|
||||||
src.type().copy_construct_n(src.data(), dst.data(), src.size());
|
src.type().copy_construct_n(src.data(), dst.data(), src.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void copy_with_map(const GSpan src, const Span<int> map, GMutableSpan dst)
|
|
||||||
{
|
|
||||||
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
|
|
||||||
using T = decltype(dummy);
|
|
||||||
array_utils::gather(src.typed<T>(), map, dst.typed<T>());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static CurvesGeometry copy_with_removed_points(
|
static CurvesGeometry copy_with_removed_points(
|
||||||
const CurvesGeometry &curves,
|
const CurvesGeometry &curves,
|
||||||
const IndexMask points_to_delete,
|
const IndexMask points_to_delete,
|
||||||
|
@ -1216,7 +1208,7 @@ static CurvesGeometry copy_with_removed_points(
|
||||||
attribute.dst.span.copy_from(attribute.src);
|
attribute.dst.span.copy_from(attribute.src);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
copy_with_map(attribute.src, new_curve_orig_indices, attribute.dst.span);
|
bke::attribute_math::gather(attribute.src, new_curve_orig_indices, attribute.dst.span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,14 +18,6 @@ static inline bool naive_edges_equal(const int2 &edge1, const int2 &edge2)
|
||||||
return edge1 == edge2;
|
return edge1 == edge2;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static void copy_to_new_verts(MutableSpan<T> data, const Span<int> new_to_old_verts_map)
|
|
||||||
{
|
|
||||||
const Span<T> old_data = data.drop_back(new_to_old_verts_map.size());
|
|
||||||
MutableSpan<T> new_data = data.take_back(new_to_old_verts_map.size());
|
|
||||||
array_utils::gather(old_data, new_to_old_verts_map, new_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_new_vertices(Mesh &mesh, const Span<int> new_to_old_verts_map)
|
static void add_new_vertices(Mesh &mesh, const Span<int> new_to_old_verts_map)
|
||||||
{
|
{
|
||||||
/* These types aren't supported for interpolation below. */
|
/* These types aren't supported for interpolation below. */
|
||||||
|
@ -46,22 +38,26 @@ static void add_new_vertices(Mesh &mesh, const Span<int> new_to_old_verts_map)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bke::attribute_math::convert_to_static_type(attribute.span.type(), [&](auto dummy) {
|
bke::attribute_math::gather(attribute.span,
|
||||||
using T = decltype(dummy);
|
new_to_old_verts_map,
|
||||||
copy_to_new_verts(attribute.span.typed<T>(), new_to_old_verts_map);
|
attribute.span.take_back(new_to_old_verts_map.size()));
|
||||||
});
|
|
||||||
|
|
||||||
attribute.finish();
|
attribute.finish();
|
||||||
}
|
}
|
||||||
if (float3 *orco = static_cast<float3 *>(
|
if (float3 *orco = static_cast<float3 *>(
|
||||||
CustomData_get_layer_for_write(&mesh.vdata, CD_ORCO, mesh.totvert)))
|
CustomData_get_layer_for_write(&mesh.vdata, CD_ORCO, mesh.totvert)))
|
||||||
{
|
{
|
||||||
copy_to_new_verts<float3>({orco, mesh.totvert}, new_to_old_verts_map);
|
array_utils::gather(Span(orco, mesh.totvert),
|
||||||
|
new_to_old_verts_map,
|
||||||
|
MutableSpan(orco, mesh.totvert).take_back(new_to_old_verts_map.size()));
|
||||||
}
|
}
|
||||||
if (int *orig_indices = static_cast<int *>(
|
if (int *orig_indices = static_cast<int *>(
|
||||||
CustomData_get_layer_for_write(&mesh.vdata, CD_ORIGINDEX, mesh.totvert)))
|
CustomData_get_layer_for_write(&mesh.vdata, CD_ORIGINDEX, mesh.totvert)))
|
||||||
{
|
{
|
||||||
copy_to_new_verts<int>({orig_indices, mesh.totvert}, new_to_old_verts_map);
|
array_utils::gather(
|
||||||
|
Span(orig_indices, mesh.totvert),
|
||||||
|
new_to_old_verts_map,
|
||||||
|
MutableSpan(orig_indices, mesh.totvert).take_back(new_to_old_verts_map.size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,12 +115,8 @@ static void add_new_edges(Mesh &mesh,
|
||||||
const CPPType &type = attribute.varray.type();
|
const CPPType &type = attribute.varray.type();
|
||||||
void *new_data = MEM_malloc_arrayN(new_edges.size(), type.size(), __func__);
|
void *new_data = MEM_malloc_arrayN(new_edges.size(), type.size(), __func__);
|
||||||
|
|
||||||
bke::attribute_math::convert_to_static_type(type, [&](auto dummy) {
|
bke::attribute_math::gather(
|
||||||
using T = decltype(dummy);
|
attribute.varray, new_to_old_edges_map, GMutableSpan(type, new_data, new_edges.size()));
|
||||||
const VArray<T> src = attribute.varray.typed<T>();
|
|
||||||
MutableSpan<T> dst(static_cast<T *>(new_data), new_edges.size());
|
|
||||||
array_utils::gather(src, new_to_old_edges_map, dst);
|
|
||||||
});
|
|
||||||
|
|
||||||
/* Free the original attribute as soon as possible to lower peak memory usage. */
|
/* Free the original attribute as soon as possible to lower peak memory usage. */
|
||||||
attributes.remove(local_id);
|
attributes.remove(local_id);
|
||||||
|
|
|
@ -51,21 +51,19 @@ BLI_NOINLINE bke::CurvesGeometry create_curve_from_vert_indices(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GVArray mesh_attribute = *mesh_attributes.lookup(attribute_id, ATTR_DOMAIN_POINT);
|
const GVArray src = *mesh_attributes.lookup(attribute_id, ATTR_DOMAIN_POINT);
|
||||||
/* Some attributes might not exist if they were builtin attribute on domains that don't
|
/* Some attributes might not exist if they were builtin attribute on domains that don't
|
||||||
* have any elements, i.e. a face attribute on the output of the line primitive node. */
|
* have any elements, i.e. a face attribute on the output of the line primitive node. */
|
||||||
if (!mesh_attribute) {
|
if (!src) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
const eCustomDataType type = bke::cpp_type_to_custom_data_type(src.type());
|
||||||
|
|
||||||
/* Copy attribute based on the map for this curve. */
|
/* Copy attribute based on the map for this curve. */
|
||||||
bke::attribute_math::convert_to_static_type(mesh_attribute.type(), [&](auto dummy) {
|
bke::GSpanAttributeWriter dst = curves_attributes.lookup_or_add_for_write_only_span(
|
||||||
using T = decltype(dummy);
|
attribute_id, ATTR_DOMAIN_POINT, type);
|
||||||
bke::SpanAttributeWriter<T> attribute =
|
bke::attribute_math::gather(src, vert_indices, dst.span);
|
||||||
curves_attributes.lookup_or_add_for_write_only_span<T>(attribute_id, ATTR_DOMAIN_POINT);
|
dst.finish();
|
||||||
array_utils::gather<T>(mesh_attribute.typed<T>(), vert_indices, attribute.span);
|
|
||||||
attribute.finish();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return curves;
|
return curves;
|
||||||
|
|
|
@ -334,10 +334,8 @@ class SampleCurveFunction : public mf::MultiFunction {
|
||||||
sampled_normals.fill_indices(mask.indices(), float3(0));
|
sampled_normals.fill_indices(mask.indices(), float3(0));
|
||||||
}
|
}
|
||||||
if (!sampled_values.is_empty()) {
|
if (!sampled_values.is_empty()) {
|
||||||
bke::attribute_math::convert_to_static_type(source_data_->type(), [&](auto dummy) {
|
const CPPType &type = sampled_values.type();
|
||||||
using T = decltype(dummy);
|
type.fill_construct_indices(type.default_value(), sampled_values.data(), mask);
|
||||||
|
|||||||
sampled_values.typed<T>().fill_indices(mask.indices(), {});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -149,52 +149,58 @@ static void transfer_attributes(
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const AttributeIDRef &id : attribute_ids) {
|
for (const AttributeIDRef &id : attribute_ids) {
|
||||||
GAttributeReader src_attribute = src_attributes.lookup(id);
|
GAttributeReader src = src_attributes.lookup(id);
|
||||||
|
|
||||||
eAttrDomain out_domain;
|
eAttrDomain out_domain;
|
||||||
if (src_attribute.domain == ATTR_DOMAIN_FACE) {
|
if (src.domain == ATTR_DOMAIN_FACE) {
|
||||||
out_domain = ATTR_DOMAIN_POINT;
|
out_domain = ATTR_DOMAIN_POINT;
|
||||||
}
|
}
|
||||||
else if (src_attribute.domain == ATTR_DOMAIN_POINT) {
|
else if (src.domain == ATTR_DOMAIN_POINT) {
|
||||||
out_domain = ATTR_DOMAIN_FACE;
|
out_domain = ATTR_DOMAIN_FACE;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Edges and Face Corners. */
|
/* Edges and Face Corners. */
|
||||||
out_domain = src_attribute.domain;
|
out_domain = src.domain;
|
||||||
}
|
}
|
||||||
const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(
|
const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(src.varray.type());
|
||||||
src_attribute.varray.type());
|
GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
|
||||||
GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_only_span(
|
|
||||||
id, out_domain, data_type);
|
id, out_domain, data_type);
|
||||||
if (!dst_attribute) {
|
if (!dst) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bke::attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
switch (src.domain) {
|
||||||
using T = decltype(dummy);
|
case ATTR_DOMAIN_POINT: {
|
||||||
VArraySpan<T> span{src_attribute.varray.typed<T>()};
|
const GVArraySpan src_span(*src);
|
||||||
MutableSpan<T> dst_span = dst_attribute.span.typed<T>();
|
bke::attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||||
switch (src_attribute.domain) {
|
using T = decltype(dummy);
|
||||||
case ATTR_DOMAIN_POINT:
|
copy_data_based_on_vertex_types(
|
||||||
copy_data_based_on_vertex_types(span, dst_span, vertex_types, keep_boundaries);
|
src_span.typed<T>(), dst.span.typed<T>(), vertex_types, keep_boundaries);
|
||||||
break;
|
});
|
||||||
case ATTR_DOMAIN_EDGE:
|
break;
|
||||||
array_utils::gather(span, new_to_old_edges_map, dst_span);
|
|
||||||
break;
|
|
||||||
case ATTR_DOMAIN_FACE:
|
|
||||||
dst_span.take_front(span.size()).copy_from(span);
|
|
||||||
if (keep_boundaries) {
|
|
||||||
copy_data_based_on_pairs(span, dst_span, boundary_vertex_to_relevant_face_map);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ATTR_DOMAIN_CORNER:
|
|
||||||
array_utils::gather(span, new_to_old_face_corners_map, dst_span);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
BLI_assert_unreachable();
|
|
||||||
}
|
}
|
||||||
});
|
case ATTR_DOMAIN_EDGE:
|
||||||
dst_attribute.finish();
|
bke::attribute_math::gather(*src, new_to_old_edges_map, dst.span);
|
||||||
|
break;
|
||||||
|
case ATTR_DOMAIN_FACE: {
|
||||||
|
const GVArraySpan src_span(*src);
|
||||||
|
dst.span.take_front(src_span.size()).copy_from(src_span);
|
||||||
|
bke::attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||||
|
using T = decltype(dummy);
|
||||||
|
if (keep_boundaries) {
|
||||||
|
copy_data_based_on_pairs(
|
||||||
|
src_span.typed<T>(), dst.span.typed<T>(), boundary_vertex_to_relevant_face_map);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ATTR_DOMAIN_CORNER:
|
||||||
|
bke::attribute_math::gather(*src, new_to_old_face_corners_map, dst.span);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
}
|
||||||
|
dst.finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,17 @@ static void threaded_slice_fill(const OffsetIndices<int> offsets,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void threaded_slice_fill(const OffsetIndices<int> offsets,
|
||||||
|
const IndexMask selection,
|
||||||
|
const GSpan src,
|
||||||
|
GMutableSpan dst)
|
||||||
|
{
|
||||||
|
bke::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
|
||||||
|
using T = decltype(dummy);
|
||||||
|
threaded_slice_fill<T>(offsets, selection, src.typed<T>(), dst.typed<T>());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static void copy_hashed_ids(const Span<int> src, const int hash, MutableSpan<int> dst)
|
static void copy_hashed_ids(const Span<int> src, const int hash, MutableSpan<int> dst)
|
||||||
{
|
{
|
||||||
for (const int i : src.index_range()) {
|
for (const int i : src.index_range()) {
|
||||||
|
@ -181,12 +192,7 @@ static void copy_attributes_without_id(const OffsetIndices<int> offsets,
|
||||||
for (auto &attribute : bke::retrieve_attributes_for_transfer(
|
for (auto &attribute : bke::retrieve_attributes_for_transfer(
|
||||||
src_attributes, dst_attributes, ATTR_DOMAIN_AS_MASK(domain), propagation_info, {"id"}))
|
src_attributes, dst_attributes, ATTR_DOMAIN_AS_MASK(domain), propagation_info, {"id"}))
|
||||||
{
|
{
|
||||||
bke::attribute_math::convert_to_static_type(attribute.src.type(), [&](auto dummy) {
|
threaded_slice_fill(offsets, selection, attribute.src, attribute.dst.span);
|
||||||
using T = decltype(dummy);
|
|
||||||
const Span<T> src = attribute.src.typed<T>();
|
|
||||||
MutableSpan<T> dst = attribute.dst.span.typed<T>();
|
|
||||||
threaded_slice_fill<T>(offsets, selection, src, dst);
|
|
||||||
});
|
|
||||||
attribute.dst.finish();
|
attribute.dst.finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -217,16 +223,15 @@ static void copy_curve_attributes_without_id(
|
||||||
propagation_info,
|
propagation_info,
|
||||||
{"id"}))
|
{"id"}))
|
||||||
{
|
{
|
||||||
bke::attribute_math::convert_to_static_type(attribute.src.type(), [&](auto dummy) {
|
switch (attribute.meta_data.domain) {
|
||||||
using T = decltype(dummy);
|
case ATTR_DOMAIN_CURVE:
|
||||||
const Span<T> src = attribute.src.typed<T>();
|
threaded_slice_fill(curve_offsets, selection, attribute.src, attribute.dst.span);
|
||||||
MutableSpan<T> dst = attribute.dst.span.typed<T>();
|
break;
|
||||||
|
case ATTR_DOMAIN_POINT:
|
||||||
switch (attribute.meta_data.domain) {
|
bke::attribute_math::convert_to_static_type(attribute.src.type(), [&](auto dummy) {
|
||||||
case ATTR_DOMAIN_CURVE:
|
using T = decltype(dummy);
|
||||||
threaded_slice_fill<T>(curve_offsets, selection, src, dst);
|
const Span<T> src = attribute.src.typed<T>();
|
||||||
break;
|
MutableSpan<T> dst = attribute.dst.span.typed<T>();
|
||||||
case ATTR_DOMAIN_POINT:
|
|
||||||
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
|
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
|
||||||
for (const int i_selection : range) {
|
for (const int i_selection : range) {
|
||||||
const int i_src_curve = selection[i_selection];
|
const int i_src_curve = selection[i_selection];
|
||||||
|
@ -236,12 +241,12 @@ static void copy_curve_attributes_without_id(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
});
|
||||||
default:
|
break;
|
||||||
BLI_assert_unreachable();
|
default:
|
||||||
break;
|
BLI_assert_unreachable();
|
||||||
}
|
break;
|
||||||
});
|
}
|
||||||
attribute.dst.finish();
|
attribute.dst.finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -395,29 +400,23 @@ static void copy_face_attributes_without_id(
|
||||||
propagation_info,
|
propagation_info,
|
||||||
{"id", ".corner_vert", ".corner_edge", ".edge_verts"}))
|
{"id", ".corner_vert", ".corner_edge", ".edge_verts"}))
|
||||||
{
|
{
|
||||||
bke::attribute_math::convert_to_static_type(attribute.src.type(), [&](auto dummy) {
|
switch (attribute.meta_data.domain) {
|
||||||
using T = decltype(dummy);
|
case ATTR_DOMAIN_POINT:
|
||||||
const Span<T> src = attribute.src.typed<T>();
|
bke::attribute_math::gather(attribute.src, vert_mapping, attribute.dst.span);
|
||||||
MutableSpan<T> dst = attribute.dst.span.typed<T>();
|
break;
|
||||||
|
case ATTR_DOMAIN_EDGE:
|
||||||
switch (attribute.meta_data.domain) {
|
bke::attribute_math::gather(attribute.src, edge_mapping, attribute.dst.span);
|
||||||
case ATTR_DOMAIN_POINT:
|
break;
|
||||||
array_utils::gather(src, vert_mapping, dst);
|
case ATTR_DOMAIN_FACE:
|
||||||
break;
|
threaded_slice_fill(offsets, selection, attribute.src, attribute.dst.span);
|
||||||
case ATTR_DOMAIN_EDGE:
|
break;
|
||||||
array_utils::gather(src, edge_mapping, dst);
|
case ATTR_DOMAIN_CORNER:
|
||||||
break;
|
bke::attribute_math::gather(attribute.src, loop_mapping, attribute.dst.span);
|
||||||
case ATTR_DOMAIN_FACE:
|
break;
|
||||||
threaded_slice_fill<T>(offsets, selection, src, dst);
|
default:
|
||||||
break;
|
BLI_assert_unreachable();
|
||||||
case ATTR_DOMAIN_CORNER:
|
break;
|
||||||
array_utils::gather(src, loop_mapping, dst);
|
}
|
||||||
break;
|
|
||||||
default:
|
|
||||||
BLI_assert_unreachable();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
attribute.dst.finish();
|
attribute.dst.finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -606,23 +605,17 @@ static void copy_edge_attributes_without_id(
|
||||||
propagation_info,
|
propagation_info,
|
||||||
{"id", ".edge_verts"}))
|
{"id", ".edge_verts"}))
|
||||||
{
|
{
|
||||||
bke::attribute_math::convert_to_static_type(attribute.src.type(), [&](auto dummy) {
|
switch (attribute.meta_data.domain) {
|
||||||
using T = decltype(dummy);
|
case ATTR_DOMAIN_EDGE:
|
||||||
const Span<T> src = attribute.src.typed<T>();
|
threaded_slice_fill(offsets, selection, attribute.src, attribute.dst.span);
|
||||||
MutableSpan<T> dst = attribute.dst.span.typed<T>();
|
break;
|
||||||
|
case ATTR_DOMAIN_POINT:
|
||||||
switch (attribute.meta_data.domain) {
|
bke::attribute_math::gather(attribute.src, point_mapping, attribute.dst.span);
|
||||||
case ATTR_DOMAIN_EDGE:
|
break;
|
||||||
threaded_slice_fill<T>(offsets, selection, src, dst);
|
default:
|
||||||
break;
|
BLI_assert_unreachable();
|
||||||
case ATTR_DOMAIN_POINT:
|
break;
|
||||||
array_utils::gather(src, point_mapping, dst);
|
}
|
||||||
break;
|
|
||||||
default:
|
|
||||||
BLI_assert_unreachable();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
attribute.dst.finish();
|
attribute.dst.finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -784,10 +777,7 @@ static void duplicate_points_curve(GeometrySet &geometry_set,
|
||||||
bke::curves_copy_parameters(src_curves_id, *new_curves_id);
|
bke::curves_copy_parameters(src_curves_id, *new_curves_id);
|
||||||
bke::CurvesGeometry &new_curves = new_curves_id->geometry.wrap();
|
bke::CurvesGeometry &new_curves = new_curves_id->geometry.wrap();
|
||||||
MutableSpan<int> new_curve_offsets = new_curves.offsets_for_write();
|
MutableSpan<int> new_curve_offsets = new_curves.offsets_for_write();
|
||||||
for (const int i : new_curves.curves_range()) {
|
std::iota(new_curve_offsets.begin(), new_curve_offsets.end(), 0);
|
||||||
new_curve_offsets[i] = i;
|
|
||||||
}
|
|
||||||
new_curve_offsets.last() = dst_num;
|
|
||||||
|
|
||||||
for (auto &attribute : bke::retrieve_attributes_for_transfer(src_curves.attributes(),
|
for (auto &attribute : bke::retrieve_attributes_for_transfer(src_curves.attributes(),
|
||||||
new_curves.attributes_for_write(),
|
new_curves.attributes_for_write(),
|
||||||
|
@ -795,27 +785,27 @@ static void duplicate_points_curve(GeometrySet &geometry_set,
|
||||||
propagation_info,
|
propagation_info,
|
||||||
{"id"}))
|
{"id"}))
|
||||||
{
|
{
|
||||||
bke::attribute_math::convert_to_static_type(attribute.src.type(), [&](auto dummy) {
|
switch (attribute.meta_data.domain) {
|
||||||
using T = decltype(dummy);
|
case ATTR_DOMAIN_CURVE:
|
||||||
const Span<T> src = attribute.src.typed<T>();
|
bke::attribute_math::convert_to_static_type(attribute.src.type(), [&](auto dummy) {
|
||||||
MutableSpan<T> dst = attribute.dst.span.typed<T>();
|
using T = decltype(dummy);
|
||||||
switch (attribute.meta_data.domain) {
|
const Span<T> src = attribute.src.typed<T>();
|
||||||
case ATTR_DOMAIN_CURVE:
|
MutableSpan<T> dst = attribute.dst.span.typed<T>();
|
||||||
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
|
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
|
||||||
for (const int i_selection : range) {
|
for (const int i_selection : range) {
|
||||||
const T &src_value = src[point_to_curve_map[selection[i_selection]]];
|
const T &src_value = src[point_to_curve_map[selection[i_selection]]];
|
||||||
dst.slice(duplicates[i_selection]).fill(src_value);
|
dst.slice(duplicates[i_selection]).fill(src_value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
});
|
||||||
case ATTR_DOMAIN_POINT:
|
break;
|
||||||
threaded_slice_fill(duplicates, selection, src, dst);
|
case ATTR_DOMAIN_POINT:
|
||||||
break;
|
threaded_slice_fill(duplicates, selection, attribute.src, attribute.dst.span);
|
||||||
default:
|
break;
|
||||||
BLI_assert_unreachable();
|
default:
|
||||||
break;
|
BLI_assert_unreachable();
|
||||||
}
|
break;
|
||||||
});
|
}
|
||||||
attribute.dst.finish();
|
attribute.dst.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -199,15 +199,16 @@ static MutableSpan<int> get_orig_index_layer(Mesh &mesh, const eAttrDomain domai
|
||||||
* \param get_mix_indices_fn: Returns a Span of indices of the source points to mix for every
|
* \param get_mix_indices_fn: Returns a Span of indices of the source points to mix for every
|
||||||
* result point.
|
* result point.
|
||||||
*/
|
*/
|
||||||
template<typename T, typename GetMixIndicesFn>
|
template<typename T>
|
||||||
void copy_with_mixing(const Span<T> src,
|
void copy_with_mixing(const Span<T> src,
|
||||||
const GetMixIndicesFn &get_mix_indices_fn,
|
const FunctionRef<Span<int>(int)> get_mix_indices_fn,
|
||||||
MutableSpan<T> dst)
|
MutableSpan<T> dst)
|
||||||
{
|
{
|
||||||
threading::parallel_for(dst.index_range(), 512, [&](const IndexRange range) {
|
threading::parallel_for(dst.index_range(), 512, [&](const IndexRange range) {
|
||||||
bke::attribute_math::DefaultPropagationMixer<T> mixer{dst.slice(range)};
|
bke::attribute_math::DefaultPropagationMixer<T> mixer{dst.slice(range)};
|
||||||
for (const int i_dst : IndexRange(range.size())) {
|
for (const int i_dst : IndexRange(range.size())) {
|
||||||
for (const int i_src : get_mix_indices_fn(range[i_dst])) {
|
const Span<int> indices = get_mix_indices_fn(range[i_dst]);
|
||||||
|
for (const int i_src : indices) {
|
||||||
mixer.mix_in(i_dst, src[i_src]);
|
mixer.mix_in(i_dst, src[i_src]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,8 +216,9 @@ void copy_with_mixing(const Span<T> src,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename GetMixIndicesFn>
|
static void copy_with_mixing(const GSpan src,
|
||||||
void copy_with_mixing(const GSpan src, const GetMixIndicesFn &get_mix_indices_fn, GMutableSpan dst)
|
const FunctionRef<Span<int>(int)> get_mix_indices_fn,
|
||||||
|
GMutableSpan dst)
|
||||||
{
|
{
|
||||||
bke::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
|
bke::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
|
||||||
using T = decltype(dummy);
|
using T = decltype(dummy);
|
||||||
|
@ -535,41 +537,40 @@ static void extrude_mesh_edges(Mesh &mesh,
|
||||||
}
|
}
|
||||||
GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
|
GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
|
||||||
|
|
||||||
bke::attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
|
switch (attribute.domain) {
|
||||||
using T = decltype(dummy);
|
case ATTR_DOMAIN_POINT: {
|
||||||
MutableSpan<T> data = attribute.span.typed<T>();
|
/* New vertices copy the attribute values from their source vertex. */
|
||||||
switch (attribute.domain) {
|
bke::attribute_math::gather(
|
||||||
case ATTR_DOMAIN_POINT: {
|
attribute.span, new_vert_indices, attribute.span.slice(new_vert_range));
|
||||||
/* New vertices copy the attribute values from their source vertex. */
|
break;
|
||||||
array_utils::gather(
|
}
|
||||||
data.as_span(), new_vert_indices.as_span(), data.slice(new_vert_range));
|
case ATTR_DOMAIN_EDGE: {
|
||||||
break;
|
/* Edges parallel to original edges copy the edge attributes from the original edges. */
|
||||||
}
|
GMutableSpan duplicate_data = attribute.span.slice(duplicate_edge_range);
|
||||||
case ATTR_DOMAIN_EDGE: {
|
array_utils::gather(attribute.span, edge_selection, duplicate_data);
|
||||||
/* Edges parallel to original edges copy the edge attributes from the original edges. */
|
|
||||||
MutableSpan<T> duplicate_data = data.slice(duplicate_edge_range);
|
|
||||||
array_utils::gather(data.as_span(), edge_selection, duplicate_data);
|
|
||||||
|
|
||||||
/* Edges connected to original vertices mix values of selected connected edges. */
|
/* Edges connected to original vertices mix values of selected connected edges. */
|
||||||
copy_with_mixing(
|
copy_with_mixing(
|
||||||
duplicate_data.as_span(),
|
duplicate_data,
|
||||||
[&](const int i) { return new_vert_to_duplicate_edge_map[i].as_span(); },
|
[&](const int i) { return new_vert_to_duplicate_edge_map[i].as_span(); },
|
||||||
data.slice(connect_edge_range));
|
attribute.span.slice(connect_edge_range));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ATTR_DOMAIN_FACE: {
|
case ATTR_DOMAIN_FACE: {
|
||||||
/* Attribute values for new faces are a mix of the values of faces connected to the its
|
/* Attribute values for new faces are a mix of the values of faces connected to the its
|
||||||
* original edge. */
|
* original edge. */
|
||||||
copy_with_mixing(
|
copy_with_mixing(
|
||||||
data.as_span(),
|
attribute.span,
|
||||||
[&](const int i) { return edge_to_poly_map[edge_selection[i]].as_span(); },
|
[&](const int i) { return edge_to_poly_map[edge_selection[i]].as_span(); },
|
||||||
data.slice(new_poly_range));
|
attribute.span.slice(new_poly_range));
|
||||||
|
break;
|
||||||
break;
|
}
|
||||||
}
|
case ATTR_DOMAIN_CORNER: {
|
||||||
case ATTR_DOMAIN_CORNER: {
|
/* New corners get the average value of all adjacent corners on original faces connected
|
||||||
/* New corners get the average value of all adjacent corners on original faces connected
|
* to the original edge of their face. */
|
||||||
* to the original edge of their face. */
|
bke::attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
|
||||||
|
using T = decltype(dummy);
|
||||||
|
MutableSpan<T> data = attribute.span.typed<T>();
|
||||||
MutableSpan<T> new_data = data.slice(new_loop_range);
|
MutableSpan<T> new_data = data.slice(new_loop_range);
|
||||||
threading::parallel_for(edge_selection.index_range(), 256, [&](const IndexRange range) {
|
threading::parallel_for(edge_selection.index_range(), 256, [&](const IndexRange range) {
|
||||||
for (const int i_edge_selection : range) {
|
for (const int i_edge_selection : range) {
|
||||||
|
@ -623,12 +624,12 @@ static void extrude_mesh_edges(Mesh &mesh,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
});
|
||||||
}
|
break;
|
||||||
default:
|
|
||||||
BLI_assert_unreachable();
|
|
||||||
}
|
}
|
||||||
});
|
default:
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
attribute.finish();
|
attribute.finish();
|
||||||
return true;
|
return true;
|
||||||
|
@ -935,41 +936,41 @@ static void extrude_mesh_face_regions(Mesh &mesh,
|
||||||
}
|
}
|
||||||
GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
|
GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
|
||||||
|
|
||||||
bke::attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
|
switch (attribute.domain) {
|
||||||
using T = decltype(dummy);
|
case ATTR_DOMAIN_POINT: {
|
||||||
MutableSpan<T> data = attribute.span.typed<T>();
|
/* New vertices copy the attributes from their original vertices. */
|
||||||
switch (attribute.domain) {
|
bke::attribute_math::gather(
|
||||||
case ATTR_DOMAIN_POINT: {
|
attribute.span, new_vert_indices, attribute.span.slice(new_vert_range));
|
||||||
/* New vertices copy the attributes from their original vertices. */
|
break;
|
||||||
array_utils::gather(
|
}
|
||||||
data.as_span(), new_vert_indices.as_span(), data.slice(new_vert_range));
|
case ATTR_DOMAIN_EDGE: {
|
||||||
break;
|
/* Edges parallel to original edges copy the edge attributes from the original edges. */
|
||||||
}
|
GMutableSpan boundary_data = attribute.span.slice(boundary_edge_range);
|
||||||
case ATTR_DOMAIN_EDGE: {
|
bke::attribute_math::gather(attribute.span, boundary_edge_indices, boundary_data);
|
||||||
/* Edges parallel to original edges copy the edge attributes from the original edges. */
|
|
||||||
MutableSpan<T> boundary_data = data.slice(boundary_edge_range);
|
|
||||||
array_utils::gather(data.as_span(), boundary_edge_indices.as_span(), boundary_data);
|
|
||||||
|
|
||||||
/* Edges inside of face regions also just duplicate their source data. */
|
/* Edges inside of face regions also just duplicate their source data. */
|
||||||
MutableSpan<T> new_inner_data = data.slice(new_inner_edge_range);
|
GMutableSpan new_inner_data = attribute.span.slice(new_inner_edge_range);
|
||||||
array_utils::gather(data.as_span(), new_inner_edge_indices.as_span(), new_inner_data);
|
bke::attribute_math::gather(attribute.span, new_inner_edge_indices, new_inner_data);
|
||||||
|
|
||||||
/* Edges connected to original vertices mix values of selected connected edges. */
|
/* Edges connected to original vertices mix values of selected connected edges. */
|
||||||
copy_with_mixing(
|
copy_with_mixing(
|
||||||
boundary_data.as_span(),
|
boundary_data,
|
||||||
[&](const int i) { return new_vert_to_duplicate_edge_map[i].as_span(); },
|
[&](const int i) { return new_vert_to_duplicate_edge_map[i].as_span(); },
|
||||||
data.slice(connect_edge_range));
|
attribute.span.slice(connect_edge_range));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ATTR_DOMAIN_FACE: {
|
case ATTR_DOMAIN_FACE: {
|
||||||
/* New faces on the side of extrusions get the values from the corresponding selected
|
/* New faces on the side of extrusions get the values from the corresponding selected
|
||||||
* face. */
|
* face. */
|
||||||
array_utils::gather(
|
GMutableSpan side_data = attribute.span.slice(side_poly_range);
|
||||||
data.as_span(), edge_extruded_face_indices.as_span(), data.slice(side_poly_range));
|
bke::attribute_math::gather(attribute.span, edge_extruded_face_indices, side_data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ATTR_DOMAIN_CORNER: {
|
case ATTR_DOMAIN_CORNER: {
|
||||||
/* New corners get the values from the corresponding corner on the extruded face. */
|
/* New corners get the values from the corresponding corner on the extruded face. */
|
||||||
|
bke::attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
|
||||||
|
using T = decltype(dummy);
|
||||||
|
MutableSpan<T> data = attribute.span.typed<T>();
|
||||||
MutableSpan<T> new_data = data.slice(side_loop_range);
|
MutableSpan<T> new_data = data.slice(side_loop_range);
|
||||||
threading::parallel_for(
|
threading::parallel_for(
|
||||||
boundary_edge_indices.index_range(), 256, [&](const IndexRange range) {
|
boundary_edge_indices.index_range(), 256, [&](const IndexRange range) {
|
||||||
|
@ -1009,12 +1010,12 @@ static void extrude_mesh_face_regions(Mesh &mesh,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
});
|
||||||
}
|
break;
|
||||||
default:
|
|
||||||
BLI_assert_unreachable();
|
|
||||||
}
|
}
|
||||||
});
|
default:
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
attribute.finish();
|
attribute.finish();
|
||||||
return true;
|
return true;
|
||||||
|
@ -1227,21 +1228,21 @@ static void extrude_individual_mesh_faces(
|
||||||
}
|
}
|
||||||
GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
|
GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
|
||||||
|
|
||||||
bke::attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
|
switch (attribute.domain) {
|
||||||
using T = decltype(dummy);
|
case ATTR_DOMAIN_POINT: {
|
||||||
MutableSpan<T> data = attribute.span.typed<T>();
|
/* New vertices copy the attributes from their original vertices. */
|
||||||
switch (attribute.domain) {
|
GMutableSpan new_data = attribute.span.slice(new_vert_range);
|
||||||
case ATTR_DOMAIN_POINT: {
|
bke::attribute_math::gather(attribute.span, new_vert_indices, new_data);
|
||||||
/* New vertices copy the attributes from their original vertices. */
|
break;
|
||||||
MutableSpan<T> new_data = data.slice(new_vert_range);
|
}
|
||||||
array_utils::gather(data.as_span(), new_vert_indices.as_span(), new_data);
|
case ATTR_DOMAIN_EDGE: {
|
||||||
break;
|
/* The data for the duplicate edge is simply a copy of the original edge's data. */
|
||||||
}
|
GMutableSpan duplicate_data = attribute.span.slice(duplicate_edge_range);
|
||||||
case ATTR_DOMAIN_EDGE: {
|
bke::attribute_math::gather(attribute.span, duplicate_edge_indices, duplicate_data);
|
||||||
/* The data for the duplicate edge is simply a copy of the original edge's data. */
|
|
||||||
MutableSpan<T> duplicate_data = data.slice(duplicate_edge_range);
|
|
||||||
array_utils::gather(data.as_span(), duplicate_edge_indices.as_span(), duplicate_data);
|
|
||||||
|
|
||||||
|
bke::attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
|
||||||
|
using T = decltype(dummy);
|
||||||
|
MutableSpan<T> data = attribute.span.typed<T>();
|
||||||
MutableSpan<T> connect_data = data.slice(connect_edge_range);
|
MutableSpan<T> connect_data = data.slice(connect_edge_range);
|
||||||
threading::parallel_for(poly_selection.index_range(), 512, [&](const IndexRange range) {
|
threading::parallel_for(poly_selection.index_range(), 512, [&](const IndexRange range) {
|
||||||
for (const int i_selection : range) {
|
for (const int i_selection : range) {
|
||||||
|
@ -1268,10 +1269,14 @@ static void extrude_individual_mesh_faces(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
});
|
||||||
}
|
break;
|
||||||
case ATTR_DOMAIN_FACE: {
|
}
|
||||||
/* Each side face gets the values from the corresponding new face. */
|
case ATTR_DOMAIN_FACE: {
|
||||||
|
/* Each side face gets the values from the corresponding new face. */
|
||||||
|
bke::attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
|
||||||
|
using T = decltype(dummy);
|
||||||
|
MutableSpan<T> data = attribute.span.typed<T>();
|
||||||
MutableSpan<T> new_data = data.slice(side_poly_range);
|
MutableSpan<T> new_data = data.slice(side_poly_range);
|
||||||
threading::parallel_for(poly_selection.index_range(), 1024, [&](const IndexRange range) {
|
threading::parallel_for(poly_selection.index_range(), 1024, [&](const IndexRange range) {
|
||||||
for (const int i_selection : range) {
|
for (const int i_selection : range) {
|
||||||
|
@ -1280,11 +1285,15 @@ static void extrude_individual_mesh_faces(
|
||||||
new_data.slice(extrude_range).fill(data[poly_index]);
|
new_data.slice(extrude_range).fill(data[poly_index]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
});
|
||||||
}
|
break;
|
||||||
case ATTR_DOMAIN_CORNER: {
|
}
|
||||||
/* Each corner on a side face gets its value from the matching corner on an extruded
|
case ATTR_DOMAIN_CORNER: {
|
||||||
* face. */
|
/* Each corner on a side face gets its value from the matching corner on an extruded
|
||||||
|
* face. */
|
||||||
|
bke::attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
|
||||||
|
using T = decltype(dummy);
|
||||||
|
MutableSpan<T> data = attribute.span.typed<T>();
|
||||||
MutableSpan<T> new_data = data.slice(side_loop_range);
|
MutableSpan<T> new_data = data.slice(side_loop_range);
|
||||||
threading::parallel_for(poly_selection.index_range(), 256, [&](const IndexRange range) {
|
threading::parallel_for(poly_selection.index_range(), 256, [&](const IndexRange range) {
|
||||||
for (const int i_selection : range) {
|
for (const int i_selection : range) {
|
||||||
|
@ -1308,12 +1317,12 @@ static void extrude_individual_mesh_faces(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
});
|
||||||
}
|
break;
|
||||||
default:
|
|
||||||
BLI_assert_unreachable();
|
|
||||||
}
|
}
|
||||||
});
|
default:
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
attribute.finish();
|
attribute.finish();
|
||||||
return true;
|
return true;
|
||||||
|
|
Loading…
Reference in New Issue
Should use
fill_construct_indices
.