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