Blender  V3.3
node_geo_set_curve_handles.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <atomic>
4 
5 #include "BKE_curves.hh"
6 
7 #include "UI_interface.h"
8 #include "UI_resources.h"
9 
10 #include "node_geometry_util.hh"
11 
13 
15 
17 {
18  b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE);
19  b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field();
20  b.add_input<decl::Vector>(N_("Position")).implicit_field();
21  b.add_input<decl::Vector>(N_("Offset")).default_value(float3(0.0f, 0.0f, 0.0f)).supports_field();
22  b.add_output<decl::Geometry>(N_("Curve"));
23 }
24 
25 static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
26 {
27  uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
28 }
29 
31 {
32  NodeGeometrySetCurveHandlePositions *data = MEM_cnew<NodeGeometrySetCurveHandlePositions>(
33  __func__);
34 
36  node->storage = data;
37 }
38 
40 {
41  switch (type) {
42  case BEZIER_HANDLE_FREE:
43  break;
44  case BEZIER_HANDLE_AUTO:
45  /* Converting auto handles to aligned handled instead of free handles is
46  * arbitrary, but expected and "standard" based on behavior in edit mode. */
47  if (other == BEZIER_HANDLE_AUTO) {
48  /* Convert pairs of auto handles to aligned handles when moving one side. */
50  other = BEZIER_HANDLE_ALIGN;
51  }
52  else {
53  /* If the other handle isn't automatic, just make the handle free. */
55  }
56  break;
59  break;
61  /* The handle can stay aligned if the other handle is also aligned (in which case the other
62  * handle should be updated to be consistent). But otherwise the handle must be made free to
63  * avoid conflicting with its "aligned" type. */
64  if (other != BEZIER_HANDLE_ALIGN) {
66  }
67  break;
68  }
69 }
70 
72  const GeometryNodeCurveHandleMode mode,
73  const Field<bool> &selection_field,
74  const Field<float3> &position_field,
75  const Field<float3> &offset_field)
76 {
78  const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
79  if (domain_size == 0) {
80  return;
81  }
82 
83  fn::FieldEvaluator evaluator{field_context, domain_size};
84  evaluator.set_selection(selection_field);
85  evaluator.add(position_field);
86  evaluator.add(offset_field);
87  evaluator.evaluate();
88  const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
89  const VArray<float3> new_positions = evaluator.get_evaluated<float3>(0);
90  const VArray<float3> new_offsets = evaluator.get_evaluated<float3>(1);
91 
92  Curves &curves_id = *component.get_for_write();
94 
95  Span<float3> positions = curves.positions();
96 
97  const bool use_left = mode == GEO_NODE_CURVE_HANDLE_LEFT;
98  MutableSpan<int8_t> handle_types = use_left ? curves.handle_types_left_for_write() :
99  curves.handle_types_right_for_write();
100  MutableSpan<int8_t> handle_types_other = use_left ? curves.handle_types_right_for_write() :
101  curves.handle_types_left_for_write();
102  MutableSpan<float3> handle_positions = use_left ? curves.handle_positions_left_for_write() :
103  curves.handle_positions_right_for_write();
104  MutableSpan<float3> handle_positions_other = use_left ?
105  curves.handle_positions_right_for_write() :
106  curves.handle_positions_left_for_write();
107 
108  threading::parallel_for(selection.index_range(), 2048, [&](IndexRange range) {
109  for (const int i : selection.slice(range)) {
110  update_handle_types_for_movement(handle_types[i], handle_types_other[i]);
111  }
112  });
113 
114  threading::parallel_for(selection.index_range(), 2048, [&](IndexRange range) {
115  for (const int i : selection.slice(range)) {
116  bke::curves::bezier::set_handle_position(positions[i],
117  HandleType(handle_types[i]),
118  HandleType(handle_types_other[i]),
119  new_positions[i] + new_offsets[i],
120  handle_positions[i],
121  handle_positions_other[i]);
122  }
123  });
124 
125  curves.calculate_bezier_auto_handles();
126 
127  curves.tag_positions_changed();
128 }
129 
131 {
132  const NodeGeometrySetCurveHandlePositions &storage = node_storage(params.node());
134 
135  GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
136  Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
137  Field<float3> position_field = params.extract_input<Field<float3>>("Position");
138  Field<float3> offset_field = params.extract_input<Field<float3>>("Offset");
139 
140  std::atomic<bool> has_curves = false;
141  std::atomic<bool> has_bezier = false;
142 
143  geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
144  if (!geometry_set.has_curves()) {
145  return;
146  }
147  has_curves = true;
149  const AttributeAccessor attributes = *component.attributes();
150  if (!attributes.contains("handle_left") || !attributes.contains("handle_right")) {
151  return;
152  }
153  has_bezier = true;
154 
156  mode,
157  selection_field,
158  position_field,
159  offset_field);
160  });
161 
162  if (has_curves && !has_bezier) {
163  params.error_message_add(NodeWarningType::Info, TIP_("Input curves do not have Bezier type"));
164  }
165 
166  params.set_output("Curve", std::move(geometry_set));
167 }
168 
169 } // namespace blender::nodes::node_geo_set_curve_handles_cc
170 
172 {
174 
175  static bNodeType ntype;
176 
178  &ntype, GEO_NODE_SET_CURVE_HANDLES, "Set Handle Positions", NODE_CLASS_GEOMETRY);
181  ntype.minwidth = 100.0f;
183  node_type_storage(&ntype,
184  "NodeGeometrySetCurveHandlePositions",
188  nodeRegisterType(&ntype);
189 }
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:27
Low-level operations for curves.
@ GEO_COMPONENT_TYPE_CURVE
#define GEO_NODE_SET_CURVE_HANDLES
Definition: BKE_node.h:1455
#define NODE_STORAGE_FUNCS(StorageT)
Definition: BKE_node.h:1563
void node_type_init(struct bNodeType *ntype, void(*initfunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4390
#define NODE_CLASS_GEOMETRY
Definition: BKE_node.h:359
void node_type_storage(struct bNodeType *ntype, const char *storagename, void(*freefunc)(struct bNode *node), void(*copyfunc)(struct bNodeTree *dest_ntree, struct bNode *dest_node, const struct bNode *src_node))
Definition: node.cc:4426
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1357
#define UNUSED(x)
#define TIP_(msgid)
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:108
@ BEZIER_HANDLE_FREE
@ BEZIER_HANDLE_ALIGN
@ BEZIER_HANDLE_VECTOR
@ BEZIER_HANDLE_AUTO
GeometryNodeCurveHandleMode
@ GEO_NODE_CURVE_HANDLE_LEFT
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
in reality light always falls off quadratically Particle Info
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to curves
@ UI_ITEM_R_EXPAND
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
IndexRange index_range() const
static CurvesGeometry & wrap(::CurvesGeometry &dna_struct)
Definition: BKE_curves.hh:138
void set_selection(Field< bool > selection)
Definition: FN_field.hh:366
OperationNode * node
void * tree
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
static void node_declare(NodeDeclarationBuilder &b)
static void node_geo_exec(GeoNodeExecParams params)
static void update_handle_types_for_movement(int8_t &type, int8_t &other)
static void set_position_in_component(CurveComponent &component, const GeometryNodeCurveHandleMode mode, const Field< bool > &selection_field, const Field< float3 > &position_field, const Field< float3 > &offset_field)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
Definition: BLI_task.hh:51
vec_base< float, 3 > float3
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node)
Definition: node.cc:1082
MutableSpan< float3 > positions
void register_node_type_geo_set_curve_handles()
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
void node_copy_standard_storage(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node)
Definition: node_util.c:55
void node_free_standard_storage(bNode *node)
Definition: node_util.c:43
signed char int8_t
Definition: stdint.h:75
GeometryComponent & get_component_for_write(GeometryComponentType component_type)
const GeometryComponent * get_component_for_read(GeometryComponentType component_type) const
bool has_curves() const
Defines a node type.
Definition: BKE_node.h:226
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:316
float minwidth
Definition: BKE_node.h:234
void(* draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr)
Definition: BKE_node.h:244
NodeDeclareFunction declare
Definition: BKE_node.h:324
#define N_(msgid)
PointerRNA * ptr
Definition: wm_files.c:3480