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:
authorHans Goudey <h.goudey@me.com>2022-02-28 18:46:34 +0300
committerHans Goudey <h.goudey@me.com>2022-02-28 18:46:34 +0300
commit9ec12c26f16ea3da1e6de95d5d5daf1057464830 (patch)
tree708e542d5d4de0efdda7b9a54def6b25b6b64039 /source/blender/blenkernel
parent81bb86c7506c0ae5f07780a63f954a8416a0d4e6 (diff)
Geometry Nodes: Begin conversion to new curves
This commit changes `CurveComponent` to store the new curve type by adding conversions to and from `CurveEval` in most nodes. This will temporarily make performance of curves in geometry nodes much worse, but as functionality is implemented for the new type and it is used in more places, performance will become better than before. We still use `CurveEval` for drawing curves, because the new `Curves` data-block has no evaluated points yet. So the `Curve` ID is still generated for rendering in the same way as before. It's also still needed for drawing curve object edit mode overlays. The old curve component isn't removed yet, because it is still used to implement the conversions to and from `CurveEval`. A few more attributes are added to make this possible: - `nurbs_weight`: The weight for each control point on NURBS curves. - `nurbs_order`: The order of the NURBS curve - `knots_mode`: Necessary for conversion, not defined yet. - `handle_type_{left/right}`: An 8 bit integer attribute. Differential Revision: https://developer.blender.org/D14145
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh73
-rw-r--r--source/blender/blenkernel/BKE_spline.hh3
-rw-r--r--source/blender/blenkernel/CMakeLists.txt1
-rw-r--r--source/blender/blenkernel/intern/curve.cc2
-rw-r--r--source/blender/blenkernel/intern/curve_eval.cc189
-rw-r--r--source/blender/blenkernel/intern/displist.cc4
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curve.cc167
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curves.cc521
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc26
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc7
10 files changed, 819 insertions, 174 deletions
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index d93b3ca95e7..f11bfb7692a 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -24,6 +24,7 @@
#include "FN_field.hh"
+struct Curves;
struct Collection;
struct Curve;
struct CurveEval;
@@ -415,7 +416,7 @@ struct GeometrySet {
* Create a new geometry set that only contains the given curve.
*/
static GeometrySet create_with_curve(
- CurveEval *curve, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ Curves *curves, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
/* Utility methods for access. */
/**
@@ -462,7 +463,7 @@ struct GeometrySet {
/**
* Returns a read-only curve or null.
*/
- const CurveEval *get_curve_for_read() const;
+ const Curves *get_curve_for_read() const;
/**
* Returns a mutable mesh or null. No ownership is transferred.
@@ -479,7 +480,7 @@ struct GeometrySet {
/**
* Returns a mutable curve or null. No ownership is transferred.
*/
- CurveEval *get_curve_for_write();
+ Curves *get_curve_for_write();
/* Utility methods for replacement. */
/**
@@ -499,7 +500,7 @@ struct GeometrySet {
/**
* Clear the existing curve and replace it with the given one.
*/
- void replace_curve(CurveEval *curve,
+ void replace_curve(Curves *curves,
GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
private:
@@ -632,17 +633,59 @@ class PointCloudComponent : public GeometryComponent {
};
/**
- * A geometry component that stores curve data, in other words, a group of splines.
- * Curves are stored differently than other geometry components, because the data structure used
- * here does not correspond exactly to the #Curve DNA data structure. A #CurveEval is stored here
- * instead, though the component does give access to a #Curve for interfacing with render engines
- * and other areas of Blender that expect to use a data-block with an #ID.
+ * Legacy runtime-only curves type.
+ * These curves are stored differently than other geometry components, because the data structure
+ * used here does not correspond exactly to the #Curve DNA data structure. A #CurveEval is stored
+ * here instead, though the component does give access to a #Curve for interfacing with render
+ * engines and other areas of Blender that expect to use a data-block with an #ID.
*/
-class CurveComponent : public GeometryComponent {
+class CurveComponentLegacy : public GeometryComponent {
private:
CurveEval *curve_ = nullptr;
GeometryOwnershipType ownership_ = GeometryOwnershipType::Owned;
+ public:
+ CurveComponentLegacy();
+ ~CurveComponentLegacy();
+ GeometryComponent *copy() const override;
+
+ void clear();
+ bool has_curve() const;
+ /**
+ * Clear the component and replace it with the new curve.
+ */
+ void replace(CurveEval *curve, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ CurveEval *release();
+
+ const CurveEval *get_for_read() const;
+ CurveEval *get_for_write();
+
+ int attribute_domain_size(AttributeDomain domain) const final;
+
+ bool is_empty() const final;
+
+ bool owns_direct_data() const override;
+ void ensure_owns_direct_data() override;
+
+ static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_CURVE;
+
+ private:
+ const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
+
+ blender::fn::GVArray attribute_try_adapt_domain_impl(const blender::fn::GVArray &varray,
+ AttributeDomain from_domain,
+ AttributeDomain to_domain) const final;
+};
+
+/**
+ * A geometry component that stores a group of curves, corresponding the the #Curves and
+ * #CurvesGeometry types.
+ */
+class CurveComponent : public GeometryComponent {
+ private:
+ Curves *curves_ = nullptr;
+ GeometryOwnershipType ownership_ = GeometryOwnershipType::Owned;
+
/**
* Curve data necessary to hold the draw cache for rendering, consistent over multiple redraws.
* This is necessary because Blender assumes that objects evaluate to an object data type, and
@@ -658,15 +701,15 @@ class CurveComponent : public GeometryComponent {
GeometryComponent *copy() const override;
void clear();
- bool has_curve() const;
+ bool has_curves() const;
/**
* Clear the component and replace it with the new curve.
*/
- void replace(CurveEval *curve, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
- CurveEval *release();
+ void replace(Curves *curve, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ Curves *release();
- const CurveEval *get_for_read() const;
- CurveEval *get_for_write();
+ const Curves *get_for_read() const;
+ Curves *get_for_write();
int attribute_domain_size(AttributeDomain domain) const final;
diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh
index 439f20ee471..42b4702ee44 100644
--- a/source/blender/blenkernel/BKE_spline.hh
+++ b/source/blender/blenkernel/BKE_spline.hh
@@ -20,6 +20,7 @@
#include "BKE_attribute_math.hh"
struct Curve;
+struct Curves;
struct ListBase;
class Spline;
@@ -691,3 +692,5 @@ struct CurveEval {
std::unique_ptr<CurveEval> curve_eval_from_dna_curve(const Curve &curve,
const ListBase &nurbs_list);
std::unique_ptr<CurveEval> curve_eval_from_dna_curve(const Curve &dna_curve);
+std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves);
+Curves *curve_eval_to_curves(const CurveEval &curve_eval);
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 2b77b2c5dae..a12a956cbf5 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -131,6 +131,7 @@ set(SRC
intern/fmodifier.c
intern/freestyle.c
intern/geometry_component_curve.cc
+ intern/geometry_component_curves.cc
intern/geometry_component_instances.cc
intern/geometry_component_mesh.cc
intern/geometry_component_pointcloud.cc
diff --git a/source/blender/blenkernel/intern/curve.cc b/source/blender/blenkernel/intern/curve.cc
index b0f58dd4ec9..6be04b79761 100644
--- a/source/blender/blenkernel/intern/curve.cc
+++ b/source/blender/blenkernel/intern/curve.cc
@@ -115,6 +115,8 @@ static void curve_free_data(ID *id)
MEM_SAFE_FREE(curve->str);
MEM_SAFE_FREE(curve->strinfo);
MEM_SAFE_FREE(curve->tb);
+
+ delete curve->curve_eval;
}
static void curve_foreach_id(ID *id, LibraryForeachIDData *data)
diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc
index 8529e7ad194..78dafe34b4f 100644
--- a/source/blender/blenkernel/intern/curve_eval.cc
+++ b/source/blender/blenkernel/intern/curve_eval.cc
@@ -13,6 +13,8 @@
#include "BKE_anonymous_attribute.hh"
#include "BKE_curve.h"
+#include "BKE_curves.hh"
+#include "BKE_geometry_set.hh"
#include "BKE_spline.hh"
using blender::Array;
@@ -23,8 +25,15 @@ using blender::Map;
using blender::MutableSpan;
using blender::Span;
using blender::StringRefNull;
+using blender::VArray;
+using blender::VArray_Span;
using blender::Vector;
using blender::bke::AttributeIDRef;
+using blender::bke::OutputAttribute;
+using blender::bke::OutputAttribute_Typed;
+using blender::bke::ReadAttributeLookup;
+using blender::fn::GVArray;
+using blender::fn::GVArray_GSpan;
blender::Span<SplinePtr> CurveEval::splines() const
{
@@ -336,6 +345,186 @@ std::unique_ptr<CurveEval> curve_eval_from_dna_curve(const Curve &dna_curve)
return curve_eval_from_dna_curve(dna_curve, *BKE_curve_nurbs_get_for_read(&dna_curve));
}
+static void copy_attributes_between_components(const GeometryComponent &src_component,
+ GeometryComponent &dst_component,
+ Span<std::string> skip)
+{
+ src_component.attribute_foreach(
+ [&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ if (id.is_named() && skip.contains(id.name())) {
+ return true;
+ }
+
+ GVArray src_attribute = src_component.attribute_try_get_for_read(
+ id, meta_data.domain, meta_data.data_type);
+ if (!src_attribute) {
+ return true;
+ }
+ GVArray_GSpan src_attribute_data{src_attribute};
+
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ id, meta_data.domain, meta_data.data_type);
+ if (!dst_attribute) {
+ return true;
+ }
+ dst_attribute.varray().set_all(src_attribute_data.data());
+ dst_attribute.save();
+ return true;
+ });
+}
+
+std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves)
+{
+ CurveComponent src_component;
+ src_component.replace(&const_cast<Curves &>(curves), GeometryOwnershipType::ReadOnly);
+ const blender::bke::CurvesGeometry &geometry = blender::bke::CurvesGeometry::wrap(
+ curves.geometry);
+
+ VArray_Span<float> nurbs_weights{
+ src_component.attribute_get_for_read<float>("nurbs_weight", ATTR_DOMAIN_POINT, 0.0f)};
+ VArray_Span<int> nurbs_orders{
+ src_component.attribute_get_for_read<int>("nurbs_order", ATTR_DOMAIN_CURVE, 4)};
+ VArray_Span<int8_t> nurbs_knots_modes{
+ src_component.attribute_get_for_read<int8_t>("knots_mode", ATTR_DOMAIN_CURVE, 0)};
+
+ VArray_Span<int8_t> handle_types_right{
+ src_component.attribute_get_for_read<int8_t>("handle_type_right", ATTR_DOMAIN_POINT, 0)};
+ VArray_Span<int8_t> handle_types_left{
+ src_component.attribute_get_for_read<int8_t>("handle_type_left", ATTR_DOMAIN_POINT, 0)};
+
+ /* Create splines with the correct size and type. */
+ VArray<int8_t> curve_types = geometry.curve_types();
+ std::unique_ptr<CurveEval> curve_eval = std::make_unique<CurveEval>();
+ for (const int curve_index : curve_types.index_range()) {
+ const IndexRange point_range = geometry.range_for_curve(curve_index);
+
+ std::unique_ptr<Spline> spline;
+ switch (curve_types[curve_index]) {
+ case CURVE_TYPE_POLY: {
+ spline = std::make_unique<PolySpline>();
+ spline->resize(point_range.size());
+ break;
+ }
+ case CURVE_TYPE_BEZIER: {
+ std::unique_ptr<BezierSpline> bezier_spline = std::make_unique<BezierSpline>();
+ bezier_spline->resize(point_range.size());
+ bezier_spline->handle_types_left().copy_from(handle_types_left.slice(point_range));
+ bezier_spline->handle_types_right().copy_from(handle_types_right.slice(point_range));
+
+ spline = std::move(bezier_spline);
+ break;
+ }
+ case CURVE_TYPE_NURBS: {
+ std::unique_ptr<NURBSpline> nurb_spline = std::make_unique<NURBSpline>();
+ nurb_spline->resize(point_range.size());
+ nurb_spline->weights().copy_from(nurbs_weights.slice(point_range));
+ nurb_spline->set_order(nurbs_orders[curve_index]);
+ nurb_spline->knots_mode = static_cast<NURBSpline::KnotsMode>(
+ nurbs_knots_modes[curve_index]);
+
+ spline = std::move(nurb_spline);
+ break;
+ }
+ case CURVE_TYPE_CATMULL_ROM:
+ /* Not supported yet. */
+ BLI_assert_unreachable();
+ continue;
+ }
+ spline->positions().fill(float3(0));
+ spline->tilts().fill(0.0f);
+ spline->radii().fill(0.0f);
+ curve_eval->add_spline(std::move(spline));
+ }
+
+ CurveComponentLegacy dst_component;
+ dst_component.replace(curve_eval.get(), GeometryOwnershipType::Editable);
+
+ copy_attributes_between_components(src_component,
+ dst_component,
+ {"curve_type",
+ "nurbs_weight",
+ "nurbs_order",
+ "knots_mode",
+ "handle_type_right",
+ "handle_type_left"});
+
+ return curve_eval;
+}
+
+Curves *curve_eval_to_curves(const CurveEval &curve_eval)
+{
+ Curves *curves = blender::bke::curves_new_nomain(curve_eval.total_control_point_size(),
+ curve_eval.splines().size());
+ CurveComponent dst_component;
+ dst_component.replace(curves, GeometryOwnershipType::Editable);
+
+ blender::bke::CurvesGeometry &geometry = blender::bke::CurvesGeometry::wrap(curves->geometry);
+ geometry.offsets().copy_from(curve_eval.control_point_offsets());
+ MutableSpan<int8_t> curve_types = geometry.curve_types();
+
+ OutputAttribute_Typed<float> nurbs_weight;
+ OutputAttribute_Typed<int> nurbs_order;
+ OutputAttribute_Typed<int8_t> nurbs_knots_mode;
+ if (curve_eval.has_spline_with_type(CURVE_TYPE_NURBS)) {
+ nurbs_weight = dst_component.attribute_try_get_for_output_only<float>("nurbs_weight",
+ ATTR_DOMAIN_POINT);
+ nurbs_order = dst_component.attribute_try_get_for_output_only<int>("nurbs_order",
+ ATTR_DOMAIN_CURVE);
+ nurbs_knots_mode = dst_component.attribute_try_get_for_output_only<int8_t>("knots_mode",
+ ATTR_DOMAIN_CURVE);
+ }
+ OutputAttribute_Typed<int8_t> handle_type_right;
+ OutputAttribute_Typed<int8_t> handle_type_left;
+ if (curve_eval.has_spline_with_type(CURVE_TYPE_BEZIER)) {
+ handle_type_right = dst_component.attribute_try_get_for_output_only<int8_t>(
+ "handle_type_right", ATTR_DOMAIN_POINT);
+ handle_type_left = dst_component.attribute_try_get_for_output_only<int8_t>("handle_type_left",
+ ATTR_DOMAIN_POINT);
+ }
+
+ for (const int curve_index : curve_eval.splines().index_range()) {
+ const Spline &spline = *curve_eval.splines()[curve_index];
+ curve_types[curve_index] = curve_eval.splines()[curve_index]->type();
+
+ const IndexRange point_range = geometry.range_for_curve(curve_index);
+
+ switch (spline.type()) {
+ case CURVE_TYPE_POLY:
+ break;
+ case CURVE_TYPE_BEZIER: {
+ const BezierSpline &src = static_cast<const BezierSpline &>(spline);
+ handle_type_right.as_span().slice(point_range).copy_from(src.handle_types_right());
+ handle_type_left.as_span().slice(point_range).copy_from(src.handle_types_left());
+ break;
+ }
+ case CURVE_TYPE_NURBS: {
+ const NURBSpline &src = static_cast<const NURBSpline &>(spline);
+ nurbs_knots_mode.as_span()[curve_index] = static_cast<int8_t>(src.knots_mode);
+ nurbs_order.as_span()[curve_index] = src.order();
+ nurbs_weight.as_span().slice(point_range).copy_from(src.weights());
+ break;
+ }
+ case CURVE_TYPE_CATMULL_ROM: {
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+ }
+
+ nurbs_weight.save();
+ nurbs_order.save();
+ nurbs_knots_mode.save();
+ handle_type_right.save();
+ handle_type_left.save();
+
+ CurveComponentLegacy src_component;
+ src_component.replace(&const_cast<CurveEval &>(curve_eval), GeometryOwnershipType::ReadOnly);
+
+ copy_attributes_between_components(src_component, dst_component, {});
+
+ return curves;
+}
+
void CurveEval::assert_valid_point_attributes() const
{
#ifdef DEBUG
diff --git a/source/blender/blenkernel/intern/displist.cc b/source/blender/blenkernel/intern/displist.cc
index 5c761e94bb9..97445851ffa 100644
--- a/source/blender/blenkernel/intern/displist.cc
+++ b/source/blender/blenkernel/intern/displist.cc
@@ -865,7 +865,7 @@ static GeometrySet curve_calc_modifiers_post(Depsgraph *depsgraph,
else {
std::unique_ptr<CurveEval> curve_eval = curve_eval_from_dna_curve(
*cu, ob->runtime.curve_cache->deformed_nurbs);
- geometry_set.replace_curve(curve_eval.release());
+ geometry_set.replace_curve(curve_eval_to_curves(*curve_eval));
}
for (; md; md = md->next) {
@@ -1497,7 +1497,7 @@ void BKE_displist_make_curveTypes(Depsgraph *depsgraph,
* the CurveEval data type was introduced, when an evaluated object's curve data was just a
* copy of the original curve and everything else ended up in #CurveCache. */
CurveComponent &curve_component = geometry.get_component_for_write<CurveComponent>();
- cow_curve.curve_eval = curve_component.get_for_write();
+ cow_curve.curve_eval = curves_to_curve_eval(*curve_component.get_for_read()).release();
BKE_object_eval_assign_data(ob, &cow_curve.id, false);
}
diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc
index c22b6ff07ec..0926d65b306 100644
--- a/source/blender/blenkernel/intern/geometry_component_curve.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curve.cc
@@ -23,18 +23,18 @@ using blender::fn::GVArray_GSpan;
/** \name Geometry Component Implementation
* \{ */
-CurveComponent::CurveComponent() : GeometryComponent(GEO_COMPONENT_TYPE_CURVE)
+CurveComponentLegacy::CurveComponentLegacy() : GeometryComponent(GEO_COMPONENT_TYPE_CURVE)
{
}
-CurveComponent::~CurveComponent()
+CurveComponentLegacy::~CurveComponentLegacy()
{
this->clear();
}
-GeometryComponent *CurveComponent::copy() const
+GeometryComponent *CurveComponentLegacy::copy() const
{
- CurveComponent *new_component = new CurveComponent();
+ CurveComponentLegacy *new_component = new CurveComponentLegacy();
if (curve_ != nullptr) {
new_component->curve_ = new CurveEval(*curve_);
new_component->ownership_ = GeometryOwnershipType::Owned;
@@ -42,30 +42,23 @@ GeometryComponent *CurveComponent::copy() const
return new_component;
}
-void CurveComponent::clear()
+void CurveComponentLegacy::clear()
{
BLI_assert(this->is_mutable());
if (curve_ != nullptr) {
if (ownership_ == GeometryOwnershipType::Owned) {
delete curve_;
}
- if (curve_for_render_ != nullptr) {
- /* The curve created by this component should not have any edit mode data. */
- BLI_assert(curve_for_render_->editfont == nullptr && curve_for_render_->editnurb == nullptr);
- BKE_id_free(nullptr, curve_for_render_);
- curve_for_render_ = nullptr;
- }
-
curve_ = nullptr;
}
}
-bool CurveComponent::has_curve() const
+bool CurveComponentLegacy::has_curve() const
{
return curve_ != nullptr;
}
-void CurveComponent::replace(CurveEval *curve, GeometryOwnershipType ownership)
+void CurveComponentLegacy::replace(CurveEval *curve, GeometryOwnershipType ownership)
{
BLI_assert(this->is_mutable());
this->clear();
@@ -73,7 +66,7 @@ void CurveComponent::replace(CurveEval *curve, GeometryOwnershipType ownership)
ownership_ = ownership;
}
-CurveEval *CurveComponent::release()
+CurveEval *CurveComponentLegacy::release()
{
BLI_assert(this->is_mutable());
CurveEval *curve = curve_;
@@ -81,12 +74,12 @@ CurveEval *CurveComponent::release()
return curve;
}
-const CurveEval *CurveComponent::get_for_read() const
+const CurveEval *CurveComponentLegacy::get_for_read() const
{
return curve_;
}
-CurveEval *CurveComponent::get_for_write()
+CurveEval *CurveComponentLegacy::get_for_write()
{
BLI_assert(this->is_mutable());
if (ownership_ == GeometryOwnershipType::ReadOnly) {
@@ -96,17 +89,17 @@ CurveEval *CurveComponent::get_for_write()
return curve_;
}
-bool CurveComponent::is_empty() const
+bool CurveComponentLegacy::is_empty() const
{
return curve_ == nullptr;
}
-bool CurveComponent::owns_direct_data() const
+bool CurveComponentLegacy::owns_direct_data() const
{
return ownership_ == GeometryOwnershipType::Owned;
}
-void CurveComponent::ensure_owns_direct_data()
+void CurveComponentLegacy::ensure_owns_direct_data()
{
BLI_assert(this->is_mutable());
if (ownership_ != GeometryOwnershipType::Owned) {
@@ -115,32 +108,13 @@ void CurveComponent::ensure_owns_direct_data()
}
}
-const Curve *CurveComponent::get_curve_for_render() const
-{
- if (curve_ == nullptr) {
- return nullptr;
- }
- if (curve_for_render_ != nullptr) {
- return curve_for_render_;
- }
- std::lock_guard lock{curve_for_render_mutex_};
- if (curve_for_render_ != nullptr) {
- return curve_for_render_;
- }
-
- curve_for_render_ = (Curve *)BKE_id_new_nomain(ID_CU_LEGACY, nullptr);
- curve_for_render_->curve_eval = curve_;
-
- return curve_for_render_;
-}
-
/** \} */
/* -------------------------------------------------------------------- */
/** \name Attribute Access Helper Functions
* \{ */
-int CurveComponent::attribute_domain_size(const AttributeDomain domain) const
+int CurveComponentLegacy::attribute_domain_size(const AttributeDomain domain) const
{
if (curve_ == nullptr) {
return 0;
@@ -334,9 +308,10 @@ static GVArray adapt_curve_domain_spline_to_point(const CurveEval &curve, GVArra
} // namespace blender::bke
-GVArray CurveComponent::attribute_try_adapt_domain_impl(const GVArray &varray,
- const AttributeDomain from_domain,
- const AttributeDomain to_domain) const
+GVArray CurveComponentLegacy::attribute_try_adapt_domain_impl(
+ const GVArray &varray,
+ const AttributeDomain from_domain,
+ const AttributeDomain to_domain) const
{
if (!varray) {
return {};
@@ -361,14 +336,15 @@ GVArray CurveComponent::attribute_try_adapt_domain_impl(const GVArray &varray,
static CurveEval *get_curve_from_component_for_write(GeometryComponent &component)
{
BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE);
- CurveComponent &curve_component = static_cast<CurveComponent &>(component);
+ CurveComponentLegacy &curve_component = static_cast<CurveComponentLegacy &>(component);
return curve_component.get_for_write();
}
static const CurveEval *get_curve_from_component_for_read(const GeometryComponent &component)
{
BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE);
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ const CurveComponentLegacy &curve_component = static_cast<const CurveComponentLegacy &>(
+ component);
return curve_component.get_for_read();
}
@@ -377,101 +353,6 @@ static const CurveEval *get_curve_from_component_for_read(const GeometryComponen
namespace blender::bke {
/* -------------------------------------------------------------------- */
-/** \name Curve Normals Access
- * \{ */
-
-static void calculate_bezier_normals(const BezierSpline &spline, MutableSpan<float3> normals)
-{
- Span<int> offsets = spline.control_point_offsets();
- Span<float3> evaluated_normals = spline.evaluated_normals();
- for (const int i : IndexRange(spline.size())) {
- normals[i] = evaluated_normals[offsets[i]];
- }
-}
-
-static void calculate_poly_normals(const PolySpline &spline, MutableSpan<float3> normals)
-{
- normals.copy_from(spline.evaluated_normals());
-}
-
-/**
- * Because NURBS control points are not necessarily on the path, the normal at the control points
- * is not well defined, so create a temporary poly spline to find the normals. This requires extra
- * copying currently, but may be more efficient in the future if attributes have some form of CoW.
- */
-static void calculate_nurbs_normals(const NURBSpline &spline, MutableSpan<float3> normals)
-{
- PolySpline poly_spline;
- poly_spline.resize(spline.size());
- poly_spline.positions().copy_from(spline.positions());
- poly_spline.tilts().copy_from(spline.tilts());
- normals.copy_from(poly_spline.evaluated_normals());
-}
-
-static Array<float3> curve_normal_point_domain(const CurveEval &curve)
-{
- Span<SplinePtr> splines = curve.splines();
- Array<int> offsets = curve.control_point_offsets();
- const int total_size = offsets.last();
- Array<float3> normals(total_size);
-
- threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
- for (const int i : range) {
- const Spline &spline = *splines[i];
- MutableSpan spline_normals{normals.as_mutable_span().slice(offsets[i], spline.size())};
- switch (splines[i]->type()) {
- case CURVE_TYPE_BEZIER:
- calculate_bezier_normals(static_cast<const BezierSpline &>(spline), spline_normals);
- break;
- case CURVE_TYPE_POLY:
- calculate_poly_normals(static_cast<const PolySpline &>(spline), spline_normals);
- break;
- case CURVE_TYPE_NURBS:
- calculate_nurbs_normals(static_cast<const NURBSpline &>(spline), spline_normals);
- break;
- case CURVE_TYPE_CATMULL_ROM:
- BLI_assert_unreachable();
- break;
- }
- }
- });
- return normals;
-}
-
-VArray<float3> curve_normals_varray(const CurveComponent &component, const AttributeDomain domain)
-{
- const CurveEval *curve = component.get_for_read();
- if (curve == nullptr) {
- return nullptr;
- }
-
- if (domain == ATTR_DOMAIN_POINT) {
- const Span<SplinePtr> splines = curve->splines();
-
- /* Use a reference to evaluated normals if possible to avoid an allocation and a copy.
- * This is only possible when there is only one poly spline. */
- if (splines.size() == 1 && splines.first()->type() == CURVE_TYPE_POLY) {
- const PolySpline &spline = static_cast<PolySpline &>(*splines.first());
- return VArray<float3>::ForSpan(spline.evaluated_normals());
- }
-
- Array<float3> normals = curve_normal_point_domain(*curve);
- return VArray<float3>::ForContainer(std::move(normals));
- }
-
- if (domain == ATTR_DOMAIN_CURVE) {
- Array<float3> point_normals = curve_normal_point_domain(*curve);
- VArray<float3> varray = VArray<float3>::ForContainer(std::move(point_normals));
- return component.attribute_try_adapt_domain<float3>(
- std::move(varray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
- }
-
- return nullptr;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Builtin Spline Attributes
*
* Attributes with a value for every spline, stored contiguously or in every spline separately.
@@ -1306,7 +1187,8 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
private:
static constexpr uint64_t supported_types_mask = CD_MASK_PROP_FLOAT | CD_MASK_PROP_FLOAT2 |
CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 |
- CD_MASK_PROP_COLOR | CD_MASK_PROP_BOOL;
+ CD_MASK_PROP_COLOR | CD_MASK_PROP_BOOL |
+ CD_MASK_PROP_INT8;
public:
ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
@@ -1551,7 +1433,8 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
} // namespace blender::bke
-const blender::bke::ComponentAttributeProviders *CurveComponent::get_attribute_providers() const
+const blender::bke::ComponentAttributeProviders *CurveComponentLegacy::get_attribute_providers()
+ const
{
static blender::bke::ComponentAttributeProviders providers =
blender::bke::create_attribute_providers_for_curve();
diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc
new file mode 100644
index 00000000000..e32dd852e0e
--- /dev/null
+++ b/source/blender/blenkernel/intern/geometry_component_curves.cc
@@ -0,0 +1,521 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BLI_task.hh"
+
+#include "DNA_ID_enums.h"
+#include "DNA_curve_types.h"
+
+#include "BKE_attribute_access.hh"
+#include "BKE_attribute_math.hh"
+#include "BKE_curve.h"
+#include "BKE_curves.hh"
+#include "BKE_geometry_set.hh"
+#include "BKE_lib_id.h"
+#include "BKE_spline.hh"
+
+#include "attribute_access_intern.hh"
+
+using blender::fn::GVArray;
+
+/* -------------------------------------------------------------------- */
+/** \name Geometry Component Implementation
+ * \{ */
+
+CurveComponent::CurveComponent() : GeometryComponent(GEO_COMPONENT_TYPE_CURVE)
+{
+}
+
+CurveComponent::~CurveComponent()
+{
+ this->clear();
+}
+
+GeometryComponent *CurveComponent::copy() const
+{
+ CurveComponent *new_component = new CurveComponent();
+ if (curves_ != nullptr) {
+ new_component->curves_ = BKE_curves_copy_for_eval(curves_, false);
+ new_component->ownership_ = GeometryOwnershipType::Owned;
+ }
+ return new_component;
+}
+
+void CurveComponent::clear()
+{
+ BLI_assert(this->is_mutable());
+ if (curves_ != nullptr) {
+ if (ownership_ == GeometryOwnershipType::Owned) {
+ BKE_id_free(nullptr, curves_);
+ }
+ if (curve_for_render_ != nullptr) {
+ /* The curve created by this component should not have any edit mode data. */
+ BLI_assert(curve_for_render_->editfont == nullptr && curve_for_render_->editnurb == nullptr);
+ BKE_id_free(nullptr, curve_for_render_);
+ curve_for_render_ = nullptr;
+ }
+
+ curves_ = nullptr;
+ }
+}
+
+bool CurveComponent::has_curves() const
+{
+ return curves_ != nullptr;
+}
+
+void CurveComponent::replace(Curves *curves, GeometryOwnershipType ownership)
+{
+ BLI_assert(this->is_mutable());
+ this->clear();
+ curves_ = curves;
+ ownership_ = ownership;
+}
+
+Curves *CurveComponent::release()
+{
+ BLI_assert(this->is_mutable());
+ Curves *curves = curves_;
+ curves_ = nullptr;
+ return curves;
+}
+
+const Curves *CurveComponent::get_for_read() const
+{
+ return curves_;
+}
+
+Curves *CurveComponent::get_for_write()
+{
+ BLI_assert(this->is_mutable());
+ if (ownership_ == GeometryOwnershipType::ReadOnly) {
+ curves_ = BKE_curves_copy_for_eval(curves_, false);
+ ownership_ = GeometryOwnershipType::Owned;
+ }
+ return curves_;
+}
+
+bool CurveComponent::is_empty() const
+{
+ return curves_ == nullptr;
+}
+
+bool CurveComponent::owns_direct_data() const
+{
+ return ownership_ == GeometryOwnershipType::Owned;
+}
+
+void CurveComponent::ensure_owns_direct_data()
+{
+ BLI_assert(this->is_mutable());
+ if (ownership_ != GeometryOwnershipType::Owned) {
+ curves_ = BKE_curves_copy_for_eval(curves_, false);
+ ownership_ = GeometryOwnershipType::Owned;
+ }
+}
+
+const Curve *CurveComponent::get_curve_for_render() const
+{
+ if (curves_ == nullptr) {
+ return nullptr;
+ }
+ if (curve_for_render_ != nullptr) {
+ return curve_for_render_;
+ }
+ std::lock_guard lock{curve_for_render_mutex_};
+ if (curve_for_render_ != nullptr) {
+ return curve_for_render_;
+ }
+
+ curve_for_render_ = (Curve *)BKE_id_new_nomain(ID_CU_LEGACY, nullptr);
+ curve_for_render_->curve_eval = curves_to_curve_eval(*curves_).release();
+
+ return curve_for_render_;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Curve Normals Access
+ * \{ */
+
+namespace blender::bke {
+
+static void calculate_bezier_normals(const BezierSpline &spline, MutableSpan<float3> normals)
+{
+ Span<int> offsets = spline.control_point_offsets();
+ Span<float3> evaluated_normals = spline.evaluated_normals();
+ for (const int i : IndexRange(spline.size())) {
+ normals[i] = evaluated_normals[offsets[i]];
+ }
+}
+
+static void calculate_poly_normals(const PolySpline &spline, MutableSpan<float3> normals)
+{
+ normals.copy_from(spline.evaluated_normals());
+}
+
+/**
+ * Because NURBS control points are not necessarily on the path, the normal at the control points
+ * is not well defined, so create a temporary poly spline to find the normals. This requires extra
+ * copying currently, but may be more efficient in the future if attributes have some form of CoW.
+ */
+static void calculate_nurbs_normals(const NURBSpline &spline, MutableSpan<float3> normals)
+{
+ PolySpline poly_spline;
+ poly_spline.resize(spline.size());
+ poly_spline.positions().copy_from(spline.positions());
+ poly_spline.tilts().copy_from(spline.tilts());
+ normals.copy_from(poly_spline.evaluated_normals());
+}
+
+static Array<float3> curve_normal_point_domain(const CurveEval &curve)
+{
+ Span<SplinePtr> splines = curve.splines();
+ Array<int> offsets = curve.control_point_offsets();
+ const int total_size = offsets.last();
+ Array<float3> normals(total_size);
+
+ threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
+ for (const int i : range) {
+ const Spline &spline = *splines[i];
+ MutableSpan spline_normals{normals.as_mutable_span().slice(offsets[i], spline.size())};
+ switch (splines[i]->type()) {
+ case CURVE_TYPE_BEZIER:
+ calculate_bezier_normals(static_cast<const BezierSpline &>(spline), spline_normals);
+ break;
+ case CURVE_TYPE_POLY:
+ calculate_poly_normals(static_cast<const PolySpline &>(spline), spline_normals);
+ break;
+ case CURVE_TYPE_NURBS:
+ calculate_nurbs_normals(static_cast<const NURBSpline &>(spline), spline_normals);
+ break;
+ case CURVE_TYPE_CATMULL_ROM:
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+ });
+ return normals;
+}
+
+VArray<float3> curve_normals_varray(const CurveComponent &component, const AttributeDomain domain)
+{
+ if (component.is_empty()) {
+ return nullptr;
+ }
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_read());
+
+ if (domain == ATTR_DOMAIN_POINT) {
+ Array<float3> normals = curve_normal_point_domain(*curve);
+ return VArray<float3>::ForContainer(std::move(normals));
+ }
+
+ if (domain == ATTR_DOMAIN_CURVE) {
+ Array<float3> point_normals = curve_normal_point_domain(*curve);
+ VArray<float3> varray = VArray<float3>::ForContainer(std::move(point_normals));
+ return component.attribute_try_adapt_domain<float3>(
+ std::move(varray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
+ }
+
+ return nullptr;
+}
+
+} // namespace blender::bke
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Attribute Access Helper Functions
+ * \{ */
+
+int CurveComponent::attribute_domain_size(const AttributeDomain domain) const
+{
+ if (curves_ == nullptr) {
+ return 0;
+ }
+ const blender::bke::CurvesGeometry &geometry = blender::bke::CurvesGeometry::wrap(
+ curves_->geometry);
+ if (domain == ATTR_DOMAIN_POINT) {
+ return geometry.points_size();
+ }
+ if (domain == ATTR_DOMAIN_CURVE) {
+ return geometry.curves_size();
+ }
+ return 0;
+}
+
+GVArray CurveComponent::attribute_try_adapt_domain_impl(const GVArray &varray,
+ const AttributeDomain from_domain,
+ const AttributeDomain to_domain) const
+{
+ return blender::bke::CurvesGeometry::wrap(curves_->geometry)
+ .adapt_domain(varray, from_domain, to_domain);
+}
+
+static Curves *get_curves_from_component_for_write(GeometryComponent &component)
+{
+ BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE);
+ CurveComponent &curve_component = static_cast<CurveComponent &>(component);
+ return curve_component.get_for_write();
+}
+
+static const Curves *get_curves_from_component_for_read(const GeometryComponent &component)
+{
+ BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE);
+ const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
+ return curve_component.get_for_read();
+}
+
+static void tag_component_topology_changed(GeometryComponent &component)
+{
+ Curves *curves = get_curves_from_component_for_write(component);
+ if (curves) {
+ blender::bke::CurvesGeometry::wrap(curves->geometry).tag_topology_changed();
+ }
+}
+
+static void tag_component_positions_changed(GeometryComponent &component)
+{
+ Curves *curves = get_curves_from_component_for_write(component);
+ if (curves) {
+ blender::bke::CurvesGeometry::wrap(curves->geometry).tag_positions_changed();
+ }
+}
+
+static void tag_component_normals_changed(GeometryComponent &component)
+{
+ Curves *curves = get_curves_from_component_for_write(component);
+ if (curves) {
+ blender::bke::CurvesGeometry::wrap(curves->geometry).tag_normals_changed();
+ }
+}
+
+/** \} */
+
+namespace blender::bke {
+
+/* -------------------------------------------------------------------- */
+/** \name Attribute Provider Declaration
+ * \{ */
+
+/**
+ * In this function all the attribute providers for a curves component are created.
+ * Most data in this function is statically allocated, because it does not change over time.
+ */
+static ComponentAttributeProviders create_attribute_providers_for_curve()
+{
+ static CustomDataAccessInfo curve_access = {
+ [](GeometryComponent &component) -> CustomData * {
+ Curves *curves = get_curves_from_component_for_write(component);
+ return curves ? &curves->geometry.curve_data : nullptr;
+ },
+ [](const GeometryComponent &component) -> const CustomData * {
+ const Curves *curves = get_curves_from_component_for_read(component);
+ return curves ? &curves->geometry.curve_data : nullptr;
+ },
+ [](GeometryComponent &component) {
+ Curves *curves = get_curves_from_component_for_write(component);
+ if (curves) {
+ blender::bke::CurvesGeometry::wrap(curves->geometry).update_customdata_pointers();
+ }
+ }};
+ static CustomDataAccessInfo point_access = {
+ [](GeometryComponent &component) -> CustomData * {
+ Curves *curves = get_curves_from_component_for_write(component);
+ return curves ? &curves->geometry.point_data : nullptr;
+ },
+ [](const GeometryComponent &component) -> const CustomData * {
+ const Curves *curves = get_curves_from_component_for_read(component);
+ return curves ? &curves->geometry.point_data : nullptr;
+ },
+ [](GeometryComponent &component) {
+ Curves *curves = get_curves_from_component_for_write(component);
+ if (curves) {
+ blender::bke::CurvesGeometry::wrap(curves->geometry).update_customdata_pointers();
+ }
+ }};
+
+ static BuiltinCustomDataLayerProvider position("position",
+ ATTR_DOMAIN_POINT,
+ CD_PROP_FLOAT3,
+ CD_PROP_FLOAT3,
+ BuiltinAttributeProvider::NonCreatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::NonDeletable,
+ point_access,
+ make_array_read_attribute<float3>,
+ make_array_write_attribute<float3>,
+ tag_component_positions_changed);
+
+ static BuiltinCustomDataLayerProvider radius("radius",
+ ATTR_DOMAIN_POINT,
+ CD_PROP_FLOAT,
+ CD_PROP_FLOAT,
+ BuiltinAttributeProvider::Creatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::Deletable,
+ point_access,
+ make_array_read_attribute<float>,
+ make_array_write_attribute<float>,
+ tag_component_normals_changed);
+
+ static BuiltinCustomDataLayerProvider id("id",
+ ATTR_DOMAIN_POINT,
+ CD_PROP_INT32,
+ CD_PROP_INT32,
+ BuiltinAttributeProvider::Creatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::Deletable,
+ point_access,
+ make_array_read_attribute<int>,
+ make_array_write_attribute<int>,
+ nullptr);
+
+ static BuiltinCustomDataLayerProvider tilt("tilt",
+ ATTR_DOMAIN_POINT,
+ CD_PROP_FLOAT,
+ CD_PROP_FLOAT,
+ BuiltinAttributeProvider::Creatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::Deletable,
+ point_access,
+ make_array_read_attribute<float>,
+ make_array_write_attribute<float>,
+ tag_component_normals_changed);
+
+ static BuiltinCustomDataLayerProvider handle_right("handle_right",
+ ATTR_DOMAIN_POINT,
+ CD_PROP_FLOAT3,
+ CD_PROP_FLOAT3,
+ BuiltinAttributeProvider::Creatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::Deletable,
+ point_access,
+ make_array_read_attribute<float3>,
+ make_array_write_attribute<float3>,
+ tag_component_positions_changed);
+
+ static BuiltinCustomDataLayerProvider handle_left("handle_left",
+ ATTR_DOMAIN_POINT,
+ CD_PROP_FLOAT3,
+ CD_PROP_FLOAT3,
+ BuiltinAttributeProvider::Creatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::Deletable,
+ point_access,
+ make_array_read_attribute<float3>,
+ make_array_write_attribute<float3>,
+ tag_component_positions_changed);
+
+ static BuiltinCustomDataLayerProvider handle_type_right("handle_type_right",
+ ATTR_DOMAIN_POINT,
+ CD_PROP_INT8,
+ CD_PROP_INT8,
+ BuiltinAttributeProvider::Creatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::Deletable,
+ point_access,
+ make_array_read_attribute<int8_t>,
+ make_array_write_attribute<int8_t>,
+ tag_component_topology_changed);
+
+ static BuiltinCustomDataLayerProvider handle_type_left("handle_type_left",
+ ATTR_DOMAIN_POINT,
+ CD_PROP_INT8,
+ CD_PROP_INT8,
+ BuiltinAttributeProvider::Creatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::Deletable,
+ point_access,
+ make_array_read_attribute<int8_t>,
+ make_array_write_attribute<int8_t>,
+ tag_component_topology_changed);
+
+ static BuiltinCustomDataLayerProvider nurbs_weight("nurbs_weight",
+ ATTR_DOMAIN_POINT,
+ CD_PROP_FLOAT,
+ CD_PROP_FLOAT,
+ BuiltinAttributeProvider::Creatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::Deletable,
+ point_access,
+ make_array_read_attribute<float>,
+ make_array_write_attribute<float>,
+ tag_component_positions_changed);
+
+ static BuiltinCustomDataLayerProvider nurbs_order("nurbs_order",
+ ATTR_DOMAIN_CURVE,
+ CD_PROP_INT32,
+ CD_PROP_INT32,
+ BuiltinAttributeProvider::Creatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::Deletable,
+ curve_access,
+ make_array_read_attribute<int>,
+ make_array_write_attribute<int>,
+ tag_component_topology_changed);
+
+ static BuiltinCustomDataLayerProvider nurbs_knots_mode("knots_mode",
+ ATTR_DOMAIN_CURVE,
+ CD_PROP_INT8,
+ CD_PROP_INT8,
+ BuiltinAttributeProvider::Creatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::Deletable,
+ curve_access,
+ make_array_read_attribute<int8_t>,
+ make_array_write_attribute<int8_t>,
+ tag_component_topology_changed);
+
+ static BuiltinCustomDataLayerProvider resolution("resolution",
+ ATTR_DOMAIN_CURVE,
+ CD_PROP_INT32,
+ CD_PROP_INT32,
+ BuiltinAttributeProvider::Creatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::Deletable,
+ curve_access,
+ make_array_read_attribute<int>,
+ make_array_write_attribute<int>,
+ tag_component_positions_changed);
+
+ static BuiltinCustomDataLayerProvider cyclic("cyclic",
+ ATTR_DOMAIN_CURVE,
+ CD_PROP_BOOL,
+ CD_PROP_BOOL,
+ BuiltinAttributeProvider::Creatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::Deletable,
+ curve_access,
+ make_array_read_attribute<bool>,
+ make_array_write_attribute<bool>,
+ tag_component_topology_changed);
+
+ static CustomDataAttributeProvider curve_custom_data(ATTR_DOMAIN_CURVE, curve_access);
+ static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access);
+
+ return ComponentAttributeProviders({&position,
+ &radius,
+ &id,
+ &tilt,
+ &handle_right,
+ &handle_left,
+ &handle_type_right,
+ &handle_type_left,
+ &nurbs_order,
+ &nurbs_weight,
+ &resolution,
+ &cyclic},
+ {&curve_custom_data, &point_custom_data});
+}
+
+/** \} */
+
+} // namespace blender::bke
+
+const blender::bke::ComponentAttributeProviders *CurveComponent::get_attribute_providers() const
+{
+ static blender::bke::ComponentAttributeProviders providers =
+ blender::bke::create_attribute_providers_for_curve();
+ return &providers;
+}
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index 13441b4914a..73572e30d61 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -7,6 +7,7 @@
#include "BKE_attribute.h"
#include "BKE_attribute_access.hh"
+#include "BKE_curves.hh"
#include "BKE_geometry_set.hh"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
@@ -186,8 +187,9 @@ bool GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_ma
if (volume != nullptr) {
have_minmax |= BKE_volume_min_max(volume, *r_min, *r_max);
}
- const CurveEval *curve = this->get_curve_for_read();
- if (curve != nullptr) {
+ const Curves *curves = this->get_curve_for_read();
+ if (curves != nullptr) {
+ std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curves);
/* Using the evaluated positions is somewhat arbitrary, but it is probably expected. */
have_minmax |= curve->bounds_min_max(*r_min, *r_max, true);
}
@@ -258,7 +260,7 @@ const Volume *GeometrySet::get_volume_for_read() const
return (component == nullptr) ? nullptr : component->get_for_read();
}
-const CurveEval *GeometrySet::get_curve_for_read() const
+const Curves *GeometrySet::get_curve_for_read() const
{
const CurveComponent *component = this->get_component_for_read<CurveComponent>();
return (component == nullptr) ? nullptr : component->get_for_read();
@@ -285,7 +287,7 @@ bool GeometrySet::has_volume() const
bool GeometrySet::has_curve() const
{
const CurveComponent *component = this->get_component_for_read<CurveComponent>();
- return component != nullptr && component->has_curve();
+ return component != nullptr && component->has_curves();
}
bool GeometrySet::has_realized_data() const
@@ -327,12 +329,12 @@ GeometrySet GeometrySet::create_with_pointcloud(PointCloud *pointcloud,
return geometry_set;
}
-GeometrySet GeometrySet::create_with_curve(CurveEval *curve, GeometryOwnershipType ownership)
+GeometrySet GeometrySet::create_with_curve(Curves *curves, GeometryOwnershipType ownership)
{
GeometrySet geometry_set;
- if (curve != nullptr) {
+ if (curves != nullptr) {
CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
- component.replace(curve, ownership);
+ component.replace(curves, ownership);
}
return geometry_set;
}
@@ -351,18 +353,18 @@ void GeometrySet::replace_mesh(Mesh *mesh, GeometryOwnershipType ownership)
component.replace(mesh, ownership);
}
-void GeometrySet::replace_curve(CurveEval *curve, GeometryOwnershipType ownership)
+void GeometrySet::replace_curve(Curves *curves, GeometryOwnershipType ownership)
{
- if (curve == nullptr) {
+ if (curves == nullptr) {
this->remove<CurveComponent>();
return;
}
- if (curve == this->get_curve_for_read()) {
+ if (curves == this->get_curve_for_read()) {
return;
}
this->remove<CurveComponent>();
CurveComponent &component = this->get_component_for_write<CurveComponent>();
- component.replace(curve, ownership);
+ component.replace(curves, ownership);
}
void GeometrySet::replace_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership)
@@ -411,7 +413,7 @@ Volume *GeometrySet::get_volume_for_write()
return component == nullptr ? nullptr : component->get_for_write();
}
-CurveEval *GeometrySet::get_curve_for_write()
+Curves *GeometrySet::get_curve_for_write()
{
CurveComponent *component = this->get_component_ptr<CurveComponent>();
return component == nullptr ? nullptr : component->get_for_write();
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index 5af599f0302..6b5c04ac25e 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -953,7 +953,7 @@ static const Mesh *get_evaluated_mesh_from_object(const Object *object)
return nullptr;
}
-static const CurveEval *get_evaluated_curve_from_object(const Object *object)
+static const Curves *get_evaluated_curves_from_object(const Object *object)
{
GeometrySet *geometry_set_eval = object->runtime.geometry_set_eval;
if (geometry_set_eval) {
@@ -968,8 +968,9 @@ static Mesh *mesh_new_from_evaluated_curve_type_object(const Object *evaluated_o
if (mesh) {
return BKE_mesh_copy_for_eval(mesh, false);
}
- const CurveEval *curve = get_evaluated_curve_from_object(evaluated_object);
- if (curve) {
+ const Curves *curves = get_evaluated_curves_from_object(evaluated_object);
+ if (curves) {
+ std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curves);
return blender::bke::curve_to_wire_mesh(*curve);
}
return nullptr;