Blender V4.5
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 "node_common.h"
46#include "node_util.hh"
47
48using blender::Map;
50using blender::Set;
51using blender::Stack;
53using blender::Vector;
54
56
57/* -------------------------------------------------------------------- */
60
62{
63 LISTBASE_FOREACH (bNodeSocket *, socket, &sockets) {
64 if (socket->identifier == identifier) {
65 return socket;
66 }
67 }
68 return nullptr;
69}
70
72{
73 return find_matching_socket(groupnode->inputs, identifier);
74}
75
77{
78 return find_matching_socket(groupnode->outputs, identifier);
79}
80
81void node_group_label(const bNodeTree * /*ntree*/,
82 const bNode *node,
83 char *label,
84 int label_maxncpy)
85{
87 label, (node->id) ? node->id->name + 2 : IFACE_("Missing Data-Block"), label_maxncpy);
88}
89
90int node_group_ui_class(const bNode *node)
91{
92 const bNodeTree *group = reinterpret_cast<const bNodeTree *>(node->id);
93 if (!group) {
94 return NODE_CLASS_GROUP;
95 }
96 switch (blender::bke::NodeColorTag(group->color_tag)) {
98 return NODE_CLASS_GROUP;
102 return NODE_CLASS_OP_COLOR;
106 return NODE_CLASS_DISTORT;
110 return NODE_CLASS_GEOMETRY;
112 return NODE_CLASS_INPUT;
114 return NODE_CLASS_MATTE;
116 return NODE_CLASS_OUTPUT;
118 return NODE_CLASS_SCRIPT;
120 return NODE_CLASS_SHADER;
122 return NODE_CLASS_TEXTURE;
126 return NODE_CLASS_PATTERN;
130 return NODE_CLASS_GROUP;
131 }
132 return NODE_CLASS_GROUP;
133}
134
136 const bNodeTree *nodetree,
137 const char **r_disabled_hint)
138{
139 if (!node->typeinfo->poll(node->typeinfo, nodetree, r_disabled_hint)) {
140 return false;
141 }
142 const bNodeTree *grouptree = reinterpret_cast<const bNodeTree *>(node->id);
143 if (!grouptree) {
144 return true;
145 }
146 return blender::bke::node_group_poll(nodetree, grouptree, r_disabled_hint);
147}
148
149std::string node_group_ui_description(const bNode &node)
150{
151 if (!node.id) {
152 return "";
153 }
154 const bNodeTree *group = reinterpret_cast<const bNodeTree *>(node.id);
155 if (group->id.asset_data) {
156 if (group->id.asset_data->description) {
157 return group->id.asset_data->description;
158 }
159 }
160 if (!group->description) {
161 return "";
162 }
163 return group->description;
164}
165
167 const bNodeTree *grouptree,
168 const char **r_disabled_hint)
169{
170 /* unspecified node group, generally allowed
171 * (if anything, should be avoided on operator level)
172 */
173 if (grouptree == nullptr) {
174 return true;
175 }
176
177 if (nodetree == grouptree) {
178 if (r_disabled_hint) {
179 *r_disabled_hint = RPT_("Nesting a node group inside of itself is not allowed");
180 }
181 return false;
182 }
183 if (nodetree->type != grouptree->type) {
184 if (r_disabled_hint) {
185 *r_disabled_hint = RPT_("Node group has different type");
186 }
187 return false;
188 }
189
190 for (const bNode *node : grouptree->all_nodes()) {
191 if (node->typeinfo->poll_instance &&
192 !node->typeinfo->poll_instance(node, nodetree, r_disabled_hint))
193 {
194 return false;
195 }
196 }
197 return true;
198}
199
200namespace blender::nodes {
201
202static std::function<ID *(const bNode &node)> get_default_id_getter(
203 const bNodeTreeInterface &tree_interface, const bNodeTreeInterfaceSocket &io_socket)
204{
205 const int item_index = tree_interface.find_item_index(io_socket.item);
206 BLI_assert(item_index >= 0);
207
208 /* Avoid capturing pointers that can become dangling. */
209 return [item_index](const bNode &node) -> ID * {
210 if (node.id == nullptr) {
211 return nullptr;
212 }
213 if (GS(node.id->name) != ID_NT) {
214 return nullptr;
215 }
216 const bNodeTree &ntree = *reinterpret_cast<const bNodeTree *>(node.id);
217 const bNodeTreeInterfaceItem *io_item = ntree.tree_interface.get_item_at_index(item_index);
218 const bNodeTreeInterfaceSocket *io_socket =
220 if (!io_socket) {
221 return nullptr;
222 }
223 return *static_cast<ID **>(io_socket->socket_data);
224 };
225}
226
227static std::function<void(bNode &node, bNodeSocket &socket, const char *data_path)>
229{
230 const int item_index = interface.find_item_index(io_socket.item);
231 BLI_assert(item_index >= 0);
232
233 /* Avoid capturing pointers that can become dangling. */
234 return [item_index](bNode &node, bNodeSocket &socket, const char *data_path) {
235 if (node.id == nullptr) {
236 return;
237 }
238 if (GS(node.id->name) != ID_NT) {
239 return;
240 }
241 bNodeTree &ntree = *reinterpret_cast<bNodeTree *>(node.id);
242 const bNodeTreeInterfaceItem *io_item = ntree.tree_interface.get_item_at_index(item_index);
243 if (io_item == nullptr || io_item->item_type != NODE_INTERFACE_SOCKET) {
244 return;
245 }
246 const bNodeTreeInterfaceSocket &io_socket =
248 blender::bke::bNodeSocketType *typeinfo = io_socket.socket_typeinfo();
249 if (typeinfo && typeinfo->interface_init_socket) {
250 typeinfo->interface_init_socket(&ntree.id, &io_socket, &node, &socket, data_path);
251 }
252 };
253}
254
256 const bNodeTree &tree,
257 const bNodeTreeInterfaceSocket &io_socket,
258 const std::optional<StructureType> structure_type,
259 const eNodeSocketInOut in_out,
261{
263 io_socket.socket_type);
265
266 const StringRef name = io_socket.name;
267 const StringRef identifier = io_socket.identifier;
268
270 if (base_typeinfo) {
271 datatype = base_typeinfo->type;
272 switch (datatype) {
273 case SOCK_FLOAT: {
275 decl = &b.add_socket<decl::Float>(name, identifier, in_out)
276 .subtype(PropertySubType(value.subtype))
277 .default_value(value.value)
278 .min(value.min)
279 .max(value.max);
280 break;
281 }
282 case SOCK_VECTOR: {
284 decl = &b.add_socket<decl::Vector>(name, identifier, in_out)
285 .subtype(PropertySubType(value.subtype))
286 .default_value(float4(value.value))
287 .dimensions(value.dimensions)
288 .min(value.min)
289 .max(value.max);
290 break;
291 }
292 case SOCK_RGBA: {
294 decl = &b.add_socket<decl::Color>(name, identifier, in_out).default_value(value.value);
295 break;
296 }
297 case SOCK_SHADER: {
298 decl = &b.add_socket<decl::Shader>(name, identifier, in_out);
299 break;
300 }
301 case SOCK_BOOLEAN: {
303 decl = &b.add_socket<decl::Bool>(name, identifier, in_out).default_value(value.value);
304 break;
305 }
306 case SOCK_ROTATION: {
308 io_socket);
309 decl = &b.add_socket<decl::Rotation>(name, identifier, in_out)
310 .default_value(math::EulerXYZ(float3(value.value_euler)));
311 break;
312 }
313 case SOCK_MATRIX: {
314 decl = &b.add_socket<decl::Matrix>(name, identifier, in_out);
315 break;
316 }
317 case SOCK_INT: {
318 const auto &value = node_interface::get_socket_data_as<bNodeSocketValueInt>(io_socket);
319 decl = &b.add_socket<decl::Int>(name, identifier, in_out)
320 .subtype(PropertySubType(value.subtype))
321 .default_value(value.value)
322 .min(value.min)
323 .max(value.max);
324 break;
325 }
326 case SOCK_STRING: {
328 decl = &b.add_socket<decl::String>(name, identifier, in_out)
329 .subtype(PropertySubType(value.subtype))
330 .default_value(value.value);
331 break;
332 }
333 case SOCK_MENU: {
335 decl = &b.add_socket<decl::Menu>(name, identifier, in_out)
336 .default_value(value.value)
337 .expanded(io_socket.flag & NODE_INTERFACE_SOCKET_MENU_EXPANDED);
338 break;
339 }
340 case SOCK_OBJECT: {
341 decl = &b.add_socket<decl::Object>(name, identifier, in_out)
342 .default_value_fn(get_default_id_getter(tree.tree_interface, io_socket));
343 break;
344 }
345 case SOCK_IMAGE: {
346 decl = &b.add_socket<decl::Image>(name, identifier, in_out)
347 .default_value_fn(get_default_id_getter(tree.tree_interface, io_socket));
348 break;
349 }
350 case SOCK_GEOMETRY:
351 decl = &b.add_socket<decl::Geometry>(name, identifier, in_out);
352 break;
353 case SOCK_COLLECTION: {
354 decl = &b.add_socket<decl::Collection>(name, identifier, in_out)
355 .default_value_fn(get_default_id_getter(tree.tree_interface, io_socket));
356 break;
357 }
358 case SOCK_TEXTURE: {
359 decl = &b.add_socket<decl::Texture>(name, identifier, in_out)
360 .default_value_fn(get_default_id_getter(tree.tree_interface, io_socket));
361 break;
362 }
363 case SOCK_MATERIAL: {
364 decl = &b.add_socket<decl::Material>(name, identifier, in_out)
365 .default_value_fn(get_default_id_getter(tree.tree_interface, io_socket));
366 break;
367 }
368 case SOCK_BUNDLE: {
369 decl = &b.add_socket<decl::Bundle>(name, identifier, in_out);
370 break;
371 }
372 case SOCK_CLOSURE: {
373 decl = &b.add_socket<decl::Closure>(name, identifier, in_out);
374 break;
375 }
376 case SOCK_CUSTOM: {
377 decl = &b.add_socket<decl::Custom>(name, identifier, in_out)
378 .idname(io_socket.socket_type)
379 .init_socket_fn(get_init_socket_fn(tree.tree_interface, io_socket));
380 break;
381 }
382 }
383 }
384 else {
385 decl = &b.add_socket<decl::Custom>(name, identifier, in_out)
386 .idname(io_socket.socket_type)
387 .init_socket_fn(get_init_socket_fn(tree.tree_interface, io_socket));
388 }
389 decl->description(io_socket.description ? io_socket.description : "");
390 decl->hide_value(io_socket.flag & NODE_INTERFACE_SOCKET_HIDE_VALUE);
391 decl->compact(io_socket.flag & NODE_INTERFACE_SOCKET_COMPACT);
392 decl->panel_toggle(io_socket.flag & NODE_INTERFACE_SOCKET_PANEL_TOGGLE);
393 decl->default_input_type(NodeDefaultInputType(io_socket.default_input));
394 if (structure_type) {
395 decl->structure_type(*structure_type);
396 }
397 if (io_socket.default_input != NODE_DEFAULT_INPUT_VALUE) {
398 decl->hide_value();
399 }
400 return *decl;
401}
402
405 const bNode &node,
406 const bNodeTree &group,
407 const Map<const bNodeTreeInterfaceSocket *, StructureType> &structure_type_by_socket,
408 const bNodeTreeInterfacePanel &io_parent_panel,
409 const bool is_root)
410{
411 bool layout_added = false;
412 auto add_layout_if_needed = [&]() {
413 /* Some custom group nodes don't have a draw function. */
414 if (node.typeinfo->draw_buttons) {
415 if (is_root && !layout_added) {
416 b.add_default_layout();
417 layout_added = true;
418 }
419 }
420 };
421
422 for (const bNodeTreeInterfaceItem *item : io_parent_panel.items()) {
423 switch (NodeTreeInterfaceItemType(item->item_type)) {
425 const auto &io_socket = node_interface::get_item_as<bNodeTreeInterfaceSocket>(*item);
426 const eNodeSocketInOut in_out = (io_socket.flag & NODE_INTERFACE_SOCKET_INPUT) ? SOCK_IN :
427 SOCK_OUT;
428 if (in_out == SOCK_IN) {
429 add_layout_if_needed();
430 }
432 group, io_socket, structure_type_by_socket.lookup_try(&io_socket), in_out, b);
433 break;
434 }
436 add_layout_if_needed();
437 const auto &io_panel = node_interface::get_item_as<bNodeTreeInterfacePanel>(*item);
438 auto &panel_b = b.add_panel(StringRef(io_panel.name), io_panel.identifier)
439 .description(StringRef(io_panel.description))
440 .default_closed(io_panel.flag & NODE_INTERFACE_PANEL_DEFAULT_CLOSED);
442 panel_b, node, group, structure_type_by_socket, io_panel, false);
443 break;
444 }
445 }
446 }
447
448 add_layout_if_needed();
449}
450
452{
453 const bNode *node = b.node_or_null();
454 if (node == nullptr) {
455 return;
456 }
457 NodeDeclaration &r_declaration = b.declaration();
458 const bNodeTree *group = reinterpret_cast<const bNodeTree *>(node->id);
459 if (!group) {
460 return;
461 }
462 if (ID_IS_LINKED(&group->id) && (group->id.tag & ID_TAG_MISSING)) {
463 r_declaration.skip_updating_sockets = true;
464 return;
465 }
466 r_declaration.skip_updating_sockets = false;
467
468 /* Allow the node group interface to define the socket order. */
469 r_declaration.use_custom_socket_order = true;
470
471 group->ensure_interface_cache();
472
474 if (group->type == NTREE_GEOMETRY) {
475 structure_type_by_socket.reserve(group->interface_items().size());
476
477 const Span<const bNodeTreeInterfaceSocket *> inputs = group->interface_inputs();
478 const Span<StructureType> input_structure_types =
479 group->runtime->structure_type_interface->inputs;
480 for (const int i : inputs.index_range()) {
481 structure_type_by_socket.add(inputs[i], input_structure_types[i]);
482 }
483
484 const Span<const bNodeTreeInterfaceSocket *> outputs = group->interface_outputs();
485 const Span<StructureTypeInterface::OutputDependency> output_structure_types =
486 group->runtime->structure_type_interface->outputs;
487 for (const int i : outputs.index_range()) {
488 structure_type_by_socket.add(outputs[i], output_structure_types[i].type);
489 }
490 }
491
493 b, *node, *group, structure_type_by_socket, group->tree_interface.root_panel, true);
494
495 if (group->type == NTREE_GEOMETRY) {
496 group->ensure_interface_cache();
497 const Span<const bNodeTreeInterfaceSocket *> inputs = group->interface_inputs();
498 const FieldInferencingInterface &field_interface =
499 *group->runtime->field_inferencing_interface;
500 for (const int i : inputs.index_range()) {
501 SocketDeclaration &decl = *r_declaration.inputs[i];
502 decl.input_field_type = field_interface.inputs[i];
503 }
504
505 for (const int i : r_declaration.outputs.index_range()) {
506 r_declaration.outputs[i]->output_field_dependency = field_interface.outputs[i];
507 }
508 }
509}
510
511} // namespace blender::nodes
512
514
515/* -------------------------------------------------------------------- */
518
519static void node_frame_init(bNodeTree * /*ntree*/, bNode *node)
520{
521 NodeFrame *data = MEM_callocN<NodeFrame>("frame node storage");
522 node->storage = data;
523
524 data->flag |= NODE_FRAME_SHRINK;
525
526 data->label_size = 20;
527}
528
530{
531 /* frame type is used for all tree types, needs dynamic allocation */
532 blender::bke::bNodeType *ntype = MEM_new<blender::bke::bNodeType>("frame node type");
533 ntype->free_self = [](blender::bke::bNodeType *type) { MEM_delete(type); };
534
535 blender::bke::node_type_base(*ntype, "NodeFrame", NODE_FRAME);
536 ntype->ui_name = "Frame";
537 ntype->ui_description =
538 "Collect related nodes together in a common area. Useful for organization when the "
539 "re-usability of a node group is not required";
540 ntype->nclass = NODE_CLASS_LAYOUT;
541 ntype->enum_name_legacy = "FRAME";
542 ntype->initfunc = node_frame_init;
545 blender::bke::node_type_size(*ntype, 150, 100, 0);
546 ntype->flag |= NODE_BACKGROUND;
547
549}
550
552
553/* -------------------------------------------------------------------- */
556
558{
559 const bNode *node = b.node_or_null();
560 if (node == nullptr) {
561 return;
562 }
563
564 const blender::StringRefNull socket_idname(
565 static_cast<const NodeReroute *>(node->storage)->type_idname);
566 b.add_input<blender::nodes::decl::Custom>("Input")
567 .idname(socket_idname.c_str())
568 .structure_type(blender::nodes::StructureType::Dynamic);
569 b.add_output<blender::nodes::decl::Custom>("Output")
570 .idname(socket_idname.c_str())
571 .structure_type(blender::nodes::StructureType::Dynamic);
572}
573
574static void node_reroute_init(bNodeTree * /*ntree*/, bNode *node)
575{
577 STRNCPY(data->type_idname, "NodeSocketColor");
578 node->storage = data;
579}
580
582{
583 /* frame type is used for all tree types, needs dynamic allocation */
584 blender::bke::bNodeType *ntype = MEM_new<blender::bke::bNodeType>("frame node type");
585 ntype->free_self = [](blender::bke::bNodeType *type) { MEM_delete(type); };
586
587 blender::bke::node_type_base(*ntype, "NodeReroute", NODE_REROUTE);
588 ntype->ui_name = "Reroute";
589 ntype->ui_description =
590 "A single-socket organization tool that supports one input and multiple outputs";
591 ntype->enum_name_legacy = "REROUTE";
592 ntype->nclass = NODE_CLASS_LAYOUT;
595 node_type_storage(*ntype, "NodeReroute", node_free_standard_storage, node_copy_standard_storage);
596
598}
599
601 int node_i = std::numeric_limits<int>::max();
602 int socket_in_node_i = std::numeric_limits<int>::max();
603
606 : node_i(socket.owner_node().index()), socket_in_node_i(socket.index())
607 {
608 }
609
611 {
612 if (this->node_i == other.node_i) {
613 return this->socket_in_node_i < other.socket_in_node_i;
614 }
615 return this->node_i < other.node_i;
616 }
617};
618
620{
621 using namespace blender;
622 ntree->ensure_topology_cache();
623
624 const Span<bNode *> all_reroute_nodes = ntree->nodes_by_type("NodeReroute");
625
626 VectorSet<int> reroute_nodes;
627 for (const bNode *reroute : all_reroute_nodes) {
628 reroute_nodes.add(reroute->index());
629 }
630
631 /* Any reroute can be connected only to one source, or can be not connected at all.
632 * So reroute forms a trees. It is possible that there will be cycle, but such cycle
633 * can be only one in strongly connected set of reroutes. To propagate a types from
634 * some certain target to all the reroutes in such a tree we need to know all such
635 * a trees and all possible targets for each tree. */
636 DisjointSet reroutes_groups(reroute_nodes.size());
637
638 for (const bNode *src_reroute : all_reroute_nodes) {
639 const int src_reroute_i = reroute_nodes.index_of(src_reroute->index());
640 for (const bNodeSocket *dst_socket :
641 src_reroute->output_sockets().first()->directly_linked_sockets())
642 {
643 const bNode &dst_node = dst_socket->owner_node();
644 if (!dst_node.is_reroute()) {
645 continue;
646 }
647 const int dst_reroute_i = reroute_nodes.index_of(dst_node.index());
648 reroutes_groups.join(src_reroute_i, dst_reroute_i);
649 }
650 }
651
652 VectorSet<int> reroute_groups;
653 for (const int reroute_i : reroute_nodes.index_range()) {
654 const int root_reroute_i = reroutes_groups.find_root(reroute_i);
655 reroute_groups.add(root_reroute_i);
656 }
657
658 /* Any reroute can have only one source and many destination targets. Type propagation considers
659 * source as target with highest priority. */
660 Array<const bke::bNodeSocketType *> dst_type_by_reroute_group(reroute_groups.size(), nullptr);
661 Array<const bke::bNodeSocketType *> src_type_by_reroute_group(reroute_groups.size(), nullptr);
662
663 /* Reroute type priority based on the indices of target sockets in the node and the nodes in the
664 * tree. */
665 Array<RerouteTargetPriority> reroute_group_dst_type_priority(reroute_groups.size(),
667
668 for (const bNodeLink *link : ntree->all_links()) {
669 const bNode *src_node = link->fromnode;
670 const bNode *dst_node = link->tonode;
671
672 if (src_node->is_reroute() == dst_node->is_reroute()) {
673 continue;
674 }
675
676 if (!dst_node->is_reroute()) {
677 const int src_reroute_i = reroute_nodes.index_of(src_node->index());
678 const int src_reroute_root_i = reroutes_groups.find_root(src_reroute_i);
679 const int src_reroute_group_i = reroute_groups.index_of(src_reroute_root_i);
680
681 const RerouteTargetPriority type_priority(*link->tosock);
682 if (reroute_group_dst_type_priority[src_reroute_group_i] > type_priority) {
683 continue;
684 }
685
686 reroute_group_dst_type_priority[src_reroute_group_i] = type_priority;
687
688 const bNodeSocket *dst_socket = link->tosock;
689 /* There could be a function which will choose best from
690 * #dst_type_by_reroute_group and #dst_socket, but right now this match behavior as-is. */
691 dst_type_by_reroute_group[src_reroute_group_i] = dst_socket->typeinfo;
692 continue;
693 }
694
695 BLI_assert(!src_node->is_reroute());
696 const int dst_reroute_i = reroute_nodes.index_of(dst_node->index());
697 const int dst_reroute_root_i = reroutes_groups.find_root(dst_reroute_i);
698 const int dst_reroute_group_i = reroute_groups.index_of(dst_reroute_root_i);
699
700 const bNodeSocket *src_socket = link->fromsock;
701 /* There could be a function which will choose best from
702 * #src_type_by_reroute_group and #src_socket, but right now this match behavior as-is. */
703 src_type_by_reroute_group[dst_reroute_group_i] = src_socket->typeinfo;
704 }
705
706 const Span<bNode *> all_nodes = ntree->all_nodes();
707 for (const int reroute_i : reroute_nodes.index_range()) {
708 const int reroute_root_i = reroutes_groups.find_root(reroute_i);
709 const int reroute_group_i = reroute_groups.index_of(reroute_root_i);
710
711 const bke::bNodeSocketType *reroute_type = nullptr;
712 if (dst_type_by_reroute_group[reroute_group_i] != nullptr) {
713 reroute_type = dst_type_by_reroute_group[reroute_group_i];
714 }
715 if (src_type_by_reroute_group[reroute_group_i] != nullptr) {
716 reroute_type = src_type_by_reroute_group[reroute_group_i];
717 }
718
719 if (reroute_type == nullptr) {
720 continue;
721 }
722
723 const int reroute_index = reroute_nodes[reroute_i];
724 bNode &reroute_node = *all_nodes[reroute_index];
725 NodeReroute *storage = static_cast<NodeReroute *>(reroute_node.storage);
726 StringRef(reroute_type->idname).copy_utf8_truncated(storage->type_idname);
727 nodes::update_node_declaration_and_sockets(*ntree, reroute_node);
728 }
729}
730
732{
733 ntree.ensure_topology_cache();
734 Stack<const bNode *> nodes_to_check;
735 for (const bNodeSocket *socket : node.output_sockets()) {
736 for (const bNodeLink *link : socket->directly_linked_links()) {
737 nodes_to_check.push(link->tonode);
738 }
739 }
740 while (!nodes_to_check.is_empty()) {
741 const bNode *next_node = nodes_to_check.pop();
742 for (const bNodeSocket *socket : next_node->output_sockets()) {
743 for (const bNodeLink *link : socket->directly_linked_links()) {
744 if (link->tonode->typeinfo->nclass == NODE_CLASS_OUTPUT &&
745 link->tonode->flag & NODE_DO_OUTPUT)
746 {
747 return true;
748 }
749 nodes_to_check.push(link->tonode);
750 }
751 }
752 }
753
754 return false;
755}
756
758
759/* -------------------------------------------------------------------- */
762
764{
765 LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
766 if (sock->identifier == identifier) {
767 return sock;
768 }
769 }
770 return nullptr;
771}
772
773namespace blender::nodes {
774
776{
777 const bNodeTree *node_tree = b.tree_or_null();
778 if (node_tree == nullptr) {
779 return;
780 }
781 node_tree->tree_interface.foreach_item([&](const bNodeTreeInterfaceItem &item) {
782 switch (NodeTreeInterfaceItemType(item.item_type)) {
784 const bNodeTreeInterfaceSocket &socket =
786 if (socket.flag & NODE_INTERFACE_SOCKET_INPUT) {
787 /* Trying to use the evaluated structure type for the group output node introduces a
788 * "dependency cycle" between this and the structure type inferencing which uses node
789 * declarations. The compromise is to not use the proper structure type in the group
790 * input/output declarations and instead use a special case for the choice of socket
791 * shapes.*/
792 build_interface_socket_declaration(*node_tree, socket, std::nullopt, SOCK_OUT, b);
793 }
794 break;
795 }
797 break;
798 }
799 }
800 return true;
801 });
802 b.add_output<decl::Extend>("", "__extend__");
803}
804
806{
807 const bNodeTree *node_tree = b.tree_or_null();
808 if (node_tree == nullptr) {
809 return;
810 }
811 node_tree->tree_interface.foreach_item([&](const bNodeTreeInterfaceItem &item) {
812 switch (NodeTreeInterfaceItemType(item.item_type)) {
814 const bNodeTreeInterfaceSocket &socket =
816 if (socket.flag & NODE_INTERFACE_SOCKET_OUTPUT) {
817 build_interface_socket_declaration(*node_tree, socket, std::nullopt, SOCK_IN, b);
818 }
819 break;
820 }
822 break;
823 }
824 }
825 return true;
826 });
827 b.add_input<decl::Extend>("", "__extend__");
828}
829
830static bool group_input_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
831{
832 BLI_assert(link->tonode != node);
833 BLI_assert(link->tosock->in_out == SOCK_IN);
834 if (!StringRef(link->fromsock->identifier).startswith("__extend__")) {
835 return true;
836 }
837 if (StringRef(link->tosock->identifier).startswith("__extend__")) {
838 /* Don't connect to other "extend" sockets. */
839 return false;
840 }
842 *ntree, *link->tonode, *link->tosock);
843 if (!io_socket) {
844 return false;
845 }
847 link->fromsock = node_group_input_find_socket(node, io_socket->identifier);
848 return true;
849}
850
851static bool group_output_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
852{
853 BLI_assert(link->fromnode != node);
855 if (!StringRef(link->tosock->identifier).startswith("__extend__")) {
856 return true;
857 }
858 if (StringRef(link->fromsock->identifier).startswith("__extend__")) {
859 /* Don't connect to other "extend" sockets. */
860 return false;
861 }
863 *ntree, *link->fromnode, *link->fromsock);
864 if (!io_socket) {
865 return false;
866 }
868 link->tosock = node_group_output_find_socket(node, io_socket->identifier);
869 return true;
870}
871
872} // namespace blender::nodes
873
875{
876 /* used for all tree types, needs dynamic allocation */
877 blender::bke::bNodeType *ntype = MEM_new<blender::bke::bNodeType>("node type");
878 ntype->free_self = [](blender::bke::bNodeType *type) { MEM_delete(type); };
879
880 blender::bke::node_type_base(*ntype, "NodeGroupInput", NODE_GROUP_INPUT);
881 ntype->ui_name = "Group Input";
882 ntype->ui_description =
883 "Expose connected data from inside a node group as inputs to its interface";
884 ntype->enum_name_legacy = "GROUP_INPUT";
886 blender::bke::node_type_size(*ntype, 140, 80, 400);
890
892}
893
895{
896 LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
897 if (sock->identifier == identifier) {
898 return sock;
899 }
900 }
901 return nullptr;
902}
903
905{
906 const blender::Span<const bNode *> group_output_nodes = params.tree.nodes_by_type(
907 "NodeGroupOutput");
908 if (group_output_nodes.size() <= 1) {
909 return;
910 }
911 if (params.node.flag & NODE_DO_OUTPUT) {
912 return;
913 }
915 row.text = IFACE_("Unused Output");
916 row.icon = ICON_ERROR;
917 row.tooltip = TIP_("There are multiple group output nodes and this one is not active");
918 params.rows.append(std::move(row));
919}
920
922{
923 /* used for all tree types, needs dynamic allocation */
924 blender::bke::bNodeType *ntype = MEM_new<blender::bke::bNodeType>("node type");
925 ntype->free_self = [](blender::bke::bNodeType *type) { MEM_delete(type); };
926
927 blender::bke::node_type_base(*ntype, "NodeGroupOutput", NODE_GROUP_OUTPUT);
928 ntype->ui_name = "Group Output";
929 ntype->ui_description = "Output data from inside of a node group";
930 ntype->enum_name_legacy = "GROUP_OUTPUT";
932 blender::bke::node_type_size(*ntype, 140, 80, 400);
936
937 ntype->no_muting = true;
938
940}
941
#define NODE_CLASS_OUTPUT
Definition BKE_node.hh:434
#define NODE_REROUTE
Definition BKE_node.hh:798
#define NODE_CLASS_INTERFACE
Definition BKE_node.hh:445
#define NODE_CLASS_MATTE
Definition BKE_node.hh:440
#define NODE_CLASS_CONVERTER
Definition BKE_node.hh:439
#define NODE_CLASS_PATTERN
Definition BKE_node.hh:442
#define NODE_CLASS_GEOMETRY
Definition BKE_node.hh:447
#define NODE_GROUP_OUTPUT
Definition BKE_node.hh:800
#define NODE_CLASS_DISTORT
Definition BKE_node.hh:441
#define NODE_CLASS_OP_VECTOR
Definition BKE_node.hh:436
#define NODE_CLASS_LAYOUT
Definition BKE_node.hh:449
#define NODE_CLASS_OP_COLOR
Definition BKE_node.hh:435
#define NODE_CLASS_INPUT
Definition BKE_node.hh:433
#define NODE_CLASS_OP_FILTER
Definition BKE_node.hh:437
#define NODE_FRAME
Definition BKE_node.hh:797
#define NODE_CLASS_GROUP
Definition BKE_node.hh:438
#define NODE_GROUP_INPUT
Definition BKE_node.hh:799
#define NODE_CLASS_ATTRIBUTE
Definition BKE_node.hh:448
#define NODE_CLASS_TEXTURE
Definition BKE_node.hh:443
#define NODE_CLASS_SHADER
Definition BKE_node.hh:446
#define NODE_CLASS_SCRIPT
Definition BKE_node.hh:444
#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:688
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define RPT_(msgid)
#define TIP_(msgid)
#define IFACE_(msgid)
@ ID_TAG_MISSING
Definition DNA_ID.h:775
@ ID_NT
@ NODE_INTERFACE_PANEL_DEFAULT_CLOSED
@ NODE_INTERFACE_SOCKET_PANEL_TOGGLE
@ NODE_INTERFACE_SOCKET_MENU_EXPANDED
@ NODE_INTERFACE_SOCKET_COMPACT
@ NODE_INTERFACE_SOCKET_HIDE_VALUE
@ NTREE_GEOMETRY
eNodeSocketInOut
@ SOCK_OUT
@ SOCK_IN
@ NODE_DO_OUTPUT
@ NODE_BACKGROUND
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:220
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 ID_IS_LINKED(_id)
#define GS(a)
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:5573
void node_register_type(bNodeType &ntype)
Definition node.cc:2748
void node_type_base(bNodeType &ntype, std::string idname, std::optional< int16_t > legacy_type=std::nullopt)
Definition node.cc:5310
bNodeSocketType * node_socket_type_find(StringRef idname)
Definition node.cc:2794
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:5603
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 bool group_input_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
void update_node_declaration_and_sockets(bNodeTree &ntree, bNode &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 void group_output_declare(NodeDeclarationBuilder &b)
compositor::NodeOperation * get_group_input_compositor_operation(compositor::Context &context, DNode node)
static bool group_output_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
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_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
Definition DNA_ID.h:404
int tag
Definition DNA_ID.h:424
struct AssetMetaData * asset_data
Definition DNA_ID.h:413
char name[66]
Definition DNA_ID.h:415
char type_idname[64]
RerouteTargetPriority()=default
RerouteTargetPriority(const bNodeSocket &socket)
bool operator>(const RerouteTargetPriority other)
bNodeSocketTypeHandle * typeinfo
char identifier[64]
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:152
void(* interface_init_socket)(ID *id, const bNodeTreeInterfaceSocket *interface_socket, bNode *node, bNodeSocket *socket, StringRefNull data_path)
Definition BKE_node.hh:172
eNodeSocketDatatype type
Definition BKE_node.hh:187
Defines a node type.
Definition BKE_node.hh:226
std::string ui_description
Definition BKE_node.hh:232
NodeGetCompositorOperationFunction get_compositor_operation
Definition BKE_node.hh:336
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:277
NodeExtraInfoFunction get_extra_info
Definition BKE_node.hh:374
const char * enum_name_legacy
Definition BKE_node.hh:235
bool(* insert_link)(bNodeTree *ntree, bNode *node, bNodeLink *link)
Definition BKE_node.hh:321
NodeDeclareFunction declare
Definition BKE_node.hh:355
void(* free_self)(bNodeType *ntype)
Definition BKE_node.hh:323
i
Definition text_draw.cc:230