Blender V5.0
node_common.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2007 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cstddef>
10#include <cstring>
11
12#include "DNA_asset_types.h"
13#include "DNA_node_types.h"
14
15#include "BLI_array.hh"
16#include "BLI_disjoint_set.hh"
17#include "BLI_listbase.h"
18#include "BLI_map.hh"
20#include "BLI_set.hh"
21#include "BLI_stack.hh"
22#include "BLI_string.h"
23#include "BLI_string_ref.hh"
24#include "BLI_vector_set.hh"
25
26#include "BLT_translation.hh"
27
28#include "BKE_node.hh"
29#include "BKE_node_runtime.hh"
31
32#include "MEM_guardedalloc.h"
33
34#include "NOD_common.hh"
35#include "NOD_composite.hh"
38#include "NOD_register.hh"
39#include "NOD_socket.hh"
42
43#include "UI_resources.hh"
44
45#include "ED_node.hh"
46
47#include "node_common.h"
48#include "node_util.hh"
49
50using blender::Map;
52using blender::Set;
53using blender::Stack;
55using blender::Vector;
56
58
59/* -------------------------------------------------------------------- */
62
64{
65 LISTBASE_FOREACH (bNodeSocket *, socket, &sockets) {
66 if (socket->identifier == identifier) {
67 return socket;
68 }
69 }
70 return nullptr;
71}
72
74{
75 return find_matching_socket(groupnode->inputs, identifier);
76}
77
79{
80 return find_matching_socket(groupnode->outputs, identifier);
81}
82
83void node_group_label(const bNodeTree * /*ntree*/,
84 const bNode *node,
85 char *label,
86 int label_maxncpy)
87{
88 BLI_strncpy(label,
89 (node->id) ? node->id->name + 2 :
90 CTX_IFACE_(BLT_I18NCONTEXT_ID_NODETREE, "Missing Data-Block"),
91 label_maxncpy);
92}
93
94int node_group_ui_class(const bNode *node)
95{
96 const bNodeTree *group = reinterpret_cast<const bNodeTree *>(node->id);
97 if (!group) {
98 return NODE_CLASS_GROUP;
99 }
100 switch (blender::bke::NodeColorTag(group->color_tag)) {
102 return NODE_CLASS_GROUP;
106 return NODE_CLASS_OP_COLOR;
110 return NODE_CLASS_DISTORT;
114 return NODE_CLASS_GEOMETRY;
116 return NODE_CLASS_INPUT;
118 return NODE_CLASS_MATTE;
120 return NODE_CLASS_OUTPUT;
122 return NODE_CLASS_SCRIPT;
124 return NODE_CLASS_SHADER;
126 return NODE_CLASS_TEXTURE;
130 return NODE_CLASS_PATTERN;
134 return NODE_CLASS_GROUP;
135 }
136 return NODE_CLASS_GROUP;
137}
138
140 const bNodeTree *nodetree,
141 const char **r_disabled_hint)
142{
143 if (!node->typeinfo->poll(node->typeinfo, nodetree, r_disabled_hint)) {
144 return false;
145 }
146 const bNodeTree *grouptree = reinterpret_cast<const bNodeTree *>(node->id);
147 if (!grouptree) {
148 return true;
149 }
150 return blender::bke::node_group_poll(nodetree, grouptree, r_disabled_hint);
151}
152
153std::string node_group_ui_description(const bNode &node)
154{
155 if (!node.id) {
156 return "";
157 }
158 const bNodeTree *group = reinterpret_cast<const bNodeTree *>(node.id);
159 if (group->id.asset_data) {
160 if (group->id.asset_data->description) {
161 return group->id.asset_data->description;
162 }
163 }
164 if (!group->description) {
165 return "";
166 }
167 return group->description;
168}
169
171 const bNodeTree *grouptree,
172 const char **r_disabled_hint)
173{
174 /* unspecified node group, generally allowed
175 * (if anything, should be avoided on operator level)
176 */
177 if (grouptree == nullptr) {
178 return true;
179 }
180
181 if (nodetree == grouptree) {
182 if (r_disabled_hint) {
183 *r_disabled_hint = RPT_("Nesting a node group inside of itself is not allowed");
184 }
185 return false;
186 }
187 if (nodetree->type != grouptree->type) {
188 if (r_disabled_hint) {
189 *r_disabled_hint = RPT_("Node group has different type");
190 }
191 return false;
192 }
193
194 for (const bNode *node : grouptree->all_nodes()) {
195 if (node->typeinfo->poll_instance &&
196 !node->typeinfo->poll_instance(node, nodetree, r_disabled_hint))
197 {
198 return false;
199 }
200 }
201 return true;
202}
203
204namespace blender::nodes {
205
206static std::function<ID *(const bNode &node)> get_default_id_getter(
207 const bNodeTreeInterface &tree_interface, const bNodeTreeInterfaceSocket &io_socket)
208{
209 const int item_index = tree_interface.find_item_index(io_socket.item);
210 BLI_assert(item_index >= 0);
211
212 /* Avoid capturing pointers that can become dangling. */
213 return [item_index](const bNode &node) -> ID * {
214 if (node.id == nullptr) {
215 return nullptr;
216 }
217 if (GS(node.id->name) != ID_NT) {
218 return nullptr;
219 }
220 const bNodeTree &ntree = *reinterpret_cast<const bNodeTree *>(node.id);
221 const bNodeTreeInterfaceItem *io_item = ntree.tree_interface.get_item_at_index(item_index);
222 const bNodeTreeInterfaceSocket *io_socket =
224 if (!io_socket) {
225 return nullptr;
226 }
227 return *static_cast<ID **>(io_socket->socket_data);
228 };
229}
230
231static std::function<void(bNode &node, bNodeSocket &socket, const char *data_path)>
233{
234 const int item_index = interface.find_item_index(io_socket.item);
235 BLI_assert(item_index >= 0);
236
237 /* Avoid capturing pointers that can become dangling. */
238 return [item_index](bNode &node, bNodeSocket &socket, const char *data_path) {
239 if (node.id == nullptr) {
240 return;
241 }
242 if (GS(node.id->name) != ID_NT) {
243 return;
244 }
245 bNodeTree &ntree = *reinterpret_cast<bNodeTree *>(node.id);
246 const bNodeTreeInterfaceItem *io_item = ntree.tree_interface.get_item_at_index(item_index);
247 if (io_item == nullptr || io_item->item_type != NODE_INTERFACE_SOCKET) {
248 return;
249 }
250 const bNodeTreeInterfaceSocket &io_socket =
252 blender::bke::bNodeSocketType *typeinfo = io_socket.socket_typeinfo();
253 if (typeinfo && typeinfo->interface_init_socket) {
254 typeinfo->interface_init_socket(&ntree.id, &io_socket, &node, &socket, data_path);
255 }
256 };
257}
258
260 const bNodeTree &tree,
261 const bNodeTreeInterfaceSocket &io_socket,
262 const std::optional<StructureType> structure_type,
263 const eNodeSocketInOut in_out,
265{
267 io_socket.socket_type);
269
270 const StringRef name = io_socket.name;
271 const StringRef identifier = io_socket.identifier;
272
274 if (base_typeinfo) {
275 datatype = base_typeinfo->type;
276 switch (datatype) {
277 case SOCK_FLOAT: {
279 decl = &b.add_socket<decl::Float>(name, identifier, in_out)
280 .subtype(PropertySubType(value.subtype))
281 .default_value(value.value)
282 .min(value.min)
283 .max(value.max);
284 break;
285 }
286 case SOCK_VECTOR: {
288 decl = &b.add_socket<decl::Vector>(name, identifier, in_out)
289 .subtype(PropertySubType(value.subtype))
290 .default_value(float4(value.value))
291 .dimensions(value.dimensions)
292 .min(value.min)
293 .max(value.max);
294 break;
295 }
296 case SOCK_RGBA: {
298 decl = &b.add_socket<decl::Color>(name, identifier, in_out).default_value(value.value);
299 break;
300 }
301 case SOCK_SHADER: {
302 decl = &b.add_socket<decl::Shader>(name, identifier, in_out);
303 break;
304 }
305 case SOCK_BOOLEAN: {
307 decl = &b.add_socket<decl::Bool>(name, identifier, in_out).default_value(value.value);
308 break;
309 }
310 case SOCK_ROTATION: {
312 io_socket);
313 decl = &b.add_socket<decl::Rotation>(name, identifier, in_out)
314 .default_value(math::EulerXYZ(float3(value.value_euler)));
315 break;
316 }
317 case SOCK_MATRIX: {
318 decl = &b.add_socket<decl::Matrix>(name, identifier, in_out);
319 break;
320 }
321 case SOCK_INT: {
322 const auto &value = node_interface::get_socket_data_as<bNodeSocketValueInt>(io_socket);
323 decl = &b.add_socket<decl::Int>(name, identifier, in_out)
324 .subtype(PropertySubType(value.subtype))
325 .default_value(value.value)
326 .min(value.min)
327 .max(value.max);
328 break;
329 }
330 case SOCK_STRING: {
332 decl = &b.add_socket<decl::String>(name, identifier, in_out)
333 .subtype(PropertySubType(value.subtype))
334 .default_value(value.value);
335 break;
336 }
337 case SOCK_MENU: {
339 decl = &b.add_socket<decl::Menu>(name, identifier, in_out)
340 .default_value(MenuValue(value.value))
341 .expanded(io_socket.flag & NODE_INTERFACE_SOCKET_MENU_EXPANDED)
343 break;
344 }
345 case SOCK_OBJECT: {
346 decl = &b.add_socket<decl::Object>(name, identifier, in_out)
347 .default_value_fn(get_default_id_getter(tree.tree_interface, io_socket));
348 break;
349 }
350 case SOCK_IMAGE: {
351 decl = &b.add_socket<decl::Image>(name, identifier, in_out)
352 .default_value_fn(get_default_id_getter(tree.tree_interface, io_socket));
353 break;
354 }
355 case SOCK_GEOMETRY:
356 decl = &b.add_socket<decl::Geometry>(name, identifier, in_out);
357 break;
358 case SOCK_COLLECTION: {
359 decl = &b.add_socket<decl::Collection>(name, identifier, in_out)
360 .default_value_fn(get_default_id_getter(tree.tree_interface, io_socket));
361 break;
362 }
363 case SOCK_TEXTURE: {
364 decl = &b.add_socket<decl::Texture>(name, identifier, in_out)
365 .default_value_fn(get_default_id_getter(tree.tree_interface, io_socket));
366 break;
367 }
368 case SOCK_MATERIAL: {
369 decl = &b.add_socket<decl::Material>(name, identifier, in_out)
370 .default_value_fn(get_default_id_getter(tree.tree_interface, io_socket));
371 break;
372 }
373 case SOCK_BUNDLE: {
374 decl = &b.add_socket<decl::Bundle>(name, identifier, in_out);
375 break;
376 }
377 case SOCK_CLOSURE: {
378 decl = &b.add_socket<decl::Closure>(name, identifier, in_out);
379 break;
380 }
381 case SOCK_CUSTOM: {
382 decl = &b.add_socket<decl::Custom>(name, identifier, in_out)
383 .idname(io_socket.socket_type)
384 .init_socket_fn(get_init_socket_fn(tree.tree_interface, io_socket));
385 break;
386 }
387 }
388 }
389 else {
390 decl = &b.add_socket<decl::Custom>(name, identifier, in_out)
391 .idname(io_socket.socket_type)
392 .init_socket_fn(get_init_socket_fn(tree.tree_interface, io_socket));
393 }
394 decl->description(io_socket.description ? io_socket.description : "");
395 decl->hide_value(io_socket.flag & NODE_INTERFACE_SOCKET_HIDE_VALUE);
396 decl->compact(io_socket.flag & NODE_INTERFACE_SOCKET_COMPACT);
397 decl->panel_toggle(io_socket.flag & NODE_INTERFACE_SOCKET_PANEL_TOGGLE);
398 decl->optional_label(io_socket.flag & NODE_INTERFACE_SOCKET_OPTIONAL_LABEL);
399 decl->default_input_type(NodeDefaultInputType(io_socket.default_input));
400 if (structure_type) {
401 decl->structure_type(*structure_type);
402 }
403 if (io_socket.default_input != NODE_DEFAULT_INPUT_VALUE) {
404 decl->hide_value();
405 }
406 return *decl;
407}
408
411 const bNode &node,
412 const bNodeTree &group,
413 const Map<const bNodeTreeInterfaceSocket *, StructureType> &structure_type_by_socket,
414 const bNodeTreeInterfacePanel &io_parent_panel,
415 const bool is_root)
416{
417 bool layout_added = false;
418 auto add_layout_if_needed = [&]() {
419 /* Some custom group nodes don't have a draw function. */
420 if (node.typeinfo->draw_buttons) {
421 if (is_root && !layout_added) {
422 b.add_default_layout();
423 layout_added = true;
424 }
425 }
426 };
427
428 for (const bNodeTreeInterfaceItem *item : io_parent_panel.items()) {
429 switch (NodeTreeInterfaceItemType(item->item_type)) {
431 const auto &io_socket = node_interface::get_item_as<bNodeTreeInterfaceSocket>(*item);
432 const eNodeSocketInOut in_out = (io_socket.flag & NODE_INTERFACE_SOCKET_INPUT) ? SOCK_IN :
433 SOCK_OUT;
434 if (in_out == SOCK_IN) {
435 add_layout_if_needed();
436 }
438 group, io_socket, structure_type_by_socket.lookup_try(&io_socket), in_out, b);
439 break;
440 }
442 add_layout_if_needed();
443 const auto &io_panel = node_interface::get_item_as<bNodeTreeInterfacePanel>(*item);
444 auto &panel_b = b.add_panel(StringRef(io_panel.name), io_panel.identifier)
445 .description(StringRef(io_panel.description))
446 .default_closed(io_panel.flag & NODE_INTERFACE_PANEL_DEFAULT_CLOSED);
448 panel_b, node, group, structure_type_by_socket, io_panel, false);
449 break;
450 }
451 }
452 }
453
454 add_layout_if_needed();
455}
456
458{
459 const bNode *node = b.node_or_null();
460 if (node == nullptr) {
461 return;
462 }
463 NodeDeclaration &r_declaration = b.declaration();
464 const bNodeTree *group = reinterpret_cast<const bNodeTree *>(node->id);
465 if (!group) {
466 return;
467 }
468 if (ID_IS_LINKED(&group->id) && (group->id.tag & ID_TAG_MISSING)) {
469 r_declaration.skip_updating_sockets = true;
470 return;
471 }
472 r_declaration.skip_updating_sockets = false;
473
474 /* Allow the node group interface to define the socket order. */
475 r_declaration.use_custom_socket_order = true;
476
477 group->ensure_interface_cache();
478
480 if (ELEM(group->type, NTREE_GEOMETRY, NTREE_COMPOSIT)) {
481 structure_type_by_socket.reserve(group->interface_items().size());
482
483 const Span<const bNodeTreeInterfaceSocket *> inputs = group->interface_inputs();
484 const Span<StructureType> input_structure_types =
485 group->runtime->structure_type_interface->inputs;
486 for (const int i : inputs.index_range()) {
487 structure_type_by_socket.add(inputs[i], input_structure_types[i]);
488 }
489
490 const Span<const bNodeTreeInterfaceSocket *> outputs = group->interface_outputs();
491 const Span<StructureTypeInterface::OutputDependency> output_structure_types =
492 group->runtime->structure_type_interface->outputs;
493 for (const int i : outputs.index_range()) {
494 structure_type_by_socket.add(outputs[i], output_structure_types[i].type);
495 }
496 }
497
499 b, *node, *group, structure_type_by_socket, group->tree_interface.root_panel, true);
500
501 if (group->type == NTREE_GEOMETRY) {
502 group->ensure_interface_cache();
503 const Span<const bNodeTreeInterfaceSocket *> inputs = group->interface_inputs();
504 const FieldInferencingInterface &field_interface =
505 *group->runtime->field_inferencing_interface;
506 for (const int i : inputs.index_range()) {
507 SocketDeclaration &decl = *r_declaration.inputs[i];
508 decl.input_field_type = field_interface.inputs[i];
509 }
510
511 for (const int i : r_declaration.outputs.index_range()) {
512 r_declaration.outputs[i]->output_field_dependency = field_interface.outputs[i];
513 }
514 }
515}
516
517} // namespace blender::nodes
518
520
521/* -------------------------------------------------------------------- */
524
525static void node_frame_init(bNodeTree * /*ntree*/, bNode *node)
526{
527 NodeFrame *data = MEM_callocN<NodeFrame>("frame node storage");
528 node->storage = data;
529
530 data->flag |= NODE_FRAME_SHRINK;
531
532 data->label_size = 20;
533}
534
536{
537 /* frame type is used for all tree types, needs dynamic allocation */
538 blender::bke::bNodeType *ntype = MEM_new<blender::bke::bNodeType>("frame node type");
539 ntype->free_self = [](blender::bke::bNodeType *type) { MEM_delete(type); };
540
541 blender::bke::node_type_base(*ntype, "NodeFrame", NODE_FRAME);
542 ntype->ui_name = "Frame";
543 ntype->ui_description =
544 "Collect related nodes together in a common area. Useful for organization when the "
545 "re-usability of a node group is not required";
546 ntype->nclass = NODE_CLASS_LAYOUT;
547 ntype->enum_name_legacy = "FRAME";
548 ntype->initfunc = node_frame_init;
551 blender::bke::node_type_size(*ntype, 150, 100, 0);
552 ntype->flag |= NODE_BACKGROUND;
553
555}
556
558
559/* -------------------------------------------------------------------- */
562
564{
565 const bNode *node = b.node_or_null();
566 if (node == nullptr) {
567 return;
568 }
569
570 const blender::StringRefNull socket_idname(
571 static_cast<const NodeReroute *>(node->storage)->type_idname);
572 b.add_input<blender::nodes::decl::Custom>("Input")
573 .idname(socket_idname.c_str())
574 .structure_type(blender::nodes::StructureType::Dynamic);
575 b.add_output<blender::nodes::decl::Custom>("Output")
576 .idname(socket_idname.c_str())
577 .structure_type(blender::nodes::StructureType::Dynamic);
578}
579
580static void node_reroute_init(bNodeTree * /*ntree*/, bNode *node)
581{
583 STRNCPY(data->type_idname, "NodeSocketColor");
584 node->storage = data;
585}
586
588{
589 /* frame type is used for all tree types, needs dynamic allocation */
590 blender::bke::bNodeType *ntype = MEM_new<blender::bke::bNodeType>("frame node type");
591 ntype->free_self = [](blender::bke::bNodeType *type) { MEM_delete(type); };
592
593 blender::bke::node_type_base(*ntype, "NodeReroute", NODE_REROUTE);
594 ntype->ui_name = "Reroute";
595 ntype->ui_description =
596 "A single-socket organization tool that supports one input and multiple outputs";
597 ntype->enum_name_legacy = "REROUTE";
598 ntype->nclass = NODE_CLASS_LAYOUT;
601 node_type_storage(*ntype, "NodeReroute", node_free_standard_storage, node_copy_standard_storage);
602
604}
605
607 int node_i = std::numeric_limits<int>::max();
608 int socket_in_node_i = std::numeric_limits<int>::max();
609
612 : node_i(socket.owner_node().index()), socket_in_node_i(socket.index())
613 {
614 }
615
617 {
618 if (this->node_i == other.node_i) {
619 return this->socket_in_node_i < other.socket_in_node_i;
620 }
621 return this->node_i < other.node_i;
622 }
623};
624
626{
627 using namespace blender;
628 ntree->ensure_topology_cache();
629
630 const Span<bNode *> all_reroute_nodes = ntree->nodes_by_type("NodeReroute");
631
632 VectorSet<int> reroute_nodes;
633 for (const bNode *reroute : all_reroute_nodes) {
634 reroute_nodes.add(reroute->index());
635 }
636
637 /* Any reroute can be connected only to one source, or can be not connected at all.
638 * So reroute forms a trees. It is possible that there will be cycle, but such cycle
639 * can be only one in strongly connected set of reroutes. To propagate a types from
640 * some certain target to all the reroutes in such a tree we need to know all such
641 * a trees and all possible targets for each tree. */
642 DisjointSet reroutes_groups(reroute_nodes.size());
643
644 for (const bNode *src_reroute : all_reroute_nodes) {
645 const int src_reroute_i = reroute_nodes.index_of(src_reroute->index());
646 for (const bNodeSocket *dst_socket :
647 src_reroute->output_sockets().first()->directly_linked_sockets())
648 {
649 const bNode &dst_node = dst_socket->owner_node();
650 if (!dst_node.is_reroute()) {
651 continue;
652 }
653 const int dst_reroute_i = reroute_nodes.index_of(dst_node.index());
654 reroutes_groups.join(src_reroute_i, dst_reroute_i);
655 }
656 }
657
658 VectorSet<int> reroute_groups;
659 for (const int reroute_i : reroute_nodes.index_range()) {
660 const int root_reroute_i = reroutes_groups.find_root(reroute_i);
661 reroute_groups.add(root_reroute_i);
662 }
663
664 /* Any reroute can have only one source and many destination targets. Type propagation considers
665 * source as target with highest priority. */
666 Array<const bke::bNodeSocketType *> dst_type_by_reroute_group(reroute_groups.size(), nullptr);
667 Array<const bke::bNodeSocketType *> src_type_by_reroute_group(reroute_groups.size(), nullptr);
668
669 /* Reroute type priority based on the indices of target sockets in the node and the nodes in the
670 * tree. */
671 Array<RerouteTargetPriority> reroute_group_dst_type_priority(reroute_groups.size(),
673
674 for (const bNodeLink *link : ntree->all_links()) {
675 const bNode *src_node = link->fromnode;
676 const bNode *dst_node = link->tonode;
677
678 if (src_node->is_reroute() == dst_node->is_reroute()) {
679 continue;
680 }
681
682 if (!dst_node->is_reroute()) {
683 const int src_reroute_i = reroute_nodes.index_of(src_node->index());
684 const int src_reroute_root_i = reroutes_groups.find_root(src_reroute_i);
685 const int src_reroute_group_i = reroute_groups.index_of(src_reroute_root_i);
686
687 const RerouteTargetPriority type_priority(*link->tosock);
688 if (reroute_group_dst_type_priority[src_reroute_group_i] > type_priority) {
689 continue;
690 }
691
692 reroute_group_dst_type_priority[src_reroute_group_i] = type_priority;
693
694 const bNodeSocket *dst_socket = link->tosock;
695 /* There could be a function which will choose best from
696 * #dst_type_by_reroute_group and #dst_socket, but right now this match behavior as-is. */
697 dst_type_by_reroute_group[src_reroute_group_i] = dst_socket->typeinfo;
698 continue;
699 }
700
701 BLI_assert(!src_node->is_reroute());
702 const int dst_reroute_i = reroute_nodes.index_of(dst_node->index());
703 const int dst_reroute_root_i = reroutes_groups.find_root(dst_reroute_i);
704 const int dst_reroute_group_i = reroute_groups.index_of(dst_reroute_root_i);
705
706 const bNodeSocket *src_socket = link->fromsock;
707 /* There could be a function which will choose best from
708 * #src_type_by_reroute_group and #src_socket, but right now this match behavior as-is. */
709 src_type_by_reroute_group[dst_reroute_group_i] = src_socket->typeinfo;
710 }
711
712 const Span<bNode *> all_nodes = ntree->all_nodes();
713 for (const int reroute_i : reroute_nodes.index_range()) {
714 const int reroute_root_i = reroutes_groups.find_root(reroute_i);
715 const int reroute_group_i = reroute_groups.index_of(reroute_root_i);
716
717 const bke::bNodeSocketType *reroute_type = nullptr;
718 if (dst_type_by_reroute_group[reroute_group_i] != nullptr) {
719 reroute_type = dst_type_by_reroute_group[reroute_group_i];
720 }
721 if (src_type_by_reroute_group[reroute_group_i] != nullptr) {
722 reroute_type = src_type_by_reroute_group[reroute_group_i];
723 }
724
725 if (reroute_type == nullptr) {
726 continue;
727 }
728
729 const int reroute_index = reroute_nodes[reroute_i];
730 bNode &reroute_node = *all_nodes[reroute_index];
731 NodeReroute *storage = static_cast<NodeReroute *>(reroute_node.storage);
732 if (reroute_type->idname != storage->type_idname) {
733 StringRef(reroute_type->idname).copy_utf8_truncated(storage->type_idname);
734 nodes::update_node_declaration_and_sockets(*ntree, reroute_node);
735 }
736 }
737}
738
740{
741 ntree.ensure_topology_cache();
742 Stack<const bNode *> nodes_to_check;
743 for (const bNodeSocket *socket : node.output_sockets()) {
744 for (const bNodeLink *link : socket->directly_linked_links()) {
745 nodes_to_check.push(link->tonode);
746 }
747 }
748 while (!nodes_to_check.is_empty()) {
749 const bNode *next_node = nodes_to_check.pop();
750 for (const bNodeSocket *socket : next_node->output_sockets()) {
751 for (const bNodeLink *link : socket->directly_linked_links()) {
752 if (link->tonode->typeinfo->nclass == NODE_CLASS_OUTPUT &&
753 link->tonode->flag & NODE_DO_OUTPUT)
754 {
755 return true;
756 }
757 nodes_to_check.push(link->tonode);
758 }
759 }
760 }
761
762 return false;
763}
764
766
767/* -------------------------------------------------------------------- */
770
772{
773 LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
774 if (sock->identifier == identifier) {
775 return sock;
776 }
777 }
778 return nullptr;
779}
780
781namespace blender::nodes {
782
784{
785 const bNodeTree *node_tree = b.tree_or_null();
786 if (node_tree == nullptr) {
787 return;
788 }
789 node_tree->tree_interface.foreach_item([&](const bNodeTreeInterfaceItem &item) {
790 switch (NodeTreeInterfaceItemType(item.item_type)) {
792 const bNodeTreeInterfaceSocket &socket =
794 if (socket.flag & NODE_INTERFACE_SOCKET_INPUT) {
795 /* Trying to use the evaluated structure type for the group output node introduces a
796 * "dependency cycle" between this and the structure type inferencing which uses node
797 * declarations. The compromise is to not use the proper structure type in the group
798 * input/output declarations and instead use a special case for the choice of socket
799 * shapes. */
800 build_interface_socket_declaration(*node_tree, socket, std::nullopt, SOCK_OUT, b);
801 }
802 break;
803 }
805 break;
806 }
807 }
808 return true;
809 });
810 b.add_output<decl::Extend>("", "__extend__");
811}
812
814{
815 const bNodeTree *node_tree = b.tree_or_null();
816 if (node_tree == nullptr) {
817 return;
818 }
819 node_tree->tree_interface.foreach_item([&](const bNodeTreeInterfaceItem &item) {
820 switch (NodeTreeInterfaceItemType(item.item_type)) {
822 const bNodeTreeInterfaceSocket &socket =
824 if (socket.flag & NODE_INTERFACE_SOCKET_OUTPUT) {
825 build_interface_socket_declaration(*node_tree, socket, std::nullopt, SOCK_IN, b);
826 }
827 break;
828 }
830 break;
831 }
832 }
833 return true;
834 });
835 b.add_input<decl::Extend>("", "__extend__");
836}
837
839{
840 BLI_assert(params.link.tonode != &params.node);
841 BLI_assert(params.link.tosock->in_out == SOCK_IN);
842 if (!StringRef(params.link.fromsock->identifier).startswith("__extend__")) {
843 return true;
844 }
845 if (StringRef(params.link.tosock->identifier).startswith("__extend__")) {
846 /* Don't connect to other "extend" sockets. */
847 return false;
848 }
850 params.ntree, *params.link.tonode, *params.link.tosock);
851 if (!io_socket) {
852 return false;
853 }
855 params.link.fromsock = node_group_input_find_socket(&params.node, io_socket->identifier);
856 return true;
857}
858
860{
861 BLI_assert(params.link.fromnode != &params.node);
862 BLI_assert(params.link.fromsock->in_out == SOCK_OUT);
863 if (!StringRef(params.link.tosock->identifier).startswith("__extend__")) {
864 return true;
865 }
866 if (StringRef(params.link.fromsock->identifier).startswith("__extend__")) {
867 /* Don't connect to other "extend" sockets. */
868 return false;
869 }
871 params.ntree, *params.link.fromnode, *params.link.fromsock);
872 if (!io_socket) {
873 return false;
874 }
876 params.link.tosock = node_group_output_find_socket(&params.node, io_socket->identifier);
877 return true;
878}
879
881{
882 ed::space_node::node_tree_interface_draw(*C, *layout, *id_cast<bNodeTree *>(ptr->owner_id));
883}
884
886{
887 ed::space_node::node_tree_interface_draw(*C, *layout, *id_cast<bNodeTree *>(ptr->owner_id));
888}
889
890} // namespace blender::nodes
891
893{
894 get_compositor_group_input_extra_info(params);
895}
896
898{
899 /* used for all tree types, needs dynamic allocation */
900 blender::bke::bNodeType *ntype = MEM_new<blender::bke::bNodeType>("node type");
901 ntype->free_self = [](blender::bke::bNodeType *type) { MEM_delete(type); };
902
903 blender::bke::node_type_base(*ntype, "NodeGroupInput", NODE_GROUP_INPUT);
904 ntype->ui_name = "Group Input";
905 ntype->ui_description =
906 "Expose connected data from inside a node group as inputs to its interface";
907 ntype->enum_name_legacy = "GROUP_INPUT";
909 blender::bke::node_type_size(*ntype, 140, 80, 400);
915 ntype->no_muting = true;
916
918}
919
921{
922 LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
923 if (sock->identifier == identifier) {
924 return sock;
925 }
926 }
927 return nullptr;
928}
929
931{
932 get_compositor_group_output_extra_info(params);
933 const blender::Span<const bNode *> group_output_nodes = params.tree.nodes_by_type(
934 "NodeGroupOutput");
935 if (group_output_nodes.size() <= 1) {
936 return;
937 }
938 if (params.node.flag & NODE_DO_OUTPUT) {
939 return;
940 }
942 row.text = IFACE_("Unused Output");
943 row.icon = ICON_ERROR;
944 row.tooltip = TIP_("There are multiple group output nodes and this one is not active");
945 params.rows.append(std::move(row));
946}
947
949{
950 /* used for all tree types, needs dynamic allocation */
951 blender::bke::bNodeType *ntype = MEM_new<blender::bke::bNodeType>("node type");
952 ntype->free_self = [](blender::bke::bNodeType *type) { MEM_delete(type); };
953
954 blender::bke::node_type_base(*ntype, "NodeGroupOutput", NODE_GROUP_OUTPUT);
955 ntype->ui_name = "Group Output";
956 ntype->ui_description = "Output data from inside of a node group";
957 ntype->enum_name_legacy = "GROUP_OUTPUT";
959 blender::bke::node_type_size(*ntype, 140, 80, 400);
965
966 ntype->no_muting = true;
967
969}
970
#define NODE_CLASS_OUTPUT
Definition BKE_node.hh:448
#define NODE_REROUTE
Definition BKE_node.hh:813
#define NODE_CLASS_INTERFACE
Definition BKE_node.hh:459
#define NODE_CLASS_MATTE
Definition BKE_node.hh:454
#define NODE_CLASS_CONVERTER
Definition BKE_node.hh:453
#define NODE_CLASS_PATTERN
Definition BKE_node.hh:456
#define NODE_CLASS_GEOMETRY
Definition BKE_node.hh:461
#define NODE_GROUP_OUTPUT
Definition BKE_node.hh:815
#define NODE_CLASS_DISTORT
Definition BKE_node.hh:455
#define NODE_CLASS_OP_VECTOR
Definition BKE_node.hh:450
#define NODE_CLASS_LAYOUT
Definition BKE_node.hh:463
#define NODE_CLASS_OP_COLOR
Definition BKE_node.hh:449
#define NODE_CLASS_INPUT
Definition BKE_node.hh:447
#define NODE_CLASS_OP_FILTER
Definition BKE_node.hh:451
#define NODE_FRAME
Definition BKE_node.hh:812
#define NODE_CLASS_GROUP
Definition BKE_node.hh:452
#define NODE_GROUP_INPUT
Definition BKE_node.hh:814
#define NODE_CLASS_ATTRIBUTE
Definition BKE_node.hh:462
#define NODE_CLASS_TEXTURE
Definition BKE_node.hh:457
#define NODE_CLASS_SHADER
Definition BKE_node.hh:460
#define NODE_CLASS_SCRIPT
Definition BKE_node.hh:458
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define ELEM(...)
#define RPT_(msgid)
#define BLT_I18NCONTEXT_ID_NODETREE
#define TIP_(msgid)
#define CTX_IFACE_(context, msgid)
#define IFACE_(msgid)
@ ID_TAG_MISSING
Definition DNA_ID.h:867
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:694
@ ID_NT
@ NODE_INTERFACE_PANEL_DEFAULT_CLOSED
@ NODE_INTERFACE_SOCKET_PANEL_TOGGLE
@ NODE_INTERFACE_SOCKET_OPTIONAL_LABEL
@ NODE_INTERFACE_SOCKET_MENU_EXPANDED
@ NODE_INTERFACE_SOCKET_COMPACT
@ NODE_INTERFACE_SOCKET_HIDE_VALUE
@ NODE_DO_OUTPUT
@ NODE_BACKGROUND
@ NTREE_GEOMETRY
@ NTREE_COMPOSIT
eNodeSocketInOut
@ SOCK_OUT
@ SOCK_IN
eNodeSocketDatatype
@ SOCK_INT
@ SOCK_TEXTURE
@ SOCK_VECTOR
@ SOCK_CLOSURE
@ SOCK_BOOLEAN
@ SOCK_MATERIAL
@ SOCK_SHADER
@ SOCK_MATRIX
@ SOCK_FLOAT
@ SOCK_IMAGE
@ SOCK_COLLECTION
@ SOCK_CUSTOM
@ SOCK_BUNDLE
@ SOCK_GEOMETRY
@ SOCK_ROTATION
@ SOCK_OBJECT
@ SOCK_STRING
@ SOCK_RGBA
@ SOCK_MENU
@ NODE_FRAME_SHRINK
Read Guarded memory(de)allocation.
PropertySubType
Definition RNA_types.hh:232
#define C
Definition RandGen.cpp:29
BMesh const char void * data
void join(const size_t x, const size_t y)
bool add(const Key &key)
int64_t size() const
int64_t index_of(const Key &key) const
IndexRange index_range() const
std::optional< Value > lookup_try(const Key &key) const
Definition BLI_map.hh:531
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
void reserve(int64_t n)
Definition BLI_map.hh:1028
constexpr int64_t size() const
Definition BLI_span.hh:252
bool is_empty() const
Definition BLI_stack.hh:308
void push(const T &value)
Definition BLI_stack.hh:213
constexpr bool startswith(StringRef prefix) const
void copy_utf8_truncated(char *dst, int64_t dst_size) const
Definition string_ref.cc:28
constexpr const char * c_str() const
Vector< SocketDeclaration * > inputs
Vector< SocketDeclaration * > outputs
std::function< void(bNode &node, bNodeSocket &socket, const char *data_path)> init_socket_fn
KDTree_3d * tree
#define GS(x)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
T & get_item_as(bNodeTreeInterfaceItem &item)
bNodeTreeInterfaceSocket * add_interface_socket_from_node(bNodeTree &ntree, const bNode &from_node, const bNodeSocket &from_sock, StringRef socket_type, StringRef name)
T & get_socket_data_as(bNodeTreeInterfaceSocket &item)
bool node_is_connected_to_output(const bNodeTree &ntree, const bNode &node)
bool node_group_poll(const bNodeTree *nodetree, const bNodeTree *grouptree, const char **r_disabled_hint)
void node_type_size(bNodeType &ntype, int width, int minwidth, int maxwidth)
Definition node.cc:5384
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
void node_type_base(bNodeType &ntype, std::string idname, std::optional< int16_t > legacy_type=std::nullopt)
Definition node.cc:5099
bNodeSocketType * node_socket_type_find(StringRef idname)
Definition node.cc:2462
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
void node_tree_interface_draw(bContext &C, uiLayout &layout, bNodeTree &tree)
EulerXYZBase< float > EulerXYZ
static void group_input_declare(NodeDeclarationBuilder &b)
static std::function< ID *(const bNode &node)> get_default_id_getter(const bNodeTreeInterface &tree_interface, const bNodeTreeInterfaceSocket &io_socket)
static void node_group_output_layout(uiLayout *layout, bContext *C, PointerRNA *ptr)
static bool group_input_insert_link(blender::bke::NodeInsertLinkParams &params)
void update_node_declaration_and_sockets(bNodeTree &ntree, bNode &node)
compositor::NodeOperation * get_group_output_compositor_operation(compositor::Context &context, DNode node)
static std::function< void(bNode &node, bNodeSocket &socket, const char *data_path)> get_init_socket_fn(const bNodeTreeInterface &interface, const bNodeTreeInterfaceSocket &io_socket)
void node_group_declare(NodeDeclarationBuilder &b)
static bool group_output_insert_link(blender::bke::NodeInsertLinkParams &params)
static void node_group_input_layout(uiLayout *layout, bContext *C, PointerRNA *ptr)
static void group_output_declare(NodeDeclarationBuilder &b)
compositor::NodeOperation * get_group_input_compositor_operation(compositor::Context &context, DNode node)
static BaseSocketDeclarationBuilder & build_interface_socket_declaration(const bNodeTree &tree, const bNodeTreeInterfaceSocket &io_socket, const std::optional< StructureType > structure_type, const eNodeSocketInOut in_out, DeclarationListBuilder &b)
static void node_group_declare_panel_recursive(DeclarationListBuilder &b, const bNode &node, const bNodeTree &group, const Map< const bNodeTreeInterfaceSocket *, StructureType > &structure_type_by_socket, const bNodeTreeInterfacePanel &io_parent_panel, const bool is_root)
VecBase< float, 4 > float4
VecBase< float, 3 > float3
static void node_group_input_extra_info(blender::nodes::NodeExtraInfoParams &params)
static void node_group_output_extra_info(blender::nodes::NodeExtraInfoParams &params)
static bNodeSocket * find_matching_socket(ListBase &sockets, StringRef identifier)
int node_group_ui_class(const bNode *node)
bNodeSocket * node_group_output_find_socket(bNode *node, const StringRef identifier)
bNodeSocket * node_group_input_find_socket(bNode *node, const StringRef identifier)
void register_node_type_group_output()
void node_group_label(const bNodeTree *, const bNode *node, char *label, int label_maxncpy)
void register_node_type_group_input()
bNodeSocket * node_group_find_input_socket(bNode *groupnode, const blender::StringRef identifier)
void ntree_update_reroute_nodes(bNodeTree *ntree)
static void node_frame_init(bNodeTree *, bNode *node)
bool node_group_poll_instance(const bNode *node, const bNodeTree *nodetree, const char **r_disabled_hint)
static void node_reroute_init(bNodeTree *, bNode *node)
void register_node_type_frame()
bNodeSocket * node_group_find_output_socket(bNode *groupnode, const blender::StringRef identifier)
static void node_reroute_declare(blender::nodes::NodeDeclarationBuilder &b)
std::string node_group_ui_description(const bNode &node)
void register_node_type_reroute()
static blender::bke::bNodeSocketTemplate outputs[]
static blender::bke::bNodeSocketTemplate inputs[]
void node_free_standard_storage(bNode *node)
Definition node_util.cc:42
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:54
const char * name
Definition DNA_ID.h:414
int tag
Definition DNA_ID.h:442
struct AssetMetaData * asset_data
Definition DNA_ID.h:423
char name[258]
Definition DNA_ID.h:432
char type_idname[64]
RerouteTargetPriority()=default
RerouteTargetPriority(const bNodeSocket &socket)
bool operator>(const RerouteTargetPriority other)
bNodeSocketTypeHandle * typeinfo
bNodeTreeInterfacePanel root_panel
bNodeTreeRuntimeHandle * runtime
char * description
bNodeTreeInterface tree_interface
bNodeTypeHandle * typeinfo
ListBase inputs
struct ID * id
void * storage
ListBase outputs
Defines a socket type.
Definition BKE_node.hh:158
void(* interface_init_socket)(ID *id, const bNodeTreeInterfaceSocket *interface_socket, bNode *node, bNodeSocket *socket, StringRefNull data_path)
Definition BKE_node.hh:178
eNodeSocketDatatype type
Definition BKE_node.hh:193
Defines a node type.
Definition BKE_node.hh:238
std::string ui_description
Definition BKE_node.hh:244
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
NodeExtraInfoFunction get_extra_info
Definition BKE_node.hh:381
const char * enum_name_legacy
Definition BKE_node.hh:247
bool(* insert_link)(NodeInsertLinkParams &params)
Definition BKE_node.hh:333
NodeDeclareFunction declare
Definition BKE_node.hh:362
void(* free_self)(bNodeType *ntype)
Definition BKE_node.hh:335
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4238