From 32e61d3d090ab6e1afa134f6d85e9da4f8a57e61 Mon Sep 17 00:00:00 2001 From: Mattias Fredriksson Date: Mon, 8 Sep 2025 19:16:48 +0200 Subject: [PATCH] OBJ IO: Import NURBS as Curves directly (not legacy) Extends obj importer for importing NURBS directly as Curves, avoiding importing and converting legacy curves. This change only affects geonode importer, and will not be a change in behavior for users (import operator will still create legacy curve). Pull Request: https://projects.blender.org/blender/blender/pulls/145850 --- .../importer/obj_import_nurbs.cc | 74 +++++++++++++++---- .../importer/obj_import_nurbs.hh | 3 +- .../io/wavefront_obj/importer/obj_importer.cc | 6 +- 3 files changed, 63 insertions(+), 20 deletions(-) diff --git a/source/blender/io/wavefront_obj/importer/obj_import_nurbs.cc b/source/blender/io/wavefront_obj/importer/obj_import_nurbs.cc index 7587af0931e..edb0aa3956d 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_nurbs.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_nurbs.cc @@ -6,6 +6,7 @@ * \ingroup obj */ +#include "BKE_curve_legacy_convert.hh" #include "BKE_curves.hh" #include "BKE_lib_id.hh" #include "BKE_object.hh" @@ -24,23 +25,14 @@ namespace blender::io::obj { -Curve *blender::io::obj::CurveFromGeometry::create_curve(const OBJImportParams &import_params) +Curves *blender::io::obj::CurveFromGeometry::create_curve(const OBJImportParams &import_params) { BLI_assert(!curve_geometry_.nurbs_element_.curv_indices.is_empty()); - /* Use of #BKE_id_new_nomain(nullptr) limits use for the Curve, see #BKE_curve_add. */ - Curve *curve = BKE_id_new_nomain(nullptr); - - curve->flag = CU_3D; - curve->resolu = curve->resolv = 12; - /* Only one NURBS spline will be created in the curve object. */ - curve->actnu = 0; - - Nurb *nurb = MEM_callocN(__func__); - BLI_addtail(BKE_curve_nurbs_get(curve), nurb); - this->create_nurbs(curve, import_params); - - return curve; + Curves *curves_id = bke::curves_new_nomain(0, 0); + bke::CurvesGeometry &curves = curves_id->geometry.wrap(); + this->create_nurbs(curves, import_params); + return curves_id; } Object *CurveFromGeometry::create_curve_object(Main *bmain, const OBJImportParams &import_params) @@ -146,6 +138,60 @@ void CurveFromGeometry::create_nurbs(Curve *curve, const OBJImportParams &import } } +void CurveFromGeometry::create_nurbs(bke::CurvesGeometry &curves, + const OBJImportParams &import_params) +{ + const NurbsElement &nurbs_geometry = curve_geometry_.nurbs_element_; + const int8_t degree = get_valid_nurbs_degree(nurbs_geometry); + const int8_t order = degree + 1; + + const Vector multiplicity = bke::curves::nurbs::calculate_multiplicity_sequence( + nurbs_geometry.parm); + const short knot_flag = this->detect_knot_mode( + import_params, degree, nurbs_geometry.curv_indices, nurbs_geometry.parm, multiplicity); + + const bool is_cyclic = knot_flag & CU_NURB_CYCLIC; + const int repeated_points = is_cyclic ? repeating_cyclic_point_num(order, nurbs_geometry.parm) : + 0; + const Span indices = nurbs_geometry.curv_indices.as_span().slice( + nurbs_geometry.curv_indices.index_range().drop_back(repeated_points)); + + const int points_num = indices.size(); + const int curve_index = 0; + curves.resize(points_num, 1); + + MutableSpan types = curves.curve_types_for_write(); + MutableSpan cyclic = curves.cyclic_for_write(); + MutableSpan orders = curves.nurbs_orders_for_write(); + MutableSpan modes = curves.nurbs_knots_modes_for_write(); + types.first() = CURVE_TYPE_NURBS; + cyclic.first() = is_cyclic; + orders.first() = order; + modes.first() = bke::knots_mode_from_legacy(knot_flag); + curves.update_curve_types(); + + const OffsetIndices points_by_curve = curves.points_by_curve(); + const IndexRange point_range = points_by_curve[curve_index]; + + MutableSpan positions = curves.positions_for_write().slice(point_range); + MutableSpan weights = curves.nurbs_weights_for_write().slice(point_range); + for (const int i : indices.index_range()) { + positions[i] = global_vertices_.vertices[indices[i]]; + weights[i] = (global_vertices_.vertex_weights.size() > indices[i]) ? + global_vertices_.vertex_weights[indices[i]] : + 1.0f; + } + + if (modes.first() == NURBS_KNOT_MODE_CUSTOM) { + OffsetIndices knot_offsets = curves.nurbs_custom_knots_by_curve(); + curves.nurbs_custom_knots_update_size(); + MutableSpan knots = curves.nurbs_custom_knots_for_write().slice( + knot_offsets[curve_index]); + + array_utils::copy(nurbs_geometry.parm, knots); + } +} + static bool detect_clamped_endpoint(const int8_t degree, const Span multiplicity) { const int8_t order = degree + 1; diff --git a/source/blender/io/wavefront_obj/importer/obj_import_nurbs.hh b/source/blender/io/wavefront_obj/importer/obj_import_nurbs.hh index cc498b888f1..765cc041130 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_nurbs.hh +++ b/source/blender/io/wavefront_obj/importer/obj_import_nurbs.hh @@ -34,7 +34,7 @@ class CurveFromGeometry : NonMovable, NonCopyable { { } - Curve *create_curve(const OBJImportParams &import_params); + Curves *create_curve(const OBJImportParams &import_params); Object *create_curve_object(Main *bmain, const OBJImportParams &import_params); @@ -43,6 +43,7 @@ class CurveFromGeometry : NonMovable, NonCopyable { * Create a NURBS spline for the Curve converted from Geometry. */ void create_nurbs(Curve *curve, const OBJImportParams &import_params); + void create_nurbs(bke::CurvesGeometry &curve, const OBJImportParams &import_params); short detect_knot_mode(const OBJImportParams &import_params, int8_t degree, diff --git a/source/blender/io/wavefront_obj/importer/obj_importer.cc b/source/blender/io/wavefront_obj/importer/obj_importer.cc index 65fb0aebe1b..00b042e115b 100644 --- a/source/blender/io/wavefront_obj/importer/obj_importer.cc +++ b/source/blender/io/wavefront_obj/importer/obj_importer.cc @@ -95,12 +95,8 @@ static void geometry_to_blender_geometry_set(const OBJImportParams &import_param } else if (geometry->geom_type_ == GEOM_CURVE) { CurveFromGeometry curve_ob_from_geometry(*geometry, global_vertices); - Curve *curve = curve_ob_from_geometry.create_curve(import_params); - Curves *curves_id = bke::curve_legacy_to_curves(*curve); + Curves *curves_id = curve_ob_from_geometry.create_curve(import_params); geometry_set = bke::GeometrySet::from_curves(curves_id); - - /* Free temporary legacy curve object. */ - BKE_id_free(nullptr, curve); } geometry_set.name = geometry->geometry_name_;