diff options
-rw-r--r-- | release/scripts/startup/nodeitems_builtins.py | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_node.h | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_spline.hh | 5 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/node.cc | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/spline_base.cc | 75 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_node_types.h | 14 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_nodetree.c | 22 | ||||
-rw-r--r-- | source/blender/nodes/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/nodes/NOD_geometry.h | 1 | ||||
-rw-r--r-- | source/blender/nodes/NOD_static_types.h | 1 | ||||
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_curve_deform.cc | 305 |
11 files changed, 419 insertions, 8 deletions
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index e7d991622e8..005e282fc0f 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -504,6 +504,7 @@ geometry_node_categories = [ NodeItem("GeometryNodeCurveSubdivide"), NodeItem("GeometryNodeCurveToMesh"), NodeItem("GeometryNodeCurveResample"), + NodeItem("GeometryNodeCurveDeform"), NodeItem("GeometryNodeMeshToCurve"), NodeItem("GeometryNodeCurveToPoints"), NodeItem("GeometryNodeCurveLength"), diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index a0f6be6b3e9..87140964ccb 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1439,6 +1439,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_SEPARATE_COMPONENTS 1059 #define GEO_NODE_CURVE_SUBDIVIDE 1060 #define GEO_NODE_RAYCAST 1061 +#define GEO_NODE_CURVE_DEFORM 1062 /** \} */ diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh index 24b5a78e598..8b8de115330 100644 --- a/source/blender/blenkernel/BKE_spline.hh +++ b/source/blender/blenkernel/BKE_spline.hh @@ -55,6 +55,8 @@ using SplinePtr = std::unique_ptr<Spline>; * along the length of a curve. * 3. #sample_uniform_index_factors returns an array that stores uniform-length samples * along the spline which can be used to interpolate data from method 1. + * 4. #sample_length_parameters_to_index_factors does the same, but uses arbitrary parameter + * inputs, instead of sampling uniformly. * * Commonly used evaluated data is stored in caches on the spline itself so that operations on * splines don't need to worry about taking ownership of evaluated data when they don't need to. @@ -167,8 +169,11 @@ class Spline { }; LookupResult lookup_evaluated_factor(const float factor) const; LookupResult lookup_evaluated_length(const float length) const; + LookupResult lookup_evaluated_length_cyclic(const float length) const; blender::Array<float> sample_uniform_index_factors(const int samples_size) const; + void sample_length_parameters_to_index_factors(blender::MutableSpan<float> parameters) const; + LookupResult lookup_data_from_index_factor(const float index_factor) const; void sample_with_index_factors(const blender::fn::GVArray &src, diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index db18cecb5d3..4e0e784a5b8 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -5053,6 +5053,7 @@ static void registerGeometryNodes() register_node_type_geo_bounding_box(); register_node_type_geo_collection_info(); register_node_type_geo_convex_hull(); + register_node_type_geo_curve_deform(); register_node_type_geo_curve_length(); register_node_type_geo_curve_to_mesh(); register_node_type_geo_curve_to_points(); diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc index aa0d95d4d61..584156ea40f 100644 --- a/source/blender/blenkernel/intern/spline_base.cc +++ b/source/blender/blenkernel/intern/spline_base.cc @@ -399,21 +399,33 @@ Spline::LookupResult Spline::lookup_evaluated_factor(const float factor) const return this->lookup_evaluated_length(this->length() * factor); } -/** - * \note This does not support extrapolation currently. - */ Spline::LookupResult Spline::lookup_evaluated_length(const float length) const { - BLI_assert(length >= 0.0f && length <= this->length()); - + const int64_t evaluated_size = this->evaluated_points_size(); Span<float> lengths = this->evaluated_lengths(); + if (is_cyclic_) { + const float *offset = std::lower_bound( + lengths.begin(), lengths.end(), std::remainder(length, this->length())); + const int index = offset - lengths.begin(); + const int next_index = (index == evaluated_size - 1) ? 0 : index + 1; + + const float previous_length = (index == 0) ? 0.0f : lengths[index - 1]; + const float factor = (lengths[index] == previous_length) ? + 0.0f : + (length - previous_length) / (lengths[index] - previous_length); + + return LookupResult{index, next_index, factor}; + } + const float *offset = std::lower_bound(lengths.begin(), lengths.end(), length); - const int index = offset - lengths.begin(); - const int next_index = (index == this->size() - 1) ? 0 : index + 1; + const int index = std::min(offset - lengths.begin(), evaluated_size - 2); + const int next_index = index + 1; const float previous_length = (index == 0) ? 0.0f : lengths[index - 1]; - const float factor = (length - previous_length) / (lengths[index] - previous_length); + const float factor = (lengths[index] == previous_length) ? + 0.0f : + (length - previous_length) / (lengths[index] - previous_length); return LookupResult{index, next_index, factor}; } @@ -463,6 +475,53 @@ Array<float> Spline::sample_uniform_index_factors(const int samples_size) const return samples; } +#ifdef DEBUG +static void assert_sorted_array_in_range(Span<float> data, const float min, const float max) +{ + BLI_assert(data.first() >= min); + for (const int i : IndexRange(1, data.size() - 1)) { + BLI_assert(data[i] >= data[i - 1]); + } + BLI_assert(data.last() <= max); +} +#endif + +/** + * Transform an array of sorted length parameters into index factors. The result is indices + * and factors to the next index, encoded in floats. The logic for converting from the float + * values to interpolation data is in #lookup_data_from_index_factor. + * + * \param parameters: Lengths along the spline to be transformed into index factors + * (to save another allocation). Must be between zero and the total length of the spline. + * + * \note The implementation is similar to #sample_uniform_index_factors(), though + * the two loops are inverted, and obviously custom parameters are provided. + */ +void Spline::sample_length_parameters_to_index_factors(MutableSpan<float> parameters) const +{ + const Span<float> lengths = this->evaluated_lengths(); +#ifdef DEBUG + assert_sorted_array_in_range(parameters, 0.0f, this->length()); +#endif + + /* Store the length at the previous evaluated point in a variable so it can + * start out at zero (the lengths array doesn't contain 0 for the first point). */ + float prev_length = 0.0f; + int i_evaluated = 0; + for (const int i_sample : parameters.index_range()) { + const float sample_length = parameters[i_sample]; + + /* Skip over every evaluated point that fits before this sample. */ + while (lengths[i_evaluated] < sample_length) { + prev_length = lengths[i_evaluated]; + i_evaluated++; + } + + const float factor = (sample_length - prev_length) / (lengths[i_evaluated] - prev_length); + parameters[i_sample] = i_evaluated + factor; + } +} + Spline::LookupResult Spline::lookup_data_from_index_factor(const float index_factor) const { const int eval_size = this->evaluated_points_size(); diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 12625d3408d..186d5cc9884 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1362,6 +1362,11 @@ typedef struct NodeGeometryCurveResample { uint8_t mode; } NodeGeometryCurveResample; +typedef struct NodeGeometryCurveDeform { + /* GeometryNodeCurveDeformAxis. */ + uint8_t axis; +} NodeGeometryCurveDeform; + typedef struct NodeGeometryCurveSubdivide { /* GeometryNodeAttributeInputMode (integer or attribute). */ uint8_t cuts_type; @@ -1900,6 +1905,15 @@ typedef enum GeometryNodeAttributeTransferMapMode { GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST = 1, } GeometryNodeAttributeTransferMapMode; +typedef enum GeometryNodeCurveDeformAxis { + GEO_NODE_CURVE_DEFORM_POSX = 0, + GEO_NODE_CURVE_DEFORM_POSY = 1, + GEO_NODE_CURVE_DEFORM_POSZ = 2, + GEO_NODE_CURVE_DEFORM_NEGX = 3, + GEO_NODE_CURVE_DEFORM_NEGY = 4, + GEO_NODE_CURVE_DEFORM_NEGZ = 5, +} GeometryNodeCurveDeformAxis; + typedef enum GeometryNodeRaycastMapMode { GEO_NODE_RAYCAST_INTERPOLATED = 0, GEO_NODE_RAYCAST_NEAREST = 1, diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index c26e9e883d6..e27c3e6dada 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -9859,6 +9859,28 @@ static void def_geo_curve_resample(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } +static void def_geo_curve_deform(StructRNA *srna) +{ + PropertyRNA *prop; + + static const EnumPropertyItem axis_items[] = { + {GEO_NODE_CURVE_DEFORM_POSX, "POS_X", 0, "X", ""}, + {GEO_NODE_CURVE_DEFORM_POSY, "POS_Y", 0, "Y", ""}, + {GEO_NODE_CURVE_DEFORM_POSZ, "POS_Z", 0, "Z", ""}, + {GEO_NODE_CURVE_DEFORM_NEGX, "NEG_X", 0, "-X", ""}, + {GEO_NODE_CURVE_DEFORM_NEGY, "NEG_Y", 0, "-Y", ""}, + {GEO_NODE_CURVE_DEFORM_NEGZ, "NEG_Z", 0, "-Z", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + RNA_def_struct_sdna_from(srna, "NodeGeometryCurveDeform", "storage"); + + prop = RNA_def_property(srna, "axis", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, axis_items); + RNA_def_property_ui_text(prop, "Position Axis", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); +} + static void def_geo_curve_subdivide(StructRNA *srna) { PropertyRNA *prop; diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 39f26737620..4ae4dbc2c7f 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -163,6 +163,7 @@ set(SRC geometry/nodes/node_geo_collection_info.cc geometry/nodes/node_geo_common.cc geometry/nodes/node_geo_convex_hull.cc + geometry/nodes/node_geo_curve_deform.cc geometry/nodes/node_geo_curve_length.cc geometry/nodes/node_geo_curve_to_mesh.cc geometry/nodes/node_geo_curve_to_points.cc diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index fddaaf6e640..66f7028af88 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -51,6 +51,7 @@ void register_node_type_geo_boolean(void); void register_node_type_geo_bounding_box(void); void register_node_type_geo_collection_info(void); void register_node_type_geo_convex_hull(void); +void register_node_type_geo_curve_deform(void); void register_node_type_geo_curve_length(void); void register_node_type_geo_curve_to_mesh(void); void register_node_type_geo_curve_to_points(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index d79fa7bffb3..4e39568f688 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -290,6 +290,7 @@ DefNode(GeometryNode, GEO_NODE_BOOLEAN, def_geo_boolean, "BOOLEAN", Boolean, "Bo DefNode(GeometryNode, GEO_NODE_BOUNDING_BOX, 0, "BOUNDING_BOX", BoundBox, "Bounding Box", "") DefNode(GeometryNode, GEO_NODE_COLLECTION_INFO, def_geo_collection_info, "COLLECTION_INFO", CollectionInfo, "Collection Info", "") DefNode(GeometryNode, GEO_NODE_CONVEX_HULL, 0, "CONVEX_HULL", ConvexHull, "Convex Hull", "") +DefNode(GeometryNode, GEO_NODE_CURVE_DEFORM, def_geo_curve_deform, "CURVE_DEFORM", CurveDeform, "Curve Deform", "") DefNode(GeometryNode, GEO_NODE_CURVE_LENGTH, 0, "CURVE_LENGTH", CurveLength, "Curve Length", "") DefNode(GeometryNode, GEO_NODE_CURVE_RESAMPLE, def_geo_curve_resample, "CURVE_RESAMPLE", CurveResample, "Resample Curve", "") DefNode(GeometryNode, GEO_NODE_CURVE_SUBDIVIDE, def_geo_curve_subdivide, "CURVE_SUBDIVIDE", CurveSubdivide, "Curve Subdivide", "") diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_deform.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_deform.cc new file mode 100644 index 00000000000..dde7191fb69 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_deform.cc @@ -0,0 +1,305 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "BLI_array.hh" +#include "BLI_float4x4.hh" +#include "BLI_resource_scope.hh" +#include "BLI_task.hh" +#include "BLI_timeit.hh" + +#include "BKE_attribute_math.hh" +#include "BKE_geometry_set_instances.hh" +#include "BKE_spline.hh" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "node_geometry_util.hh" + +using blender::float4x4; +using blender::bke::GeometryInstanceGroup; + +static bNodeSocketTemplate geo_node_curve_deform_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {SOCK_GEOMETRY, N_("Curve")}, + {SOCK_STRING, N_("Factor")}, + {SOCK_FLOAT, N_("Factor"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, + {SOCK_BOOLEAN, N_("Use Bounds")}, + {SOCK_BOOLEAN, N_("Stretch")}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_curve_deform_out[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {-1, ""}, +}; + +static void geo_node_curve_deform_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "axis", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); +} + +static void geo_node_curve_deform_init(bNodeTree *UNUSED(tree), bNode *node) +{ + NodeGeometryCurveDeform *data = (NodeGeometryCurveDeform *)MEM_callocN( + sizeof(NodeGeometryCurveDeform), __func__); + + data->axis = GEO_NODE_CURVE_DEFORM_POSX; + node->storage = data; +} + +namespace blender::nodes { + +static constexpr int deform_axis_index(const GeometryNodeCurveDeformAxis axis) +{ + switch (axis) { + case GEO_NODE_CURVE_DEFORM_POSX: + case GEO_NODE_CURVE_DEFORM_NEGX: + return 0; + case GEO_NODE_CURVE_DEFORM_POSY: + case GEO_NODE_CURVE_DEFORM_NEGY: + return 1; + case GEO_NODE_CURVE_DEFORM_POSZ: + case GEO_NODE_CURVE_DEFORM_NEGZ: + return 2; + } + BLI_assert_unreachable(); + return 0; +} + +static constexpr int deform_next_axis_index(const GeometryNodeCurveDeformAxis axis) +{ + switch (axis) { + case GEO_NODE_CURVE_DEFORM_POSX: + case GEO_NODE_CURVE_DEFORM_NEGX: + return 1; + case GEO_NODE_CURVE_DEFORM_POSY: + case GEO_NODE_CURVE_DEFORM_NEGY: + return 2; + case GEO_NODE_CURVE_DEFORM_POSZ: + case GEO_NODE_CURVE_DEFORM_NEGZ: + return 0; + } + BLI_assert_unreachable(); + return 0; +} + +static constexpr int deform_other_axis_index(const GeometryNodeCurveDeformAxis axis) +{ + switch (axis) { + case GEO_NODE_CURVE_DEFORM_POSX: + case GEO_NODE_CURVE_DEFORM_NEGX: + return 2; + case GEO_NODE_CURVE_DEFORM_POSY: + case GEO_NODE_CURVE_DEFORM_NEGY: + return 0; + case GEO_NODE_CURVE_DEFORM_POSZ: + case GEO_NODE_CURVE_DEFORM_NEGZ: + return 1; + } + BLI_assert_unreachable(); + return 0; +} + +static constexpr bool axis_is_negative(const GeometryNodeCurveDeformAxis axis) +{ + switch (axis) { + case GEO_NODE_CURVE_DEFORM_POSX: + case GEO_NODE_CURVE_DEFORM_POSY: + case GEO_NODE_CURVE_DEFORM_POSZ: + return false; + case GEO_NODE_CURVE_DEFORM_NEGX: + case GEO_NODE_CURVE_DEFORM_NEGY: + case GEO_NODE_CURVE_DEFORM_NEGZ: + return true; + } + BLI_assert_unreachable(); + return false; +} + +struct SplineDeformInput { + const Spline &spline; + Span<float3> positions; + Span<float3> tangents; + Span<float3> normals; + GVArray_Typed<float> radii; + float total_length; + bool use_stretch; + bool use_bounds; +}; + +static float3 deform_position(const SplineDeformInput &in, + const Spline::LookupResult &lookup, + const float cotangent_factor, + const float normal_factor, + const bool is_negative) +{ + const int index = lookup.evaluated_index; + const int next = lookup.next_evaluated_index; + const float factor = lookup.factor; + const float clamped = std::clamp(lookup.factor, 0.0f, 1.0f); + + const float3 position = float3::interpolate(in.positions[index], in.positions[next], factor); + const float3 tangent = float3::interpolate(in.tangents[index], in.tangents[next], clamped); + const float3 normal = float3::interpolate(in.normals[index], in.normals[next], clamped); + const float3 cotangent = float3::cross(tangent, normal).normalized(); + const float radius = interpf(in.radii[next], in.radii[index], clamped); + + if (is_negative) { + return position + (cotangent * cotangent_factor + normal * normal_factor) * radius; + } + + return position - (cotangent * cotangent_factor + normal * normal_factor) * radius; +} + +struct Bounds { + float3 min; + float3 max; + float3 inv_size; +}; + +static Bounds position_bounds(const Span<float3> positions) +{ + float3 min = float3(FLT_MAX); + float3 max = float3(-FLT_MAX); + for (const float3 &position : positions) { + minmax_v3v3_v3(min, max, position); + } + return {min, max, float3::safe_divide(float3(1), max - min)}; +} + +static Bounds dummy_parameter_bounds(const GeometryNodeCurveDeformAxis deform_axis) +{ + if (axis_is_negative(deform_axis)) { + return {float3(-1), float3(0), float3(-1)}; + } + return {float3(0), float3(1), float3(1)}; +} + +static float process_parameter(const float3 position, + const int axis_index, + const bool is_negative, + const SplineDeformInput &input, + const Bounds &bounds) +{ + const float parameter = is_negative ? -(position[axis_index] - bounds.max[axis_index]) : + position[axis_index] - bounds.min[axis_index]; + if (input.use_stretch) { + return parameter * bounds.inv_size[axis_index] * input.total_length; + } + return parameter; +} + +static void execute_on_component(const GeoNodeExecParams ¶ms, + const SplineDeformInput &input, + GeometryComponent &component) +{ + const NodeGeometryCurveDeform &node_storage = *(NodeGeometryCurveDeform *)params.node().storage; + const GeometryNodeCurveDeformAxis deform_axis = (GeometryNodeCurveDeformAxis)node_storage.axis; + const int axis_index = deform_axis_index(deform_axis); + const int next_axis = deform_next_axis_index(deform_axis); + const int other_axis = deform_other_axis_index(deform_axis); + const bool is_negative = axis_is_negative(deform_axis); + + OutputAttribute_Typed<float3> position_attribute = + component.attribute_try_get_for_output<float3>("position", ATTR_DOMAIN_POINT, {0, 0, 0}); + MutableSpan<float3> positions = position_attribute.as_span(); + const Bounds bounds = position_bounds(positions); + const Bounds parameter_bounds = input.use_bounds ? bounds : dummy_parameter_bounds(deform_axis); + + threading::parallel_for(positions.index_range(), 1024, [&](IndexRange range) { + for (const int i : range) { + const float parameter = process_parameter( + positions[i], axis_index, is_negative, input, parameter_bounds); + + const Spline::LookupResult lookup = input.spline.lookup_evaluated_length(parameter); + + const float3 co = (positions[i] - bounds.min) * bounds.inv_size * 2.0f - float3(1); + if (is_negative) { + positions[i] = deform_position(input, lookup, co[next_axis], co[other_axis], is_negative); + } + else { + positions[i] = deform_position(input, lookup, co[other_axis], co[next_axis], is_negative); + } + } + }); + + position_attribute.save(); +} + +static void geo_node_curve_deform_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); + GeometrySet curve_geometry_set = params.extract_input<GeometrySet>("Curve"); + + geometry_set = bke::geometry_set_realize_instances(geometry_set); + + /* TODO: Theoretically this could be easily avoided. */ + curve_geometry_set = bke::geometry_set_realize_instances(curve_geometry_set); + + const CurveEval *curve = curve_geometry_set.get_curve_for_read(); + if (curve == nullptr || curve->splines().size() == 0) { + params.set_output("Geometry", geometry_set); + return; + } + + const Spline &spline = *curve->splines().first(); + const float total_length = spline.length(); + if (total_length == 0.0f) { + params.set_output("Geometry", geometry_set); + return; + } + + const SplineDeformInput spline_data{spline, + spline.evaluated_positions(), + spline.evaluated_tangents(), + spline.evaluated_normals(), + spline.interpolate_to_evaluated(spline.radii()), + total_length, + params.extract_input<bool>("Stretch"), + params.extract_input<bool>("Use Bounds")}; + + if (geometry_set.has<MeshComponent>()) { + execute_on_component( + params, spline_data, geometry_set.get_component_for_write<MeshComponent>()); + } + if (geometry_set.has<PointCloudComponent>()) { + execute_on_component( + params, spline_data, geometry_set.get_component_for_write<PointCloudComponent>()); + } + if (geometry_set.has<CurveComponent>()) { + execute_on_component( + params, spline_data, geometry_set.get_component_for_write<CurveComponent>()); + } + + params.set_output("Geometry", geometry_set); +} + +} // namespace blender::nodes + +void register_node_type_geo_curve_deform() +{ + static bNodeType ntype; + + geo_node_type_base(&ntype, GEO_NODE_CURVE_DEFORM, "Curve Deform", NODE_CLASS_GEOMETRY, 0); + node_type_socket_templates(&ntype, geo_node_curve_deform_in, geo_node_curve_deform_out); + ntype.draw_buttons = geo_node_curve_deform_layout; + node_type_storage( + &ntype, "NodeGeometryCurveDeform", node_free_standard_storage, node_copy_standard_storage); + node_type_init(&ntype, geo_node_curve_deform_init); + ntype.geometry_node_execute = blender::nodes::geo_node_curve_deform_exec; + nodeRegisterType(&ntype); +} |