Cleanup: Use offset indices arguments for curves utilities

Make the functions more flexible and more generic by changing the curves
arguments to the curve offsets. This way, theoretically they could become
normal utility functions in the future. Also do a consistency pass over
the algorithms that generate new curves geometry for naming and
code ordering, and use of utility functions. The functions are really
quite similar, and it's much easier to tell this way.
This commit is contained in:
Hans Goudey 2023-01-23 14:41:40 -06:00
parent 15575b953d
commit 7fc395354c
Notes: blender-bot 2023-11-06 15:08:17 +01:00
Referenced by issue #109399, Blender LTS: Maintenance Task 3.6
8 changed files with 228 additions and 188 deletions

View File

@ -471,54 +471,58 @@ class IndexRangeCyclic {
* ranges, assuming that all curves have the same number of control points in #src_curves
* and #dst_curves.
*/
void copy_point_data(const CurvesGeometry &src_curves,
const CurvesGeometry &dst_curves,
void copy_point_data(OffsetIndices<int> src_points_by_curve,
OffsetIndices<int> dst_points_by_curve,
Span<IndexRange> curve_ranges,
GSpan src,
GMutableSpan dst);
void copy_point_data(const CurvesGeometry &src_curves,
const CurvesGeometry &dst_curves,
void copy_point_data(OffsetIndices<int> src_points_by_curve,
OffsetIndices<int> dst_points_by_curve,
IndexMask src_curve_selection,
GSpan src,
GMutableSpan dst);
template<typename T>
void copy_point_data(const CurvesGeometry &src_curves,
const CurvesGeometry &dst_curves,
void copy_point_data(OffsetIndices<int> src_points_by_curve,
OffsetIndices<int> dst_points_by_curve,
IndexMask src_curve_selection,
Span<T> src,
MutableSpan<T> dst)
{
copy_point_data(src_curves, dst_curves, src_curve_selection, GSpan(src), GMutableSpan(dst));
copy_point_data(src_points_by_curve,
dst_points_by_curve,
src_curve_selection,
GSpan(src),
GMutableSpan(dst));
}
void fill_points(const CurvesGeometry &curves,
void fill_points(OffsetIndices<int> points_by_curve,
IndexMask curve_selection,
GPointer value,
GMutableSpan dst);
template<typename T>
void fill_points(const CurvesGeometry &curves,
void fill_points(const OffsetIndices<int> points_by_curve,
IndexMask curve_selection,
const T &value,
MutableSpan<T> dst)
{
fill_points(curves, curve_selection, &value, dst);
fill_points(points_by_curve, curve_selection, &value, dst);
}
void fill_points(const CurvesGeometry &curves,
void fill_points(const OffsetIndices<int> points_by_curve,
Span<IndexRange> curve_ranges,
GPointer value,
GMutableSpan dst);
template<typename T>
void fill_points(const CurvesGeometry &curves,
void fill_points(const OffsetIndices<int> points_by_curve,
Span<IndexRange> curve_ranges,
const T &value,
MutableSpan<T> dst)
{
fill_points(curves, curve_ranges, &value, dst);
fill_points(points_by_curve, curve_ranges, &value, dst);
}
/**
@ -533,9 +537,15 @@ void fill_points(const CurvesGeometry &curves,
bke::CurvesGeometry copy_only_curve_domain(const bke::CurvesGeometry &src_curves);
/**
* Copy the number of points in every curve in #curve_ranges to the corresponding index in #sizes.
* Copy the number of points in every curve in the mask to the corresponding index in #sizes.
*/
void copy_curve_sizes(const bke::CurvesGeometry &curves,
void copy_curve_sizes(OffsetIndices<int> points_by_curve, IndexMask mask, MutableSpan<int> sizes);
/**
* Copy the number of points in every curve in #curve_ranges to the corresponding index in
* #sizes.
*/
void copy_curve_sizes(OffsetIndices<int> points_by_curve,
Span<IndexRange> curve_ranges,
MutableSpan<int> sizes);

View File

@ -10,11 +10,21 @@
namespace blender::bke::curves {
void copy_curve_sizes(const bke::CurvesGeometry &curves,
void copy_curve_sizes(const OffsetIndices<int> points_by_curve,
const IndexMask mask,
MutableSpan<int> sizes)
{
threading::parallel_for(mask.index_range(), 4096, [&](IndexRange ranges_range) {
for (const int64_t i : mask.slice(ranges_range)) {
sizes[i] = points_by_curve.size(i);
}
});
}
void copy_curve_sizes(const OffsetIndices<int> points_by_curve,
const Span<IndexRange> curve_ranges,
MutableSpan<int> sizes)
{
const OffsetIndices points_by_curve = curves.points_by_curve();
threading::parallel_for(curve_ranges.index_range(), 512, [&](IndexRange ranges_range) {
for (const IndexRange curves_range : curve_ranges.slice(ranges_range)) {
threading::parallel_for(curves_range, 4096, [&](IndexRange range) {
@ -26,14 +36,12 @@ void copy_curve_sizes(const bke::CurvesGeometry &curves,
});
}
void copy_point_data(const CurvesGeometry &src_curves,
const CurvesGeometry &dst_curves,
void copy_point_data(const OffsetIndices<int> src_points_by_curve,
const OffsetIndices<int> dst_points_by_curve,
const Span<IndexRange> curve_ranges,
const GSpan src,
GMutableSpan dst)
{
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
threading::parallel_for(curve_ranges.index_range(), 512, [&](IndexRange range) {
for (const IndexRange range : curve_ranges.slice(range)) {
const IndexRange src_points = src_points_by_curve[range];
@ -44,14 +52,12 @@ void copy_point_data(const CurvesGeometry &src_curves,
});
}
void copy_point_data(const CurvesGeometry &src_curves,
const CurvesGeometry &dst_curves,
void copy_point_data(const OffsetIndices<int> src_points_by_curve,
const OffsetIndices<int> dst_points_by_curve,
const IndexMask src_curve_selection,
const GSpan src,
GMutableSpan dst)
{
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
threading::parallel_for(src_curve_selection.index_range(), 512, [&](IndexRange range) {
for (const int i : src_curve_selection.slice(range)) {
const IndexRange src_points = src_points_by_curve[i];
@ -62,14 +68,13 @@ void copy_point_data(const CurvesGeometry &src_curves,
});
}
void fill_points(const CurvesGeometry &curves,
void fill_points(const OffsetIndices<int> points_by_curve,
const IndexMask curve_selection,
const GPointer value,
GMutableSpan dst)
{
BLI_assert(*value.type() == dst.type());
const CPPType &type = dst.type();
const OffsetIndices points_by_curve = curves.points_by_curve();
threading::parallel_for(curve_selection.index_range(), 512, [&](IndexRange range) {
for (const int i : curve_selection.slice(range)) {
const IndexRange points = points_by_curve[i];
@ -78,14 +83,13 @@ void fill_points(const CurvesGeometry &curves,
});
}
void fill_points(const CurvesGeometry &curves,
void fill_points(const OffsetIndices<int> points_by_curve,
Span<IndexRange> curve_ranges,
GPointer value,
GMutableSpan dst)
{
BLI_assert(*value.type() == dst.type());
const CPPType &type = dst.type();
const OffsetIndices points_by_curve = curves.points_by_curve();
threading::parallel_for(curve_ranges.index_range(), 512, [&](IndexRange range) {
for (const IndexRange range : curve_ranges.slice(range)) {
const IndexRange points = points_by_curve[range];

View File

@ -286,7 +286,7 @@ AddCurvesOnMeshOutputs add_curves_on_mesh(CurvesGeometry &curves,
/* Compute new curve offsets. */
MutableSpan<int> curve_offsets = curves.offsets_for_write();
MutableSpan<int> new_point_counts_per_curve = curve_offsets.take_back(added_curves_num);
MutableSpan<int> new_point_counts_per_curve = curve_offsets.drop_front(old_curves_num);
if (inputs.interpolate_point_count) {
interpolate_from_neighbors<int>(
neighbors_per_curve,
@ -297,9 +297,8 @@ AddCurvesOnMeshOutputs add_curves_on_mesh(CurvesGeometry &curves,
else {
new_point_counts_per_curve.fill(inputs.fallback_point_count);
}
for (const int i : new_curves_range) {
curve_offsets[i + 1] += curve_offsets[i];
}
offset_indices::accumulate_counts_to_offsets(curve_offsets.drop_front(old_curves_num),
old_points_num);
const int new_points_num = curves.offsets().last();
curves.resize(new_points_num, new_curves_num);

View File

@ -26,15 +26,13 @@ static void threaded_slice_fill(const Span<T> src,
}
template<typename T>
static void duplicate_fillet_point_data(const bke::CurvesGeometry &src_curves,
const bke::CurvesGeometry &dst_curves,
static void duplicate_fillet_point_data(const OffsetIndices<int> src_points_by_curve,
const OffsetIndices<int> dst_points_by_curve,
const IndexMask curve_selection,
const Span<int> all_point_offsets,
const Span<T> src,
MutableSpan<T> dst)
{
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
threading::parallel_for(curve_selection.index_range(), 512, [&](IndexRange range) {
for (const int curve_i : curve_selection.slice(range)) {
const IndexRange src_points = src_points_by_curve[curve_i];
@ -47,8 +45,8 @@ static void duplicate_fillet_point_data(const bke::CurvesGeometry &src_curves,
});
}
static void duplicate_fillet_point_data(const bke::CurvesGeometry &src_curves,
const bke::CurvesGeometry &dst_curves,
static void duplicate_fillet_point_data(const OffsetIndices<int> src_points_by_curve,
const OffsetIndices<int> dst_points_by_curve,
const IndexMask selection,
const Span<int> all_point_offsets,
const GSpan src,
@ -56,12 +54,16 @@ static void duplicate_fillet_point_data(const bke::CurvesGeometry &src_curves,
{
attribute_math::convert_to_static_type(dst.type(), [&](auto dummy) {
using T = decltype(dummy);
duplicate_fillet_point_data(
src_curves, dst_curves, selection, all_point_offsets, src.typed<T>(), dst.typed<T>());
duplicate_fillet_point_data(src_points_by_curve,
dst_points_by_curve,
selection,
all_point_offsets,
src.typed<T>(),
dst.typed<T>());
});
}
static void calculate_result_offsets(const bke::CurvesGeometry &src_curves,
static void calculate_result_offsets(const OffsetIndices<int> src_points_by_curve,
const IndexMask selection,
const Span<IndexRange> unselected_ranges,
const VArray<float> &radii,
@ -71,11 +73,10 @@ static void calculate_result_offsets(const bke::CurvesGeometry &src_curves,
MutableSpan<int> dst_point_offsets)
{
/* Fill the offsets array with the curve point counts, then accumulate them to form offsets. */
bke::curves::copy_curve_sizes(src_curves, unselected_ranges, dst_curve_offsets);
const OffsetIndices points_by_curve = src_curves.points_by_curve();
bke::curves::copy_curve_sizes(src_points_by_curve, unselected_ranges, dst_curve_offsets);
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
for (const int curve_i : selection.slice(range)) {
const IndexRange src_points = points_by_curve[curve_i];
const IndexRange src_points = src_points_by_curve[curve_i];
const IndexRange offsets_range = bke::curves::per_curve_point_offsets_range(src_points,
curve_i);
@ -403,18 +404,18 @@ static bke::CurvesGeometry fillet_curves(
const bool use_bezier_mode,
const bke::AnonymousAttributePropagationInfo &propagation_info)
{
const Vector<IndexRange> unselected_ranges = curve_selection.extract_ranges_invert(
src_curves.curves_range());
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
const Span<float3> positions = src_curves.positions();
const VArraySpan<bool> cyclic{src_curves.cyclic()};
const bke::AttributeAccessor src_attributes = src_curves.attributes();
const Vector<IndexRange> unselected_ranges = curve_selection.extract_ranges_invert(
src_curves.curves_range());
bke::CurvesGeometry dst_curves = bke::curves::copy_only_curve_domain(src_curves);
/* Stores the offset of every result point for every original point.
* The extra length is used in order to store an extra zero for every curve. */
Array<int> dst_point_offsets(src_curves.points_num() + src_curves.curves_num());
calculate_result_offsets(src_curves,
calculate_result_offsets(src_points_by_curve,
curve_selection,
unselected_ranges,
radius_input,
@ -422,6 +423,7 @@ static bke::CurvesGeometry fillet_curves(
cyclic,
dst_curves.offsets_for_write(),
dst_point_offsets);
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
const Span<int> all_point_offsets = dst_point_offsets.as_span();
dst_curves.resize(dst_curves.offsets().last(), dst_curves.curves_num());
@ -448,8 +450,6 @@ static bke::CurvesGeometry fillet_curves(
dst_handles_r = dst_curves.handle_positions_right_for_write();
}
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
threading::parallel_for(curve_selection.index_range(), 512, [&](IndexRange range) {
Array<float3> directions;
Array<float> angles;
@ -525,8 +525,8 @@ static bke::CurvesGeometry fillet_curves(
ATTR_DOMAIN_MASK_POINT,
propagation_info,
{"position", "handle_type_left", "handle_type_right", "handle_right", "handle_left"})) {
duplicate_fillet_point_data(src_curves,
dst_curves,
duplicate_fillet_point_data(src_points_by_curve,
dst_points_by_curve,
curve_selection,
all_point_offsets,
attribute.src,
@ -537,8 +537,11 @@ static bke::CurvesGeometry fillet_curves(
if (!unselected_ranges.is_empty()) {
for (auto &attribute : bke::retrieve_attributes_for_transfer(
src_attributes, dst_attributes, ATTR_DOMAIN_MASK_POINT, propagation_info)) {
bke::curves::copy_point_data(
src_curves, dst_curves, unselected_ranges, attribute.src, attribute.dst.span);
bke::curves::copy_point_data(src_points_by_curve,
dst_points_by_curve,
unselected_ranges,
attribute.src,
attribute.dst.span);
attribute.dst.finish();
}
}

View File

@ -192,29 +192,36 @@ static void copy_or_defaults_for_unselected_curves(const CurvesGeometry &src_cur
const AttributesForInterpolation &attributes,
CurvesGeometry &dst_curves)
{
bke::curves::copy_point_data(src_curves,
dst_curves,
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
bke::curves::copy_point_data(src_points_by_curve,
dst_points_by_curve,
unselected_ranges,
src_curves.positions(),
dst_curves.positions_for_write());
for (const int i : attributes.src.index_range()) {
bke::curves::copy_point_data(
src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
bke::curves::copy_point_data(src_points_by_curve,
dst_points_by_curve,
unselected_ranges,
attributes.src[i],
attributes.dst[i]);
}
for (const int i : attributes.src_no_interpolation.index_range()) {
bke::curves::copy_point_data(src_curves,
dst_curves,
bke::curves::copy_point_data(src_points_by_curve,
dst_points_by_curve,
unselected_ranges,
attributes.src_no_interpolation[i],
attributes.dst_no_interpolation[i]);
}
if (!attributes.dst_tangents.is_empty()) {
bke::curves::fill_points(dst_curves, unselected_ranges, float3(0), attributes.dst_tangents);
bke::curves::fill_points(
dst_points_by_curve, unselected_ranges, float3(0), attributes.dst_tangents);
}
if (!attributes.dst_normals.is_empty()) {
bke::curves::fill_points(dst_curves, unselected_ranges, float3(0), attributes.dst_normals);
bke::curves::fill_points(
dst_points_by_curve, unselected_ranges, float3(0), attributes.dst_normals);
}
}
@ -239,6 +246,12 @@ static CurvesGeometry resample_to_uniform(const CurvesGeometry &src_curves,
const fn::Field<int> &count_field,
const ResampleCurvesOutputAttributeIDs &output_ids)
{
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
const OffsetIndices evaluated_points_by_curve = src_curves.evaluated_points_by_curve();
const VArray<bool> curves_cyclic = src_curves.cyclic();
const VArray<int8_t> curve_types = src_curves.curve_types();
const Span<float3> evaluated_positions = src_curves.evaluated_positions();
CurvesGeometry dst_curves = bke::curves::copy_only_curve_domain(src_curves);
MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
@ -252,18 +265,13 @@ static CurvesGeometry resample_to_uniform(const CurvesGeometry &src_curves,
src_curves.curves_range(), nullptr);
/* Fill the counts for the curves that aren't selected and accumulate the counts into offsets. */
bke::curves::copy_curve_sizes(src_curves, unselected_ranges, dst_offsets);
bke::curves::copy_curve_sizes(src_points_by_curve, unselected_ranges, dst_offsets);
offset_indices::accumulate_counts_to_offsets(dst_offsets);
dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
/* All resampled curves are poly curves. */
dst_curves.fill_curve_types(selection, CURVE_TYPE_POLY);
const OffsetIndices evaluated_points_by_curve = src_curves.evaluated_points_by_curve();
const VArray<bool> curves_cyclic = src_curves.cyclic();
const VArray<int8_t> curve_types = src_curves.curve_types();
const Span<float3> evaluated_positions = src_curves.evaluated_positions();
MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
AttributesForInterpolation attributes;
@ -280,7 +288,6 @@ static CurvesGeometry resample_to_uniform(const CurvesGeometry &src_curves,
Array<float> sample_factors(dst_curves.points_num());
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
/* Use a "for each group of curves: for each attribute: for each curve" pattern to work on
* smaller sections of data that ideally fit into CPU cache better than simply one attribute at a
@ -403,6 +410,10 @@ CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
const fn::Field<bool> &selection_field,
const ResampleCurvesOutputAttributeIDs &output_ids)
{
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
const OffsetIndices src_evaluated_points_by_curve = src_curves.evaluated_points_by_curve();
const Span<float3> evaluated_positions = src_curves.evaluated_positions();
const bke::CurvesFieldContext field_context{src_curves, ATTR_DOMAIN_CURVE};
fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
evaluator.set_selection(selection_field);
@ -410,25 +421,17 @@ CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
src_curves.curves_range(), nullptr);
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
const OffsetIndices src_evaluated_points_by_curve = src_curves.evaluated_points_by_curve();
CurvesGeometry dst_curves = bke::curves::copy_only_curve_domain(src_curves);
dst_curves.fill_curve_types(selection, CURVE_TYPE_POLY);
MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
threading::parallel_for(selection.index_range(), 4096, [&](IndexRange range) {
for (const int i : selection.slice(range)) {
dst_offsets[i] = src_evaluated_points_by_curve.size(i);
}
});
bke::curves::copy_curve_sizes(src_curves, unselected_ranges, dst_offsets);
bke::curves::copy_curve_sizes(src_evaluated_points_by_curve, selection, dst_offsets);
bke::curves::copy_curve_sizes(src_points_by_curve, unselected_ranges, dst_offsets);
offset_indices::accumulate_counts_to_offsets(dst_offsets);
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
/* Create the correct number of uniform-length samples for every selected curve. */
const Span<float3> evaluated_positions = src_curves.evaluated_positions();
MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
AttributesForInterpolation attributes;

View File

@ -277,43 +277,44 @@ static int to_nurbs_size(const CurveType src_type, const int src_size)
}
}
static void retrieve_curve_sizes(const bke::CurvesGeometry &curves, MutableSpan<int> sizes)
{
const OffsetIndices points_by_curve = curves.points_by_curve();
threading::parallel_for(curves.curves_range(), 4096, [&](IndexRange range) {
for (const int i : range) {
sizes[i] = points_by_curve[i].size();
}
});
}
static bke::CurvesGeometry convert_curves_to_bezier(
const bke::CurvesGeometry &src_curves,
const IndexMask selection,
const bke::AnonymousAttributePropagationInfo &propagation_info)
{
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
const VArray<int8_t> src_knot_modes = src_curves.nurbs_knots_modes();
const VArray<int8_t> src_types = src_curves.curve_types();
const VArray<bool> src_cyclic = src_curves.cyclic();
const Span<float3> src_positions = src_curves.positions();
const bke::AttributeAccessor src_attributes = src_curves.attributes();
const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
src_curves.curves_range());
bke::CurvesGeometry dst_curves = bke::curves::copy_only_curve_domain(src_curves);
dst_curves.fill_curve_types(selection, CURVE_TYPE_BEZIER);
MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
retrieve_curve_sizes(src_curves, dst_curves.offsets_for_write());
bke::curves::copy_curve_sizes(src_points_by_curve, unselected_ranges, dst_offsets);
threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
for (const int i : selection.slice(range)) {
dst_offsets[i] = to_bezier_size(
CurveType(src_types[i]), src_cyclic[i], KnotsMode(src_knot_modes[i]), dst_offsets[i]);
dst_offsets[i] = to_bezier_size(CurveType(src_types[i]),
src_cyclic[i],
KnotsMode(src_knot_modes[i]),
src_points_by_curve.size(i));
}
});
offset_indices::accumulate_counts_to_offsets(dst_offsets);
dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
const bke::AttributeAccessor src_attributes = src_curves.attributes();
MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
MutableSpan<float3> dst_handles_l = dst_curves.handle_positions_left_for_write();
MutableSpan<float3> dst_handles_r = dst_curves.handle_positions_right_for_write();
MutableSpan<int8_t> dst_types_l = dst_curves.handle_types_left_for_write();
MutableSpan<int8_t> dst_types_r = dst_curves.handle_types_right_for_write();
MutableSpan<float> dst_weights = dst_curves.nurbs_weights_for_write();
bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
Vector<bke::AttributeTransferData> generic_attributes = bke::retrieve_attributes_for_transfer(
src_attributes,
dst_attributes,
@ -326,20 +327,13 @@ static bke::CurvesGeometry convert_curves_to_bezier(
"handle_left",
"nurbs_weight"});
MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
MutableSpan<float3> dst_handles_l = dst_curves.handle_positions_left_for_write();
MutableSpan<float3> dst_handles_r = dst_curves.handle_positions_right_for_write();
MutableSpan<int8_t> dst_types_l = dst_curves.handle_types_left_for_write();
MutableSpan<int8_t> dst_types_r = dst_curves.handle_types_right_for_write();
MutableSpan<float> dst_weights = dst_curves.nurbs_weights_for_write();
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
auto catmull_rom_to_bezier = [&](IndexMask selection) {
bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_l);
bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_r);
bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
bke::curves::fill_points<int8_t>(
dst_points_by_curve, selection, BEZIER_HANDLE_ALIGN, dst_types_l);
bke::curves::fill_points<int8_t>(
dst_points_by_curve, selection, BEZIER_HANDLE_ALIGN, dst_types_r);
bke::curves::copy_point_data(
src_points_by_curve, dst_points_by_curve, selection, src_positions, dst_positions);
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
for (const int i : selection.slice(range)) {
@ -354,18 +348,21 @@ static bke::CurvesGeometry convert_curves_to_bezier(
for (bke::AttributeTransferData &attribute : generic_attributes) {
bke::curves::copy_point_data(
src_curves, dst_curves, selection, attribute.src, attribute.dst.span);
src_points_by_curve, dst_points_by_curve, selection, attribute.src, attribute.dst.span);
}
};
auto poly_to_bezier = [&](IndexMask selection) {
bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_VECTOR, dst_types_l);
bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_VECTOR, dst_types_r);
bke::curves::copy_point_data(
src_points_by_curve, dst_points_by_curve, selection, src_positions, dst_positions);
bke::curves::fill_points<int8_t>(
dst_points_by_curve, selection, BEZIER_HANDLE_VECTOR, dst_types_l);
bke::curves::fill_points<int8_t>(
dst_points_by_curve, selection, BEZIER_HANDLE_VECTOR, dst_types_r);
dst_curves.calculate_bezier_auto_handles();
for (bke::AttributeTransferData &attribute : generic_attributes) {
bke::curves::copy_point_data(
src_curves, dst_curves, selection, attribute.src, attribute.dst.span);
src_points_by_curve, dst_points_by_curve, selection, attribute.src, attribute.dst.span);
}
};
@ -375,24 +372,31 @@ static bke::CurvesGeometry convert_curves_to_bezier(
const Span<float3> src_handles_l = src_curves.handle_positions_left();
const Span<float3> src_handles_r = src_curves.handle_positions_right();
bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
bke::curves::copy_point_data(src_curves, dst_curves, selection, src_handles_l, dst_handles_l);
bke::curves::copy_point_data(src_curves, dst_curves, selection, src_handles_r, dst_handles_r);
bke::curves::copy_point_data(src_curves, dst_curves, selection, src_types_l, dst_types_l);
bke::curves::copy_point_data(src_curves, dst_curves, selection, src_types_r, dst_types_r);
bke::curves::copy_point_data(
src_points_by_curve, dst_points_by_curve, selection, src_positions, dst_positions);
bke::curves::copy_point_data(
src_points_by_curve, dst_points_by_curve, selection, src_handles_l, dst_handles_l);
bke::curves::copy_point_data(
src_points_by_curve, dst_points_by_curve, selection, src_handles_r, dst_handles_r);
bke::curves::copy_point_data(
src_points_by_curve, dst_points_by_curve, selection, src_types_l, dst_types_l);
bke::curves::copy_point_data(
src_points_by_curve, dst_points_by_curve, selection, src_types_r, dst_types_r);
dst_curves.calculate_bezier_auto_handles();
for (bke::AttributeTransferData &attribute : generic_attributes) {
bke::curves::copy_point_data(
src_curves, dst_curves, selection, attribute.src, attribute.dst.span);
src_points_by_curve, dst_points_by_curve, selection, attribute.src, attribute.dst.span);
}
};
auto nurbs_to_bezier = [&](IndexMask selection) {
bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_l);
bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_r);
bke::curves::fill_points<float>(dst_curves, selection, 0.0f, dst_weights);
bke::curves::fill_points<int8_t>(
dst_points_by_curve, selection, BEZIER_HANDLE_ALIGN, dst_types_l);
bke::curves::fill_points<int8_t>(
dst_points_by_curve, selection, BEZIER_HANDLE_ALIGN, dst_types_r);
bke::curves::fill_points<float>(dst_points_by_curve, selection, 0.0f, dst_weights);
threading::parallel_for(selection.index_range(), 64, [&](IndexRange range) {
for (const int i : selection.slice(range)) {
@ -452,12 +456,12 @@ static bke::CurvesGeometry convert_curves_to_bezier(
bezier_to_bezier,
nurbs_to_bezier);
const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
src_curves.curves_range());
for (bke::AttributeTransferData &attribute : generic_attributes) {
bke::curves::copy_point_data(
src_curves, dst_curves, unselected_ranges, attribute.src, attribute.dst.span);
bke::curves::copy_point_data(src_points_by_curve,
dst_points_by_curve,
unselected_ranges,
attribute.src,
attribute.dst.span);
}
for (bke::AttributeTransferData &attribute : generic_attributes) {
@ -472,26 +476,30 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
const IndexMask selection,
const bke::AnonymousAttributePropagationInfo &propagation_info)
{
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
const VArray<int8_t> src_types = src_curves.curve_types();
const VArray<bool> src_cyclic = src_curves.cyclic();
const Span<float3> src_positions = src_curves.positions();
const bke::AttributeAccessor src_attributes = src_curves.attributes();
const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
src_curves.curves_range());
bke::CurvesGeometry dst_curves = bke::curves::copy_only_curve_domain(src_curves);
dst_curves.fill_curve_types(selection, CURVE_TYPE_NURBS);
MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
retrieve_curve_sizes(src_curves, dst_curves.offsets_for_write());
bke::curves::copy_curve_sizes(src_points_by_curve, unselected_ranges, dst_offsets);
threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
for (const int i : selection.slice(range)) {
dst_offsets[i] = to_nurbs_size(CurveType(src_types[i]), dst_offsets[i]);
dst_offsets[i] = to_nurbs_size(CurveType(src_types[i]), src_points_by_curve.size(i));
}
});
offset_indices::accumulate_counts_to_offsets(dst_offsets);
dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
const bke::AttributeAccessor src_attributes = src_curves.attributes();
MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
Vector<bke::AttributeTransferData> generic_attributes = bke::retrieve_attributes_for_transfer(
src_attributes,
dst_attributes,
@ -504,17 +512,13 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
"handle_left",
"nurbs_weight"});
MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
auto fill_weights_if_necessary = [&](const IndexMask selection) {
if (!src_curves.nurbs_weights().is_empty()) {
bke::curves::fill_points(dst_curves, selection, 1.0f, dst_curves.nurbs_weights_for_write());
bke::curves::fill_points(
dst_points_by_curve, selection, 1.0f, dst_curves.nurbs_weights_for_write());
}
};
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
auto catmull_rom_to_nurbs = [&](IndexMask selection) {
dst_curves.nurbs_orders_for_write().fill_indices(selection, 4);
dst_curves.nurbs_knots_modes_for_write().fill_indices(selection, NURBS_KNOT_MODE_BEZIER);
@ -543,7 +547,8 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
auto poly_to_nurbs = [&](IndexMask selection) {
dst_curves.nurbs_orders_for_write().fill_indices(selection, 4);
bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
bke::curves::copy_point_data(
src_points_by_curve, dst_points_by_curve, selection, src_positions, dst_positions);
fill_weights_if_necessary(selection);
/* Avoid using "Endpoint" knots modes for cyclic curves, since it adds a sharp point at the
@ -565,7 +570,7 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
for (bke::AttributeTransferData &attribute : generic_attributes) {
bke::curves::copy_point_data(
src_curves, dst_curves, selection, attribute.src, attribute.dst.span);
src_points_by_curve, dst_points_by_curve, selection, attribute.src, attribute.dst.span);
}
};
@ -601,11 +606,12 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
};
auto nurbs_to_nurbs = [&](IndexMask selection) {
bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
bke::curves::copy_point_data(
src_points_by_curve, dst_points_by_curve, selection, src_positions, dst_positions);
if (!src_curves.nurbs_weights().is_empty()) {
bke::curves::copy_point_data(src_curves,
dst_curves,
bke::curves::copy_point_data(src_points_by_curve,
dst_points_by_curve,
selection,
src_curves.nurbs_weights(),
dst_curves.nurbs_weights_for_write());
@ -613,7 +619,7 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
for (bke::AttributeTransferData &attribute : generic_attributes) {
bke::curves::copy_point_data(
src_curves, dst_curves, selection, attribute.src, attribute.dst.span);
src_points_by_curve, dst_points_by_curve, selection, attribute.src, attribute.dst.span);
}
};
@ -625,12 +631,12 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
bezier_to_nurbs,
nurbs_to_nurbs);
const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
src_curves.curves_range());
for (bke::AttributeTransferData &attribute : generic_attributes) {
bke::curves::copy_point_data(
src_curves, dst_curves, unselected_ranges, attribute.src, attribute.dst.span);
bke::curves::copy_point_data(src_points_by_curve,
dst_points_by_curve,
unselected_ranges,
attribute.src,
attribute.dst.span);
}
for (bke::AttributeTransferData &attribute : generic_attributes) {

View File

@ -20,8 +20,8 @@ static void calculate_result_offsets(const bke::CurvesGeometry &src_curves,
MutableSpan<int> dst_point_offsets)
{
/* Fill the array with each curve's point count, then accumulate them to the offsets. */
bke::curves::copy_curve_sizes(src_curves, unselected_ranges, dst_curve_offsets);
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
bke::curves::copy_curve_sizes(src_points_by_curve, unselected_ranges, dst_curve_offsets);
threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
for (const int curve_i : selection.slice(range)) {
const IndexRange src_points = src_points_by_curve[curve_i];
@ -64,15 +64,13 @@ static inline void linear_interpolation(const T &a, const T &b, MutableSpan<T> d
}
template<typename T>
static void subdivide_attribute_linear(const bke::CurvesGeometry &src_curves,
const bke::CurvesGeometry &dst_curves,
static void subdivide_attribute_linear(const OffsetIndices<int> src_points_by_curve,
const OffsetIndices<int> dst_points_by_curve,
const IndexMask selection,
const Span<int> all_point_offsets,
const Span<T> src,
MutableSpan<T> dst)
{
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
threading::parallel_for(selection.index_range(), 512, [&](IndexRange selection_range) {
for (const int curve_i : selection.slice(selection_range)) {
const IndexRange src_points = src_points_by_curve[curve_i];
@ -96,8 +94,8 @@ static void subdivide_attribute_linear(const bke::CurvesGeometry &src_curves,
});
}
static void subdivide_attribute_linear(const bke::CurvesGeometry &src_curves,
const bke::CurvesGeometry &dst_curves,
static void subdivide_attribute_linear(const OffsetIndices<int> src_points_by_curve,
const OffsetIndices<int> dst_points_by_curve,
const IndexMask selection,
const Span<int> all_point_offsets,
const GSpan src,
@ -105,22 +103,24 @@ static void subdivide_attribute_linear(const bke::CurvesGeometry &src_curves,
{
attribute_math::convert_to_static_type(dst.type(), [&](auto dummy) {
using T = decltype(dummy);
subdivide_attribute_linear(
src_curves, dst_curves, selection, all_point_offsets, src.typed<T>(), dst.typed<T>());
subdivide_attribute_linear(src_points_by_curve,
dst_points_by_curve,
selection,
all_point_offsets,
src.typed<T>(),
dst.typed<T>());
});
}
template<typename T>
static void subdivide_attribute_catmull_rom(const bke::CurvesGeometry &src_curves,
const bke::CurvesGeometry &dst_curves,
static void subdivide_attribute_catmull_rom(const OffsetIndices<int> src_points_by_curve,
const OffsetIndices<int> dst_points_by_curve,
const IndexMask selection,
const Span<int> all_point_offsets,
const Span<bool> cyclic,
const Span<T> src,
MutableSpan<T> dst)
{
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
threading::parallel_for(selection.index_range(), 512, [&](IndexRange selection_range) {
for (const int curve_i : selection.slice(selection_range)) {
const IndexRange src_points = src_points_by_curve[curve_i];
@ -135,8 +135,8 @@ static void subdivide_attribute_catmull_rom(const bke::CurvesGeometry &src_curve
});
}
static void subdivide_attribute_catmull_rom(const bke::CurvesGeometry &src_curves,
const bke::CurvesGeometry &dst_curves,
static void subdivide_attribute_catmull_rom(const OffsetIndices<int> src_points_by_curve,
const OffsetIndices<int> dst_points_by_curve,
const IndexMask selection,
const Span<int> all_point_offsets,
const Span<bool> cyclic,
@ -145,8 +145,8 @@ static void subdivide_attribute_catmull_rom(const bke::CurvesGeometry &src_curve
{
attribute_math::convert_to_static_type(dst.type(), [&](auto dummy) {
using T = decltype(dummy);
subdivide_attribute_catmull_rom(src_curves,
dst_curves,
subdivide_attribute_catmull_rom(src_points_by_curve,
dst_points_by_curve,
selection,
all_point_offsets,
cyclic,
@ -300,11 +300,11 @@ bke::CurvesGeometry subdivide_curves(
const VArray<int> &cuts,
const bke::AnonymousAttributePropagationInfo &propagation_info)
{
const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
src_curves.curves_range());
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
/* Cyclic is accessed a lot, it's probably worth it to make sure it's a span. */
const VArraySpan<bool> cyclic{src_curves.cyclic()};
const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
src_curves.curves_range());
bke::CurvesGeometry dst_curves = bke::curves::copy_only_curve_domain(src_curves);
@ -331,6 +331,8 @@ bke::CurvesGeometry subdivide_curves(
cyclic,
dst_curves.offsets_for_write(),
all_point_offset_data);
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
const Span<int> all_point_offsets(all_point_offset_data);
dst_curves.resize(dst_curves.offsets().last(), dst_curves.curves_num());
@ -341,8 +343,8 @@ bke::CurvesGeometry subdivide_curves(
auto subdivide_catmull_rom = [&](IndexMask selection) {
for (auto &attribute : bke::retrieve_attributes_for_transfer(
src_attributes, dst_attributes, ATTR_DOMAIN_MASK_POINT, propagation_info)) {
subdivide_attribute_catmull_rom(src_curves,
dst_curves,
subdivide_attribute_catmull_rom(src_points_by_curve,
dst_points_by_curve,
selection,
all_point_offsets,
cyclic,
@ -355,8 +357,12 @@ bke::CurvesGeometry subdivide_curves(
auto subdivide_poly = [&](IndexMask selection) {
for (auto &attribute : bke::retrieve_attributes_for_transfer(
src_attributes, dst_attributes, ATTR_DOMAIN_MASK_POINT, propagation_info)) {
subdivide_attribute_linear(
src_curves, dst_curves, selection, all_point_offsets, attribute.src, attribute.dst.span);
subdivide_attribute_linear(src_points_by_curve,
dst_points_by_curve,
selection,
all_point_offsets,
attribute.src,
attribute.dst.span);
attribute.dst.finish();
}
};
@ -367,7 +373,6 @@ bke::CurvesGeometry subdivide_curves(
const VArraySpan<int8_t> src_types_r{src_curves.handle_types_right()};
const Span<float3> src_handles_l = src_curves.handle_positions_left();
const Span<float3> src_handles_r = src_curves.handle_positions_right();
const OffsetIndices<int> src_points_by_curve = src_curves.points_by_curve();
MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
MutableSpan<int8_t> dst_types_l = dst_curves.handle_types_left_for_write();
@ -406,8 +411,12 @@ bke::CurvesGeometry subdivide_curves(
"handle_type_right",
"handle_right",
"handle_left"})) {
subdivide_attribute_linear(
src_curves, dst_curves, selection, all_point_offsets, attribute.src, attribute.dst.span);
subdivide_attribute_linear(src_points_by_curve,
dst_points_by_curve,
selection,
all_point_offsets,
attribute.src,
attribute.dst.span);
attribute.dst.finish();
}
};
@ -427,8 +436,11 @@ bke::CurvesGeometry subdivide_curves(
if (!unselected_ranges.is_empty()) {
for (auto &attribute : bke::retrieve_attributes_for_transfer(
src_attributes, dst_attributes, ATTR_DOMAIN_MASK_POINT, propagation_info)) {
bke::curves::copy_point_data(
src_curves, dst_curves, unselected_ranges, attribute.src, attribute.dst.span);
bke::curves::copy_point_data(src_points_by_curve,
dst_points_by_curve,
unselected_ranges,
attribute.src,
attribute.dst.span);
attribute.dst.finish();
}
}

View File

@ -212,7 +212,8 @@ static void fill_nurbs_data(bke::CurvesGeometry &dst_curves, const IndexMask sel
if (!dst_curves.has_curve_with_type(CURVE_TYPE_NURBS)) {
return;
}
bke::curves::fill_points(dst_curves, selection, 0.0f, dst_curves.nurbs_weights_for_write());
bke::curves::fill_points(
dst_curves.points_by_curve(), selection, 0.0f, dst_curves.nurbs_weights_for_write());
}
template<typename T>
@ -950,21 +951,21 @@ bke::CurvesGeometry trim_curves(const bke::CurvesGeometry &src_curves,
const GeometryNodeCurveSampleMode mode,
const bke::AnonymousAttributePropagationInfo &propagation_info)
{
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
src_curves.curves_range());
BLI_assert(selection.size() > 0);
BLI_assert(selection.last() <= src_curves.curves_num());
BLI_assert(starts.size() == src_curves.curves_num());
BLI_assert(starts.size() == ends.size());
src_curves.ensure_evaluated_lengths();
const Vector<IndexRange> inverse_selection = selection.extract_ranges_invert(
src_curves.curves_range());
bke::CurvesGeometry dst_curves = bke::curves::copy_only_curve_domain(src_curves);
MutableSpan<int> dst_curve_offsets = dst_curves.offsets_for_write();
Array<bke::curves::CurvePoint, 16> start_points(src_curves.curves_num());
Array<bke::curves::CurvePoint, 16> end_points(src_curves.curves_num());
Array<bke::curves::IndexRangeCyclic, 16> src_ranges(src_curves.curves_num());
compute_curve_trim_parameters(src_curves,
selection,
starts,
@ -974,10 +975,9 @@ bke::CurvesGeometry trim_curves(const bke::CurvesGeometry &src_curves,
start_points,
end_points,
src_ranges);
bke::curves::copy_curve_sizes(src_curves, inverse_selection, dst_curve_offsets);
/* Finalize and update the geometry container. */
bke::curves::copy_curve_sizes(src_points_by_curve, unselected_ranges, dst_curve_offsets);
offset_indices::accumulate_counts_to_offsets(dst_curve_offsets);
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
dst_curves.resize(dst_curves.offsets().last(), dst_curves.curves_num());
/* Populate curve domain. */
@ -1058,7 +1058,7 @@ bke::CurvesGeometry trim_curves(const bke::CurvesGeometry &src_curves,
}
/* Copy unselected */
if (inverse_selection.is_empty()) {
if (unselected_ranges.is_empty()) {
/* Since all curves were trimmed, none of them are cyclic and the attribute can be removed. */
dst_curves.attributes_for_write().remove("cyclic");
}
@ -1081,8 +1081,11 @@ bke::CurvesGeometry trim_curves(const bke::CurvesGeometry &src_curves,
ATTR_DOMAIN_MASK_POINT,
propagation_info,
copy_point_skip)) {
bke::curves::copy_point_data(
src_curves, dst_curves, inverse_selection, attribute.src, attribute.dst.span);
bke::curves::copy_point_data(src_points_by_curve,
dst_points_by_curve,
unselected_ranges,
attribute.src,
attribute.dst.span);
attribute.dst.finish();
}
}