Curves: add OffsetIndices abstraction
This changes how we access the points that correspond to each curve in a `CurvesGeometry`. Previously, `CurvesGeometry::points_for_curve(int curve_index) -> IndexRange` was called for every curve in many loops. Now one has to call `CurvesGeometry::points_by_curve() -> OffsetIndices` before the loop and use the returned value inside the loop. While this is a little bit more verbose in general, it has some benefits: * Better standardization of how "offset indices" are used. The new data structure can be used independent of curves. * Allows for better data oriented design. Generally, we want to retrieve all the arrays we need for a loop first and then do the processing. Accessing the old `CurvesGeometry::points_for_curve(...)` did not follow that design because it hid the underlying offset array. * Makes it easier to pass the offsets to a function without having to pass the entire `CurvesGeometry`. * Can improve performance in theory due to one less memory access because `this` does not have to be dereferenced every time. This likely doesn't have a noticable impact in practice. Differential Revision: https://developer.blender.org/D17025
This commit is contained in:
parent
c1d360f7fb
commit
2c2178549b
|
@ -18,6 +18,7 @@
|
|||
#include "BLI_generic_virtual_array.hh"
|
||||
#include "BLI_index_mask.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_offset_indices.hh"
|
||||
#include "BLI_shared_cache.hh"
|
||||
#include "BLI_span.hh"
|
||||
#include "BLI_task.hh"
|
||||
|
@ -164,23 +165,17 @@ class CurvesGeometry : public ::CurvesGeometry {
|
|||
IndexRange points_range() const;
|
||||
IndexRange curves_range() const;
|
||||
|
||||
/**
|
||||
* Number of control points in the indexed curve.
|
||||
*/
|
||||
int points_num_for_curve(const int index) const;
|
||||
|
||||
/**
|
||||
* The index of the first point in every curve. The size of this span is one larger than the
|
||||
* number of curves. Consider using #points_for_curve rather than using the offsets directly.
|
||||
* number of curves. Consider using #points_by_curve rather than using the offsets directly.
|
||||
*/
|
||||
Span<int> offsets() const;
|
||||
MutableSpan<int> offsets_for_write();
|
||||
|
||||
/**
|
||||
* Access a range of indices of point data for a specific curve.
|
||||
* The offsets of every curve into arrays on the points domain.
|
||||
*/
|
||||
IndexRange points_for_curve(int index) const;
|
||||
IndexRange points_for_curves(IndexRange curves) const;
|
||||
OffsetIndices<int> points_by_curve() const;
|
||||
|
||||
/** The type (#CurveType) of each curve, or potentially a single if all are the same type. */
|
||||
VArray<int8_t> curve_types() const;
|
||||
|
@ -852,16 +847,6 @@ inline IndexRange CurvesGeometry::curves_range() const
|
|||
return IndexRange(this->curves_num());
|
||||
}
|
||||
|
||||
inline int CurvesGeometry::points_num_for_curve(const int index) const
|
||||
{
|
||||
BLI_assert(this->curve_num > 0);
|
||||
BLI_assert(this->curve_num > index);
|
||||
BLI_assert(this->curve_offsets != nullptr);
|
||||
const int offset = this->curve_offsets[index];
|
||||
const int offset_next = this->curve_offsets[index + 1];
|
||||
return offset_next - offset;
|
||||
}
|
||||
|
||||
inline bool CurvesGeometry::is_single_type(const CurveType type) const
|
||||
{
|
||||
return this->curve_type_counts()[type] == this->curves_num();
|
||||
|
@ -884,25 +869,9 @@ inline const std::array<int, CURVE_TYPES_NUM> &CurvesGeometry::curve_type_counts
|
|||
return this->runtime->type_counts;
|
||||
}
|
||||
|
||||
inline IndexRange CurvesGeometry::points_for_curve(const int index) const
|
||||
inline OffsetIndices<int> CurvesGeometry::points_by_curve() const
|
||||
{
|
||||
/* Offsets are not allocated when there are no curves. */
|
||||
BLI_assert(this->curve_num > 0);
|
||||
BLI_assert(this->curve_num > index);
|
||||
BLI_assert(this->curve_offsets != nullptr);
|
||||
const int offset = this->curve_offsets[index];
|
||||
const int offset_next = this->curve_offsets[index + 1];
|
||||
return {offset, offset_next - offset};
|
||||
}
|
||||
|
||||
inline IndexRange CurvesGeometry::points_for_curves(const IndexRange curves) const
|
||||
{
|
||||
/* Offsets are not allocated when there are no curves. */
|
||||
BLI_assert(this->curve_num > 0);
|
||||
BLI_assert(this->curve_offsets != nullptr);
|
||||
const int offset = this->curve_offsets[curves.start()];
|
||||
const int offset_next = this->curve_offsets[curves.one_after_last()];
|
||||
return {offset, offset_next - offset};
|
||||
return OffsetIndices<int>({this->curve_offsets, this->curve_num + 1});
|
||||
}
|
||||
|
||||
inline int CurvesGeometry::evaluated_points_num() const
|
||||
|
@ -928,7 +897,8 @@ inline IndexRange CurvesGeometry::evaluated_points_for_curves(const IndexRange c
|
|||
|
||||
inline Span<int> CurvesGeometry::bezier_evaluated_offsets_for_curve(const int curve_index) const
|
||||
{
|
||||
const IndexRange points = this->points_for_curve(curve_index);
|
||||
const OffsetIndices points_by_curve = this->points_by_curve();
|
||||
const IndexRange points = points_by_curve[curve_index];
|
||||
return this->runtime->bezier_evaluated_offsets.as_span().slice(points);
|
||||
}
|
||||
|
||||
|
|
|
@ -532,11 +532,6 @@ void fill_curve_counts(const bke::CurvesGeometry &curves,
|
|||
Span<IndexRange> curve_ranges,
|
||||
MutableSpan<int> counts);
|
||||
|
||||
/**
|
||||
* Turn an array of sizes into the offset at each index including all previous sizes.
|
||||
*/
|
||||
void accumulate_counts_to_offsets(MutableSpan<int> counts_to_offsets, int start_offset = 0);
|
||||
|
||||
IndexMask indices_for_type(const VArray<int8_t> &types,
|
||||
const std::array<int, CURVE_TYPES_NUM> &type_counts,
|
||||
const CurveType type,
|
||||
|
|
|
@ -108,6 +108,7 @@ Curves *curve_legacy_to_curves(const Curve &curve_legacy, const ListBase &nurbs_
|
|||
return curves_id;
|
||||
}
|
||||
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
MutableSpan<float3> positions = curves.positions_for_write();
|
||||
SpanAttributeWriter<float> radius_attribute =
|
||||
curves_attributes.lookup_or_add_for_write_only_span<float>("radius", ATTR_DOMAIN_POINT);
|
||||
|
@ -119,7 +120,7 @@ Curves *curve_legacy_to_curves(const Curve &curve_legacy, const ListBase &nurbs_
|
|||
for (const int curve_i : selection.slice(range)) {
|
||||
const Nurb &src_curve = *src_curves[curve_i];
|
||||
const Span<BPoint> src_points(src_curve.bp, src_curve.pntsu);
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
|
||||
for (const int i : src_points.index_range()) {
|
||||
const BPoint &bp = src_points[i];
|
||||
|
@ -146,7 +147,7 @@ Curves *curve_legacy_to_curves(const Curve &curve_legacy, const ListBase &nurbs_
|
|||
for (const int curve_i : selection.slice(range)) {
|
||||
const Nurb &src_curve = *src_curves[curve_i];
|
||||
const Span<BezTriple> src_points(src_curve.bezt, src_curve.pntsu);
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
|
||||
resolutions[curve_i] = src_curve.resolu;
|
||||
|
||||
|
@ -174,7 +175,7 @@ Curves *curve_legacy_to_curves(const Curve &curve_legacy, const ListBase &nurbs_
|
|||
for (const int curve_i : selection.slice(range)) {
|
||||
const Nurb &src_curve = *src_curves[curve_i];
|
||||
const Span src_points(src_curve.bp, src_curve.pntsu);
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
|
||||
resolutions[curve_i] = src_curve.resolu;
|
||||
nurbs_orders[curve_i] = src_curve.orderu;
|
||||
|
|
|
@ -633,10 +633,11 @@ static void write_sharp_bezier_edges(const CurvesInfo &curves_info,
|
|||
|
||||
sharp_edges = mesh_attributes.lookup_or_add_for_write_span<bool>("sharp_edge", ATTR_DOMAIN_EDGE);
|
||||
|
||||
const OffsetIndices profile_points_by_curve = profile.points_by_curve();
|
||||
const VArray<int8_t> types = profile.curve_types();
|
||||
foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
|
||||
if (types[info.i_profile] == CURVE_TYPE_BEZIER) {
|
||||
const IndexRange points = profile.points_for_curve(info.i_profile);
|
||||
const IndexRange points = profile_points_by_curve[info.i_profile];
|
||||
mark_bezier_vector_edges_sharp(points.size(),
|
||||
info.main_segment_num,
|
||||
profile.bezier_evaluated_offsets_for_curve(info.i_profile),
|
||||
|
|
|
@ -457,6 +457,7 @@ static void calculate_evaluated_offsets(const CurvesGeometry &curves,
|
|||
MutableSpan<int> offsets,
|
||||
MutableSpan<int> bezier_evaluated_offsets)
|
||||
{
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
VArray<int8_t> types = curves.curve_types();
|
||||
VArray<int> resolution = curves.resolution();
|
||||
VArray<bool> cyclic = curves.cyclic();
|
||||
|
@ -468,7 +469,7 @@ static void calculate_evaluated_offsets(const CurvesGeometry &curves,
|
|||
VArray<int8_t> nurbs_knots_modes = curves.nurbs_knots_modes();
|
||||
|
||||
build_offsets(offsets, [&](const int curve_index) -> int {
|
||||
const IndexRange points = curves.points_for_curve(curve_index);
|
||||
const IndexRange points = points_by_curve[curve_index];
|
||||
switch (types[curve_index]) {
|
||||
case CURVE_TYPE_CATMULL_ROM:
|
||||
return curves::catmull_rom::calculate_evaluated_num(
|
||||
|
@ -533,9 +534,10 @@ IndexMask CurvesGeometry::indices_for_curve_type(const CurveType type,
|
|||
|
||||
Array<int> CurvesGeometry::point_to_curve_map() const
|
||||
{
|
||||
const OffsetIndices points_by_curve = this->points_by_curve();
|
||||
Array<int> map(this->points_num());
|
||||
for (const int i : this->curves_range()) {
|
||||
map.as_mutable_span().slice(this->points_for_curve(i)).fill(i);
|
||||
map.as_mutable_span().slice(points_by_curve[i]).fill(i);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
@ -552,13 +554,14 @@ void CurvesGeometry::ensure_nurbs_basis_cache() const
|
|||
this->runtime->nurbs_basis_cache.resize(this->curves_num());
|
||||
MutableSpan<curves::nurbs::BasisCache> basis_caches(this->runtime->nurbs_basis_cache);
|
||||
|
||||
const OffsetIndices points_by_curve = this->points_by_curve();
|
||||
VArray<bool> cyclic = this->cyclic();
|
||||
VArray<int8_t> orders = this->nurbs_orders();
|
||||
VArray<int8_t> knots_modes = this->nurbs_knots_modes();
|
||||
|
||||
threading::parallel_for(nurbs_mask.index_range(), 64, [&](const IndexRange range) {
|
||||
for (const int curve_index : nurbs_mask.slice(range)) {
|
||||
const IndexRange points = this->points_for_curve(curve_index);
|
||||
const IndexRange points = points_by_curve[curve_index];
|
||||
const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index);
|
||||
|
||||
const int8_t order = orders[curve_index];
|
||||
|
@ -597,6 +600,7 @@ Span<float3> CurvesGeometry::evaluated_positions() const
|
|||
MutableSpan<float3> evaluated_positions = this->runtime->evaluated_position_cache;
|
||||
this->runtime->evaluated_positions_span = evaluated_positions;
|
||||
|
||||
const OffsetIndices points_by_curve = this->points_by_curve();
|
||||
VArray<int8_t> types = this->curve_types();
|
||||
VArray<bool> cyclic = this->cyclic();
|
||||
VArray<int> resolution = this->resolution();
|
||||
|
@ -613,7 +617,7 @@ Span<float3> CurvesGeometry::evaluated_positions() const
|
|||
|
||||
threading::parallel_for(this->curves_range(), 128, [&](IndexRange curves_range) {
|
||||
for (const int curve_index : curves_range) {
|
||||
const IndexRange points = this->points_for_curve(curve_index);
|
||||
const IndexRange points = points_by_curve[curve_index];
|
||||
const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index);
|
||||
|
||||
switch (types[curve_index]) {
|
||||
|
@ -677,6 +681,7 @@ Span<float3> CurvesGeometry::evaluated_tangents() const
|
|||
Vector<int64_t> bezier_indices;
|
||||
const IndexMask bezier_mask = this->indices_for_curve_type(CURVE_TYPE_BEZIER, bezier_indices);
|
||||
if (!bezier_mask.is_empty()) {
|
||||
const OffsetIndices points_by_curve = this->points_by_curve();
|
||||
const Span<float3> positions = this->positions();
|
||||
const Span<float3> handles_left = this->handle_positions_left();
|
||||
const Span<float3> handles_right = this->handle_positions_right();
|
||||
|
@ -686,7 +691,7 @@ Span<float3> CurvesGeometry::evaluated_tangents() const
|
|||
if (cyclic[curve_index]) {
|
||||
continue;
|
||||
}
|
||||
const IndexRange points = this->points_for_curve(curve_index);
|
||||
const IndexRange points = points_by_curve[curve_index];
|
||||
const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index);
|
||||
|
||||
const float epsilon = 1e-6f;
|
||||
|
@ -753,6 +758,7 @@ static void evaluate_generic_data_for_curve(
|
|||
Span<float3> CurvesGeometry::evaluated_normals() const
|
||||
{
|
||||
this->runtime->normal_cache_mutex.ensure([&]() {
|
||||
const OffsetIndices points_by_curve = this->points_by_curve();
|
||||
const VArray<int8_t> types = this->curve_types();
|
||||
const VArray<bool> cyclic = this->cyclic();
|
||||
const VArray<int8_t> normal_mode = this->normal_mode();
|
||||
|
@ -792,7 +798,7 @@ Span<float3> CurvesGeometry::evaluated_normals() const
|
|||
/* If the "tilt" attribute exists, rotate the normals around the tangents by the
|
||||
* evaluated angles. We can avoid copying the tilts to evaluate them for poly curves. */
|
||||
if (use_tilt) {
|
||||
const IndexRange points = this->points_for_curve(curve_index);
|
||||
const IndexRange points = points_by_curve[curve_index];
|
||||
if (types[curve_index] == CURVE_TYPE_POLY) {
|
||||
rotate_directions_around_axes(evaluated_normals.slice(evaluated_points),
|
||||
evaluated_tangents.slice(evaluated_points),
|
||||
|
@ -828,7 +834,8 @@ void CurvesGeometry::interpolate_to_evaluated(const int curve_index,
|
|||
{
|
||||
BLI_assert(this->runtime->offsets_cache_mutex.is_cached());
|
||||
BLI_assert(this->runtime->nurbs_basis_cache_mutex.is_cached());
|
||||
const IndexRange points = this->points_for_curve(curve_index);
|
||||
const OffsetIndices points_by_curve = this->points_by_curve();
|
||||
const IndexRange points = points_by_curve[curve_index];
|
||||
BLI_assert(src.size() == points.size());
|
||||
BLI_assert(dst.size() == this->evaluated_points_for_curve(curve_index).size());
|
||||
evaluate_generic_data_for_curve(curve_index,
|
||||
|
@ -848,6 +855,7 @@ void CurvesGeometry::interpolate_to_evaluated(const GSpan src, GMutableSpan dst)
|
|||
{
|
||||
BLI_assert(this->runtime->offsets_cache_mutex.is_cached());
|
||||
BLI_assert(this->runtime->nurbs_basis_cache_mutex.is_cached());
|
||||
const OffsetIndices points_by_curve = this->points_by_curve();
|
||||
const VArray<int8_t> types = this->curve_types();
|
||||
const VArray<int> resolution = this->resolution();
|
||||
const VArray<bool> cyclic = this->cyclic();
|
||||
|
@ -856,7 +864,7 @@ void CurvesGeometry::interpolate_to_evaluated(const GSpan src, GMutableSpan dst)
|
|||
|
||||
threading::parallel_for(this->curves_range(), 512, [&](IndexRange curves_range) {
|
||||
for (const int curve_index : curves_range) {
|
||||
const IndexRange points = this->points_for_curve(curve_index);
|
||||
const IndexRange points = points_by_curve[curve_index];
|
||||
const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index);
|
||||
evaluate_generic_data_for_curve(curve_index,
|
||||
points,
|
||||
|
@ -973,6 +981,7 @@ void CurvesGeometry::calculate_bezier_auto_handles()
|
|||
if (this->handle_positions_left().is_empty() || this->handle_positions_right().is_empty()) {
|
||||
return;
|
||||
}
|
||||
const OffsetIndices points_by_curve = this->points_by_curve();
|
||||
const VArray<int8_t> types = this->curve_types();
|
||||
const VArray<bool> cyclic = this->cyclic();
|
||||
const VArraySpan<int8_t> types_left{this->handle_types_left()};
|
||||
|
@ -984,7 +993,7 @@ void CurvesGeometry::calculate_bezier_auto_handles()
|
|||
threading::parallel_for(this->curves_range(), 128, [&](IndexRange range) {
|
||||
for (const int i_curve : range) {
|
||||
if (types[i_curve] == CURVE_TYPE_BEZIER) {
|
||||
const IndexRange points = this->points_for_curve(i_curve);
|
||||
const IndexRange points = points_by_curve[i_curve];
|
||||
curves::bezier::calculate_auto_handles(cyclic[i_curve],
|
||||
types_left.slice(points),
|
||||
types_right.slice(points),
|
||||
|
@ -1071,10 +1080,11 @@ static void copy_with_map(const GSpan src, const Span<int> map, GMutableSpan dst
|
|||
*/
|
||||
static Array<int> build_point_to_curve_map(const CurvesGeometry &curves)
|
||||
{
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
Array<int> point_to_curve_map(curves.points_num());
|
||||
threading::parallel_for(curves.curves_range(), 1024, [&](const IndexRange curves_range) {
|
||||
for (const int i_curve : curves_range) {
|
||||
point_to_curve_map.as_mutable_span().slice(curves.points_for_curve(i_curve)).fill(i_curve);
|
||||
point_to_curve_map.as_mutable_span().slice(points_by_curve[i_curve]).fill(i_curve);
|
||||
}
|
||||
});
|
||||
return point_to_curve_map;
|
||||
|
@ -1202,6 +1212,7 @@ static CurvesGeometry copy_with_removed_curves(
|
|||
const IndexMask curves_to_delete,
|
||||
const AnonymousAttributePropagationInfo &propagation_info)
|
||||
{
|
||||
const OffsetIndices old_points_by_curve = curves.points_by_curve();
|
||||
const Span<int> old_offsets = curves.offsets();
|
||||
const Vector<IndexRange> old_curve_ranges = curves_to_delete.extract_ranges_invert(
|
||||
curves.curves_range(), nullptr);
|
||||
|
@ -1214,7 +1225,7 @@ static CurvesGeometry copy_with_removed_curves(
|
|||
new_curve_ranges.append(IndexRange(new_tot_curves, curve_range.size()));
|
||||
new_tot_curves += curve_range.size();
|
||||
|
||||
const IndexRange old_point_range = curves.points_for_curves(curve_range);
|
||||
const IndexRange old_point_range = old_points_by_curve[curve_range];
|
||||
old_point_ranges.append(old_point_range);
|
||||
new_point_ranges.append(IndexRange(new_tot_points, old_point_range.size()));
|
||||
new_tot_points += old_point_range.size();
|
||||
|
@ -1319,9 +1330,10 @@ static void reverse_curve_point_data(const CurvesGeometry &curves,
|
|||
const IndexMask curve_selection,
|
||||
MutableSpan<T> data)
|
||||
{
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
threading::parallel_for(curve_selection.index_range(), 256, [&](IndexRange range) {
|
||||
for (const int curve_i : curve_selection.slice(range)) {
|
||||
data.slice(curves.points_for_curve(curve_i)).reverse();
|
||||
data.slice(points_by_curve[curve_i]).reverse();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1332,9 +1344,10 @@ static void reverse_swap_curve_point_data(const CurvesGeometry &curves,
|
|||
MutableSpan<T> data_a,
|
||||
MutableSpan<T> data_b)
|
||||
{
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
threading::parallel_for(curve_selection.index_range(), 256, [&](IndexRange range) {
|
||||
for (const int curve_i : curve_selection.slice(range)) {
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
MutableSpan<T> a = data_a.slice(points);
|
||||
MutableSpan<T> b = data_b.slice(points);
|
||||
for (const int i : IndexRange(points.size() / 2)) {
|
||||
|
@ -1440,9 +1453,10 @@ static void adapt_curve_domain_point_to_curve_impl(const CurvesGeometry &curves,
|
|||
{
|
||||
attribute_math::DefaultMixer<T> mixer(r_values);
|
||||
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
threading::parallel_for(curves.curves_range(), 128, [&](const IndexRange range) {
|
||||
for (const int i_curve : range) {
|
||||
for (const int i_point : curves.points_for_curve(i_curve)) {
|
||||
for (const int i_point : points_by_curve[i_curve]) {
|
||||
mixer.mix_in(i_curve, old_values[i_point]);
|
||||
}
|
||||
}
|
||||
|
@ -1462,9 +1476,10 @@ void adapt_curve_domain_point_to_curve_impl(const CurvesGeometry &curves,
|
|||
const VArray<bool> &old_values,
|
||||
MutableSpan<bool> r_values)
|
||||
{
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
r_values.fill(true);
|
||||
for (const int i_curve : IndexRange(curves.curves_num())) {
|
||||
for (const int i_point : curves.points_for_curve(i_curve)) {
|
||||
for (const int i_point : points_by_curve[i_curve]) {
|
||||
if (!old_values[i_point]) {
|
||||
r_values[i_curve] = false;
|
||||
break;
|
||||
|
@ -1500,8 +1515,9 @@ static void adapt_curve_domain_curve_to_point_impl(const CurvesGeometry &curves,
|
|||
const VArray<T> &old_values,
|
||||
MutableSpan<T> r_values)
|
||||
{
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
for (const int i_curve : IndexRange(curves.curves_num())) {
|
||||
r_values.slice(curves.points_for_curve(i_curve)).fill(old_values[i_curve]);
|
||||
r_values.slice(points_by_curve[i_curve]).fill(old_values[i_curve]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,39 +14,30 @@ void fill_curve_counts(const bke::CurvesGeometry &curves,
|
|||
const Span<IndexRange> curve_ranges,
|
||||
MutableSpan<int> counts)
|
||||
{
|
||||
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) {
|
||||
for (const int i : range) {
|
||||
counts[i] = curves.points_for_curve(i).size();
|
||||
counts[i] = points_by_curve.size(i);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void accumulate_counts_to_offsets(MutableSpan<int> counts_to_offsets, const int start_offset)
|
||||
{
|
||||
int offset = start_offset;
|
||||
for (const int i : counts_to_offsets.index_range().drop_back(1)) {
|
||||
const int count = counts_to_offsets[i];
|
||||
BLI_assert(count > 0);
|
||||
counts_to_offsets[i] = offset;
|
||||
offset += count;
|
||||
}
|
||||
counts_to_offsets.last() = offset;
|
||||
}
|
||||
|
||||
void copy_point_data(const CurvesGeometry &src_curves,
|
||||
const CurvesGeometry &dst_curves,
|
||||
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_curves.points_for_curves(range);
|
||||
const IndexRange dst_points = dst_curves.points_for_curves(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));
|
||||
}
|
||||
|
@ -59,10 +50,12 @@ void copy_point_data(const CurvesGeometry &src_curves,
|
|||
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_curves.points_for_curve(i);
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(i);
|
||||
const IndexRange src_points = src_points_by_curve[i];
|
||||
const IndexRange dst_points = dst_points_by_curve[i];
|
||||
/* The arrays might be large, so a threaded copy might make sense here too. */
|
||||
dst.slice(dst_points).copy_from(src.slice(src_points));
|
||||
}
|
||||
|
@ -76,10 +69,11 @@ void fill_points(const CurvesGeometry &curves,
|
|||
{
|
||||
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 = curves.points_for_curve(i);
|
||||
type.fill_assign_n(value.get(), dst.slice(curves.points_for_curve(i)).data(), points.size());
|
||||
const IndexRange points = points_by_curve[i];
|
||||
type.fill_assign_n(value.get(), dst.slice(points).data(), points.size());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -91,9 +85,10 @@ void fill_points(const CurvesGeometry &curves,
|
|||
{
|
||||
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 = curves.points_for_curves(range);
|
||||
const IndexRange points = points_by_curve[range];
|
||||
type.fill_assign_n(value.get(), dst.slice(points).data(), points.size());
|
||||
}
|
||||
});
|
||||
|
|
|
@ -143,6 +143,7 @@ namespace blender::bke {
|
|||
|
||||
static Array<float3> curve_normal_point_domain(const bke::CurvesGeometry &curves)
|
||||
{
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
const VArray<int8_t> types = curves.curve_types();
|
||||
const VArray<int> resolutions = curves.resolution();
|
||||
const VArray<bool> curves_cyclic = curves.cyclic();
|
||||
|
@ -158,7 +159,7 @@ static Array<float3> curve_normal_point_domain(const bke::CurvesGeometry &curves
|
|||
Vector<float3> nurbs_tangents;
|
||||
|
||||
for (const int i_curve : range) {
|
||||
const IndexRange points = curves.points_for_curve(i_curve);
|
||||
const IndexRange points = points_by_curve[i_curve];
|
||||
const IndexRange evaluated_points = curves.evaluated_points_for_curve(i_curve);
|
||||
|
||||
MutableSpan<float3> curve_normals = results.as_mutable_span().slice(points);
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_index_range.hh"
|
||||
#include "BLI_span.hh"
|
||||
|
||||
namespace blender::offset_indices {
|
||||
|
||||
/**
|
||||
* References an array of ascending indices. A pair of consecutive indices encode an index range.
|
||||
* Another common way to store the same kind of data is to store the start and size of every range
|
||||
* separately. Using offsets instead halves the memory consumption. The downside is that the
|
||||
* array has to be one element longer than the total number of ranges. The extra element is
|
||||
* necessary to be able to get the last index range without requiring an extra branch for the case.
|
||||
*
|
||||
* This class is a thin wrapper around such an array that makes it easy to retrieve the index range
|
||||
* at a specific index.
|
||||
*/
|
||||
template<typename T> class OffsetIndices {
|
||||
private:
|
||||
static_assert(std::is_integral_v<T>);
|
||||
|
||||
Span<T> offsets_;
|
||||
|
||||
public:
|
||||
OffsetIndices(const Span<T> offsets) : offsets_(offsets)
|
||||
{
|
||||
BLI_assert(std::is_sorted(offsets_.begin(), offsets_.end()));
|
||||
}
|
||||
|
||||
T size(const int64_t index) const
|
||||
{
|
||||
BLI_assert(index >= 0);
|
||||
BLI_assert(index < offsets_.size() - 1);
|
||||
const int64_t begin = offsets_[index];
|
||||
const int64_t end = offsets_[index + 1];
|
||||
const int64_t size = end - begin;
|
||||
return size;
|
||||
}
|
||||
|
||||
IndexRange operator[](const int64_t index) const
|
||||
{
|
||||
BLI_assert(index >= 0);
|
||||
BLI_assert(index < offsets_.size() - 1);
|
||||
const int64_t begin = offsets_[index];
|
||||
const int64_t end = offsets_[index + 1];
|
||||
const int64_t size = end - begin;
|
||||
return IndexRange(begin, size);
|
||||
}
|
||||
|
||||
IndexRange operator[](const IndexRange indices) const
|
||||
{
|
||||
const int64_t begin = offsets_[indices.start()];
|
||||
const int64_t end = offsets_[indices.one_after_last()];
|
||||
const int64_t size = end - begin;
|
||||
return IndexRange(begin, size);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Turn an array of sizes into the offset at each index including all previous sizes.
|
||||
*/
|
||||
void accumulate_counts_to_offsets(MutableSpan<int> counts_to_offsets, int start_offset = 0);
|
||||
|
||||
} // namespace blender::offset_indices
|
||||
|
||||
namespace blender {
|
||||
using offset_indices::OffsetIndices;
|
||||
}
|
|
@ -117,6 +117,7 @@ set(SRC
|
|||
intern/mesh_intersect.cc
|
||||
intern/noise.c
|
||||
intern/noise.cc
|
||||
intern/offset_indices.cc
|
||||
intern/path_util.c
|
||||
intern/polyfill_2d.c
|
||||
intern/polyfill_2d_beautify.c
|
||||
|
@ -294,6 +295,7 @@ set(SRC
|
|||
BLI_multi_value_map.hh
|
||||
BLI_noise.h
|
||||
BLI_noise.hh
|
||||
BLI_offset_indices.hh
|
||||
BLI_parameter_pack_utils.hh
|
||||
BLI_path_util.h
|
||||
BLI_polyfill_2d.h
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BLI_offset_indices.hh"
|
||||
|
||||
namespace blender::offset_indices {
|
||||
|
||||
void accumulate_counts_to_offsets(MutableSpan<int> counts_to_offsets, const int start_offset)
|
||||
{
|
||||
int offset = start_offset;
|
||||
for (const int i : counts_to_offsets.index_range().drop_back(1)) {
|
||||
const int count = counts_to_offsets[i];
|
||||
BLI_assert(count > 0);
|
||||
counts_to_offsets[i] = offset;
|
||||
offset += count;
|
||||
}
|
||||
counts_to_offsets.last() = offset;
|
||||
}
|
||||
|
||||
} // namespace blender::offset_indices
|
|
@ -238,11 +238,12 @@ static void curves_batch_cache_fill_segments_proc_pos(
|
|||
using namespace blender;
|
||||
/* TODO: use hair radius layer if available. */
|
||||
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
const Span<float3> positions = curves.positions();
|
||||
|
||||
threading::parallel_for(curves.curves_range(), 1024, [&](const IndexRange range) {
|
||||
for (const int i_curve : range) {
|
||||
const IndexRange points = curves.points_for_curve(i_curve);
|
||||
const IndexRange points = points_by_curve[i_curve];
|
||||
|
||||
Span<float3> curve_positions = positions.slice(points);
|
||||
MutableSpan<PositionAndParameter> curve_posTime_data = posTime_data.slice(points);
|
||||
|
@ -334,6 +335,8 @@ static void curves_batch_cache_ensure_edit_points_data(const Curves &curves_id,
|
|||
GPU_vertbuf_init_with_format(cache.edit_points_data, &format_data);
|
||||
GPU_vertbuf_data_alloc(cache.edit_points_data, curves.points_num());
|
||||
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
|
||||
const VArray<bool> selection = curves.attributes().lookup_or_default<bool>(
|
||||
".selection", eAttrDomain(curves_id.selection_domain), true);
|
||||
switch (curves_id.selection_domain) {
|
||||
|
@ -346,7 +349,7 @@ static void curves_batch_cache_ensure_edit_points_data(const Curves &curves_id,
|
|||
case ATTR_DOMAIN_CURVE:
|
||||
for (const int curve_i : curves.curves_range()) {
|
||||
const float curve_selection = selection[curve_i] ? 1.0f : 0.0f;
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
for (const int point_i : points) {
|
||||
GPU_vertbuf_attr_set(cache.edit_points_data, color, point_i, &curve_selection);
|
||||
}
|
||||
|
@ -367,8 +370,10 @@ static void curves_batch_cache_ensure_edit_lines(const Curves &curves_id, Curves
|
|||
GPUIndexBufBuilder elb;
|
||||
GPU_indexbuf_init_ex(&elb, GPU_PRIM_LINE_STRIP, index_len, vert_len);
|
||||
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
|
||||
for (const int i : curves.curves_range()) {
|
||||
const IndexRange points = curves.points_for_curve(i);
|
||||
const IndexRange points = points_by_curve[i];
|
||||
for (const int i_point : points) {
|
||||
GPU_indexbuf_add_generic_vert(&elb, i_point);
|
||||
}
|
||||
|
@ -460,9 +465,10 @@ static void curves_batch_cache_fill_strands_data(const Curves &curves_id,
|
|||
{
|
||||
const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap(
|
||||
curves_id.geometry);
|
||||
const blender::OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
|
||||
for (const int i : IndexRange(curves.curves_num())) {
|
||||
const IndexRange points = curves.points_for_curve(i);
|
||||
const IndexRange points = points_by_curve[i];
|
||||
|
||||
*(uint *)GPU_vertbuf_raw_step(&data_step) = points.start();
|
||||
*(ushort *)GPU_vertbuf_raw_step(&seg_step) = points.size() - 1;
|
||||
|
|
|
@ -334,7 +334,7 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object,
|
|||
if (curves.curves_num() >= 1) {
|
||||
blender::VArray<float> radii = curves.attributes().lookup_or_default(
|
||||
"radius", ATTR_DOMAIN_POINT, 0.005f);
|
||||
const blender::IndexRange first_curve_points = curves.points_for_curve(0);
|
||||
const blender::IndexRange first_curve_points = curves.points_by_curve()[0];
|
||||
const float first_radius = radii[first_curve_points.first()];
|
||||
const float last_radius = radii[first_curve_points.last()];
|
||||
const float middle_radius = radii[first_curve_points.size() / 2];
|
||||
|
|
|
@ -112,8 +112,9 @@ bke::CurvesGeometry primitive_random_sphere(const int curves_size, const int poi
|
|||
|
||||
RandomNumberGenerator rng;
|
||||
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
for (const int i : curves.curves_range()) {
|
||||
const IndexRange points = curves.points_for_curve(i);
|
||||
const IndexRange points = points_by_curve[i];
|
||||
MutableSpan<float3> curve_positions = positions.slice(points);
|
||||
MutableSpan<float> curve_radii = radius.span.slice(points);
|
||||
|
||||
|
|
|
@ -286,11 +286,12 @@ static void try_convert_single_object(Object &curves_ob,
|
|||
const bke::CurvesSurfaceTransforms transforms{curves_ob, &surface_ob};
|
||||
|
||||
const MFace *mfaces = (const MFace *)CustomData_get_layer(&surface_me.fdata, CD_MFACE);
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
const Span<float3> positions = surface_me.vert_positions();
|
||||
|
||||
for (const int new_hair_i : IndexRange(hair_num)) {
|
||||
const int curve_i = new_hair_i;
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
|
||||
const float3 &root_pos_cu = positions_cu[points.first()];
|
||||
const float3 root_pos_su = transforms.curves_to_surface * root_pos_cu;
|
||||
|
@ -440,6 +441,7 @@ static bke::CurvesGeometry particles_to_curves(Object &object, ParticleSystem &p
|
|||
const float4x4 world_to_object_mat = object_to_world_mat.inverted();
|
||||
|
||||
MutableSpan<float3> positions = curves.positions_for_write();
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
|
||||
const auto copy_hair_to_curves = [&](const Span<ParticleCacheKey *> hair_cache,
|
||||
const Span<int> indices_to_transfer,
|
||||
|
@ -448,7 +450,7 @@ static bke::CurvesGeometry particles_to_curves(Object &object, ParticleSystem &p
|
|||
for (const int i : range) {
|
||||
const int hair_i = indices_to_transfer[i];
|
||||
const int curve_i = i + curve_index_offset;
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
const Span<ParticleCacheKey> keys{hair_cache[hair_i], points.size()};
|
||||
for (const int key_i : keys.index_range()) {
|
||||
const float3 key_pos_wo = keys[key_i].co;
|
||||
|
@ -554,6 +556,7 @@ static void snap_curves_to_surface_exec_object(Object &curves_ob,
|
|||
.typed<float2>();
|
||||
}
|
||||
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
MutableSpan<float3> positions_cu = curves.positions_for_write();
|
||||
MutableSpan<float2> surface_uv_coords = curves.surface_uv_coords_for_write();
|
||||
|
||||
|
@ -567,7 +570,7 @@ static void snap_curves_to_surface_exec_object(Object &curves_ob,
|
|||
|
||||
threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) {
|
||||
for (const int curve_i : curves_range) {
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
const int first_point_i = points.first();
|
||||
const float3 old_first_point_pos_cu = positions_cu[first_point_i];
|
||||
const float3 old_first_point_pos_su = transforms.curves_to_surface *
|
||||
|
@ -625,7 +628,7 @@ static void snap_curves_to_surface_exec_object(Object &curves_ob,
|
|||
|
||||
threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) {
|
||||
for (const int curve_i : curves_range) {
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
const int first_point_i = points.first();
|
||||
const float3 old_first_point_pos_cu = positions_cu[first_point_i];
|
||||
|
||||
|
|
|
@ -32,9 +32,10 @@ static IndexMask retrieve_selected_curves(const bke::CurvesGeometry &curves,
|
|||
if (selection.is_single()) {
|
||||
return selection.get_internal_single() ? IndexMask(curves_range) : IndexMask();
|
||||
}
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
return index_mask_ops::find_indices_based_on_predicate(
|
||||
curves_range, 512, r_indices, [&](const int64_t curve_i) {
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
/* The curve is selected if any of its points are selected. */
|
||||
Array<bool, 32> point_selection(points.size());
|
||||
selection.materialize_compressed(points, point_selection);
|
||||
|
|
|
@ -91,6 +91,8 @@ static std::optional<float3> find_curves_brush_position(const CurvesGeometry &cu
|
|||
}
|
||||
};
|
||||
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
|
||||
BrushPositionCandidate best_candidate = threading::parallel_reduce(
|
||||
curves.curves_range(),
|
||||
128,
|
||||
|
@ -99,7 +101,7 @@ static std::optional<float3> find_curves_brush_position(const CurvesGeometry &cu
|
|||
BrushPositionCandidate best_candidate = init;
|
||||
|
||||
for (const int curve_i : curves_range) {
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
|
||||
if (points.size() == 1) {
|
||||
const float3 &pos_cu = positions[points.first()];
|
||||
|
|
|
@ -189,6 +189,7 @@ struct CombOperationExecutor {
|
|||
MutableSpan<float3> positions_cu_orig = curves_orig_->positions_for_write();
|
||||
const bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *curves_ob_orig_);
|
||||
const OffsetIndices points_by_curve = curves_orig_->points_by_curve();
|
||||
|
||||
float4x4 projection;
|
||||
ED_view3d_ob_project_mat_get(ctx_.rv3d, curves_ob_orig_, projection.values);
|
||||
|
@ -200,7 +201,7 @@ struct CombOperationExecutor {
|
|||
Vector<int> &local_changed_curves = r_changed_curves.local();
|
||||
for (const int curve_i : curve_selection_.slice(range)) {
|
||||
bool curve_changed = false;
|
||||
const IndexRange points = curves_orig_->points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
for (const int point_i : points.drop_front(1)) {
|
||||
const float3 old_pos_cu = deformation.positions[point_i];
|
||||
const float3 old_symm_pos_cu = brush_transform_inv * old_pos_cu;
|
||||
|
@ -295,12 +296,13 @@ struct CombOperationExecutor {
|
|||
|
||||
const bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *curves_ob_orig_);
|
||||
const OffsetIndices points_by_curve = curves_orig_->points_by_curve();
|
||||
|
||||
threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
|
||||
Vector<int> &local_changed_curves = r_changed_curves.local();
|
||||
for (const int curve_i : curve_selection_.slice(range)) {
|
||||
bool curve_changed = false;
|
||||
const IndexRange points = curves_orig_->points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
for (const int point_i : points.drop_front(1)) {
|
||||
const float3 pos_old_cu = deformation.positions[point_i];
|
||||
|
||||
|
@ -359,10 +361,11 @@ struct CombOperationExecutor {
|
|||
void initialize_segment_lengths()
|
||||
{
|
||||
const Span<float3> positions_cu = curves_orig_->positions();
|
||||
const OffsetIndices points_by_curve = curves_orig_->points_by_curve();
|
||||
self_->segment_lengths_cu_.reinitialize(curves_orig_->points_num());
|
||||
threading::parallel_for(curves_orig_->curves_range(), 128, [&](const IndexRange range) {
|
||||
for (const int curve_i : range) {
|
||||
const IndexRange points = curves_orig_->points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
for (const int point_i : points.drop_back(1)) {
|
||||
const float3 &p1_cu = positions_cu[point_i];
|
||||
const float3 &p2_cu = positions_cu[point_i + 1];
|
||||
|
@ -379,12 +382,13 @@ struct CombOperationExecutor {
|
|||
void restore_segment_lengths(EnumerableThreadSpecific<Vector<int>> &changed_curves)
|
||||
{
|
||||
const Span<float> expected_lengths_cu = self_->segment_lengths_cu_;
|
||||
const OffsetIndices points_by_curve = curves_orig_->points_by_curve();
|
||||
MutableSpan<float3> positions_cu = curves_orig_->positions_for_write();
|
||||
|
||||
threading::parallel_for_each(changed_curves, [&](const Vector<int> &changed_curves) {
|
||||
threading::parallel_for(changed_curves.index_range(), 256, [&](const IndexRange range) {
|
||||
for (const int curve_i : changed_curves.as_span().slice(range)) {
|
||||
const IndexRange points = curves_orig_->points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
for (const int segment_i : points.drop_back(1)) {
|
||||
const float3 &p1_cu = positions_cu[segment_i];
|
||||
float3 &p2_cu = positions_cu[segment_i + 1];
|
||||
|
|
|
@ -140,10 +140,11 @@ struct DeleteOperationExecutor {
|
|||
/* Remove deleted curves from the stored deformed positions. */
|
||||
const Vector<IndexRange> ranges_to_keep = mask_to_delete.extract_ranges_invert(
|
||||
curves_->curves_range());
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
Vector<float3> new_deformed_positions;
|
||||
for (const IndexRange curves_range : ranges_to_keep) {
|
||||
new_deformed_positions.extend(
|
||||
self_->deformed_positions_.as_span().slice(curves_->points_for_curves(curves_range)));
|
||||
self_->deformed_positions_.as_span().slice(points_by_curve[curves_range]));
|
||||
}
|
||||
self_->deformed_positions_ = std::move(new_deformed_positions);
|
||||
|
||||
|
@ -172,10 +173,11 @@ struct DeleteOperationExecutor {
|
|||
|
||||
const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
|
||||
const float brush_radius_sq_re = pow2f(brush_radius_re);
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
|
||||
threading::parallel_for(curve_selection_.index_range(), 512, [&](const IndexRange range) {
|
||||
for (const int curve_i : curve_selection_.slice(range)) {
|
||||
const IndexRange points = curves_->points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
if (points.size() == 1) {
|
||||
const float3 pos_cu = brush_transform_inv * self_->deformed_positions_[points.first()];
|
||||
float2 pos_re;
|
||||
|
@ -231,10 +233,11 @@ struct DeleteOperationExecutor {
|
|||
{
|
||||
const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
|
||||
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
|
||||
threading::parallel_for(curve_selection_.index_range(), 512, [&](const IndexRange range) {
|
||||
for (const int curve_i : curve_selection_.slice(range)) {
|
||||
const IndexRange points = curves_->points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
|
||||
if (points.size() == 1) {
|
||||
const float3 &pos_cu = self_->deformed_positions_[points.first()];
|
||||
|
|
|
@ -88,13 +88,14 @@ class ShrinkCurvesEffect : public CurvesEffect {
|
|||
const Span<int> curve_indices,
|
||||
const Span<float> move_distances_cu) override
|
||||
{
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
MutableSpan<float3> positions_cu = curves.positions_for_write();
|
||||
threading::parallel_for(curve_indices.index_range(), 256, [&](const IndexRange range) {
|
||||
ParameterizationBuffers data;
|
||||
for (const int influence_i : range) {
|
||||
const int curve_i = curve_indices[influence_i];
|
||||
const float move_distance_cu = move_distances_cu[influence_i];
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
this->shrink_curve(positions_cu.slice(points), move_distance_cu, data);
|
||||
}
|
||||
});
|
||||
|
@ -137,13 +138,14 @@ class ExtrapolateCurvesEffect : public CurvesEffect {
|
|||
const Span<int> curve_indices,
|
||||
const Span<float> move_distances_cu) override
|
||||
{
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
MutableSpan<float3> positions_cu = curves.positions_for_write();
|
||||
threading::parallel_for(curve_indices.index_range(), 256, [&](const IndexRange range) {
|
||||
MoveAndResampleBuffers resample_buffer;
|
||||
for (const int influence_i : range) {
|
||||
const int curve_i = curve_indices[influence_i];
|
||||
const float move_distance_cu = move_distances_cu[influence_i];
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
if (points.size() <= 1) {
|
||||
continue;
|
||||
}
|
||||
|
@ -178,12 +180,13 @@ class ScaleCurvesEffect : public CurvesEffect {
|
|||
const Span<int> curve_indices,
|
||||
const Span<float> move_distances_cu) override
|
||||
{
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
MutableSpan<float3> positions_cu = curves.positions_for_write();
|
||||
threading::parallel_for(curve_indices.index_range(), 256, [&](const IndexRange range) {
|
||||
for (const int influence_i : range) {
|
||||
const int curve_i = curve_indices[influence_i];
|
||||
const float move_distance_cu = move_distances_cu[influence_i];
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
|
||||
const float old_length = this->compute_poly_curve_length(positions_cu.slice(points));
|
||||
const float length_diff = scale_up_ ? move_distance_cu : -move_distance_cu;
|
||||
|
@ -342,6 +345,7 @@ struct CurvesEffectOperationExecutor {
|
|||
{
|
||||
const bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
|
||||
float4x4 projection;
|
||||
ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
|
||||
|
@ -360,7 +364,7 @@ struct CurvesEffectOperationExecutor {
|
|||
Influences &local_influences = influences_for_thread.local();
|
||||
|
||||
for (const int curve_i : curves_range) {
|
||||
const IndexRange points = curves_->points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
|
||||
const float curve_selection_factor = curve_selection_factors_[curve_i];
|
||||
|
||||
|
@ -452,12 +456,13 @@ struct CurvesEffectOperationExecutor {
|
|||
|
||||
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
|
||||
eCurvesSymmetryType(curves_id_->symmetry));
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
|
||||
threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
|
||||
Influences &local_influences = influences_for_thread.local();
|
||||
|
||||
for (const int curve_i : curves_range) {
|
||||
const IndexRange points = curves_->points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
|
||||
float max_move_distance_cu = 0.0f;
|
||||
|
||||
|
|
|
@ -370,13 +370,14 @@ static int select_random_exec(bContext *C, wmOperator *op)
|
|||
if (!was_anything_selected) {
|
||||
selection.fill(1.0f);
|
||||
}
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
switch (curves_id->selection_domain) {
|
||||
case ATTR_DOMAIN_POINT: {
|
||||
if (partial) {
|
||||
if (constant_per_curve) {
|
||||
for (const int curve_i : curves.curves_range()) {
|
||||
const float random_value = next_partial_random_value();
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
for (const int point_i : points) {
|
||||
selection[point_i] *= random_value;
|
||||
}
|
||||
|
@ -393,7 +394,7 @@ static int select_random_exec(bContext *C, wmOperator *op)
|
|||
if (constant_per_curve) {
|
||||
for (const int curve_i : curves.curves_range()) {
|
||||
const bool random_value = next_bool_random_value();
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
if (!random_value) {
|
||||
selection.slice(points).fill(0.0f);
|
||||
}
|
||||
|
@ -547,6 +548,7 @@ static int select_end_exec(bContext *C, wmOperator *op)
|
|||
if (!was_anything_selected) {
|
||||
curves::fill_selection_true(selection.span);
|
||||
}
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
selection.span.type().to_static_type_tag<bool, float>([&](auto type_tag) {
|
||||
using T = typename decltype(type_tag)::type;
|
||||
if constexpr (std::is_void_v<T>) {
|
||||
|
@ -556,7 +558,7 @@ static int select_end_exec(bContext *C, wmOperator *op)
|
|||
MutableSpan<T> selection_typed = selection.span.typed<T>();
|
||||
threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange range) {
|
||||
for (const int curve_i : range) {
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
if (end_points) {
|
||||
selection_typed.slice(points.drop_back(amount)).fill(T(0));
|
||||
}
|
||||
|
@ -667,6 +669,7 @@ static int select_grow_update(bContext *C, wmOperator *op, const float mouse_dif
|
|||
const float distance = curve_op_data->pixel_to_distance_factor * mouse_diff_x;
|
||||
|
||||
bke::SpanAttributeWriter<float> selection = float_selection_ensure(curves_id);
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
|
||||
/* Grow or shrink selection based on precomputed distances. */
|
||||
switch (selection.domain) {
|
||||
|
@ -680,7 +683,7 @@ static int select_grow_update(bContext *C, wmOperator *op, const float mouse_dif
|
|||
/* Propagate grown point selection to the curve selection. */
|
||||
MutableSpan<float> curves_selection = selection.span;
|
||||
for (const int curve_i : curves.curves_range()) {
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
const Span<float> points_selection = new_points_selection.as_span().slice(points);
|
||||
const float max_selection = *std::max_element(points_selection.begin(),
|
||||
points_selection.end());
|
||||
|
|
|
@ -160,6 +160,7 @@ struct PinchOperationExecutor {
|
|||
|
||||
const bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
|
||||
float4x4 projection;
|
||||
ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
|
||||
|
@ -169,7 +170,7 @@ struct PinchOperationExecutor {
|
|||
|
||||
threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
|
||||
for (const int curve_i : curve_selection_.slice(range)) {
|
||||
const IndexRange points = curves_->points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
for (const int point_i : points.drop_front(1)) {
|
||||
const float3 old_pos_cu = deformation.positions[point_i];
|
||||
const float3 old_symm_pos_cu = brush_transform_inv * old_pos_cu;
|
||||
|
@ -236,10 +237,11 @@ struct PinchOperationExecutor {
|
|||
|
||||
const bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
|
||||
threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
|
||||
for (const int curve_i : curve_selection_.slice(range)) {
|
||||
const IndexRange points = curves_->points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
for (const int point_i : points.drop_front(1)) {
|
||||
const float3 old_pos_cu = deformation.positions[point_i];
|
||||
|
||||
|
@ -269,10 +271,11 @@ struct PinchOperationExecutor {
|
|||
void initialize_segment_lengths()
|
||||
{
|
||||
const Span<float3> positions_cu = curves_->positions();
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
self_->segment_lengths_cu_.reinitialize(curves_->points_num());
|
||||
threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
|
||||
for (const int curve_i : curve_selection_.slice(range)) {
|
||||
const IndexRange points = curves_->points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
for (const int point_i : points.drop_back(1)) {
|
||||
const float3 &p1_cu = positions_cu[point_i];
|
||||
const float3 &p2_cu = positions_cu[point_i + 1];
|
||||
|
@ -286,6 +289,7 @@ struct PinchOperationExecutor {
|
|||
void restore_segment_lengths(const Span<bool> changed_curves)
|
||||
{
|
||||
const Span<float> expected_lengths_cu = self_->segment_lengths_cu_;
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
MutableSpan<float3> positions_cu = curves_->positions_for_write();
|
||||
|
||||
threading::parallel_for(changed_curves.index_range(), 256, [&](const IndexRange range) {
|
||||
|
@ -293,7 +297,7 @@ struct PinchOperationExecutor {
|
|||
if (!changed_curves[curve_i]) {
|
||||
continue;
|
||||
}
|
||||
const IndexRange points = curves_->points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
for (const int segment_i : IndexRange(points.size() - 1)) {
|
||||
const float3 &p1_cu = positions_cu[points[segment_i]];
|
||||
float3 &p2_cu = positions_cu[points[segment_i] + 1];
|
||||
|
|
|
@ -182,11 +182,12 @@ struct PuffOperationExecutor {
|
|||
|
||||
const bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
|
||||
threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
|
||||
for (const int curve_selection_i : range) {
|
||||
const int curve_i = curve_selection_[curve_selection_i];
|
||||
const IndexRange points = curves_->points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
const float3 first_pos_cu = brush_transform_inv * deformation.positions[points[0]];
|
||||
float2 prev_pos_re;
|
||||
ED_view3d_project_float_v2_m4(ctx_.region, first_pos_cu, prev_pos_re, projection.values);
|
||||
|
@ -242,11 +243,12 @@ struct PuffOperationExecutor {
|
|||
|
||||
const bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
|
||||
threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
|
||||
for (const int curve_selection_i : range) {
|
||||
const int curve_i = curve_selection_[curve_selection_i];
|
||||
const IndexRange points = curves_->points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
for (const int point_i : points.drop_front(1)) {
|
||||
const float3 &prev_pos_cu = deformation.positions[point_i - 1];
|
||||
const float3 &pos_cu = deformation.positions[point_i];
|
||||
|
@ -269,13 +271,14 @@ struct PuffOperationExecutor {
|
|||
void puff(const Span<float> curve_weights)
|
||||
{
|
||||
BLI_assert(curve_weights.size() == curve_selection_.size());
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
MutableSpan<float3> positions_cu = curves_->positions_for_write();
|
||||
|
||||
threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
|
||||
Vector<float> accumulated_lengths_cu;
|
||||
for (const int curve_selection_i : range) {
|
||||
const int curve_i = curve_selection_[curve_selection_i];
|
||||
const IndexRange points = curves_->points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
const int first_point_i = points[0];
|
||||
const float3 first_pos_cu = positions_cu[first_point_i];
|
||||
const float3 first_pos_su = transforms_.curves_to_surface * first_pos_cu;
|
||||
|
@ -336,11 +339,12 @@ struct PuffOperationExecutor {
|
|||
|
||||
void initialize_segment_lengths()
|
||||
{
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
const Span<float3> positions_cu = curves_->positions();
|
||||
self_->segment_lengths_cu_.reinitialize(curves_->points_num());
|
||||
threading::parallel_for(curves_->curves_range(), 128, [&](const IndexRange range) {
|
||||
for (const int curve_i : range) {
|
||||
const IndexRange points = curves_->points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
for (const int point_i : points.drop_back(1)) {
|
||||
const float3 &p1_cu = positions_cu[point_i];
|
||||
const float3 &p2_cu = positions_cu[point_i + 1];
|
||||
|
@ -354,11 +358,12 @@ struct PuffOperationExecutor {
|
|||
void restore_segment_lengths()
|
||||
{
|
||||
const Span<float> expected_lengths_cu = self_->segment_lengths_cu_;
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
MutableSpan<float3> positions_cu = curves_->positions_for_write();
|
||||
|
||||
threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange range) {
|
||||
for (const int curve_i : range) {
|
||||
const IndexRange points = curves_->points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
for (const int segment_i : points.drop_back(1)) {
|
||||
const float3 &p1_cu = positions_cu[segment_i];
|
||||
float3 &p2_cu = positions_cu[segment_i + 1];
|
||||
|
|
|
@ -263,6 +263,7 @@ struct SelectionPaintOperationExecutor {
|
|||
|
||||
const bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
|
||||
float4x4 projection;
|
||||
ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
|
||||
|
@ -273,7 +274,7 @@ struct SelectionPaintOperationExecutor {
|
|||
threading::parallel_for(curves_->curves_range(), 1024, [&](const IndexRange curves_range) {
|
||||
for (const int curve_i : curves_range) {
|
||||
const float max_weight = threading::parallel_reduce(
|
||||
curves_->points_for_curve(curve_i).drop_back(1),
|
||||
points_by_curve[curve_i].drop_back(1),
|
||||
1024,
|
||||
0.0f,
|
||||
[&](const IndexRange segment_range, const float init) {
|
||||
|
@ -330,6 +331,7 @@ struct SelectionPaintOperationExecutor {
|
|||
{
|
||||
const bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
|
||||
const float brush_radius_cu = self_->brush_3d_.radius_cu;
|
||||
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
|
||||
|
@ -337,7 +339,7 @@ struct SelectionPaintOperationExecutor {
|
|||
threading::parallel_for(curves_->curves_range(), 1024, [&](const IndexRange curves_range) {
|
||||
for (const int curve_i : curves_range) {
|
||||
const float max_weight = threading::parallel_reduce(
|
||||
curves_->points_for_curve(curve_i).drop_back(1),
|
||||
points_by_curve[curve_i].drop_back(1),
|
||||
1024,
|
||||
0.0f,
|
||||
[&](const IndexRange segment_range, const float init) {
|
||||
|
|
|
@ -317,6 +317,7 @@ struct SlideOperationExecutor {
|
|||
|
||||
const Span<float3> positions_orig_su = surface_orig_->vert_positions();
|
||||
const Span<MLoop> loops_orig = surface_orig_->loops();
|
||||
const OffsetIndices points_by_curve = curves_orig_->points_by_curve();
|
||||
|
||||
MutableSpan<float3> positions_orig_cu = curves_orig_->positions_for_write();
|
||||
MutableSpan<float2> surface_uv_coords = curves_orig_->surface_uv_coords_for_write();
|
||||
|
@ -334,7 +335,7 @@ struct SlideOperationExecutor {
|
|||
threading::parallel_for(slide_curves.index_range(), 256, [&](const IndexRange range) {
|
||||
for (const SlideCurveInfo &slide_curve_info : slide_curves.slice(range)) {
|
||||
const int curve_i = slide_curve_info.curve_i;
|
||||
const IndexRange points = curves_orig_->points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
const int first_point_i = points[0];
|
||||
|
||||
const float3 old_first_pos_eval_cu = self_->initial_deformed_positions_cu_[first_point_i];
|
||||
|
|
|
@ -138,10 +138,11 @@ struct SmoothOperationExecutor {
|
|||
|
||||
const bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
|
||||
threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
|
||||
for (const int curve_i : curve_selection_.slice(range)) {
|
||||
const IndexRange points = curves_->points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
for (const int point_i : points) {
|
||||
const float3 &pos_cu = brush_transform_inv * deformation.positions[point_i];
|
||||
float2 pos_re;
|
||||
|
@ -194,10 +195,11 @@ struct SmoothOperationExecutor {
|
|||
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
|
||||
const bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
|
||||
threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
|
||||
for (const int curve_i : curve_selection_.slice(range)) {
|
||||
const IndexRange points = curves_->points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
for (const int point_i : points) {
|
||||
const float3 &pos_cu = deformation.positions[point_i];
|
||||
const float dist_to_brush_sq_cu = math::distance_squared(pos_cu, brush_pos_cu);
|
||||
|
@ -221,11 +223,12 @@ struct SmoothOperationExecutor {
|
|||
|
||||
void smooth(const Span<float> point_smooth_factors)
|
||||
{
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
MutableSpan<float3> positions = curves_->positions_for_write();
|
||||
threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
|
||||
Vector<float3> old_positions;
|
||||
for (const int curve_i : curve_selection_.slice(range)) {
|
||||
const IndexRange points = curves_->points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
old_positions.clear();
|
||||
old_positions.extend(positions.slice(points));
|
||||
for (const int i : IndexRange(points.size()).drop_front(1).drop_back(1)) {
|
||||
|
|
|
@ -179,6 +179,7 @@ struct SnakeHookOperatorExecutor {
|
|||
const float4x4 brush_transform_inv = brush_transform.inverted();
|
||||
const bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
|
||||
MutableSpan<float3> positions_cu = curves_->positions_for_write();
|
||||
|
||||
|
@ -191,7 +192,7 @@ struct SnakeHookOperatorExecutor {
|
|||
threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
|
||||
MoveAndResampleBuffers resample_buffer;
|
||||
for (const int curve_i : curves_range) {
|
||||
const IndexRange points = curves_->points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
const int last_point_i = points.last();
|
||||
const float3 old_pos_cu = deformation.positions[last_point_i];
|
||||
const float3 old_symm_pos_cu = brush_transform_inv * old_pos_cu;
|
||||
|
@ -264,6 +265,7 @@ struct SnakeHookOperatorExecutor {
|
|||
{
|
||||
const bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *object_);
|
||||
const OffsetIndices points_by_curve = curves_->points_by_curve();
|
||||
|
||||
MutableSpan<float3> positions_cu = curves_->positions_for_write();
|
||||
const float3 brush_diff_cu = brush_end_cu - brush_start_cu;
|
||||
|
@ -272,7 +274,7 @@ struct SnakeHookOperatorExecutor {
|
|||
threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
|
||||
MoveAndResampleBuffers resample_buffer;
|
||||
for (const int curve_i : curves_range) {
|
||||
const IndexRange points = curves_->points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
const int last_point_i = points.last();
|
||||
const float3 old_pos_cu = deformation.positions[last_point_i];
|
||||
|
||||
|
|
|
@ -117,11 +117,12 @@ static void interpolate_position_without_interpolation(
|
|||
const float4x4 &surface_to_curves_normal_mat)
|
||||
{
|
||||
const int added_curves_num = root_positions_cu.size();
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
MutableSpan<float3> positions_cu = curves.positions_for_write();
|
||||
threading::parallel_for(IndexRange(added_curves_num), 256, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
const int curve_i = old_curves_num + i;
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
const float3 &root_cu = root_positions_cu[i];
|
||||
const float length = new_lengths_cu[i];
|
||||
const float3 &normal_su = new_normals_su[i];
|
||||
|
@ -147,13 +148,14 @@ static void interpolate_position_with_interpolation(CurvesGeometry &curves,
|
|||
MutableSpan<float3> positions_cu = curves.positions_for_write();
|
||||
const int added_curves_num = root_positions_cu.size();
|
||||
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
const Span<float2> uv_coords = curves.surface_uv_coords();
|
||||
|
||||
threading::parallel_for(IndexRange(added_curves_num), 256, [&](const IndexRange range) {
|
||||
for (const int added_curve_i : range) {
|
||||
const NeighborCurves &neighbors = neighbors_per_curve[added_curve_i];
|
||||
const int curve_i = old_curves_num + added_curve_i;
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
|
||||
const float length_cu = new_lengths_cu[added_curve_i];
|
||||
const float3 &normal_su = new_normals_su[added_curve_i];
|
||||
|
@ -188,7 +190,7 @@ static void interpolate_position_with_interpolation(CurvesGeometry &curves,
|
|||
float normal_rotation_cu[3][3];
|
||||
rotation_between_vecs_to_mat3(normal_rotation_cu, neighbor_normal_cu, normal_cu);
|
||||
|
||||
const IndexRange neighbor_points = curves.points_for_curve(neighbor_curve_i);
|
||||
const IndexRange neighbor_points = points_by_curve[neighbor_curve_i];
|
||||
const float3 &neighbor_root_cu = positions_cu[neighbor_points[0]];
|
||||
|
||||
/* Sample the positions on neighbors and mix them into the final positions of the curve.
|
||||
|
@ -289,7 +291,7 @@ AddCurvesOnMeshOutputs add_curves_on_mesh(CurvesGeometry &curves,
|
|||
interpolate_from_neighbors<int>(
|
||||
neighbors_per_curve,
|
||||
inputs.fallback_point_count,
|
||||
[&](const int curve_i) { return curves.points_for_curve(curve_i).size(); },
|
||||
[&](const int curve_i) { return curve_offsets[curve_i + 1] - curve_offsets[curve_i]; },
|
||||
new_point_counts_per_curve);
|
||||
}
|
||||
else {
|
||||
|
@ -314,11 +316,12 @@ AddCurvesOnMeshOutputs add_curves_on_mesh(CurvesGeometry &curves,
|
|||
/* Determine length of new curves. */
|
||||
Array<float> new_lengths_cu(added_curves_num);
|
||||
if (inputs.interpolate_length) {
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
interpolate_from_neighbors<float>(
|
||||
neighbors_per_curve,
|
||||
inputs.fallback_curve_length,
|
||||
[&](const int curve_i) {
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
float length = 0.0f;
|
||||
for (const int segment_i : points.drop_back(1)) {
|
||||
const float3 &p1 = positions_cu[segment_i];
|
||||
|
|
|
@ -41,10 +41,12 @@ static void duplicate_fillet_point_data(const bke::CurvesGeometry &src_curves,
|
|||
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_curves.points_for_curve(curve_i);
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
|
||||
const IndexRange src_points = src_points_by_curve[curve_i];
|
||||
const IndexRange dst_points = dst_points_by_curve[curve_i];
|
||||
const Span<int> offsets = point_offsets.slice(curve_dst_offsets(src_points, curve_i));
|
||||
threaded_slice_fill(src.slice(src_points), offsets, dst.slice(dst_points));
|
||||
}
|
||||
|
@ -76,9 +78,10 @@ static void calculate_result_offsets(const bke::CurvesGeometry &src_curves,
|
|||
{
|
||||
/* Fill the offsets array with the curve point counts, then accumulate them to form offsets. */
|
||||
bke::curves::fill_curve_counts(src_curves, unselected_ranges, dst_curve_offsets);
|
||||
const OffsetIndices points_by_curve = src_curves.points_by_curve();
|
||||
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
|
||||
for (const int curve_i : selection.slice(range)) {
|
||||
const IndexRange src_points = src_curves.points_for_curve(curve_i);
|
||||
const IndexRange src_points = points_by_curve[curve_i];
|
||||
const IndexRange offsets_range = curve_dst_offsets(src_points, curve_i);
|
||||
|
||||
MutableSpan<int> point_offsets = dst_point_offsets.slice(offsets_range);
|
||||
|
@ -103,12 +106,12 @@ static void calculate_result_offsets(const bke::CurvesGeometry &src_curves,
|
|||
}
|
||||
});
|
||||
|
||||
bke::curves::accumulate_counts_to_offsets(point_offsets);
|
||||
offset_indices::accumulate_counts_to_offsets(point_offsets);
|
||||
|
||||
dst_curve_offsets[curve_i] = point_offsets.last();
|
||||
}
|
||||
});
|
||||
bke::curves::accumulate_counts_to_offsets(dst_curve_offsets);
|
||||
offset_indices::accumulate_counts_to_offsets(dst_curve_offsets);
|
||||
}
|
||||
|
||||
static void calculate_directions(const Span<float3> positions, MutableSpan<float3> directions)
|
||||
|
@ -450,6 +453,8 @@ 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;
|
||||
|
@ -457,9 +462,9 @@ static bke::CurvesGeometry fillet_curves(
|
|||
Array<float> input_radii_buffer;
|
||||
|
||||
for (const int curve_i : curve_selection.slice(range)) {
|
||||
const IndexRange src_points = src_curves.points_for_curve(curve_i);
|
||||
const IndexRange src_points = src_points_by_curve[curve_i];
|
||||
const Span<int> offsets = point_offsets.slice(curve_dst_offsets(src_points, curve_i));
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
|
||||
const IndexRange dst_points = dst_points_by_curve[curve_i];
|
||||
const Span<float3> src_positions = positions.slice(src_points);
|
||||
|
||||
directions.reinitialize(src_points.size());
|
||||
|
|
|
@ -229,8 +229,9 @@ static void normalize_curve_point_data(const CurvesGeometry &curves,
|
|||
const IndexMask curve_selection,
|
||||
MutableSpan<float3> data)
|
||||
{
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
for (const int i_curve : curve_selection) {
|
||||
normalize_span(data.slice(curves.points_for_curve(i_curve)));
|
||||
normalize_span(data.slice(points_by_curve[i_curve]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -262,7 +263,7 @@ static CurvesGeometry resample_to_uniform(const CurvesGeometry &src_curves,
|
|||
|
||||
/* Fill the counts for the curves that aren't selected and accumulate the counts into offsets. */
|
||||
bke::curves::fill_curve_counts(src_curves, unselected_ranges, dst_offsets);
|
||||
bke::curves::accumulate_counts_to_offsets(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. */
|
||||
|
@ -286,6 +287,9 @@ static CurvesGeometry resample_to_uniform(const CurvesGeometry &src_curves,
|
|||
Array<int> sample_indices(dst_curves.points_num());
|
||||
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
|
||||
* time or one curve at a time. */
|
||||
|
@ -297,7 +301,7 @@ static CurvesGeometry resample_to_uniform(const CurvesGeometry &src_curves,
|
|||
/* Gather uniform samples based on the accumulated lengths of the original curve. */
|
||||
for (const int i_curve : sliced_selection) {
|
||||
const bool cyclic = curves_cyclic[i_curve];
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
|
||||
const IndexRange dst_points = dst_points_by_curve[i_curve];
|
||||
const Span<float> lengths = src_curves.evaluated_lengths_for_curve(i_curve, cyclic);
|
||||
if (lengths.is_empty()) {
|
||||
/* Handle curves with only one evaluated point. */
|
||||
|
@ -321,8 +325,8 @@ static CurvesGeometry resample_to_uniform(const CurvesGeometry &src_curves,
|
|||
MutableSpan<T> dst = attributes.dst[i_attribute].typed<T>();
|
||||
|
||||
for (const int i_curve : sliced_selection) {
|
||||
const IndexRange src_points = src_curves.points_for_curve(i_curve);
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
|
||||
const IndexRange src_points = src_points_by_curve[i_curve];
|
||||
const IndexRange dst_points = dst_points_by_curve[i_curve];
|
||||
|
||||
if (curve_types[i_curve] == CURVE_TYPE_POLY) {
|
||||
length_parameterize::interpolate(src.slice(src_points),
|
||||
|
@ -349,7 +353,7 @@ static CurvesGeometry resample_to_uniform(const CurvesGeometry &src_curves,
|
|||
auto interpolate_evaluated_data = [&](const Span<float3> src, MutableSpan<float3> dst) {
|
||||
for (const int i_curve : sliced_selection) {
|
||||
const IndexRange src_points = src_curves.evaluated_points_for_curve(i_curve);
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
|
||||
const IndexRange dst_points = dst_points_by_curve[i_curve];
|
||||
length_parameterize::interpolate(src.slice(src_points),
|
||||
sample_indices.as_span().slice(dst_points),
|
||||
sample_factors.as_span().slice(dst_points),
|
||||
|
@ -372,7 +376,7 @@ static CurvesGeometry resample_to_uniform(const CurvesGeometry &src_curves,
|
|||
/* Fill the default value for non-interpolating attributes that still must be copied. */
|
||||
for (GMutableSpan dst : attributes.dst_no_interpolation) {
|
||||
for (const int i_curve : sliced_selection) {
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
|
||||
const IndexRange dst_points = dst_points_by_curve[i_curve];
|
||||
dst.type().value_initialize_n(dst.slice(dst_points).data(), dst_points.size());
|
||||
}
|
||||
}
|
||||
|
@ -438,7 +442,7 @@ CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
|
|||
}
|
||||
});
|
||||
bke::curves::fill_curve_counts(src_curves, unselected_ranges, dst_offsets);
|
||||
bke::curves::accumulate_counts_to_offsets(dst_offsets);
|
||||
offset_indices::accumulate_counts_to_offsets(dst_offsets);
|
||||
|
||||
dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
|
||||
|
||||
|
@ -449,6 +453,8 @@ CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
|
|||
AttributesForInterpolation attributes;
|
||||
gather_point_attributes_to_interpolate(src_curves, dst_curves, attributes, output_ids);
|
||||
|
||||
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) {
|
||||
const IndexMask sliced_selection = selection.slice(selection_range);
|
||||
|
||||
|
@ -460,8 +466,8 @@ CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
|
|||
MutableSpan<T> dst = attributes.dst[i_attribute].typed<T>();
|
||||
|
||||
for (const int i_curve : sliced_selection) {
|
||||
const IndexRange src_points = src_curves.points_for_curve(i_curve);
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
|
||||
const IndexRange src_points = src_points_by_curve[i_curve];
|
||||
const IndexRange dst_points = dst_points_by_curve[i_curve];
|
||||
src_curves.interpolate_to_evaluated(
|
||||
i_curve, src.slice(src_points), dst.slice(dst_points));
|
||||
}
|
||||
|
@ -471,7 +477,7 @@ CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
|
|||
auto copy_evaluated_data = [&](const Span<float3> src, MutableSpan<float3> dst) {
|
||||
for (const int i_curve : sliced_selection) {
|
||||
const IndexRange src_points = src_curves.evaluated_points_for_curve(i_curve);
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
|
||||
const IndexRange dst_points = dst_points_by_curve[i_curve];
|
||||
dst.slice(dst_points).copy_from(src.slice(src_points));
|
||||
}
|
||||
};
|
||||
|
@ -491,7 +497,7 @@ CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
|
|||
/* Fill the default value for non-interpolating attributes that still must be copied. */
|
||||
for (GMutableSpan dst : attributes.dst_no_interpolation) {
|
||||
for (const int i_curve : sliced_selection) {
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
|
||||
const IndexRange dst_points = dst_points_by_curve[i_curve];
|
||||
dst.type().value_initialize_n(dst.slice(dst_points).data(), dst_points.size());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -279,9 +279,10 @@ 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] = curves.points_for_curve(i).size();
|
||||
sizes[i] = points_by_curve[i].size();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -307,7 +308,7 @@ static bke::CurvesGeometry convert_curves_to_bezier(
|
|||
CurveType(src_types[i]), src_cyclic[i], KnotsMode(src_knot_modes[i]), dst_offsets[i]);
|
||||
}
|
||||
});
|
||||
bke::curves::accumulate_counts_to_offsets(dst_offsets);
|
||||
offset_indices::accumulate_counts_to_offsets(dst_offsets);
|
||||
dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
|
||||
|
||||
const bke::AttributeAccessor src_attributes = src_curves.attributes();
|
||||
|
@ -332,6 +333,9 @@ static bke::CurvesGeometry convert_curves_to_bezier(
|
|||
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);
|
||||
|
@ -339,8 +343,8 @@ static bke::CurvesGeometry convert_curves_to_bezier(
|
|||
|
||||
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
|
||||
for (const int i : selection.slice(range)) {
|
||||
const IndexRange src_points = src_curves.points_for_curve(i);
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(i);
|
||||
const IndexRange src_points = src_points_by_curve[i];
|
||||
const IndexRange dst_points = dst_points_by_curve[i];
|
||||
catmull_rom_to_bezier_handles(src_positions.slice(src_points),
|
||||
src_cyclic[i],
|
||||
dst_handles_l.slice(dst_points),
|
||||
|
@ -392,8 +396,8 @@ static bke::CurvesGeometry convert_curves_to_bezier(
|
|||
|
||||
threading::parallel_for(selection.index_range(), 64, [&](IndexRange range) {
|
||||
for (const int i : selection.slice(range)) {
|
||||
const IndexRange src_points = src_curves.points_for_curve(i);
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(i);
|
||||
const IndexRange src_points = src_points_by_curve[i];
|
||||
const IndexRange dst_points = dst_points_by_curve[i];
|
||||
const Span<float3> src_curve_positions = src_positions.slice(src_points);
|
||||
if (dst_points.size() == 1) {
|
||||
const float3 &position = src_positions[src_points.first()];
|
||||
|
@ -430,8 +434,8 @@ static bke::CurvesGeometry convert_curves_to_bezier(
|
|||
for (bke::AttributeTransferData &attribute : generic_attributes) {
|
||||
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
|
||||
for (const int i : selection.slice(range)) {
|
||||
const IndexRange src_points = src_curves.points_for_curve(i);
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(i);
|
||||
const IndexRange src_points = src_points_by_curve[i];
|
||||
const IndexRange dst_points = dst_points_by_curve[i];
|
||||
nurbs_to_bezier_assign(attribute.src.slice(src_points),
|
||||
KnotsMode(src_knot_modes[i]),
|
||||
attribute.dst.span.slice(dst_points));
|
||||
|
@ -482,7 +486,7 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
|
|||
dst_offsets[i] = to_nurbs_size(CurveType(src_types[i]), dst_offsets[i]);
|
||||
}
|
||||
});
|
||||
bke::curves::accumulate_counts_to_offsets(dst_offsets);
|
||||
offset_indices::accumulate_counts_to_offsets(dst_offsets);
|
||||
dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
|
||||
|
||||
const bke::AttributeAccessor src_attributes = src_curves.attributes();
|
||||
|
@ -508,6 +512,9 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
|
|||
}
|
||||
};
|
||||
|
||||
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);
|
||||
|
@ -515,8 +522,8 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
|
|||
|
||||
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
|
||||
for (const int i : selection.slice(range)) {
|
||||
const IndexRange src_points = src_curves.points_for_curve(i);
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(i);
|
||||
const IndexRange src_points = src_points_by_curve[i];
|
||||
const IndexRange dst_points = dst_points_by_curve[i];
|
||||
catmull_rom_to_nurbs_positions(
|
||||
src_positions.slice(src_points), src_cyclic[i], dst_positions.slice(dst_points));
|
||||
}
|
||||
|
@ -525,8 +532,8 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
|
|||
for (bke::AttributeTransferData &attribute : generic_attributes) {
|
||||
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
|
||||
for (const int i : selection.slice(range)) {
|
||||
const IndexRange src_points = src_curves.points_for_curve(i);
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(i);
|
||||
const IndexRange src_points = src_points_by_curve[i];
|
||||
const IndexRange dst_points = dst_points_by_curve[i];
|
||||
bezier_generic_to_nurbs(attribute.src.slice(src_points),
|
||||
attribute.dst.span.slice(dst_points));
|
||||
}
|
||||
|
@ -572,8 +579,8 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
|
|||
|
||||
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
|
||||
for (const int i : selection.slice(range)) {
|
||||
const IndexRange src_points = src_curves.points_for_curve(i);
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(i);
|
||||
const IndexRange src_points = src_points_by_curve[i];
|
||||
const IndexRange dst_points = dst_points_by_curve[i];
|
||||
bezier_positions_to_nurbs(src_positions.slice(src_points),
|
||||
src_handles_l.slice(src_points),
|
||||
src_handles_r.slice(src_points),
|
||||
|
@ -584,8 +591,8 @@ static bke::CurvesGeometry convert_curves_to_nurbs(
|
|||
for (bke::AttributeTransferData &attribute : generic_attributes) {
|
||||
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
|
||||
for (const int i : selection.slice(range)) {
|
||||
const IndexRange src_points = src_curves.points_for_curve(i);
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(i);
|
||||
const IndexRange src_points = src_points_by_curve[i];
|
||||
const IndexRange dst_points = dst_points_by_curve[i];
|
||||
bezier_generic_to_nurbs(attribute.src.slice(src_points),
|
||||
attribute.dst.span.slice(dst_points));
|
||||
}
|
||||
|
|
|
@ -31,9 +31,10 @@ 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. */
|
||||
bke::curves::fill_curve_counts(src_curves, unselected_ranges, dst_curve_offsets);
|
||||
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
|
||||
threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
|
||||
for (const int curve_i : selection.slice(range)) {
|
||||
const IndexRange src_points = src_curves.points_for_curve(curve_i);
|
||||
const IndexRange src_points = src_points_by_curve[curve_i];
|
||||
const IndexRange src_segments = curve_dst_offsets(src_points, curve_i);
|
||||
|
||||
MutableSpan<int> point_offsets = dst_point_offsets.slice(src_segments);
|
||||
|
@ -54,11 +55,11 @@ static void calculate_result_offsets(const bke::CurvesGeometry &src_curves,
|
|||
}
|
||||
}
|
||||
|
||||
bke::curves::accumulate_counts_to_offsets(point_offsets);
|
||||
offset_indices::accumulate_counts_to_offsets(point_offsets);
|
||||
dst_curve_offsets[curve_i] = point_offsets.last();
|
||||
}
|
||||
});
|
||||
bke::curves::accumulate_counts_to_offsets(dst_curve_offsets);
|
||||
offset_indices::accumulate_counts_to_offsets(dst_curve_offsets);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
@ -79,13 +80,15 @@ static void subdivide_attribute_linear(const bke::CurvesGeometry &src_curves,
|
|||
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_curves.points_for_curve(curve_i);
|
||||
const IndexRange src_points = src_points_by_curve[curve_i];
|
||||
const IndexRange src_segments = curve_dst_offsets(src_points, curve_i);
|
||||
const Span<int> offsets = point_offsets.slice(src_segments);
|
||||
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
|
||||
const IndexRange dst_points = dst_points_by_curve[curve_i];
|
||||
const Span<T> curve_src = src.slice(src_points);
|
||||
MutableSpan<T> curve_dst = dst.slice(dst_points);
|
||||
|
||||
|
@ -126,11 +129,13 @@ static void subdivide_attribute_catmull_rom(const bke::CurvesGeometry &src_curve
|
|||
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_curves.points_for_curve(curve_i);
|
||||
const IndexRange src_points = src_points_by_curve[curve_i];
|
||||
const IndexRange src_segments = curve_dst_offsets(src_points, curve_i);
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
|
||||
const IndexRange dst_points = dst_points_by_curve[curve_i];
|
||||
|
||||
bke::curves::catmull_rom::interpolate_to_evaluated(src.slice(src_points),
|
||||
cyclic[curve_i],
|
||||
|
@ -367,19 +372,21 @@ 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 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();
|
||||
MutableSpan<int8_t> dst_types_r = dst_curves.handle_types_right_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();
|
||||
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
|
||||
|
||||
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
|
||||
for (const int curve_i : selection.slice(range)) {
|
||||
const IndexRange src_points = src_curves.points_for_curve(curve_i);
|
||||
const IndexRange src_points = src_points_by_curve[curve_i];
|
||||
const IndexRange src_segments = curve_dst_offsets(src_points, curve_i);
|
||||
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
|
||||
const IndexRange dst_points = dst_points_by_curve[curve_i];
|
||||
subdivide_bezier_positions(src_positions.slice(src_points),
|
||||
src_types_l.slice(src_points),
|
||||
src_types_r.slice(src_points),
|
||||
|
|
|
@ -191,6 +191,7 @@ static void fill_bezier_data(bke::CurvesGeometry &dst_curves, const IndexMask se
|
|||
if (!dst_curves.has_curve_with_type(CURVE_TYPE_BEZIER)) {
|
||||
return;
|
||||
}
|
||||
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
|
||||
MutableSpan<float3> handle_positions_left = dst_curves.handle_positions_left_for_write();
|
||||
MutableSpan<float3> handle_positions_right = dst_curves.handle_positions_right_for_write();
|
||||
MutableSpan<int8_t> handle_types_left = dst_curves.handle_types_left_for_write();
|
||||
|
@ -198,7 +199,7 @@ static void fill_bezier_data(bke::CurvesGeometry &dst_curves, const IndexMask se
|
|||
|
||||
threading::parallel_for(selection.index_range(), 4096, [&](const IndexRange range) {
|
||||
for (const int64_t curve_i : selection.slice(range)) {
|
||||
const IndexRange points = dst_curves.points_for_curve(curve_i);
|
||||
const IndexRange points = dst_points_by_curve[curve_i];
|
||||
handle_types_right.slice(points).fill(int8_t(BEZIER_HANDLE_FREE));
|
||||
handle_types_left.slice(points).fill(int8_t(BEZIER_HANDLE_FREE));
|
||||
handle_positions_left.slice(points).fill({0.0f, 0.0f, 0.0f});
|
||||
|
@ -587,18 +588,20 @@ static void trim_attribute_linear(const bke::CurvesGeometry &src_curves,
|
|||
const Span<bke::curves::IndexRangeCyclic> src_ranges,
|
||||
MutableSpan<bke::AttributeTransferData> transfer_attributes)
|
||||
{
|
||||
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
|
||||
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
|
||||
for (bke::AttributeTransferData &attribute : transfer_attributes) {
|
||||
attribute_math::convert_to_static_type(attribute.meta_data.data_type, [&](auto dummy) {
|
||||
using T = decltype(dummy);
|
||||
|
||||
threading::parallel_for(selection.index_range(), 512, [&](const IndexRange range) {
|
||||
for (const int64_t curve_i : selection.slice(range)) {
|
||||
const IndexRange src_points = src_curves.points_for_curve(curve_i);
|
||||
const IndexRange src_points = src_points_by_curve[curve_i];
|
||||
|
||||
sample_interval_linear<T>(attribute.src.template typed<T>().slice(src_points),
|
||||
attribute.dst.span.typed<T>(),
|
||||
src_ranges[curve_i],
|
||||
dst_curves.points_for_curve(curve_i),
|
||||
dst_points_by_curve[curve_i],
|
||||
start_points[curve_i],
|
||||
end_points[curve_i]);
|
||||
}
|
||||
|
@ -615,13 +618,15 @@ static void trim_polygonal_curves(const bke::CurvesGeometry &src_curves,
|
|||
const Span<bke::curves::IndexRangeCyclic> src_ranges,
|
||||
MutableSpan<bke::AttributeTransferData> transfer_attributes)
|
||||
{
|
||||
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
|
||||
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
|
||||
const Span<float3> src_positions = src_curves.positions();
|
||||
MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
|
||||
|
||||
threading::parallel_for(selection.index_range(), 512, [&](const IndexRange range) {
|
||||
for (const int64_t curve_i : selection.slice(range)) {
|
||||
const IndexRange src_points = src_curves.points_for_curve(curve_i);
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
|
||||
const IndexRange src_points = src_points_by_curve[curve_i];
|
||||
const IndexRange dst_points = dst_points_by_curve[curve_i];
|
||||
|
||||
sample_interval_linear<float3>(src_positions.slice(src_points),
|
||||
dst_positions,
|
||||
|
@ -650,14 +655,16 @@ static void trim_catmull_rom_curves(const bke::CurvesGeometry &src_curves,
|
|||
const Span<bke::curves::IndexRangeCyclic> src_ranges,
|
||||
MutableSpan<bke::AttributeTransferData> transfer_attributes)
|
||||
{
|
||||
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
|
||||
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
|
||||
const Span<float3> src_positions = src_curves.positions();
|
||||
const VArray<bool> src_cyclic = src_curves.cyclic();
|
||||
MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
|
||||
|
||||
threading::parallel_for(selection.index_range(), 512, [&](const IndexRange range) {
|
||||
for (const int64_t curve_i : selection.slice(range)) {
|
||||
const IndexRange src_points = src_curves.points_for_curve(curve_i);
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
|
||||
const IndexRange src_points = src_points_by_curve[curve_i];
|
||||
const IndexRange dst_points = dst_points_by_curve[curve_i];
|
||||
|
||||
sample_interval_catmull_rom<float3>(src_positions.slice(src_points),
|
||||
dst_positions,
|
||||
|
@ -677,8 +684,8 @@ static void trim_catmull_rom_curves(const bke::CurvesGeometry &src_curves,
|
|||
|
||||
threading::parallel_for(selection.index_range(), 512, [&](const IndexRange range) {
|
||||
for (const int64_t curve_i : selection.slice(range)) {
|
||||
const IndexRange src_points = src_curves.points_for_curve(curve_i);
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
|
||||
const IndexRange src_points = src_points_by_curve[curve_i];
|
||||
const IndexRange dst_points = dst_points_by_curve[curve_i];
|
||||
|
||||
sample_interval_catmull_rom<T>(attribute.src.template typed<T>().slice(src_points),
|
||||
attribute.dst.span.typed<T>(),
|
||||
|
@ -701,12 +708,14 @@ static void trim_bezier_curves(const bke::CurvesGeometry &src_curves,
|
|||
const Span<bke::curves::IndexRangeCyclic> src_ranges,
|
||||
MutableSpan<bke::AttributeTransferData> transfer_attributes)
|
||||
{
|
||||
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
|
||||
const Span<float3> src_positions = src_curves.positions();
|
||||
const VArraySpan<int8_t> src_types_l{src_curves.handle_types_left()};
|
||||
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 dst_points_by_curve = dst_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();
|
||||
MutableSpan<int8_t> dst_types_r = dst_curves.handle_types_right_for_write();
|
||||
|
@ -715,8 +724,8 @@ static void trim_bezier_curves(const bke::CurvesGeometry &src_curves,
|
|||
|
||||
threading::parallel_for(selection.index_range(), 512, [&](const IndexRange range) {
|
||||
for (const int64_t curve_i : selection.slice(range)) {
|
||||
const IndexRange src_points = src_curves.points_for_curve(curve_i);
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
|
||||
const IndexRange src_points = src_points_by_curve[curve_i];
|
||||
const IndexRange dst_points = dst_points_by_curve[curve_i];
|
||||
|
||||
sample_interval_bezier(src_positions.slice(src_points),
|
||||
src_handles_l.slice(src_points),
|
||||
|
@ -752,12 +761,14 @@ static void trim_evaluated_curves(const bke::CurvesGeometry &src_curves,
|
|||
const Span<bke::curves::IndexRangeCyclic> src_ranges,
|
||||
MutableSpan<bke::AttributeTransferData> transfer_attributes)
|
||||
{
|
||||
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
|
||||
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
|
||||
const Span<float3> src_eval_positions = src_curves.evaluated_positions();
|
||||
MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
|
||||
|
||||
threading::parallel_for(selection.index_range(), 512, [&](const IndexRange range) {
|
||||
for (const int64_t curve_i : selection.slice(range)) {
|
||||
const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
|
||||
const IndexRange dst_points = dst_points_by_curve[curve_i];
|
||||
const IndexRange src_evaluated_points = src_curves.evaluated_points_for_curve(curve_i);
|
||||
|
||||
sample_interval_linear<float3>(src_eval_positions.slice(src_evaluated_points),
|
||||
|
@ -782,11 +793,11 @@ static void trim_evaluated_curves(const bke::CurvesGeometry &src_curves,
|
|||
GArray<> evaluated_data(CPPType::get<T>(), src_evaluated_points.size());
|
||||
GMutableSpan evaluated_span = evaluated_data.as_mutable_span();
|
||||
src_curves.interpolate_to_evaluated(
|
||||
curve_i, attribute.src.slice(src_curves.points_for_curve(curve_i)), evaluated_span);
|
||||
curve_i, attribute.src.slice(src_points_by_curve[curve_i]), evaluated_span);
|
||||
sample_interval_linear<T>(evaluated_span.typed<T>(),
|
||||
attribute.dst.span.typed<T>(),
|
||||
src_ranges[curve_i],
|
||||
dst_curves.points_for_curve(curve_i),
|
||||
dst_points_by_curve[curve_i],
|
||||
start_points[curve_i],
|
||||
end_points[curve_i]);
|
||||
}
|
||||
|
@ -824,6 +835,7 @@ static void compute_curve_trim_parameters(const bke::CurvesGeometry &curves,
|
|||
MutableSpan<bke::curves::CurvePoint> end_points,
|
||||
MutableSpan<bke::curves::IndexRangeCyclic> src_ranges)
|
||||
{
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
const VArray<bool> src_cyclic = curves.cyclic();
|
||||
const VArray<int> resolution = curves.resolution();
|
||||
const VArray<int8_t> curve_types = curves.curve_types();
|
||||
|
@ -840,7 +852,7 @@ static void compute_curve_trim_parameters(const bke::CurvesGeometry &curves,
|
|||
}
|
||||
else {
|
||||
dst_curve_types[curve_i] = curve_type;
|
||||
point_count = curves.points_num_for_curve(curve_i);
|
||||
point_count = points_by_curve.size(curve_i);
|
||||
}
|
||||
if (point_count == 1) {
|
||||
/* Single point. */
|
||||
|
@ -976,15 +988,16 @@ bke::CurvesGeometry trim_curves(const bke::CurvesGeometry &src_curves,
|
|||
|
||||
/* Transfer copied curves parameters. */
|
||||
const VArray<int8_t> src_curve_types = src_curves.curve_types();
|
||||
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
|
||||
threading::parallel_for(
|
||||
inverse_selection.index_range(), 4096, [&](const IndexRange selection_range) {
|
||||
for (const int64_t curve_i : inverse_selection.slice(selection_range)) {
|
||||
dst_curve_offsets[curve_i] = src_curves.points_num_for_curve(curve_i);
|
||||
dst_curve_offsets[curve_i] = src_points_by_curve.size(curve_i);
|
||||
dst_curve_types[curve_i] = src_curve_types[curve_i];
|
||||
}
|
||||
});
|
||||
/* Finalize and update the geometry container. */
|
||||
bke::curves::accumulate_counts_to_offsets(dst_curve_offsets);
|
||||
offset_indices::accumulate_counts_to_offsets(dst_curve_offsets);
|
||||
dst_curves.resize(dst_curves.offsets().last(), dst_curves.curves_num());
|
||||
dst_curves.update_curve_types();
|
||||
|
||||
|
|
|
@ -304,13 +304,14 @@ static void blur_on_curve_exec(const bke::CurvesGeometry &curves,
|
|||
MutableSpan<T> src = main_buffer;
|
||||
MutableSpan<T> dst = tmp_buffer;
|
||||
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
const VArray<bool> cyclic = curves.cyclic();
|
||||
|
||||
for ([[maybe_unused]] const int iteration : IndexRange(iterations)) {
|
||||
attribute_math::DefaultMixer<T> mixer{dst, IndexMask(0)};
|
||||
threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange range) {
|
||||
for (const int curve_i : range) {
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
if (points.size() == 1) {
|
||||
/* No mixing possible. */
|
||||
const int point_i = points[0];
|
||||
|
@ -347,7 +348,7 @@ static void blur_on_curve_exec(const bke::CurvesGeometry &curves,
|
|||
mixer.mix_in(last_i, src[last_i - 1], last_neighbor_weight);
|
||||
}
|
||||
}
|
||||
mixer.finalize(curves.points_for_curves(range));
|
||||
mixer.finalize(points_by_curve[range]);
|
||||
});
|
||||
std::swap(src, dst);
|
||||
}
|
||||
|
|
|
@ -61,10 +61,11 @@ class EndpointFieldInput final : public bke::CurvesFieldInput {
|
|||
|
||||
Array<bool> selection(curves.points_num(), false);
|
||||
MutableSpan<bool> selection_span = selection.as_mutable_span();
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
devirtualize_varray2(start_size, end_size, [&](const auto &start_size, const auto &end_size) {
|
||||
threading::parallel_for(curves.curves_range(), 1024, [&](IndexRange curves_range) {
|
||||
for (const int i : curves_range) {
|
||||
const IndexRange points = curves.points_for_curve(i);
|
||||
const IndexRange points = points_by_curve[i];
|
||||
const int start = std::max(start_size[i], 0);
|
||||
const int end = std::max(end_size[i], 0);
|
||||
|
||||
|
|
|
@ -52,12 +52,13 @@ static void select_by_handle_type(const bke::CurvesGeometry &curves,
|
|||
const GeometryNodeCurveHandleMode mode,
|
||||
const MutableSpan<bool> r_selection)
|
||||
{
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
VArray<int8_t> curve_types = curves.curve_types();
|
||||
VArray<int8_t> left = curves.handle_types_left();
|
||||
VArray<int8_t> right = curves.handle_types_right();
|
||||
|
||||
for (const int i_curve : curves.curves_range()) {
|
||||
const IndexRange points = curves.points_for_curve(i_curve);
|
||||
const IndexRange points = points_by_curve[i_curve];
|
||||
if (curve_types[i_curve] != CURVE_TYPE_BEZIER) {
|
||||
r_selection.slice(points).fill(false);
|
||||
}
|
||||
|
|
|
@ -312,6 +312,7 @@ class SampleCurveFunction : public mf::MultiFunction {
|
|||
evaluated_normals = curves.evaluated_normals();
|
||||
}
|
||||
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
const VArray<int> curve_indices = params.readonly_single_input<int>(0, "Curve Index");
|
||||
const VArraySpan<float> lengths = params.readonly_single_input<float>(1, "Length");
|
||||
const VArray<bool> cyclic = curves.cyclic();
|
||||
|
@ -377,7 +378,7 @@ class SampleCurveFunction : public mf::MultiFunction {
|
|||
}
|
||||
}
|
||||
if (!sampled_values.is_empty()) {
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
src_original_values.reinitialize(points.size());
|
||||
source_data_->materialize_compressed_to_uninitialized(points, src_original_values.data());
|
||||
src_evaluated_values.reinitialize(curves.evaluated_points_for_curve(curve_i).size());
|
||||
|
|
|
@ -58,6 +58,7 @@ static Array<float> accumulated_lengths_curve_domain(const bke::CurvesGeometry &
|
|||
static Array<float> curve_length_point_domain(const bke::CurvesGeometry &curves)
|
||||
{
|
||||
curves.ensure_evaluated_lengths();
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
const VArray<int8_t> types = curves.curve_types();
|
||||
const VArray<int> resolutions = curves.resolution();
|
||||
const VArray<bool> cyclic = curves.cyclic();
|
||||
|
@ -66,7 +67,7 @@ static Array<float> curve_length_point_domain(const bke::CurvesGeometry &curves)
|
|||
|
||||
threading::parallel_for(curves.curves_range(), 128, [&](IndexRange range) {
|
||||
for (const int i_curve : range) {
|
||||
const IndexRange points = curves.points_for_curve(i_curve);
|
||||
const IndexRange points = points_by_curve[i_curve];
|
||||
const Span<float> evaluated_lengths = curves.evaluated_lengths_for_curve(i_curve,
|
||||
cyclic[i_curve]);
|
||||
MutableSpan<float> lengths = result.as_mutable_span().slice(points);
|
||||
|
@ -114,10 +115,11 @@ static VArray<float> construct_curve_parameter_varray(const bke::CurvesGeometry
|
|||
if (domain == ATTR_DOMAIN_POINT) {
|
||||
Array<float> result = curve_length_point_domain(curves);
|
||||
MutableSpan<float> lengths = result.as_mutable_span();
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
|
||||
threading::parallel_for(curves.curves_range(), 1024, [&](IndexRange range) {
|
||||
for (const int i_curve : range) {
|
||||
MutableSpan<float> curve_lengths = lengths.slice(curves.points_for_curve(i_curve));
|
||||
MutableSpan<float> curve_lengths = lengths.slice(points_by_curve[i_curve]);
|
||||
const float total_length = curve_lengths.last();
|
||||
if (total_length > 0.0f) {
|
||||
const float factor = 1.0f / total_length;
|
||||
|
@ -193,9 +195,10 @@ static VArray<int> construct_index_on_spline_varray(const bke::CurvesGeometry &c
|
|||
if (domain == ATTR_DOMAIN_POINT) {
|
||||
Array<int> result(curves.points_num());
|
||||
MutableSpan<int> span = result.as_mutable_span();
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
threading::parallel_for(curves.curves_range(), 1024, [&](IndexRange range) {
|
||||
for (const int i_curve : range) {
|
||||
MutableSpan<int> indices = span.slice(curves.points_for_curve(i_curve));
|
||||
MutableSpan<int> indices = span.slice(points_by_curve[i_curve]);
|
||||
for (const int i : indices.index_range()) {
|
||||
indices[i] = i;
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ class PointsOfCurveInput final : public bke::CurvesFieldInput {
|
|||
point_evaluator.add(sort_weight_);
|
||||
point_evaluator.evaluate();
|
||||
const VArray<float> all_sort_weights = point_evaluator.get_evaluated<float>(0);
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
|
||||
Array<int> point_of_curve(mask.min_array_size());
|
||||
threading::parallel_for(mask.index_range(), 256, [&](const IndexRange range) {
|
||||
|
@ -77,7 +78,7 @@ class PointsOfCurveInput final : public bke::CurvesFieldInput {
|
|||
continue;
|
||||
}
|
||||
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
|
||||
/* Retrieve the weights for each point. */
|
||||
sort_weights.reinitialize(points.size());
|
||||
|
@ -142,8 +143,9 @@ class CurvePointCountInput final : public bke::CurvesFieldInput {
|
|||
if (domain != ATTR_DOMAIN_CURVE) {
|
||||
return {};
|
||||
}
|
||||
return VArray<int>::ForFunc(curves.curves_num(), [&, curves](const int64_t curve_i) {
|
||||
return curves.points_num_for_curve(curve_i);
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
return VArray<int>::ForFunc(curves.curves_num(), [points_by_curve](const int64_t curve_i) {
|
||||
return points_by_curve.size(curve_i);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -74,6 +74,8 @@ static void deform_curves(const CurvesGeometry &curves,
|
|||
const Span<MLoop> surface_loops_new = surface_mesh_new.loops();
|
||||
const Span<MLoopTri> surface_looptris_new = surface_mesh_new.looptris();
|
||||
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
|
||||
threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange range) {
|
||||
for (const int curve_i : range) {
|
||||
const ReverseUVSampler::Result &surface_sample_old = surface_samples_old[curve_i];
|
||||
|
@ -197,7 +199,7 @@ static void deform_curves(const CurvesGeometry &curves,
|
|||
const float4x4 curve_transform = surface_to_curves * surface_transform * curves_to_surface;
|
||||
|
||||
/* Actually transform all points. */
|
||||
const IndexRange points = curves.points_for_curve(curve_i);
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
for (const int point_i : points) {
|
||||
const float3 old_point_pos = r_positions[point_i];
|
||||
const float3 new_point_pos = curve_transform * old_point_pos;
|
||||
|
|
|
@ -235,6 +235,9 @@ static void copy_curve_attributes_without_id(
|
|||
Map<AttributeIDRef, AttributeKind> attributes = gather_attributes_without_id(
|
||||
geometry_set, GEO_COMPONENT_TYPE_CURVE, propagation_info);
|
||||
|
||||
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
|
||||
const OffsetIndices dst_points_by_curve = dst_curves.points_by_curve();
|
||||
|
||||
for (const Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
|
||||
const AttributeIDRef attribute_id = entry.key;
|
||||
GAttributeReader src_attribute = src_curves.attributes().lookup(attribute_id);
|
||||
|
@ -265,9 +268,9 @@ static void copy_curve_attributes_without_id(
|
|||
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
|
||||
for (const int i_selection : range) {
|
||||
const int i_src_curve = selection[i_selection];
|
||||
const Span<T> curve_src = src.slice(src_curves.points_for_curve(i_src_curve));
|
||||
const Span<T> curve_src = src.slice(src_points_by_curve[i_src_curve]);
|
||||
for (const int i_dst_curve : range_for_offsets_index(curve_offsets, i_selection)) {
|
||||
dst.slice(dst_curves.points_for_curve(i_dst_curve)).copy_from(curve_src);
|
||||
dst.slice(dst_points_by_curve[i_dst_curve]).copy_from(curve_src);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -305,15 +308,17 @@ static void copy_stable_id_curves(const bke::CurvesGeometry &src_curves,
|
|||
VArraySpan<int> src{src_attribute.varray.typed<int>()};
|
||||
MutableSpan<int> dst = dst_attribute.span.typed<int>();
|
||||
|
||||
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 range) {
|
||||
for (const int i_selection : range) {
|
||||
const int i_src_curve = selection[i_selection];
|
||||
const Span<int> curve_src = src.slice(src_curves.points_for_curve(i_src_curve));
|
||||
const Span<int> curve_src = src.slice(src_points_by_curve[i_src_curve]);
|
||||
const IndexRange duplicates_range = range_for_offsets_index(curve_offsets, i_selection);
|
||||
for (const int i_duplicate : IndexRange(duplicates_range.size()).drop_front(1)) {
|
||||
const int i_dst_curve = duplicates_range[i_duplicate];
|
||||
copy_hashed_ids(
|
||||
curve_src, i_duplicate, dst.slice(dst_curves.points_for_curve(i_dst_curve)));
|
||||
copy_hashed_ids(curve_src, i_duplicate, dst.slice(dst_points_by_curve[i_dst_curve]));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -344,6 +349,8 @@ static void duplicate_curves(GeometrySet &geometry_set,
|
|||
const VArray<int> counts = evaluator.get_evaluated<int>(0);
|
||||
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
|
||||
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
|
||||
/* The offset in the result curve domain at every selected input curve. */
|
||||
Array<int> curve_offsets(selection.size() + 1);
|
||||
Array<int> point_offsets(selection.size() + 1);
|
||||
|
@ -355,7 +362,7 @@ static void duplicate_curves(GeometrySet &geometry_set,
|
|||
curve_offsets[i_curve] = dst_curves_num;
|
||||
point_offsets[i_curve] = dst_points_num;
|
||||
dst_curves_num += count;
|
||||
dst_points_num += count * curves.points_for_curve(selection[i_curve]).size();
|
||||
dst_points_num += count * points_by_curve.size(selection[i_curve]);
|
||||
}
|
||||
curve_offsets.last() = dst_curves_num;
|
||||
point_offsets.last() = dst_points_num;
|
||||
|
@ -368,7 +375,7 @@ static void duplicate_curves(GeometrySet &geometry_set,
|
|||
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
|
||||
for (const int i_selection : range) {
|
||||
const int i_src_curve = selection[i_selection];
|
||||
const IndexRange src_curve_range = curves.points_for_curve(i_src_curve);
|
||||
const IndexRange src_curve_range = points_by_curve[i_src_curve];
|
||||
const IndexRange dst_curves_range = range_for_offsets_index(curve_offsets, i_selection);
|
||||
MutableSpan<int> dst_offsets = all_dst_offsets.slice(dst_curves_range);
|
||||
for (const int i_duplicate : IndexRange(dst_curves_range.size())) {
|
||||
|
@ -814,10 +821,11 @@ static void duplicate_points_curve(GeometrySet &geometry_set,
|
|||
Array<int> offsets = accumulate_counts_to_offsets(selection, counts);
|
||||
const int dst_num = offsets.last();
|
||||
|
||||
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
|
||||
Array<int> point_to_curve_map(src_curves.points_num());
|
||||
threading::parallel_for(src_curves.curves_range(), 1024, [&](const IndexRange range) {
|
||||
for (const int i_curve : range) {
|
||||
const IndexRange points = src_curves.points_for_curve(i_curve);
|
||||
const IndexRange points = src_points_by_curve[i_curve];
|
||||
point_to_curve_map.as_mutable_span().slice(points).fill(i_curve);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -19,7 +19,8 @@ static void node_declare(NodeDeclarationBuilder &b)
|
|||
static VArray<int> construct_curve_point_count_gvarray(const bke::CurvesGeometry &curves,
|
||||
const eAttrDomain domain)
|
||||
{
|
||||
auto count_fn = [curves](int64_t i) { return curves.points_for_curve(i).size(); };
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
auto count_fn = [points_by_curve](int64_t i) { return points_by_curve.size(i); };
|
||||
|
||||
if (domain == ATTR_DOMAIN_CURVE) {
|
||||
return VArray<int>::ForFunc(curves.curves_num(), count_fn);
|
||||
|
|
|
@ -15,6 +15,7 @@ static void node_declare(NodeDeclarationBuilder &b)
|
|||
|
||||
static Array<float3> curve_tangent_point_domain(const bke::CurvesGeometry &curves)
|
||||
{
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
const VArray<int8_t> types = curves.curve_types();
|
||||
const VArray<int> resolutions = curves.resolution();
|
||||
const VArray<bool> cyclic = curves.cyclic();
|
||||
|
@ -26,7 +27,7 @@ static Array<float3> curve_tangent_point_domain(const bke::CurvesGeometry &curve
|
|||
|
||||
threading::parallel_for(curves.curves_range(), 128, [&](IndexRange range) {
|
||||
for (const int i_curve : range) {
|
||||
const IndexRange points = curves.points_for_curve(i_curve);
|
||||
const IndexRange points = points_by_curve[i_curve];
|
||||
const IndexRange evaluated_points = curves.evaluated_points_for_curve(i_curve);
|
||||
|
||||
MutableSpan<float3> curve_tangents = results.as_mutable_span().slice(points);
|
||||
|
|
|
@ -61,6 +61,7 @@ class ControlPointNeighborFieldInput final : public bke::CurvesFieldInput {
|
|||
const eAttrDomain domain,
|
||||
const IndexMask mask) const final
|
||||
{
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
const VArray<bool> cyclic = curves.cyclic();
|
||||
const Array<int> parent_curves = curves.point_to_curve_map();
|
||||
|
||||
|
@ -76,7 +77,7 @@ class ControlPointNeighborFieldInput final : public bke::CurvesFieldInput {
|
|||
for (const int i_selection : mask) {
|
||||
const int i_point = std::clamp(indices[i_selection], 0, curves.points_num() - 1);
|
||||
const int i_curve = parent_curves[i_point];
|
||||
const IndexRange curve_points = curves.points_for_curve(i_curve);
|
||||
const IndexRange curve_points = points_by_curve[i_curve];
|
||||
const int offset_point = i_point + offsets[i_point];
|
||||
|
||||
if (cyclic[i_curve]) {
|
||||
|
@ -116,6 +117,7 @@ class OffsetValidFieldInput final : public bke::CurvesFieldInput {
|
|||
const IndexMask mask) const final
|
||||
{
|
||||
const VArray<bool> cyclic = curves.cyclic();
|
||||
const OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
const Array<int> parent_curves = curves.point_to_curve_map();
|
||||
|
||||
const bke::CurvesFieldContext context{curves, domain};
|
||||
|
@ -135,7 +137,7 @@ class OffsetValidFieldInput final : public bke::CurvesFieldInput {
|
|||
}
|
||||
|
||||
const int i_curve = parent_curves[i_point];
|
||||
const IndexRange curve_points = curves.points_for_curve(i_curve);
|
||||
const IndexRange curve_points = points_by_curve[i_curve];
|
||||
if (cyclic[i_curve]) {
|
||||
output[i_selection] = true;
|
||||
continue;
|
||||
|
|
Loading…
Reference in New Issue