Curves: Use simpler index mask logic in various places

In several nodes, and sculpt brushes, use the proper `IndexMask` type
instead of a span of ranges to encode a selection. This allows deleting
the duplicate data copying utilities using the second format.
This commit is contained in:
Hans Goudey
2023-05-26 13:18:15 -04:00
parent f63cfd8e28
commit d7e671028c
9 changed files with 58 additions and 146 deletions

View File

@@ -473,12 +473,6 @@ class IndexRangeCyclic {
* ranges, assuming that all curves have the same number of control points in #src_curves
* and #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(OffsetIndices<int> src_points_by_curve,
OffsetIndices<int> dst_points_by_curve,
const IndexMask &src_curve_selection,
@@ -513,20 +507,6 @@ void fill_points(const OffsetIndices<int> points_by_curve,
fill_points(points_by_curve, curve_selection, &value, dst);
}
void fill_points(const OffsetIndices<int> points_by_curve,
Span<IndexRange> curve_ranges,
GPointer value,
GMutableSpan dst);
template<typename T>
void fill_points(const OffsetIndices<int> points_by_curve,
Span<IndexRange> curve_ranges,
const T &value,
MutableSpan<T> dst)
{
fill_points(points_by_curve, curve_ranges, &value, dst);
}
/**
* Create new curves with the same number of curves as the input, but no points. Copy all curve
* domain attributes to the new curves, except the offsets encoding the size of each curve.
@@ -538,14 +518,6 @@ void fill_points(const OffsetIndices<int> points_by_curve,
*/
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.
*/
void copy_curve_sizes(OffsetIndices<int> points_by_curve,
Span<IndexRange> curve_ranges,
MutableSpan<int> sizes);
IndexMask indices_for_type(const VArray<int8_t> &types,
const std::array<int, CURVE_TYPES_NUM> &type_counts,
const CurveType type,

View File

@@ -8,37 +8,6 @@
namespace blender::bke::curves {
void copy_curve_sizes(const OffsetIndices<int> points_by_curve,
const Span<IndexRange> curve_ranges,
MutableSpan<int> sizes)
{
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) {
for (const int i : range) {
sizes[i] = points_by_curve[i].size();
}
});
}
});
}
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)
{
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];
const IndexRange dst_points = dst_points_by_curve[range];
/* The arrays might be large, so a threaded copy might make sense here too. */
dst.slice(dst_points).copy_from(src.slice(src_points));
}
});
}
void copy_point_data(const OffsetIndices<int> src_points_by_curve,
const OffsetIndices<int> dst_points_by_curve,
const IndexMask &src_curve_selection,
@@ -66,21 +35,6 @@ void fill_points(const OffsetIndices<int> points_by_curve,
});
}
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();
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];
type.fill_assign_n(value.get(), dst.slice(points).data(), points.size());
}
});
}
bke::CurvesGeometry copy_only_curve_domain(const bke::CurvesGeometry &src_curves)
{
bke::CurvesGeometry dst_curves(0, src_curves.curves_num());

View File

@@ -131,14 +131,14 @@ struct DeleteOperationExecutor {
const IndexMask mask_to_delete = IndexMask::from_bools(curves_to_delete, mask_memory);
/* Remove deleted curves from the stored deformed positions. */
const Vector<IndexRange> ranges_to_keep = mask_to_delete.to_ranges_invert(
curves_->curves_range());
IndexMaskMemory memory;
const IndexMask mask_to_keep = mask_to_delete.complement(curves_->curves_range(), memory);
const OffsetIndices points_by_curve = curves_->points_by_curve();
Vector<float3> new_deformed_positions;
for (const IndexRange curves_range : ranges_to_keep) {
mask_to_keep.foreach_index([&](const int64_t i) {
new_deformed_positions.extend(
self_->deformed_positions_.as_span().slice(points_by_curve[curves_range]));
}
self_->deformed_positions_.as_span().slice(points_by_curve[i]));
});
self_->deformed_positions_ = std::move(new_deformed_positions);
curves_->remove_curves(mask_to_delete);

View File

@@ -20,6 +20,7 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
#include "BLI_array_utils.hh"
#include "BLI_enumerable_thread_specific.hh"
#include "BLI_kdtree.h"
#include "BLI_rand.hh"
@@ -607,13 +608,13 @@ struct DensitySubtractOperationExecutor {
const IndexMask mask_to_delete = IndexMask::from_bools(curves_to_delete, mask_memory);
/* Remove deleted curves from the stored deformed root positions. */
const Vector<IndexRange> ranges_to_keep = mask_to_delete.to_ranges_invert(
curves_->curves_range());
IndexMaskMemory memory;
const IndexMask mask_to_keep = mask_to_delete.complement(curves_->curves_range(), memory);
BLI_assert(curves_->curves_num() == self_->deformed_root_positions_.size());
Vector<float3> new_deformed_positions;
for (const IndexRange range : ranges_to_keep) {
new_deformed_positions.extend(self_->deformed_root_positions_.as_span().slice(range));
}
Vector<float3> new_deformed_positions(mask_to_keep.size());
array_utils::gather(self_->deformed_root_positions_.as_span(),
mask_to_keep,
new_deformed_positions.as_mutable_span());
self_->deformed_root_positions_ = std::move(new_deformed_positions);
curves_->remove_curves(mask_to_delete);

View File

@@ -63,7 +63,7 @@ static void duplicate_fillet_point_data(const OffsetIndices<int> src_points_by_c
static void calculate_result_offsets(const OffsetIndices<int> src_points_by_curve,
const IndexMask &selection,
const Span<IndexRange> unselected_ranges,
const IndexMask &unselected,
const VArray<float> &radii,
const VArray<int> &counts,
const Span<bool> cyclic,
@@ -71,7 +71,7 @@ static void calculate_result_offsets(const OffsetIndices<int> src_points_by_curv
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_points_by_curve, unselected_ranges, dst_curve_offsets);
offset_indices::copy_group_sizes(src_points_by_curve, unselected, dst_curve_offsets);
selection.foreach_index(GrainSize(512), [&](const int 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,
@@ -404,8 +404,8 @@ static bke::CurvesGeometry fillet_curves(
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.to_ranges_invert(
src_curves.curves_range());
IndexMaskMemory memory;
const IndexMask unselected = curve_selection.complement(src_curves.curves_range(), memory);
bke::CurvesGeometry dst_curves = bke::curves::copy_only_curve_domain(src_curves);
/* Stores the offset of every result point for every original point.
@@ -413,7 +413,7 @@ static bke::CurvesGeometry fillet_curves(
Array<int> dst_point_offsets(src_curves.points_num() + src_curves.curves_num());
calculate_result_offsets(src_points_by_curve,
curve_selection,
unselected_ranges,
unselected,
radius_input,
counts,
cyclic,
@@ -531,15 +531,12 @@ static bke::CurvesGeometry fillet_curves(
attribute.dst.finish();
}
if (!unselected_ranges.is_empty()) {
if (!unselected.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_points_by_curve,
dst_points_by_curve,
unselected_ranges,
attribute.src,
attribute.dst.span);
bke::curves::copy_point_data(
src_points_by_curve, dst_points_by_curve, unselected, attribute.src, attribute.dst.span);
attribute.dst.finish();
}
}

View File

@@ -186,7 +186,7 @@ static void gather_point_attributes_to_interpolate(
}
static void copy_or_defaults_for_unselected_curves(const CurvesGeometry &src_curves,
const Span<IndexRange> unselected_ranges,
const IndexMask &unselected_curves,
const AttributesForInterpolation &attributes,
CurvesGeometry &dst_curves)
{
@@ -194,32 +194,32 @@ static void copy_or_defaults_for_unselected_curves(const CurvesGeometry &src_cur
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,
unselected_curves,
src_curves.positions(),
dst_curves.positions_for_write());
for (const int i : attributes.src.index_range()) {
bke::curves::copy_point_data(src_points_by_curve,
dst_points_by_curve,
unselected_ranges,
unselected_curves,
attributes.src[i],
attributes.dst[i]);
}
for (const int i : attributes.src_no_interpolation.index_range()) {
bke::curves::copy_point_data(src_points_by_curve,
dst_points_by_curve,
unselected_ranges,
unselected_curves,
attributes.src_no_interpolation[i],
attributes.dst_no_interpolation[i]);
}
if (!attributes.dst_tangents.is_empty()) {
bke::curves::fill_points(
dst_points_by_curve, unselected_ranges, float3(0), attributes.dst_tangents);
dst_points_by_curve, unselected_curves, float3(0), attributes.dst_tangents);
}
if (!attributes.dst_normals.is_empty()) {
bke::curves::fill_points(
dst_points_by_curve, unselected_ranges, float3(0), attributes.dst_normals);
dst_points_by_curve, unselected_curves, float3(0), attributes.dst_normals);
}
}
@@ -259,11 +259,11 @@ static CurvesGeometry resample_to_uniform(const CurvesGeometry &src_curves,
evaluator.add_with_destination(count_field, dst_offsets.drop_back(1));
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
const Vector<IndexRange> unselected_ranges = selection.to_ranges_invert(
src_curves.curves_range());
IndexMaskMemory memory;
const IndexMask unselected = selection.complement(src_curves.curves_range(), memory);
/* Fill the counts for the curves that aren't selected and accumulate the counts into offsets. */
bke::curves::copy_curve_sizes(src_points_by_curve, unselected_ranges, dst_offsets);
offset_indices::copy_group_sizes(src_points_by_curve, unselected, dst_offsets);
offset_indices::accumulate_counts_to_offsets(dst_offsets);
dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
@@ -376,7 +376,7 @@ static CurvesGeometry resample_to_uniform(const CurvesGeometry &src_curves,
}
});
copy_or_defaults_for_unselected_curves(src_curves, unselected_ranges, attributes, dst_curves);
copy_or_defaults_for_unselected_curves(src_curves, unselected, attributes, dst_curves);
for (bke::GSpanAttributeWriter &attribute : attributes.dst_attributes) {
attribute.finish();
@@ -416,14 +416,14 @@ CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
evaluator.set_selection(selection_field);
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
const Vector<IndexRange> unselected_ranges = selection.to_ranges_invert(
src_curves.curves_range());
IndexMaskMemory memory;
const IndexMask unselected = selection.complement(src_curves.curves_range(), memory);
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();
offset_indices::copy_group_sizes(src_evaluated_points_by_curve, selection, dst_offsets);
bke::curves::copy_curve_sizes(src_points_by_curve, unselected_ranges, dst_offsets);
offset_indices::copy_group_sizes(src_points_by_curve, unselected, dst_offsets);
offset_indices::accumulate_counts_to_offsets(dst_offsets);
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
@@ -482,7 +482,7 @@ CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
}
});
copy_or_defaults_for_unselected_curves(src_curves, unselected_ranges, attributes, dst_curves);
copy_or_defaults_for_unselected_curves(src_curves, unselected, attributes, dst_curves);
for (bke::GSpanAttributeWriter &attribute : attributes.dst_attributes) {
attribute.finish();

View File

@@ -288,14 +288,14 @@ static bke::CurvesGeometry convert_curves_to_bezier(
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.to_ranges_invert(
src_curves.curves_range());
IndexMaskMemory memory;
const IndexMask unselected = selection.complement(src_curves.curves_range(), memory);
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();
bke::curves::copy_curve_sizes(src_points_by_curve, unselected_ranges, dst_offsets);
offset_indices::copy_group_sizes(src_points_by_curve, unselected, dst_offsets);
selection.foreach_index(GrainSize(1024), [&](const int i) {
dst_offsets[i] = to_bezier_size(CurveType(src_types[i]),
src_cyclic[i],
@@ -447,11 +447,8 @@ static bke::CurvesGeometry convert_curves_to_bezier(
nurbs_to_bezier);
for (bke::AttributeTransferData &attribute : generic_attributes) {
bke::curves::copy_point_data(src_points_by_curve,
dst_points_by_curve,
unselected_ranges,
attribute.src,
attribute.dst.span);
bke::curves::copy_point_data(
src_points_by_curve, dst_points_by_curve, unselected, attribute.src, attribute.dst.span);
}
for (bke::AttributeTransferData &attribute : generic_attributes) {
@@ -471,14 +468,14 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
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.to_ranges_invert(
src_curves.curves_range());
IndexMaskMemory memory;
const IndexMask unselected = selection.complement(src_curves.curves_range(), memory);
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();
bke::curves::copy_curve_sizes(src_points_by_curve, unselected_ranges, dst_offsets);
offset_indices::copy_group_sizes(src_points_by_curve, unselected, dst_offsets);
selection.foreach_index(GrainSize(1024), [&](const int i) {
dst_offsets[i] = to_nurbs_size(CurveType(src_types[i]), src_points_by_curve[i].size());
});
@@ -615,11 +612,8 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
nurbs_to_nurbs);
for (bke::AttributeTransferData &attribute : generic_attributes) {
bke::curves::copy_point_data(src_points_by_curve,
dst_points_by_curve,
unselected_ranges,
attribute.src,
attribute.dst.span);
bke::curves::copy_point_data(
src_points_by_curve, dst_points_by_curve, unselected, attribute.src, attribute.dst.span);
}
for (bke::AttributeTransferData &attribute : generic_attributes) {

View File

@@ -13,7 +13,7 @@ namespace blender::geometry {
static void calculate_result_offsets(const bke::CurvesGeometry &src_curves,
const IndexMask &selection,
const Span<IndexRange> unselected_ranges,
const IndexMask &unselected,
const VArray<int> &cuts,
const Span<bool> cyclic,
MutableSpan<int> dst_curve_offsets,
@@ -21,7 +21,7 @@ static void calculate_result_offsets(const bke::CurvesGeometry &src_curves,
{
/* Fill the array with each curve's point count, then accumulate them to the 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);
offset_indices::copy_group_sizes(src_points_by_curve, unselected, dst_curve_offsets);
selection.foreach_index(GrainSize(1024), [&](const int curve_i) {
const IndexRange src_points = src_points_by_curve[curve_i];
const IndexRange src_segments = bke::curves::per_curve_point_offsets_range(src_points,
@@ -276,8 +276,8 @@ bke::CurvesGeometry subdivide_curves(
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.to_ranges_invert(
src_curves.curves_range());
IndexMaskMemory memory;
const IndexMask unselected = selection.complement(src_curves.curves_range(), memory);
bke::CurvesGeometry dst_curves = bke::curves::copy_only_curve_domain(src_curves);
@@ -299,7 +299,7 @@ bke::CurvesGeometry subdivide_curves(
#endif
calculate_result_offsets(src_curves,
selection,
unselected_ranges,
unselected,
cuts,
cyclic,
dst_curves.offsets_for_write(),
@@ -404,15 +404,12 @@ bke::CurvesGeometry subdivide_curves(
subdivide_bezier,
subdivide_nurbs);
if (!unselected_ranges.is_empty()) {
if (!unselected.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_points_by_curve,
dst_points_by_curve,
unselected_ranges,
attribute.src,
attribute.dst.span);
bke::curves::copy_point_data(
src_points_by_curve, dst_points_by_curve, unselected, attribute.src, attribute.dst.span);
attribute.dst.finish();
}
}

View File

@@ -937,8 +937,8 @@ bke::CurvesGeometry trim_curves(const bke::CurvesGeometry &src_curves,
const bke::AnonymousAttributePropagationInfo &propagation_info)
{
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
const Vector<IndexRange> unselected_ranges = selection.to_ranges_invert(
src_curves.curves_range());
IndexMaskMemory memory;
const IndexMask unselected = selection.complement(src_curves.curves_range(), memory);
BLI_assert(selection.size() > 0);
BLI_assert(selection.last() <= src_curves.curves_num());
@@ -960,7 +960,7 @@ bke::CurvesGeometry trim_curves(const bke::CurvesGeometry &src_curves,
start_points,
end_points,
src_ranges);
bke::curves::copy_curve_sizes(src_points_by_curve, unselected_ranges, dst_curve_offsets);
offset_indices::copy_group_sizes(src_points_by_curve, unselected, 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());
@@ -1043,7 +1043,7 @@ bke::CurvesGeometry trim_curves(const bke::CurvesGeometry &src_curves,
}
/* Copy unselected */
if (unselected_ranges.is_empty()) {
if (unselected.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");
}
@@ -1068,11 +1068,8 @@ bke::CurvesGeometry trim_curves(const bke::CurvesGeometry &src_curves,
propagation_info,
copy_point_skip))
{
bke::curves::copy_point_data(src_points_by_curve,
dst_points_by_curve,
unselected_ranges,
attribute.src,
attribute.dst.span);
bke::curves::copy_point_data(
src_points_by_curve, dst_points_by_curve, unselected, attribute.src, attribute.dst.span);
attribute.dst.finish();
}
}