Blender V4.5
node_geo_set_curve_normal.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 "BKE_curves.hh"
7
8#include "UI_interface.hh"
9#include "UI_resources.hh"
10
11#include "NOD_rna_define.hh"
12
13#include "RNA_enum_types.hh"
14
15#include "node_geometry_util.hh"
16
18
20{
21 b.use_custom_socket_order();
22 b.allow_any_socket_order();
23 b.add_default_layout();
24 b.add_input<decl::Geometry>("Curve").supported_type(
25 {GeometryComponent::Type::Curve, GeometryComponent::Type::GreasePencil});
26 b.add_output<decl::Geometry>("Curve").propagate_all().align_with_previous();
27 b.add_input<decl::Bool>("Selection").default_value(true).hide_value().field_on_all();
28 auto &normal = b.add_input<decl::Vector>("Normal")
29 .default_value({0.0f, 0.0f, 1.0f})
30 .subtype(PROP_XYZ)
31 .field_on_all();
32
33 const bNode *node = b.node_or_null();
34 if (node != nullptr) {
35 const NormalMode mode = NormalMode(node->custom1);
36 normal.available(mode == NORMAL_MODE_FREE);
37 }
38}
39
40static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
41{
42 layout->prop(ptr, "mode", UI_ITEM_NONE, "", ICON_NONE);
43}
44
45static void node_init(bNodeTree * /*tree*/, bNode *node)
46{
48}
49
51 const NormalMode mode,
52 const fn::FieldContext &curve_context,
53 const fn::FieldContext &point_context,
54 const Field<bool> &selection_field,
55 const Field<float3> &custom_normal)
56{
57 /* First evaluate the normal modes without changing the geometry, since that will influence the
58 * result of the "Normal" node if used in the input to the custom normal field evaluation. */
59 fn::FieldEvaluator evaluator(curve_context, curves.curves_num());
60 evaluator.set_selection(selection_field);
61 evaluator.evaluate();
62 const IndexMask curve_mask = evaluator.get_evaluated_selection_as_mask();
63
64 if (mode == NORMAL_MODE_FREE) {
66 point_context,
67 "custom_normal",
68 AttrDomain::Point,
69 Field<bool>(std::make_shared<bke::EvaluateOnDomainInput>(
70 selection_field, AttrDomain::Curve)),
71 custom_normal);
72 }
73
74 index_mask::masked_fill(curves.normal_mode_for_write(), int8_t(mode), curve_mask);
75
76 curves.tag_normals_changed();
77}
78
79static void set_grease_pencil_normal(GreasePencil &grease_pencil,
80 const NormalMode mode,
81 const Field<bool> &selection_field,
82 const Field<float3> &custom_normal)
83{
84 using namespace blender::bke::greasepencil;
85 for (const int layer_index : grease_pencil.layers().index_range()) {
86 Drawing *drawing = grease_pencil.get_eval_drawing(grease_pencil.layer(layer_index));
87 if (drawing == nullptr) {
88 continue;
89 }
91 drawing->strokes_for_write(),
92 mode,
93 bke::GreasePencilLayerFieldContext(grease_pencil, AttrDomain::Curve, layer_index),
94 bke::GreasePencilLayerFieldContext(grease_pencil, AttrDomain::Point, layer_index),
95 selection_field,
96 custom_normal);
97 }
98}
99
101{
102 const NormalMode mode = static_cast<NormalMode>(params.node().custom1);
103
104 GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
105 Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
106 Field<float3> custom_normal;
107 if (mode == NORMAL_MODE_FREE) {
108 custom_normal = params.extract_input<Field<float3>>("Normal");
109 }
110
111 geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
112 if (Curves *curves_id = geometry_set.get_curves_for_write()) {
113 bke::CurvesGeometry &curves = curves_id->geometry.wrap();
115 mode,
118 selection_field,
119 custom_normal);
120 }
121 if (GreasePencil *grease_pencil = geometry_set.get_grease_pencil_for_write()) {
122 set_grease_pencil_normal(*grease_pencil, mode, selection_field, custom_normal);
123 }
124 });
125
126 params.set_output("Curve", std::move(geometry_set));
127}
128
129static void node_rna(StructRNA *srna)
130{
132 "mode",
133 "Mode",
134 "Mode for curve normal evaluation",
137}
138
139static void node_register()
140{
141 static blender::bke::bNodeType ntype;
142 geo_node_type_base(&ntype, "GeometryNodeSetCurveNormal", GEO_NODE_SET_CURVE_NORMAL);
143 ntype.ui_name = "Set Curve Normal";
144 ntype.ui_description = "Set the evaluation mode for curve normals";
145 ntype.enum_name_legacy = "SET_CURVE_NORMAL";
147 ntype.declare = node_declare;
149 ntype.initfunc = node_init;
151
153
154 node_rna(ntype.rna_ext.srna);
155}
157
158} // namespace blender::nodes::node_geo_set_curve_normal_cc
Low-level operations for curves.
Low-level operations for grease pencil.
#define NODE_CLASS_GEOMETRY
Definition BKE_node.hh:447
#define GEO_NODE_SET_CURVE_NORMAL
NormalMode
@ NORMAL_MODE_MINIMUM_TWIST
@ NORMAL_MODE_FREE
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define NOD_inline_enum_accessors(member)
@ PROP_XYZ
Definition RNA_types.hh:257
#define UI_ITEM_NONE
MutableAttributeAccessor attributes_for_write()
MutableSpan< int8_t > normal_mode_for_write()
bke::CurvesGeometry & strokes_for_write()
void set_selection(Field< bool > selection)
Definition FN_field.hh:383
IndexMask get_evaluated_selection_as_mask() const
Definition field.cc:817
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void node_register_type(bNodeType &ntype)
Definition node.cc:2748
bool try_capture_field_on_geometry(MutableAttributeAccessor attributes, const fn::FieldContext &field_context, const StringRef attribute_id, AttrDomain domain, const fn::Field< bool > &selection, const fn::GField &field)
void masked_fill(MutableSpan< T > data, const T &value, const IndexMask &mask)
static void node_init(bNodeTree *, bNode *node)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static void set_curve_normal(bke::CurvesGeometry &curves, const NormalMode mode, const fn::FieldContext &curve_context, const fn::FieldContext &point_context, const Field< bool > &selection_field, const Field< float3 > &custom_normal)
static void node_declare(NodeDeclarationBuilder &b)
static void set_grease_pencil_normal(GreasePencil &grease_pencil, const NormalMode mode, const Field< bool > &selection_field, const Field< float3 > &custom_normal)
static void node_geo_exec(GeoNodeExecParams params)
PropertyRNA * RNA_def_node_enum(StructRNA *srna, const char *identifier, const char *ui_name, const char *ui_description, const EnumPropertyItem *static_items, const EnumRNAAccessors accessors, std::optional< int > default_value, const EnumPropertyItemFunc item_func, const bool allow_animation)
void geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
const EnumPropertyItem rna_enum_curve_normal_mode_items[]
Definition rna_curves.cc:54
StructRNA * srna
Definition RNA_types.hh:909
int16_t custom1
void modify_geometry_sets(ForeachSubGeometryCallback callback)
GreasePencil * get_grease_pencil_for_write()
Defines a node type.
Definition BKE_node.hh:226
std::string ui_description
Definition BKE_node.hh:232
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:277
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:347
const char * enum_name_legacy
Definition BKE_node.hh:235
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:247
NodeDeclareFunction declare
Definition BKE_node.hh:355
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
PointerRNA * ptr
Definition wm_files.cc:4226