Blender V4.3
node_geo_offset_point_in_curve.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_task.hh"
6
7#include "BKE_curves.hh"
8
10
11namespace blender::nodes {
12
13int apply_offset_in_cyclic_range(const IndexRange range, const int start_index, const int offset)
14{
15 BLI_assert(range.contains(start_index));
16 const int start_in_range = start_index - range.first();
17 const int offset_in_range = start_in_range + offset;
18 const int mod_offset = offset_in_range % range.size();
19 if (mod_offset >= 0) {
20 return range[mod_offset];
21 }
22 return range.last(-(mod_offset + 1));
23}
24
25} // namespace blender::nodes
26
28
30{
31 b.add_input<decl::Int>("Point Index")
32 .implicit_field(implicit_field_inputs::index)
33 .description("The index of the control point to evaluate. Defaults to the current index");
34 b.add_input<decl::Int>("Offset").supports_field().description(
35 "The number of control points along the curve to traverse");
36 b.add_output<decl::Bool>("Is Valid Offset")
37 .field_source_reference_all()
39 "Whether the input control point plus the offset is a valid index of the "
40 "original curve");
41 b.add_output<decl::Int>("Point Index")
42 .field_source_reference_all()
44 "The index of the control point plus the offset within the entire "
45 "curves data-block");
46}
47
49 private:
50 const Field<int> index_;
51 const Field<int> offset_;
52
53 public:
55 : GeometryFieldInput(CPPType::get<int>(), "Offset Point in Curve"),
56 index_(std::move(index)),
57 offset_(std::move(offset))
58 {
60 }
61
63 const IndexMask &mask) const final
64 {
65 const bke::CurvesGeometry *curves_ptr = context.curves_or_strokes();
66 if (!curves_ptr) {
67 return {};
68 }
69 const bke::CurvesGeometry &curves = *curves_ptr;
70
71 const OffsetIndices points_by_curve = curves.points_by_curve();
72 const VArray<bool> cyclic = curves.cyclic();
73 const Array<int> parent_curves = curves.point_to_curve_map();
74
75 fn::FieldEvaluator evaluator{context, &mask};
76 evaluator.add(index_);
77 evaluator.add(offset_);
78 evaluator.evaluate();
79 const VArray<int> indices = evaluator.get_evaluated<int>(0);
80 const VArray<int> offsets = evaluator.get_evaluated<int>(1);
81
82 Array<int> output(mask.min_array_size());
83 mask.foreach_index([&](const int i_selection) {
84 const int i_point = std::clamp(indices[i_selection], 0, curves.points_num() - 1);
85 const int i_curve = parent_curves[i_point];
86 const IndexRange curve_points = points_by_curve[i_curve];
87 const int offset_point = i_point + offsets[i_selection];
88
89 if (cyclic[i_curve]) {
90 output[i_selection] = apply_offset_in_cyclic_range(
91 curve_points, i_point, offsets[i_selection]);
92 return;
93 }
94 output[i_selection] = std::clamp(offset_point, 0, curves.points_num() - 1);
95 });
96
97 return VArray<int>::ForContainer(std::move(output));
98 }
99
100 void for_each_field_input_recursive(FunctionRef<void(const FieldInput &)> fn) const override
101 {
104 }
105};
106
108 private:
109 const Field<int> index_;
110 const Field<int> offset_;
111
112 public:
114 : GeometryFieldInput(CPPType::get<bool>(), "Offset Valid"),
115 index_(std::move(index)),
116 offset_(std::move(offset))
117 {
119 }
120
122 const IndexMask &mask) const final
123 {
124 const bke::CurvesGeometry *curves_ptr = context.curves_or_strokes();
125 if (!curves_ptr) {
126 return {};
127 }
128 const bke::CurvesGeometry &curves = *curves_ptr;
129
130 const VArray<bool> cyclic = curves.cyclic();
131 const OffsetIndices points_by_curve = curves.points_by_curve();
132 const Array<int> parent_curves = curves.point_to_curve_map();
133
134 fn::FieldEvaluator evaluator{context, &mask};
135 evaluator.add(index_);
136 evaluator.add(offset_);
137 evaluator.evaluate();
138 const VArray<int> indices = evaluator.get_evaluated<int>(0);
139 const VArray<int> offsets = evaluator.get_evaluated<int>(1);
140
141 Array<bool> output(mask.min_array_size());
142 mask.foreach_index([&](const int i_selection) {
143 const int i_point = indices[i_selection];
144 if (!curves.points_range().contains(i_point)) {
145 output[i_selection] = false;
146 return;
147 }
148
149 const int i_curve = parent_curves[i_point];
150 const IndexRange curve_points = points_by_curve[i_curve];
151 if (cyclic[i_curve]) {
152 output[i_selection] = true;
153 return;
154 }
155 output[i_selection] = curve_points.contains(i_point + offsets[i_selection]);
156 });
157 return VArray<bool>::ForContainer(std::move(output));
158 }
159
160 void for_each_field_input_recursive(FunctionRef<void(const FieldInput &)> fn) const override
161 {
164 }
165};
166
168{
169 Field<int> index = params.extract_input<Field<int>>("Point Index");
170 Field<int> offset = params.extract_input<Field<int>>("Offset");
171
172 if (params.output_is_required("Point Index")) {
173 Field<int> curve_point_field{std::make_shared<ControlPointNeighborFieldInput>(index, offset)};
174 params.set_output("Point Index", std::move(curve_point_field));
175 }
176 if (params.output_is_required("Is Valid Offset")) {
177 Field<bool> valid_field{std::make_shared<OffsetValidFieldInput>(index, offset)};
178 params.set_output("Is Valid Offset", std::move(valid_field));
179 }
180}
181
182static void node_register()
183{
184 static blender::bke::bNodeType ntype;
186 &ntype, GEO_NODE_OFFSET_POINT_IN_CURVE, "Offset Point in Curve", NODE_CLASS_INPUT);
188 ntype.declare = node_declare;
190}
192
193} // namespace blender::nodes::node_geo_offset_point_in_curve_cc
Low-level operations for curves.
#define NODE_CLASS_INPUT
Definition BKE_node.hh:404
#define BLI_assert(a)
Definition BLI_assert.h:50
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define output
constexpr bool contains(int64_t value) const
static VArray ForContainer(ContainerT container)
int add(GField field, GVArray *varray_ptr)
Definition field.cc:756
virtual void for_each_field_input_recursive(FunctionRef< void(const FieldInput &)> fn) const
Definition field.cc:587
const FieldNode & node() const
Definition FN_field.hh:137
GVArray get_varray_for_context(const bke::GeometryFieldContext &context, const IndexMask &mask) const final
void for_each_field_input_recursive(FunctionRef< void(const FieldInput &)> fn) const override
void for_each_field_input_recursive(FunctionRef< void(const FieldInput &)> fn) const override
GVArray get_varray_for_context(const bke::GeometryFieldContext &context, const IndexMask &mask) const final
local_group_size(16, 16) .push_constant(Type b
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
void index(const bNode &, void *r_value)
int apply_offset_in_cyclic_range(IndexRange range, int start_index, int offset)
void geo_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
Defines a node type.
Definition BKE_node.hh:218
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:339
NodeDeclareFunction declare
Definition BKE_node.hh:347