Cleanup: Reduce binary size by deduplicating attribute processing #107823
|
@ -5,6 +5,8 @@
|
|||
#include "BLI_array.hh"
|
||||
#include "BLI_color.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_vector.h"
|
||||
#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
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BLI_array_utils.hh"
|
||||
|
||||
#include "BKE_attribute_math.hh"
|
||||
|
||||
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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
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(
|
||||
const CurvesGeometry &curves,
|
||||
const IndexMask points_to_delete,
|
||||
|
@ -1216,7 +1208,7 @@ static CurvesGeometry copy_with_removed_points(
|
|||
attribute.dst.span.copy_from(attribute.src);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
|
||||
bke::attribute_math::convert_to_static_type(attribute.span.type(), [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
copy_to_new_verts(attribute.span.typed<T>(), new_to_old_verts_map);
|
||||
});
|
||||
bke::attribute_math::gather(attribute.span,
|
||||
new_to_old_verts_map,
|
||||
attribute.span.take_back(new_to_old_verts_map.size()));
|
||||
|
||||
attribute.finish();
|
||||
}
|
||||
if (float3 *orco = static_cast<float3 *>(
|
||||
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 *>(
|
||||
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();
|
||||
void *new_data = MEM_malloc_arrayN(new_edges.size(), type.size(), __func__);
|
||||
|
||||
bke::attribute_math::convert_to_static_type(type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
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);
|
||||
});
|
||||
bke::attribute_math::gather(
|
||||
attribute.varray, new_to_old_edges_map, GMutableSpan(type, new_data, new_edges.size()));
|
||||
|
||||
/* Free the original attribute as soon as possible to lower peak memory usage. */
|
||||
attributes.remove(local_id);
|
||||
|
|
|
@ -51,21 +51,19 @@ BLI_NOINLINE bke::CurvesGeometry create_curve_from_vert_indices(
|
|||
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
|
||||
* have any elements, i.e. a face attribute on the output of the line primitive node. */
|
||||
if (!mesh_attribute) {
|
||||
if (!src) {
|
||||
continue;
|
||||
}
|
||||
const eCustomDataType type = bke::cpp_type_to_custom_data_type(src.type());
|
||||
|
||||
/* Copy attribute based on the map for this curve. */
|
||||
bke::attribute_math::convert_to_static_type(mesh_attribute.type(), [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
bke::SpanAttributeWriter<T> attribute =
|
||||
curves_attributes.lookup_or_add_for_write_only_span<T>(attribute_id, ATTR_DOMAIN_POINT);
|
||||
array_utils::gather<T>(mesh_attribute.typed<T>(), vert_indices, attribute.span);
|
||||
attribute.finish();
|
||||
});
|
||||
bke::GSpanAttributeWriter dst = curves_attributes.lookup_or_add_for_write_only_span(
|
||||
attribute_id, ATTR_DOMAIN_POINT, type);
|
||||
bke::attribute_math::gather(src, vert_indices, dst.span);
|
||||
dst.finish();
|
||||
}
|
||||
|
||||
return curves;
|
||||
|
|
|
@ -334,10 +334,8 @@ class SampleCurveFunction : public mf::MultiFunction {
|
|||
sampled_normals.fill_indices(mask.indices(), float3(0));
|
||||
}
|
||||
if (!sampled_values.is_empty()) {
|
||||
bke::attribute_math::convert_to_static_type(source_data_->type(), [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
sampled_values.typed<T>().fill_indices(mask.indices(), {});
|
||||
});
|
||||
const CPPType &type = sampled_values.type();
|
||||
type.fill_construct_indices(type.default_value(), sampled_values.data(), mask);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -149,52 +149,58 @@ static void transfer_attributes(
|
|||
});
|
||||
|
||||
for (const AttributeIDRef &id : attribute_ids) {
|
||||
GAttributeReader src_attribute = src_attributes.lookup(id);
|
||||
GAttributeReader src = src_attributes.lookup(id);
|
||||
|
||||
eAttrDomain out_domain;
|
||||
if (src_attribute.domain == ATTR_DOMAIN_FACE) {
|
||||
if (src.domain == ATTR_DOMAIN_FACE) {
|
||||
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;
|
||||
}
|
||||
else {
|
||||
/* Edges and Face Corners. */
|
||||
out_domain = src_attribute.domain;
|
||||
out_domain = src.domain;
|
||||
}
|
||||
const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(
|
||||
src_attribute.varray.type());
|
||||
GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_only_span(
|
||||
const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(src.varray.type());
|
||||
GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
|
||||
id, out_domain, data_type);
|
||||
if (!dst_attribute) {
|
||||
if (!dst) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bke::attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
VArraySpan<T> span{src_attribute.varray.typed<T>()};
|
||||
MutableSpan<T> dst_span = dst_attribute.span.typed<T>();
|
||||
switch (src_attribute.domain) {
|
||||
case ATTR_DOMAIN_POINT:
|
||||
copy_data_based_on_vertex_types(span, dst_span, vertex_types, keep_boundaries);
|
||||
break;
|
||||
case ATTR_DOMAIN_EDGE:
|
||||
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();
|
||||
switch (src.domain) {
|
||||
case ATTR_DOMAIN_POINT: {
|
||||
const GVArraySpan src_span(*src);
|
||||
bke::attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
copy_data_based_on_vertex_types(
|
||||
src_span.typed<T>(), dst.span.typed<T>(), vertex_types, keep_boundaries);
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
dst_attribute.finish();
|
||||
case ATTR_DOMAIN_EDGE:
|
||||
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)
|
||||
{
|
||||
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(
|
||||
src_attributes, dst_attributes, ATTR_DOMAIN_AS_MASK(domain), propagation_info, {"id"}))
|
||||
{
|
||||
bke::attribute_math::convert_to_static_type(attribute.src.type(), [&](auto dummy) {
|
||||
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);
|
||||
});
|
||||
threaded_slice_fill(offsets, selection, attribute.src, attribute.dst.span);
|
||||
attribute.dst.finish();
|
||||
}
|
||||
}
|
||||
|
@ -217,16 +223,15 @@ static void copy_curve_attributes_without_id(
|
|||
propagation_info,
|
||||
{"id"}))
|
||||
{
|
||||
bke::attribute_math::convert_to_static_type(attribute.src.type(), [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
const Span<T> src = attribute.src.typed<T>();
|
||||
MutableSpan<T> dst = attribute.dst.span.typed<T>();
|
||||
|
||||
switch (attribute.meta_data.domain) {
|
||||
case ATTR_DOMAIN_CURVE:
|
||||
threaded_slice_fill<T>(curve_offsets, selection, src, dst);
|
||||
break;
|
||||
case ATTR_DOMAIN_POINT:
|
||||
switch (attribute.meta_data.domain) {
|
||||
case ATTR_DOMAIN_CURVE:
|
||||
threaded_slice_fill(curve_offsets, selection, attribute.src, attribute.dst.span);
|
||||
break;
|
||||
case ATTR_DOMAIN_POINT:
|
||||
bke::attribute_math::convert_to_static_type(attribute.src.type(), [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
const Span<T> src = attribute.src.typed<T>();
|
||||
MutableSpan<T> dst = attribute.dst.span.typed<T>();
|
||||
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
|
||||
for (const int i_selection : range) {
|
||||
const int i_src_curve = selection[i_selection];
|
||||
|
@ -236,12 +241,12 @@ static void copy_curve_attributes_without_id(
|
|||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
attribute.dst.finish();
|
||||
}
|
||||
}
|
||||
|
@ -395,29 +400,23 @@ static void copy_face_attributes_without_id(
|
|||
propagation_info,
|
||||
{"id", ".corner_vert", ".corner_edge", ".edge_verts"}))
|
||||
{
|
||||
bke::attribute_math::convert_to_static_type(attribute.src.type(), [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
const Span<T> src = attribute.src.typed<T>();
|
||||
MutableSpan<T> dst = attribute.dst.span.typed<T>();
|
||||
|
||||
switch (attribute.meta_data.domain) {
|
||||
case ATTR_DOMAIN_POINT:
|
||||
array_utils::gather(src, vert_mapping, dst);
|
||||
break;
|
||||
case ATTR_DOMAIN_EDGE:
|
||||
array_utils::gather(src, edge_mapping, dst);
|
||||
break;
|
||||
case ATTR_DOMAIN_FACE:
|
||||
threaded_slice_fill<T>(offsets, selection, src, dst);
|
||||
break;
|
||||
case ATTR_DOMAIN_CORNER:
|
||||
array_utils::gather(src, loop_mapping, dst);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
});
|
||||
switch (attribute.meta_data.domain) {
|
||||
case ATTR_DOMAIN_POINT:
|
||||
bke::attribute_math::gather(attribute.src, vert_mapping, attribute.dst.span);
|
||||
break;
|
||||
case ATTR_DOMAIN_EDGE:
|
||||
bke::attribute_math::gather(attribute.src, edge_mapping, attribute.dst.span);
|
||||
break;
|
||||
case ATTR_DOMAIN_FACE:
|
||||
threaded_slice_fill(offsets, selection, attribute.src, attribute.dst.span);
|
||||
break;
|
||||
case ATTR_DOMAIN_CORNER:
|
||||
bke::attribute_math::gather(attribute.src, loop_mapping, attribute.dst.span);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
attribute.dst.finish();
|
||||
}
|
||||
}
|
||||
|
@ -606,23 +605,17 @@ static void copy_edge_attributes_without_id(
|
|||
propagation_info,
|
||||
{"id", ".edge_verts"}))
|
||||
{
|
||||
bke::attribute_math::convert_to_static_type(attribute.src.type(), [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
const Span<T> src = attribute.src.typed<T>();
|
||||
MutableSpan<T> dst = attribute.dst.span.typed<T>();
|
||||
|
||||
switch (attribute.meta_data.domain) {
|
||||
case ATTR_DOMAIN_EDGE:
|
||||
threaded_slice_fill<T>(offsets, selection, src, dst);
|
||||
break;
|
||||
case ATTR_DOMAIN_POINT:
|
||||
array_utils::gather(src, point_mapping, dst);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
});
|
||||
switch (attribute.meta_data.domain) {
|
||||
case ATTR_DOMAIN_EDGE:
|
||||
threaded_slice_fill(offsets, selection, attribute.src, attribute.dst.span);
|
||||
break;
|
||||
case ATTR_DOMAIN_POINT:
|
||||
bke::attribute_math::gather(attribute.src, point_mapping, attribute.dst.span);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
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::CurvesGeometry &new_curves = new_curves_id->geometry.wrap();
|
||||
MutableSpan<int> new_curve_offsets = new_curves.offsets_for_write();
|
||||
for (const int i : new_curves.curves_range()) {
|
||||
new_curve_offsets[i] = i;
|
||||
}
|
||||
new_curve_offsets.last() = dst_num;
|
||||
std::iota(new_curve_offsets.begin(), new_curve_offsets.end(), 0);
|
||||
|
||||
for (auto &attribute : bke::retrieve_attributes_for_transfer(src_curves.attributes(),
|
||||
new_curves.attributes_for_write(),
|
||||
|
@ -795,27 +785,27 @@ static void duplicate_points_curve(GeometrySet &geometry_set,
|
|||
propagation_info,
|
||||
{"id"}))
|
||||
{
|
||||
bke::attribute_math::convert_to_static_type(attribute.src.type(), [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
const Span<T> src = attribute.src.typed<T>();
|
||||
MutableSpan<T> dst = attribute.dst.span.typed<T>();
|
||||
switch (attribute.meta_data.domain) {
|
||||
case ATTR_DOMAIN_CURVE:
|
||||
switch (attribute.meta_data.domain) {
|
||||
case ATTR_DOMAIN_CURVE:
|
||||
bke::attribute_math::convert_to_static_type(attribute.src.type(), [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
const Span<T> src = attribute.src.typed<T>();
|
||||
MutableSpan<T> dst = attribute.dst.span.typed<T>();
|
||||
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
|
||||
for (const int i_selection : range) {
|
||||
const T &src_value = src[point_to_curve_map[selection[i_selection]]];
|
||||
dst.slice(duplicates[i_selection]).fill(src_value);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case ATTR_DOMAIN_POINT:
|
||||
threaded_slice_fill(duplicates, selection, src, dst);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
break;
|
||||
case ATTR_DOMAIN_POINT:
|
||||
threaded_slice_fill(duplicates, selection, attribute.src, attribute.dst.span);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
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
|
||||
* result point.
|
||||
*/
|
||||
template<typename T, typename GetMixIndicesFn>
|
||||
template<typename T>
|
||||
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)
|
||||
{
|
||||
threading::parallel_for(dst.index_range(), 512, [&](const IndexRange range) {
|
||||
bke::attribute_math::DefaultPropagationMixer<T> mixer{dst.slice(range)};
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
@ -215,8 +216,9 @@ void copy_with_mixing(const Span<T> src,
|
|||
});
|
||||
}
|
||||
|
||||
template<typename GetMixIndicesFn>
|
||||
void copy_with_mixing(const GSpan src, const GetMixIndicesFn &get_mix_indices_fn, GMutableSpan dst)
|
||||
static void copy_with_mixing(const GSpan src,
|
||||
const FunctionRef<Span<int>(int)> get_mix_indices_fn,
|
||||
GMutableSpan dst)
|
||||
{
|
||||
bke::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
|
@ -535,41 +537,40 @@ static void extrude_mesh_edges(Mesh &mesh,
|
|||
}
|
||||
GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
|
||||
|
||||
bke::attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
MutableSpan<T> data = attribute.span.typed<T>();
|
||||
switch (attribute.domain) {
|
||||
case ATTR_DOMAIN_POINT: {
|
||||
/* New vertices copy the attribute values from their source vertex. */
|
||||
array_utils::gather(
|
||||
data.as_span(), new_vert_indices.as_span(), data.slice(new_vert_range));
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_EDGE: {
|
||||
/* 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);
|
||||
switch (attribute.domain) {
|
||||
case ATTR_DOMAIN_POINT: {
|
||||
/* New vertices copy the attribute values from their source vertex. */
|
||||
bke::attribute_math::gather(
|
||||
attribute.span, new_vert_indices, attribute.span.slice(new_vert_range));
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_EDGE: {
|
||||
/* Edges parallel to original edges copy the edge attributes from the original edges. */
|
||||
GMutableSpan duplicate_data = attribute.span.slice(duplicate_edge_range);
|
||||
array_utils::gather(attribute.span, edge_selection, duplicate_data);
|
||||
|
||||
/* Edges connected to original vertices mix values of selected connected edges. */
|
||||
copy_with_mixing(
|
||||
duplicate_data.as_span(),
|
||||
[&](const int i) { return new_vert_to_duplicate_edge_map[i].as_span(); },
|
||||
data.slice(connect_edge_range));
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_FACE: {
|
||||
/* Attribute values for new faces are a mix of the values of faces connected to the its
|
||||
* original edge. */
|
||||
copy_with_mixing(
|
||||
data.as_span(),
|
||||
[&](const int i) { return edge_to_poly_map[edge_selection[i]].as_span(); },
|
||||
data.slice(new_poly_range));
|
||||
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_CORNER: {
|
||||
/* New corners get the average value of all adjacent corners on original faces connected
|
||||
* to the original edge of their face. */
|
||||
/* Edges connected to original vertices mix values of selected connected edges. */
|
||||
copy_with_mixing(
|
||||
duplicate_data,
|
||||
[&](const int i) { return new_vert_to_duplicate_edge_map[i].as_span(); },
|
||||
attribute.span.slice(connect_edge_range));
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_FACE: {
|
||||
/* Attribute values for new faces are a mix of the values of faces connected to the its
|
||||
* original edge. */
|
||||
copy_with_mixing(
|
||||
attribute.span,
|
||||
[&](const int i) { return edge_to_poly_map[edge_selection[i]].as_span(); },
|
||||
attribute.span.slice(new_poly_range));
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_CORNER: {
|
||||
/* New corners get the average value of all adjacent corners on original faces connected
|
||||
* 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);
|
||||
threading::parallel_for(edge_selection.index_range(), 256, [&](const IndexRange range) {
|
||||
for (const int i_edge_selection : range) {
|
||||
|
@ -623,12 +624,12 @@ static void extrude_mesh_edges(Mesh &mesh,
|
|||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
attribute.finish();
|
||||
return true;
|
||||
|
@ -935,41 +936,41 @@ static void extrude_mesh_face_regions(Mesh &mesh,
|
|||
}
|
||||
GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
|
||||
|
||||
bke::attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
MutableSpan<T> data = attribute.span.typed<T>();
|
||||
switch (attribute.domain) {
|
||||
case ATTR_DOMAIN_POINT: {
|
||||
/* New vertices copy the attributes from their original vertices. */
|
||||
array_utils::gather(
|
||||
data.as_span(), new_vert_indices.as_span(), data.slice(new_vert_range));
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_EDGE: {
|
||||
/* 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);
|
||||
switch (attribute.domain) {
|
||||
case ATTR_DOMAIN_POINT: {
|
||||
/* New vertices copy the attributes from their original vertices. */
|
||||
bke::attribute_math::gather(
|
||||
attribute.span, new_vert_indices, attribute.span.slice(new_vert_range));
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_EDGE: {
|
||||
/* Edges parallel to original edges copy the edge attributes from the original edges. */
|
||||
GMutableSpan boundary_data = attribute.span.slice(boundary_edge_range);
|
||||
bke::attribute_math::gather(attribute.span, boundary_edge_indices, boundary_data);
|
||||
|
||||
/* Edges inside of face regions also just duplicate their source data. */
|
||||
MutableSpan<T> new_inner_data = data.slice(new_inner_edge_range);
|
||||
array_utils::gather(data.as_span(), new_inner_edge_indices.as_span(), new_inner_data);
|
||||
/* Edges inside of face regions also just duplicate their source data. */
|
||||
GMutableSpan new_inner_data = attribute.span.slice(new_inner_edge_range);
|
||||
bke::attribute_math::gather(attribute.span, new_inner_edge_indices, new_inner_data);
|
||||
|
||||
/* Edges connected to original vertices mix values of selected connected edges. */
|
||||
copy_with_mixing(
|
||||
boundary_data.as_span(),
|
||||
[&](const int i) { return new_vert_to_duplicate_edge_map[i].as_span(); },
|
||||
data.slice(connect_edge_range));
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_FACE: {
|
||||
/* New faces on the side of extrusions get the values from the corresponding selected
|
||||
* face. */
|
||||
array_utils::gather(
|
||||
data.as_span(), edge_extruded_face_indices.as_span(), data.slice(side_poly_range));
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_CORNER: {
|
||||
/* New corners get the values from the corresponding corner on the extruded face. */
|
||||
/* Edges connected to original vertices mix values of selected connected edges. */
|
||||
copy_with_mixing(
|
||||
boundary_data,
|
||||
[&](const int i) { return new_vert_to_duplicate_edge_map[i].as_span(); },
|
||||
attribute.span.slice(connect_edge_range));
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_FACE: {
|
||||
/* New faces on the side of extrusions get the values from the corresponding selected
|
||||
* face. */
|
||||
GMutableSpan side_data = attribute.span.slice(side_poly_range);
|
||||
bke::attribute_math::gather(attribute.span, edge_extruded_face_indices, side_data);
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_CORNER: {
|
||||
/* 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);
|
||||
threading::parallel_for(
|
||||
boundary_edge_indices.index_range(), 256, [&](const IndexRange range) {
|
||||
|
@ -1009,12 +1010,12 @@ static void extrude_mesh_face_regions(Mesh &mesh,
|
|||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
attribute.finish();
|
||||
return true;
|
||||
|
@ -1227,21 +1228,21 @@ static void extrude_individual_mesh_faces(
|
|||
}
|
||||
GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
|
||||
|
||||
bke::attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
MutableSpan<T> data = attribute.span.typed<T>();
|
||||
switch (attribute.domain) {
|
||||
case ATTR_DOMAIN_POINT: {
|
||||
/* New vertices copy the attributes from their original vertices. */
|
||||
MutableSpan<T> new_data = data.slice(new_vert_range);
|
||||
array_utils::gather(data.as_span(), new_vert_indices.as_span(), new_data);
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_EDGE: {
|
||||
/* 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);
|
||||
switch (attribute.domain) {
|
||||
case ATTR_DOMAIN_POINT: {
|
||||
/* New vertices copy the attributes from their original vertices. */
|
||||
GMutableSpan new_data = attribute.span.slice(new_vert_range);
|
||||
bke::attribute_math::gather(attribute.span, new_vert_indices, new_data);
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_EDGE: {
|
||||
/* 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);
|
||||
bke::attribute_math::gather(attribute.span, duplicate_edge_indices, 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);
|
||||
threading::parallel_for(poly_selection.index_range(), 512, [&](const IndexRange range) {
|
||||
for (const int i_selection : range) {
|
||||
|
@ -1268,10 +1269,14 @@ static void extrude_individual_mesh_faces(
|
|||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_FACE: {
|
||||
/* Each side face gets the values from the corresponding new face. */
|
||||
});
|
||||
break;
|
||||
}
|
||||
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);
|
||||
threading::parallel_for(poly_selection.index_range(), 1024, [&](const IndexRange 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]);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_CORNER: {
|
||||
/* Each corner on a side face gets its value from the matching corner on an extruded
|
||||
* face. */
|
||||
});
|
||||
break;
|
||||
}
|
||||
case ATTR_DOMAIN_CORNER: {
|
||||
/* 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);
|
||||
threading::parallel_for(poly_selection.index_range(), 256, [&](const IndexRange range) {
|
||||
for (const int i_selection : range) {
|
||||
|
@ -1308,12 +1317,12 @@ static void extrude_individual_mesh_faces(
|
|||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
attribute.finish();
|
||||
return true;
|
||||
|
|
Loading…
Reference in New Issue
Should use
fill_construct_indices
.