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')
-rw-r--r--source/blender/blenkernel/BKE_attribute.hh13
-rw-r--r--source/blender/blenkernel/BKE_curves.hh73
-rw-r--r--source/blender/blenkernel/BKE_curves_utils.hh328
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc32
-rw-r--r--source/blender/blenkernel/intern/curve_catmull_rom.cc14
5 files changed, 450 insertions, 10 deletions
diff --git a/source/blender/blenkernel/BKE_attribute.hh b/source/blender/blenkernel/BKE_attribute.hh
index 21d91af55d5..fbdacee139c 100644
--- a/source/blender/blenkernel/BKE_attribute.hh
+++ b/source/blender/blenkernel/BKE_attribute.hh
@@ -710,6 +710,19 @@ Vector<AttributeTransferData> retrieve_attributes_for_transfer(
eAttrDomainMask domain_mask,
const Set<std::string> &skip = {});
+/**
+ * Copy attributes for the domain based on the elementwise mask.
+ *
+ * \param mask_indices: Indexed elements to copy from the source data-block.
+ * \param domain: Attribute domain to transfer.
+ * \param skip: Named attributes to ignore/skip.
+ */
+void copy_attribute_domain(AttributeAccessor src_attributes,
+ MutableAttributeAccessor dst_attributes,
+ IndexMask selection,
+ eAttrDomain domain,
+ const Set<std::string> &skip = {});
+
bool allow_procedural_attribute_access(StringRef attribute_name);
extern const char *no_procedural_access_message;
diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh
index 4b0fc293b54..9f150c13d6e 100644
--- a/source/blender/blenkernel/BKE_curves.hh
+++ b/source/blender/blenkernel/BKE_curves.hh
@@ -22,6 +22,7 @@
#include "BLI_virtual_array.hh"
#include "BKE_attribute.hh"
+#include "BKE_attribute_math.hh"
namespace blender::bke {
@@ -162,6 +163,11 @@ class CurvesGeometry : public ::CurvesGeometry {
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.
*/
@@ -532,6 +538,16 @@ bool segment_is_vector(Span<int8_t> handle_types_left,
int segment_index);
/**
+ * True if the Bezier curve contains polygonal segments of HandleType::BEZIER_HANDLE_VECTOR.
+ *
+ * \param num_curve_points: Number of points in the curve.
+ * \param evaluated_size: Number of evaluated points in the curve.
+ * \param cyclic: If curve is cyclic.
+ * \param resolution: Curve resolution.
+ */
+bool has_vector_handles(int num_curve_points, int64_t evaluated_size, bool cyclic, int resolution);
+
+/**
* Return true if the curve's last cyclic segment has a vector type.
* This only makes a difference in the shape of cyclic curves.
*/
@@ -693,6 +709,36 @@ void interpolate_to_evaluated(const GSpan src,
const Span<int> evaluated_offsets,
GMutableSpan dst);
+void calculate_basis(const float parameter, float r_weights[4]);
+
+/**
+ * Interpolate the control point values for the given parameter on the piecewise segment.
+ * \param a: Value associated with the first control point influencing the segment.
+ * \param d: Value associated with the fourth control point.
+ * \param parameter: Parameter in range [0, 1] to compute the interpolation for.
+ */
+template<typename T>
+T interpolate(const T &a, const T &b, const T &c, const T &d, const float parameter)
+{
+ float n[4];
+ calculate_basis(parameter, n);
+ /* TODO: Use DefaultMixer or other generic mixing in the basis evaluation function to simplify
+ * supporting more types. */
+ if constexpr (!is_same_any_v<T, float, float2, float3, float4, int8_t, int, int64_t>) {
+ T return_value;
+ attribute_math::DefaultMixer<T> mixer({&return_value, 1});
+ mixer.mix_in(0, a, n[0] * 0.5f);
+ mixer.mix_in(0, b, n[1] * 0.5f);
+ mixer.mix_in(0, c, n[2] * 0.5f);
+ mixer.mix_in(0, d, n[3] * 0.5f);
+ mixer.finalize();
+ return return_value;
+ }
+ else {
+ return 0.5f * (a * n[0] + b * n[1] + c * n[2] + d * n[3]);
+ }
+}
+
} // namespace catmull_rom
/** \} */
@@ -807,6 +853,16 @@ 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();
@@ -833,6 +889,7 @@ inline IndexRange CurvesGeometry::points_for_curve(const int index) 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];
@@ -905,11 +962,13 @@ inline float CurvesGeometry::evaluated_length_total_for_curve(const int curve_in
/** \} */
+namespace curves {
+
/* -------------------------------------------------------------------- */
/** \name Bezier Inline Methods
* \{ */
-namespace curves::bezier {
+namespace bezier {
inline bool point_is_sharp(const Span<int8_t> handle_types_left,
const Span<int8_t> handle_types_right,
@@ -929,14 +988,24 @@ inline bool segment_is_vector(const int8_t left, const int8_t right)
return segment_is_vector(HandleType(left), HandleType(right));
}
+inline bool has_vector_handles(const int num_curve_points,
+ const int64_t evaluated_size,
+ const bool cyclic,
+ const int resolution)
+{
+ return evaluated_size - !cyclic != (int64_t)segments_num(num_curve_points, cyclic) * resolution;
+}
+
inline float3 calculate_vector_handle(const float3 &point, const float3 &next_point)
{
return math::interpolate(point, next_point, 1.0f / 3.0f);
}
+} // namespace bezier
+
/** \} */
-} // namespace curves::bezier
+} // namespace curves
struct CurvesSurfaceTransforms {
float4x4 curves_to_world;
diff --git a/source/blender/blenkernel/BKE_curves_utils.hh b/source/blender/blenkernel/BKE_curves_utils.hh
index 0fbd33002e1..5579ab5654a 100644
--- a/source/blender/blenkernel/BKE_curves_utils.hh
+++ b/source/blender/blenkernel/BKE_curves_utils.hh
@@ -11,9 +11,301 @@
#include "BLI_function_ref.hh"
#include "BLI_generic_pointer.hh"
+#include "BLI_index_range.hh"
namespace blender::bke::curves {
+/* --------------------------------------------------------------------
+ * Utility structs.
+ */
+
+/**
+ * Reference to a piecewise segment on a spline curve.
+ */
+struct CurveSegment {
+ /**
+ * Index of the previous control/evaluated point on the curve. First point on the segment.
+ */
+ int index;
+ /**
+ * Index of the next control/evaluated point on the curve. Last point on the curve segment.
+ * Should be 0 for looped segments.
+ */
+ int next_index;
+};
+
+/**
+ * Reference to a point on a piecewise curve (spline).
+ *
+ * Tracks indices of the neighbouring control/evaluated point pair associated with the segment
+ * in which the point resides. Referenced point within the segment is defined by a
+ * normalized parameter in the range [0, 1].
+ */
+struct CurvePoint : public CurveSegment {
+ /**
+ * Normalized parameter in the range [0, 1] defining the point on the piecewise segment.
+ * Note that the curve point representation is not unique at segment endpoints.
+ */
+ float parameter;
+
+ /**
+ * True if the parameter is an integer and references a control/evaluated point.
+ */
+ inline bool is_controlpoint() const;
+
+ /*
+ * Compare if the points are equal.
+ */
+ inline bool operator==(const CurvePoint &other) const;
+ inline bool operator!=(const CurvePoint &other) const;
+
+ /**
+ * Compare if 'this' point comes before 'other'. Loop segment for cyclical curves counts
+ * as the first (least) segment.
+ */
+ inline bool operator<(const CurvePoint &other) const;
+};
+
+/**
+ * Cyclical index range. Iterates the interval [start, end).
+ */
+class IndexRangeCyclic {
+ /* Index to the start and end of the iterated range.
+ */
+ int64_t start_ = 0;
+ int64_t end_ = 0;
+ /* Index for the start and end of the entire iterable range which contains the iterated range
+ * (e.g. the point range for an indiviudal spline/curve within the entire Curves point domain).
+ */
+ int64_t range_start_ = 0;
+ int64_t range_end_ = 0;
+ /* Number of times the range end is passed when the range is iterated.
+ */
+ int64_t cycles_ = 0;
+
+ constexpr IndexRangeCyclic(int64_t begin,
+ int64_t end,
+ int64_t iterable_range_start,
+ int64_t iterable_range_end,
+ int64_t cycles)
+ : start_(begin),
+ end_(end),
+ range_start_(iterable_range_start),
+ range_end_(iterable_range_end),
+ cycles_(cycles)
+ {
+ }
+
+ public:
+ constexpr IndexRangeCyclic() = default;
+ ~IndexRangeCyclic() = default;
+
+ constexpr IndexRangeCyclic(int64_t start, int64_t end, IndexRange iterable_range, int64_t cycles)
+ : start_(start),
+ end_(end),
+ range_start_(iterable_range.first()),
+ range_end_(iterable_range.one_after_last()),
+ cycles_(cycles)
+ {
+ }
+
+ /**
+ * Create an iterator over the cyclical interval [start_index, end_index).
+ */
+ constexpr IndexRangeCyclic(int64_t start, int64_t end, IndexRange iterable_range)
+ : start_(start),
+ end_(end == iterable_range.one_after_last() ? iterable_range.first() : end),
+ range_start_(iterable_range.first()),
+ range_end_(iterable_range.one_after_last()),
+ cycles_(end < start)
+ {
+ }
+
+ /**
+ * Increment the range by adding the given number of indices to the beginning of the range.
+ */
+ constexpr IndexRangeCyclic push_forward(int n)
+ {
+ BLI_assert(n >= 0);
+ int64_t nstart = start_ - n;
+ int64_t cycles = cycles_;
+ if (nstart < range_start_) {
+
+ cycles += (int64_t)(n / (range_end_ - range_start_)) + (end_ < nstart) - (end_ < start_);
+ }
+ return {nstart, end_, range_start_, range_end_, cycles};
+ }
+ /**
+ * Increment the range by adding the given number of indices to the end of the range.
+ */
+ constexpr IndexRangeCyclic push_backward(int n)
+ {
+ BLI_assert(n >= 0);
+ int64_t new_end = end_ + n;
+ int64_t cycles = cycles_;
+ if (range_end_ <= new_end) {
+ cycles += (int64_t)(n / (range_end_ - range_start_)) + (new_end < start_) - (end_ < start_);
+ }
+ return {start_, new_end, range_start_, range_end_, cycles};
+ }
+
+ /**
+ * Get the index range for the curve buffer.
+ */
+ constexpr IndexRange curve_range() const
+ {
+ return IndexRange(range_start_, total_size());
+ }
+
+ /**
+ * Range between the first element up to the end of the range.
+ */
+ constexpr IndexRange range_before_loop() const
+ {
+ return IndexRange(start_, size_before_loop());
+ }
+
+ /**
+ * Range between the first element in the iterable range up to the last element in the range.
+ */
+ constexpr IndexRange range_after_loop() const
+ {
+ return IndexRange(range_start_, size_after_loop());
+ }
+
+ /**
+ * Size of the entire iterable range.
+ */
+ constexpr int64_t total_size() const
+ {
+ return range_end_ - range_start_;
+ }
+
+ /**
+ * Number of elements between the first element in the range up to the last element in the curve.
+ */
+ constexpr int64_t size_before_loop() const
+ {
+ return range_end_ - start_;
+ }
+
+ /**
+ * Number of elements between the first element in the iterable range up to the last element in
+ * the range.
+ */
+ constexpr int64_t size_after_loop() const
+ {
+ return end_ - range_start_;
+ }
+
+ /**
+ * Get number of elements iterated by the cyclical index range.
+ */
+ constexpr int64_t size() const
+ {
+ if (cycles_ > 0) {
+ return size_before_loop() + end_ + (cycles_ - 1) * (range_end_ - range_start_);
+ }
+ else {
+ return end_ - start_;
+ }
+ }
+
+ /**
+ * Return the number of times the iterator will cycle before ending.
+ */
+ constexpr int64_t cycles() const
+ {
+ return cycles_;
+ }
+
+ constexpr int64_t first() const
+ {
+ return start_;
+ }
+
+ constexpr int64_t one_after_last() const
+ {
+ return end_;
+ }
+
+ struct CyclicIterator; /* Forward declaration */
+
+ constexpr CyclicIterator begin() const
+ {
+ return CyclicIterator(range_start_, range_end_, start_, 0);
+ }
+
+ constexpr CyclicIterator end() const
+ {
+ return CyclicIterator(range_start_, range_end_, end_, cycles_);
+ }
+
+ struct CyclicIterator {
+ int64_t index_, begin_, end_, cycles_;
+
+ constexpr CyclicIterator(int64_t range_begin, int64_t range_end, int64_t index, int64_t cycles)
+ : index_(index), begin_(range_begin), end_(range_end), cycles_(cycles)
+ {
+ BLI_assert(range_begin <= index && index <= range_end);
+ }
+
+ constexpr CyclicIterator(const CyclicIterator &copy)
+ : index_(copy.index_), begin_(copy.begin_), end_(copy.end_), cycles_(copy.cycles_)
+ {
+ }
+ ~CyclicIterator() = default;
+
+ constexpr CyclicIterator &operator=(const CyclicIterator &copy)
+ {
+ if (this == &copy) {
+ return *this;
+ }
+ index_ = copy.index_;
+ begin_ = copy.begin_;
+ end_ = copy.end_;
+ cycles_ = copy.cycles_;
+ return *this;
+ }
+ constexpr CyclicIterator &operator++()
+ {
+ index_++;
+ if (index_ == end_) {
+ index_ = begin_;
+ cycles_++;
+ }
+ return *this;
+ }
+
+ void increment(int64_t n)
+ {
+ for (int i = 0; i < n; i++) {
+ ++*this;
+ }
+ }
+
+ constexpr const int64_t &operator*() const
+ {
+ return index_;
+ }
+
+ constexpr bool operator==(const CyclicIterator &other) const
+ {
+ return index_ == other.index_ && cycles_ == other.cycles_;
+ }
+ constexpr bool operator!=(const CyclicIterator &other) const
+ {
+ return !this->operator==(other);
+ }
+ };
+};
+
+/** \} */
+
+/* --------------------------------------------------------------------
+ * Utility functions.
+ */
+
/**
* Copy the provided point attribute values between all curves in the #curve_ranges index
* ranges, assuming that all curves have the same number of control points in #src_curves
@@ -88,4 +380,40 @@ void foreach_curve_by_type(const VArray<int8_t> &types,
FunctionRef<void(IndexMask)> bezier_fn,
FunctionRef<void(IndexMask)> nurbs_fn);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #CurvePoint Inline Methods
+ * \{ */
+
+inline bool CurvePoint::is_controlpoint() const
+{
+ return parameter == 0.0 || parameter == 1.0;
+}
+
+inline bool CurvePoint::operator==(const CurvePoint &other) const
+{
+ return (parameter == other.parameter && index == other.index) ||
+ (parameter == 1.0 && other.parameter == 0.0 && next_index == other.index) ||
+ (parameter == 0.0 && other.parameter == 1.0 && index == other.next_index);
+}
+inline bool CurvePoint::operator!=(const CurvePoint &other) const
+{
+ return !this->operator==(other);
+}
+
+inline bool CurvePoint::operator<(const CurvePoint &other) const
+{
+ if (index == other.index) {
+ return parameter < other.parameter;
+ }
+ else {
+ /* Use next index for cyclic comparison due to loop segment < first segment. */
+ return next_index < other.next_index &&
+ !(next_index == other.index && parameter == 1.0 && other.parameter == 0.0);
+ }
+}
+
+/** \} */
+
} // namespace blender::bke::curves
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index 27c54a3d4a7..1e237da8119 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -14,6 +14,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_pointcloud_types.h"
+#include "BLI_array_utils.hh"
#include "BLI_color.hh"
#include "BLI_math_vec_types.hh"
#include "BLI_span.hh"
@@ -974,6 +975,37 @@ Vector<AttributeTransferData> retrieve_attributes_for_transfer(
return attributes;
}
+void copy_attribute_domain(const AttributeAccessor src_attributes,
+ MutableAttributeAccessor dst_attributes,
+ const IndexMask selection,
+ const eAttrDomain domain,
+ const Set<std::string> &skip)
+{
+ src_attributes.for_all(
+ [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData &meta_data) {
+ if (meta_data.domain != domain) {
+ return true;
+ }
+ if (id.is_named() && skip.contains(id.name())) {
+ return true;
+ }
+ if (!id.should_be_kept()) {
+ return true;
+ }
+
+ const GVArray src = src_attributes.lookup(id, meta_data.domain);
+ BLI_assert(src);
+
+ /* Copy attribute. */
+ GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
+ id, domain, meta_data.data_type);
+ array_utils::copy(src, selection, dst.span);
+ dst.finish();
+
+ return true;
+ });
+}
+
} // namespace blender::bke
/** \} */
diff --git a/source/blender/blenkernel/intern/curve_catmull_rom.cc b/source/blender/blenkernel/intern/curve_catmull_rom.cc
index 952d59edcf9..dac88948036 100644
--- a/source/blender/blenkernel/intern/curve_catmull_rom.cc
+++ b/source/blender/blenkernel/intern/curve_catmull_rom.cc
@@ -17,16 +17,14 @@ int calculate_evaluated_num(const int points_num, const bool cyclic, const int r
}
/* Adapted from Cycles #catmull_rom_basis_eval function. */
-template<typename T>
-static T calculate_basis(const T &a, const T &b, const T &c, const T &d, const float parameter)
+void calculate_basis(const float parameter, float r_weights[4])
{
const float t = parameter;
const float s = 1.0f - parameter;
- const float n0 = -t * s * s;
- const float n1 = 2.0f + t * t * (3.0f * t - 5.0f);
- const float n2 = 2.0f + s * s * (3.0f * s - 5.0f);
- const float n3 = -s * t * t;
- return 0.5f * (a * n0 + b * n1 + c * n2 + d * n3);
+ r_weights[0] = -t * s * s;
+ r_weights[1] = 2.0f + t * t * (3.0f * t - 5.0f);
+ r_weights[2] = 2.0f + s * s * (3.0f * s - 5.0f);
+ r_weights[3] = -s * t * t;
}
template<typename T>
@@ -35,7 +33,7 @@ static void evaluate_segment(const T &a, const T &b, const T &c, const T &d, Mut
const float step = 1.0f / dst.size();
dst.first() = b;
for (const int i : dst.index_range().drop_front(1)) {
- dst[i] = calculate_basis<T>(a, b, c, d, i * step);
+ dst[i] = interpolate<T>(a, b, c, d, i * step);
}
}