Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/curves_geometry.cc')
-rw-r--r--source/blender/blenkernel/intern/curves_geometry.cc232
1 files changed, 134 insertions, 98 deletions
diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc
index f5c040a6fee..7c338480c71 100644
--- a/source/blender/blenkernel/intern/curves_geometry.cc
+++ b/source/blender/blenkernel/intern/curves_geometry.cc
@@ -9,10 +9,12 @@
#include "MEM_guardedalloc.h"
+#include "BLI_array_utils.hh"
#include "BLI_bounds.hh"
#include "BLI_index_mask_ops.hh"
#include "BLI_length_parameterize.hh"
#include "BLI_math_rotation.hh"
+#include "BLI_task.hh"
#include "DNA_curves_types.h"
@@ -57,7 +59,7 @@ CurvesGeometry::CurvesGeometry(const int point_num, const int curve_num)
CustomData_add_layer_named(&this->point_data,
CD_PROP_FLOAT3,
- CD_DEFAULT,
+ CD_CONSTRUCT,
nullptr,
this->point_num,
ATTR_POSITION.c_str());
@@ -221,7 +223,7 @@ static MutableSpan<T> get_mutable_attribute(CurvesGeometry &curves,
return {data, num};
}
data = (T *)CustomData_add_layer_named(
- &custom_data, type, CD_CALLOC, nullptr, num, name.c_str());
+ &custom_data, type, CD_SET_DEFAULT, nullptr, num, name.c_str());
MutableSpan<T> span = {data, num};
if (num > 0 && span.first() != default_value) {
span.fill(default_value);
@@ -254,6 +256,12 @@ void CurvesGeometry::fill_curve_types(const IndexMask selection, const CurveType
this->fill_curve_types(type);
return;
}
+ if (std::optional<int8_t> single_type = this->curve_types().get_if_single()) {
+ if (single_type == type) {
+ /* No need for an array if the types are already a single with the correct type. */
+ return;
+ }
+ }
/* A potential performance optimization is only counting the changed indices. */
this->curve_types_for_write().fill_indices(selection, type);
this->update_curve_types();
@@ -550,6 +558,15 @@ IndexMask CurvesGeometry::indices_for_curve_type(const CurveType type,
this->curve_types(), this->curve_type_counts(), type, selection, r_indices);
}
+Array<int> CurvesGeometry::point_to_curve_map() const
+{
+ 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);
+ }
+ return map;
+}
+
void CurvesGeometry::ensure_nurbs_basis_cache() const
{
if (!this->runtime->nurbs_basis_cache_dirty) {
@@ -715,8 +732,9 @@ Span<float3> CurvesGeometry::evaluated_tangents() const
}
});
- /* Correct the first and last tangents of Bezier curves so that they align with the inner
- * handles. This is a separate loop to avoid the cost when Bezier type curves are not used. */
+ /* Correct the first and last tangents of non-cyclic Bezier curves so that they align with the
+ * inner handles. This is a separate loop to avoid the cost when Bezier type curves are not
+ * used. */
Vector<int64_t> bezier_indices;
const IndexMask bezier_mask = this->indices_for_curve_type(CURVE_TYPE_BEZIER, bezier_indices);
if (!bezier_mask.is_empty()) {
@@ -726,14 +744,20 @@ Span<float3> CurvesGeometry::evaluated_tangents() const
threading::parallel_for(bezier_mask.index_range(), 1024, [&](IndexRange range) {
for (const int curve_index : bezier_mask.slice(range)) {
+ if (cyclic[curve_index]) {
+ continue;
+ }
const IndexRange points = this->points_for_curve(curve_index);
const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index);
- if (handles_right[points.first()] != positions[points.first()]) {
+ const float epsilon = 1e-6f;
+ if (!math::almost_equal_relative(
+ handles_right[points.first()], positions[points.first()], epsilon)) {
tangents[evaluated_points.first()] = math::normalize(handles_right[points.first()] -
positions[points.first()]);
}
- if (handles_left[points.last()] != positions[points.last()]) {
+ if (!math::almost_equal_relative(
+ handles_left[points.last()], positions[points.last()], epsilon)) {
tangents[evaluated_points.last()] = math::normalize(positions[points.last()] -
handles_left[points.last()]);
}
@@ -934,6 +958,12 @@ void CurvesGeometry::ensure_evaluated_lengths() const
this->runtime->length_cache_dirty = false;
}
+void CurvesGeometry::ensure_can_interpolate_to_evaluated() const
+{
+ this->ensure_evaluated_offsets();
+ this->ensure_nurbs_basis_cache();
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -943,11 +973,11 @@ void CurvesGeometry::ensure_evaluated_lengths() const
void CurvesGeometry::resize(const int points_num, const int curves_num)
{
if (points_num != this->point_num) {
- CustomData_realloc(&this->point_data, points_num);
+ CustomData_realloc(&this->point_data, this->points_num(), points_num);
this->point_num = points_num;
}
if (curves_num != this->curve_num) {
- CustomData_realloc(&this->curve_data, curves_num);
+ CustomData_realloc(&this->curve_data, this->curves_num(), curves_num);
this->curve_num = curves_num;
this->curve_offsets = (int *)MEM_reallocN(this->curve_offsets, sizeof(int) * (curves_num + 1));
}
@@ -1082,21 +1112,11 @@ static void copy_between_buffers(const CPPType &type,
src_range.size());
}
-template<typename T>
-static void copy_with_map(const Span<T> src, const Span<int> map, MutableSpan<T> dst)
-{
- threading::parallel_for(map.index_range(), 1024, [&](const IndexRange range) {
- for (const int i : range) {
- dst[i] = src[map[i]];
- }
- });
-}
-
static void copy_with_map(const GSpan src, const Span<int> map, GMutableSpan dst)
{
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
- copy_with_map(src.typed<T>(), map, dst.typed<T>());
+ array_utils::gather(src.typed<T>(), map, dst.typed<T>());
});
}
@@ -1159,14 +1179,18 @@ static CurvesGeometry copy_with_removed_points(const CurvesGeometry &curves,
}
CurvesGeometry new_curves{new_point_count, new_curve_count};
+ Vector<bke::AttributeTransferData> point_attributes = bke::retrieve_attributes_for_transfer(
+ curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_POINT);
+ Vector<bke::AttributeTransferData> curve_attributes = bke::retrieve_attributes_for_transfer(
+ curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_CURVE);
threading::parallel_invoke(
+ 256 < new_point_count * new_curve_count,
/* Initialize curve offsets. */
[&]() { new_curves.offsets_for_write().copy_from(new_curve_offsets); },
- /* Copy over point attributes. */
[&]() {
- for (auto &attribute : bke::retrieve_attributes_for_transfer(
- curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_POINT)) {
+ /* Copy over point attributes. */
+ for (bke::AttributeTransferData &attribute : point_attributes) {
threading::parallel_for(copy_point_ranges.index_range(), 128, [&](IndexRange range) {
for (const int range_i : range) {
const IndexRange src_range = copy_point_ranges[range_i];
@@ -1177,25 +1201,33 @@ static CurvesGeometry copy_with_removed_points(const CurvesGeometry &curves,
{copy_point_range_dst_offsets[range_i], src_range.size()});
}
});
- attribute.dst.finish();
}
},
- /* Copy over curve attributes.
- * In some cases points are just dissolved, so the the number of
- * curves will be the same. That could be optimized in the future. */
[&]() {
- for (auto &attribute : bke::retrieve_attributes_for_transfer(
- curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_CURVE)) {
+ /* Copy over curve attributes.
+ * In some cases points are just dissolved, so the number of
+ * curves will be the same. That could be optimized in the future. */
+ for (bke::AttributeTransferData &attribute : curve_attributes) {
if (new_curves.curves_num() == curves.curves_num()) {
attribute.dst.span.copy_from(attribute.src);
}
else {
copy_with_map(attribute.src, new_curve_orig_indices, attribute.dst.span);
}
- attribute.dst.finish();
}
});
+ for (bke::AttributeTransferData &attribute : point_attributes) {
+ attribute.dst.finish();
+ }
+ for (bke::AttributeTransferData &attribute : curve_attributes) {
+ attribute.dst.finish();
+ }
+
+ if (new_curves.curves_num() != curves.curves_num()) {
+ new_curves.remove_attributes_based_on_types();
+ }
+
return new_curves;
}
@@ -1232,8 +1264,13 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
}
CurvesGeometry new_curves{new_tot_points, new_tot_curves};
+ Vector<bke::AttributeTransferData> point_attributes = bke::retrieve_attributes_for_transfer(
+ curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_POINT);
+ Vector<bke::AttributeTransferData> curve_attributes = bke::retrieve_attributes_for_transfer(
+ curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_CURVE);
threading::parallel_invoke(
+ 256 < new_tot_points * new_tot_curves,
/* Initialize curve offsets. */
[&]() {
MutableSpan<int> new_offsets = new_curves.offsets_for_write();
@@ -1260,10 +1297,9 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
}
});
},
- /* Copy over point attributes. */
[&]() {
- for (auto &attribute : bke::retrieve_attributes_for_transfer(
- curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_POINT)) {
+ /* Copy over point attributes. */
+ for (bke::AttributeTransferData &attribute : point_attributes) {
threading::parallel_for(old_curve_ranges.index_range(), 128, [&](IndexRange range) {
for (const int range_i : range) {
copy_between_buffers(attribute.src.type(),
@@ -1273,13 +1309,11 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
new_point_ranges[range_i]);
}
});
- attribute.dst.finish();
}
},
- /* Copy over curve attributes. */
[&]() {
- for (auto &attribute : bke::retrieve_attributes_for_transfer(
- curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_CURVE)) {
+ /* Copy over curve attributes. */
+ for (bke::AttributeTransferData &attribute : curve_attributes) {
threading::parallel_for(old_curve_ranges.index_range(), 128, [&](IndexRange range) {
for (const int range_i : range) {
copy_between_buffers(attribute.src.type(),
@@ -1289,10 +1323,18 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
new_curve_ranges[range_i]);
}
});
- attribute.dst.finish();
}
});
+ for (bke::AttributeTransferData &attribute : point_attributes) {
+ attribute.dst.finish();
+ }
+ for (bke::AttributeTransferData &attribute : curve_attributes) {
+ attribute.dst.finish();
+ }
+
+ new_curves.remove_attributes_based_on_types();
+
return new_curves;
}
@@ -1336,73 +1378,60 @@ static void reverse_swap_curve_point_data(const CurvesGeometry &curves,
std::swap(a[end_index], b[i]);
std::swap(b[end_index], a[i]);
}
+ if (points.size() % 2) {
+ const int64_t middle_index = points.size() / 2;
+ std::swap(a[middle_index], b[middle_index]);
+ }
}
});
}
-static bool layer_matches_name_and_type(const CustomDataLayer &layer,
- const StringRef name,
- const eCustomDataType type)
-{
- if (layer.type != type) {
- return false;
- }
- return layer.name == name;
-}
-
void CurvesGeometry::reverse_curves(const IndexMask curves_to_reverse)
{
- CustomData_duplicate_referenced_layers(&this->point_data, this->points_num());
-
- /* Collect the Bezier handle attributes while iterating through the point custom data layers;
- * they need special treatment later. */
- MutableSpan<float3> positions_left;
- MutableSpan<float3> positions_right;
- MutableSpan<int8_t> types_left;
- MutableSpan<int8_t> types_right;
+ Set<StringRef> bezier_handle_names{{ATTR_HANDLE_POSITION_LEFT,
+ ATTR_HANDLE_POSITION_RIGHT,
+ ATTR_HANDLE_TYPE_LEFT,
+ ATTR_HANDLE_TYPE_RIGHT}};
- for (const int layer_i : IndexRange(this->point_data.totlayer)) {
- CustomDataLayer &layer = this->point_data.layers[layer_i];
+ MutableAttributeAccessor attributes = this->attributes_for_write();
- if (positions_left.is_empty() &&
- layer_matches_name_and_type(layer, ATTR_HANDLE_POSITION_LEFT, CD_PROP_FLOAT3)) {
- positions_left = {static_cast<float3 *>(layer.data), this->points_num()};
- continue;
+ attributes.for_all([&](const AttributeIDRef &id, AttributeMetaData meta_data) {
+ if (meta_data.domain != ATTR_DOMAIN_POINT) {
+ return true;
}
- if (positions_right.is_empty() &&
- layer_matches_name_and_type(layer, ATTR_HANDLE_POSITION_RIGHT, CD_PROP_FLOAT3)) {
- positions_right = {static_cast<float3 *>(layer.data), this->points_num()};
- continue;
+ if (meta_data.data_type == CD_PROP_STRING) {
+ return true;
}
- if (types_left.is_empty() &&
- layer_matches_name_and_type(layer, ATTR_HANDLE_TYPE_LEFT, CD_PROP_INT8)) {
- types_left = {static_cast<int8_t *>(layer.data), this->points_num()};
- continue;
- }
- if (types_right.is_empty() &&
- layer_matches_name_and_type(layer, ATTR_HANDLE_TYPE_RIGHT, CD_PROP_INT8)) {
- types_right = {static_cast<int8_t *>(layer.data), this->points_num()};
- continue;
+ if (id.is_named() && bezier_handle_names.contains(id.name())) {
+ return true;
}
- const eCustomDataType data_type = static_cast<eCustomDataType>(layer.type);
- attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
+ attribute_math::convert_to_static_type(attribute.span.type(), [&](auto dummy) {
using T = decltype(dummy);
- reverse_curve_point_data<T>(
- *this, curves_to_reverse, {static_cast<T *>(layer.data), this->points_num()});
+ reverse_curve_point_data<T>(*this, curves_to_reverse, attribute.span.typed<T>());
});
- }
+ attribute.finish();
+ return true;
+ });
/* In order to maintain the shape of Bezier curves, handle attributes must reverse, but also the
* values for the left and right must swap. Use a utility to swap and reverse at the same time,
* to avoid loading the attribute twice. Generally we can expect the right layer to exist when
* the left does, but there's no need to count on it, so check for both attributes. */
- if (!positions_left.is_empty() && !positions_right.is_empty()) {
- reverse_swap_curve_point_data(*this, curves_to_reverse, positions_left, positions_right);
+ if (attributes.contains(ATTR_HANDLE_POSITION_LEFT) &&
+ attributes.contains(ATTR_HANDLE_POSITION_RIGHT)) {
+ reverse_swap_curve_point_data(*this,
+ curves_to_reverse,
+ this->handle_positions_left_for_write(),
+ this->handle_positions_right_for_write());
}
- if (!types_left.is_empty() && !types_right.is_empty()) {
- reverse_swap_curve_point_data(*this, curves_to_reverse, types_left, types_right);
+ if (attributes.contains(ATTR_HANDLE_TYPE_LEFT) && attributes.contains(ATTR_HANDLE_TYPE_RIGHT)) {
+ reverse_swap_curve_point_data(*this,
+ curves_to_reverse,
+ this->handle_types_left_for_write(),
+ this->handle_types_right_for_write());
}
this->tag_topology_changed();
@@ -1410,21 +1439,20 @@ void CurvesGeometry::reverse_curves(const IndexMask curves_to_reverse)
void CurvesGeometry::remove_attributes_based_on_types()
{
- const int points_num = this->points_num();
- const int curves_num = this->curves_num();
+ MutableAttributeAccessor attributes = this->attributes_for_write();
if (!this->has_curve_with_type(CURVE_TYPE_BEZIER)) {
- CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_TYPE_LEFT.c_str(), points_num);
- CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_TYPE_RIGHT.c_str(), points_num);
- CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_POSITION_LEFT.c_str(), points_num);
- CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_POSITION_RIGHT.c_str(), points_num);
+ attributes.remove(ATTR_HANDLE_TYPE_LEFT);
+ attributes.remove(ATTR_HANDLE_TYPE_RIGHT);
+ attributes.remove(ATTR_HANDLE_POSITION_LEFT);
+ attributes.remove(ATTR_HANDLE_POSITION_RIGHT);
}
if (!this->has_curve_with_type(CURVE_TYPE_NURBS)) {
- CustomData_free_layer_named(&this->point_data, ATTR_NURBS_WEIGHT.c_str(), points_num);
- CustomData_free_layer_named(&this->curve_data, ATTR_NURBS_ORDER.c_str(), curves_num);
- CustomData_free_layer_named(&this->curve_data, ATTR_NURBS_KNOTS_MODE.c_str(), curves_num);
+ attributes.remove(ATTR_NURBS_WEIGHT);
+ attributes.remove(ATTR_NURBS_ORDER);
+ attributes.remove(ATTR_NURBS_KNOTS_MODE);
}
if (!this->has_curve_with_type({CURVE_TYPE_BEZIER, CURVE_TYPE_CATMULL_ROM, CURVE_TYPE_NURBS})) {
- CustomData_free_layer_named(&this->curve_data, ATTR_RESOLUTION.c_str(), curves_num);
+ attributes.remove(ATTR_RESOLUTION);
}
}
@@ -1447,12 +1475,15 @@ static void adapt_curve_domain_point_to_curve_impl(const CurvesGeometry &curves,
MutableSpan<T> r_values)
{
attribute_math::DefaultMixer<T> mixer(r_values);
- for (const int i_curve : IndexRange(curves.curves_num())) {
- for (const int i_point : curves.points_for_curve(i_curve)) {
- mixer.mix_in(i_curve, old_values[i_point]);
+
+ 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)) {
+ mixer.mix_in(i_curve, old_values[i_point]);
+ }
}
- }
- mixer.finalize();
+ mixer.finalize(range);
+ });
}
/**
@@ -1536,6 +1567,11 @@ GVArray CurvesGeometry::adapt_domain(const GVArray &varray,
if (from == to) {
return varray;
}
+ if (varray.is_single()) {
+ BUFFER_FOR_CPP_TYPE_VALUE(varray.type(), value);
+ varray.get_internal_single(value);
+ return GVArray::ForSingle(varray.type(), this->attributes().domain_size(to), value);
+ }
if (from == ATTR_DOMAIN_POINT && to == ATTR_DOMAIN_CURVE) {
return adapt_curve_domain_point_to_curve(*this, varray);