Differential D13275 Diff 45454 source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
Changeset View
Changeset View
Standalone View
Standalone View
source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
- This file was moved from source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc.
| Show All 14 Lines | |||||
| */ | */ | ||||
| #include "BLI_task.hh" | #include "BLI_task.hh" | ||||
| #include "BKE_spline.hh" | #include "BKE_spline.hh" | ||||
| #include "node_geometry_util.hh" | #include "node_geometry_util.hh" | ||||
| namespace blender::nodes::node_geo_curve_parameter_cc { | namespace blender::nodes::node_geo_curve_spline_parameter_cc { | ||||
HooglyBoogly: I think I'd go with `node_geo_spline_parameter_cc` (without the "curve_", just because it's… | |||||
| static void node_declare(NodeDeclarationBuilder &b) | static void node_declare(NodeDeclarationBuilder &b) | ||||
| { | { | ||||
| b.add_output<decl::Float>(N_("Factor")) | b.add_output<decl::Float>(N_("Factor")) | ||||
| .field_source() | .field_source() | ||||
| .description( | .description( | ||||
| N_("For points, the portion of the spline's total length at the control point. For " | N_("For points, the portion of the spline's total length at the control point. For " | ||||
| "Splines, the factor of that spline within the entire curve")); | "Splines, the factor of that spline within the entire curve")); | ||||
| b.add_output<decl::Float>(N_("Length")) | b.add_output<decl::Float>(N_("Length")) | ||||
| .field_source() | .field_source() | ||||
| .description( | .description( | ||||
| N_("For points, the distance along the control point's spline, For splines, the " | N_("For points, the distance along the control point's spline, For splines, the " | ||||
| "distance along the entire curve")); | "distance along the entire curve")); | ||||
| b.add_output<decl::Int>(N_("Index")) | |||||
| .field_source() | |||||
| .description(N_("Each control point's index on its spline")); | |||||
| } | } | ||||
Done Inline Actionsit's -> its Could be simplified a bit maybe, since this only has a definition for points. Something like this maybe? Each control point's index on its spline HooglyBoogly: `it's` -> `its`
Could be simplified a bit maybe, since this only has a definition for points. | |||||
| /** | /** | ||||
| * A basic interpolation from the point domain to the spline domain would be useless, since the | * A basic interpolation from the point domain to the spline domain would be useless, since the | ||||
| * average parameter for each spline would just be 0.5, or close to it. Instead, the parameter for | * average parameter for each spline would just be 0.5, or close to it. Instead, the parameter for | ||||
| * each spline is the portion of the total length at the start of the spline. | * each spline is the portion of the total length at the start of the spline. | ||||
| */ | */ | ||||
| static Array<float> curve_length_spline_domain(const CurveEval &curve, | static Array<float> curve_length_spline_domain(const CurveEval &curve, | ||||
| const IndexMask UNUSED(mask)) | const IndexMask UNUSED(mask)) | ||||
| ▲ Show 20 Lines • Show All 131 Lines • ▼ Show 20 Lines | if (domain == ATTR_DOMAIN_CURVE) { | ||||
| Array<float> lengths = curve_length_spline_domain(curve, mask); | Array<float> lengths = curve_length_spline_domain(curve, mask); | ||||
| return VArray<float>::ForContainer(std::move(lengths)); | return VArray<float>::ForContainer(std::move(lengths)); | ||||
| } | } | ||||
| return {}; | return {}; | ||||
| } | } | ||||
| static VArray<int> construct_index_on_spline_varray(const CurveEval &curve, | |||||
| const IndexMask UNUSED(mask), | |||||
| const AttributeDomain domain) | |||||
| { | |||||
| if (domain == ATTR_DOMAIN_POINT) { | |||||
| Array<int> output(curve.total_control_point_size()); | |||||
| int output_index = 0; | |||||
Done Inline ActionsCan just use output directly. No need to create a span. JacquesLucke: Can just use `output` directly. No need to create a span. | |||||
| for (int spline_index : curve.splines().index_range()) { | |||||
Done Inline ActionsRename index variables to output_index, spline_index and point_index. That should make it more clear I think. JacquesLucke: Rename index variables to `output_index`, `spline_index` and `point_index`. That should make it… | |||||
| for (int point_index : IndexRange(curve.splines()[spline_index]->size())) { | |||||
| output[output_index++] = point_index; | |||||
| } | |||||
| } | |||||
| return VArray<int>::ForContainer(std::move(output)); | |||||
| } | |||||
| return {}; | |||||
| } | |||||
Done Inline ActionsI'd suggest using the offsets from control_point_offsets to our advantage and structure the loop as a loop over all splines: for (const int i : IndexRange(curve.splines.size())) {. That should simplify it a lot. HooglyBoogly: I'd suggest using the offsets from `control_point_offsets` to our advantage and structure the… | |||||
| class CurveParameterFieldInput final : public fn::FieldInput { | class CurveParameterFieldInput final : public fn::FieldInput { | ||||
| public: | public: | ||||
| CurveParameterFieldInput() : fn::FieldInput(CPPType::get<float>(), "Curve Parameter node") | CurveParameterFieldInput() : fn::FieldInput(CPPType::get<float>(), "Curve Parameter node") | ||||
| { | { | ||||
| category_ = Category::Generated; | category_ = Category::Generated; | ||||
| } | } | ||||
Done Inline ActionsThis function has no return when the domain is not either of these values. You could just skip the if statement. HooglyBoogly: This function has no return when the domain is not either of these values. You could just skip… | |||||
| GVArray get_varray_for_context(const fn::FieldContext &context, | GVArray get_varray_for_context(const fn::FieldContext &context, | ||||
| IndexMask mask, | IndexMask mask, | ||||
| ResourceScope &UNUSED(scope)) const final | ResourceScope &UNUSED(scope)) const final | ||||
| { | { | ||||
| if (const GeometryComponentFieldContext *geometry_context = | if (const GeometryComponentFieldContext *geometry_context = | ||||
| dynamic_cast<const GeometryComponentFieldContext *>(&context)) { | dynamic_cast<const GeometryComponentFieldContext *>(&context)) { | ||||
| ▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | public: | ||||
| } | } | ||||
| bool is_equal_to(const fn::FieldNode &other) const override | bool is_equal_to(const fn::FieldNode &other) const override | ||||
| { | { | ||||
| return dynamic_cast<const CurveLengthFieldInput *>(&other) != nullptr; | return dynamic_cast<const CurveLengthFieldInput *>(&other) != nullptr; | ||||
| } | } | ||||
| }; | }; | ||||
| class IndexOnSplineFieldInput final : public fn::FieldInput { | |||||
| public: | |||||
| IndexOnSplineFieldInput() : fn::FieldInput(CPPType::get<int>(), "Spline Index") | |||||
| { | |||||
| category_ = Category::Generated; | |||||
| } | |||||
| GVArray get_varray_for_context(const fn::FieldContext &context, | |||||
| IndexMask mask, | |||||
| ResourceScope &UNUSED(scope)) const final | |||||
| { | |||||
| if (const GeometryComponentFieldContext *geometry_context = | |||||
| dynamic_cast<const GeometryComponentFieldContext *>(&context)) { | |||||
| const GeometryComponent &component = geometry_context->geometry_component(); | |||||
| const AttributeDomain domain = geometry_context->domain(); | |||||
| 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) { | |||||
| return construct_index_on_spline_varray(*curve, mask, domain); | |||||
| } | |||||
| } | |||||
| } | |||||
| return {}; | |||||
| } | |||||
| uint64_t hash() const override | |||||
| { | |||||
| /* Some random constant hash. */ | |||||
| return 4536246522; | |||||
| } | |||||
| bool is_equal_to(const fn::FieldNode &other) const override | |||||
| { | |||||
| return dynamic_cast<const IndexOnSplineFieldInput *>(&other) != nullptr; | |||||
| } | |||||
| }; | |||||
| static void node_geo_exec(GeoNodeExecParams params) | static void node_geo_exec(GeoNodeExecParams params) | ||||
| { | { | ||||
| Field<float> parameter_field{std::make_shared<CurveParameterFieldInput>()}; | Field<float> parameter_field{std::make_shared<CurveParameterFieldInput>()}; | ||||
| Field<float> length_field{std::make_shared<CurveLengthFieldInput>()}; | Field<float> length_field{std::make_shared<CurveLengthFieldInput>()}; | ||||
| Field<int> index_on_spline_field{std::make_shared<IndexOnSplineFieldInput>()}; | |||||
| params.set_output("Factor", std::move(parameter_field)); | params.set_output("Factor", std::move(parameter_field)); | ||||
| params.set_output("Length", std::move(length_field)); | params.set_output("Length", std::move(length_field)); | ||||
| params.set_output("Index", std::move(index_on_spline_field)); | |||||
| } | } | ||||
| } // namespace blender::nodes::node_geo_curve_parameter_cc | } // namespace blender::nodes::node_geo_curve_spline_parameter_cc | ||||
| void register_node_type_geo_curve_parameter() | void register_node_type_geo_curve_spline_parameter() | ||||
| { | { | ||||
| namespace file_ns = blender::nodes::node_geo_curve_parameter_cc; | namespace file_ns = blender::nodes::node_geo_curve_spline_parameter_cc; | ||||
| static bNodeType ntype; | static bNodeType ntype; | ||||
| geo_node_type_base(&ntype, GEO_NODE_CURVE_PARAMETER, "Curve Parameter", NODE_CLASS_INPUT, 0); | geo_node_type_base( | ||||
| &ntype, GEO_NODE_CURVE_SPLINE_PARAMETER, "Spline Parameter", NODE_CLASS_INPUT, 0); | |||||
| ntype.geometry_node_execute = file_ns::node_geo_exec; | ntype.geometry_node_execute = file_ns::node_geo_exec; | ||||
| ntype.declare = file_ns::node_declare; | ntype.declare = file_ns::node_declare; | ||||
| nodeRegisterType(&ntype); | nodeRegisterType(&ntype); | ||||
| } | } | ||||
I think I'd go with node_geo_spline_parameter_cc (without the "curve_", just because it's shorter and matches up exactly with the name we use in the UI). I don't feel that strongly though.