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 bNodeTree &group,
406 const Map<const bNodeTreeInterfaceSocket *, StructureType> &structure_type_by_socket,
407 const bNodeTreeInterfacePanel &io_parent_panel,
408 const bool is_root)
409{
410 bool layout_added = false;
411 auto add_layout_if_needed = [&]() {
412 if (is_root && !layout_added) {
413 b.add_default_layout();
414 layout_added = true;
415 }
416 };
417
418 for (const bNodeTreeInterfaceItem *item : io_parent_panel.items()) {
419 switch (NodeTreeInterfaceItemType(item->item_type)) {
421 const auto &io_socket = node_interface::get_item_as<bNodeTreeInterfaceSocket>(*item);
422 const eNodeSocketInOut in_out = (io_socket.flag & NODE_INTERFACE_SOCKET_INPUT) ? SOCK_IN :
423 SOCK_OUT;
424 if (in_out == SOCK_IN) {
425 add_layout_if_needed();
426 }
428 group, io_socket, structure_type_by_socket.lookup_try(&io_socket), in_out, b);
429 break;
430 }
432 add_layout_if_needed();
433 const auto &io_panel = node_interface::get_item_as<bNodeTreeInterfacePanel>(*item);
434 auto &panel_b = b.add_panel(StringRef(io_panel.name), io_panel.identifier)
435 .description(StringRef(io_panel.description))
436 .default_closed(io_panel.flag & NODE_INTERFACE_PANEL_DEFAULT_CLOSED);
438 panel_b, group, structure_type_by_socket, io_panel, false);
439 break;
440 }
441 }
442 }
443
444 add_layout_if_needed();
445}
446
448{
449 const bNode *node = b.node_or_null();
450 if (node == nullptr) {
451 return;
452 }
453 NodeDeclaration &r_declaration = b.declaration();
454 const bNodeTree *group = reinterpret_cast<const bNodeTree *>(node->id);
455 if (!group) {
456 return;
457 }
458 if (ID_IS_LINKED(&group->id) && (group->id.tag & ID_TAG_MISSING)) {
459 r_declaration.skip_updating_sockets = true;
460 return;
461 }
462 r_declaration.skip_updating_sockets = false;
463
464 /* Allow the node group interface to define the socket order. */
465 r_declaration.use_custom_socket_order = true;
466
467 group->ensure_interface_cache();
468
470 if (group->type == NTREE_GEOMETRY) {
471 structure_type_by_socket.reserve(group->interface_items().size());
472
473 const Span<const bNodeTreeInterfaceSocket *> inputs = group->interface_inputs();
474 const Span<StructureType> input_structure_types =
475 group->runtime->structure_type_interface->inputs;
476 for (const int i : inputs.index_range()) {
477 structure_type_by_socket.add(inputs[i], input_structure_types[i]);
478 }
479
480 const Span<const bNodeTreeInterfaceSocket *> outputs = group->interface_outputs();
481 const Span<StructureTypeInterface::OutputDependency> output_structure_types =
482 group->runtime->structure_type_interface->outputs;
483 for (const int i : outputs.index_range()) {
484 structure_type_by_socket.add(outputs[i], output_structure_types[i].type);
485 }
486 }
487
489 b, *group, structure_type_by_socket, group->tree_interface.root_panel, true);
490
491 if (group->type == NTREE_GEOMETRY) {
492 group->ensure_interface_cache();
493 const Span<const bNodeTreeInterfaceSocket *> inputs = group->interface_inputs();
494 const FieldInferencingInterface &field_interface =
495 *group->runtime->field_inferencing_interface;
496 for (const int i : inputs.index_range()) {
497 SocketDeclaration &decl = *r_declaration.inputs[i];
498 decl.input_field_type = field_interface.inputs[i];
499 }
500
501 for (const int i : r_declaration.outputs.index_range()) {
502 r_declaration.outputs[i]->output_field_dependency = field_interface.outputs[i];
503 }
504 }
505}
506
507} // namespace blender::nodes
508
510
511/* -------------------------------------------------------------------- */
514
515static void node_frame_init(bNodeTree * /*ntree*/, bNode *node)
516{
517 NodeFrame *data = MEM_callocN<NodeFrame>("frame node storage");
518 node->storage = data;
519
520 data->flag |= NODE_FRAME_SHRINK;
521
522 data->label_size = 20;
523}
524
526{
527 /* frame type is used for all tree types, needs dynamic allocation */
528 blender::bke::bNodeType *ntype = MEM_new<blender::bke::bNodeType>("frame node type");
529 ntype->free_self = [](blender::bke::bNodeType *type) { MEM_delete(type); };
530
531 blender::bke::node_type_base(*ntype, "NodeFrame", NODE_FRAME);
532 ntype->ui_name = "Frame";
533 ntype->ui_description =
534 "Collect related nodes together in a common area. Useful for organization when the "
535 "re-usability of a node group is not required";
536 ntype->nclass = NODE_CLASS_LAYOUT;
537 ntype->enum_name_legacy = "FRAME";
538 ntype->initfunc = node_frame_init;
541 blender::bke::node_type_size(*ntype, 150, 100, 0);
542 ntype->flag |= NODE_BACKGROUND;
543
545}
546
548
549/* -------------------------------------------------------------------- */
552
554{
555 const bNode *node = b.node_or_null();
556 if (node == nullptr) {
557 return;
558 }
559
560 const blender::StringRefNull socket_idname(
561 static_cast<const NodeReroute *>(node->storage)->type_idname);
562 b.add_input<blender::nodes::decl::Custom>("Input")
563 .idname(socket_idname.c_str())
564 .structure_type(blender::nodes::StructureType::Dynamic);
565 b.add_output<blender::nodes::decl::Custom>("Output")
566 .idname(socket_idname.c_str())
567 .structure_type(blender::nodes::StructureType::Dynamic);
568}
569
570static void node_reroute_init(bNodeTree * /*ntree*/, bNode *node)
571{
573 STRNCPY(data->type_idname, "NodeSocketColor");
574 node->storage = data;
575}
576
578{
579 /* frame type is used for all tree types, needs dynamic allocation */
580 blender::bke::bNodeType *ntype = MEM_new<blender::bke::bNodeType>("frame node type");
581 ntype->free_self = [](blender::bke::bNodeType *type) { MEM_delete(type); };
582
583 blender::bke::node_type_base(*ntype, "NodeReroute", NODE_REROUTE);
584 ntype->ui_name = "Reroute";
585 ntype->ui_description =
586 "A single-socket organization tool that supports one input and multiple outputs";
587 ntype->enum_name_legacy = "REROUTE";
588 ntype->nclass = NODE_CLASS_LAYOUT;
591 node_type_storage(*ntype, "NodeReroute", node_free_standard_storage, node_copy_standard_storage);
592
594}
595
597 int node_i = std::numeric_limits<int>::max();
598 int socket_in_node_i = std::numeric_limits<int>::max();
599
602 : node_i(socket.owner_node().index()), socket_in_node_i(socket.index())
603 {
604 }
605
607 {
608 if (this->node_i == other.node_i) {
609 return this->socket_in_node_i < other.socket_in_node_i;
610 }
611 return this->node_i < other.node_i;
612 }
613};
614
616{
617 using namespace blender;
618 ntree->ensure_topology_cache();
619
620 const Span<bNode *> all_reroute_nodes = ntree->nodes_by_type("NodeReroute");
621
622 VectorSet<int> reroute_nodes;
623 for (const bNode *reroute : all_reroute_nodes) {
624 reroute_nodes.add(reroute->index());
625 }
626
627 /* Any reroute can be connected only to one source, or can be not connected at all.
628 * So reroute forms a trees. It is possible that there will be cycle, but such cycle
629 * can be only one in strongly connected set of reroutes. To propagate a types from
630 * some certain target to all the reroutes in such a tree we need to know all such
631 * a trees and all possible targets for each tree. */
632 DisjointSet reroutes_groups(reroute_nodes.size());
633
634 for (const bNode *src_reroute : all_reroute_nodes) {
635 const int src_reroute_i = reroute_nodes.index_of(src_reroute->index());
636 for (const bNodeSocket *dst_socket :
637 src_reroute->output_sockets().first()->directly_linked_sockets())
638 {
639 const bNode &dst_node = dst_socket->owner_node();
640 if (!dst_node.is_reroute()) {
641 continue;
642 }
643 const int dst_reroute_i = reroute_nodes.index_of(dst_node.index());
644 reroutes_groups.join(src_reroute_i, dst_reroute_i);
645 }
646 }
647
648 VectorSet<int> reroute_groups;
649 for (const int reroute_i : reroute_nodes.index_range()) {
650 const int root_reroute_i = reroutes_groups.find_root(reroute_i);
651 reroute_groups.add(root_reroute_i);
652 }
653
654 /* Any reroute can have only one source and many destination targets. Type propagation considers
655 * source as target with highest priority. */
656 Array<const bke::bNodeSocketType *> dst_type_by_reroute_group(reroute_groups.size(), nullptr);
657 Array<const bke::bNodeSocketType *> src_type_by_reroute_group(reroute_groups.size(), nullptr);
658
659 /* Reroute type priority based on the indices of target sockets in the node and the nodes in the
660 * tree. */
661 Array<RerouteTargetPriority> reroute_group_dst_type_priority(reroute_groups.size(),
663
664 for (const bNodeLink *link : ntree->all_links()) {
665 const bNode *src_node = link->fromnode;
666 const bNode *dst_node = link->tonode;
667
668 if (src_node->is_reroute() == dst_node->is_reroute()) {
669 continue;
670 }
671
672 if (!dst_node->is_reroute()) {
673 const int src_reroute_i = reroute_nodes.index_of(src_node->index());
674 const int src_reroute_root_i = reroutes_groups.find_root(src_reroute_i);
675 const int src_reroute_group_i = reroute_groups.index_of(src_reroute_root_i);
676
677 const RerouteTargetPriority type_priority(*link->tosock);
678 if (reroute_group_dst_type_priority[src_reroute_group_i] > type_priority) {
679 continue;
680 }
681
682 reroute_group_dst_type_priority[src_reroute_group_i] = type_priority;
683
684 const bNodeSocket *dst_socket = link->tosock;
685 /* There could be a function which will choose best from
686 * #dst_type_by_reroute_group and #dst_socket, but right now this match behavior as-is. */
687 dst_type_by_reroute_group[src_reroute_group_i] = dst_socket->typeinfo;
688 continue;
689 }
690
691 BLI_assert(!src_node->is_reroute());
692 const int dst_reroute_i = reroute_nodes.index_of(dst_node->index());
693 const int dst_reroute_root_i = reroutes_groups.find_root(dst_reroute_i);
694 const int dst_reroute_group_i = reroute_groups.index_of(dst_reroute_root_i);
695
696 const bNodeSocket *src_socket = link->fromsock;
697 /* There could be a function which will choose best from
698 * #src_type_by_reroute_group and #src_socket, but right now this match behavior as-is. */
699 src_type_by_reroute_group[dst_reroute_group_i] = src_socket->typeinfo;
700 }
701
702 const Span<bNode *> all_nodes = ntree->all_nodes();
703 for (const int reroute_i : reroute_nodes.index_range()) {
704 const int reroute_root_i = reroutes_groups.find_root(reroute_i);
705 const int reroute_group_i = reroute_groups.index_of(reroute_root_i);
706
707 const bke::bNodeSocketType *reroute_type = nullptr;
708 if (dst_type_by_reroute_group[reroute_group_i] != nullptr) {
709 reroute_type = dst_type_by_reroute_group[reroute_group_i];
710 }
711 if (src_type_by_reroute_group[reroute_group_i] != nullptr) {
712 reroute_type = src_type_by_reroute_group[reroute_group_i];
713 }
714
715 if (reroute_type == nullptr) {
716 continue;
717 }
718
719 const int reroute_index = reroute_nodes[reroute_i];
720 bNode &reroute_node = *all_nodes[reroute_index];
721 NodeReroute *storage = static_cast<NodeReroute *>(reroute_node.storage);
722 StringRef(reroute_type->idname).copy_utf8_truncated(storage->type_idname);
723 nodes::update_node_declaration_and_sockets(*ntree, reroute_node);
724 }
725}
726
728{
729 ntree.ensure_topology_cache();
730 Stack<const bNode *> nodes_to_check;
731 for (const bNodeSocket *socket : node.output_sockets()) {
732 for (const bNodeLink *link : socket->directly_linked_links()) {
733 nodes_to_check.push(link->tonode);
734 }
735 }
736 while (!nodes_to_check.is_empty()) {
737 const bNode *next_node = nodes_to_check.pop();
738 for (const bNodeSocket *socket : next_node->output_sockets()) {
739 for (const bNodeLink *link : socket->directly_linked_links()) {
740 if (link->tonode->typeinfo->nclass == NODE_CLASS_OUTPUT &&
741 link->tonode->flag & NODE_DO_OUTPUT)
742 {
743 return true;
744 }
745 nodes_to_check.push(link->tonode);
746 }
747 }
748 }
749
750 return false;
751}
752
754
755/* -------------------------------------------------------------------- */
758
760{
761 LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
762 if (sock->identifier == identifier) {
763 return sock;
764 }
765 }
766 return nullptr;
767}
768
769namespace blender::nodes {
770
772{
773 const bNodeTree *node_tree = b.tree_or_null();
774 if (node_tree == nullptr) {
775 return;
776 }
777 node_tree->tree_interface.foreach_item([&](const bNodeTreeInterfaceItem &item) {
778 switch (NodeTreeInterfaceItemType(item.item_type)) {
780 const bNodeTreeInterfaceSocket &socket =
782 if (socket.flag & NODE_INTERFACE_SOCKET_INPUT) {
783 /* Trying to use the evaluated structure type for the group output node introduces a
784 * "dependency cycle" between this and the structure type inferencing which uses node
785 * declarations. The compromise is to not use the proper structure type in the group
786 * input/output declarations and instead use a special case for the choice of socket
787 * shapes.*/
788 build_interface_socket_declaration(*node_tree, socket, std::nullopt, SOCK_OUT, b);
789 }
790 break;
791 }
793 break;
794 }
795 }
796 return true;
797 });
798 b.add_output<decl::Extend>("", "__extend__");
799}
800
802{
803 const bNodeTree *node_tree = b.tree_or_null();
804 if (node_tree == nullptr) {
805 return;
806 }
807 node_tree->tree_interface.foreach_item([&](const bNodeTreeInterfaceItem &item) {
808 switch (NodeTreeInterfaceItemType(item.item_type)) {
810 const bNodeTreeInterfaceSocket &socket =
812 if (socket.flag & NODE_INTERFACE_SOCKET_OUTPUT) {
813 build_interface_socket_declaration(*node_tree, socket, std::nullopt, SOCK_IN, b);
814 }
815 break;
816 }
818 break;
819 }
820 }
821 return true;
822 });
823 b.add_input<decl::Extend>("", "__extend__");
824}
825
826static bool group_input_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
827{
828 BLI_assert(link->tonode != node);
829 BLI_assert(link->tosock->in_out == SOCK_IN);
830 if (!StringRef(link->fromsock->identifier).startswith("__extend__")) {
831 return true;
832 }
833 if (StringRef(link->tosock->identifier).startswith("__extend__")) {
834 /* Don't connect to other "extend" sockets. */
835 return false;
836 }
838 *ntree, *link->tonode, *link->tosock);
839 if (!io_socket) {
840 return false;
841 }
843 link->fromsock = node_group_input_find_socket(node, io_socket->identifier);
844 return true;
845}
846
847static bool group_output_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
848{
849 BLI_assert(link->fromnode != node);
851 if (!StringRef(link->tosock->identifier).startswith("__extend__")) {
852 return true;
853 }
854 if (StringRef(link->fromsock->identifier).startswith("__extend__")) {
855 /* Don't connect to other "extend" sockets. */
856 return false;
857 }
859 *ntree, *link->fromnode, *link->fromsock);
860 if (!io_socket) {
861 return false;
862 }
864 link->tosock = node_group_output_find_socket(node, io_socket->identifier);
865 return true;
866}
867
868} // namespace blender::nodes
869
871{
872 /* used for all tree types, needs dynamic allocation */
873 blender::bke::bNodeType *ntype = MEM_new<blender::bke::bNodeType>("node type");
874 ntype->free_self = [](blender::bke::bNodeType *type) { MEM_delete(type); };
875
876 blender::bke::node_type_base(*ntype, "NodeGroupInput", NODE_GROUP_INPUT);
877 ntype->ui_name = "Group Input";
878 ntype->ui_description =
879 "Expose connected data from inside a node group as inputs to its interface";
880 ntype->enum_name_legacy = "GROUP_INPUT";
882 blender::bke::node_type_size(*ntype, 140, 80, 400);
886
888}
889
891{
892 LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
893 if (sock->identifier == identifier) {
894 return sock;
895 }
896 }
897 return nullptr;
898}
899
901{
902 const blender::Span<const bNode *> group_output_nodes = params.tree.nodes_by_type(
903 "NodeGroupOutput");
904 if (group_output_nodes.size() <= 1) {
905 return;
906 }
907 if (params.node.flag & NODE_DO_OUTPUT) {
908 return;
909 }
911 row.text = IFACE_("Unused Output");
912 row.icon = ICON_ERROR;
913 row.tooltip = TIP_("There are multiple group output nodes and this one is not active");
914 params.rows.append(std::move(row));
915}
916
918{
919 /* used for all tree types, needs dynamic allocation */
920 blender::bke::bNodeType *ntype = MEM_new<blender::bke::bNodeType>("node type");
921 ntype->free_self = [](blender::bke::bNodeType *type) { MEM_delete(type); };
922
923 blender::bke::node_type_base(*ntype, "NodeGroupOutput", NODE_GROUP_OUTPUT);
924 ntype->ui_name = "Group Output";
925 ntype->ui_description = "Output data from inside of a node group";
926 ntype->enum_name_legacy = "GROUP_OUTPUT";
928 blender::bke::node_type_size(*ntype, 140, 80, 400);
932
933 ntype->no_muting = true;
934
936}
937
#define NODE_CLASS_OUTPUT
Definition BKE_node.hh:434
#define NODE_REROUTE
Definition BKE_node.hh:797
#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:799
#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:796
#define NODE_CLASS_GROUP
Definition BKE_node.hh:438
#define NODE_GROUP_INPUT
Definition BKE_node.hh:798
#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
@ NODE_FRAME_SHRINK
@ NTREE_GEOMETRY
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_DO_OUTPUT
@ NODE_BACKGROUND
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:5571
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:5308
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:5601
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_declare_panel_recursive(DeclarationListBuilder &b, const bNodeTree &group, const Map< const bNodeTreeInterfaceSocket *, StructureType > &structure_type_by_socket, const bNodeTreeInterfacePanel &io_parent_panel, const bool is_root)
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)
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