/* SPDX-License-Identifier: GPL-2.0-or-later */ #include "BKE_curves.hh" #include "UI_interface.h" #include "UI_resources.h" #include "node_geometry_util.hh" namespace blender::nodes::node_geo_curve_endpoint_selection_cc { static void node_declare(NodeDeclarationBuilder &b) { b.add_input(N_("Start Size")) .min(0) .default_value(1) .supports_field() .description(N_("The amount of points to select from the start of each spline")); b.add_input(N_("End Size")) .min(0) .default_value(1) .supports_field() .description(N_("The amount of points to select from the end of each spline")); b.add_output(N_("Selection")) .field_source() .description( N_("The selection from the start and end of the splines based on the input sizes")); } class EndpointFieldInput final : public bke::CurvesFieldInput { Field start_size_; Field end_size_; public: EndpointFieldInput(Field start_size, Field end_size) : bke::CurvesFieldInput(CPPType::get(), "Endpoint Selection node"), start_size_(start_size), end_size_(end_size) { category_ = Category::Generated; } GVArray get_varray_for_context(const bke::CurvesGeometry &curves, const eAttrDomain domain, const IndexMask /*mask*/) const final { if (domain != ATTR_DOMAIN_POINT) { return {}; } if (curves.points_num() == 0) { return {}; } bke::CurvesFieldContext size_context{curves, ATTR_DOMAIN_CURVE}; fn::FieldEvaluator evaluator{size_context, curves.curves_num()}; evaluator.add(start_size_); evaluator.add(end_size_); evaluator.evaluate(); const VArray start_size = evaluator.get_evaluated(0); const VArray end_size = evaluator.get_evaluated(1); Array selection(curves.points_num(), false); MutableSpan selection_span = selection.as_mutable_span(); devirtualize_varray2(start_size, end_size, [&](const auto &start_size, const auto &end_size) { threading::parallel_for(curves.curves_range(), 1024, [&](IndexRange curves_range) { for (const int i : curves_range) { const IndexRange points = curves.points_for_curve(i); const int start = std::max(start_size[i], 0); const int end = std::max(end_size[i], 0); selection_span.slice(points.take_front(start)).fill(true); selection_span.slice(points.take_back(end)).fill(true); } }); }); return VArray::ForContainer(std::move(selection)); }; uint64_t hash() const override { return get_default_hash_2(start_size_, end_size_); } bool is_equal_to(const fn::FieldNode &other) const override { if (const EndpointFieldInput *other_endpoint = dynamic_cast( &other)) { return start_size_ == other_endpoint->start_size_ && end_size_ == other_endpoint->end_size_; } return false; } std::optional preferred_domain(const CurvesGeometry & /*curves*/) const { return ATTR_DOMAIN_POINT; } }; static void node_geo_exec(GeoNodeExecParams params) { Field start_size = params.extract_input>("Start Size"); Field end_size = params.extract_input>("End Size"); Field selection_field{std::make_shared(start_size, end_size)}; params.set_output("Selection", std::move(selection_field)); } } // namespace blender::nodes::node_geo_curve_endpoint_selection_cc void register_node_type_geo_curve_endpoint_selection() { namespace file_ns = blender::nodes::node_geo_curve_endpoint_selection_cc; static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_CURVE_ENDPOINT_SELECTION, "Endpoint Selection", NODE_CLASS_INPUT); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); }