Blender V4.5
node_tree_update.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <fmt/format.h>
6
7#include "BLI_listbase.h"
8#include "BLI_map.hh"
10#include "BLI_noise.hh"
11#include "BLI_rand.hh"
12#include "BLI_set.hh"
13#include "BLI_stack.hh"
14#include "BLI_string.h"
16#include "BLI_vector_set.hh"
17
18#include "DNA_anim_types.h"
19#include "DNA_modifier_types.h"
20#include "DNA_node_types.h"
21
22#include "BKE_anim_data.hh"
23#include "BKE_image.hh"
24#include "BKE_lib_id.hh"
25#include "BKE_main.hh"
26#include "BKE_node.hh"
27#include "BKE_node_enum.hh"
29#include "BKE_node_runtime.hh"
32
33#include "MOD_nodes.hh"
34
35#include "NOD_geo_closure.hh"
40#include "NOD_socket.hh"
41#include "NOD_texture.h"
42
44
45#include "BLT_translation.hh"
46
47using namespace blender::nodes;
48
67
69{
70 ntree->runtime->changed_flag |= flag;
71 ntree->runtime->topology_cache_mutex.tag_dirty();
72 ntree->runtime->tree_zones_cache_mutex.tag_dirty();
73 ntree->runtime->inferenced_input_socket_usage_mutex.tag_dirty();
74}
75
76static void add_node_tag(bNodeTree *ntree, bNode *node, const eNodeTreeChangedFlag flag)
77{
78 add_tree_tag(ntree, flag);
79 node->runtime->changed_flag |= flag;
80}
81
83{
84 add_tree_tag(ntree, flag);
85 socket->runtime->changed_flag |= flag;
86}
87
88namespace blender::bke {
89
97{
98 switch (to->type) {
99 case SOCK_RGBA:
100 switch (from->type) {
101 case SOCK_RGBA:
102 return 4;
103 case SOCK_FLOAT:
104 return 3;
105 case SOCK_INT:
106 return 2;
107 case SOCK_BOOLEAN:
108 return 1;
109 default:
110 return -1;
111 }
112 case SOCK_VECTOR:
113 switch (from->type) {
114 case SOCK_VECTOR:
115 return 4;
116 case SOCK_FLOAT:
117 return 3;
118 case SOCK_INT:
119 return 2;
120 case SOCK_BOOLEAN:
121 return 1;
122 default:
123 return -1;
124 }
125 case SOCK_FLOAT:
126 switch (from->type) {
127 case SOCK_FLOAT:
128 return 5;
129 case SOCK_INT:
130 return 4;
131 case SOCK_BOOLEAN:
132 return 3;
133 case SOCK_RGBA:
134 return 2;
135 case SOCK_VECTOR:
136 return 1;
137 default:
138 return -1;
139 }
140 case SOCK_INT:
141 switch (from->type) {
142 case SOCK_INT:
143 return 5;
144 case SOCK_FLOAT:
145 return 4;
146 case SOCK_BOOLEAN:
147 return 3;
148 case SOCK_RGBA:
149 return 2;
150 case SOCK_VECTOR:
151 return 1;
152 default:
153 return -1;
154 }
155 case SOCK_BOOLEAN:
156 switch (from->type) {
157 case SOCK_BOOLEAN:
158 return 5;
159 case SOCK_INT:
160 return 4;
161 case SOCK_FLOAT:
162 return 3;
163 case SOCK_RGBA:
164 return 2;
165 case SOCK_VECTOR:
166 return 1;
167 default:
168 return -1;
169 }
170 case SOCK_ROTATION:
171 switch (from->type) {
172 case SOCK_ROTATION:
173 return 3;
174 case SOCK_VECTOR:
175 return 2;
176 case SOCK_FLOAT:
177 return 1;
178 default:
179 return -1;
180 }
181 default:
182 break;
183 }
184
185 /* The rest of the socket types only allow an internal link if both the input and output socket
186 * have the same type. If the sockets are custom, we check the idname instead. */
187 if (to->type == from->type && (to->type != SOCK_CUSTOM || to->idname == from->idname)) {
188 return 1;
189 }
190
191 return -1;
192}
193
194/* Check both the tree's own tags and the interface tags. */
195static bool is_tree_changed(const bNodeTree &tree)
196{
197 return tree.runtime->changed_flag != NTREE_CHANGED_NOTHING ||
198 tree.tree_interface.requires_dependent_tree_updates();
199}
200
201using TreeNodePair = std::pair<bNodeTree *, bNode *>;
202using ObjectModifierPair = std::pair<Object *, ModifierData *>;
203using NodeSocketPair = std::pair<bNode *, bNodeSocket *>;
204
210 private:
211 Main *bmain_;
212 std::optional<Vector<bNodeTree *>> all_trees_;
213 std::optional<MultiValueMap<bNodeTree *, TreeNodePair>> group_node_users_;
214 std::optional<MultiValueMap<bNodeTree *, ObjectModifierPair>> modifiers_users_;
215
216 public:
217 NodeTreeRelations(Main *bmain) : bmain_(bmain) {}
218
220 {
221 if (all_trees_.has_value()) {
222 return;
223 }
224 all_trees_.emplace();
225 if (bmain_ == nullptr) {
226 return;
227 }
228
229 FOREACH_NODETREE_BEGIN (bmain_, ntree, id) {
230 all_trees_->append(ntree);
231 }
233 }
234
236 {
237 if (group_node_users_.has_value()) {
238 return;
239 }
240 group_node_users_.emplace();
241 if (bmain_ == nullptr) {
242 return;
243 }
244
245 this->ensure_all_trees();
246
247 for (bNodeTree *ntree : *all_trees_) {
248 for (bNode *node : ntree->all_nodes()) {
249 if (node->id == nullptr) {
250 continue;
251 }
252 ID *id = node->id;
253 if (GS(id->name) == ID_NT) {
254 bNodeTree *group = (bNodeTree *)id;
255 group_node_users_->add(group, {ntree, node});
256 }
257 }
258 }
259 }
260
262 {
263 if (modifiers_users_.has_value()) {
264 return;
265 }
266 modifiers_users_.emplace();
267 if (bmain_ == nullptr) {
268 return;
269 }
270
271 LISTBASE_FOREACH (Object *, object, &bmain_->objects) {
272 LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
273 if (md->type == eModifierType_Nodes) {
275 if (nmd->node_group != nullptr) {
276 modifiers_users_->add(nmd->node_group, {object, md});
277 }
278 }
279 }
280 }
281 }
282
284 {
285 BLI_assert(modifiers_users_.has_value());
286 return modifiers_users_->lookup(ntree);
287 }
288
290 {
291 BLI_assert(group_node_users_.has_value());
292 return group_node_users_->lookup(ntree);
293 }
294};
295
297 bool interface_changed = false;
298 bool output_changed = false;
299};
300
302 private:
303 Main *bmain_;
304 const NodeTreeUpdateExtraParams &params_;
305 Map<bNodeTree *, TreeUpdateResult> update_result_by_tree_;
306 NodeTreeRelations relations_;
307 bool needs_relations_update_ = false;
308
309 public:
311 : bmain_(bmain), params_(params), relations_(bmain)
312 {
313 }
314
315 void update()
316 {
317 Vector<bNodeTree *> changed_ntrees;
318 FOREACH_NODETREE_BEGIN (bmain_, ntree, id) {
319 if (is_tree_changed(*ntree)) {
320 changed_ntrees.append(ntree);
321 }
322 }
324 this->update_rooted(changed_ntrees);
325 }
326
328 {
329 if (root_ntrees.is_empty()) {
330 return;
331 }
332
333 bool is_single_tree_update = false;
334
335 if (root_ntrees.size() == 1) {
336 bNodeTree *ntree = root_ntrees[0];
337 if (!is_tree_changed(*ntree)) {
338 return;
339 }
340 const TreeUpdateResult result = this->update_tree(*ntree);
341 update_result_by_tree_.add_new(ntree, result);
342 if (!result.interface_changed && !result.output_changed) {
343 is_single_tree_update = true;
344 }
345 }
346
347 if (!is_single_tree_update) {
348 Vector<bNodeTree *> ntrees_in_order = this->get_tree_update_order(root_ntrees);
349 for (bNodeTree *ntree : ntrees_in_order) {
350 if (!is_tree_changed(*ntree)) {
351 continue;
352 }
353 if (!update_result_by_tree_.contains(ntree)) {
354 const TreeUpdateResult result = this->update_tree(*ntree);
355 update_result_by_tree_.add_new(ntree, result);
356 }
357 const TreeUpdateResult result = update_result_by_tree_.lookup(ntree);
358 Span<TreeNodePair> dependent_trees = relations_.get_group_node_users(ntree);
359 if (result.output_changed) {
360 for (const TreeNodePair &pair : dependent_trees) {
361 add_node_tag(pair.first, pair.second, NTREE_CHANGED_NODE_OUTPUT);
362 }
363 }
364 if (result.interface_changed) {
365 for (const TreeNodePair &pair : dependent_trees) {
366 add_node_tag(pair.first, pair.second, NTREE_CHANGED_NODE_PROPERTY);
367 }
368 }
369 }
370 }
371
372 for (const auto item : update_result_by_tree_.items()) {
373 bNodeTree *ntree = item.key;
374 const TreeUpdateResult &result = item.value;
375
376 this->reset_changed_flags(*ntree);
377
378 if (result.interface_changed) {
379 if (ntree->type == NTREE_GEOMETRY) {
380 relations_.ensure_modifier_users();
381 for (const ObjectModifierPair &pair : relations_.get_modifier_users(ntree)) {
382 Object *object = pair.first;
383 ModifierData *md = pair.second;
384
385 if (md->type == eModifierType_Nodes) {
387 }
388 }
389 }
390 }
391
392 if (result.output_changed) {
393 ntree->runtime->geometry_nodes_lazy_function_graph_info.reset();
394 }
395
396 ID *owner_id = BKE_id_owner_get(&ntree->id);
397 ID &owner_or_self_id = owner_id ? *owner_id : ntree->id;
398 if (params_.tree_changed_fn) {
399 params_.tree_changed_fn(*ntree, owner_or_self_id);
400 }
401 if (params_.tree_output_changed_fn && result.output_changed) {
402 params_.tree_output_changed_fn(*ntree, owner_or_self_id);
403 }
404 }
405
406 if (needs_relations_update_) {
407 if (bmain_) {
409 }
410 }
411 }
412
413 private:
414 enum class ToposortMark {
415 None,
416 Temporary,
417 Permanent,
418 };
419
420 using ToposortMarkMap = Map<bNodeTree *, ToposortMark>;
421
426 Vector<bNodeTree *> get_tree_update_order(Span<bNodeTree *> root_ntrees)
427 {
428 relations_.ensure_group_node_users();
429
430 Set<bNodeTree *> trees_to_update = get_trees_to_update(root_ntrees);
431
432 Vector<bNodeTree *> sorted_ntrees;
433
434 ToposortMarkMap marks;
435 for (bNodeTree *ntree : trees_to_update) {
436 marks.add_new(ntree, ToposortMark::None);
437 }
438 for (bNodeTree *ntree : trees_to_update) {
439 if (marks.lookup(ntree) == ToposortMark::None) {
440 const bool cycle_detected = !this->get_tree_update_order__visit_recursive(
441 ntree, marks, sorted_ntrees);
442 /* This should be prevented by higher level operators. */
443 BLI_assert(!cycle_detected);
444 UNUSED_VARS_NDEBUG(cycle_detected);
445 }
446 }
447
448 std::reverse(sorted_ntrees.begin(), sorted_ntrees.end());
449
450 return sorted_ntrees;
451 }
452
453 bool get_tree_update_order__visit_recursive(bNodeTree *ntree,
454 ToposortMarkMap &marks,
455 Vector<bNodeTree *> &sorted_ntrees)
456 {
457 ToposortMark &mark = marks.lookup(ntree);
458 if (mark == ToposortMark::Permanent) {
459 return true;
460 }
461 if (mark == ToposortMark::Temporary) {
462 /* There is a dependency cycle. */
463 return false;
464 }
465
466 mark = ToposortMark::Temporary;
467
468 for (const TreeNodePair &pair : relations_.get_group_node_users(ntree)) {
469 this->get_tree_update_order__visit_recursive(pair.first, marks, sorted_ntrees);
470 }
471 sorted_ntrees.append(ntree);
472
473 mark = ToposortMark::Permanent;
474 return true;
475 }
476
477 Set<bNodeTree *> get_trees_to_update(Span<bNodeTree *> root_ntrees)
478 {
479 relations_.ensure_group_node_users();
480
481 Set<bNodeTree *> reachable_trees;
482 VectorSet<bNodeTree *> trees_to_check = root_ntrees;
483
484 while (!trees_to_check.is_empty()) {
485 bNodeTree *ntree = trees_to_check.pop();
486 if (reachable_trees.add(ntree)) {
487 for (const TreeNodePair &pair : relations_.get_group_node_users(ntree)) {
488 trees_to_check.add(pair.first);
489 }
490 }
491 }
492
493 return reachable_trees;
494 }
495
496 TreeUpdateResult update_tree(bNodeTree &ntree)
497 {
498 TreeUpdateResult result;
499
500 ntree.runtime->link_errors.clear();
501 ntree.runtime->invalid_zone_output_node_ids.clear();
502
503 if (this->update_panel_toggle_names(ntree)) {
504 result.interface_changed = true;
505 }
506
507 this->update_socket_link_and_use(ntree);
508 this->update_individual_nodes(ntree);
509 this->update_internal_links(ntree);
510 this->update_generic_callback(ntree);
511 this->remove_unused_previews_when_necessary(ntree);
512 this->make_node_previews_dirty(ntree);
513
514 this->propagate_runtime_flags(ntree);
515 if (ntree.type == NTREE_GEOMETRY) {
516 if (this->propagate_enum_definitions(ntree)) {
517 result.interface_changed = true;
518 }
520 result.interface_changed = true;
521 }
523 result.interface_changed = true;
524 }
525 this->update_from_field_inference(ntree);
527 result.interface_changed = true;
528 }
530 result.interface_changed = true;
531 }
532 this->update_socket_shapes(ntree);
533 this->update_eval_dependencies(ntree);
534 }
535
536 result.output_changed = this->check_if_output_changed(ntree);
537
538 this->update_socket_link_and_use(ntree);
539 this->update_link_validation(ntree);
540
541 if (this->update_nested_node_refs(ntree)) {
542 result.interface_changed = true;
543 }
544
545 if (ntree.type == NTREE_TEXTURE) {
546 ntreeTexCheckCyclics(&ntree);
547 }
548
549 if (ntree.tree_interface.requires_dependent_tree_updates()) {
550 result.interface_changed = true;
551 }
552
553#ifndef NDEBUG
554 /* Check the uniqueness of node identifiers. */
555 Set<int32_t> node_identifiers;
556 const Span<const bNode *> nodes = ntree.all_nodes();
557 for (const int i : nodes.index_range()) {
558 const bNode &node = *nodes[i];
559 BLI_assert(node.identifier > 0);
560 node_identifiers.add_new(node.identifier);
561 BLI_assert(node.runtime->index_in_tree == i);
562 }
563#endif
564
565 return result;
566 }
567
568 void update_socket_link_and_use(bNodeTree &tree)
569 {
570 tree.ensure_topology_cache();
571 for (bNodeSocket *socket : tree.all_input_sockets()) {
572 if (socket->directly_linked_links().is_empty()) {
573 socket->link = nullptr;
574 }
575 else {
576 socket->link = socket->directly_linked_links()[0];
577 }
578 }
579
580 this->update_socket_used_tags(tree);
581 }
582
583 void update_socket_used_tags(bNodeTree &tree)
584 {
585 tree.ensure_topology_cache();
586 for (bNodeSocket *socket : tree.all_sockets()) {
587 const bool socket_is_linked = !socket->directly_linked_links().is_empty();
588 SET_FLAG_FROM_TEST(socket->flag, socket_is_linked, SOCK_IS_LINKED);
589 }
590 }
591
592 void update_individual_nodes(bNodeTree &ntree)
593 {
594 for (bNode *node : ntree.all_nodes()) {
595 bke::node_declaration_ensure(ntree, *node);
596 if (this->should_update_individual_node(ntree, *node)) {
597 bke::bNodeType &ntype = *node->typeinfo;
598 if (ntype.declare) {
599 /* Should have been created when the node was registered. */
600 BLI_assert(ntype.static_declaration != nullptr);
603 }
604 }
605 else if (node->is_undefined()) {
606 /* If a node has become undefined (it generally was unregistered from Python), it does
607 * not have a declaration anymore. */
608 delete node->runtime->declaration;
609 node->runtime->declaration = nullptr;
610 LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
611 socket->runtime->declaration = nullptr;
612 }
613 LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
614 socket->runtime->declaration = nullptr;
615 }
616 }
617 if (ntype.updatefunc) {
618 ntype.updatefunc(&ntree, node);
619 }
620 }
621 }
622 }
623
624 bool should_update_individual_node(const bNodeTree &ntree, const bNode &node)
625 {
626 if (ntree.runtime->changed_flag & NTREE_CHANGED_ANY) {
627 return true;
628 }
629 if (node.runtime->changed_flag & NTREE_CHANGED_NODE_PROPERTY) {
630 return true;
631 }
632 if (ntree.runtime->changed_flag & NTREE_CHANGED_LINK) {
633 /* Currently we have no way to tell if a node needs to be updated when a link changed. */
634 return true;
635 }
636 if (ntree.tree_interface.requires_dependent_tree_updates()) {
637 if (node.is_group_input() || node.is_group_output()) {
638 return true;
639 }
640 }
641 /* Check paired simulation zone nodes. */
642 if (all_zone_input_node_types().contains(node.type_legacy)) {
643 const bNodeZoneType &zone_type = *zone_type_by_node_type(node.type_legacy);
644 if (const bNode *output_node = zone_type.get_corresponding_output(ntree, node)) {
645 if (output_node->runtime->changed_flag & NTREE_CHANGED_NODE_PROPERTY) {
646 return true;
647 }
648 }
649 }
650 return false;
651 }
652
653 struct InternalLink {
654 bNodeSocket *from;
655 bNodeSocket *to;
656 int multi_input_sort_id = 0;
657
658 BLI_STRUCT_EQUALITY_OPERATORS_3(InternalLink, from, to, multi_input_sort_id);
659 };
660
661 const bNodeLink *first_non_dangling_link(const bNodeTree & /*ntree*/,
662 const Span<const bNodeLink *> links) const
663 {
664 for (const bNodeLink *link : links) {
665 if (!link->fromnode->is_dangling_reroute()) {
666 return link;
667 }
668 }
669 return nullptr;
670 }
671
672 void update_internal_links(bNodeTree &ntree)
673 {
674 bke::node_tree_runtime::AllowUsingOutdatedInfo allow_outdated_info{ntree};
675 ntree.ensure_topology_cache();
676 for (bNode *node : ntree.all_nodes()) {
677 if (!this->should_update_individual_node(ntree, *node)) {
678 continue;
679 }
680 /* Find all expected internal links. */
681 Vector<InternalLink> expected_internal_links;
682 for (const bNodeSocket *output_socket : node->output_sockets()) {
683 if (!output_socket->is_available()) {
684 continue;
685 }
686 if (output_socket->flag & SOCK_NO_INTERNAL_LINK) {
687 continue;
688 }
689 const bNodeSocket *input_socket = this->find_internally_linked_input(ntree, output_socket);
690 if (input_socket == nullptr) {
691 continue;
692 }
693
694 const Span<const bNodeLink *> connected_links = input_socket->directly_linked_links();
695 const bNodeLink *connected_link = first_non_dangling_link(ntree, connected_links);
696
697 const int index = connected_link ? connected_link->multi_input_sort_id :
698 std::max<int>(0, connected_links.size() - 1);
699 expected_internal_links.append(InternalLink{const_cast<bNodeSocket *>(input_socket),
700 const_cast<bNodeSocket *>(output_socket),
701 index});
702 }
703
704 /* Rebuilt internal links if they have changed. */
705 if (node->runtime->internal_links.size() != expected_internal_links.size()) {
706 this->update_internal_links_in_node(ntree, *node, expected_internal_links);
707 continue;
708 }
709
710 const bool all_expected_internal_links_exist = std::all_of(
711 node->runtime->internal_links.begin(),
712 node->runtime->internal_links.end(),
713 [&](const bNodeLink &link) {
714 const InternalLink internal_link{link.fromsock, link.tosock, link.multi_input_sort_id};
715 return expected_internal_links.as_span().contains(internal_link);
716 });
717
718 if (all_expected_internal_links_exist) {
719 continue;
720 }
721
722 this->update_internal_links_in_node(ntree, *node, expected_internal_links);
723 }
724 }
725
726 const bNodeSocket *find_internally_linked_input(const bNodeTree &ntree,
727 const bNodeSocket *output_socket)
728 {
729 const bNode &node = output_socket->owner_node();
730 if (node.typeinfo->internally_linked_input) {
731 return node.typeinfo->internally_linked_input(ntree, node, *output_socket);
732 }
733
734 const bNodeSocket *selected_socket = nullptr;
735 int selected_priority = -1;
736 bool selected_is_linked = false;
737 for (const bNodeSocket *input_socket : node.input_sockets()) {
738 if (!input_socket->is_available()) {
739 continue;
740 }
741 if (input_socket->flag & SOCK_NO_INTERNAL_LINK) {
742 continue;
743 }
744 const int priority = get_internal_link_type_priority(input_socket->typeinfo,
745 output_socket->typeinfo);
746 if (priority < 0) {
747 continue;
748 }
749 const bool is_linked = input_socket->is_directly_linked();
750 const bool is_preferred = priority > selected_priority || (is_linked && !selected_is_linked);
751 if (!is_preferred) {
752 continue;
753 }
754 selected_socket = input_socket;
755 selected_priority = priority;
756 selected_is_linked = is_linked;
757 }
758 return selected_socket;
759 }
760
761 void update_internal_links_in_node(bNodeTree &ntree,
762 bNode &node,
763 Span<InternalLink> internal_links)
764 {
765 node.runtime->internal_links.clear();
766 node.runtime->internal_links.reserve(internal_links.size());
767 for (const InternalLink &internal_link : internal_links) {
768 bNodeLink link{};
769 link.fromnode = &node;
770 link.fromsock = internal_link.from;
771 link.tonode = &node;
772 link.tosock = internal_link.to;
773 link.multi_input_sort_id = internal_link.multi_input_sort_id;
774 link.flag |= NODE_LINK_VALID;
775 node.runtime->internal_links.append(link);
776 }
778 }
779
780 void update_generic_callback(bNodeTree &ntree)
781 {
782 if (ntree.typeinfo->update == nullptr) {
783 return;
784 }
785 ntree.typeinfo->update(&ntree);
786 }
787
788 void remove_unused_previews_when_necessary(bNodeTree &ntree)
789 {
790 /* Don't trigger preview removal when only those flags are set. */
793 if ((ntree.runtime->changed_flag & allowed_flags) == ntree.runtime->changed_flag) {
794 return;
795 }
797 }
798
799 void make_node_previews_dirty(bNodeTree &ntree)
800 {
801 ntree.runtime->previews_refresh_state++;
802 for (bNode *node : ntree.all_nodes()) {
803 if (!node->is_group()) {
804 continue;
805 }
806 if (bNodeTree *nested_tree = reinterpret_cast<bNodeTree *>(node->id)) {
807 this->make_node_previews_dirty(*nested_tree);
808 }
809 }
810 }
811
812 void propagate_runtime_flags(const bNodeTree &ntree)
813 {
814 ntree.ensure_topology_cache();
815
816 ntree.runtime->runtime_flag = 0;
817
818 for (const bNode *group_node : ntree.group_nodes()) {
819 const bNodeTree *group = reinterpret_cast<bNodeTree *>(group_node->id);
820 if (group != nullptr) {
821 ntree.runtime->runtime_flag |= group->runtime->runtime_flag;
822 }
823 }
824
825 if (ntree.type == NTREE_SHADER) {
826 /* Check if the tree itself has an animated image. */
827 for (const StringRefNull idname : {"ShaderNodeTexImage", "ShaderNodeTexEnvironment"}) {
828 for (const bNode *node : ntree.nodes_by_type(idname)) {
829 Image *image = reinterpret_cast<Image *>(node->id);
830 if (image != nullptr && BKE_image_is_animated(image)) {
831 ntree.runtime->runtime_flag |= NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION;
832 break;
833 }
834 }
835 }
836 /* Check if the tree has a material output. */
837 for (const StringRefNull idname : {"ShaderNodeOutputMaterial",
838 "ShaderNodeOutputLight",
839 "ShaderNodeOutputWorld",
840 "ShaderNodeOutputAOV"})
841 {
842 const Span<const bNode *> nodes = ntree.nodes_by_type(idname);
843 if (!nodes.is_empty()) {
844 ntree.runtime->runtime_flag |= NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT;
845 break;
846 }
847 }
848 }
849 if (ntree.type == NTREE_GEOMETRY) {
850 /* Check if there is a simulation zone. */
851 if (!ntree.nodes_by_type("GeometryNodeSimulationOutput").is_empty()) {
852 ntree.runtime->runtime_flag |= NTREE_RUNTIME_FLAG_HAS_SIMULATION_ZONE;
853 }
854 }
855 }
856
857 void update_from_field_inference(bNodeTree &ntree)
858 {
859 /* Automatically tag a bake item as attribute when the input is a field. The flag should not be
860 * removed automatically even when the field input is disconnected because the baked data may
861 * still contain attribute data instead of a single value. */
862 const Span<bke::FieldSocketState> field_states = ntree.runtime->field_states;
863 for (bNode *node : ntree.nodes_by_type("GeometryNodeBake")) {
864 NodeGeometryBake &storage = *static_cast<NodeGeometryBake *>(node->storage);
865 for (const int i : IndexRange(storage.items_num)) {
866 const bNodeSocket &socket = node->input_socket(i);
867 NodeGeometryBakeItem &item = storage.items[i];
868 if (field_states[socket.index_in_tree()] == FieldSocketState::IsField) {
870 }
871 }
872 }
873 }
874
875 static bool socket_type_always_single(const SocketDeclaration &decl)
876 {
877 switch (decl.socket_type) {
878 case SOCK_OBJECT:
879 case SOCK_IMAGE:
880 case SOCK_GEOMETRY:
881 case SOCK_COLLECTION:
882 case SOCK_TEXTURE:
883 case SOCK_MATERIAL:
884 return true;
885 default:
886 return false;
887 }
888 }
889
890 static int get_input_socket_shape(const SocketDeclaration &decl,
891 const StructureType structure_type)
892 {
893 if (decl.identifier == "__extend__") {
895 }
896 if (socket_type_always_single(decl)) {
898 }
899 switch (structure_type) {
900 case StructureType::Single:
902 case StructureType::Dynamic:
904 case StructureType::Field:
906 case StructureType::Grid:
908 }
911 }
912
913 static int get_output_socket_shape(const SocketDeclaration &decl,
914 const bke::FieldSocketState field_state,
915 const StructureType structure_type)
916 {
917 if (decl.identifier == "__extend__") {
919 }
920 if (socket_type_always_single(decl)) {
922 }
923 switch (structure_type) {
924 case StructureType::Single: {
926 }
927 case StructureType::Dynamic: {
929 }
930 case StructureType::Field: {
931 switch (field_state) {
938 }
939 break;
940 }
941 case StructureType::Grid: {
943 }
944 }
947 }
948
949 void update_socket_shapes(bNodeTree &ntree)
950 {
951 ntree.ensure_topology_cache();
952 if (U.experimental.use_socket_structure_type) {
953 const nodes::StructureTypeInterface &node_interface =
954 *ntree.runtime->structure_type_interface;
955 const Span<bke::FieldSocketState> field_states = ntree.runtime->field_states;
956 for (bNode *node : ntree.all_nodes()) {
957 if (node->is_undefined()) {
958 continue;
959 }
960 if (node->is_group_input()) {
961 const Span<bNodeSocket *> sockets = node->output_sockets();
962 for (const int i : node_interface.inputs.index_range()) {
963 sockets[i]->display_shape = get_output_socket_shape(
964 *sockets[i]->runtime->declaration,
965 field_states[sockets[i]->index_in_tree()],
966 node_interface.inputs[i]);
967 }
968 continue;
969 }
970 if (node->is_group_output()) {
971 const Span<bNodeSocket *> sockets = node->input_sockets();
972 for (const int i : node_interface.outputs.index_range()) {
973 sockets[i]->display_shape = get_output_socket_shape(
974 *sockets[i]->runtime->declaration,
975 field_states[sockets[i]->index_in_tree()],
976 node_interface.outputs[i].type);
977 }
978 continue;
979 }
980 for (bNodeSocket *socket : node->input_sockets()) {
981 if (const SocketDeclaration *declaration = socket->runtime->declaration) {
982 socket->display_shape = get_input_socket_shape(*declaration,
983 declaration->structure_type);
984 }
985 }
986 for (bNodeSocket *socket : node->output_sockets()) {
987 if (const SocketDeclaration *declaration = socket->runtime->declaration) {
988 socket->display_shape = get_output_socket_shape(
989 *declaration, field_states[socket->index_in_tree()], declaration->structure_type);
990 }
991 }
992 }
993 }
994 else {
995 const Span<bke::FieldSocketState> field_states = ntree.runtime->field_states;
996 for (bNodeSocket *socket : ntree.all_sockets()) {
997 switch (field_states[socket->index_in_tree()]) {
999 socket->display_shape = SOCK_DISPLAY_SHAPE_CIRCLE;
1000 break;
1002 socket->display_shape = SOCK_DISPLAY_SHAPE_DIAMOND_DOT;
1003 break;
1005 socket->display_shape = SOCK_DISPLAY_SHAPE_DIAMOND;
1006 break;
1007 }
1008 }
1009 }
1010 }
1011
1012 void update_eval_dependencies(bNodeTree &ntree)
1013 {
1014 ntree.ensure_topology_cache();
1015 nodes::GeometryNodesEvalDependencies new_deps =
1017
1018 /* Check if the dependencies have changed. */
1019 if (!ntree.runtime->geometry_nodes_eval_dependencies ||
1020 new_deps != *ntree.runtime->geometry_nodes_eval_dependencies)
1021 {
1022 needs_relations_update_ = true;
1023 ntree.runtime->geometry_nodes_eval_dependencies =
1024 std::make_unique<nodes::GeometryNodesEvalDependencies>(std::move(new_deps));
1025 }
1026 }
1027
1028 bool propagate_enum_definitions(bNodeTree &ntree)
1029 {
1030 ntree.ensure_interface_cache();
1031
1032 /* Propagation from right to left to determine which enum
1033 * definition to use for menu sockets. */
1034 for (bNode *node : ntree.toposort_right_to_left()) {
1035 const bool node_updated = this->should_update_individual_node(ntree, *node);
1036
1037 Vector<bNodeSocket *> locally_defined_enums;
1038 if (node->is_type("GeometryNodeMenuSwitch")) {
1039 bNodeSocket &enum_input = node->input_socket(0);
1040 BLI_assert(enum_input.is_available() && enum_input.type == SOCK_MENU);
1041 /* Generate new enum items when the node has changed, otherwise keep existing items. */
1042 if (node_updated) {
1043 const NodeMenuSwitch &storage = *static_cast<NodeMenuSwitch *>(node->storage);
1044 const RuntimeNodeEnumItems *enum_items = this->create_runtime_enum_items(
1045 storage.enum_definition);
1046
1047 this->set_enum_ptr(*enum_input.default_value_typed<bNodeSocketValueMenu>(), enum_items);
1048 /* Remove initial user. */
1049 enum_items->remove_user_and_delete_if_last();
1050 }
1051 locally_defined_enums.append(&enum_input);
1052 }
1053
1054 /* Clear current enum references. */
1055 for (bNodeSocket *socket : node->input_sockets()) {
1056 if (socket->is_available() && socket->type == SOCK_MENU &&
1057 !locally_defined_enums.contains(socket))
1058 {
1059 clear_enum_reference(*socket);
1060 }
1061 }
1062 for (bNodeSocket *socket : node->output_sockets()) {
1063 if (socket->is_available() && socket->type == SOCK_MENU) {
1064 clear_enum_reference(*socket);
1065 }
1066 }
1067
1068 /* Propagate enum references from output links. */
1069 for (bNodeSocket *output : node->output_sockets()) {
1070 if (!output->is_available() || output->type != SOCK_MENU) {
1071 continue;
1072 }
1073 for (const bNodeSocket *input : output->directly_linked_sockets()) {
1074 if (!input->is_available() || input->type != SOCK_MENU) {
1075 continue;
1076 }
1077 this->update_socket_enum_definition(*output->default_value_typed<bNodeSocketValueMenu>(),
1078 *input->default_value_typed<bNodeSocketValueMenu>());
1079 }
1080 }
1081
1082 if (node->is_group()) {
1083 /* Node groups expose internal enum definitions. */
1084 if (node->id == nullptr) {
1085 continue;
1086 }
1087 const bNodeTree *group_tree = reinterpret_cast<bNodeTree *>(node->id);
1088 group_tree->ensure_interface_cache();
1089
1090 for (const int socket_i : group_tree->interface_inputs().index_range()) {
1091 bNodeSocket &input = *node->input_sockets()[socket_i];
1092 const bNodeTreeInterfaceSocket &iosocket = *group_tree->interface_inputs()[socket_i];
1093 BLI_assert(STREQ(input.identifier, iosocket.identifier));
1094 if (input.is_available() && input.type == SOCK_MENU) {
1095 BLI_assert(STREQ(iosocket.socket_type, "NodeSocketMenu"));
1096 this->update_socket_enum_definition(
1097 *input.default_value_typed<bNodeSocketValueMenu>(),
1098 *static_cast<bNodeSocketValueMenu *>(iosocket.socket_data));
1099 }
1100 }
1101 }
1102 else if (node->is_type("GeometryNodeMenuSwitch")) {
1103 /* First input is always the node's own menu, propagate only to the enum case inputs. */
1104 const bNodeSocket *output = node->output_sockets().first();
1105 for (bNodeSocket *input : node->input_sockets().drop_front(1)) {
1106 if (input->is_available() && input->type == SOCK_MENU) {
1107 this->update_socket_enum_definition(
1108 *input->default_value_typed<bNodeSocketValueMenu>(),
1109 *output->default_value_typed<bNodeSocketValueMenu>());
1110 }
1111 }
1112 }
1113 else if (node->is_type("GeometryNodeForeachGeometryElementInput")) {
1114 /* Propagate menu from element inputs to field inputs. */
1115 BLI_assert(node->input_sockets().size() == node->output_sockets().size());
1116 /* Inputs Geometry, Selection and outputs Index, Element are ignored. */
1117 const IndexRange sockets = node->input_sockets().index_range().drop_front(2);
1118 for (const int socket_i : sockets) {
1119 bNodeSocket *input = node->input_sockets()[socket_i];
1120 bNodeSocket *output = node->output_sockets()[socket_i];
1121 if (input->is_available() && input->type == SOCK_MENU && output->is_available() &&
1122 output->type == SOCK_MENU)
1123 {
1124 this->update_socket_enum_definition(
1125 *input->default_value_typed<bNodeSocketValueMenu>(),
1126 *output->default_value_typed<bNodeSocketValueMenu>());
1127 }
1128 }
1129 }
1130 else {
1131 /* Propagate over internal relations. */
1132 /* XXX Placeholder implementation just propagates all outputs
1133 * to all inputs for built-in nodes This could perhaps use
1134 * input/output relations to handle propagation generically? */
1135 for (bNodeSocket *input : node->input_sockets()) {
1136 if (input->is_available() && input->type == SOCK_MENU) {
1137 for (const bNodeSocket *output : node->output_sockets()) {
1138 if (output->is_available() && output->type == SOCK_MENU) {
1139 this->update_socket_enum_definition(
1140 *input->default_value_typed<bNodeSocketValueMenu>(),
1141 *output->default_value_typed<bNodeSocketValueMenu>());
1142 }
1143 }
1144 }
1145 }
1146 }
1147 }
1148
1149 /* Find conflicts between on corresponding menu sockets on different group input nodes. */
1150 const Span<bNode *> group_input_nodes = ntree.group_input_nodes();
1151 for (const int interface_input_i : ntree.interface_inputs().index_range()) {
1152 const bNodeTreeInterfaceSocket &interface_socket =
1153 *ntree.interface_inputs()[interface_input_i];
1154 if (interface_socket.socket_type != StringRef("NodeSocketMenu")) {
1155 continue;
1156 }
1157 const RuntimeNodeEnumItems *found_enum_items = nullptr;
1158 bool found_conflict = false;
1159 for (bNode *input_node : group_input_nodes) {
1160 const bNodeSocket &socket = input_node->output_socket(interface_input_i);
1161 const auto &socket_value = *socket.default_value_typed<bNodeSocketValueMenu>();
1162 if (socket_value.has_conflict()) {
1163 found_conflict = true;
1164 break;
1165 }
1166 if (found_enum_items == nullptr) {
1167 found_enum_items = socket_value.enum_items;
1168 }
1169 else if (socket_value.enum_items != nullptr) {
1170 if (found_enum_items != socket_value.enum_items) {
1171 found_conflict = true;
1172 break;
1173 }
1174 }
1175 }
1176 if (found_conflict) {
1177 /* Make sure that all group input sockets know that there is a socket. */
1178 for (bNode *input_node : group_input_nodes) {
1179 bNodeSocket &socket = input_node->output_socket(interface_input_i);
1180 auto &socket_value = *socket.default_value_typed<bNodeSocketValueMenu>();
1181 if (socket_value.enum_items) {
1182 socket_value.enum_items->remove_user_and_delete_if_last();
1183 socket_value.enum_items = nullptr;
1184 }
1186 }
1187 }
1188 else if (found_enum_items != nullptr) {
1189 /* Make sure all corresponding menu sockets have the same menu reference. */
1190 for (bNode *input_node : group_input_nodes) {
1191 bNodeSocket &socket = input_node->output_socket(interface_input_i);
1192 auto &socket_value = *socket.default_value_typed<bNodeSocketValueMenu>();
1193 if (socket_value.enum_items == nullptr) {
1194 found_enum_items->add_user();
1195 socket_value.enum_items = found_enum_items;
1196 }
1197 }
1198 }
1199 }
1200
1201 /* Build list of new enum items for the node tree interface. */
1202 Vector<bNodeSocketValueMenu> interface_enum_items(ntree.interface_inputs().size(), {0});
1203 for (const bNode *group_input_node : ntree.group_input_nodes()) {
1204 for (const int socket_i : ntree.interface_inputs().index_range()) {
1205 const bNodeSocket &output = *group_input_node->output_sockets()[socket_i];
1206
1207 if (output.is_available() && output.type == SOCK_MENU) {
1208 this->update_socket_enum_definition(interface_enum_items[socket_i],
1209 *output.default_value_typed<bNodeSocketValueMenu>());
1210 }
1211 }
1212 }
1213
1214 /* Move enum items to the interface and detect if anything changed. */
1215 bool changed = false;
1216 for (const int socket_i : ntree.interface_inputs().index_range()) {
1217 bNodeTreeInterfaceSocket &iosocket = *ntree.interface_inputs()[socket_i];
1218 if (STREQ(iosocket.socket_type, "NodeSocketMenu")) {
1219 bNodeSocketValueMenu &dst = *static_cast<bNodeSocketValueMenu *>(iosocket.socket_data);
1220 const bNodeSocketValueMenu &src = interface_enum_items[socket_i];
1221 if (dst.enum_items != src.enum_items || dst.has_conflict() != src.has_conflict()) {
1222 changed = true;
1223 if (dst.enum_items) {
1224 dst.enum_items->remove_user_and_delete_if_last();
1225 }
1226 /* Items are moved, no need to change user count. */
1227 dst.enum_items = src.enum_items;
1229 }
1230 else {
1231 /* If the item isn't move make sure it gets released again. */
1232 if (src.enum_items) {
1233 src.enum_items->remove_user_and_delete_if_last();
1234 }
1235 }
1236 }
1237 }
1238
1239 return changed;
1240 }
1241
1246 const RuntimeNodeEnumItems *create_runtime_enum_items(const NodeEnumDefinition &enum_def)
1247 {
1248 RuntimeNodeEnumItems *enum_items = new RuntimeNodeEnumItems();
1249 enum_items->items.reinitialize(enum_def.items_num);
1250 for (const int i : enum_def.items().index_range()) {
1251 const NodeEnumItem &src = enum_def.items()[i];
1252 RuntimeNodeEnumItem &dst = enum_items->items[i];
1253
1254 dst.identifier = src.identifier;
1255 dst.name = src.name ? src.name : "";
1256 dst.description = src.description ? src.description : "";
1257 }
1258 return enum_items;
1259 }
1260
1261 void clear_enum_reference(bNodeSocket &socket)
1262 {
1263 BLI_assert(socket.is_available() && socket.type == SOCK_MENU);
1264 bNodeSocketValueMenu &default_value = *socket.default_value_typed<bNodeSocketValueMenu>();
1265 this->reset_enum_ptr(default_value);
1266 default_value.runtime_flag &= ~NODE_MENU_ITEMS_CONFLICT;
1267 }
1268
1269 void update_socket_enum_definition(bNodeSocketValueMenu &dst, const bNodeSocketValueMenu &src)
1270 {
1271 if (dst.has_conflict()) {
1272 /* Target enum already has a conflict. */
1273 BLI_assert(dst.enum_items == nullptr);
1274 return;
1275 }
1276
1277 if (src.has_conflict()) {
1278 /* Target conflict if any source enum has a conflict. */
1279 this->reset_enum_ptr(dst);
1281 }
1282 else if (!dst.enum_items) {
1283 /* First connection, set the reference. */
1284 this->set_enum_ptr(dst, src.enum_items);
1285 }
1286 else if (src.enum_items && dst.enum_items != src.enum_items) {
1287 /* Error if enum ref does not match other connections. */
1288 this->reset_enum_ptr(dst);
1290 }
1291 }
1292
1293 void reset_enum_ptr(bNodeSocketValueMenu &dst)
1294 {
1295 if (dst.enum_items) {
1296 dst.enum_items->remove_user_and_delete_if_last();
1297 dst.enum_items = nullptr;
1298 }
1299 }
1300
1301 void set_enum_ptr(bNodeSocketValueMenu &dst, const RuntimeNodeEnumItems *enum_items)
1302 {
1303 if (dst.enum_items) {
1304 dst.enum_items->remove_user_and_delete_if_last();
1305 dst.enum_items = nullptr;
1306 }
1307 if (enum_items) {
1308 enum_items->add_user();
1309 dst.enum_items = enum_items;
1310 }
1311 }
1312
1313 void update_link_validation(bNodeTree &ntree)
1314 {
1315 /* Tests if enum references are undefined. */
1316 const auto is_invalid_enum_ref = [](const bNodeSocket &socket) -> bool {
1317 if (socket.type == SOCK_MENU) {
1318 return socket.default_value_typed<bNodeSocketValueMenu>()->enum_items == nullptr;
1319 }
1320 return false;
1321 };
1322
1323 const bNodeTreeZones *fallback_zones = nullptr;
1324 if (ntree.type == NTREE_GEOMETRY && !ntree.zones() && ntree.runtime->last_valid_zones) {
1325 fallback_zones = ntree.runtime->last_valid_zones.get();
1326 }
1327
1328 LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
1329 link->flag |= NODE_LINK_VALID;
1330 if (!link->fromsock->is_available() || !link->tosock->is_available()) {
1331 link->flag &= ~NODE_LINK_VALID;
1332 continue;
1333 }
1334 if (is_invalid_enum_ref(*link->fromsock) || is_invalid_enum_ref(*link->tosock)) {
1335 link->flag &= ~NODE_LINK_VALID;
1336 ntree.runtime->link_errors.add(
1337 NodeLinkKey{*link},
1338 NodeLinkError{TIP_("Use node groups to reuse the same menu multiple times")});
1339 continue;
1340 }
1341 if (ntree.type == NTREE_GEOMETRY) {
1342 const Span<FieldSocketState> field_states = ntree.runtime->field_states;
1343 if (field_states[link->fromsock->index_in_tree()] == FieldSocketState::IsField &&
1344 field_states[link->tosock->index_in_tree()] != FieldSocketState::IsField)
1345 {
1346 link->flag &= ~NODE_LINK_VALID;
1347 ntree.runtime->link_errors.add(
1348 NodeLinkKey{*link}, NodeLinkError{TIP_("The node input does not support fields")});
1349 continue;
1350 }
1351 }
1352 const bNode &from_node = *link->fromnode;
1353 const bNode &to_node = *link->tonode;
1354 if (from_node.runtime->toposort_left_to_right_index >
1355 to_node.runtime->toposort_left_to_right_index)
1356 {
1357 link->flag &= ~NODE_LINK_VALID;
1358 ntree.runtime->link_errors.add(
1359 NodeLinkKey{*link},
1360 NodeLinkError{TIP_("The links form a cycle which is not supported")});
1361 continue;
1362 }
1363 if (ntree.typeinfo->validate_link) {
1364 const eNodeSocketDatatype from_type = eNodeSocketDatatype(link->fromsock->type);
1365 const eNodeSocketDatatype to_type = eNodeSocketDatatype(link->tosock->type);
1366 if (!ntree.typeinfo->validate_link(from_type, to_type)) {
1367 link->flag &= ~NODE_LINK_VALID;
1368 ntree.runtime->link_errors.add(
1369 NodeLinkKey{*link},
1371 " {}",
1372 TIP_("Conversion is not supported"),
1373 TIP_(link->fromsock->typeinfo->label),
1374 TIP_(link->tosock->typeinfo->label))});
1375 continue;
1376 }
1377 }
1378 if (fallback_zones) {
1379 if (!fallback_zones->link_between_sockets_is_allowed(*link->fromsock, *link->tosock)) {
1380 if (const bNodeTreeZone *from_zone = fallback_zones->get_zone_by_socket(*link->fromsock))
1381 {
1382 ntree.runtime->invalid_zone_output_node_ids.add(*from_zone->output_node_id);
1383 }
1384
1385 link->flag &= ~NODE_LINK_VALID;
1386 ntree.runtime->link_errors.add(
1387 NodeLinkKey{*link},
1388 NodeLinkError{TIP_("Links can only go into a zone but not out")});
1389 continue;
1390 }
1391 }
1392 }
1393 }
1394
1395 bool check_if_output_changed(const bNodeTree &tree)
1396 {
1397 tree.ensure_topology_cache();
1398
1399 /* Compute a hash that represents the node topology connected to the output. This always has
1400 * to be updated even if it is not used to detect changes right now. Otherwise
1401 * #btree.runtime.output_topology_hash will go out of date. */
1402 const Vector<const bNodeSocket *> tree_output_sockets = this->find_output_sockets(tree);
1403 const uint32_t old_topology_hash = tree.runtime->output_topology_hash;
1404 const uint32_t new_topology_hash = this->get_combined_socket_topology_hash(
1405 tree, tree_output_sockets);
1406 tree.runtime->output_topology_hash = new_topology_hash;
1407
1408 if (const AnimData *adt = BKE_animdata_from_id(&tree.id)) {
1409 /* Drivers may copy values in the node tree around arbitrarily and may cause the output to
1410 * change even if it wouldn't without drivers. Only some special drivers like `frame/5` can
1411 * be used without causing updates all the time currently. In the future we could try to
1412 * handle other drivers better as well.
1413 * Note that this optimization only works in practice when the depsgraph didn't also get a
1414 * copy-on-evaluation tag for the node tree (which happens when changing node properties). It
1415 * does work in a few situations like adding reroutes and duplicating nodes though. */
1416 LISTBASE_FOREACH (const FCurve *, fcurve, &adt->drivers) {
1417 const ChannelDriver *driver = fcurve->driver;
1418 const StringRef expression = driver->expression;
1419 if (expression.startswith("frame")) {
1420 const StringRef remaining_expression = expression.drop_known_prefix("frame");
1421 if (remaining_expression.find_first_not_of(" */+-0123456789.") == StringRef::not_found) {
1422 continue;
1423 }
1424 }
1425 /* Unrecognized driver, assume that the output always changes. */
1426 return true;
1427 }
1428 }
1429
1430 if (tree.runtime->changed_flag & NTREE_CHANGED_ANY) {
1431 return true;
1432 }
1433
1434 if (old_topology_hash != new_topology_hash) {
1435 return true;
1436 }
1437
1438 /* The topology hash can only be used when only topology-changing operations have been done.
1439 */
1440 if (tree.runtime->changed_flag ==
1441 (tree.runtime->changed_flag & (NTREE_CHANGED_LINK | NTREE_CHANGED_REMOVED_NODE)))
1442 {
1443 if (old_topology_hash == new_topology_hash) {
1444 return false;
1445 }
1446 }
1447
1448 if (!this->check_if_socket_outputs_changed_based_on_flags(tree, tree_output_sockets)) {
1449 return false;
1450 }
1451
1452 return true;
1453 }
1454
1455 Vector<const bNodeSocket *> find_output_sockets(const bNodeTree &tree)
1456 {
1458 for (const bNode *node : tree.all_nodes()) {
1459 if (!this->is_output_node(*node)) {
1460 continue;
1461 }
1462 for (const bNodeSocket *socket : node->input_sockets()) {
1463 if (!STREQ(socket->idname, "NodeSocketVirtual")) {
1464 sockets.append(socket);
1465 }
1466 }
1467 }
1468 return sockets;
1469 }
1470
1471 bool is_output_node(const bNode &node) const
1472 {
1473 if (node.typeinfo->nclass == NODE_CLASS_OUTPUT) {
1474 return true;
1475 }
1476 if (node.is_group_output()) {
1477 return true;
1478 }
1479 if (node.is_type("GeometryNodeWarning")) {
1480 return true;
1481 }
1483 return true;
1484 }
1485 /* Assume node groups without output sockets are outputs. */
1486 if (node.is_group()) {
1487 const bNodeTree *node_group = reinterpret_cast<const bNodeTree *>(node.id);
1488 if (node_group != nullptr &&
1489 node_group->runtime->runtime_flag & NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT)
1490 {
1491 return true;
1492 }
1493 }
1494 return false;
1495 }
1496
1501 uint32_t get_combined_socket_topology_hash(const bNodeTree &tree,
1502 Span<const bNodeSocket *> sockets)
1503 {
1504 if (tree.has_available_link_cycle()) {
1505 /* Return dummy value when the link has any cycles. The algorithm below could be improved
1506 * to handle cycles more gracefully. */
1507 return 0;
1508 }
1509 Array<uint32_t> hashes = this->get_socket_topology_hashes(tree, sockets);
1510 uint32_t combined_hash = 0;
1511 for (uint32_t hash : hashes) {
1512 combined_hash = noise::hash(combined_hash, hash);
1513 }
1514 return combined_hash;
1515 }
1516
1517 Array<uint32_t> get_socket_topology_hashes(const bNodeTree &tree,
1518 const Span<const bNodeSocket *> sockets)
1519 {
1520 BLI_assert(!tree.has_available_link_cycle());
1521 Array<std::optional<uint32_t>> hash_by_socket_id(tree.all_sockets().size());
1522 Stack<const bNodeSocket *> sockets_to_check = sockets;
1523
1524 auto get_socket_ptr_hash = [&](const bNodeSocket &socket) {
1525 const uint64_t socket_ptr = uintptr_t(&socket);
1526 return noise::hash(socket_ptr, socket_ptr >> 32);
1527 };
1528 const bNodeTreeZones *zones = tree.zones();
1529
1530 while (!sockets_to_check.is_empty()) {
1531 const bNodeSocket &socket = *sockets_to_check.peek();
1532 const bNode &node = socket.owner_node();
1533
1534 if (hash_by_socket_id[socket.index_in_tree()].has_value()) {
1535 sockets_to_check.pop();
1536 /* Socket is handled already. */
1537 continue;
1538 }
1539
1540 uint32_t socket_hash = 0;
1541 if (socket.is_input()) {
1542 /* For input sockets, first compute the hashes of all linked sockets. */
1543 bool all_origins_computed = true;
1544 bool get_value_from_origin = false;
1545 Vector<const bNodeSocket *, 16> origin_sockets;
1546 for (const bNodeLink *link : socket.directly_linked_links()) {
1547 if (link->is_muted()) {
1548 continue;
1549 }
1550 if (!link->is_available()) {
1551 continue;
1552 }
1553 origin_sockets.append(link->fromsock);
1554 }
1555 if (zones) {
1556 if (const bNodeTreeZone *zone = zones->get_zone_by_socket(socket)) {
1557 if (zone->output_node_id == node.identifier) {
1558 if (const bNode *input_node = zone->input_node()) {
1559 origin_sockets.extend(input_node->input_sockets());
1560 }
1561 }
1562 }
1563 }
1564 for (const bNodeSocket *origin_socket : origin_sockets) {
1565 const std::optional<uint32_t> origin_hash =
1566 hash_by_socket_id[origin_socket->index_in_tree()];
1567 if (origin_hash.has_value()) {
1568 if (get_value_from_origin || socket.type != origin_socket->type) {
1569 socket_hash = noise::hash(socket_hash, *origin_hash);
1570 }
1571 else {
1572 /* Copy the socket hash because the link did not change it. */
1573 socket_hash = *origin_hash;
1574 }
1575 get_value_from_origin = true;
1576 }
1577 else {
1578 sockets_to_check.push(origin_socket);
1579 all_origins_computed = false;
1580 }
1581 }
1582 if (!all_origins_computed) {
1583 continue;
1584 }
1585
1586 if (!get_value_from_origin) {
1587 socket_hash = get_socket_ptr_hash(socket);
1588 }
1589 }
1590 else {
1591 bool all_available_inputs_computed = true;
1592 for (const bNodeSocket *input_socket : node.input_sockets()) {
1593 if (input_socket->is_available()) {
1594 if (!hash_by_socket_id[input_socket->index_in_tree()].has_value()) {
1595 sockets_to_check.push(input_socket);
1596 all_available_inputs_computed = false;
1597 }
1598 }
1599 }
1600 if (!all_available_inputs_computed) {
1601 continue;
1602 }
1603 if (node.is_reroute()) {
1604 socket_hash = *hash_by_socket_id[node.input_socket(0).index_in_tree()];
1605 }
1606 else if (node.is_muted()) {
1607 const bNodeSocket *internal_input = socket.internal_link_input();
1608 if (internal_input == nullptr) {
1609 socket_hash = get_socket_ptr_hash(socket);
1610 }
1611 else {
1612 if (internal_input->type == socket.type) {
1613 socket_hash = *hash_by_socket_id[internal_input->index_in_tree()];
1614 }
1615 else {
1616 socket_hash = get_socket_ptr_hash(socket);
1617 }
1618 }
1619 }
1620 else {
1621 socket_hash = get_socket_ptr_hash(socket);
1622 for (const bNodeSocket *input_socket : node.input_sockets()) {
1623 if (input_socket->is_available()) {
1624 const uint32_t input_socket_hash = *hash_by_socket_id[input_socket->index_in_tree()];
1625 socket_hash = noise::hash(socket_hash, input_socket_hash);
1626 }
1627 }
1628
1629 /* The Image Texture node has a special case. The behavior of the color output changes
1630 * depending on whether the Alpha output is linked. */
1631 if (node.is_type("ShaderNodeTexImage") && socket.index() == 0) {
1632 BLI_assert(STREQ(socket.name, "Color"));
1633 const bNodeSocket &alpha_socket = node.output_socket(1);
1634 BLI_assert(STREQ(alpha_socket.name, "Alpha"));
1635 if (alpha_socket.is_directly_linked()) {
1636 socket_hash = noise::hash(socket_hash);
1637 }
1638 }
1639 }
1640 }
1641 hash_by_socket_id[socket.index_in_tree()] = socket_hash;
1642 /* Check that nothing has been pushed in the meantime. */
1643 BLI_assert(sockets_to_check.peek() == &socket);
1644 sockets_to_check.pop();
1645 }
1646
1647 /* Create output array. */
1648 Array<uint32_t> hashes(sockets.size());
1649 for (const int i : sockets.index_range()) {
1650 hashes[i] = *hash_by_socket_id[sockets[i]->index_in_tree()];
1651 }
1652 return hashes;
1653 }
1654
1659 bool check_if_socket_outputs_changed_based_on_flags(const bNodeTree &tree,
1660 Span<const bNodeSocket *> sockets)
1661 {
1662 /* Avoid visiting the same socket twice when multiple links point to the same socket. */
1663 Array<bool> pushed_by_socket_id(tree.all_sockets().size(), false);
1664 Stack<const bNodeSocket *> sockets_to_check = sockets;
1665
1666 for (const bNodeSocket *socket : sockets) {
1667 pushed_by_socket_id[socket->index_in_tree()] = true;
1668 }
1669
1670 while (!sockets_to_check.is_empty()) {
1671 const bNodeSocket &socket = *sockets_to_check.pop();
1672 const bNode &node = socket.owner_node();
1673 if (socket.runtime->changed_flag != NTREE_CHANGED_NOTHING) {
1674 return true;
1675 }
1676 if (node.runtime->changed_flag != NTREE_CHANGED_NOTHING) {
1677 const bool only_unused_internal_link_changed = !node.is_muted() &&
1678 node.runtime->changed_flag ==
1680 const bool only_parent_changed = node.runtime->changed_flag == NTREE_CHANGED_PARENT;
1681 const bool change_affects_output = !(only_unused_internal_link_changed ||
1682 only_parent_changed);
1683 if (change_affects_output) {
1684 return true;
1685 }
1686 }
1687 if (socket.is_input()) {
1688 for (const bNodeSocket *origin_socket : socket.directly_linked_sockets()) {
1689 bool &pushed = pushed_by_socket_id[origin_socket->index_in_tree()];
1690 if (!pushed) {
1691 sockets_to_check.push(origin_socket);
1692 pushed = true;
1693 }
1694 }
1695 }
1696 else {
1697 for (const bNodeSocket *input_socket : node.input_sockets()) {
1698 if (input_socket->is_available()) {
1699 bool &pushed = pushed_by_socket_id[input_socket->index_in_tree()];
1700 if (!pushed) {
1701 sockets_to_check.push(input_socket);
1702 pushed = true;
1703 }
1704 }
1705 }
1706 /* Zones may propagate changes from the input node to the output node even though there is
1707 * no explicit link. */
1708 switch (node.type_legacy) {
1712 const bNodeTreeZones *zones = tree.zones();
1713 if (!zones) {
1714 break;
1715 }
1716 const bNodeTreeZone *zone = zones->get_zone_by_node(node.identifier);
1717 if (!zone->input_node()) {
1718 break;
1719 }
1720 for (const bNodeSocket *input_socket : zone->input_node()->input_sockets()) {
1721 if (input_socket->is_available()) {
1722 bool &pushed = pushed_by_socket_id[input_socket->index_in_tree()];
1723 if (!pushed) {
1724 sockets_to_check.push(input_socket);
1725 pushed = true;
1726 }
1727 }
1728 }
1729 break;
1730 }
1731 }
1732 /* The Normal node has a special case, because the value stored in the first output
1733 * socket is used as input in the node. */
1734 if ((node.is_type("ShaderNodeNormal") || node.is_type("CompositorNodeNormal")) &&
1735 socket.index() == 1)
1736 {
1737 BLI_assert(STREQ(socket.name, "Dot"));
1738 const bNodeSocket &normal_output = node.output_socket(0);
1739 BLI_assert(STREQ(normal_output.name, "Normal"));
1740 bool &pushed = pushed_by_socket_id[normal_output.index_in_tree()];
1741 if (!pushed) {
1742 sockets_to_check.push(&normal_output);
1743 pushed = true;
1744 }
1745 }
1746 }
1747 }
1748 return false;
1749 }
1750
1755 bool update_nested_node_refs(bNodeTree &ntree)
1756 {
1757 ntree.ensure_topology_cache();
1758
1759 /* Simplify lookup of old ids. */
1760 Map<bNestedNodePath, int32_t> old_id_by_path;
1761 Set<int32_t> old_ids;
1762 for (const bNestedNodeRef &ref : ntree.nested_node_refs_span()) {
1763 old_id_by_path.add(ref.path, ref.id);
1764 old_ids.add(ref.id);
1765 }
1766
1767 Vector<bNestedNodePath> nested_node_paths;
1768
1769 /* Don't forget nested node refs just because the linked file is not available right now. */
1770 for (const bNestedNodePath &path : old_id_by_path.keys()) {
1771 const bNode *node = ntree.node_by_id(path.node_id);
1772 if (node && node->is_group() && node->id) {
1773 if (node->id->tag & ID_TAG_MISSING) {
1774 nested_node_paths.append(path);
1775 }
1776 }
1777 }
1778 if (ntree.type == NTREE_GEOMETRY) {
1779 /* Create references for simulations and bake nodes in geometry nodes.
1780 * Those are the nodes that we want to store settings for at a higher level. */
1781 for (StringRefNull idname : {"GeometryNodeSimulationOutput", "GeometryNodeBake"}) {
1782 for (const bNode *node : ntree.nodes_by_type(idname)) {
1783 nested_node_paths.append({node->identifier, -1});
1784 }
1785 }
1786 }
1787 /* Propagate references to nested nodes in group nodes. */
1788 for (const bNode *node : ntree.group_nodes()) {
1789 const bNodeTree *group = reinterpret_cast<const bNodeTree *>(node->id);
1790 if (group == nullptr) {
1791 continue;
1792 }
1793 for (const int i : group->nested_node_refs_span().index_range()) {
1794 const bNestedNodeRef &child_ref = group->nested_node_refs[i];
1795 nested_node_paths.append({node->identifier, child_ref.id});
1796 }
1797 }
1798
1799 /* Used to generate new unique IDs if necessary. */
1800 RandomNumberGenerator rng = RandomNumberGenerator::from_random_seed();
1801
1802 Map<int32_t, bNestedNodePath> new_path_by_id;
1803 for (const bNestedNodePath &path : nested_node_paths) {
1804 const int32_t old_id = old_id_by_path.lookup_default(path, -1);
1805 if (old_id != -1) {
1806 /* The same path existed before, it should keep the same ID as before. */
1807 new_path_by_id.add(old_id, path);
1808 continue;
1809 }
1810 int32_t new_id;
1811 while (true) {
1812 new_id = rng.get_int32(INT32_MAX);
1813 if (!old_ids.contains(new_id) && !new_path_by_id.contains(new_id)) {
1814 break;
1815 }
1816 }
1817 /* The path is new, it should get a new ID that does not collide with any existing IDs. */
1818 new_path_by_id.add(new_id, path);
1819 }
1820
1821 /* Check if the old and new references are identical. */
1822 if (!this->nested_node_refs_changed(ntree, new_path_by_id)) {
1823 return false;
1824 }
1825
1827 if (new_path_by_id.is_empty()) {
1828 ntree.nested_node_refs_num = 0;
1829 return true;
1830 }
1831
1832 /* Allocate new array for the nested node references contained in the node tree. */
1833 bNestedNodeRef *new_refs = MEM_malloc_arrayN<bNestedNodeRef>(size_t(new_path_by_id.size()),
1834 __func__);
1835 int index = 0;
1836 for (const auto item : new_path_by_id.items()) {
1837 bNestedNodeRef &ref = new_refs[index];
1838 ref.id = item.key;
1839 ref.path = item.value;
1840 index++;
1841 }
1842
1843 ntree.nested_node_refs = new_refs;
1844 ntree.nested_node_refs_num = new_path_by_id.size();
1845
1846 return true;
1847 }
1848
1849 bool nested_node_refs_changed(const bNodeTree &ntree,
1850 const Map<int32_t, bNestedNodePath> &new_path_by_id)
1851 {
1852 if (ntree.nested_node_refs_num != new_path_by_id.size()) {
1853 return true;
1854 }
1855 for (const bNestedNodeRef &ref : ntree.nested_node_refs_span()) {
1856 if (!new_path_by_id.contains(ref.id)) {
1857 return true;
1858 }
1859 }
1860 return false;
1861 }
1862
1863 void reset_changed_flags(bNodeTree &ntree)
1864 {
1865 ntree.runtime->changed_flag = NTREE_CHANGED_NOTHING;
1866 for (bNode *node : ntree.all_nodes()) {
1867 node->runtime->changed_flag = NTREE_CHANGED_NOTHING;
1868 node->runtime->update = 0;
1869 LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
1870 socket->runtime->changed_flag = NTREE_CHANGED_NOTHING;
1871 }
1872 LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
1873 socket->runtime->changed_flag = NTREE_CHANGED_NOTHING;
1874 }
1875 }
1876
1877 ntree.tree_interface.reset_interface_changed();
1878 }
1879
1883 bool update_panel_toggle_names(bNodeTree &ntree)
1884 {
1885 bool changed = false;
1886 ntree.ensure_interface_cache();
1887 for (bNodeTreeInterfaceItem *item : ntree.interface_items()) {
1888 if (item->item_type != NODE_INTERFACE_PANEL) {
1889 continue;
1890 }
1891 bNodeTreeInterfacePanel *panel = reinterpret_cast<bNodeTreeInterfacePanel *>(item);
1892 if (bNodeTreeInterfaceSocket *toggle_socket = panel->header_toggle_socket()) {
1893 if (!STREQ(panel->name, toggle_socket->name)) {
1894 MEM_SAFE_FREE(toggle_socket->name);
1895 toggle_socket->name = BLI_strdup_null(panel->name);
1896 changed = true;
1897 }
1898 }
1899 }
1900 return changed;
1901 }
1902};
1903
1904} // namespace blender::bke
1905
1910
1915
1920
1925
1930
1935
1940
1945
1950
1955
1960
1965
1970
1975
1977{
1979}
1980
1982{
1984}
1985
1990
1995
1997{
1998 add_node_tag(ntree, node, NTREE_CHANGED_PARENT);
1999}
2000
2002{
2003 FOREACH_NODETREE_BEGIN (bmain, ntree, ntree_id) {
2004 for (bNode *node : ntree->all_nodes()) {
2005 if (node->id == id) {
2006 node->runtime->update |= NODE_UPDATE_ID;
2008 }
2009 }
2010 }
2012}
2013
2015{
2016 /* Would have to search for the node that uses the image user for a more detailed tag. */
2018}
2019
2020uint64_t bNestedNodePath::hash() const
2021{
2022 return blender::get_default_hash(this->node_id, this->id_in_node);
2023}
2024
2026{
2027 return a.node_id == b.node_id && a.id_in_node == b.id_in_node;
2028}
2029
2037static bool is_updating = false;
2038
2040 const std::optional<blender::Span<bNodeTree *>> modified_trees,
2042{
2043 if (is_updating) {
2044 return;
2045 }
2046
2047 is_updating = true;
2049 if (modified_trees.has_value()) {
2050 updater.update_rooted(*modified_trees);
2051 }
2052 else {
2053 updater.update();
2054 }
2055 is_updating = false;
2056}
2057
2059 bNodeTree &modified_tree,
2061{
2062 BKE_ntree_update(bmain, blender::Span{&modified_tree}, params);
2063}
2064
2066{
2067 if (is_updating) {
2068 return;
2069 }
2070 is_updating = true;
2072 blender::bke::NodeTreeMainUpdater updater{nullptr, params};
2073 updater.update_rooted({&tree});
2074 is_updating = false;
2075}
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:82
bool BKE_image_is_animated(Image *image)
ID * BKE_id_owner_get(ID *id, const bool debug_relationship_assert=true)
Definition lib_id.cc:2491
#define NODE_CLASS_OUTPUT
Definition BKE_node.hh:434
#define FOREACH_NODETREE_END
Definition BKE_node.hh:866
#define FOREACH_NODETREE_BEGIN(bmain, _nodetree, _id)
Definition BKE_node.hh:856
#define GEO_NODE_FOREACH_GEOMETRY_ELEMENT_OUTPUT
#define GEO_NODE_SIMULATION_OUTPUT
#define GEO_NODE_REPEAT_OUTPUT
void BKE_ntree_update_tag_node_internal_link(bNodeTree *ntree, bNode *node)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
char * BLI_strdup_null(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_MALLOC
Definition string.cc:46
#define BLI_STR_UTF8_BLACK_RIGHT_POINTING_SMALL_TRIANGLE
#define BLI_STRUCT_EQUALITY_OPERATORS_3(Type, m1, m2, m3)
#define UNUSED_VARS_NDEBUG(...)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define STREQ(a, b)
#define TIP_(msgid)
float[3] Vector
void DEG_relations_tag_update(Main *bmain)
@ ID_TAG_MISSING
Definition DNA_ID.h:775
@ ID_NT
struct FCurve FCurve
struct AnimData AnimData
struct ChannelDriver ChannelDriver
struct Image Image
@ eModifierType_Nodes
struct bNodeTreeInterfaceSocket bNodeTreeInterfaceSocket
struct bNodeTreeInterfacePanel bNodeTreeInterfacePanel
struct bNodeTreeInterfaceItem bNodeTreeInterfaceItem
struct NodeMenuSwitch NodeMenuSwitch
@ NTREE_TEXTURE
@ NTREE_SHADER
@ NTREE_GEOMETRY
struct bNodeSocketValueMenu bNodeSocketValueMenu
@ NODE_UPDATE_ID
@ NODE_LINK_VALID
struct bNestedNodeRef bNestedNodeRef
struct NodeGeometryBake NodeGeometryBake
struct NodeEnumDefinition NodeEnumDefinition
struct NodeGeometryBakeItem NodeGeometryBakeItem
@ GEO_NODE_BAKE_ITEM_IS_ATTRIBUTE
struct bNodeLink bNodeLink
@ NTREE_RUNTIME_FLAG_HAS_SIMULATION_ZONE
@ NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT
@ NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION
@ SOCK_IS_LINKED
@ SOCK_NO_INTERNAL_LINK
struct bNode bNode
@ SOCK_DISPLAY_SHAPE_LINE
@ SOCK_DISPLAY_SHAPE_CIRCLE
@ SOCK_DISPLAY_SHAPE_DIAMOND
@ SOCK_DISPLAY_SHAPE_VOLUME_GRID
@ SOCK_DISPLAY_SHAPE_DIAMOND_DOT
eNodeSocketDatatype
@ SOCK_INT
@ SOCK_TEXTURE
@ SOCK_VECTOR
@ SOCK_BOOLEAN
@ SOCK_MATERIAL
@ SOCK_FLOAT
@ SOCK_IMAGE
@ SOCK_COLLECTION
@ SOCK_CUSTOM
@ SOCK_GEOMETRY
@ SOCK_ROTATION
@ SOCK_OBJECT
@ SOCK_RGBA
@ SOCK_MENU
struct bNodeTree bNodeTree
struct bNestedNodePath bNestedNodePath
struct NodeEnumItem NodeEnumItem
struct bNodeSocket bNodeSocket
void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
Definition MOD_nodes.cc:448
void ntreeTexCheckCyclics(struct bNodeTree *ntree)
#define U
unsigned long long int uint64_t
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
Value lookup_default(const Key &key, const Value &default_value) const
Definition BLI_map.hh:570
int64_t size() const
Definition BLI_map.hh:976
KeyIterator keys() const &
Definition BLI_map.hh:875
bool is_empty() const
Definition BLI_map.hh:986
bool contains(const Key &key) const
Definition BLI_map.hh:353
ItemIterator items() const &
Definition BLI_map.hh:902
bool contains(const Key &key) const
Definition BLI_set.hh:310
bool add(const Key &key)
Definition BLI_set.hh:248
void add_new(const Key &key)
Definition BLI_set.hh:233
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
Definition BLI_span.hh:260
T & peek()
Definition BLI_stack.hh:263
bool is_empty() const
Definition BLI_stack.hh:308
T pop()
Definition BLI_stack.hh:242
void push(const T &value)
Definition BLI_stack.hh:213
constexpr StringRef drop_known_prefix(StringRef prefix) const
bool add(const Key &key)
bool is_empty() const
int64_t size() const
bool contains(const T &value) const
void append(const T &value)
void extend(Span< T > array)
Span< T > as_span() const
static RandomNumberGenerator from_random_seed()
Definition rand.cc:288
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr bool is_empty() const
Definition BLI_span.hh:260
static constexpr int64_t not_found
constexpr int64_t find_first_not_of(StringRef chars, int64_t pos=0) const
constexpr bool startswith(StringRef prefix) const
void append(const T &value)
NodeTreeMainUpdater(Main *bmain, const NodeTreeUpdateExtraParams &params)
void update_rooted(Span< bNodeTree * > root_ntrees)
const bNode * input_node() const
Vector< bNodeTreeZone * > zones
const bNodeTreeZone * get_zone_by_node(const int32_t node_id) const
const bNodeTreeZone * get_zone_by_socket(const bNodeSocket &socket) const
bool link_between_sockets_is_allowed(const bNodeSocket &from, const bNodeSocket &to) const
KDTree_3d * tree
#define INT32_MAX
#define input
#define output
#define MEM_SAFE_FREE(v)
#define GS(a)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
const bNodeZoneType * zone_type_by_node_type(const int node_type)
std::pair< Object *, ModifierData * > ObjectModifierPair
std::pair< bNodeTree *, bNode * > TreeNodePair
void node_preview_remove_unused(bNodeTree *ntree)
Definition node.cc:4508
Span< int > all_zone_input_node_types()
static bool is_tree_changed(const bNodeTree &tree)
std::pair< bNode *, bNodeSocket * > NodeSocketPair
bool node_declaration_ensure(bNodeTree &ntree, bNode &node)
Definition node.cc:5090
static int get_internal_link_type_priority(const bNodeSocketType *from, const bNodeSocketType *to)
static Type to_type(const eGPUType type)
bool update_tree_gizmo_propagation(bNodeTree &tree)
bool is_builtin_gizmo_node(const bNode &node)
GeometryNodesEvalDependencies gather_geometry_nodes_eval_dependencies_with_cache(const bNodeTree &ntree)
void update_node_declaration_and_sockets(bNodeTree &ntree, bNode &node)
uint32_t hash(uint32_t kx)
Definition noise.cc:77
uint64_t get_default_hash(const T &v, const Args &...args)
Definition BLI_hash.hh:233
void BKE_ntree_update_tag_node_new(bNodeTree *ntree, bNode *node)
static void add_node_tag(bNodeTree *ntree, bNode *node, const eNodeTreeChangedFlag flag)
void BKE_ntree_update_tag_active_output_changed(bNodeTree *ntree)
void BKE_ntree_update_tag_socket_type(bNodeTree *ntree, bNodeSocket *socket)
void BKE_ntree_update_tag_node_internal_link(bNodeTree *ntree, bNode *node)
void BKE_ntree_update_tag_node_mute(bNodeTree *ntree, bNode *node)
void BKE_ntree_update_tag_all(bNodeTree *ntree)
void BKE_ntree_update_without_main(bNodeTree &tree)
void BKE_ntree_update_tag_link_mute(bNodeTree *ntree, bNodeLink *)
void BKE_ntree_update_tag_link_changed(bNodeTree *ntree)
void BKE_ntree_update_tag_socket_new(bNodeTree *ntree, bNodeSocket *socket)
bool operator==(const bNestedNodePath &a, const bNestedNodePath &b)
void BKE_ntree_update_tag_socket_removed(bNodeTree *ntree)
void BKE_ntree_update_tag_socket_property(bNodeTree *ntree, bNodeSocket *socket)
static void add_socket_tag(bNodeTree *ntree, bNodeSocket *socket, const eNodeTreeChangedFlag flag)
static void add_tree_tag(bNodeTree *ntree, const eNodeTreeChangedFlag flag)
void BKE_ntree_update_tag_missing_runtime_data(bNodeTree *ntree)
static bool is_updating
void BKE_ntree_update_tag_link_removed(bNodeTree *ntree)
void BKE_ntree_update_tag_socket_availability(bNodeTree *ntree, bNodeSocket *socket)
void BKE_ntree_update_tag_link_added(bNodeTree *ntree, bNodeLink *)
void BKE_ntree_update_tag_node_type(bNodeTree *ntree, bNode *node)
void BKE_ntree_update_tag_node_removed(bNodeTree *ntree)
void BKE_ntree_update_tag_id_changed(Main *bmain, ID *id)
void BKE_ntree_update_tag_image_user_changed(bNodeTree *ntree, ImageUser *)
void BKE_ntree_update(Main &bmain, const std::optional< blender::Span< bNodeTree * > > modified_trees, const NodeTreeUpdateExtraParams &params)
eNodeTreeChangedFlag
@ NTREE_CHANGED_ANY
@ NTREE_CHANGED_REMOVED_SOCKET
@ NTREE_CHANGED_NOTHING
@ NTREE_CHANGED_NODE_OUTPUT
@ NTREE_CHANGED_NODE_PROPERTY
@ NTREE_CHANGED_LINK
@ NTREE_CHANGED_SOCKET_PROPERTY
@ NTREE_CHANGED_REMOVED_NODE
@ NTREE_CHANGED_PARENT
@ NTREE_CHANGED_ALL
@ NTREE_CHANGED_INTERNAL_LINK
void BKE_ntree_update_after_single_tree_change(Main &bmain, bNodeTree &modified_tree, const NodeTreeUpdateExtraParams &params)
void BKE_ntree_update_tag_node_property(bNodeTree *ntree, bNode *node)
void BKE_ntree_update_tag_parent_change(bNodeTree *ntree, bNode *node)
#define hash
Definition noise_c.cc:154
char expression[256]
Definition DNA_ID.h:404
int tag
Definition DNA_ID.h:424
NodeGeometryBakeItem * items
NodeEnumDefinition enum_definition
struct bNodeTree * node_group
bNestedNodePath path
const RuntimeNodeEnumItemsHandle * enum_items
bNodeSocketRuntimeHandle * runtime
bNodeSocketTypeHandle * typeinfo
char idname[64]
bNodeTreeRuntimeHandle * runtime
int nested_node_refs_num
bNestedNodeRef * nested_node_refs
bNodeTreeTypeHandle * typeinfo
bNodeTreeInterface tree_interface
ListBase links
bNodeTypeHandle * typeinfo
ListBase inputs
struct ID * id
int16_t type_legacy
bNodeRuntimeHandle * runtime
void * storage
ListBase outputs
int32_t identifier
Span< TreeNodePair > get_group_node_users(bNodeTree *ntree)
Span< ObjectModifierPair > get_modifier_users(bNodeTree *ntree)
Defines a socket type.
Definition BKE_node.hh:152
eNodeSocketDatatype type
Definition BKE_node.hh:187
blender::nodes::NodeDeclaration * static_declaration
Definition BKE_node.hh:364
NodeDeclareFunction declare
Definition BKE_node.hh:355
void(* updatefunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:269
i
Definition text_draw.cc:230
uint8_t flag
Definition wm_window.cc:139