From 9ec12c26f16ea3da1e6de95d5d5daf1057464830 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Mon, 28 Feb 2022 10:46:34 -0500 Subject: [PATCH] Geometry Nodes: Begin conversion to new curves This commit changes `CurveComponent` to store the new curve type by adding conversions to and from `CurveEval` in most nodes. This will temporarily make performance of curves in geometry nodes much worse, but as functionality is implemented for the new type and it is used in more places, performance will become better than before. We still use `CurveEval` for drawing curves, because the new `Curves` data-block has no evaluated points yet. So the `Curve` ID is still generated for rendering in the same way as before. It's also still needed for drawing curve object edit mode overlays. The old curve component isn't removed yet, because it is still used to implement the conversions to and from `CurveEval`. A few more attributes are added to make this possible: - `nurbs_weight`: The weight for each control point on NURBS curves. - `nurbs_order`: The order of the NURBS curve - `knots_mode`: Necessary for conversion, not defined yet. - `handle_type_{left/right}`: An 8 bit integer attribute. Differential Revision: https://developer.blender.org/D14145 --- source/blender/blenkernel/BKE_geometry_set.hh | 73 ++- source/blender/blenkernel/BKE_spline.hh | 3 + source/blender/blenkernel/CMakeLists.txt | 1 + source/blender/blenkernel/intern/curve.cc | 2 + .../blender/blenkernel/intern/curve_eval.cc | 189 +++++++ source/blender/blenkernel/intern/displist.cc | 4 +- .../intern/geometry_component_curve.cc | 167 +----- .../intern/geometry_component_curves.cc | 521 ++++++++++++++++++ .../blender/blenkernel/intern/geometry_set.cc | 26 +- .../blender/blenkernel/intern/mesh_convert.cc | 7 +- .../geometry/intern/realize_instances.cc | 39 +- .../legacy/node_geo_legacy_curve_endpoints.cc | 10 +- .../legacy/node_geo_legacy_curve_reverse.cc | 6 +- ..._geo_legacy_curve_select_by_handle_type.cc | 5 +- .../node_geo_legacy_curve_set_handles.cc | 6 +- .../node_geo_legacy_curve_spline_type.cc | 16 +- .../legacy/node_geo_legacy_curve_subdivide.cc | 6 +- .../legacy/node_geo_legacy_curve_to_points.cc | 10 +- .../legacy/node_geo_legacy_delete_geometry.cc | 4 +- .../legacy/node_geo_legacy_mesh_to_curve.cc | 2 +- .../geometry/nodes/node_geo_convex_hull.cc | 12 +- .../node_geo_curve_endpoint_selection.cc | 7 +- .../geometry/nodes/node_geo_curve_fill.cc | 7 +- .../geometry/nodes/node_geo_curve_fillet.cc | 6 +- .../node_geo_curve_handle_type_selection.cc | 4 +- .../geometry/nodes/node_geo_curve_length.cc | 4 +- .../nodes/node_geo_curve_primitive_arc.cc | 4 +- ...node_geo_curve_primitive_bezier_segment.cc | 2 +- .../nodes/node_geo_curve_primitive_circle.cc | 2 +- .../nodes/node_geo_curve_primitive_line.cc | 2 +- ...de_geo_curve_primitive_quadratic_bezier.cc | 2 +- .../node_geo_curve_primitive_quadrilateral.cc | 2 +- .../nodes/node_geo_curve_primitive_spiral.cc | 2 +- .../nodes/node_geo_curve_primitive_star.cc | 2 +- .../geometry/nodes/node_geo_curve_resample.cc | 4 +- .../geometry/nodes/node_geo_curve_reverse.cc | 6 +- .../geometry/nodes/node_geo_curve_sample.cc | 8 +- .../nodes/node_geo_curve_set_handles.cc | 6 +- .../nodes/node_geo_curve_spline_parameter.cc | 14 +- .../nodes/node_geo_curve_spline_type.cc | 21 +- .../nodes/node_geo_curve_subdivide.cc | 6 +- .../geometry/nodes/node_geo_curve_to_mesh.cc | 8 +- .../nodes/node_geo_curve_to_points.cc | 13 +- .../geometry/nodes/node_geo_curve_trim.cc | 6 +- .../nodes/node_geo_delete_geometry.cc | 4 +- .../nodes/node_geo_duplicate_elements.cc | 24 +- .../nodes/node_geo_input_spline_length.cc | 8 +- .../geometry/nodes/node_geo_input_tangent.cc | 15 +- .../geometry/nodes/node_geo_mesh_to_curve.cc | 2 +- .../nodes/node_geo_set_curve_handles.cc | 15 +- .../nodes/node_geo_set_spline_resolution.cc | 4 +- .../nodes/node_geo_string_to_curves.cc | 3 +- .../geometry/nodes/node_geo_transform.cc | 9 +- 53 files changed, 1004 insertions(+), 327 deletions(-) create mode 100644 source/blender/blenkernel/intern/geometry_component_curves.cc 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,15 +633,57 @@ 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 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: - CurveEval *curve_ = nullptr; + Curves *curves_ = nullptr; GeometryOwnershipType ownership_ = GeometryOwnershipType::Owned; /** @@ -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 curve_eval_from_dna_curve(const Curve &curve, const ListBase &nurbs_list); std::unique_ptr curve_eval_from_dna_curve(const Curve &dna_curve); +std::unique_ptr 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 CurveEval::splines() const { @@ -336,6 +345,186 @@ std::unique_ptr 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 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 curves_to_curve_eval(const Curves &curves) +{ + CurveComponent src_component; + src_component.replace(&const_cast(curves), GeometryOwnershipType::ReadOnly); + const blender::bke::CurvesGeometry &geometry = blender::bke::CurvesGeometry::wrap( + curves.geometry); + + VArray_Span nurbs_weights{ + src_component.attribute_get_for_read("nurbs_weight", ATTR_DOMAIN_POINT, 0.0f)}; + VArray_Span nurbs_orders{ + src_component.attribute_get_for_read("nurbs_order", ATTR_DOMAIN_CURVE, 4)}; + VArray_Span nurbs_knots_modes{ + src_component.attribute_get_for_read("knots_mode", ATTR_DOMAIN_CURVE, 0)}; + + VArray_Span handle_types_right{ + src_component.attribute_get_for_read("handle_type_right", ATTR_DOMAIN_POINT, 0)}; + VArray_Span handle_types_left{ + src_component.attribute_get_for_read("handle_type_left", ATTR_DOMAIN_POINT, 0)}; + + /* Create splines with the correct size and type. */ + VArray curve_types = geometry.curve_types(); + std::unique_ptr curve_eval = std::make_unique(); + for (const int curve_index : curve_types.index_range()) { + const IndexRange point_range = geometry.range_for_curve(curve_index); + + std::unique_ptr spline; + switch (curve_types[curve_index]) { + case CURVE_TYPE_POLY: { + spline = std::make_unique(); + spline->resize(point_range.size()); + break; + } + case CURVE_TYPE_BEZIER: { + std::unique_ptr bezier_spline = std::make_unique(); + 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 nurb_spline = std::make_unique(); + 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( + 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 curve_types = geometry.curve_types(); + + OutputAttribute_Typed nurbs_weight; + OutputAttribute_Typed nurbs_order; + OutputAttribute_Typed nurbs_knots_mode; + if (curve_eval.has_spline_with_type(CURVE_TYPE_NURBS)) { + nurbs_weight = dst_component.attribute_try_get_for_output_only("nurbs_weight", + ATTR_DOMAIN_POINT); + nurbs_order = dst_component.attribute_try_get_for_output_only("nurbs_order", + ATTR_DOMAIN_CURVE); + nurbs_knots_mode = dst_component.attribute_try_get_for_output_only("knots_mode", + ATTR_DOMAIN_CURVE); + } + OutputAttribute_Typed handle_type_right; + OutputAttribute_Typed handle_type_left; + if (curve_eval.has_spline_with_type(CURVE_TYPE_BEZIER)) { + handle_type_right = dst_component.attribute_try_get_for_output_only( + "handle_type_right", ATTR_DOMAIN_POINT); + handle_type_left = dst_component.attribute_try_get_for_output_only("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(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(spline); + nurbs_knots_mode.as_span()[curve_index] = static_cast(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(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 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(); - 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(component); + CurveComponentLegacy &curve_component = static_cast(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(component); + const CurveComponentLegacy &curve_component = static_cast( + component); return curve_component.get_for_read(); } @@ -376,101 +352,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 normals) -{ - Span offsets = spline.control_point_offsets(); - Span 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 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 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 curve_normal_point_domain(const CurveEval &curve) -{ - Span splines = curve.splines(); - Array offsets = curve.control_point_offsets(); - const int total_size = offsets.last(); - Array 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(spline), spline_normals); - break; - case CURVE_TYPE_POLY: - calculate_poly_normals(static_cast(spline), spline_normals); - break; - case CURVE_TYPE_NURBS: - calculate_nurbs_normals(static_cast(spline), spline_normals); - break; - case CURVE_TYPE_CATMULL_ROM: - BLI_assert_unreachable(); - break; - } - } - }); - return normals; -} - -VArray 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 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(*splines.first()); - return VArray::ForSpan(spline.evaluated_normals()); - } - - Array normals = curve_normal_point_domain(*curve); - return VArray::ForContainer(std::move(normals)); - } - - if (domain == ATTR_DOMAIN_CURVE) { - Array point_normals = curve_normal_point_domain(*curve); - VArray varray = VArray::ForContainer(std::move(point_normals)); - return component.attribute_try_adapt_domain( - std::move(varray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); - } - - return nullptr; -} - -/** \} */ - /* -------------------------------------------------------------------- */ /** \name Builtin Spline Attributes * @@ -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 normals) +{ + Span offsets = spline.control_point_offsets(); + Span 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 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 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 curve_normal_point_domain(const CurveEval &curve) +{ + Span splines = curve.splines(); + Array offsets = curve.control_point_offsets(); + const int total_size = offsets.last(); + Array 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(spline), spline_normals); + break; + case CURVE_TYPE_POLY: + calculate_poly_normals(static_cast(spline), spline_normals); + break; + case CURVE_TYPE_NURBS: + calculate_nurbs_normals(static_cast(spline), spline_normals); + break; + case CURVE_TYPE_CATMULL_ROM: + BLI_assert_unreachable(); + break; + } + } + }); + return normals; +} + +VArray curve_normals_varray(const CurveComponent &component, const AttributeDomain domain) +{ + if (component.is_empty()) { + return nullptr; + } + const std::unique_ptr curve = curves_to_curve_eval(*component.get_for_read()); + + if (domain == ATTR_DOMAIN_POINT) { + Array normals = curve_normal_point_domain(*curve); + return VArray::ForContainer(std::move(normals)); + } + + if (domain == ATTR_DOMAIN_CURVE) { + Array point_normals = curve_normal_point_domain(*curve); + VArray varray = VArray::ForContainer(std::move(point_normals)); + return component.attribute_try_adapt_domain( + 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(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(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, + make_array_write_attribute, + 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, + make_array_write_attribute, + 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, + make_array_write_attribute, + 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, + make_array_write_attribute, + 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, + make_array_write_attribute, + 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, + make_array_write_attribute, + 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, + make_array_write_attribute, + 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, + make_array_write_attribute, + 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, + make_array_write_attribute, + 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, + make_array_write_attribute, + 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, + make_array_write_attribute, + 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, + make_array_write_attribute, + 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, + make_array_write_attribute, + 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 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(); 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(); - 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(); - 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(); return; } - if (curve == this->get_curve_for_read()) { + if (curves == this->get_curve_for_read()) { return; } this->remove(); CurveComponent &component = this->get_component_for_write(); - 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(); 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 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 order; + VectorSet order; /** Preprocessed data about every original curve. This is ordered by #order. */ Array 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(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 &r_curves) + VectorSet &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(curve), GeometryOwnershipType::ReadOnly); + component.replace(const_cast(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 dst_spline_attributes) { const RealizeCurveInfo &curve_info = *task.curve_info; - const CurveEval &curve = *curve_info.curve; + const std::unique_ptr curve = curves_to_curve_eval(*curve_info.curves); - const Span src_splines = curve.splines(); + const Span 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 dst_splines(tot_splines); - CurveEval *dst_curve = new CurveEval(); + std::unique_ptr dst_curve = std::make_unique(); 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(); - 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(); - const CurveEval &curve = *curve_component.get_for_read(); - const Span splines = curve.splines(); - curve.assert_valid_point_attributes(); + const std::unique_ptr curve = curves_to_curve_eval(*curve_component.get_for_read()); + const Span 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(); 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(); - CurveEval &curve = *curve_component.get_for_write(); - MutableSpan splines = curve.splines(); + std::unique_ptr curve = curves_to_curve_eval(*curve_component.get_for_read()); + MutableSpan splines = curve->splines(); const std::string selection_name = params.extract_input("Selection"); VArray 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(); - const CurveEval *curve = curve_component.get_for_read(); - - if (curve != nullptr) { + if (curve_component.has_curves()) { + const std::unique_ptr curve = curves_to_curve_eval(*curve_component.get_for_read()); const std::string selection_name = params.extract_input("Selection"); OutputAttribute_Typed selection = curve_component.attribute_try_get_for_output_only(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(); - CurveEval &curve = *curve_component.get_for_write(); - MutableSpan splines = curve.splines(); + std::unique_ptr curve = curves_to_curve_eval(*curve_component.get_for_read()); + MutableSpan splines = curve->splines(); const std::string selection_name = params.extract_input("Selection"); VArray 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(); - const CurveEval &curve = *curve_component->get_for_read(); + const std::unique_ptr curve = curves_to_curve_eval(*curve_component->get_for_read()); const std::string selection_name = params.extract_input("Selection"); VArray selection = curve_component->attribute_get_for_read( selection_name, ATTR_DOMAIN_CURVE, true); std::unique_ptr new_curve = std::make_unique(); - 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 output_curve = subdivide_curve(*component.get_for_read(), cuts); + std::unique_ptr 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(); - const CurveEval &curve = *curve_component.get_for_read(); - const Span splines = curve.splines(); - curve.assert_valid_point_attributes(); + const std::unique_ptr curve = curves_to_curve_eval(*curve_component.get_for_read()); + const Span splines = curve->splines(); + curve->assert_valid_point_attributes(); evaluate_splines(splines); - const Array offsets = calculate_spline_point_offsets(params, mode, curve, splines); + const Array 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(); 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 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 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 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 curve = curves_to_curve_eval( + *geometry_set.get_curve_for_read()); + for (const SplinePtr &spline : curve->splines()) { Span 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(), 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(component); - const CurveEval *curve = curve_component.get_for_read(); + if (!curve_component.has_curves()) { + return nullptr; + } + + const std::unique_ptr curve = curves_to_curve_eval(*curve_component.get_for_read()); Array 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 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 results = do_cdt(curve, output_type); + const blender::meshintersect::CDT_result 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 output_curve = fillet_curve(input_curve, fillet_param); + const std::unique_ptr input_curve = curves_to_curve_eval(*component.get_for_read()); + std::unique_ptr 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(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 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::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 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("Connect Center"), params.extract_input("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("End Handle"), std::max(params.extract_input("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("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("Middle"), params.extract_input("End"), std::max(params.extract_input("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("End Radius"), params.extract_input("Height"), params.extract_input("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("Outer Radius"), 0.0f), params.extract_input("Twist"), std::max(params.extract_input("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 resample_curve(const CurveComponent *component, const SampleModeParam &mode_param) { - const CurveEval *input_curve = component->get_for_read(); + const std::unique_ptr 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 output_curve = resample_curve( geometry_set.get_component_for_read(), 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 splines = curve.splines(); + std::unique_ptr curve = curves_to_curve_eval(*component.get_for_write()); + MutableSpan 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(); - const CurveEval *curve = curve_component->get_for_read(); + const std::unique_ptr curve = curves_to_curve_eval( + *curve_component->get_for_read()); Span 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 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(); - CurveEval &curve = *curve_component.get_for_write(); - MutableSpan splines = curve.splines(); + std::unique_ptr curve = curves_to_curve_eval(*curve_component.get_for_read()); + MutableSpan 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(component); - const CurveEval *curve = curve_component.get_for_read(); - if (curve) { + if (curve_component.has_curves()) { + const std::unique_ptr 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(component); - const CurveEval *curve = curve_component.get_for_read(); - if (curve) { + if (curve_component.has_curves()) { + std::unique_ptr 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(component); - const CurveEval *curve = curve_component.get_for_read(); - if (curve) { + if (curve_component.has_curves()) { + const std::unique_ptr 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(); - const CurveEval &curve = *curve_component->get_for_read(); + const std::unique_ptr 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 src_splines = curve->splines(); + fn::FieldEvaluator selection_evaluator{field_context, domain_size}; selection_evaluator.add(selection_field); selection_evaluator.evaluate(); const VArray &selection = selection_evaluator.get_evaluated(0); std::unique_ptr new_curve = std::make_unique(); - 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 output_curve = subdivide_curve(*component.get_for_read(), cuts); - geometry_set.replace_curve(output_curve.release()); + std::unique_ptr 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 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 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 splines = curve.splines(); - curve.assert_valid_point_attributes(); + const std::unique_ptr curve = curves_to_curve_eval( + *geometry_set.get_curve_for_read()); + const Span splines = curve->splines(); + curve->assert_valid_point_attributes(); - const Array offsets = calculate_spline_point_offsets(params, mode, curve, splines); + const Array 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(); 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 &starts = evaluator.get_evaluated(0); const blender::VArray &ends = evaluator.get_evaluated(1); - CurveEval &curve = *geometry_set.get_curve_for_write(); - MutableSpan splines = curve.splines(); + std::unique_ptr curve = curves_to_curve_eval(*geometry_set.get_curve_for_read()); + MutableSpan 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 &selection = selection_evaluator.get_evaluated(0); std::unique_ptr 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 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 control_point_offsets = curve.control_point_offsets(); + Array control_point_offsets = curve->control_point_offsets(); Array point_mapping(dst_points_size); std::unique_ptr new_curve = std::make_unique(); @@ -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 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 offsets = accumulate_counts_to_offsets(selection, counts); CurveComponent &curve_component = geometry_set.get_component_for_write(); - const CurveEval &curve = *geometry_set.get_curve_for_read(); - Array control_point_offsets = curve.control_point_offsets(); + const std::unique_ptr curve = curves_to_curve_eval( + *geometry_set.get_curve_for_read()); + Array control_point_offsets = curve->control_point_offsets(); std::unique_ptr new_curve = std::make_unique(); Array 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 spline = std::make_unique(); @@ -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 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 curve = curves_to_curve_eval(*component.get_for_read()); Span splines = curve->splines(); auto length_fn = [splines](int i) { return splines[i]->length(); }; @@ -76,10 +76,10 @@ class SplineLengthFieldInput final : public GeometryFieldInput { static VArray 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 curve = curves_to_curve_eval(*component.get_for_read()); Span 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 curve_tangent_point_domain(const CurveEval &curve) static VArray 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 curve = curves_to_curve_eval(*component.get_for_read()); if (domain == ATTR_DOMAIN_POINT) { - const Span 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(*splines.first()); - return VArray::ForSpan(spline.evaluated_tangents()); - } - Array tangents = curve_tangent_point_domain(*curve); return VArray::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 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 &selection_field, const Field &position_field, const Field &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(&component); - CurveEval *curve = curve_component.get_for_write(); + std::unique_ptr 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 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(), 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 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 create_curve_instances(GeoNodeExecParams ¶ms, 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 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 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);