Blender V5.0
node_geo_menu_switch.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_array_utils.hh"
6
9
10#include "DNA_node_types.h"
11
12#include "FN_multi_function.hh"
13
15#include "UI_resources.hh"
16
18#include "NOD_rna_define.hh"
19#include "NOD_socket.hh"
24
25#include "BLO_read_write.hh"
26
27#include "RNA_enum_types.hh"
28#include "RNA_prototypes.hh"
29
31#include "BKE_screen.hh"
32
33#include "WM_api.hh"
34
35#include "COM_node_operation.hh"
36#include "COM_result.hh"
37#include "COM_utilities.hh"
38
40
42
44{
45 b.use_custom_socket_order();
46 b.allow_any_socket_order();
47
48 const bNodeTree *ntree = b.tree_or_null();
49 const bNode *node = b.node_or_null();
50 if (node == nullptr) {
51 return;
52 }
53 const NodeMenuSwitch &storage = node_storage(*node);
54 const eNodeSocketDatatype data_type = eNodeSocketDatatype(storage.data_type);
55 const bool supports_fields = socket_type_supports_fields(data_type) &&
56 ntree->type == NTREE_GEOMETRY;
57
58 StructureType value_structure_type = socket_type_always_single(data_type) ?
59 StructureType::Single :
60 StructureType::Dynamic;
61 StructureType menu_structure_type = value_structure_type;
62
63 if (ntree->type == NTREE_COMPOSIT) {
64 const bool is_single_compositor_type = compositor::Result::is_single_value_only_type(
66 if (is_single_compositor_type) {
67 value_structure_type = StructureType::Single;
68 }
69 menu_structure_type = StructureType::Single;
70 }
71
72 auto &output = b.add_output(data_type, "Output");
73 if (supports_fields) {
74 output.dependent_field().reference_pass_all();
75 }
77 output.propagate_all();
78 }
80 output.reference_pass_all();
81 }
82 output.structure_type(value_structure_type);
83
84 b.add_default_layout();
85
86 auto &menu = b.add_input<decl::Menu>("Menu");
87 if (supports_fields) {
88 menu.supports_field();
89 }
90 menu.structure_type(menu_structure_type);
91 menu.optional_label();
92
93 for (const NodeEnumItem &enum_item : storage.enum_definition.items()) {
94 const std::string identifier = MenuSwitchItemsAccessor::socket_identifier_for_item(enum_item);
95 auto &input = b.add_input(data_type, enum_item.name, identifier)
96 .socket_name_ptr(
97 &ntree->id, MenuSwitchItemsAccessor::item_srna, &enum_item, "name")
98 .compositor_realization_mode(CompositorInputRealizationMode::None)
99 .description("Becomes the output value if it is chosen by the menu input");
100 if (supports_fields) {
101 input.supports_field();
102 }
103 /* Labels are ugly in combination with data-block pickers and are usually disabled. */
104 input.optional_label(ELEM(data_type, SOCK_OBJECT, SOCK_IMAGE, SOCK_COLLECTION, SOCK_MATERIAL));
105 input.structure_type(value_structure_type);
106 auto &item_output = b.add_output<decl::Bool>(enum_item.name, std::move(identifier))
107 .align_with_previous()
108 .description("True if this item is chosen by the menu input");
109 if (supports_fields) {
110 item_output.dependent_field({menu.index()});
111 item_output.structure_type(menu_structure_type);
112 }
113 }
114
115 b.add_input<decl::Extend>("", "__extend__")
116 .structure_type(StructureType::Dynamic)
117 .custom_draw([](CustomSocketDrawParams &params) {
118 uiLayout &layout = params.layout;
120 PointerRNA op_ptr = layout.op("node.enum_definition_item_add", "", ICON_ADD);
121 RNA_int_set(&op_ptr, "node_identifier", params.node.identifier);
122 });
123}
124
125static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
126{
127 layout->prop(ptr, "data_type", UI_ITEM_NONE, "", ICON_NONE);
128}
129
130static void node_init(bNodeTree *tree, bNode *node)
131{
133 data->data_type = tree->type == NTREE_GEOMETRY ? SOCK_GEOMETRY : SOCK_RGBA;
134 data->enum_definition.next_identifier = 0;
135 data->enum_definition.items_array = nullptr;
136 data->enum_definition.items_num = 0;
137 node->storage = data;
138
141}
142
148
149static void node_copy_storage(bNodeTree * /*dst_tree*/, bNode *dst_node, const bNode *src_node)
150{
151 const NodeMenuSwitch &src_storage = node_storage(*src_node);
152 NodeMenuSwitch *dst_storage = MEM_dupallocN<NodeMenuSwitch>(__func__, src_storage);
153 dst_node->storage = dst_storage;
154
156}
157
159{
160 const eNodeSocketDatatype data_type = eNodeSocketDatatype(params.other_socket().type);
161 if (params.in_out() == SOCK_IN) {
162 if (data_type == SOCK_MENU) {
163 params.add_item(IFACE_("Menu"), [](LinkSearchOpParams &params) {
164 bNode &node = params.add_node("GeometryNodeMenuSwitch");
165 params.update_and_connect_available_socket(node, "Menu");
166 });
167 }
168 }
169 else {
170 if (data_type != SOCK_MENU) {
171 params.add_item(IFACE_("Output"), [](LinkSearchOpParams &params) {
172 bNode &node = params.add_node("GeometryNodeMenuSwitch");
173 node_storage(node).data_type = params.socket.type;
174 params.update_and_connect_available_socket(node, "Output");
175 });
176 }
177 }
178}
179
184class MenuSwitchFn : public mf::MultiFunction {
185 const NodeEnumDefinition &enum_def_;
186 const CPPType &type_;
187 mf::Signature signature_;
188
189 public:
190 MenuSwitchFn(const NodeEnumDefinition &enum_def, const CPPType &type)
191 : enum_def_(enum_def), type_(type)
192 {
193 mf::SignatureBuilder builder{"Menu Switch", signature_};
194 builder.single_input<MenuValue>("Menu");
195 for (const NodeEnumItem &enum_item : enum_def.items()) {
196 builder.single_input(enum_item.name, type);
197 }
198 builder.single_output("Output", type, mf::ParamFlag::SupportsUnusedOutput);
199 for (const NodeEnumItem &item : enum_def.items()) {
200 builder.single_output<bool>(item.name, mf::ParamFlag::SupportsUnusedOutput);
201 }
202
203 this->set_signature(&signature_);
204 }
205
206 void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override
207 {
208 const int value_inputs_start = 1;
209 const int inputs_num = enum_def_.items_num;
210 const VArray<MenuValue> values = params.readonly_single_input<MenuValue>(0, "Menu");
211 /* Use one extra mask at the end for invalid indices. */
212 const int invalid_index = inputs_num;
213
214 GMutableSpan value_output = params.uninitialized_single_output_if_required(1 + inputs_num,
215 "Output");
216
217 Array<MutableSpan<bool>> item_mask_outputs(inputs_num);
218 for (const int item_i : IndexRange(inputs_num)) {
219 const int param_index = 2 + inputs_num + item_i;
220 item_mask_outputs[item_i] = params.uninitialized_single_output_if_required<bool>(
221 param_index);
222 }
223
224 auto find_item_index = [&](const MenuValue value) -> int {
225 for (const int i : enum_def_.items().index_range()) {
226 const NodeEnumItem &item = enum_def_.items()[i];
227 if (item.identifier == value.value) {
228 return i;
229 }
230 }
231 return invalid_index;
232 };
233
234 if (const std::optional<MenuValue> value = values.get_if_single()) {
235 const int index = find_item_index(*value);
236 if (index < inputs_num) {
237 if (!value_output.is_empty()) {
238 const GVArray inputs = params.readonly_single_input(value_inputs_start + index);
239 inputs.materialize_to_uninitialized(mask, value_output.data());
240 }
241 for (const int item_i : IndexRange(inputs_num)) {
242 MutableSpan<bool> item_mask_output = item_mask_outputs[item_i];
243 if (!item_mask_output.is_empty()) {
244 index_mask::masked_fill(item_mask_output, item_i == index, mask);
245 }
246 }
247 }
248 else {
249 if (!value_output.is_empty()) {
250 type_.fill_construct_indices(type_.default_value(), value_output.data(), mask);
251 }
252 for (const int item_i : IndexRange(inputs_num)) {
253 MutableSpan<bool> item_mask_output = item_mask_outputs[item_i];
254 if (!item_mask_output.is_empty()) {
255 index_mask::masked_fill(item_mask_output, false, mask);
256 }
257 }
258 }
259 return;
260 }
261
262 IndexMaskMemory memory;
263 Array<IndexMask> masks(inputs_num + 1);
265 mask, memory, [&](const int64_t i) { return find_item_index(values[i]); }, masks);
266
267 for (const int item_i : IndexRange(inputs_num)) {
268 const IndexMask &mask_for_index = masks[item_i];
269 if (!mask_for_index.is_empty() && !value_output.is_empty()) {
270 const GVArray inputs = params.readonly_single_input(value_inputs_start + item_i);
271 inputs.materialize_to_uninitialized(mask_for_index, value_output.data());
272 }
273 MutableSpan<bool> item_mask_output = item_mask_outputs[item_i];
274 if (!item_mask_output.is_empty()) {
275 if (mask.size() != mask_for_index.size()) {
276 /* First set output to false before setting selected items to true. */
277 index_mask::masked_fill(item_mask_output, false, mask);
278 }
279 index_mask::masked_fill(item_mask_output, true, mask_for_index);
280 }
281 }
282
283 type_.fill_construct_indices(type_.default_value(), value_output.data(), masks[invalid_index]);
284 }
285};
286
288 private:
289 const bNode &node_;
290 bool can_be_field_ = false;
291 const NodeEnumDefinition &enum_def_;
292 const CPPType *field_base_type_;
293
294 public:
297 : node_(node), enum_def_(node_storage(node).enum_definition)
298 {
299 const NodeMenuSwitch &storage = node_storage(node);
300 const eNodeSocketDatatype data_type = eNodeSocketDatatype(storage.data_type);
301 can_be_field_ = socket_type_supports_fields(data_type);
302 const bke::bNodeSocketType *socket_type = bke::node_socket_type_find_static(data_type);
303 BLI_assert(socket_type != nullptr);
304 field_base_type_ = socket_type->base_cpp_type;
305
306 MutableSpan<int> lf_index_by_bsocket = lf_graph_info.mapping.lf_index_by_bsocket;
307 debug_name_ = node.name;
308 lf_index_by_bsocket[node.input_socket(0).index_in_tree()] = inputs_.append_and_get_index_as(
310 for (const int i : enum_def_.items().index_range()) {
311 const NodeEnumItem &enum_item = enum_def_.items()[i];
312 lf_index_by_bsocket[node.input_socket(i + 1).index_in_tree()] =
313 inputs_.append_and_get_index_as(
315 }
316 lf_index_by_bsocket[node.output_socket(0).index_in_tree()] = outputs_.append_and_get_index_as(
318 for (const int i : enum_def_.items().index_range()) {
319 const NodeEnumItem &enum_item = enum_def_.items()[i];
320 lf_index_by_bsocket[node.output_socket(i + 1).index_in_tree()] =
321 outputs_.append_and_get_index_as(enum_item.name, CPPType::get<SocketValueVariant>());
322 }
323 }
324
325 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
326 {
327 SocketValueVariant condition_variant = params.get_input<SocketValueVariant>(0);
328 if (condition_variant.is_context_dependent_field() && can_be_field_) {
329 this->execute_field(condition_variant.get<Field<MenuValue>>(), params);
330 }
331 else {
332 this->execute_single(condition_variant.get<MenuValue>(), params);
333 }
334 }
335
336 void execute_single(const MenuValue condition, lf::Params &params) const
337 {
338 for (const int i : IndexRange(enum_def_.items_num)) {
339 const NodeEnumItem &enum_item = enum_def_.items_array[i];
340 const int input_index = i + 1;
341 const bool is_selected = enum_item.identifier == condition.value;
342 if (is_selected) {
343 SocketValueVariant *value_to_forward =
344 params.try_get_input_data_ptr_or_request<SocketValueVariant>(input_index);
345 if (value_to_forward == nullptr) {
346 /* Try again when the value is available. */
347 return;
348 }
349
350 params.set_output(0, std::move(*value_to_forward));
351 }
352 else {
353 params.set_input_unused(input_index);
354 }
355 if (!params.output_was_set(i + 1)) {
356 params.set_output(i + 1, SocketValueVariant(is_selected));
357 }
358 }
359 /* No guarantee that the switch input matches any enum,
360 * set default outputs to ensure valid state. */
362 }
363
365 {
366 /* When the condition is a non-constant field, we need all inputs. */
367 const int values_num = this->enum_def_.items_num;
368 Array<SocketValueVariant *, 8> input_values(values_num);
369 for (const int i : IndexRange(values_num)) {
370 const int input_index = i + 1;
371 input_values[i] = params.try_get_input_data_ptr_or_request<SocketValueVariant>(input_index);
372 }
373 if (input_values.as_span().contains(nullptr)) {
374 /* Try again when inputs are available. */
375 return;
376 }
377
378 Vector<GField> item_fields(enum_def_.items_num + 1);
379 item_fields[0] = std::move(condition);
380 for (const int i : IndexRange(enum_def_.items_num)) {
381 item_fields[i + 1] = input_values[i]->extract<GField>();
382 }
383 std::unique_ptr<MultiFunction> multi_function = std::make_unique<MenuSwitchFn>(
384 enum_def_, *field_base_type_);
385 std::shared_ptr<fn::FieldOperation> operation = FieldOperation::from(std::move(multi_function),
386 std::move(item_fields));
387
388 params.set_output(0, SocketValueVariant::From(GField(operation, 0)));
389 for (const int item_i : IndexRange(enum_def_.items_num)) {
390 params.set_output(item_i + 1, SocketValueVariant::From(GField(operation, item_i + 1)));
391 }
392 }
393};
394
401 const NodeEnumDefinition &enum_def_;
402
403 public:
405 : enum_def_(node_storage(node).enum_definition)
406 {
407 debug_name_ = "Menu Switch Socket Usage";
408 inputs_.append_as("Condition", CPPType::get<SocketValueVariant>());
409 for (const int i : IndexRange(enum_def_.items_num)) {
410 const NodeEnumItem &enum_item = enum_def_.items()[i];
411 outputs_.append_as(enum_item.name, CPPType::get<bool>());
412 }
413 }
414
415 void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
416 {
417 const SocketValueVariant &condition_variant = params.get_input<SocketValueVariant>(0);
418 if (condition_variant.is_context_dependent_field()) {
419 for (const int i : IndexRange(enum_def_.items_num)) {
420 params.set_output(i, true);
421 }
422 }
423 else {
424 const MenuValue value = condition_variant.get<MenuValue>();
425 for (const int i : IndexRange(enum_def_.items_num)) {
426 const NodeEnumItem &enum_item = enum_def_.items()[i];
427 params.set_output(i, value.value == enum_item.identifier);
428 }
429 }
430 }
431};
432
433using namespace blender::compositor;
434
436 public:
438
439 void execute() override
440 {
441 Result &value_output = this->get_result("Output");
442 const MenuValue menu_identifier = this->get_input("Menu").get_single_value<MenuValue>();
443 const NodeEnumDefinition &enum_definition = node_storage(bnode()).enum_definition;
444 bool found_item = false;
445
446 for (const int i : IndexRange(enum_definition.items_num)) {
447 const NodeEnumItem &enum_item = enum_definition.items()[i];
448 const std::string identifier = MenuSwitchItemsAccessor::socket_identifier_for_item(
449 enum_item);
450 const bool is_selected = enum_item.identifier == menu_identifier.value;
451 Result &item_output = this->get_result(identifier);
452 if (item_output.should_compute()) {
453 item_output.allocate_single_value();
454 item_output.set_single_value(is_selected);
455 }
456 if (!is_selected) {
457 continue;
458 }
459 const Result &input = this->get_input(identifier);
460 value_output.share_data(input);
461 found_item = true;
462 }
463
464 if (!found_item) {
465 /* The menu identifier didn't match any item, so allocate an invalid output. */
466 value_output.allocate_invalid();
467 }
468 }
469};
470
472{
473 return new MenuSwitchOperation(context, node);
474}
475
477{
478 bNodeTree &tree = *reinterpret_cast<bNodeTree *>(ptr->owner_id);
479 bNode &node = *static_cast<bNode *>(ptr->data);
480
481 layout->prop(ptr, "data_type", UI_ITEM_NONE, "", ICON_NONE);
482
483 if (uiLayout *panel = layout->panel(C, "menu_switch_items", false, IFACE_("Menu Items"))) {
485 C, panel, tree, node);
487 tree, node, [&](PointerRNA *item_ptr) {
488 panel->use_property_split_set(true);
489 panel->use_property_decorate_set(false);
490 panel->prop(item_ptr, "description", UI_ITEM_NONE, std::nullopt, ICON_NONE);
491 });
492 }
493}
494
499
505
506static void node_blend_write(const bNodeTree & /*ntree*/, const bNode &node, BlendWriter &writer)
507{
509}
510
511static void node_blend_read(bNodeTree & /*ntree*/, bNode &node, BlendDataReader &reader)
512{
514}
515
517 const bNode &node,
518 const bNodeSocket &output_socket)
519{
520 const NodeMenuSwitch &storage = node_storage(node);
521 if (storage.enum_definition.items_num == 0) {
522 return nullptr;
523 }
524 if (&output_socket == node.outputs.first) {
525 /* Default to the first enum item input. */
526 return &node.input_socket(1);
527 }
528 return nullptr;
529}
530
533 PropertyRNA * /*prop*/,
534 bool *r_free)
535{
536 *r_free = true;
537 const bNodeTree &ntree = *reinterpret_cast<bNodeTree *>(ptr->owner_id);
538 blender::bke::bNodeTreeType *ntree_type = ntree.typeinfo;
539 return enum_items_filter(
542 return ntree_type->valid_socket_type(ntree_type, socket_type);
543 });
544}
545
546static void node_rna(StructRNA *srna)
547{
549 "data_type",
550 "Data Type",
551 "",
556}
557
558static void register_node()
559{
560 static blender::bke::bNodeType ntype;
561
562 common_node_type_base(&ntype, "GeometryNodeMenuSwitch", GEO_NODE_MENU_SWITCH);
563 ntype.ui_name = "Menu Switch";
564 ntype.ui_description = "Select from multiple inputs by name";
565 ntype.enum_name_legacy = "MENU_SWITCH";
567 ntype.declare = node_declare;
568 ntype.initfunc = node_init;
581
582 node_rna(ntype.rna_ext.srna);
583}
585
586} // namespace blender::nodes::node_geo_menu_switch_cc
587
588namespace blender::nodes {
589
590std::unique_ptr<LazyFunction> get_menu_switch_node_lazy_function(
591 const bNode &node, GeometryNodesLazyFunctionGraphInfo &lf_graph_info)
592{
593 using namespace node_geo_menu_switch_cc;
595 return std::make_unique<LazyFunctionForMenuSwitchNode>(node, lf_graph_info);
596}
597
598std::unique_ptr<LazyFunction> get_menu_switch_node_socket_usage_lazy_function(const bNode &node)
599{
600 using namespace node_geo_menu_switch_cc;
602 return std::make_unique<LazyFunctionForMenuSwitchSocketUsage>(node);
603}
604
606
608{
609 BLO_write_string(writer, item.name);
610 BLO_write_string(writer, item.description);
611}
612
614{
615 BLO_read_string(reader, &item.name);
616 BLO_read_string(reader, &item.description);
617}
618
619} // namespace blender::nodes
#define NODE_CLASS_CONVERTER
Definition BKE_node.hh:453
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1240
#define GEO_NODE_MENU_SWITCH
#define BLI_assert(a)
Definition BLI_assert.h:46
#define ELEM(...)
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
Definition readfile.cc:5828
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
#define IFACE_(msgid)
@ NTREE_GEOMETRY
@ NTREE_COMPOSIT
@ SOCK_IN
eNodeSocketDatatype
@ SOCK_MATERIAL
@ SOCK_IMAGE
@ SOCK_COLLECTION
@ SOCK_GEOMETRY
@ SOCK_OBJECT
@ SOCK_RGBA
@ SOCK_MENU
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define NOD_storage_enum_accessors(member)
#define C
Definition RandGen.cpp:29
#define UI_ITEM_NONE
BMesh const char void * data
long long int int64_t
Span< T > as_span() const
Definition BLI_array.hh:243
static const CPPType & get()
static void from_groups(const IndexMask &universe, IndexMaskMemory &memory, Fn &&get_group_index, MutableSpan< IndexMask > r_masks)
constexpr bool is_empty() const
Definition BLI_span.hh:509
std::optional< T > get_if_single() const
NodeOperation(Context &context, DNode node)
Result & get_result(StringRef identifier)
Definition operation.cc:39
Result & get_input(StringRef identifier) const
Definition operation.cc:138
void share_data(const Result &source)
Definition result.cc:523
static bool is_single_value_only_type(ResultType type)
Definition result.cc:44
void set_single_value(const T &value)
const T & get_single_value() const
static std::shared_ptr< FieldOperation > from(std::shared_ptr< const mf::MultiFunction > function, Vector< GField > inputs={})
Definition FN_field.hh:242
static SocketValueVariant From(T &&value)
void execute_impl(lf::Params &params, const lf::Context &) const override
void execute_single(const MenuValue condition, lf::Params &params) const
LazyFunctionForMenuSwitchNode(const bNode &node, GeometryNodesLazyFunctionGraphInfo &lf_graph_info)
void execute_field(Field< MenuValue > condition, lf::Params &params) const
void execute_impl(lf::Params &params, const lf::Context &) const override
MenuSwitchFn(const NodeEnumDefinition &enum_def, const CPPType &type)
void call(const IndexMask &mask, mf::Params params, mf::Context) const override
KDTree_3d * tree
#define input
#define output
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
bool can_contain_reference(eNodeSocketDatatype socket_type)
bool can_contain_referenced_data(eNodeSocketDatatype socket_type)
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
bNodeSocketType * node_socket_type_find_static(int type, int subtype=0)
Definition node.cc:2471
void node_type_storage(bNodeType &ntype, std::optional< StringRefNull > storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:5414
ResultType socket_data_type_to_result_type(const eNodeSocketDatatype data_type, const std::optional< int > dimensions=std::nullopt)
Definition utilities.cc:68
void masked_fill(MutableSpan< T > data, const T &value, const IndexMask &mask)
static void node_blend_write(const bNodeTree &, const bNode &node, BlendWriter &writer)
static void node_blend_read(bNodeTree &, bNode &node, BlendDataReader &reader)
static void node_copy_storage(bNodeTree *, bNode *dst_node, const bNode *src_node)
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static const bNodeSocket * node_internally_linked_input(const bNodeTree &, const bNode &node, const bNodeSocket &output_socket)
static void node_declare(blender::nodes::NodeDeclarationBuilder &b)
static void node_init(bNodeTree *tree, bNode *node)
static NodeOperation * get_compositor_operation(Context &context, DNode node)
static const EnumPropertyItem * data_type_items_callback(bContext *, PointerRNA *ptr, PropertyRNA *, bool *r_free)
static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
static bool node_insert_link(bke::NodeInsertLinkParams &params)
static void draw_items_list_with_operators(const bContext *C, uiLayout *layout, const bNodeTree &tree, const bNode &node)
static void draw_active_item_props(const bNodeTree &tree, const bNode &node, const FunctionRef< void(PointerRNA *item_ptr)> draw_item)
void blend_write(BlendWriter *writer, const bNode &node)
Accessor::ItemT * add_item_with_name(bNode &node, const char *name)
void blend_read_data(BlendDataReader *reader, bNode &node)
void copy_array(const bNode &src_node, bNode &dst_node)
bool try_add_item_via_any_extend_socket(bNodeTree &ntree, bNode &extend_node, bNode &storage_node, bNodeLink &link, const std::optional< StringRef > socket_identifier=std::nullopt, typename Accessor::ItemT **r_new_item=nullptr)
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)
std::unique_ptr< LazyFunction > get_menu_switch_node_socket_usage_lazy_function(const bNode &node)
bool socket_type_supports_fields(const eNodeSocketDatatype socket_type)
void set_default_remaining_node_outputs(lf::Params &params, const bNode &node)
bool socket_type_always_single(const eNodeSocketDatatype socket_type)
std::unique_ptr< LazyFunction > get_menu_switch_node_lazy_function(const bNode &node, GeometryNodesLazyFunctionGraphInfo &lf_graph_info)
const EnumPropertyItem * enum_items_filter(const EnumPropertyItem *original_item_array, FunctionRef< bool(const EnumPropertyItem &item)> fn)
void common_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
static blender::bke::bNodeSocketTemplate inputs[]
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
const EnumPropertyItem rna_enum_node_socket_data_type_items[]
StructRNA * srna
void * first
NodeEnumDefinition enum_definition
bNodeTreeTypeHandle * typeinfo
char name[64]
int16_t type_legacy
void * storage
ListBase outputs
Defines a socket type.
Definition BKE_node.hh:158
const blender::CPPType * base_cpp_type
Definition BKE_node.hh:205
bool(* valid_socket_type)(bNodeTreeType *ntreetype, bNodeSocketType *socket_type)
Definition BKE_node.hh:529
Defines a node type.
Definition BKE_node.hh:238
NodeInternallyLinkedInputFunction internally_linked_input
Definition BKE_node.hh:384
NodeBlendWriteFunction blend_write_storage_content
Definition BKE_node.hh:390
std::string ui_description
Definition BKE_node.hh:244
NodeBlendDataReadFunction blend_data_read_storage_content
Definition BKE_node.hh:391
NodeGetCompositorOperationFunction get_compositor_operation
Definition BKE_node.hh:348
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:289
void(* draw_buttons_ex)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:261
const char * enum_name_legacy
Definition BKE_node.hh:247
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:259
bool(* insert_link)(NodeInsertLinkParams &params)
Definition BKE_node.hh:333
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition BKE_node.hh:378
NodeDeclareFunction declare
Definition BKE_node.hh:362
void(* register_operators)()
Definition BKE_node.hh:417
bool ignore_inferred_input_socket_visibility
Definition BKE_node.hh:422
static std::string socket_identifier_for_item(const NodeEnumItem &item)
static void blend_write_item(BlendWriter *writer, const ItemT &item)
static void blend_read_data_item(BlendDataReader *reader, ItemT &item)
PanelLayout panel(const bContext *C, blender::StringRef idname, bool default_closed)
void emboss_set(blender::ui::EmbossType emboss)
PointerRNA op(wmOperatorType *ot, std::optional< blender::StringRef > name, int icon, blender::wm::OpCallContext context, eUI_Item_Flag flag)
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)
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4238