Blender V5.0
node_declaration.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
9
10#include "BLI_assert.h"
11#include "BLI_listbase.h"
12#include "BLI_utildefines.h"
13
15#include "BKE_node.hh"
16#include "BKE_node_runtime.hh"
18
19#include "RNA_access.hh"
20
21namespace blender::nodes {
22
23static void reset_declaration(NodeDeclaration &declaration)
24{
25 std::destroy_at(&declaration);
26 new (&declaration) NodeDeclaration();
27}
28
30 NodeDeclaration &r_declaration,
31 const bNodeTree *ntree,
32 const bNode *node)
33{
34 reset_declaration(r_declaration);
35 NodeDeclarationBuilder node_decl_builder{typeinfo, r_declaration, ntree, node};
36 typeinfo.declare(node_decl_builder);
37 node_decl_builder.finalize();
38}
39
40void NodeDeclarationBuilder::build_remaining_anonymous_attribute_relations()
41{
42 auto is_data_socket_decl = [](const SocketDeclaration *socket_decl) {
43 return ELEM(socket_decl->socket_type, SOCK_GEOMETRY, SOCK_BUNDLE, SOCK_CLOSURE);
44 };
45
46 Vector<int> data_inputs;
47 for (const int i : declaration_.inputs.index_range()) {
48 if (is_data_socket_decl(declaration_.inputs[i])) {
49 data_inputs.append(i);
50 }
51 }
52 Vector<int> data_outputs;
53 for (const int i : declaration_.outputs.index_range()) {
54 if (is_data_socket_decl(declaration_.outputs[i])) {
55 data_outputs.append(i);
56 }
57 }
58
59 for (BaseSocketDeclarationBuilder *socket_builder : input_socket_builders_) {
60 if (socket_builder->field_on_all_) {
61 aal::RelationsInNode &relations = this->get_anonymous_attribute_relations();
62 const int field_input = socket_builder->decl_base_->index;
63 for (const int data_input : data_inputs) {
64 relations.eval_relations.append({field_input, data_input});
65 }
66 }
67 }
68 for (BaseSocketDeclarationBuilder *socket_builder : output_socket_builders_) {
69 if (socket_builder->field_on_all_) {
70 aal::RelationsInNode &relations = this->get_anonymous_attribute_relations();
71 const int field_output = socket_builder->decl_base_->index;
72 for (const int data_output : data_outputs) {
73 relations.available_relations.append({field_output, data_output});
74 }
75 }
76 if (socket_builder->reference_pass_all_) {
77 aal::RelationsInNode &relations = this->get_anonymous_attribute_relations();
78 const int field_output = socket_builder->decl_base_->index;
79 for (const int input_i : declaration_.inputs.index_range()) {
80 SocketDeclaration &input_socket_decl = *declaration_.inputs[input_i];
81 if (input_socket_decl.input_field_type != InputSocketFieldType::None ||
82 ELEM(input_socket_decl.socket_type, SOCK_BUNDLE, SOCK_CLOSURE))
83 {
84 relations.reference_relations.append({input_i, field_output});
85 }
86 }
87 }
88 if (socket_builder->propagate_from_all_) {
89 aal::RelationsInNode &relations = this->get_anonymous_attribute_relations();
90 const int data_output = socket_builder->decl_base_->index;
91 for (const int data_input : data_inputs) {
92 relations.propagate_relations.append({data_input, data_output});
93 }
94 }
95 }
96}
97
99{
100 this->build_remaining_anonymous_attribute_relations();
101 if (is_function_node_) {
102 for (SocketDeclaration *socket_decl : declaration_.inputs) {
103 socket_decl->structure_type = StructureType::Dynamic;
104 }
105 for (SocketDeclaration *socket_decl : declaration_.outputs) {
106 socket_decl->structure_type = StructureType::Dynamic;
107 }
108 }
109#ifndef NDEBUG
110 declaration_.assert_valid();
111#endif
112}
113
116 const bNodeTree *ntree,
117 const bNode *node)
118 : DeclarationListBuilder(*this, declaration.root_items),
119 typeinfo_(typeinfo),
120 declaration_(declaration),
121 ntree_(ntree),
122 node_(node)
123{
124 /* Unused in release builds, but used for BLI_assert() in debug builds. */
125 UNUSED_VARS(typeinfo_);
126}
127
129{
130 declaration_.use_custom_socket_order = enable;
131}
132
134{
135 BLI_assert(declaration_.use_custom_socket_order);
136 declaration_.allow_any_socket_order = enable;
137}
138
140{
141 if (in_out == SOCK_IN) {
142 return inputs;
143 }
144 return outputs;
145}
146
148
149std::ostream &operator<<(std::ostream &stream, const RelationsInNode &relations)
150{
151 stream << "Propagate Relations: " << relations.propagate_relations.size() << "\n";
152 for (const PropagateRelation &relation : relations.propagate_relations) {
153 stream << " " << relation.from_geometry_input << " -> " << relation.to_geometry_output
154 << "\n";
155 }
156 stream << "Reference Relations: " << relations.reference_relations.size() << "\n";
157 for (const ReferenceRelation &relation : relations.reference_relations) {
158 stream << " " << relation.from_field_input << " -> " << relation.to_field_output << "\n";
159 }
160 stream << "Eval Relations: " << relations.eval_relations.size() << "\n";
161 for (const EvalRelation &relation : relations.eval_relations) {
162 stream << " eval " << relation.field_input << " on " << relation.geometry_input << "\n";
163 }
164 stream << "Available Relations: " << relations.available_relations.size() << "\n";
165 for (const AvailableRelation &relation : relations.available_relations) {
166 stream << " " << relation.field_output << " available on " << relation.geometry_output
167 << "\n";
168 }
169 stream << "Available on None: " << relations.available_on_none.size() << "\n";
170 for (const int i : relations.available_on_none) {
171 stream << " output " << i << " available on none\n";
172 }
173 return stream;
174}
175
176} // namespace anonymous_attribute_lifetime
177
181 Vector<const SocketDeclaration *> &r_flat_outputs)
182{
183 /* Expected item order unless any order is allowed: outputs, inputs, panels. */
184 bool found_input = false;
185 bool found_panel = false;
186
187 for (const ItemDeclaration *item_decl : items) {
188 if (const auto *socket_decl = dynamic_cast<const SocketDeclaration *>(item_decl)) {
189 if (socket_decl->in_out == SOCK_IN) {
190 BLI_assert(node_decl.allow_any_socket_order || !found_panel);
191 found_input = true;
192 r_flat_inputs.append(socket_decl);
193 }
194 else {
195 BLI_assert(node_decl.allow_any_socket_order || (!found_input && !found_panel));
196 r_flat_outputs.append(socket_decl);
197 }
198 }
199 else if (const auto *panel_decl = dynamic_cast<const PanelDeclaration *>(item_decl)) {
200 found_panel = true;
201 assert_valid_panels_recursive(node_decl, panel_decl->items, r_flat_inputs, r_flat_outputs);
202 }
203 }
204 UNUSED_VARS(found_input, found_panel);
205}
206
208{
209 if (!this->use_custom_socket_order) {
210 /* Skip validation for conventional socket layouts. Those are reordered in drawing code. */
211 return;
212 }
213
216 assert_valid_panels_recursive(*this, this->root_items, flat_inputs, flat_outputs);
217
218 BLI_assert(this->inputs.as_span() == flat_inputs);
219 BLI_assert(this->outputs.as_span() == flat_outputs);
220}
221
222bool NodeDeclaration::matches(const bNode &node) const
223{
224 const bNodeSocket *current_input = static_cast<bNodeSocket *>(node.inputs.first);
225 const bNodeSocket *current_output = static_cast<bNodeSocket *>(node.outputs.first);
226 const bNodePanelState *current_panel = node.panel_states_array;
227 for (const ItemDeclarationPtr &item_decl : this->all_items) {
228 if (const SocketDeclaration *socket_decl = dynamic_cast<const SocketDeclaration *>(
229 item_decl.get()))
230 {
231 switch (socket_decl->in_out) {
232 case SOCK_IN:
233 if (current_input == nullptr || !socket_decl->matches(*current_input)) {
234 return false;
235 }
236 current_input = current_input->next;
237 break;
238 case SOCK_OUT:
239 if (current_output == nullptr || !socket_decl->matches(*current_output)) {
240 return false;
241 }
242 current_output = current_output->next;
243 break;
244 }
245 }
246 else if (const PanelDeclaration *panel_decl = dynamic_cast<const PanelDeclaration *>(
247 item_decl.get()))
248 {
249 if (!node.panel_states().contains_ptr(current_panel) || !panel_decl->matches(*current_panel))
250 {
251 return false;
252 }
253 ++current_panel;
254 }
255 else if (dynamic_cast<const SeparatorDeclaration *>(item_decl.get()) ||
256 dynamic_cast<const LayoutDeclaration *>(item_decl.get()))
257 {
258 /* Ignored because they don't have corresponding data in DNA. */
259 }
260 else {
261 /* Unknown item type. */
263 }
264 }
265 /* If items are left over, some were removed from the declaration. */
266 if (current_input != nullptr || current_output != nullptr ||
267 node.panel_states().contains_ptr(current_panel))
268 {
269 return false;
270 }
271 return true;
272}
273
275 bNode &node,
276 bNodeSocket &socket) const
277{
278 /* By default just rebuild. */
279 BLI_assert(socket.in_out == this->in_out);
280 UNUSED_VARS_NDEBUG(socket);
281 return this->build(ntree, node);
282}
283
290
292{
293 if (socket.name != this->name) {
294 return false;
295 }
296 if (socket.identifier != this->identifier) {
297 return false;
298 }
299 if (((socket.flag & SOCK_HIDE_VALUE) != 0) != this->hide_value) {
300 return false;
301 }
302 if (((socket.flag & SOCK_MULTI_INPUT) != 0) != this->is_multi_input) {
303 return false;
304 }
305 if (((socket.flag & SOCK_UNAVAIL) != 0) != !this->is_available) {
306 return false;
307 }
308 return true;
309}
310
311template<typename Fn>
312static bool socket_type_to_static_decl_type(const eNodeSocketDatatype socket_type, Fn &&fn)
313{
314 switch (socket_type) {
315 case SOCK_FLOAT:
317 return true;
318 case SOCK_VECTOR:
320 return true;
321 case SOCK_RGBA:
323 return true;
324 case SOCK_SHADER:
326 return true;
327 case SOCK_BOOLEAN:
329 return true;
330 case SOCK_ROTATION:
332 return true;
333 case SOCK_MATRIX:
335 return true;
336 case SOCK_INT:
338 return true;
339 case SOCK_STRING:
341 return true;
342 case SOCK_GEOMETRY:
344 return true;
345 case SOCK_OBJECT:
347 return true;
348 case SOCK_IMAGE:
350 return true;
351 case SOCK_COLLECTION:
353 return true;
354 case SOCK_MATERIAL:
356 return true;
357 case SOCK_MENU:
359 return true;
360 case SOCK_BUNDLE:
362 return true;
363 case SOCK_CLOSURE:
365 return true;
366 default:
367 return false;
368 }
369}
370
371std::unique_ptr<SocketDeclaration> make_declaration_for_socket_type(
372 const eNodeSocketDatatype socket_type)
373{
374 std::unique_ptr<SocketDeclaration> decl;
375 socket_type_to_static_decl_type(socket_type, [&](auto type_tag) {
376 using DeclT = typename decltype(type_tag)::type;
377 decl = std::make_unique<DeclT>();
378 });
379 return decl;
380}
381
383 const eNodeSocketDatatype socket_type, const StringRef name, const StringRef identifier)
384{
386 socket_type_to_static_decl_type(socket_type, [&](auto type_tag) {
387 using DeclT = typename decltype(type_tag)::type;
388 decl = &this->add_input<DeclT>(name, identifier);
389 });
390 if (!decl) {
392 decl = &this->add_input<decl::Float>("", "");
393 }
394 return *decl;
395}
396
398 const StringRef name,
399 const StringRef identifier)
400{
401 return this->add_input(*bke::custom_data_type_to_socket_type(data_type), name, identifier);
402}
403
405 const eNodeSocketDatatype socket_type, const StringRef name, const StringRef identifier)
406{
408 socket_type_to_static_decl_type(socket_type, [&](auto type_tag) {
409 using DeclT = typename decltype(type_tag)::type;
410 decl = &this->add_output<DeclT>(name, identifier);
411 });
412 if (!decl) {
414 decl = &this->add_output<decl::Float>("", "");
415 }
416 return *decl;
417}
418
420 const StringRef name,
421 const StringRef identifier)
422{
423 return this->add_output(*bke::custom_data_type_to_socket_type(data_type), name, identifier);
424}
425
427{
428 auto decl_ptr = std::make_unique<SeparatorDeclaration>();
429 SeparatorDeclaration &decl = *decl_ptr;
430 this->node_decl_builder.declaration_.all_items.append(std::move(decl_ptr));
431 this->items.append(&decl);
432}
433
435{
436 BLI_assert(this->node_decl_builder.typeinfo_.draw_buttons);
437 this->add_layout([](uiLayout *layout, bContext *C, PointerRNA *ptr) {
438 const bNode &node = *static_cast<bNode *>(ptr->data);
439 node.typeinfo->draw_buttons(layout, C, ptr);
440 });
441 static_cast<LayoutDeclaration &>(*this->items.last()).is_default = true;
442}
443
445 std::function<void(uiLayout *, bContext *, PointerRNA *)> draw)
446{
447 auto decl_ptr = std::make_unique<LayoutDeclaration>();
448 LayoutDeclaration &decl = *decl_ptr;
449 decl.draw = std::move(draw);
450 this->node_decl_builder.declaration_.all_items.append(std::move(decl_ptr));
451 this->items.append(&decl);
452}
453
455{
456 auto panel_decl_ptr = std::make_unique<PanelDeclaration>();
457 PanelDeclaration &panel_decl = *panel_decl_ptr;
458 auto panel_decl_builder_ptr = std::make_unique<PanelDeclarationBuilder>(this->node_decl_builder,
459 panel_decl);
460 PanelDeclarationBuilder &panel_decl_builder = *panel_decl_builder_ptr;
461
462 if (identifier >= 0) {
463 panel_decl.identifier = identifier;
464 }
465 else {
466 /* Use index as identifier. */
467 panel_decl.identifier = this->node_decl_builder.declaration_.all_items.size();
468 }
469 panel_decl.name = name;
470 panel_decl.parent_panel = this->parent_panel_decl;
471 panel_decl.index = this->node_decl_builder.declaration_.panels.append_and_get_index(&panel_decl);
472 this->node_decl_builder.declaration_.all_items.append(std::move(panel_decl_ptr));
473 this->node_decl_builder.panel_builders_.append_and_get_index(std::move(panel_decl_builder_ptr));
474 this->items.append(&panel_decl);
475 return panel_decl_builder;
476}
477
479{
480 panel = {0};
481 panel.identifier = this->identifier;
482 SET_FLAG_FROM_TEST(panel.flag, this->default_collapsed, NODE_PANEL_COLLAPSED);
483}
484
486{
487 return panel.identifier == this->identifier;
488}
489
491 bNodePanelState &new_panel) const
492{
493 build(new_panel);
494 /* Copy existing state to the new panel */
495 SET_FLAG_FROM_TEST(new_panel.flag, old_panel.is_collapsed(), NODE_PANEL_COLLAPSED);
496}
497
499{
500 int count = 0;
501 for (const PanelDeclaration *parent = this->parent_panel; parent; parent = parent->parent_panel)
502 {
503 count++;
504 }
505 return count;
506}
507
509{
510 if (this->items.is_empty()) {
511 return nullptr;
512 }
513 const nodes::ItemDeclaration *item_decl = this->items.first();
514 if (const auto *socket_decl = dynamic_cast<const nodes::SocketDeclaration *>(item_decl)) {
515 if (socket_decl->is_panel_toggle && (socket_decl->in_out & SOCK_IN) &&
516 (socket_decl->socket_type & SOCK_BOOLEAN))
517 {
518 return socket_decl;
519 }
520 }
521 return nullptr;
522}
523
525{
526 BLI_assert(this->is_input());
528 this->structure_type(StructureType::Field);
529 return *this;
530}
531
533 Vector<int> input_dependencies)
534{
535 BLI_assert(this->is_output());
536 this->reference_pass(input_dependencies);
538 std::move(input_dependencies));
539 this->structure_type(StructureType::Dynamic);
540 return *this;
541}
542
544{
545 decl_base_->optional_label = value;
546 return *this;
547}
548
550{
551 decl_base_->hide_value = value;
552 return *this;
553}
554
556{
557 BLI_assert(this->is_input());
558 decl_base_->is_multi_input = value;
559 return *this;
560}
561
563{
564 decl_base_->compact = value;
565 return *this;
566}
567
569 const Span<int> input_indices)
570{
571 BLI_assert(this->is_output());
572 aal::RelationsInNode &relations = node_decl_builder_->get_anonymous_attribute_relations();
573 for (const int from_input : input_indices) {
574 aal::ReferenceRelation relation;
575 relation.from_field_input = from_input;
576 relation.to_field_output = decl_base_->index;
577 relations.reference_relations.append(relation);
578 }
579 return *this;
580}
581
583{
584 aal::RelationsInNode &relations = node_decl_builder_->get_anonymous_attribute_relations();
585 if (this->is_input()) {
586 this->supports_field();
587 for (const int input_index : indices) {
588 aal::EvalRelation relation;
589 relation.field_input = decl_base_->index;
590 relation.geometry_input = input_index;
591 relations.eval_relations.append(relation);
592 }
593 }
594 else {
595 this->field_source();
596 for (const int output_index : indices) {
597 aal::AvailableRelation relation;
598 relation.field_output = decl_base_->index;
599 relation.geometry_output = output_index;
600 relations.available_relations.append(relation);
601 }
602 }
603 this->structure_type(StructureType::Field);
604 return *this;
605}
606
608{
609 decl_base_->short_label = std::move(value);
610 return *this;
611}
612
614{
615 decl_base_->description = std::move(value);
616 return *this;
617}
618
620 std::optional<std::string> value)
621{
622 decl_base_->translation_context = std::move(value);
623 return *this;
624}
625
627{
628 decl_base_->no_mute_links = value;
629 return *this;
630}
631
633{
634 decl_base_->is_available = value;
635 return *this;
636}
637
639{
640 decl_base_->is_attribute_name = value;
641 return *this;
642}
643
645{
646 decl_base_->is_default_link_socket = value;
647 return *this;
648}
649
651 const NodeDefaultInputType value)
652{
653 decl_base_->default_input_type = value;
654 return *this;
655}
656
658{
659 if (this->is_input()) {
660 this->supports_field();
661 }
662 if (this->is_output()) {
663 this->field_source();
664 }
665 field_on_all_ = true;
666 this->structure_type(StructureType::Field);
667 return *this;
668}
669
671{
672 BLI_assert(this->is_output());
673 decl_base_->output_field_dependency = OutputFieldDependency::ForFieldSource();
674 this->structure_type(StructureType::Field);
675 return *this;
676}
677
680{
681 BLI_assert(this->is_input());
682 this->hide_value();
683 this->structure_type(StructureType::Dynamic);
684 decl_base_->input_field_type = InputSocketFieldType::Implicit;
685 decl_base_->default_input_type = default_input_type;
686 return *this;
687}
688
691{
692 this->implicit_field(default_input_type);
693 field_on_all_ = true;
694 this->structure_type(StructureType::Field);
695 return *this;
696}
697
699 const NodeDefaultInputType default_input_type, const Span<int> input_indices)
700{
701 this->field_on(input_indices);
702 this->implicit_field(default_input_type);
703 this->structure_type(StructureType::Field);
704 return *this;
705}
706
708{
709 BLI_assert(this->is_output());
710 decl_base_->output_field_dependency = OutputFieldDependency::ForDependentField();
711 this->structure_type(StructureType::Dynamic);
712 this->reference_pass_all();
713 return *this;
714}
715
722
728
734
736{
737 /* We can't distinguish between actually propagating everything or just instance attributes
738 * currently. It's still nice to be more explicit at the node declaration level. */
739 this->propagate_all();
740 return *this;
741}
742
745{
746 decl_base_->compositor_realization_mode_ = value;
747 return *this;
748}
749
751 int priority)
752{
753 BLI_assert(priority >= 0);
754 decl_base_->compositor_domain_priority_ = priority;
755 return *this;
756}
757
759 std::function<void(bNode &)> fn)
760{
761 decl_base_->make_available_fn_ = std::move(fn);
762 return *this;
763}
764
766{
767 decl_base_->custom_draw_fn = std::make_unique<CustomSocketDrawFn>(std::move(fn));
768 return *this;
769}
770
773{
774 decl_base_->usage_inference_fn = std::make_unique<InputSocketUsageInferenceFn>(std::move(fn));
775 return *this;
776}
777
778static const bNodeSocket &find_single_menu_input(const bNode &node)
779{
780#ifndef NDEBUG
781 int menu_input_count = 0;
782 /* Topology cache may not be available here and this function may be called while doing tree
783 * modifications. */
784 LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
785 if (socket->type == SOCK_MENU) {
786 menu_input_count++;
787 }
788 }
789 BLI_assert(menu_input_count == 1);
790#endif
791
792 LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
793 if (!socket->is_available()) {
794 continue;
795 }
796 if (socket->type != SOCK_MENU) {
797 continue;
798 }
799 return *socket;
800 }
802 return node.input_socket(0);
803}
804
806 const int menu_value)
807{
808 this->make_available([menu_value](bNode &node) {
809 bNodeSocket &socket = const_cast<bNodeSocket &>(find_single_menu_input(node));
810 bNodeSocketValueMenu *value = socket.default_value_typed<bNodeSocketValueMenu>();
811 value->value = menu_value;
812 });
814 -> std::optional<bool> {
815 const bNodeSocket &socket = find_single_menu_input(params.node);
816 if (const std::optional<bool> any_output_used = params.any_output_is_used()) {
817 if (!*any_output_used) {
818 /* If no output is used, none of the inputs is used either. */
819 return false;
820 }
821 }
822 else {
823 /* It's not known if any output is used yet. This function will be called again once new
824 * information about output usages is available. */
825 return std::nullopt;
826 }
827 return params.menu_input_may_be(socket.identifier, menu_value);
828 });
829 return *this;
830}
831
833 const StringRef menu_input_identifier, const int menu_value)
834{
835 Array<int> menu_values = {menu_value};
836 this->usage_by_menu(menu_input_identifier, menu_values);
837 return *this;
838}
839
841 const StringRef menu_input_identifier, const Array<int> menu_values)
842{
843 this->make_available([menu_input_identifier, menu_values](bNode &node) {
845 node, SOCK_IN, menu_input_identifier);
846 const SocketDeclaration &socket_declaration = *menu_socket.runtime->declaration;
847 socket_declaration.make_available(node);
848 bNodeSocketValueMenu *value = menu_socket.default_value_typed<bNodeSocketValueMenu>();
849 value->value = menu_values[0];
850 });
851 this->usage_inference(
852 [menu_input_identifier, menu_values](
853 const socket_usage_inference::InputSocketUsageParams &params) -> std::optional<bool> {
854 if (const std::optional<bool> any_output_used = params.any_output_is_used()) {
855 if (!*any_output_used) {
856 /* If no output is used, none of the inputs is used either. */
857 return false;
858 }
859 }
860 else {
861 /* It's not known if any output is used yet. This function will be called again once new
862 * information about output usages is available. */
863 return std::nullopt;
864 }
865
866 /* Check if the menu might be any of the given values. */
867 bool menu_might_be_any_value = false;
868 for (const int menu_value : menu_values) {
869 menu_might_be_any_value = params.menu_input_may_be(menu_input_identifier, menu_value);
870 if (menu_might_be_any_value) {
871 break;
872 }
873 }
874
875 const bNodeSocket &menu_socket = *blender::bke::node_find_socket(
876 params.node, SOCK_IN, menu_input_identifier);
877 const SocketDeclaration &menu_socket_declaration = *menu_socket.runtime->declaration;
878 if (!menu_socket_declaration.usage_inference_fn) {
879 return menu_might_be_any_value;
880 }
881
882 /* If the menu socket has a usage inference function, check if it might be used. */
883 const std::optional<bool> menu_might_be_used =
884 (*menu_socket_declaration.usage_inference_fn)(params);
885 if (!menu_might_be_used.has_value()) {
886 return menu_might_be_any_value;
887 }
888
889 /* The input is only used if the menu might be any of the values and the menu itself is
890 * used. */
891 return *menu_might_be_used && menu_might_be_any_value;
892 });
893 return *this;
894}
895
897{
898 decl_base_->align_with_previous_socket = value;
899 return *this;
900}
901
910
911BaseSocketDeclarationBuilder &BaseSocketDeclarationBuilder ::socket_name_ptr(
912 const PointerRNA ptr, const StringRef property_name)
913{
914 decl_base_->socket_name_rna = std::make_unique<SocketNameRNA>();
915 decl_base_->socket_name_rna->owner = ptr;
916 decl_base_->socket_name_rna->property_name = property_name;
917 return *this;
918}
919
921 const ID *id, const StructRNA *srna, const void *data, StringRef property_name)
922{
923 /* Doing const-casts here because this data is generally only available as const when creating
924 * the declaration, but it's still valid to modify later. */
925 return this->socket_name_ptr(RNA_pointer_create_discrete(const_cast<ID *>(id),
926 const_cast<StructRNA *>(srna),
927 const_cast<void *>(data)),
928 property_name);
929}
930
932{
933 decl_base_->is_panel_toggle = value;
934 return *this;
935}
936
938{
939 decl_base_->is_layer_name = value;
940 return *this;
941}
942
944{
945 decl_base_->is_volume_grid_name = value;
946 return *this;
947}
948
950{
951 OutputFieldDependency field_dependency;
952 field_dependency.type_ = OutputSocketFieldType::FieldSource;
953 return field_dependency;
954}
955
957{
958 OutputFieldDependency field_dependency;
959 field_dependency.type_ = OutputSocketFieldType::None;
960 return field_dependency;
961}
962
964{
965 OutputFieldDependency field_dependency;
966 field_dependency.type_ = OutputSocketFieldType::DependentField;
967 return field_dependency;
968}
969
971{
972 OutputFieldDependency field_dependency;
973 if (indices.is_empty()) {
974 field_dependency.type_ = OutputSocketFieldType::None;
975 }
976 else {
977 field_dependency.type_ = OutputSocketFieldType::PartiallyDependent;
978 field_dependency.linked_input_indices_ = std::move(indices);
979 }
980 return field_dependency;
981}
982
987
989{
990 return linked_input_indices_;
991}
992
994{
995 return compositor_realization_mode_;
996}
997
999{
1000 return compositor_domain_priority_;
1001}
1002
1004{
1005 if (make_available_fn_) {
1006 make_available_fn_(node);
1007 }
1008}
1009
1011{
1012 decl_->description = std::move(value);
1013 return *this;
1014}
1015
1017 std::optional<std::string> value)
1018{
1019 decl_->translation_context = value;
1020 return *this;
1021}
1022
1024{
1025 decl_->default_collapsed = closed;
1026 return *this;
1027}
1028
1030
1031static void position(const bNode & /*node*/, void *r_value)
1032{
1035}
1036
1037static void normal(const bNode & /*node*/, void *r_value)
1038{
1040 r_value, fn::Field<float3>(std::make_shared<bke::NormalFieldInput>()));
1041}
1042
1043static void index(const bNode & /*node*/, void *r_value)
1044{
1046 fn::Field<int>(std::make_shared<fn::IndexFieldInput>()));
1047}
1048
1049static void id_or_index(const bNode & /*node*/, void *r_value)
1050{
1052 r_value, fn::Field<int>(std::make_shared<bke::IDAttributeFieldInput>()));
1053}
1054
1055static void instance_transform(const bNode & /*node*/, void *r_value)
1056{
1058 r_value, bke::AttributeFieldInput::from<float4x4>("instance_transform"));
1059}
1060
1061static void handle_left(const bNode & /*node*/, void *r_value)
1062{
1065}
1066
1067static void handle_right(const bNode & /*node*/, void *r_value)
1068{
1071}
1072
1073} // namespace implicit_field_inputs
1074
1075std::optional<ImplicitInputValueFn> get_implicit_input_value_fn(const NodeDefaultInputType type)
1076{
1077 switch (type) {
1079 return std::nullopt;
1081 return std::make_optional(implicit_field_inputs::index);
1083 return std::make_optional(implicit_field_inputs::id_or_index);
1085 return std::make_optional(implicit_field_inputs::normal);
1087 return std::make_optional(implicit_field_inputs::position);
1089 return std::make_optional(implicit_field_inputs::instance_transform);
1091 return std::make_optional(implicit_field_inputs::handle_left);
1093 return std::make_optional(implicit_field_inputs::handle_right);
1094 }
1095 return std::nullopt;
1096}
1097
1099 const NodeDefaultInputType input_type)
1100{
1101 const eNodeSocketDatatype stype = socket_type.type;
1102 switch (input_type) {
1104 return true;
1107 return stype == SOCK_INT;
1112 return stype == SOCK_VECTOR;
1114 return stype == SOCK_MATRIX;
1115 }
1116 return false;
1117}
1118
1120 const std::optional<StringRefNull> label_override)
1121{
1122 this->socket.typeinfo->draw(const_cast<bContext *>(&this->C),
1123 &layout,
1124 &this->socket_ptr,
1125 &this->node_ptr,
1126 label_override.has_value() ? *label_override : this->label);
1127}
1128
1129} // namespace blender::nodes
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
#define UNUSED_VARS(...)
#define UNUSED_VARS_NDEBUG(...)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define ELEM(...)
@ NODE_DEFAULT_INPUT_POSITION_FIELD
@ NODE_DEFAULT_INPUT_HANDLE_RIGHT_FIELD
@ NODE_DEFAULT_INPUT_HANDLE_LEFT_FIELD
@ NODE_DEFAULT_INPUT_ID_INDEX_FIELD
@ NODE_DEFAULT_INPUT_INSTANCE_TRANSFORM_FIELD
@ NODE_DEFAULT_INPUT_NORMAL_FIELD
@ NODE_INTERFACE_SOCKET_STRUCTURE_TYPE_AUTO
eNodeSocketInOut
@ SOCK_OUT
@ SOCK_IN
@ SOCK_HIDE_VALUE
@ SOCK_MULTI_INPUT
@ SOCK_UNAVAIL
eNodeSocketDatatype
@ SOCK_INT
@ SOCK_VECTOR
@ SOCK_CLOSURE
@ SOCK_BOOLEAN
@ SOCK_MATERIAL
@ SOCK_SHADER
@ SOCK_MATRIX
@ SOCK_FLOAT
@ SOCK_IMAGE
@ SOCK_COLLECTION
@ SOCK_BUNDLE
@ SOCK_GEOMETRY
@ SOCK_ROTATION
@ SOCK_OBJECT
@ SOCK_STRING
@ SOCK_RGBA
@ SOCK_MENU
@ NODE_PANEL_COLLAPSED
#define C
Definition RandGen.cpp:29
BMesh const char void * data
eNodeSocketDatatype socket_type
InputSocketFieldType input_field_type
void append(const T &value)
int64_t size() const
void append(const T &value)
static fn::GField from(std::string name, const CPPType &type, std::optional< std::string > socket_inspection_name=std::nullopt)
static SocketValueVariant & ConstructIn(void *ptr, T &&value)
BaseSocketDeclarationBuilder & is_layer_name(bool value=true)
BaseSocketDeclarationBuilder & dependent_field()
BaseSocketDeclarationBuilder & align_with_previous(bool value=true)
BaseSocketDeclarationBuilder & make_available(std::function< void(bNode &)> fn)
BaseSocketDeclarationBuilder & field_source()
BaseSocketDeclarationBuilder & optional_label(bool value=true)
BaseSocketDeclarationBuilder & usage_by_menu(const StringRef menu_input_identifier, const int menu_value)
BaseSocketDeclarationBuilder & usage_by_single_menu(const int menu_value)
BaseSocketDeclarationBuilder & compositor_realization_mode(CompositorInputRealizationMode value)
BaseSocketDeclarationBuilder & propagate_all()
BaseSocketDeclarationBuilder & available(bool value=true)
BaseSocketDeclarationBuilder & implicit_field(NodeDefaultInputType default_input)
BaseSocketDeclarationBuilder & usage_inference(InputSocketUsageInferenceFn fn)
BaseSocketDeclarationBuilder & field_on_all()
BaseSocketDeclarationBuilder & is_attribute_name(bool value=true)
BaseSocketDeclarationBuilder & reference_pass(Span< int > input_indices)
BaseSocketDeclarationBuilder & compact(bool value=true)
BaseSocketDeclarationBuilder & structure_type(StructureType structure_type)
BaseSocketDeclarationBuilder & description(std::string value="")
BaseSocketDeclarationBuilder & socket_name_ptr(PointerRNA ptr, StringRef property_name)
BaseSocketDeclarationBuilder & short_label(std::string value="")
BaseSocketDeclarationBuilder & supports_field()
BaseSocketDeclarationBuilder & implicit_field_on_all(NodeDefaultInputType default_input)
BaseSocketDeclarationBuilder & translation_context(std::optional< std::string > value=std::nullopt)
BaseSocketDeclarationBuilder & multi_input(bool value=true)
BaseSocketDeclarationBuilder & custom_draw(CustomSocketDrawFn fn)
BaseSocketDeclarationBuilder & panel_toggle(bool value=true)
BaseSocketDeclarationBuilder & is_default_link_socket(bool value=true)
BaseSocketDeclarationBuilder & compositor_domain_priority(int priority)
BaseSocketDeclarationBuilder & is_volume_grid_name(bool value=true)
BaseSocketDeclarationBuilder & field_source_reference_all()
BaseSocketDeclarationBuilder & field_on(Span< int > indices)
BaseSocketDeclarationBuilder & hide_value(bool value=true)
BaseSocketDeclarationBuilder & propagate_all_instance_attributes()
BaseSocketDeclarationBuilder & implicit_field_on(NodeDefaultInputType default_input, Span< int > input_indices)
BaseSocketDeclarationBuilder & no_muted_links(bool value=true)
BaseSocketDeclarationBuilder & reference_pass_all()
BaseSocketDeclarationBuilder & default_input_type(NodeDefaultInputType value)
DeclType::Builder & add_output(StringRef name, StringRef identifier="")
void add_layout(std::function< void(uiLayout *, bContext *, PointerRNA *)> draw)
PanelDeclarationBuilder & add_panel(StringRef name, int identifier=-1)
DeclType::Builder & add_input(StringRef name, StringRef identifier="")
NodeDeclarationBuilder(const bke::bNodeType &typeinfo, NodeDeclaration &declaration, const bNodeTree *ntree=nullptr, const bNode *node=nullptr)
aal::RelationsInNode & get_anonymous_attribute_relations()
Vector< ItemDeclaration * > root_items
Vector< SocketDeclaration * > inputs
bool matches(const bNode &node) const
Vector< SocketDeclaration * > outputs
Vector< ItemDeclarationPtr > all_items
Span< SocketDeclaration * > sockets(eNodeSocketInOut in_out) const
static OutputFieldDependency ForPartiallyDependentField(Vector< int > indices)
static OutputFieldDependency ForDataSource()
static OutputFieldDependency ForDependentField()
static OutputFieldDependency ForFieldSource()
OutputSocketFieldType field_type() const
Self & description(std::string value="")
Self & translation_context(std::optional< std::string > value=std::nullopt)
PanelDeclarationBuilder(NodeDeclarationBuilder &node_builder, PanelDeclaration &decl)
Vector< ItemDeclaration * > items
void update_or_build(const bNodePanelState &old_panel, bNodePanelState &new_panel) const
bool matches(const bNodePanelState &panel) const
const SocketDeclaration * panel_input_decl() const
void build(bNodePanelState &panel) const
bool matches_common_data(const bNodeSocket &socket) const
std::unique_ptr< InputSocketUsageInferenceFn > usage_inference_fn
const CompositorInputRealizationMode & compositor_realization_mode() const
void make_available(bNode &node) const
virtual bNodeSocket & update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
void set_common_flags(bNodeSocket &socket) const
virtual bNodeSocket & build(bNodeTree &ntree, bNode &node) const =0
static ushort indices[]
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
int count
bNodeSocket * node_find_socket(bNode &node, eNodeSocketInOut in_out, StringRef identifier)
Definition node.cc:2532
std::optional< eNodeSocketDatatype > custom_data_type_to_socket_type(eCustomDataType type)
Definition node.cc:5168
std::ostream & operator<<(std::ostream &stream, const RelationsInNode &relations)
static void position(const bNode &, void *r_value)
static void id_or_index(const bNode &, void *r_value)
static void handle_left(const bNode &, void *r_value)
static void index(const bNode &, void *r_value)
static void instance_transform(const bNode &, void *r_value)
static void handle_right(const bNode &, void *r_value)
static void normal(const bNode &, void *r_value)
std::function< std::optional< bool >( const socket_usage_inference::InputSocketUsageParams &params)> InputSocketUsageInferenceFn
std::optional< ImplicitInputValueFn > get_implicit_input_value_fn(const NodeDefaultInputType type)
static void assert_valid_panels_recursive(const NodeDeclaration &node_decl, const Span< const ItemDeclaration * > items, Vector< const SocketDeclaration * > &r_flat_inputs, Vector< const SocketDeclaration * > &r_flat_outputs)
static const bNodeSocket & find_single_menu_input(const bNode &node)
void build_node_declaration(const bke::bNodeType &typeinfo, NodeDeclaration &r_declaration, const bNodeTree *ntree, const bNode *node)
static bool socket_type_to_static_decl_type(const eNodeSocketDatatype socket_type, Fn &&fn)
std::unique_ptr< ItemDeclaration > ItemDeclarationPtr
bool socket_type_supports_default_input_type(const bke::bNodeSocketType &socket_type, const NodeDefaultInputType input_type)
std::function< void(CustomSocketDrawParams &params)> CustomSocketDrawFn
static void reset_declaration(NodeDeclaration &declaration)
std::unique_ptr< SocketDeclaration > make_declaration_for_socket_type(const eNodeSocketDatatype socket_type)
const char * name
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
Definition DNA_ID.h:414
void * first
bNodeSocketRuntimeHandle * runtime
struct bNodeSocket * next
char identifier[64]
bNodeTypeHandle * typeinfo
ListBase inputs
bNodePanelState * panel_states_array
ListBase outputs
Defines a socket type.
Definition BKE_node.hh:158
eNodeSocketDatatype type
Definition BKE_node.hh:193
Defines a node type.
Definition BKE_node.hh:238
NodeDeclareFunction declare
Definition BKE_node.hh:362
void draw_standard(uiLayout &layout, std::optional< StringRefNull > label_override=std::nullopt)
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4238