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:
-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
-rw-r--r--source/blender/geometry/intern/realize_instances.cc39
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc7
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc7
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_length.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc21
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc13
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc24
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc15
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc15
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transform.cc9
53 files changed, 1004 insertions, 327 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;
diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc
index c98bd9d6b74..149ae70dda1 100644
--- a/source/blender/geometry/intern/realize_instances.cc
+++ b/source/blender/geometry/intern/realize_instances.cc
@@ -13,6 +13,7 @@
#include "BLI_task.hh"
#include "BKE_collection.h"
+#include "BKE_curves.hh"
#include "BKE_geometry_set_instances.hh"
#include "BKE_material.h"
#include "BKE_mesh.h"
@@ -118,7 +119,7 @@ struct RealizeMeshTask {
};
struct RealizeCurveInfo {
- const CurveEval *curve = nullptr;
+ const Curves *curves;
/**
* Matches the order in #AllCurvesInfo.attributes. For point attributes, the `std::optional`
* will be empty.
@@ -163,7 +164,7 @@ struct AllCurvesInfo {
/** Ordering of all attributes that are propagated to the output curve generically. */
OrderedAttributes attributes;
/** Ordering of the original curves that are joined. */
- VectorSet<const CurveEval *> order;
+ VectorSet<const Curves *> order;
/** Preprocessed data about every original curve. This is ordered by #order. */
Array<RealizeCurveInfo> realize_info;
bool create_id_attribute = false;
@@ -443,16 +444,16 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
}
case GEO_COMPONENT_TYPE_CURVE: {
const CurveComponent &curve_component = *static_cast<const CurveComponent *>(component);
- const CurveEval *curve = curve_component.get_for_read();
- if (curve != nullptr && !curve->splines().is_empty()) {
- const int curve_index = gather_info.curves.order.index_of(curve);
+ const Curves *curves = curve_component.get_for_read();
+ if (curves != nullptr && curves->geometry.curve_size > 0) {
+ const int curve_index = gather_info.curves.order.index_of(curves);
const RealizeCurveInfo &curve_info = gather_info.curves.realize_info[curve_index];
gather_info.r_tasks.curve_tasks.append({gather_info.r_offsets.spline_offset,
&curve_info,
base_transform,
base_instance_context.curves,
base_instance_context.id});
- gather_info.r_offsets.spline_offset += curve->splines().size();
+ gather_info.r_offsets.spline_offset += curves->geometry.curve_size;
}
break;
}
@@ -1038,11 +1039,11 @@ static OrderedAttributes gather_generic_curve_attributes_to_propagate(
}
static void gather_curves_to_realize(const GeometrySet &geometry_set,
- VectorSet<const CurveEval *> &r_curves)
+ VectorSet<const Curves *> &r_curves)
{
- if (const CurveEval *curve = geometry_set.get_curve_for_read()) {
- if (!curve->splines().is_empty()) {
- r_curves.add(curve);
+ if (const Curves *curves = geometry_set.get_curve_for_read()) {
+ if (curves->geometry.curve_size != 0) {
+ r_curves.add(curves);
}
}
if (const InstancesComponent *instances =
@@ -1064,12 +1065,12 @@ static AllCurvesInfo preprocess_curves(const GeometrySet &geometry_set,
info.realize_info.reinitialize(info.order.size());
for (const int curve_index : info.realize_info.index_range()) {
RealizeCurveInfo &curve_info = info.realize_info[curve_index];
- const CurveEval *curve = info.order[curve_index];
- curve_info.curve = curve;
+ const Curves *curves = info.order[curve_index];
+ curve_info.curves = curves;
/* Access attributes. */
CurveComponent component;
- component.replace(const_cast<CurveEval *>(curve), GeometryOwnershipType::ReadOnly);
+ component.replace(const_cast<Curves *>(curves), GeometryOwnershipType::ReadOnly);
curve_info.spline_attributes.reinitialize(info.attributes.size());
for (const int attribute_index : info.attributes.index_range()) {
const AttributeDomain domain = info.attributes.kinds[attribute_index].domain;
@@ -1095,9 +1096,9 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options,
MutableSpan<GMutableSpan> dst_spline_attributes)
{
const RealizeCurveInfo &curve_info = *task.curve_info;
- const CurveEval &curve = *curve_info.curve;
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_info.curves);
- const Span<SplinePtr> src_splines = curve.splines();
+ const Span<SplinePtr> src_splines = curve->splines();
/* Initialize point attributes. */
threading::parallel_for(src_splines.index_range(), 100, [&](const IndexRange src_spline_range) {
@@ -1206,12 +1207,12 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
}
const RealizeCurveTask &last_task = tasks.last();
- const CurveEval &last_curve = *last_task.curve_info->curve;
- const int tot_splines = last_task.start_spline_index + last_curve.splines().size();
+ const Curves &last_curves = *last_task.curve_info->curves;
+ const int tot_splines = last_task.start_spline_index + last_curves.geometry.curve_size;
Array<SplinePtr> dst_splines(tot_splines);
- CurveEval *dst_curve = new CurveEval();
+ std::unique_ptr<CurveEval> dst_curve = std::make_unique<CurveEval>();
dst_curve->attributes.reallocate(tot_splines);
CustomDataAttributes &spline_attributes = dst_curve->attributes;
@@ -1242,7 +1243,7 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
dst_curve->add_splines(dst_splines);
CurveComponent &dst_component = r_realized_geometry.get_component_for_write<CurveComponent>();
- dst_component.replace(dst_curve);
+ dst_component.replace(curve_eval_to_curves(*dst_curve));
}
/** \} */
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc
index b83aa8b69a9..e6f3e483f1f 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc
@@ -143,9 +143,9 @@ static void node_geo_exec(GeoNodeExecParams params)
}
const CurveComponent &curve_component = *geometry_set.get_component_for_read<CurveComponent>();
- const CurveEval &curve = *curve_component.get_for_read();
- const Span<SplinePtr> splines = curve.splines();
- curve.assert_valid_point_attributes();
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read());
+ const Span<SplinePtr> splines = curve->splines();
+ curve->assert_valid_point_attributes();
evaluate_splines(splines);
@@ -167,9 +167,9 @@ static void node_geo_exec(GeoNodeExecParams params)
end_result.get_component_for_write<PointCloudComponent>();
CurveToPointsResults start_attributes = curve_to_points_create_result_attributes(
- start_point_component, curve);
+ start_point_component, *curve);
CurveToPointsResults end_attributes = curve_to_points_create_result_attributes(
- end_point_component, curve);
+ end_point_component, *curve);
copy_endpoint_attributes(splines, offsets.as_span(), start_attributes, end_attributes);
copy_spline_domain_attributes(curve_component, offsets.as_span(), start_point_component);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc
index 6deaf5b554a..78e36784be7 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc
@@ -26,8 +26,8 @@ static void node_geo_exec(GeoNodeExecParams params)
/* Retrieve data for write access so we can avoid new allocations for the reversed data. */
CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
- CurveEval &curve = *curve_component.get_for_write();
- MutableSpan<SplinePtr> splines = curve.splines();
+ std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read());
+ MutableSpan<SplinePtr> splines = curve->splines();
const std::string selection_name = params.extract_input<std::string>("Selection");
VArray<bool> selection = curve_component.attribute_get_for_read(
@@ -41,6 +41,8 @@ static void node_geo_exec(GeoNodeExecParams params)
}
});
+ geometry_set.replace_curve(curve_eval_to_curves(*curve));
+
params.set_output("Curve", geometry_set);
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc
index a09a751b550..729ccca5f04 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc
@@ -89,9 +89,8 @@ static void node_geo_exec(GeoNodeExecParams params)
geometry_set = geometry::realize_instances_legacy(geometry_set);
CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
- const CurveEval *curve = curve_component.get_for_read();
-
- if (curve != nullptr) {
+ if (curve_component.has_curves()) {
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read());
const std::string selection_name = params.extract_input<std::string>("Selection");
OutputAttribute_Typed<bool> selection =
curve_component.attribute_try_get_for_output_only<bool>(selection_name, ATTR_DOMAIN_POINT);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc
index e5d4d6c1d0f..8ab43909a20 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc
@@ -63,8 +63,8 @@ static void node_geo_exec(GeoNodeExecParams params)
/* Retrieve data for write access so we can avoid new allocations for the handles data. */
CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
- CurveEval &curve = *curve_component.get_for_write();
- MutableSpan<SplinePtr> splines = curve.splines();
+ std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read());
+ MutableSpan<SplinePtr> splines = curve->splines();
const std::string selection_name = params.extract_input<std::string>("Selection");
VArray<bool> selection = curve_component.attribute_get_for_read(
@@ -101,6 +101,8 @@ static void node_geo_exec(GeoNodeExecParams params)
bezier_spline.mark_cache_invalid();
}
+ geometry_set.replace_curve(curve_eval_to_curves(*curve));
+
if (!has_bezier_spline) {
params.error_message_add(NodeWarningType::Info, TIP_("No Bezier splines in input curve"));
}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc
index 87b8bbf8786..e15e7339107 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc
@@ -242,34 +242,34 @@ static void node_geo_exec(GeoNodeExecParams params)
}
const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>();
- const CurveEval &curve = *curve_component->get_for_read();
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component->get_for_read());
const std::string selection_name = params.extract_input<std::string>("Selection");
VArray<bool> selection = curve_component->attribute_get_for_read(
selection_name, ATTR_DOMAIN_CURVE, true);
std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>();
- for (const int i : curve.splines().index_range()) {
+ for (const int i : curve->splines().index_range()) {
if (selection[i]) {
switch (output_type) {
case GEO_NODE_SPLINE_TYPE_POLY:
- new_curve->add_spline(convert_to_poly_spline(*curve.splines()[i]));
+ new_curve->add_spline(convert_to_poly_spline(*curve->splines()[i]));
break;
case GEO_NODE_SPLINE_TYPE_BEZIER:
- new_curve->add_spline(convert_to_bezier(*curve.splines()[i], params));
+ new_curve->add_spline(convert_to_bezier(*curve->splines()[i], params));
break;
case GEO_NODE_SPLINE_TYPE_NURBS:
- new_curve->add_spline(convert_to_nurbs(*curve.splines()[i]));
+ new_curve->add_spline(convert_to_nurbs(*curve->splines()[i]));
break;
}
}
else {
- new_curve->add_spline(curve.splines()[i]->copy());
+ new_curve->add_spline(curve->splines()[i]->copy());
}
}
- new_curve->attributes = curve.attributes;
- params.set_output("Curve", GeometrySet::create_with_curve(new_curve.release()));
+ new_curve->attributes = curve->attributes;
+ params.set_output("Curve", GeometrySet::create_with_curve(curve_eval_to_curves(*new_curve)));
}
} // namespace blender::nodes::node_geo_legacy_curve_spline_type_cc
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc
index bce320496a1..2a8ab2990db 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc
@@ -354,9 +354,11 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
- std::unique_ptr<CurveEval> output_curve = subdivide_curve(*component.get_for_read(), cuts);
+ std::unique_ptr<CurveEval> output_curve = subdivide_curve(
+ *curves_to_curve_eval(*component.get_for_read()), cuts);
- params.set_output("Geometry", GeometrySet::create_with_curve(output_curve.release()));
+ params.set_output("Geometry",
+ GeometrySet::create_with_curve(curve_eval_to_curves(*output_curve)));
}
} // namespace blender::nodes::node_geo_legacy_curve_subdivide_cc
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc
index 64627e61910..f68dd6b6b0c 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc
@@ -289,13 +289,13 @@ static void node_geo_exec(GeoNodeExecParams params)
}
const CurveComponent &curve_component = *geometry_set.get_component_for_read<CurveComponent>();
- const CurveEval &curve = *curve_component.get_for_read();
- const Span<SplinePtr> splines = curve.splines();
- curve.assert_valid_point_attributes();
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read());
+ const Span<SplinePtr> splines = curve->splines();
+ curve->assert_valid_point_attributes();
evaluate_splines(splines);
- const Array<int> offsets = calculate_spline_point_offsets(params, mode, curve, splines);
+ const Array<int> offsets = calculate_spline_point_offsets(params, mode, *curve, splines);
const int total_size = offsets.last();
if (total_size == 0) {
params.set_output("Geometry", GeometrySet());
@@ -306,7 +306,7 @@ static void node_geo_exec(GeoNodeExecParams params)
PointCloudComponent &point_component = result.get_component_for_write<PointCloudComponent>();
CurveToPointsResults new_attributes = curve_to_points_create_result_attributes(point_component,
- curve);
+ *curve);
switch (mode) {
case GEO_NODE_CURVE_RESAMPLE_COUNT:
case GEO_NODE_CURVE_RESAMPLE_LENGTH:
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc
index 897a1c1cd2d..ca98d83c137 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc
@@ -235,9 +235,9 @@ static void delete_curve_selection(const CurveComponent &in_component,
const bool invert)
{
std::unique_ptr<CurveEval> r_curve = curve_delete(
- *in_component.get_for_read(), selection_name, invert);
+ *curves_to_curve_eval(*in_component.get_for_read()), selection_name, invert);
if (r_curve) {
- r_component.replace(r_curve.release());
+ r_component.replace(curve_eval_to_curves(*r_curve));
}
else {
r_component.clear();
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc
index ff86a92f2c7..cb5a757811e 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc
@@ -48,7 +48,7 @@ static void node_geo_exec(GeoNodeExecParams params)
std::unique_ptr<CurveEval> curve = geometry::mesh_to_curve_convert(
component, IndexMask(selected_edge_indices));
- params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+ params.set_output("Curve", GeometrySet::create_with_curve(curve_eval_to_curves(*curve)));
}
} // namespace blender::nodes::node_geo_legacy_mesh_to_curve_cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
index 59147e9b23f..44b9857e791 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
@@ -162,8 +162,9 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
}
if (geometry_set.has_curve()) {
- const CurveEval &curve = *geometry_set.get_curve_for_read();
- for (const SplinePtr &spline : curve.splines()) {
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *geometry_set.get_curve_for_read());
+ for (const SplinePtr &spline : curve->splines()) {
positions_span = spline->evaluated_positions();
total_size += positions_span.size();
count++;
@@ -202,8 +203,9 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
}
if (geometry_set.has_curve()) {
- const CurveEval &curve = *geometry_set.get_curve_for_read();
- for (const SplinePtr &spline : curve.splines()) {
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *geometry_set.get_curve_for_read());
+ for (const SplinePtr &spline : curve->splines()) {
Span<float3> array = spline->evaluated_positions();
positions.as_mutable_span().slice(offset, array.size()).copy_from(array);
offset += array.size();
@@ -273,7 +275,7 @@ static Mesh *convex_hull_from_instances(const GeometrySet &geometry_set)
read_positions(*set.get_component_for_read<MeshComponent>(), transforms, &coords);
}
if (set.has_curve()) {
- read_curve_positions(*set.get_curve_for_read(), transforms, &coords);
+ read_curve_positions(*curves_to_curve_eval(*set.get_curve_for_read()), transforms, &coords);
}
}
return hull_from_bullet(nullptr, coords);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
index 65aad0fcbf1..ce3058c7d42 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
@@ -59,10 +59,13 @@ class EndpointFieldInput final : public GeometryFieldInput {
}
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- const CurveEval *curve = curve_component.get_for_read();
+ if (!curve_component.has_curves()) {
+ return nullptr;
+ }
- Array<int> control_point_offsets = curve->control_point_offsets();
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read());
+ Array<int> control_point_offsets = curve->control_point_offsets();
if (curve == nullptr || control_point_offsets.last() == 0) {
return nullptr;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
index 9824b2b2ece..c1220746c22 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
@@ -117,8 +117,9 @@ static void curve_fill_calculate(GeometrySet &geometry_set, const GeometryNodeCu
return;
}
- const CurveEval &curve = *geometry_set.get_curve_for_read();
- if (curve.splines().is_empty()) {
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *geometry_set.get_curve_for_read());
+ if (curve->splines().is_empty()) {
geometry_set.replace_curve(nullptr);
return;
}
@@ -127,7 +128,7 @@ static void curve_fill_calculate(GeometrySet &geometry_set, const GeometryNodeCu
CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES :
CDT_INSIDE_WITH_HOLES;
- const blender::meshintersect::CDT_result<double> results = do_cdt(curve, output_type);
+ const blender::meshintersect::CDT_result<double> results = do_cdt(*curve, output_type);
Mesh *mesh = cdt_to_mesh(results);
geometry_set.replace_mesh(mesh);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
index b8f317a9679..6742b1103ee 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
@@ -603,10 +603,10 @@ static void calculate_curve_fillet(GeometrySet &geometry_set,
fillet_param.limit_radius = limit_radius;
- const CurveEval &input_curve = *geometry_set.get_curve_for_read();
- std::unique_ptr<CurveEval> output_curve = fillet_curve(input_curve, fillet_param);
+ const std::unique_ptr<CurveEval> input_curve = curves_to_curve_eval(*component.get_for_read());
+ std::unique_ptr<CurveEval> output_curve = fillet_curve(*input_curve, fillet_param);
- geometry_set.replace_curve(output_curve.release());
+ geometry_set.replace_curve(curve_eval_to_curves(*output_curve));
}
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
index 8dc74aa3dea..ccd3a587e63 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc
@@ -92,14 +92,14 @@ class HandleTypeFieldInput final : public GeometryFieldInput {
}
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- const CurveEval *curve = curve_component.get_for_read();
+ const Curves *curve = curve_component.get_for_read();
if (curve == nullptr) {
return {};
}
if (domain == ATTR_DOMAIN_POINT) {
Array<bool> selection(mask.min_array_size());
- select_by_handle_type(*curve, type_, mode_, selection);
+ select_by_handle_type(*curves_to_curve_eval(*curve), type_, mode_, selection);
return VArray<bool>::ForContainer(std::move(selection));
}
return {};
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
index 82621189964..c7c822db983 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
@@ -18,9 +18,9 @@ static void node_geo_exec(GeoNodeExecParams params)
params.set_default_remaining_outputs();
return;
}
- const CurveEval &curve = *curve_set.get_curve_for_read();
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_set.get_curve_for_read());
float length = 0.0f;
- for (const SplinePtr &spline : curve.splines()) {
+ for (const SplinePtr &spline : curve->splines()) {
length += spline->length();
}
params.set_output("Length", length);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc
index 9919e24473e..9fbc01935ce 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc
@@ -335,7 +335,7 @@ static void node_geo_exec(GeoNodeExecParams params)
r_center,
r_normal,
r_radius);
- params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+ params.set_output("Curve", GeometrySet::create_with_curve(curve_eval_to_curves(*curve)));
params.set_output("Center", r_center);
params.set_output("Normal", r_normal);
params.set_output("Radius", r_radius);
@@ -350,7 +350,7 @@ static void node_geo_exec(GeoNodeExecParams params)
params.extract_input<bool>("Connect Center"),
params.extract_input<bool>("Invert Arc"));
- params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+ params.set_output("Curve", GeometrySet::create_with_curve(curve_eval_to_curves(*curve)));
break;
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
index 1d006aea1ef..eabd6aa1aa0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
@@ -113,7 +113,7 @@ static void node_geo_exec(GeoNodeExecParams params)
params.extract_input<float3>("End Handle"),
std::max(params.extract_input<int>("Resolution"), 1),
mode);
- params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+ params.set_output("Curve", GeometrySet::create_with_curve(curve_eval_to_curves(*curve)));
}
} // namespace blender::nodes::node_geo_curve_primitive_bezier_segment_cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
index 44505b61a27..73929dce1af 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
@@ -203,7 +203,7 @@ static void node_geo_exec(GeoNodeExecParams params)
}
if (curve) {
- params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+ params.set_output("Curve", GeometrySet::create_with_curve(curve_eval_to_curves(*curve)));
}
else {
params.set_default_remaining_outputs();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
index d11af3b1cc0..066947de496 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
@@ -111,7 +111,7 @@ static void node_geo_exec(GeoNodeExecParams params)
params.extract_input<float>("Length"));
}
- params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+ params.set_output("Curve", GeometrySet::create_with_curve(curve_eval_to_curves(*curve)));
}
} // namespace blender::nodes::node_geo_curve_primitive_line_cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
index 456f6e55c1e..1b055a3a3d5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
@@ -61,7 +61,7 @@ static void node_geo_exec(GeoNodeExecParams params)
params.extract_input<float3>("Middle"),
params.extract_input<float3>("End"),
std::max(params.extract_input<int>("Resolution"), 3));
- params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+ params.set_output("Curve", GeometrySet::create_with_curve(curve_eval_to_curves(*curve)));
}
} // namespace blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
index b6a847eebf4..7842ad028b7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
@@ -264,7 +264,7 @@ static void node_geo_exec(GeoNodeExecParams params)
curve->add_spline(std::move(spline));
curve->attributes.reallocate(curve->splines().size());
- params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+ params.set_output("Curve", GeometrySet::create_with_curve(curve_eval_to_curves(*curve)));
}
} // namespace blender::nodes::node_geo_curve_primitive_quadrilateral_cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
index f448ddabd2b..d5bc70e37cd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
@@ -86,7 +86,7 @@ static void node_geo_exec(GeoNodeExecParams params)
params.extract_input<float>("End Radius"),
params.extract_input<float>("Height"),
params.extract_input<bool>("Reverse"));
- params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+ params.set_output("Curve", GeometrySet::create_with_curve(curve_eval_to_curves(*curve)));
}
} // namespace blender::nodes::node_geo_curve_primitive_spiral_cc
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
index 5969af43bc1..e02bcfb73cc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
@@ -83,7 +83,7 @@ static void node_geo_exec(GeoNodeExecParams params)
std::max(params.extract_input<float>("Outer Radius"), 0.0f),
params.extract_input<float>("Twist"),
std::max(params.extract_input<int>("Points"), 3));
- GeometrySet output = GeometrySet::create_with_curve(curve.release());
+ GeometrySet output = GeometrySet::create_with_curve(curve_eval_to_curves(*curve));
if (params.output_is_required("Outer Points")) {
StrongAnonymousAttributeID attribute_output("Outer Points");
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
index d2afeaa7094..fffc6188dfd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -158,7 +158,7 @@ static SplinePtr resample_spline_evaluated(const Spline &src)
static std::unique_ptr<CurveEval> resample_curve(const CurveComponent *component,
const SampleModeParam &mode_param)
{
- const CurveEval *input_curve = component->get_for_read();
+ const std::unique_ptr<CurveEval> input_curve = curves_to_curve_eval(*component->get_for_read());
GeometryComponentFieldContext field_context{*component, ATTR_DOMAIN_CURVE};
const int domain_size = component->attribute_domain_size(ATTR_DOMAIN_CURVE);
@@ -242,7 +242,7 @@ static void geometry_set_curve_resample(GeometrySet &geometry_set,
std::unique_ptr<CurveEval> output_curve = resample_curve(
geometry_set.get_component_for_read<CurveComponent>(), mode_param);
- geometry_set.replace_curve(output_curve.release());
+ geometry_set.replace_curve(curve_eval_to_curves(*output_curve));
}
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
index 0ef3230937b..06ca0483063 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
@@ -34,13 +34,15 @@ static void node_geo_exec(GeoNodeExecParams params)
selection_evaluator.evaluate();
const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
- CurveEval &curve = *component.get_for_write();
- MutableSpan<SplinePtr> splines = curve.splines();
+ std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_write());
+ MutableSpan<SplinePtr> splines = curve->splines();
threading::parallel_for(selection.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
splines[selection[i]]->reverse();
}
});
+
+ component.replace(curve_eval_to_curves(*curve));
});
params.set_output("Curve", std::move(geometry_set));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
index 152828b284c..222c28dd21b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
@@ -127,7 +127,8 @@ class SampleCurveFunction : public fn::MultiFunction {
}
const CurveComponent *curve_component = geometry_set_.get_component_for_read<CurveComponent>();
- const CurveEval *curve = curve_component->get_for_read();
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *curve_component->get_for_read());
Span<SplinePtr> splines = curve->splines();
if (splines.is_empty()) {
return return_default();
@@ -234,12 +235,13 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
- const CurveEval *curve = component->get_for_read();
- if (curve == nullptr) {
+ if (!component->has_curves()) {
params.set_default_remaining_outputs();
return;
}
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component->get_for_read());
+
if (curve->splines().is_empty()) {
params.set_default_remaining_outputs();
return;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
index 9f50b29d995..a892ff419e5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
@@ -66,8 +66,8 @@ static void node_geo_exec(GeoNodeExecParams params)
/* Retrieve data for write access so we can avoid new allocations for the handles data. */
CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
- CurveEval &curve = *curve_component.get_for_write();
- MutableSpan<SplinePtr> splines = curve.splines();
+ std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read());
+ MutableSpan<SplinePtr> splines = curve->splines();
GeometryComponentFieldContext field_context{curve_component, ATTR_DOMAIN_POINT};
const int domain_size = curve_component.attribute_domain_size(ATTR_DOMAIN_POINT);
@@ -108,6 +108,8 @@ static void node_geo_exec(GeoNodeExecParams params)
}
bezier_spline.mark_cache_invalid();
}
+
+ curve_component.replace(curve_eval_to_curves(*curve));
});
if (!has_bezier_spline) {
params.error_message_add(NodeWarningType::Info, TIP_("No Bezier splines in input curve"));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
index 3fcbd1b88c3..3edaccba506 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
@@ -205,8 +205,9 @@ class CurveParameterFieldInput final : public GeometryFieldInput {
{
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- const CurveEval *curve = curve_component.get_for_read();
- if (curve) {
+ if (curve_component.has_curves()) {
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *curve_component.get_for_read());
return construct_curve_parameter_varray(*curve, mask, domain);
}
}
@@ -238,8 +239,8 @@ class CurveLengthFieldInput final : public GeometryFieldInput {
{
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- const CurveEval *curve = curve_component.get_for_read();
- if (curve) {
+ if (curve_component.has_curves()) {
+ std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read());
return construct_curve_length_varray(*curve, mask, domain);
}
}
@@ -271,8 +272,9 @@ class IndexOnSplineFieldInput final : public GeometryFieldInput {
{
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- const CurveEval *curve = curve_component.get_for_read();
- if (curve) {
+ if (curve_component.has_curves()) {
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *curve_component.get_for_read());
return construct_index_on_spline_varray(*curve, mask, domain);
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
index 053df030f15..d691726da27 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
@@ -367,40 +367,43 @@ static void node_geo_exec(GeoNodeExecParams params)
}
const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>();
- const CurveEval &curve = *curve_component->get_for_read();
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *curve_component->get_for_read());
GeometryComponentFieldContext field_context{*curve_component, ATTR_DOMAIN_CURVE};
const int domain_size = curve_component->attribute_domain_size(ATTR_DOMAIN_CURVE);
+ Span<SplinePtr> src_splines = curve->splines();
+
fn::FieldEvaluator selection_evaluator{field_context, domain_size};
selection_evaluator.add(selection_field);
selection_evaluator.evaluate();
const VArray<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>();
- new_curve->resize(curve.splines().size());
+ new_curve->resize(src_splines.size());
- threading::parallel_for(curve.splines().index_range(), 512, [&](IndexRange range) {
+ threading::parallel_for(src_splines.index_range(), 512, [&](IndexRange range) {
for (const int i : range) {
if (selection[i]) {
switch (output_type) {
case GEO_NODE_SPLINE_TYPE_POLY:
- new_curve->splines()[i] = convert_to_poly_spline(*curve.splines()[i]);
+ new_curve->splines()[i] = convert_to_poly_spline(*src_splines[i]);
break;
case GEO_NODE_SPLINE_TYPE_BEZIER:
- new_curve->splines()[i] = convert_to_bezier(*curve.splines()[i], params);
+ new_curve->splines()[i] = convert_to_bezier(*src_splines[i], params);
break;
case GEO_NODE_SPLINE_TYPE_NURBS:
- new_curve->splines()[i] = convert_to_nurbs(*curve.splines()[i]);
+ new_curve->splines()[i] = convert_to_nurbs(*src_splines[i]);
break;
}
}
else {
- new_curve->splines()[i] = curve.splines()[i]->copy();
+ new_curve->splines()[i] = src_splines[i]->copy();
}
}
});
- new_curve->attributes = curve.attributes;
- geometry_set.replace_curve(new_curve.release());
+ new_curve->attributes = curve->attributes;
+ geometry_set.replace_curve(curve_eval_to_curves(*new_curve));
});
params.set_output("Curve", std::move(geometry_set));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
index 81c3f14d8b1..3297ddcae85 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
@@ -340,9 +340,9 @@ static void node_geo_exec(GeoNodeExecParams params)
if (cuts.is_single() && cuts.get_internal_single() < 1) {
return;
}
-
- std::unique_ptr<CurveEval> output_curve = subdivide_curve(*component.get_for_read(), cuts);
- geometry_set.replace_curve(output_curve.release());
+ std::unique_ptr<CurveEval> output_curve = subdivide_curve(
+ *curves_to_curve_eval(*component.get_for_read()), cuts);
+ geometry_set.replace_curve(curve_eval_to_curves(*output_curve));
});
params.set_output("Curve", geometry_set);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
index ed497b6fbe0..753a6fe7278 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
@@ -27,14 +27,16 @@ static void geometry_set_curve_to_mesh(GeometrySet &geometry_set,
const GeometrySet &profile_set,
const bool fill_caps)
{
- const CurveEval *curve = geometry_set.get_curve_for_read();
- const CurveEval *profile_curve = profile_set.get_curve_for_read();
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *geometry_set.get_curve_for_read());
+ const Curves *profile_curves = profile_set.get_curve_for_read();
- if (profile_curve == nullptr) {
+ if (profile_curves == nullptr) {
Mesh *mesh = bke::curve_to_wire_mesh(*curve);
geometry_set.replace_mesh(mesh);
}
else {
+ const std::unique_ptr<CurveEval> profile_curve = curves_to_curve_eval(*profile_curves);
Mesh *mesh = bke::curve_to_mesh_sweep(*curve, *profile_curve, fill_caps);
geometry_set.replace_mesh(mesh);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
index 7481f7248a1..33e7a818c87 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
@@ -325,11 +325,12 @@ static void node_geo_exec(GeoNodeExecParams params)
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
return;
}
- const CurveEval &curve = *geometry_set.get_curve_for_read();
- const Span<SplinePtr> splines = curve.splines();
- curve.assert_valid_point_attributes();
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *geometry_set.get_curve_for_read());
+ const Span<SplinePtr> splines = curve->splines();
+ curve->assert_valid_point_attributes();
- const Array<int> offsets = calculate_spline_point_offsets(params, mode, curve, splines);
+ const Array<int> offsets = calculate_spline_point_offsets(params, mode, *curve, splines);
const int total_size = offsets.last();
if (total_size == 0) {
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
@@ -339,7 +340,7 @@ static void node_geo_exec(GeoNodeExecParams params)
geometry_set.replace_pointcloud(BKE_pointcloud_new_nomain(total_size));
PointCloudComponent &points = geometry_set.get_component_for_write<PointCloudComponent>();
ResultAttributes point_attributes = create_attributes_for_transfer(
- points, curve, attribute_outputs);
+ points, *curve, attribute_outputs);
switch (mode) {
case GEO_NODE_CURVE_RESAMPLE_COUNT:
@@ -351,7 +352,7 @@ static void node_geo_exec(GeoNodeExecParams params)
break;
}
- copy_spline_domain_attributes(curve, offsets, points);
+ copy_spline_domain_attributes(*curve, offsets, points);
if (!point_attributes.rotations.is_empty()) {
curve_create_default_rotation_attribute(
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
index 6f2eb9f23c4..649391a2346 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
@@ -515,8 +515,8 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set,
const blender::VArray<float> &starts = evaluator.get_evaluated<float>(0);
const blender::VArray<float> &ends = evaluator.get_evaluated<float>(1);
- CurveEval &curve = *geometry_set.get_curve_for_write();
- MutableSpan<SplinePtr> splines = curve.splines();
+ std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*geometry_set.get_curve_for_read());
+ MutableSpan<SplinePtr> splines = curve->splines();
threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
for (const int i : range) {
@@ -565,6 +565,8 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set,
}
}
});
+
+ geometry_set.replace_curve(curve_eval_to_curves(*curve));
}
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
index c11b82a7d99..9fc71ebe8d1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -475,9 +475,9 @@ static void separate_curve_selection(GeometrySet &geometry_set,
selection_evaluator.evaluate();
const VArray_Span<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
std::unique_ptr<CurveEval> r_curve = curve_separate(
- *src_component.get_for_read(), selection, selection_domain, invert);
+ *curves_to_curve_eval(*src_component.get_for_read()), selection, selection_domain, invert);
if (r_curve) {
- geometry_set.replace_curve(r_curve.release());
+ geometry_set.replace_curve(curve_eval_to_curves(*r_curve));
}
else {
geometry_set.replace_curve(nullptr);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
index c247a255e5b..41f1e6663d3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
@@ -529,7 +529,8 @@ static void duplicate_splines(GeometrySet &geometry_set,
const GeometryComponent &src_component = *geometry_set.get_component_for_read(
GEO_COMPONENT_TYPE_CURVE);
- const CurveEval &curve = *geometry_set.get_curve_for_read();
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *geometry_set.get_curve_for_read());
const int domain_size = src_component.attribute_domain_size(ATTR_DOMAIN_CURVE);
GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_CURVE};
FieldEvaluator evaluator{field_context, domain_size};
@@ -547,11 +548,11 @@ static void duplicate_splines(GeometrySet &geometry_set,
int count = std::max(counts[selection[i_spline]], 0);
curve_offsets[i_spline] = dst_splines_size;
dst_splines_size += count;
- dst_points_size += count * curve.splines()[selection[i_spline]]->size();
+ dst_points_size += count * curve->splines()[selection[i_spline]]->size();
}
curve_offsets.last() = dst_splines_size;
- Array<int> control_point_offsets = curve.control_point_offsets();
+ Array<int> control_point_offsets = curve->control_point_offsets();
Array<int> point_mapping(dst_points_size);
std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>();
@@ -559,8 +560,8 @@ static void duplicate_splines(GeometrySet &geometry_set,
for (const int i_spline : selection.index_range()) {
const IndexRange spline_range = range_for_offsets_index(curve_offsets, i_spline);
for ([[maybe_unused]] const int i_duplicate : IndexRange(spline_range.size())) {
- SplinePtr spline = curve.splines()[selection[i_spline]]->copy();
- for (const int i_point : IndexRange(curve.splines()[selection[i_spline]]->size())) {
+ SplinePtr spline = curve->splines()[selection[i_spline]]->copy();
+ for (const int i_point : IndexRange(curve->splines()[selection[i_spline]]->size())) {
point_mapping[point_index++] = control_point_offsets[selection[i_spline]] + i_point;
}
new_curve->add_spline(std::move(spline));
@@ -569,7 +570,7 @@ static void duplicate_splines(GeometrySet &geometry_set,
new_curve->attributes.reallocate(new_curve->splines().size());
CurveComponent dst_component;
- dst_component.replace(new_curve.release(), GeometryOwnershipType::Editable);
+ dst_component.replace(curve_eval_to_curves(*new_curve), GeometryOwnershipType::Editable);
Vector<std::string> skip(
{"position", "radius", "resolution", "cyclic", "tilt", "handle_left", "handle_right"});
@@ -577,7 +578,7 @@ static void duplicate_splines(GeometrySet &geometry_set,
copy_spline_attributes_without_id(
geometry_set, point_mapping, curve_offsets, skip, src_component, dst_component);
- copy_stable_id_splines(curve, selection, curve_offsets, src_component, dst_component);
+ copy_stable_id_splines(*curve, selection, curve_offsets, src_component, dst_component);
if (attributes.duplicate_index) {
create_duplicate_index_attribute(
@@ -786,8 +787,9 @@ static void duplicate_points_curve(const GeometryComponentType component_type,
Array<int> offsets = accumulate_counts_to_offsets(selection, counts);
CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
- const CurveEval &curve = *geometry_set.get_curve_for_read();
- Array<int> control_point_offsets = curve.control_point_offsets();
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *geometry_set.get_curve_for_read());
+ Array<int> control_point_offsets = curve->control_point_offsets();
std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>();
Array<int> parent(domain_size);
@@ -802,7 +804,7 @@ static void duplicate_points_curve(const GeometryComponentType component_type,
for (const int i_point : selection) {
const IndexRange point_range = range_for_offsets_index(offsets, i_point);
for ([[maybe_unused]] const int i_duplicate : IndexRange(point_range.size())) {
- const SplinePtr &parent_spline = curve.splines()[parent[i_point]];
+ const SplinePtr &parent_spline = curve->splines()[parent[i_point]];
switch (parent_spline->type()) {
case CurveType::CURVE_TYPE_BEZIER: {
std::unique_ptr<BezierSpline> spline = std::make_unique<BezierSpline>();
@@ -833,7 +835,7 @@ static void duplicate_points_curve(const GeometryComponentType component_type,
}
new_curve->attributes.reallocate(new_curve->splines().size());
CurveComponent dst_component;
- dst_component.replace(new_curve.release(), GeometryOwnershipType::Editable);
+ dst_component.replace(curve_eval_to_curves(*new_curve), GeometryOwnershipType::Editable);
copy_point_attributes_without_id(
geometry_set, GEO_COMPONENT_TYPE_CURVE, false, offsets, src_component, dst_component);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
index 4537721d173..f952e15fbbe 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
@@ -19,10 +19,10 @@ static void node_declare(NodeDeclarationBuilder &b)
static VArray<float> construct_spline_length_gvarray(const CurveComponent &component,
const AttributeDomain domain)
{
- const CurveEval *curve = component.get_for_read();
- if (curve == nullptr) {
+ if (!component.has_curves()) {
return {};
}
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_read());
Span<SplinePtr> splines = curve->splines();
auto length_fn = [splines](int i) { return splines[i]->length(); };
@@ -76,10 +76,10 @@ class SplineLengthFieldInput final : public GeometryFieldInput {
static VArray<int> construct_spline_count_gvarray(const CurveComponent &component,
const AttributeDomain domain)
{
- const CurveEval *curve = component.get_for_read();
- if (curve == nullptr) {
+ if (!component.has_curves()) {
return {};
}
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_read());
Span<SplinePtr> splines = curve->splines();
auto count_fn = [splines](int i) { return splines[i]->size(); };
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
index 4ee7c52a872..435dd969c03 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
@@ -77,21 +77,12 @@ static Array<float3> curve_tangent_point_domain(const CurveEval &curve)
static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &component,
const AttributeDomain domain)
{
- const CurveEval *curve = component.get_for_read();
- if (curve == nullptr) {
- return nullptr;
+ if (!component.has_curves()) {
+ return {};
}
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_read());
if (domain == ATTR_DOMAIN_POINT) {
- const Span<SplinePtr> splines = curve->splines();
-
- /* Use a reference to evaluated tangents 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_tangents());
- }
-
Array<float3> tangents = curve_tangent_point_domain(*curve);
return VArray<float3>::ForContainer(std::move(tangents));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
index 3284378a2cb..91cde52f9eb 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
@@ -35,7 +35,7 @@ static void node_geo_exec(GeoNodeExecParams params)
}
std::unique_ptr<CurveEval> curve = geometry::mesh_to_curve_convert(component, selection);
- geometry_set.replace_curve(curve.release());
+ geometry_set.replace_curve(curve_eval_to_curves(*curve));
geometry_set.keep_only({GEO_COMPONENT_TYPE_CURVE, GEO_COMPONENT_TYPE_INSTANCES});
});
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
index 808d679fb73..85b042ddb9b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
@@ -35,7 +35,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
}
static void set_position_in_component(const GeometryNodeCurveHandleMode mode,
- GeometryComponent &component,
+ CurveComponent &component,
const Field<bool> &selection_field,
const Field<float3> &position_field,
const Field<float3> &offset_field)
@@ -53,8 +53,7 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode,
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
- CurveComponent &curve_component = *static_cast<CurveComponent *>(&component);
- CurveEval *curve = curve_component.get_for_write();
+ std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_read());
int current_point = 0;
int current_mask = 0;
@@ -126,6 +125,8 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode,
}
}
}
+
+ component.replace(curve_eval_to_curves(*curve), GeometryOwnershipType::Owned);
}
static void node_geo_exec(GeoNodeExecParams params)
@@ -140,9 +141,11 @@ static void node_geo_exec(GeoNodeExecParams params)
bool has_bezier = false;
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- if (geometry_set.has_curve() &&
- geometry_set.get_curve_for_read()->has_spline_with_type(CURVE_TYPE_BEZIER)) {
- has_bezier = true;
+ if (geometry_set.has_curve()) {
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *geometry_set.get_curve_for_read());
+ has_bezier = curve->has_spline_with_type(CURVE_TYPE_BEZIER);
+
set_position_in_component(mode,
geometry_set.get_component_for_write<CurveComponent>(),
selection_field,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
index f1353bda9ce..e1c252d0081 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
@@ -45,7 +45,9 @@ static void node_geo_exec(GeoNodeExecParams params)
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
if (geometry_set.has_curve()) {
if (only_poly) {
- for (const SplinePtr &spline : geometry_set.get_curve_for_read()->splines()) {
+ const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
+ *geometry_set.get_curve_for_read());
+ for (const SplinePtr &spline : curve->splines()) {
if (ELEM(spline->type(), CURVE_TYPE_BEZIER, CURVE_TYPE_NURBS)) {
only_poly = false;
break;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
index ddc0bb2bc11..45156e0cbf8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
@@ -298,7 +298,8 @@ static Map<int, int> create_curve_instances(GeoNodeExecParams &params,
layout.pivot_points.add_new(layout.char_codes[i], pivot_point);
}
- GeometrySet geometry_set_curve = GeometrySet::create_with_curve(curve_eval.release());
+ GeometrySet geometry_set_curve = GeometrySet::create_with_curve(
+ curve_eval_to_curves(*curve_eval));
handles.add_new(layout.char_codes[i],
instance_component.add_reference(std::move(geometry_set_curve)));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
index 5950a2a16d2..045dea77f38 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
@@ -10,6 +10,7 @@
#include "DNA_pointcloud_types.h"
#include "DNA_volume_types.h"
+#include "BKE_curves.hh"
#include "BKE_mesh.h"
#include "BKE_pointcloud.h"
#include "BKE_spline.hh"
@@ -125,8 +126,10 @@ static void translate_geometry_set(GeometrySet &geometry,
const float3 translation,
const Depsgraph &depsgraph)
{
- if (CurveEval *curve = geometry.get_curve_for_write()) {
+ if (Curves *curves = geometry.get_curve_for_write()) {
+ std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curves);
curve->translate(translation);
+ geometry.replace_curve(curve_eval_to_curves(*curve));
}
if (Mesh *mesh = geometry.get_mesh_for_write()) {
translate_mesh(*mesh, translation);
@@ -146,8 +149,10 @@ void transform_geometry_set(GeometrySet &geometry,
const float4x4 &transform,
const Depsgraph &depsgraph)
{
- if (CurveEval *curve = geometry.get_curve_for_write()) {
+ if (Curves *curves = geometry.get_curve_for_write()) {
+ std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curves);
curve->transform(transform);
+ geometry.replace_curve(curve_eval_to_curves(*curve));
}
if (Mesh *mesh = geometry.get_mesh_for_write()) {
transform_mesh(*mesh, transform);