diff options
53 files changed, 1004 insertions, 327 deletions
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index d93b3ca95e7..f11bfb7692a 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -24,6 +24,7 @@ #include "FN_field.hh" +struct Curves; struct Collection; struct Curve; struct CurveEval; @@ -415,7 +416,7 @@ struct GeometrySet { * Create a new geometry set that only contains the given curve. */ static GeometrySet create_with_curve( - CurveEval *curve, GeometryOwnershipType ownership = GeometryOwnershipType::Owned); + Curves *curves, GeometryOwnershipType ownership = GeometryOwnershipType::Owned); /* Utility methods for access. */ /** @@ -462,7 +463,7 @@ struct GeometrySet { /** * Returns a read-only curve or null. */ - const CurveEval *get_curve_for_read() const; + const Curves *get_curve_for_read() const; /** * Returns a mutable mesh or null. No ownership is transferred. @@ -479,7 +480,7 @@ struct GeometrySet { /** * Returns a mutable curve or null. No ownership is transferred. */ - CurveEval *get_curve_for_write(); + Curves *get_curve_for_write(); /* Utility methods for replacement. */ /** @@ -499,7 +500,7 @@ struct GeometrySet { /** * Clear the existing curve and replace it with the given one. */ - void replace_curve(CurveEval *curve, + void replace_curve(Curves *curves, GeometryOwnershipType ownership = GeometryOwnershipType::Owned); private: @@ -632,17 +633,59 @@ class PointCloudComponent : public GeometryComponent { }; /** - * A geometry component that stores curve data, in other words, a group of splines. - * Curves are stored differently than other geometry components, because the data structure used - * here does not correspond exactly to the #Curve DNA data structure. A #CurveEval is stored here - * instead, though the component does give access to a #Curve for interfacing with render engines - * and other areas of Blender that expect to use a data-block with an #ID. + * Legacy runtime-only curves type. + * These curves are stored differently than other geometry components, because the data structure + * used here does not correspond exactly to the #Curve DNA data structure. A #CurveEval is stored + * here instead, though the component does give access to a #Curve for interfacing with render + * engines and other areas of Blender that expect to use a data-block with an #ID. */ -class CurveComponent : public GeometryComponent { +class CurveComponentLegacy : public GeometryComponent { private: CurveEval *curve_ = nullptr; GeometryOwnershipType ownership_ = GeometryOwnershipType::Owned; + public: + CurveComponentLegacy(); + ~CurveComponentLegacy(); + GeometryComponent *copy() const override; + + void clear(); + bool has_curve() const; + /** + * Clear the component and replace it with the new curve. + */ + void replace(CurveEval *curve, GeometryOwnershipType ownership = GeometryOwnershipType::Owned); + CurveEval *release(); + + const CurveEval *get_for_read() const; + CurveEval *get_for_write(); + + int attribute_domain_size(AttributeDomain domain) const final; + + bool is_empty() const final; + + bool owns_direct_data() const override; + void ensure_owns_direct_data() override; + + static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_CURVE; + + private: + const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final; + + blender::fn::GVArray attribute_try_adapt_domain_impl(const blender::fn::GVArray &varray, + AttributeDomain from_domain, + AttributeDomain to_domain) const final; +}; + +/** + * A geometry component that stores a group of curves, corresponding the the #Curves and + * #CurvesGeometry types. + */ +class CurveComponent : public GeometryComponent { + private: + Curves *curves_ = nullptr; + GeometryOwnershipType ownership_ = GeometryOwnershipType::Owned; + /** * Curve data necessary to hold the draw cache for rendering, consistent over multiple redraws. * This is necessary because Blender assumes that objects evaluate to an object data type, and @@ -658,15 +701,15 @@ class CurveComponent : public GeometryComponent { GeometryComponent *copy() const override; void clear(); - bool has_curve() const; + bool has_curves() const; /** * Clear the component and replace it with the new curve. */ - void replace(CurveEval *curve, GeometryOwnershipType ownership = GeometryOwnershipType::Owned); - CurveEval *release(); + void replace(Curves *curve, GeometryOwnershipType ownership = GeometryOwnershipType::Owned); + Curves *release(); - const CurveEval *get_for_read() const; - CurveEval *get_for_write(); + const Curves *get_for_read() const; + Curves *get_for_write(); int attribute_domain_size(AttributeDomain domain) const final; diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh index 439f20ee471..42b4702ee44 100644 --- a/source/blender/blenkernel/BKE_spline.hh +++ b/source/blender/blenkernel/BKE_spline.hh @@ -20,6 +20,7 @@ #include "BKE_attribute_math.hh" struct Curve; +struct Curves; struct ListBase; class Spline; @@ -691,3 +692,5 @@ struct CurveEval { std::unique_ptr<CurveEval> curve_eval_from_dna_curve(const Curve &curve, const ListBase &nurbs_list); std::unique_ptr<CurveEval> curve_eval_from_dna_curve(const Curve &dna_curve); +std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves); +Curves *curve_eval_to_curves(const CurveEval &curve_eval); diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 2b77b2c5dae..a12a956cbf5 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -131,6 +131,7 @@ set(SRC intern/fmodifier.c intern/freestyle.c intern/geometry_component_curve.cc + intern/geometry_component_curves.cc intern/geometry_component_instances.cc intern/geometry_component_mesh.cc intern/geometry_component_pointcloud.cc diff --git a/source/blender/blenkernel/intern/curve.cc b/source/blender/blenkernel/intern/curve.cc index b0f58dd4ec9..6be04b79761 100644 --- a/source/blender/blenkernel/intern/curve.cc +++ b/source/blender/blenkernel/intern/curve.cc @@ -115,6 +115,8 @@ static void curve_free_data(ID *id) MEM_SAFE_FREE(curve->str); MEM_SAFE_FREE(curve->strinfo); MEM_SAFE_FREE(curve->tb); + + delete curve->curve_eval; } static void curve_foreach_id(ID *id, LibraryForeachIDData *data) diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc index 8529e7ad194..78dafe34b4f 100644 --- a/source/blender/blenkernel/intern/curve_eval.cc +++ b/source/blender/blenkernel/intern/curve_eval.cc @@ -13,6 +13,8 @@ #include "BKE_anonymous_attribute.hh" #include "BKE_curve.h" +#include "BKE_curves.hh" +#include "BKE_geometry_set.hh" #include "BKE_spline.hh" using blender::Array; @@ -23,8 +25,15 @@ using blender::Map; using blender::MutableSpan; using blender::Span; using blender::StringRefNull; +using blender::VArray; +using blender::VArray_Span; using blender::Vector; using blender::bke::AttributeIDRef; +using blender::bke::OutputAttribute; +using blender::bke::OutputAttribute_Typed; +using blender::bke::ReadAttributeLookup; +using blender::fn::GVArray; +using blender::fn::GVArray_GSpan; blender::Span<SplinePtr> CurveEval::splines() const { @@ -336,6 +345,186 @@ std::unique_ptr<CurveEval> curve_eval_from_dna_curve(const Curve &dna_curve) return curve_eval_from_dna_curve(dna_curve, *BKE_curve_nurbs_get_for_read(&dna_curve)); } +static void copy_attributes_between_components(const GeometryComponent &src_component, + GeometryComponent &dst_component, + Span<std::string> skip) +{ + src_component.attribute_foreach( + [&](const AttributeIDRef &id, const AttributeMetaData meta_data) { + if (id.is_named() && skip.contains(id.name())) { + return true; + } + + GVArray src_attribute = src_component.attribute_try_get_for_read( + id, meta_data.domain, meta_data.data_type); + if (!src_attribute) { + return true; + } + GVArray_GSpan src_attribute_data{src_attribute}; + + OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only( + id, meta_data.domain, meta_data.data_type); + if (!dst_attribute) { + return true; + } + dst_attribute.varray().set_all(src_attribute_data.data()); + dst_attribute.save(); + return true; + }); +} + +std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves) +{ + CurveComponent src_component; + src_component.replace(&const_cast<Curves &>(curves), GeometryOwnershipType::ReadOnly); + const blender::bke::CurvesGeometry &geometry = blender::bke::CurvesGeometry::wrap( + curves.geometry); + + VArray_Span<float> nurbs_weights{ + src_component.attribute_get_for_read<float>("nurbs_weight", ATTR_DOMAIN_POINT, 0.0f)}; + VArray_Span<int> nurbs_orders{ + src_component.attribute_get_for_read<int>("nurbs_order", ATTR_DOMAIN_CURVE, 4)}; + VArray_Span<int8_t> nurbs_knots_modes{ + src_component.attribute_get_for_read<int8_t>("knots_mode", ATTR_DOMAIN_CURVE, 0)}; + + VArray_Span<int8_t> handle_types_right{ + src_component.attribute_get_for_read<int8_t>("handle_type_right", ATTR_DOMAIN_POINT, 0)}; + VArray_Span<int8_t> handle_types_left{ + src_component.attribute_get_for_read<int8_t>("handle_type_left", ATTR_DOMAIN_POINT, 0)}; + + /* Create splines with the correct size and type. */ + VArray<int8_t> curve_types = geometry.curve_types(); + std::unique_ptr<CurveEval> curve_eval = std::make_unique<CurveEval>(); + for (const int curve_index : curve_types.index_range()) { + const IndexRange point_range = geometry.range_for_curve(curve_index); + + std::unique_ptr<Spline> spline; + switch (curve_types[curve_index]) { + case CURVE_TYPE_POLY: { + spline = std::make_unique<PolySpline>(); + spline->resize(point_range.size()); + break; + } + case CURVE_TYPE_BEZIER: { + std::unique_ptr<BezierSpline> bezier_spline = std::make_unique<BezierSpline>(); + bezier_spline->resize(point_range.size()); + bezier_spline->handle_types_left().copy_from(handle_types_left.slice(point_range)); + bezier_spline->handle_types_right().copy_from(handle_types_right.slice(point_range)); + + spline = std::move(bezier_spline); + break; + } + case CURVE_TYPE_NURBS: { + std::unique_ptr<NURBSpline> nurb_spline = std::make_unique<NURBSpline>(); + nurb_spline->resize(point_range.size()); + nurb_spline->weights().copy_from(nurbs_weights.slice(point_range)); + nurb_spline->set_order(nurbs_orders[curve_index]); + nurb_spline->knots_mode = static_cast<NURBSpline::KnotsMode>( + nurbs_knots_modes[curve_index]); + + spline = std::move(nurb_spline); + break; + } + case CURVE_TYPE_CATMULL_ROM: + /* Not supported yet. */ + BLI_assert_unreachable(); + continue; + } + spline->positions().fill(float3(0)); + spline->tilts().fill(0.0f); + spline->radii().fill(0.0f); + curve_eval->add_spline(std::move(spline)); + } + + CurveComponentLegacy dst_component; + dst_component.replace(curve_eval.get(), GeometryOwnershipType::Editable); + + copy_attributes_between_components(src_component, + dst_component, + {"curve_type", + "nurbs_weight", + "nurbs_order", + "knots_mode", + "handle_type_right", + "handle_type_left"}); + + return curve_eval; +} + +Curves *curve_eval_to_curves(const CurveEval &curve_eval) +{ + Curves *curves = blender::bke::curves_new_nomain(curve_eval.total_control_point_size(), + curve_eval.splines().size()); + CurveComponent dst_component; + dst_component.replace(curves, GeometryOwnershipType::Editable); + + blender::bke::CurvesGeometry &geometry = blender::bke::CurvesGeometry::wrap(curves->geometry); + geometry.offsets().copy_from(curve_eval.control_point_offsets()); + MutableSpan<int8_t> curve_types = geometry.curve_types(); + + OutputAttribute_Typed<float> nurbs_weight; + OutputAttribute_Typed<int> nurbs_order; + OutputAttribute_Typed<int8_t> nurbs_knots_mode; + if (curve_eval.has_spline_with_type(CURVE_TYPE_NURBS)) { + nurbs_weight = dst_component.attribute_try_get_for_output_only<float>("nurbs_weight", + ATTR_DOMAIN_POINT); + nurbs_order = dst_component.attribute_try_get_for_output_only<int>("nurbs_order", + ATTR_DOMAIN_CURVE); + nurbs_knots_mode = dst_component.attribute_try_get_for_output_only<int8_t>("knots_mode", + ATTR_DOMAIN_CURVE); + } + OutputAttribute_Typed<int8_t> handle_type_right; + OutputAttribute_Typed<int8_t> handle_type_left; + if (curve_eval.has_spline_with_type(CURVE_TYPE_BEZIER)) { + handle_type_right = dst_component.attribute_try_get_for_output_only<int8_t>( + "handle_type_right", ATTR_DOMAIN_POINT); + handle_type_left = dst_component.attribute_try_get_for_output_only<int8_t>("handle_type_left", + ATTR_DOMAIN_POINT); + } + + for (const int curve_index : curve_eval.splines().index_range()) { + const Spline &spline = *curve_eval.splines()[curve_index]; + curve_types[curve_index] = curve_eval.splines()[curve_index]->type(); + + const IndexRange point_range = geometry.range_for_curve(curve_index); + + switch (spline.type()) { + case CURVE_TYPE_POLY: + break; + case CURVE_TYPE_BEZIER: { + const BezierSpline &src = static_cast<const BezierSpline &>(spline); + handle_type_right.as_span().slice(point_range).copy_from(src.handle_types_right()); + handle_type_left.as_span().slice(point_range).copy_from(src.handle_types_left()); + break; + } + case CURVE_TYPE_NURBS: { + const NURBSpline &src = static_cast<const NURBSpline &>(spline); + nurbs_knots_mode.as_span()[curve_index] = static_cast<int8_t>(src.knots_mode); + nurbs_order.as_span()[curve_index] = src.order(); + nurbs_weight.as_span().slice(point_range).copy_from(src.weights()); + break; + } + case CURVE_TYPE_CATMULL_ROM: { + BLI_assert_unreachable(); + break; + } + } + } + + nurbs_weight.save(); + nurbs_order.save(); + nurbs_knots_mode.save(); + handle_type_right.save(); + handle_type_left.save(); + + CurveComponentLegacy src_component; + src_component.replace(&const_cast<CurveEval &>(curve_eval), GeometryOwnershipType::ReadOnly); + + copy_attributes_between_components(src_component, dst_component, {}); + + return curves; +} + void CurveEval::assert_valid_point_attributes() const { #ifdef DEBUG diff --git a/source/blender/blenkernel/intern/displist.cc b/source/blender/blenkernel/intern/displist.cc index 5c761e94bb9..97445851ffa 100644 --- a/source/blender/blenkernel/intern/displist.cc +++ b/source/blender/blenkernel/intern/displist.cc @@ -865,7 +865,7 @@ static GeometrySet curve_calc_modifiers_post(Depsgraph *depsgraph, else { std::unique_ptr<CurveEval> curve_eval = curve_eval_from_dna_curve( *cu, ob->runtime.curve_cache->deformed_nurbs); - geometry_set.replace_curve(curve_eval.release()); + geometry_set.replace_curve(curve_eval_to_curves(*curve_eval)); } for (; md; md = md->next) { @@ -1497,7 +1497,7 @@ void BKE_displist_make_curveTypes(Depsgraph *depsgraph, * the CurveEval data type was introduced, when an evaluated object's curve data was just a * copy of the original curve and everything else ended up in #CurveCache. */ CurveComponent &curve_component = geometry.get_component_for_write<CurveComponent>(); - cow_curve.curve_eval = curve_component.get_for_write(); + cow_curve.curve_eval = curves_to_curve_eval(*curve_component.get_for_read()).release(); BKE_object_eval_assign_data(ob, &cow_curve.id, false); } diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc index c22b6ff07ec..0926d65b306 100644 --- a/source/blender/blenkernel/intern/geometry_component_curve.cc +++ b/source/blender/blenkernel/intern/geometry_component_curve.cc @@ -23,18 +23,18 @@ using blender::fn::GVArray_GSpan; /** \name Geometry Component Implementation * \{ */ -CurveComponent::CurveComponent() : GeometryComponent(GEO_COMPONENT_TYPE_CURVE) +CurveComponentLegacy::CurveComponentLegacy() : GeometryComponent(GEO_COMPONENT_TYPE_CURVE) { } -CurveComponent::~CurveComponent() +CurveComponentLegacy::~CurveComponentLegacy() { this->clear(); } -GeometryComponent *CurveComponent::copy() const +GeometryComponent *CurveComponentLegacy::copy() const { - CurveComponent *new_component = new CurveComponent(); + CurveComponentLegacy *new_component = new CurveComponentLegacy(); if (curve_ != nullptr) { new_component->curve_ = new CurveEval(*curve_); new_component->ownership_ = GeometryOwnershipType::Owned; @@ -42,30 +42,23 @@ GeometryComponent *CurveComponent::copy() const return new_component; } -void CurveComponent::clear() +void CurveComponentLegacy::clear() { BLI_assert(this->is_mutable()); if (curve_ != nullptr) { if (ownership_ == GeometryOwnershipType::Owned) { delete curve_; } - if (curve_for_render_ != nullptr) { - /* The curve created by this component should not have any edit mode data. */ - BLI_assert(curve_for_render_->editfont == nullptr && curve_for_render_->editnurb == nullptr); - BKE_id_free(nullptr, curve_for_render_); - curve_for_render_ = nullptr; - } - curve_ = nullptr; } } -bool CurveComponent::has_curve() const +bool CurveComponentLegacy::has_curve() const { return curve_ != nullptr; } -void CurveComponent::replace(CurveEval *curve, GeometryOwnershipType ownership) +void CurveComponentLegacy::replace(CurveEval *curve, GeometryOwnershipType ownership) { BLI_assert(this->is_mutable()); this->clear(); @@ -73,7 +66,7 @@ void CurveComponent::replace(CurveEval *curve, GeometryOwnershipType ownership) ownership_ = ownership; } -CurveEval *CurveComponent::release() +CurveEval *CurveComponentLegacy::release() { BLI_assert(this->is_mutable()); CurveEval *curve = curve_; @@ -81,12 +74,12 @@ CurveEval *CurveComponent::release() return curve; } -const CurveEval *CurveComponent::get_for_read() const +const CurveEval *CurveComponentLegacy::get_for_read() const { return curve_; } -CurveEval *CurveComponent::get_for_write() +CurveEval *CurveComponentLegacy::get_for_write() { BLI_assert(this->is_mutable()); if (ownership_ == GeometryOwnershipType::ReadOnly) { @@ -96,17 +89,17 @@ CurveEval *CurveComponent::get_for_write() return curve_; } -bool CurveComponent::is_empty() const +bool CurveComponentLegacy::is_empty() const { return curve_ == nullptr; } -bool CurveComponent::owns_direct_data() const +bool CurveComponentLegacy::owns_direct_data() const { return ownership_ == GeometryOwnershipType::Owned; } -void CurveComponent::ensure_owns_direct_data() +void CurveComponentLegacy::ensure_owns_direct_data() { BLI_assert(this->is_mutable()); if (ownership_ != GeometryOwnershipType::Owned) { @@ -115,32 +108,13 @@ void CurveComponent::ensure_owns_direct_data() } } -const Curve *CurveComponent::get_curve_for_render() const -{ - if (curve_ == nullptr) { - return nullptr; - } - if (curve_for_render_ != nullptr) { - return curve_for_render_; - } - std::lock_guard lock{curve_for_render_mutex_}; - if (curve_for_render_ != nullptr) { - return curve_for_render_; - } - - curve_for_render_ = (Curve *)BKE_id_new_nomain(ID_CU_LEGACY, nullptr); - curve_for_render_->curve_eval = curve_; - - return curve_for_render_; -} - /** \} */ /* -------------------------------------------------------------------- */ /** \name Attribute Access Helper Functions * \{ */ -int CurveComponent::attribute_domain_size(const AttributeDomain domain) const +int CurveComponentLegacy::attribute_domain_size(const AttributeDomain domain) const { if (curve_ == nullptr) { return 0; @@ -334,9 +308,10 @@ static GVArray adapt_curve_domain_spline_to_point(const CurveEval &curve, GVArra } // namespace blender::bke -GVArray CurveComponent::attribute_try_adapt_domain_impl(const GVArray &varray, - const AttributeDomain from_domain, - const AttributeDomain to_domain) const +GVArray CurveComponentLegacy::attribute_try_adapt_domain_impl( + const GVArray &varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const { if (!varray) { return {}; @@ -361,14 +336,15 @@ GVArray CurveComponent::attribute_try_adapt_domain_impl(const GVArray &varray, static CurveEval *get_curve_from_component_for_write(GeometryComponent &component) { BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE); - CurveComponent &curve_component = static_cast<CurveComponent &>(component); + CurveComponentLegacy &curve_component = static_cast<CurveComponentLegacy &>(component); return curve_component.get_for_write(); } static const CurveEval *get_curve_from_component_for_read(const GeometryComponent &component) { BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE); - const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); + const CurveComponentLegacy &curve_component = static_cast<const CurveComponentLegacy &>( + component); return curve_component.get_for_read(); } @@ -377,101 +353,6 @@ static const CurveEval *get_curve_from_component_for_read(const GeometryComponen namespace blender::bke { /* -------------------------------------------------------------------- */ -/** \name Curve Normals Access - * \{ */ - -static void calculate_bezier_normals(const BezierSpline &spline, MutableSpan<float3> normals) -{ - Span<int> offsets = spline.control_point_offsets(); - Span<float3> evaluated_normals = spline.evaluated_normals(); - for (const int i : IndexRange(spline.size())) { - normals[i] = evaluated_normals[offsets[i]]; - } -} - -static void calculate_poly_normals(const PolySpline &spline, MutableSpan<float3> normals) -{ - normals.copy_from(spline.evaluated_normals()); -} - -/** - * Because NURBS control points are not necessarily on the path, the normal at the control points - * is not well defined, so create a temporary poly spline to find the normals. This requires extra - * copying currently, but may be more efficient in the future if attributes have some form of CoW. - */ -static void calculate_nurbs_normals(const NURBSpline &spline, MutableSpan<float3> normals) -{ - PolySpline poly_spline; - poly_spline.resize(spline.size()); - poly_spline.positions().copy_from(spline.positions()); - poly_spline.tilts().copy_from(spline.tilts()); - normals.copy_from(poly_spline.evaluated_normals()); -} - -static Array<float3> curve_normal_point_domain(const CurveEval &curve) -{ - Span<SplinePtr> splines = curve.splines(); - Array<int> offsets = curve.control_point_offsets(); - const int total_size = offsets.last(); - Array<float3> normals(total_size); - - threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) { - for (const int i : range) { - const Spline &spline = *splines[i]; - MutableSpan spline_normals{normals.as_mutable_span().slice(offsets[i], spline.size())}; - switch (splines[i]->type()) { - case CURVE_TYPE_BEZIER: - calculate_bezier_normals(static_cast<const BezierSpline &>(spline), spline_normals); - break; - case CURVE_TYPE_POLY: - calculate_poly_normals(static_cast<const PolySpline &>(spline), spline_normals); - break; - case CURVE_TYPE_NURBS: - calculate_nurbs_normals(static_cast<const NURBSpline &>(spline), spline_normals); - break; - case CURVE_TYPE_CATMULL_ROM: - BLI_assert_unreachable(); - break; - } - } - }); - return normals; -} - -VArray<float3> curve_normals_varray(const CurveComponent &component, const AttributeDomain domain) -{ - const CurveEval *curve = component.get_for_read(); - if (curve == nullptr) { - return nullptr; - } - - if (domain == ATTR_DOMAIN_POINT) { - const Span<SplinePtr> splines = curve->splines(); - - /* Use a reference to evaluated normals if possible to avoid an allocation and a copy. - * This is only possible when there is only one poly spline. */ - if (splines.size() == 1 && splines.first()->type() == CURVE_TYPE_POLY) { - const PolySpline &spline = static_cast<PolySpline &>(*splines.first()); - return VArray<float3>::ForSpan(spline.evaluated_normals()); - } - - Array<float3> normals = curve_normal_point_domain(*curve); - return VArray<float3>::ForContainer(std::move(normals)); - } - - if (domain == ATTR_DOMAIN_CURVE) { - Array<float3> point_normals = curve_normal_point_domain(*curve); - VArray<float3> varray = VArray<float3>::ForContainer(std::move(point_normals)); - return component.attribute_try_adapt_domain<float3>( - std::move(varray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); - } - - return nullptr; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Builtin Spline Attributes * * Attributes with a value for every spline, stored contiguously or in every spline separately. @@ -1306,7 +1187,8 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider { private: static constexpr uint64_t supported_types_mask = CD_MASK_PROP_FLOAT | CD_MASK_PROP_FLOAT2 | CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 | - CD_MASK_PROP_COLOR | CD_MASK_PROP_BOOL; + CD_MASK_PROP_COLOR | CD_MASK_PROP_BOOL | + CD_MASK_PROP_INT8; public: ReadAttributeLookup try_get_for_read(const GeometryComponent &component, @@ -1551,7 +1433,8 @@ static ComponentAttributeProviders create_attribute_providers_for_curve() } // namespace blender::bke -const blender::bke::ComponentAttributeProviders *CurveComponent::get_attribute_providers() const +const blender::bke::ComponentAttributeProviders *CurveComponentLegacy::get_attribute_providers() + const { static blender::bke::ComponentAttributeProviders providers = blender::bke::create_attribute_providers_for_curve(); diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc new file mode 100644 index 00000000000..e32dd852e0e --- /dev/null +++ b/source/blender/blenkernel/intern/geometry_component_curves.cc @@ -0,0 +1,521 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_task.hh" + +#include "DNA_ID_enums.h" +#include "DNA_curve_types.h" + +#include "BKE_attribute_access.hh" +#include "BKE_attribute_math.hh" +#include "BKE_curve.h" +#include "BKE_curves.hh" +#include "BKE_geometry_set.hh" +#include "BKE_lib_id.h" +#include "BKE_spline.hh" + +#include "attribute_access_intern.hh" + +using blender::fn::GVArray; + +/* -------------------------------------------------------------------- */ +/** \name Geometry Component Implementation + * \{ */ + +CurveComponent::CurveComponent() : GeometryComponent(GEO_COMPONENT_TYPE_CURVE) +{ +} + +CurveComponent::~CurveComponent() +{ + this->clear(); +} + +GeometryComponent *CurveComponent::copy() const +{ + CurveComponent *new_component = new CurveComponent(); + if (curves_ != nullptr) { + new_component->curves_ = BKE_curves_copy_for_eval(curves_, false); + new_component->ownership_ = GeometryOwnershipType::Owned; + } + return new_component; +} + +void CurveComponent::clear() +{ + BLI_assert(this->is_mutable()); + if (curves_ != nullptr) { + if (ownership_ == GeometryOwnershipType::Owned) { + BKE_id_free(nullptr, curves_); + } + if (curve_for_render_ != nullptr) { + /* The curve created by this component should not have any edit mode data. */ + BLI_assert(curve_for_render_->editfont == nullptr && curve_for_render_->editnurb == nullptr); + BKE_id_free(nullptr, curve_for_render_); + curve_for_render_ = nullptr; + } + + curves_ = nullptr; + } +} + +bool CurveComponent::has_curves() const +{ + return curves_ != nullptr; +} + +void CurveComponent::replace(Curves *curves, GeometryOwnershipType ownership) +{ + BLI_assert(this->is_mutable()); + this->clear(); + curves_ = curves; + ownership_ = ownership; +} + +Curves *CurveComponent::release() +{ + BLI_assert(this->is_mutable()); + Curves *curves = curves_; + curves_ = nullptr; + return curves; +} + +const Curves *CurveComponent::get_for_read() const +{ + return curves_; +} + +Curves *CurveComponent::get_for_write() +{ + BLI_assert(this->is_mutable()); + if (ownership_ == GeometryOwnershipType::ReadOnly) { + curves_ = BKE_curves_copy_for_eval(curves_, false); + ownership_ = GeometryOwnershipType::Owned; + } + return curves_; +} + +bool CurveComponent::is_empty() const +{ + return curves_ == nullptr; +} + +bool CurveComponent::owns_direct_data() const +{ + return ownership_ == GeometryOwnershipType::Owned; +} + +void CurveComponent::ensure_owns_direct_data() +{ + BLI_assert(this->is_mutable()); + if (ownership_ != GeometryOwnershipType::Owned) { + curves_ = BKE_curves_copy_for_eval(curves_, false); + ownership_ = GeometryOwnershipType::Owned; + } +} + +const Curve *CurveComponent::get_curve_for_render() const +{ + if (curves_ == nullptr) { + return nullptr; + } + if (curve_for_render_ != nullptr) { + return curve_for_render_; + } + std::lock_guard lock{curve_for_render_mutex_}; + if (curve_for_render_ != nullptr) { + return curve_for_render_; + } + + curve_for_render_ = (Curve *)BKE_id_new_nomain(ID_CU_LEGACY, nullptr); + curve_for_render_->curve_eval = curves_to_curve_eval(*curves_).release(); + + return curve_for_render_; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Curve Normals Access + * \{ */ + +namespace blender::bke { + +static void calculate_bezier_normals(const BezierSpline &spline, MutableSpan<float3> normals) +{ + Span<int> offsets = spline.control_point_offsets(); + Span<float3> evaluated_normals = spline.evaluated_normals(); + for (const int i : IndexRange(spline.size())) { + normals[i] = evaluated_normals[offsets[i]]; + } +} + +static void calculate_poly_normals(const PolySpline &spline, MutableSpan<float3> normals) +{ + normals.copy_from(spline.evaluated_normals()); +} + +/** + * Because NURBS control points are not necessarily on the path, the normal at the control points + * is not well defined, so create a temporary poly spline to find the normals. This requires extra + * copying currently, but may be more efficient in the future if attributes have some form of CoW. + */ +static void calculate_nurbs_normals(const NURBSpline &spline, MutableSpan<float3> normals) +{ + PolySpline poly_spline; + poly_spline.resize(spline.size()); + poly_spline.positions().copy_from(spline.positions()); + poly_spline.tilts().copy_from(spline.tilts()); + normals.copy_from(poly_spline.evaluated_normals()); +} + +static Array<float3> curve_normal_point_domain(const CurveEval &curve) +{ + Span<SplinePtr> splines = curve.splines(); + Array<int> offsets = curve.control_point_offsets(); + const int total_size = offsets.last(); + Array<float3> normals(total_size); + + threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) { + for (const int i : range) { + const Spline &spline = *splines[i]; + MutableSpan spline_normals{normals.as_mutable_span().slice(offsets[i], spline.size())}; + switch (splines[i]->type()) { + case CURVE_TYPE_BEZIER: + calculate_bezier_normals(static_cast<const BezierSpline &>(spline), spline_normals); + break; + case CURVE_TYPE_POLY: + calculate_poly_normals(static_cast<const PolySpline &>(spline), spline_normals); + break; + case CURVE_TYPE_NURBS: + calculate_nurbs_normals(static_cast<const NURBSpline &>(spline), spline_normals); + break; + case CURVE_TYPE_CATMULL_ROM: + BLI_assert_unreachable(); + break; + } + } + }); + return normals; +} + +VArray<float3> curve_normals_varray(const CurveComponent &component, const AttributeDomain domain) +{ + if (component.is_empty()) { + return nullptr; + } + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_read()); + + if (domain == ATTR_DOMAIN_POINT) { + Array<float3> normals = curve_normal_point_domain(*curve); + return VArray<float3>::ForContainer(std::move(normals)); + } + + if (domain == ATTR_DOMAIN_CURVE) { + Array<float3> point_normals = curve_normal_point_domain(*curve); + VArray<float3> varray = VArray<float3>::ForContainer(std::move(point_normals)); + return component.attribute_try_adapt_domain<float3>( + std::move(varray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); + } + + return nullptr; +} + +} // namespace blender::bke + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Attribute Access Helper Functions + * \{ */ + +int CurveComponent::attribute_domain_size(const AttributeDomain domain) const +{ + if (curves_ == nullptr) { + return 0; + } + const blender::bke::CurvesGeometry &geometry = blender::bke::CurvesGeometry::wrap( + curves_->geometry); + if (domain == ATTR_DOMAIN_POINT) { + return geometry.points_size(); + } + if (domain == ATTR_DOMAIN_CURVE) { + return geometry.curves_size(); + } + return 0; +} + +GVArray CurveComponent::attribute_try_adapt_domain_impl(const GVArray &varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const +{ + return blender::bke::CurvesGeometry::wrap(curves_->geometry) + .adapt_domain(varray, from_domain, to_domain); +} + +static Curves *get_curves_from_component_for_write(GeometryComponent &component) +{ + BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE); + CurveComponent &curve_component = static_cast<CurveComponent &>(component); + return curve_component.get_for_write(); +} + +static const Curves *get_curves_from_component_for_read(const GeometryComponent &component) +{ + BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE); + const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); + return curve_component.get_for_read(); +} + +static void tag_component_topology_changed(GeometryComponent &component) +{ + Curves *curves = get_curves_from_component_for_write(component); + if (curves) { + blender::bke::CurvesGeometry::wrap(curves->geometry).tag_topology_changed(); + } +} + +static void tag_component_positions_changed(GeometryComponent &component) +{ + Curves *curves = get_curves_from_component_for_write(component); + if (curves) { + blender::bke::CurvesGeometry::wrap(curves->geometry).tag_positions_changed(); + } +} + +static void tag_component_normals_changed(GeometryComponent &component) +{ + Curves *curves = get_curves_from_component_for_write(component); + if (curves) { + blender::bke::CurvesGeometry::wrap(curves->geometry).tag_normals_changed(); + } +} + +/** \} */ + +namespace blender::bke { + +/* -------------------------------------------------------------------- */ +/** \name Attribute Provider Declaration + * \{ */ + +/** + * In this function all the attribute providers for a curves component are created. + * Most data in this function is statically allocated, because it does not change over time. + */ +static ComponentAttributeProviders create_attribute_providers_for_curve() +{ + static CustomDataAccessInfo curve_access = { + [](GeometryComponent &component) -> CustomData * { + Curves *curves = get_curves_from_component_for_write(component); + return curves ? &curves->geometry.curve_data : nullptr; + }, + [](const GeometryComponent &component) -> const CustomData * { + const Curves *curves = get_curves_from_component_for_read(component); + return curves ? &curves->geometry.curve_data : nullptr; + }, + [](GeometryComponent &component) { + Curves *curves = get_curves_from_component_for_write(component); + if (curves) { + blender::bke::CurvesGeometry::wrap(curves->geometry).update_customdata_pointers(); + } + }}; + static CustomDataAccessInfo point_access = { + [](GeometryComponent &component) -> CustomData * { + Curves *curves = get_curves_from_component_for_write(component); + return curves ? &curves->geometry.point_data : nullptr; + }, + [](const GeometryComponent &component) -> const CustomData * { + const Curves *curves = get_curves_from_component_for_read(component); + return curves ? &curves->geometry.point_data : nullptr; + }, + [](GeometryComponent &component) { + Curves *curves = get_curves_from_component_for_write(component); + if (curves) { + blender::bke::CurvesGeometry::wrap(curves->geometry).update_customdata_pointers(); + } + }}; + + static BuiltinCustomDataLayerProvider position("position", + ATTR_DOMAIN_POINT, + CD_PROP_FLOAT3, + CD_PROP_FLOAT3, + BuiltinAttributeProvider::NonCreatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::NonDeletable, + point_access, + make_array_read_attribute<float3>, + make_array_write_attribute<float3>, + tag_component_positions_changed); + + static BuiltinCustomDataLayerProvider radius("radius", + ATTR_DOMAIN_POINT, + CD_PROP_FLOAT, + CD_PROP_FLOAT, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::Deletable, + point_access, + make_array_read_attribute<float>, + make_array_write_attribute<float>, + tag_component_normals_changed); + + static BuiltinCustomDataLayerProvider id("id", + ATTR_DOMAIN_POINT, + CD_PROP_INT32, + CD_PROP_INT32, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::Deletable, + point_access, + make_array_read_attribute<int>, + make_array_write_attribute<int>, + nullptr); + + static BuiltinCustomDataLayerProvider tilt("tilt", + ATTR_DOMAIN_POINT, + CD_PROP_FLOAT, + CD_PROP_FLOAT, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::Deletable, + point_access, + make_array_read_attribute<float>, + make_array_write_attribute<float>, + tag_component_normals_changed); + + static BuiltinCustomDataLayerProvider handle_right("handle_right", + ATTR_DOMAIN_POINT, + CD_PROP_FLOAT3, + CD_PROP_FLOAT3, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::Deletable, + point_access, + make_array_read_attribute<float3>, + make_array_write_attribute<float3>, + tag_component_positions_changed); + + static BuiltinCustomDataLayerProvider handle_left("handle_left", + ATTR_DOMAIN_POINT, + CD_PROP_FLOAT3, + CD_PROP_FLOAT3, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::Deletable, + point_access, + make_array_read_attribute<float3>, + make_array_write_attribute<float3>, + tag_component_positions_changed); + + static BuiltinCustomDataLayerProvider handle_type_right("handle_type_right", + ATTR_DOMAIN_POINT, + CD_PROP_INT8, + CD_PROP_INT8, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::Deletable, + point_access, + make_array_read_attribute<int8_t>, + make_array_write_attribute<int8_t>, + tag_component_topology_changed); + + static BuiltinCustomDataLayerProvider handle_type_left("handle_type_left", + ATTR_DOMAIN_POINT, + CD_PROP_INT8, + CD_PROP_INT8, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::Deletable, + point_access, + make_array_read_attribute<int8_t>, + make_array_write_attribute<int8_t>, + tag_component_topology_changed); + + static BuiltinCustomDataLayerProvider nurbs_weight("nurbs_weight", + ATTR_DOMAIN_POINT, + CD_PROP_FLOAT, + CD_PROP_FLOAT, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::Deletable, + point_access, + make_array_read_attribute<float>, + make_array_write_attribute<float>, + tag_component_positions_changed); + + static BuiltinCustomDataLayerProvider nurbs_order("nurbs_order", + ATTR_DOMAIN_CURVE, + CD_PROP_INT32, + CD_PROP_INT32, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::Deletable, + curve_access, + make_array_read_attribute<int>, + make_array_write_attribute<int>, + tag_component_topology_changed); + + static BuiltinCustomDataLayerProvider nurbs_knots_mode("knots_mode", + ATTR_DOMAIN_CURVE, + CD_PROP_INT8, + CD_PROP_INT8, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::Deletable, + curve_access, + make_array_read_attribute<int8_t>, + make_array_write_attribute<int8_t>, + tag_component_topology_changed); + + static BuiltinCustomDataLayerProvider resolution("resolution", + ATTR_DOMAIN_CURVE, + CD_PROP_INT32, + CD_PROP_INT32, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::Deletable, + curve_access, + make_array_read_attribute<int>, + make_array_write_attribute<int>, + tag_component_positions_changed); + + static BuiltinCustomDataLayerProvider cyclic("cyclic", + ATTR_DOMAIN_CURVE, + CD_PROP_BOOL, + CD_PROP_BOOL, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::Deletable, + curve_access, + make_array_read_attribute<bool>, + make_array_write_attribute<bool>, + tag_component_topology_changed); + + static CustomDataAttributeProvider curve_custom_data(ATTR_DOMAIN_CURVE, curve_access); + static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access); + + return ComponentAttributeProviders({&position, + &radius, + &id, + &tilt, + &handle_right, + &handle_left, + &handle_type_right, + &handle_type_left, + &nurbs_order, + &nurbs_weight, + &resolution, + &cyclic}, + {&curve_custom_data, &point_custom_data}); +} + +/** \} */ + +} // namespace blender::bke + +const blender::bke::ComponentAttributeProviders *CurveComponent::get_attribute_providers() const +{ + static blender::bke::ComponentAttributeProviders providers = + blender::bke::create_attribute_providers_for_curve(); + return &providers; +} diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index 13441b4914a..73572e30d61 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -7,6 +7,7 @@ #include "BKE_attribute.h" #include "BKE_attribute_access.hh" +#include "BKE_curves.hh" #include "BKE_geometry_set.hh" #include "BKE_lib_id.h" #include "BKE_mesh.h" @@ -186,8 +187,9 @@ bool GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_ma if (volume != nullptr) { have_minmax |= BKE_volume_min_max(volume, *r_min, *r_max); } - const CurveEval *curve = this->get_curve_for_read(); - if (curve != nullptr) { + const Curves *curves = this->get_curve_for_read(); + if (curves != nullptr) { + std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curves); /* Using the evaluated positions is somewhat arbitrary, but it is probably expected. */ have_minmax |= curve->bounds_min_max(*r_min, *r_max, true); } @@ -258,7 +260,7 @@ const Volume *GeometrySet::get_volume_for_read() const return (component == nullptr) ? nullptr : component->get_for_read(); } -const CurveEval *GeometrySet::get_curve_for_read() const +const Curves *GeometrySet::get_curve_for_read() const { const CurveComponent *component = this->get_component_for_read<CurveComponent>(); return (component == nullptr) ? nullptr : component->get_for_read(); @@ -285,7 +287,7 @@ bool GeometrySet::has_volume() const bool GeometrySet::has_curve() const { const CurveComponent *component = this->get_component_for_read<CurveComponent>(); - return component != nullptr && component->has_curve(); + return component != nullptr && component->has_curves(); } bool GeometrySet::has_realized_data() const @@ -327,12 +329,12 @@ GeometrySet GeometrySet::create_with_pointcloud(PointCloud *pointcloud, return geometry_set; } -GeometrySet GeometrySet::create_with_curve(CurveEval *curve, GeometryOwnershipType ownership) +GeometrySet GeometrySet::create_with_curve(Curves *curves, GeometryOwnershipType ownership) { GeometrySet geometry_set; - if (curve != nullptr) { + if (curves != nullptr) { CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>(); - component.replace(curve, ownership); + component.replace(curves, ownership); } return geometry_set; } @@ -351,18 +353,18 @@ void GeometrySet::replace_mesh(Mesh *mesh, GeometryOwnershipType ownership) component.replace(mesh, ownership); } -void GeometrySet::replace_curve(CurveEval *curve, GeometryOwnershipType ownership) +void GeometrySet::replace_curve(Curves *curves, GeometryOwnershipType ownership) { - if (curve == nullptr) { + if (curves == nullptr) { this->remove<CurveComponent>(); return; } - if (curve == this->get_curve_for_read()) { + if (curves == this->get_curve_for_read()) { return; } this->remove<CurveComponent>(); CurveComponent &component = this->get_component_for_write<CurveComponent>(); - component.replace(curve, ownership); + component.replace(curves, ownership); } void GeometrySet::replace_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership) @@ -411,7 +413,7 @@ Volume *GeometrySet::get_volume_for_write() return component == nullptr ? nullptr : component->get_for_write(); } -CurveEval *GeometrySet::get_curve_for_write() +Curves *GeometrySet::get_curve_for_write() { CurveComponent *component = this->get_component_ptr<CurveComponent>(); return component == nullptr ? nullptr : component->get_for_write(); diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index 5af599f0302..6b5c04ac25e 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -953,7 +953,7 @@ static const Mesh *get_evaluated_mesh_from_object(const Object *object) return nullptr; } -static const CurveEval *get_evaluated_curve_from_object(const Object *object) +static const Curves *get_evaluated_curves_from_object(const Object *object) { GeometrySet *geometry_set_eval = object->runtime.geometry_set_eval; if (geometry_set_eval) { @@ -968,8 +968,9 @@ static Mesh *mesh_new_from_evaluated_curve_type_object(const Object *evaluated_o if (mesh) { return BKE_mesh_copy_for_eval(mesh, false); } - const CurveEval *curve = get_evaluated_curve_from_object(evaluated_object); - if (curve) { + const Curves *curves = get_evaluated_curves_from_object(evaluated_object); + if (curves) { + std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curves); return blender::bke::curve_to_wire_mesh(*curve); } return nullptr; diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc index c98bd9d6b74..149ae70dda1 100644 --- a/source/blender/geometry/intern/realize_instances.cc +++ b/source/blender/geometry/intern/realize_instances.cc @@ -13,6 +13,7 @@ #include "BLI_task.hh" #include "BKE_collection.h" +#include "BKE_curves.hh" #include "BKE_geometry_set_instances.hh" #include "BKE_material.h" #include "BKE_mesh.h" @@ -118,7 +119,7 @@ struct RealizeMeshTask { }; struct RealizeCurveInfo { - const CurveEval *curve = nullptr; + const Curves *curves; /** * Matches the order in #AllCurvesInfo.attributes. For point attributes, the `std::optional` * will be empty. @@ -163,7 +164,7 @@ struct AllCurvesInfo { /** Ordering of all attributes that are propagated to the output curve generically. */ OrderedAttributes attributes; /** Ordering of the original curves that are joined. */ - VectorSet<const CurveEval *> order; + VectorSet<const Curves *> order; /** Preprocessed data about every original curve. This is ordered by #order. */ Array<RealizeCurveInfo> realize_info; bool create_id_attribute = false; @@ -443,16 +444,16 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info, } case GEO_COMPONENT_TYPE_CURVE: { const CurveComponent &curve_component = *static_cast<const CurveComponent *>(component); - const CurveEval *curve = curve_component.get_for_read(); - if (curve != nullptr && !curve->splines().is_empty()) { - const int curve_index = gather_info.curves.order.index_of(curve); + const Curves *curves = curve_component.get_for_read(); + if (curves != nullptr && curves->geometry.curve_size > 0) { + const int curve_index = gather_info.curves.order.index_of(curves); const RealizeCurveInfo &curve_info = gather_info.curves.realize_info[curve_index]; gather_info.r_tasks.curve_tasks.append({gather_info.r_offsets.spline_offset, &curve_info, base_transform, base_instance_context.curves, base_instance_context.id}); - gather_info.r_offsets.spline_offset += curve->splines().size(); + gather_info.r_offsets.spline_offset += curves->geometry.curve_size; } break; } @@ -1038,11 +1039,11 @@ static OrderedAttributes gather_generic_curve_attributes_to_propagate( } static void gather_curves_to_realize(const GeometrySet &geometry_set, - VectorSet<const CurveEval *> &r_curves) + VectorSet<const Curves *> &r_curves) { - if (const CurveEval *curve = geometry_set.get_curve_for_read()) { - if (!curve->splines().is_empty()) { - r_curves.add(curve); + if (const Curves *curves = geometry_set.get_curve_for_read()) { + if (curves->geometry.curve_size != 0) { + r_curves.add(curves); } } if (const InstancesComponent *instances = @@ -1064,12 +1065,12 @@ static AllCurvesInfo preprocess_curves(const GeometrySet &geometry_set, info.realize_info.reinitialize(info.order.size()); for (const int curve_index : info.realize_info.index_range()) { RealizeCurveInfo &curve_info = info.realize_info[curve_index]; - const CurveEval *curve = info.order[curve_index]; - curve_info.curve = curve; + const Curves *curves = info.order[curve_index]; + curve_info.curves = curves; /* Access attributes. */ CurveComponent component; - component.replace(const_cast<CurveEval *>(curve), GeometryOwnershipType::ReadOnly); + component.replace(const_cast<Curves *>(curves), GeometryOwnershipType::ReadOnly); curve_info.spline_attributes.reinitialize(info.attributes.size()); for (const int attribute_index : info.attributes.index_range()) { const AttributeDomain domain = info.attributes.kinds[attribute_index].domain; @@ -1095,9 +1096,9 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options, MutableSpan<GMutableSpan> dst_spline_attributes) { const RealizeCurveInfo &curve_info = *task.curve_info; - const CurveEval &curve = *curve_info.curve; + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_info.curves); - const Span<SplinePtr> src_splines = curve.splines(); + const Span<SplinePtr> src_splines = curve->splines(); /* Initialize point attributes. */ threading::parallel_for(src_splines.index_range(), 100, [&](const IndexRange src_spline_range) { @@ -1206,12 +1207,12 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options, } const RealizeCurveTask &last_task = tasks.last(); - const CurveEval &last_curve = *last_task.curve_info->curve; - const int tot_splines = last_task.start_spline_index + last_curve.splines().size(); + const Curves &last_curves = *last_task.curve_info->curves; + const int tot_splines = last_task.start_spline_index + last_curves.geometry.curve_size; Array<SplinePtr> dst_splines(tot_splines); - CurveEval *dst_curve = new CurveEval(); + std::unique_ptr<CurveEval> dst_curve = std::make_unique<CurveEval>(); dst_curve->attributes.reallocate(tot_splines); CustomDataAttributes &spline_attributes = dst_curve->attributes; @@ -1242,7 +1243,7 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options, dst_curve->add_splines(dst_splines); CurveComponent &dst_component = r_realized_geometry.get_component_for_write<CurveComponent>(); - dst_component.replace(dst_curve); + dst_component.replace(curve_eval_to_curves(*dst_curve)); } /** \} */ diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc index b83aa8b69a9..e6f3e483f1f 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc @@ -143,9 +143,9 @@ static void node_geo_exec(GeoNodeExecParams params) } const CurveComponent &curve_component = *geometry_set.get_component_for_read<CurveComponent>(); - const CurveEval &curve = *curve_component.get_for_read(); - const Span<SplinePtr> splines = curve.splines(); - curve.assert_valid_point_attributes(); + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read()); + const Span<SplinePtr> splines = curve->splines(); + curve->assert_valid_point_attributes(); evaluate_splines(splines); @@ -167,9 +167,9 @@ static void node_geo_exec(GeoNodeExecParams params) end_result.get_component_for_write<PointCloudComponent>(); CurveToPointsResults start_attributes = curve_to_points_create_result_attributes( - start_point_component, curve); + start_point_component, *curve); CurveToPointsResults end_attributes = curve_to_points_create_result_attributes( - end_point_component, curve); + end_point_component, *curve); copy_endpoint_attributes(splines, offsets.as_span(), start_attributes, end_attributes); copy_spline_domain_attributes(curve_component, offsets.as_span(), start_point_component); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc index 6deaf5b554a..78e36784be7 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc @@ -26,8 +26,8 @@ static void node_geo_exec(GeoNodeExecParams params) /* Retrieve data for write access so we can avoid new allocations for the reversed data. */ CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>(); - CurveEval &curve = *curve_component.get_for_write(); - MutableSpan<SplinePtr> splines = curve.splines(); + std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read()); + MutableSpan<SplinePtr> splines = curve->splines(); const std::string selection_name = params.extract_input<std::string>("Selection"); VArray<bool> selection = curve_component.attribute_get_for_read( @@ -41,6 +41,8 @@ static void node_geo_exec(GeoNodeExecParams params) } }); + geometry_set.replace_curve(curve_eval_to_curves(*curve)); + params.set_output("Curve", geometry_set); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc index a09a751b550..729ccca5f04 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc @@ -89,9 +89,8 @@ static void node_geo_exec(GeoNodeExecParams params) geometry_set = geometry::realize_instances_legacy(geometry_set); CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>(); - const CurveEval *curve = curve_component.get_for_read(); - - if (curve != nullptr) { + if (curve_component.has_curves()) { + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read()); const std::string selection_name = params.extract_input<std::string>("Selection"); OutputAttribute_Typed<bool> selection = curve_component.attribute_try_get_for_output_only<bool>(selection_name, ATTR_DOMAIN_POINT); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc index e5d4d6c1d0f..8ab43909a20 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc @@ -63,8 +63,8 @@ static void node_geo_exec(GeoNodeExecParams params) /* Retrieve data for write access so we can avoid new allocations for the handles data. */ CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>(); - CurveEval &curve = *curve_component.get_for_write(); - MutableSpan<SplinePtr> splines = curve.splines(); + std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read()); + MutableSpan<SplinePtr> splines = curve->splines(); const std::string selection_name = params.extract_input<std::string>("Selection"); VArray<bool> selection = curve_component.attribute_get_for_read( @@ -101,6 +101,8 @@ static void node_geo_exec(GeoNodeExecParams params) bezier_spline.mark_cache_invalid(); } + geometry_set.replace_curve(curve_eval_to_curves(*curve)); + if (!has_bezier_spline) { params.error_message_add(NodeWarningType::Info, TIP_("No Bezier splines in input curve")); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc index 87b8bbf8786..e15e7339107 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc @@ -242,34 +242,34 @@ static void node_geo_exec(GeoNodeExecParams params) } const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>(); - const CurveEval &curve = *curve_component->get_for_read(); + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component->get_for_read()); const std::string selection_name = params.extract_input<std::string>("Selection"); VArray<bool> selection = curve_component->attribute_get_for_read( selection_name, ATTR_DOMAIN_CURVE, true); std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>(); - for (const int i : curve.splines().index_range()) { + for (const int i : curve->splines().index_range()) { if (selection[i]) { switch (output_type) { case GEO_NODE_SPLINE_TYPE_POLY: - new_curve->add_spline(convert_to_poly_spline(*curve.splines()[i])); + new_curve->add_spline(convert_to_poly_spline(*curve->splines()[i])); break; case GEO_NODE_SPLINE_TYPE_BEZIER: - new_curve->add_spline(convert_to_bezier(*curve.splines()[i], params)); + new_curve->add_spline(convert_to_bezier(*curve->splines()[i], params)); break; case GEO_NODE_SPLINE_TYPE_NURBS: - new_curve->add_spline(convert_to_nurbs(*curve.splines()[i])); + new_curve->add_spline(convert_to_nurbs(*curve->splines()[i])); break; } } else { - new_curve->add_spline(curve.splines()[i]->copy()); + new_curve->add_spline(curve->splines()[i]->copy()); } } - new_curve->attributes = curve.attributes; - params.set_output("Curve", GeometrySet::create_with_curve(new_curve.release())); + new_curve->attributes = curve->attributes; + params.set_output("Curve", GeometrySet::create_with_curve(curve_eval_to_curves(*new_curve))); } } // namespace blender::nodes::node_geo_legacy_curve_spline_type_cc diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc index bce320496a1..2a8ab2990db 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc @@ -354,9 +354,11 @@ static void node_geo_exec(GeoNodeExecParams params) return; } - std::unique_ptr<CurveEval> output_curve = subdivide_curve(*component.get_for_read(), cuts); + std::unique_ptr<CurveEval> output_curve = subdivide_curve( + *curves_to_curve_eval(*component.get_for_read()), cuts); - params.set_output("Geometry", GeometrySet::create_with_curve(output_curve.release())); + params.set_output("Geometry", + GeometrySet::create_with_curve(curve_eval_to_curves(*output_curve))); } } // namespace blender::nodes::node_geo_legacy_curve_subdivide_cc diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc index 64627e61910..f68dd6b6b0c 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc @@ -289,13 +289,13 @@ static void node_geo_exec(GeoNodeExecParams params) } const CurveComponent &curve_component = *geometry_set.get_component_for_read<CurveComponent>(); - const CurveEval &curve = *curve_component.get_for_read(); - const Span<SplinePtr> splines = curve.splines(); - curve.assert_valid_point_attributes(); + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read()); + const Span<SplinePtr> splines = curve->splines(); + curve->assert_valid_point_attributes(); evaluate_splines(splines); - const Array<int> offsets = calculate_spline_point_offsets(params, mode, curve, splines); + const Array<int> offsets = calculate_spline_point_offsets(params, mode, *curve, splines); const int total_size = offsets.last(); if (total_size == 0) { params.set_output("Geometry", GeometrySet()); @@ -306,7 +306,7 @@ static void node_geo_exec(GeoNodeExecParams params) PointCloudComponent &point_component = result.get_component_for_write<PointCloudComponent>(); CurveToPointsResults new_attributes = curve_to_points_create_result_attributes(point_component, - curve); + *curve); switch (mode) { case GEO_NODE_CURVE_RESAMPLE_COUNT: case GEO_NODE_CURVE_RESAMPLE_LENGTH: diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc index 897a1c1cd2d..ca98d83c137 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc @@ -235,9 +235,9 @@ static void delete_curve_selection(const CurveComponent &in_component, const bool invert) { std::unique_ptr<CurveEval> r_curve = curve_delete( - *in_component.get_for_read(), selection_name, invert); + *curves_to_curve_eval(*in_component.get_for_read()), selection_name, invert); if (r_curve) { - r_component.replace(r_curve.release()); + r_component.replace(curve_eval_to_curves(*r_curve)); } else { r_component.clear(); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc index ff86a92f2c7..cb5a757811e 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc @@ -48,7 +48,7 @@ static void node_geo_exec(GeoNodeExecParams params) std::unique_ptr<CurveEval> curve = geometry::mesh_to_curve_convert( component, IndexMask(selected_edge_indices)); - params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); + params.set_output("Curve", GeometrySet::create_with_curve(curve_eval_to_curves(*curve))); } } // namespace blender::nodes::node_geo_legacy_mesh_to_curve_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc index 59147e9b23f..44b9857e791 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc @@ -162,8 +162,9 @@ static Mesh *compute_hull(const GeometrySet &geometry_set) } if (geometry_set.has_curve()) { - const CurveEval &curve = *geometry_set.get_curve_for_read(); - for (const SplinePtr &spline : curve.splines()) { + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval( + *geometry_set.get_curve_for_read()); + for (const SplinePtr &spline : curve->splines()) { positions_span = spline->evaluated_positions(); total_size += positions_span.size(); count++; @@ -202,8 +203,9 @@ static Mesh *compute_hull(const GeometrySet &geometry_set) } if (geometry_set.has_curve()) { - const CurveEval &curve = *geometry_set.get_curve_for_read(); - for (const SplinePtr &spline : curve.splines()) { + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval( + *geometry_set.get_curve_for_read()); + for (const SplinePtr &spline : curve->splines()) { Span<float3> array = spline->evaluated_positions(); positions.as_mutable_span().slice(offset, array.size()).copy_from(array); offset += array.size(); @@ -273,7 +275,7 @@ static Mesh *convex_hull_from_instances(const GeometrySet &geometry_set) read_positions(*set.get_component_for_read<MeshComponent>(), transforms, &coords); } if (set.has_curve()) { - read_curve_positions(*set.get_curve_for_read(), transforms, &coords); + read_curve_positions(*curves_to_curve_eval(*set.get_curve_for_read()), transforms, &coords); } } return hull_from_bullet(nullptr, coords); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc index 65aad0fcbf1..ce3058c7d42 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc @@ -59,10 +59,13 @@ class EndpointFieldInput final : public GeometryFieldInput { } const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); - const CurveEval *curve = curve_component.get_for_read(); + if (!curve_component.has_curves()) { + return nullptr; + } - Array<int> control_point_offsets = curve->control_point_offsets(); + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read()); + Array<int> control_point_offsets = curve->control_point_offsets(); if (curve == nullptr || control_point_offsets.last() == 0) { return nullptr; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc index 9824b2b2ece..c1220746c22 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc @@ -117,8 +117,9 @@ static void curve_fill_calculate(GeometrySet &geometry_set, const GeometryNodeCu return; } - const CurveEval &curve = *geometry_set.get_curve_for_read(); - if (curve.splines().is_empty()) { + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval( + *geometry_set.get_curve_for_read()); + if (curve->splines().is_empty()) { geometry_set.replace_curve(nullptr); return; } @@ -127,7 +128,7 @@ static void curve_fill_calculate(GeometrySet &geometry_set, const GeometryNodeCu CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES : CDT_INSIDE_WITH_HOLES; - const blender::meshintersect::CDT_result<double> results = do_cdt(curve, output_type); + const blender::meshintersect::CDT_result<double> results = do_cdt(*curve, output_type); Mesh *mesh = cdt_to_mesh(results); geometry_set.replace_mesh(mesh); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc index b8f317a9679..6742b1103ee 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc @@ -603,10 +603,10 @@ static void calculate_curve_fillet(GeometrySet &geometry_set, fillet_param.limit_radius = limit_radius; - const CurveEval &input_curve = *geometry_set.get_curve_for_read(); - std::unique_ptr<CurveEval> output_curve = fillet_curve(input_curve, fillet_param); + const std::unique_ptr<CurveEval> input_curve = curves_to_curve_eval(*component.get_for_read()); + std::unique_ptr<CurveEval> output_curve = fillet_curve(*input_curve, fillet_param); - geometry_set.replace_curve(output_curve.release()); + geometry_set.replace_curve(curve_eval_to_curves(*output_curve)); } static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc index 8dc74aa3dea..ccd3a587e63 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc @@ -92,14 +92,14 @@ class HandleTypeFieldInput final : public GeometryFieldInput { } const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); - const CurveEval *curve = curve_component.get_for_read(); + const Curves *curve = curve_component.get_for_read(); if (curve == nullptr) { return {}; } if (domain == ATTR_DOMAIN_POINT) { Array<bool> selection(mask.min_array_size()); - select_by_handle_type(*curve, type_, mode_, selection); + select_by_handle_type(*curves_to_curve_eval(*curve), type_, mode_, selection); return VArray<bool>::ForContainer(std::move(selection)); } return {}; diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc index 82621189964..c7c822db983 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc @@ -18,9 +18,9 @@ static void node_geo_exec(GeoNodeExecParams params) params.set_default_remaining_outputs(); return; } - const CurveEval &curve = *curve_set.get_curve_for_read(); + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_set.get_curve_for_read()); float length = 0.0f; - for (const SplinePtr &spline : curve.splines()) { + for (const SplinePtr &spline : curve->splines()) { length += spline->length(); } params.set_output("Length", length); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc index 9919e24473e..9fbc01935ce 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc @@ -335,7 +335,7 @@ static void node_geo_exec(GeoNodeExecParams params) r_center, r_normal, r_radius); - params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); + params.set_output("Curve", GeometrySet::create_with_curve(curve_eval_to_curves(*curve))); params.set_output("Center", r_center); params.set_output("Normal", r_normal); params.set_output("Radius", r_radius); @@ -350,7 +350,7 @@ static void node_geo_exec(GeoNodeExecParams params) params.extract_input<bool>("Connect Center"), params.extract_input<bool>("Invert Arc")); - params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); + params.set_output("Curve", GeometrySet::create_with_curve(curve_eval_to_curves(*curve))); break; } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc index 1d006aea1ef..eabd6aa1aa0 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc @@ -113,7 +113,7 @@ static void node_geo_exec(GeoNodeExecParams params) params.extract_input<float3>("End Handle"), std::max(params.extract_input<int>("Resolution"), 1), mode); - params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); + params.set_output("Curve", GeometrySet::create_with_curve(curve_eval_to_curves(*curve))); } } // namespace blender::nodes::node_geo_curve_primitive_bezier_segment_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc index 44505b61a27..73929dce1af 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc @@ -203,7 +203,7 @@ static void node_geo_exec(GeoNodeExecParams params) } if (curve) { - params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); + params.set_output("Curve", GeometrySet::create_with_curve(curve_eval_to_curves(*curve))); } else { params.set_default_remaining_outputs(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc index d11af3b1cc0..066947de496 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc @@ -111,7 +111,7 @@ static void node_geo_exec(GeoNodeExecParams params) params.extract_input<float>("Length")); } - params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); + params.set_output("Curve", GeometrySet::create_with_curve(curve_eval_to_curves(*curve))); } } // namespace blender::nodes::node_geo_curve_primitive_line_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc index 456f6e55c1e..1b055a3a3d5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc @@ -61,7 +61,7 @@ static void node_geo_exec(GeoNodeExecParams params) params.extract_input<float3>("Middle"), params.extract_input<float3>("End"), std::max(params.extract_input<int>("Resolution"), 3)); - params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); + params.set_output("Curve", GeometrySet::create_with_curve(curve_eval_to_curves(*curve))); } } // namespace blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc index b6a847eebf4..7842ad028b7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc @@ -264,7 +264,7 @@ static void node_geo_exec(GeoNodeExecParams params) curve->add_spline(std::move(spline)); curve->attributes.reallocate(curve->splines().size()); - params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); + params.set_output("Curve", GeometrySet::create_with_curve(curve_eval_to_curves(*curve))); } } // namespace blender::nodes::node_geo_curve_primitive_quadrilateral_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc index f448ddabd2b..d5bc70e37cd 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc @@ -86,7 +86,7 @@ static void node_geo_exec(GeoNodeExecParams params) params.extract_input<float>("End Radius"), params.extract_input<float>("Height"), params.extract_input<bool>("Reverse")); - params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); + params.set_output("Curve", GeometrySet::create_with_curve(curve_eval_to_curves(*curve))); } } // namespace blender::nodes::node_geo_curve_primitive_spiral_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc index 5969af43bc1..e02bcfb73cc 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc @@ -83,7 +83,7 @@ static void node_geo_exec(GeoNodeExecParams params) std::max(params.extract_input<float>("Outer Radius"), 0.0f), params.extract_input<float>("Twist"), std::max(params.extract_input<int>("Points"), 3)); - GeometrySet output = GeometrySet::create_with_curve(curve.release()); + GeometrySet output = GeometrySet::create_with_curve(curve_eval_to_curves(*curve)); if (params.output_is_required("Outer Points")) { StrongAnonymousAttributeID attribute_output("Outer Points"); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc index d2afeaa7094..fffc6188dfd 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc @@ -158,7 +158,7 @@ static SplinePtr resample_spline_evaluated(const Spline &src) static std::unique_ptr<CurveEval> resample_curve(const CurveComponent *component, const SampleModeParam &mode_param) { - const CurveEval *input_curve = component->get_for_read(); + const std::unique_ptr<CurveEval> input_curve = curves_to_curve_eval(*component->get_for_read()); GeometryComponentFieldContext field_context{*component, ATTR_DOMAIN_CURVE}; const int domain_size = component->attribute_domain_size(ATTR_DOMAIN_CURVE); @@ -242,7 +242,7 @@ static void geometry_set_curve_resample(GeometrySet &geometry_set, std::unique_ptr<CurveEval> output_curve = resample_curve( geometry_set.get_component_for_read<CurveComponent>(), mode_param); - geometry_set.replace_curve(output_curve.release()); + geometry_set.replace_curve(curve_eval_to_curves(*output_curve)); } static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc index 0ef3230937b..06ca0483063 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc @@ -34,13 +34,15 @@ static void node_geo_exec(GeoNodeExecParams params) selection_evaluator.evaluate(); const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0); - CurveEval &curve = *component.get_for_write(); - MutableSpan<SplinePtr> splines = curve.splines(); + std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_write()); + MutableSpan<SplinePtr> splines = curve->splines(); threading::parallel_for(selection.index_range(), 128, [&](IndexRange range) { for (const int i : range) { splines[selection[i]]->reverse(); } }); + + component.replace(curve_eval_to_curves(*curve)); }); params.set_output("Curve", std::move(geometry_set)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc index 152828b284c..222c28dd21b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc @@ -127,7 +127,8 @@ class SampleCurveFunction : public fn::MultiFunction { } const CurveComponent *curve_component = geometry_set_.get_component_for_read<CurveComponent>(); - const CurveEval *curve = curve_component->get_for_read(); + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval( + *curve_component->get_for_read()); Span<SplinePtr> splines = curve->splines(); if (splines.is_empty()) { return return_default(); @@ -234,12 +235,13 @@ static void node_geo_exec(GeoNodeExecParams params) return; } - const CurveEval *curve = component->get_for_read(); - if (curve == nullptr) { + if (!component->has_curves()) { params.set_default_remaining_outputs(); return; } + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component->get_for_read()); + if (curve->splines().is_empty()) { params.set_default_remaining_outputs(); return; diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc index 9f50b29d995..a892ff419e5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc @@ -66,8 +66,8 @@ static void node_geo_exec(GeoNodeExecParams params) /* Retrieve data for write access so we can avoid new allocations for the handles data. */ CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>(); - CurveEval &curve = *curve_component.get_for_write(); - MutableSpan<SplinePtr> splines = curve.splines(); + std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read()); + MutableSpan<SplinePtr> splines = curve->splines(); GeometryComponentFieldContext field_context{curve_component, ATTR_DOMAIN_POINT}; const int domain_size = curve_component.attribute_domain_size(ATTR_DOMAIN_POINT); @@ -108,6 +108,8 @@ static void node_geo_exec(GeoNodeExecParams params) } bezier_spline.mark_cache_invalid(); } + + curve_component.replace(curve_eval_to_curves(*curve)); }); if (!has_bezier_spline) { params.error_message_add(NodeWarningType::Info, TIP_("No Bezier splines in input curve")); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc index 3fcbd1b88c3..3edaccba506 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc @@ -205,8 +205,9 @@ class CurveParameterFieldInput final : public GeometryFieldInput { { if (component.type() == GEO_COMPONENT_TYPE_CURVE) { const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); - const CurveEval *curve = curve_component.get_for_read(); - if (curve) { + if (curve_component.has_curves()) { + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval( + *curve_component.get_for_read()); return construct_curve_parameter_varray(*curve, mask, domain); } } @@ -238,8 +239,8 @@ class CurveLengthFieldInput final : public GeometryFieldInput { { if (component.type() == GEO_COMPONENT_TYPE_CURVE) { const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); - const CurveEval *curve = curve_component.get_for_read(); - if (curve) { + if (curve_component.has_curves()) { + std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read()); return construct_curve_length_varray(*curve, mask, domain); } } @@ -271,8 +272,9 @@ class IndexOnSplineFieldInput final : public GeometryFieldInput { { if (component.type() == GEO_COMPONENT_TYPE_CURVE) { const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); - const CurveEval *curve = curve_component.get_for_read(); - if (curve) { + if (curve_component.has_curves()) { + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval( + *curve_component.get_for_read()); return construct_index_on_spline_varray(*curve, mask, domain); } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc index 053df030f15..d691726da27 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc @@ -367,40 +367,43 @@ static void node_geo_exec(GeoNodeExecParams params) } const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>(); - const CurveEval &curve = *curve_component->get_for_read(); + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval( + *curve_component->get_for_read()); GeometryComponentFieldContext field_context{*curve_component, ATTR_DOMAIN_CURVE}; const int domain_size = curve_component->attribute_domain_size(ATTR_DOMAIN_CURVE); + Span<SplinePtr> src_splines = curve->splines(); + fn::FieldEvaluator selection_evaluator{field_context, domain_size}; selection_evaluator.add(selection_field); selection_evaluator.evaluate(); const VArray<bool> &selection = selection_evaluator.get_evaluated<bool>(0); std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>(); - new_curve->resize(curve.splines().size()); + new_curve->resize(src_splines.size()); - threading::parallel_for(curve.splines().index_range(), 512, [&](IndexRange range) { + threading::parallel_for(src_splines.index_range(), 512, [&](IndexRange range) { for (const int i : range) { if (selection[i]) { switch (output_type) { case GEO_NODE_SPLINE_TYPE_POLY: - new_curve->splines()[i] = convert_to_poly_spline(*curve.splines()[i]); + new_curve->splines()[i] = convert_to_poly_spline(*src_splines[i]); break; case GEO_NODE_SPLINE_TYPE_BEZIER: - new_curve->splines()[i] = convert_to_bezier(*curve.splines()[i], params); + new_curve->splines()[i] = convert_to_bezier(*src_splines[i], params); break; case GEO_NODE_SPLINE_TYPE_NURBS: - new_curve->splines()[i] = convert_to_nurbs(*curve.splines()[i]); + new_curve->splines()[i] = convert_to_nurbs(*src_splines[i]); break; } } else { - new_curve->splines()[i] = curve.splines()[i]->copy(); + new_curve->splines()[i] = src_splines[i]->copy(); } } }); - new_curve->attributes = curve.attributes; - geometry_set.replace_curve(new_curve.release()); + new_curve->attributes = curve->attributes; + geometry_set.replace_curve(curve_eval_to_curves(*new_curve)); }); params.set_output("Curve", std::move(geometry_set)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc index 81c3f14d8b1..3297ddcae85 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc @@ -340,9 +340,9 @@ static void node_geo_exec(GeoNodeExecParams params) if (cuts.is_single() && cuts.get_internal_single() < 1) { return; } - - std::unique_ptr<CurveEval> output_curve = subdivide_curve(*component.get_for_read(), cuts); - geometry_set.replace_curve(output_curve.release()); + std::unique_ptr<CurveEval> output_curve = subdivide_curve( + *curves_to_curve_eval(*component.get_for_read()), cuts); + geometry_set.replace_curve(curve_eval_to_curves(*output_curve)); }); params.set_output("Curve", geometry_set); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc index ed497b6fbe0..753a6fe7278 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc @@ -27,14 +27,16 @@ static void geometry_set_curve_to_mesh(GeometrySet &geometry_set, const GeometrySet &profile_set, const bool fill_caps) { - const CurveEval *curve = geometry_set.get_curve_for_read(); - const CurveEval *profile_curve = profile_set.get_curve_for_read(); + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval( + *geometry_set.get_curve_for_read()); + const Curves *profile_curves = profile_set.get_curve_for_read(); - if (profile_curve == nullptr) { + if (profile_curves == nullptr) { Mesh *mesh = bke::curve_to_wire_mesh(*curve); geometry_set.replace_mesh(mesh); } else { + const std::unique_ptr<CurveEval> profile_curve = curves_to_curve_eval(*profile_curves); Mesh *mesh = bke::curve_to_mesh_sweep(*curve, *profile_curve, fill_caps); geometry_set.replace_mesh(mesh); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc index 7481f7248a1..33e7a818c87 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc @@ -325,11 +325,12 @@ static void node_geo_exec(GeoNodeExecParams params) geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES}); return; } - const CurveEval &curve = *geometry_set.get_curve_for_read(); - const Span<SplinePtr> splines = curve.splines(); - curve.assert_valid_point_attributes(); + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval( + *geometry_set.get_curve_for_read()); + const Span<SplinePtr> splines = curve->splines(); + curve->assert_valid_point_attributes(); - const Array<int> offsets = calculate_spline_point_offsets(params, mode, curve, splines); + const Array<int> offsets = calculate_spline_point_offsets(params, mode, *curve, splines); const int total_size = offsets.last(); if (total_size == 0) { geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES}); @@ -339,7 +340,7 @@ static void node_geo_exec(GeoNodeExecParams params) geometry_set.replace_pointcloud(BKE_pointcloud_new_nomain(total_size)); PointCloudComponent &points = geometry_set.get_component_for_write<PointCloudComponent>(); ResultAttributes point_attributes = create_attributes_for_transfer( - points, curve, attribute_outputs); + points, *curve, attribute_outputs); switch (mode) { case GEO_NODE_CURVE_RESAMPLE_COUNT: @@ -351,7 +352,7 @@ static void node_geo_exec(GeoNodeExecParams params) break; } - copy_spline_domain_attributes(curve, offsets, points); + copy_spline_domain_attributes(*curve, offsets, points); if (!point_attributes.rotations.is_empty()) { curve_create_default_rotation_attribute( diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc index 6f2eb9f23c4..649391a2346 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc @@ -515,8 +515,8 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set, const blender::VArray<float> &starts = evaluator.get_evaluated<float>(0); const blender::VArray<float> &ends = evaluator.get_evaluated<float>(1); - CurveEval &curve = *geometry_set.get_curve_for_write(); - MutableSpan<SplinePtr> splines = curve.splines(); + std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*geometry_set.get_curve_for_read()); + MutableSpan<SplinePtr> splines = curve->splines(); threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) { for (const int i : range) { @@ -565,6 +565,8 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set, } } }); + + geometry_set.replace_curve(curve_eval_to_curves(*curve)); } static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc index c11b82a7d99..9fc71ebe8d1 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc @@ -475,9 +475,9 @@ static void separate_curve_selection(GeometrySet &geometry_set, selection_evaluator.evaluate(); const VArray_Span<bool> &selection = selection_evaluator.get_evaluated<bool>(0); std::unique_ptr<CurveEval> r_curve = curve_separate( - *src_component.get_for_read(), selection, selection_domain, invert); + *curves_to_curve_eval(*src_component.get_for_read()), selection, selection_domain, invert); if (r_curve) { - geometry_set.replace_curve(r_curve.release()); + geometry_set.replace_curve(curve_eval_to_curves(*r_curve)); } else { geometry_set.replace_curve(nullptr); diff --git a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc index c247a255e5b..41f1e6663d3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc @@ -529,7 +529,8 @@ static void duplicate_splines(GeometrySet &geometry_set, const GeometryComponent &src_component = *geometry_set.get_component_for_read( GEO_COMPONENT_TYPE_CURVE); - const CurveEval &curve = *geometry_set.get_curve_for_read(); + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval( + *geometry_set.get_curve_for_read()); const int domain_size = src_component.attribute_domain_size(ATTR_DOMAIN_CURVE); GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_CURVE}; FieldEvaluator evaluator{field_context, domain_size}; @@ -547,11 +548,11 @@ static void duplicate_splines(GeometrySet &geometry_set, int count = std::max(counts[selection[i_spline]], 0); curve_offsets[i_spline] = dst_splines_size; dst_splines_size += count; - dst_points_size += count * curve.splines()[selection[i_spline]]->size(); + dst_points_size += count * curve->splines()[selection[i_spline]]->size(); } curve_offsets.last() = dst_splines_size; - Array<int> control_point_offsets = curve.control_point_offsets(); + Array<int> control_point_offsets = curve->control_point_offsets(); Array<int> point_mapping(dst_points_size); std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>(); @@ -559,8 +560,8 @@ static void duplicate_splines(GeometrySet &geometry_set, for (const int i_spline : selection.index_range()) { const IndexRange spline_range = range_for_offsets_index(curve_offsets, i_spline); for ([[maybe_unused]] const int i_duplicate : IndexRange(spline_range.size())) { - SplinePtr spline = curve.splines()[selection[i_spline]]->copy(); - for (const int i_point : IndexRange(curve.splines()[selection[i_spline]]->size())) { + SplinePtr spline = curve->splines()[selection[i_spline]]->copy(); + for (const int i_point : IndexRange(curve->splines()[selection[i_spline]]->size())) { point_mapping[point_index++] = control_point_offsets[selection[i_spline]] + i_point; } new_curve->add_spline(std::move(spline)); @@ -569,7 +570,7 @@ static void duplicate_splines(GeometrySet &geometry_set, new_curve->attributes.reallocate(new_curve->splines().size()); CurveComponent dst_component; - dst_component.replace(new_curve.release(), GeometryOwnershipType::Editable); + dst_component.replace(curve_eval_to_curves(*new_curve), GeometryOwnershipType::Editable); Vector<std::string> skip( {"position", "radius", "resolution", "cyclic", "tilt", "handle_left", "handle_right"}); @@ -577,7 +578,7 @@ static void duplicate_splines(GeometrySet &geometry_set, copy_spline_attributes_without_id( geometry_set, point_mapping, curve_offsets, skip, src_component, dst_component); - copy_stable_id_splines(curve, selection, curve_offsets, src_component, dst_component); + copy_stable_id_splines(*curve, selection, curve_offsets, src_component, dst_component); if (attributes.duplicate_index) { create_duplicate_index_attribute( @@ -786,8 +787,9 @@ static void duplicate_points_curve(const GeometryComponentType component_type, Array<int> offsets = accumulate_counts_to_offsets(selection, counts); CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>(); - const CurveEval &curve = *geometry_set.get_curve_for_read(); - Array<int> control_point_offsets = curve.control_point_offsets(); + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval( + *geometry_set.get_curve_for_read()); + Array<int> control_point_offsets = curve->control_point_offsets(); std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>(); Array<int> parent(domain_size); @@ -802,7 +804,7 @@ static void duplicate_points_curve(const GeometryComponentType component_type, for (const int i_point : selection) { const IndexRange point_range = range_for_offsets_index(offsets, i_point); for ([[maybe_unused]] const int i_duplicate : IndexRange(point_range.size())) { - const SplinePtr &parent_spline = curve.splines()[parent[i_point]]; + const SplinePtr &parent_spline = curve->splines()[parent[i_point]]; switch (parent_spline->type()) { case CurveType::CURVE_TYPE_BEZIER: { std::unique_ptr<BezierSpline> spline = std::make_unique<BezierSpline>(); @@ -833,7 +835,7 @@ static void duplicate_points_curve(const GeometryComponentType component_type, } new_curve->attributes.reallocate(new_curve->splines().size()); CurveComponent dst_component; - dst_component.replace(new_curve.release(), GeometryOwnershipType::Editable); + dst_component.replace(curve_eval_to_curves(*new_curve), GeometryOwnershipType::Editable); copy_point_attributes_without_id( geometry_set, GEO_COMPONENT_TYPE_CURVE, false, offsets, src_component, dst_component); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc index 4537721d173..f952e15fbbe 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc @@ -19,10 +19,10 @@ static void node_declare(NodeDeclarationBuilder &b) static VArray<float> construct_spline_length_gvarray(const CurveComponent &component, const AttributeDomain domain) { - const CurveEval *curve = component.get_for_read(); - if (curve == nullptr) { + if (!component.has_curves()) { return {}; } + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_read()); Span<SplinePtr> splines = curve->splines(); auto length_fn = [splines](int i) { return splines[i]->length(); }; @@ -76,10 +76,10 @@ class SplineLengthFieldInput final : public GeometryFieldInput { static VArray<int> construct_spline_count_gvarray(const CurveComponent &component, const AttributeDomain domain) { - const CurveEval *curve = component.get_for_read(); - if (curve == nullptr) { + if (!component.has_curves()) { return {}; } + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_read()); Span<SplinePtr> splines = curve->splines(); auto count_fn = [splines](int i) { return splines[i]->size(); }; diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc index 4ee7c52a872..435dd969c03 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc @@ -77,21 +77,12 @@ static Array<float3> curve_tangent_point_domain(const CurveEval &curve) static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &component, const AttributeDomain domain) { - const CurveEval *curve = component.get_for_read(); - if (curve == nullptr) { - return nullptr; + if (!component.has_curves()) { + return {}; } + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_read()); if (domain == ATTR_DOMAIN_POINT) { - const Span<SplinePtr> splines = curve->splines(); - - /* Use a reference to evaluated tangents if possible to avoid an allocation and a copy. - * This is only possible when there is only one poly spline. */ - if (splines.size() == 1 && splines.first()->type() == CURVE_TYPE_POLY) { - const PolySpline &spline = static_cast<PolySpline &>(*splines.first()); - return VArray<float3>::ForSpan(spline.evaluated_tangents()); - } - Array<float3> tangents = curve_tangent_point_domain(*curve); return VArray<float3>::ForContainer(std::move(tangents)); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc index 3284378a2cb..91cde52f9eb 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc @@ -35,7 +35,7 @@ static void node_geo_exec(GeoNodeExecParams params) } std::unique_ptr<CurveEval> curve = geometry::mesh_to_curve_convert(component, selection); - geometry_set.replace_curve(curve.release()); + geometry_set.replace_curve(curve_eval_to_curves(*curve)); geometry_set.keep_only({GEO_COMPONENT_TYPE_CURVE, GEO_COMPONENT_TYPE_INSTANCES}); }); diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc index 808d679fb73..85b042ddb9b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc @@ -35,7 +35,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node) } static void set_position_in_component(const GeometryNodeCurveHandleMode mode, - GeometryComponent &component, + CurveComponent &component, const Field<bool> &selection_field, const Field<float3> &position_field, const Field<float3> &offset_field) @@ -53,8 +53,7 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode, evaluator.evaluate(); const IndexMask selection = evaluator.get_evaluated_selection_as_mask(); - CurveComponent &curve_component = *static_cast<CurveComponent *>(&component); - CurveEval *curve = curve_component.get_for_write(); + std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_read()); int current_point = 0; int current_mask = 0; @@ -126,6 +125,8 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode, } } } + + component.replace(curve_eval_to_curves(*curve), GeometryOwnershipType::Owned); } static void node_geo_exec(GeoNodeExecParams params) @@ -140,9 +141,11 @@ static void node_geo_exec(GeoNodeExecParams params) bool has_bezier = false; geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { - if (geometry_set.has_curve() && - geometry_set.get_curve_for_read()->has_spline_with_type(CURVE_TYPE_BEZIER)) { - has_bezier = true; + if (geometry_set.has_curve()) { + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval( + *geometry_set.get_curve_for_read()); + has_bezier = curve->has_spline_with_type(CURVE_TYPE_BEZIER); + set_position_in_component(mode, geometry_set.get_component_for_write<CurveComponent>(), selection_field, diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc index f1353bda9ce..e1c252d0081 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc @@ -45,7 +45,9 @@ static void node_geo_exec(GeoNodeExecParams params) geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { if (geometry_set.has_curve()) { if (only_poly) { - for (const SplinePtr &spline : geometry_set.get_curve_for_read()->splines()) { + const std::unique_ptr<CurveEval> curve = curves_to_curve_eval( + *geometry_set.get_curve_for_read()); + for (const SplinePtr &spline : curve->splines()) { if (ELEM(spline->type(), CURVE_TYPE_BEZIER, CURVE_TYPE_NURBS)) { only_poly = false; break; diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc index ddc0bb2bc11..45156e0cbf8 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc @@ -298,7 +298,8 @@ static Map<int, int> create_curve_instances(GeoNodeExecParams ¶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<CurveEval> curve = curves_to_curve_eval(*curves); curve->translate(translation); + geometry.replace_curve(curve_eval_to_curves(*curve)); } if (Mesh *mesh = geometry.get_mesh_for_write()) { translate_mesh(*mesh, translation); @@ -146,8 +149,10 @@ void transform_geometry_set(GeometrySet &geometry, const float4x4 &transform, const Depsgraph &depsgraph) { - if (CurveEval *curve = geometry.get_curve_for_write()) { + if (Curves *curves = geometry.get_curve_for_write()) { + std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curves); curve->transform(transform); + geometry.replace_curve(curve_eval_to_curves(*curve)); } if (Mesh *mesh = geometry.get_mesh_for_write()) { transform_mesh(*mesh, transform); |