From 9788f9f62aebecf9115c815b23a9714f6b702709 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 31 Jul 2025 20:49:28 +0200 Subject: [PATCH] Geometry Nodes: sync bundle/closure nodes on first link When using link-drag-search to create bundle or closure nodes, the newly created nodes are already synced automatically. Now this automatic syncing also happens when an empty node is first linked. If there are any sockets already, the automatic syncing does not happen as it can be unintentional. In this case the user can just click the sync icon in the node header to update the sockets. Pull Request: https://projects.blender.org/blender/blender/pulls/143744 --- source/blender/blenkernel/BKE_node.hh | 2 + .../editors/space_node/node_relationships.cc | 22 +++-- source/blender/nodes/NOD_sync_sockets.hh | 13 ++- .../nodes/geometry/nodes/node_geo_closure.cc | 14 ++++ .../geometry/nodes/node_geo_combine_bundle.cc | 10 +++ .../nodes/node_geo_evaluate_closure.cc | 10 +++ .../nodes/node_geo_separate_bundle.cc | 10 +++ source/blender/nodes/intern/sync_sockets.cc | 83 ++++++++++++------- source/blender/nodes/intern/trace_values.cc | 1 + 9 files changed, 123 insertions(+), 42 deletions(-) diff --git a/source/blender/blenkernel/BKE_node.hh b/source/blender/blenkernel/BKE_node.hh index e7ad3edce31..9345f521f39 100644 --- a/source/blender/blenkernel/BKE_node.hh +++ b/source/blender/blenkernel/BKE_node.hh @@ -226,6 +226,8 @@ struct NodeInsertLinkParams { bNodeTree &ntree; bNode &node; bNodeLink &link; + /** Optional context to allow for more advanced link insertion functionality. */ + bContext *C = nullptr; }; /** diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index 8c9c3f0d429..22bb0e276fe 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -286,7 +286,8 @@ static bNodeSocket *best_socket_input(bNodeTree *ntree, bNode *node, int num, in return nullptr; } -static bool snode_autoconnect_input(SpaceNode &snode, +static bool snode_autoconnect_input(bContext &C, + SpaceNode &snode, bNode *node_fr, bNodeSocket *sock_fr, bNode *node_to, @@ -302,14 +303,14 @@ static bool snode_autoconnect_input(SpaceNode &snode, bNodeLink &link = bke::node_add_link(*ntree, *node_fr, *sock_fr, *node_to, *sock_to); if (link.fromnode->typeinfo->insert_link) { - bke::NodeInsertLinkParams params{*ntree, *link.fromnode, link}; + bke::NodeInsertLinkParams params{*ntree, *link.fromnode, link, &C}; if (!link.fromnode->typeinfo->insert_link(params)) { bke::node_remove_link(ntree, link); return false; } } if (link.tonode->typeinfo->insert_link) { - bke::NodeInsertLinkParams params{*ntree, *link.tonode, link}; + bke::NodeInsertLinkParams params{*ntree, *link.tonode, link, &C}; if (!link.tonode->typeinfo->insert_link(params)) { bke::node_remove_link(ntree, link); return false; @@ -365,7 +366,10 @@ void update_multi_input_indices_for_removed_links(bNode &node) } } -static void snode_autoconnect(SpaceNode &snode, const bool allow_multiple, const bool replace) +static void snode_autoconnect(bContext &C, + SpaceNode &snode, + const bool allow_multiple, + const bool replace) { bNodeTree *ntree = snode.edittree; Vector sorted_nodes = get_selected_nodes(*ntree).extract_vector(); @@ -401,7 +405,7 @@ static void snode_autoconnect(SpaceNode &snode, const bool allow_multiple, const continue; } - if (snode_autoconnect_input(snode, node_fr, sock_fr, node_to, sock_to, replace)) { + if (snode_autoconnect_input(C, snode, node_fr, sock_fr, node_to, sock_to, replace)) { // numlinks++; } } @@ -425,7 +429,7 @@ static void snode_autoconnect(SpaceNode &snode, const bool allow_multiple, const continue; } - if (snode_autoconnect_input(snode, node_fr, sock_fr, node_to, sock_to, replace)) { + if (snode_autoconnect_input(C, snode, node_fr, sock_fr, node_to, sock_to, replace)) { // numlinks++; break; } @@ -1260,14 +1264,14 @@ static void add_dragged_links_to_tree(bContext &C, bNodeLinkDrag &nldrag) bNodeLink *new_link = MEM_mallocN(__func__); *new_link = link; if (link.fromnode->typeinfo->insert_link) { - bke::NodeInsertLinkParams params{ntree, *link.fromnode, *new_link}; + bke::NodeInsertLinkParams params{ntree, *link.fromnode, *new_link, &C}; if (!link.fromnode->typeinfo->insert_link(params)) { MEM_freeN(new_link); continue; } } if (link.tonode->typeinfo->insert_link) { - bke::NodeInsertLinkParams params{ntree, *link.tonode, *new_link}; + bke::NodeInsertLinkParams params{ntree, *link.tonode, *new_link, &C}; if (!link.tonode->typeinfo->insert_link(params)) { MEM_freeN(new_link); continue; @@ -1660,7 +1664,7 @@ static wmOperatorStatus node_make_link_exec(bContext *C, wmOperator *op) ED_preview_kill_jobs(CTX_wm_manager(C), &bmain); - snode_autoconnect(snode, true, replace); + snode_autoconnect(*C, snode, true, replace); /* Deselect sockets after linking. */ node_deselect_all_input_sockets(node_tree, false); diff --git a/source/blender/nodes/NOD_sync_sockets.hh b/source/blender/nodes/NOD_sync_sockets.hh index e728a4ca0df..934962de2be 100644 --- a/source/blender/nodes/NOD_sync_sockets.hh +++ b/source/blender/nodes/NOD_sync_sockets.hh @@ -12,6 +12,7 @@ struct ReportList; struct bContext; struct bNodeTree; struct Main; +struct bNodeSocket; namespace blender::nodes { @@ -32,16 +33,20 @@ void node_can_sync_cache_clear(Main &bmain); void sync_sockets_evaluate_closure(SpaceNode &snode, bNode &evaluate_closure_node, - ReportList *reports); + ReportList *reports, + const bNodeSocket *src_closure_socket = nullptr); void sync_sockets_separate_bundle(SpaceNode &snode, bNode &separate_bundle_node, - ReportList *reports); + ReportList *reports, + const bNodeSocket *src_bundle_socket = nullptr); void sync_sockets_combine_bundle(SpaceNode &snode, bNode &combine_bundle_node, - ReportList *reports); + ReportList *reports, + const bNodeSocket *src_bundle_socket = nullptr); void sync_sockets_closure(SpaceNode &snode, bNode &closure_input_node, bNode &closure_output_node, - ReportList *reports); + ReportList *reports, + const bNodeSocket *src_closure_socket = nullptr); } // namespace blender::nodes diff --git a/source/blender/nodes/geometry/nodes/node_geo_closure.cc b/source/blender/nodes/geometry/nodes/node_geo_closure.cc index ebeb2e94b27..f6b4d372f26 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_closure.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_closure.cc @@ -181,6 +181,20 @@ static void node_free_storage(bNode *node) static bool node_insert_link(bke::NodeInsertLinkParams ¶ms) { + if (params.C && params.link.fromnode == ¶ms.node) { + const NodeGeometryClosureOutput &storage = node_storage(params.node); + if (storage.input_items.items_num == 0 && storage.output_items.items_num == 0) { + SpaceNode *snode = CTX_wm_space_node(params.C); + if (snode && snode->edittree == ¶ms.ntree) { + bNode *input_node = bke::zone_type_by_node_type(GEO_NODE_CLOSURE_OUTPUT) + ->get_corresponding_input(params.ntree, params.node); + if (input_node) { + sync_sockets_closure(*snode, *input_node, params.node, nullptr, params.link.tosock); + } + } + } + return true; + } return socket_items::try_add_item_via_any_extend_socket( params.ntree, params.node, params.node, params.link); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_combine_bundle.cc b/source/blender/nodes/geometry/nodes/node_geo_combine_bundle.cc index a7de6c9483b..eb138ed9e19 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_combine_bundle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_combine_bundle.cc @@ -67,6 +67,16 @@ static void node_free_storage(bNode *node) static bool node_insert_link(bke::NodeInsertLinkParams ¶ms) { + if (params.C && params.link.fromnode == ¶ms.node) { + const NodeGeometryCombineBundle &storage = node_storage(params.node); + if (storage.items_num == 0) { + SpaceNode *snode = CTX_wm_space_node(params.C); + if (snode && snode->edittree == ¶ms.ntree) { + sync_sockets_combine_bundle(*snode, params.node, nullptr, params.link.tosock); + } + } + return true; + } return socket_items::try_add_item_via_any_extend_socket( params.ntree, params.node, params.node, params.link); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_evaluate_closure.cc b/source/blender/nodes/geometry/nodes/node_geo_evaluate_closure.cc index 3b170704aee..7f76f1df2a8 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_evaluate_closure.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_evaluate_closure.cc @@ -77,6 +77,16 @@ static void node_free_storage(bNode *node) static bool node_insert_link(bke::NodeInsertLinkParams ¶ms) { if (params.link.tonode == ¶ms.node) { + if (params.link.tosock == params.node.inputs.first) { + const NodeGeometryEvaluateClosure &storage = node_storage(params.node); + if (storage.input_items.items_num == 0 && storage.output_items.items_num == 0) { + SpaceNode *snode = CTX_wm_space_node(params.C); + if (snode && snode->edittree == ¶ms.ntree) { + sync_sockets_evaluate_closure(*snode, params.node, nullptr, params.link.fromsock); + } + } + return true; + } return socket_items::try_add_item_via_any_extend_socket( params.ntree, params.node, params.node, params.link); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_bundle.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_bundle.cc index 08d1a308b8e..f16b2b5dd3b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_separate_bundle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_separate_bundle.cc @@ -71,6 +71,16 @@ static void node_free_storage(bNode *node) static bool node_insert_link(bke::NodeInsertLinkParams ¶ms) { + if (params.C && params.link.tonode == ¶ms.node) { + const NodeGeometrySeparateBundle &storage = node_storage(params.node); + if (storage.items_num == 0) { + SpaceNode *snode = CTX_wm_space_node(params.C); + if (snode && snode->edittree == ¶ms.ntree) { + sync_sockets_separate_bundle(*snode, params.node, nullptr, params.link.fromsock); + } + } + return true; + } return socket_items::try_add_item_via_any_extend_socket( params.ntree, params.node, params.node, params.link); } diff --git a/source/blender/nodes/intern/sync_sockets.cc b/source/blender/nodes/intern/sync_sockets.cc index 5ce82b6eeaf..5c6789bc194 100644 --- a/source/blender/nodes/intern/sync_sockets.cc +++ b/source/blender/nodes/intern/sync_sockets.cc @@ -53,18 +53,22 @@ struct ClosureSyncState { std::optional source_signature; }; -static BundleSyncState get_sync_state_separate_bundle(const SpaceNode &snode, - const bNode &separate_bundle_node) +static BundleSyncState get_sync_state_separate_bundle( + const SpaceNode &snode, + const bNode &separate_bundle_node, + const bNodeSocket *src_bundle_socket = nullptr) { BLI_assert(separate_bundle_node.is_type("GeometryNodeSeparateBundle")); snode.edittree->ensure_topology_cache(); - const bNodeSocket &bundle_socket = separate_bundle_node.input_socket(0); + if (!src_bundle_socket) { + src_bundle_socket = &separate_bundle_node.input_socket(0); + } bke::ComputeContextCache compute_context_cache; const ComputeContext *current_context = ed::space_node::compute_context_for_edittree_socket( - snode, compute_context_cache, bundle_socket); + snode, compute_context_cache, *src_bundle_socket); const Vector source_signatures = gather_linked_origin_bundle_signatures( - current_context, bundle_socket, compute_context_cache); + current_context, *src_bundle_socket, compute_context_cache); if (source_signatures.is_empty()) { return {NodeSyncState::NoSyncSource}; } @@ -80,18 +84,22 @@ static BundleSyncState get_sync_state_separate_bundle(const SpaceNode &snode, return {NodeSyncState::Synced}; } -static BundleSyncState get_sync_state_combine_bundle(const SpaceNode &snode, - const bNode &combine_bundle_node) +static BundleSyncState get_sync_state_combine_bundle( + const SpaceNode &snode, + const bNode &combine_bundle_node, + const bNodeSocket *src_bundle_socket = nullptr) { BLI_assert(combine_bundle_node.is_type("GeometryNodeCombineBundle")); snode.edittree->ensure_topology_cache(); - const bNodeSocket &bundle_socket = combine_bundle_node.output_socket(0); + if (!src_bundle_socket) { + src_bundle_socket = &combine_bundle_node.output_socket(0); + } bke::ComputeContextCache compute_context_cache; const ComputeContext *current_context = ed::space_node::compute_context_for_edittree_socket( - snode, compute_context_cache, bundle_socket); + snode, compute_context_cache, *src_bundle_socket); const Vector source_signatures = gather_linked_target_bundle_signatures( - current_context, bundle_socket, compute_context_cache); + current_context, *src_bundle_socket, compute_context_cache); if (source_signatures.is_empty()) { return {NodeSyncState::NoSyncSource}; } @@ -107,18 +115,22 @@ static BundleSyncState get_sync_state_combine_bundle(const SpaceNode &snode, return {NodeSyncState::Synced}; } -static ClosureSyncState get_sync_state_closure_output(const SpaceNode &snode, - const bNode &closure_output_node) +static ClosureSyncState get_sync_state_closure_output( + const SpaceNode &snode, + const bNode &closure_output_node, + const bNodeSocket *src_closure_socket = nullptr) { snode.edittree->ensure_topology_cache(); - const bNodeSocket &closure_socket = closure_output_node.output_socket(0); + if (!src_closure_socket) { + src_closure_socket = &closure_output_node.output_socket(0); + } bke::ComputeContextCache compute_context_cache; const ComputeContext *current_context = ed::space_node::compute_context_for_edittree_socket( - snode, compute_context_cache, closure_socket); + snode, compute_context_cache, *src_closure_socket); const Vector source_signatures = gather_linked_target_closure_signatures( - current_context, closure_socket, compute_context_cache); + current_context, *src_closure_socket, compute_context_cache); if (source_signatures.is_empty()) { return {NodeSyncState::NoSyncSource}; } @@ -134,18 +146,22 @@ static ClosureSyncState get_sync_state_closure_output(const SpaceNode &snode, return {NodeSyncState::Synced}; } -static ClosureSyncState get_sync_state_evaluate_closure(const SpaceNode &snode, - const bNode &evaluate_closure_node) +static ClosureSyncState get_sync_state_evaluate_closure( + const SpaceNode &snode, + const bNode &evaluate_closure_node, + const bNodeSocket *src_closure_socket = nullptr) { snode.edittree->ensure_topology_cache(); - const bNodeSocket &closure_socket = evaluate_closure_node.input_socket(0); + if (!src_closure_socket) { + src_closure_socket = &evaluate_closure_node.input_socket(0); + } bke::ComputeContextCache compute_context_cache; const ComputeContext *current_context = ed::space_node::compute_context_for_edittree_socket( - snode, compute_context_cache, closure_socket); + snode, compute_context_cache, *src_closure_socket); const Vector source_signatures = gather_linked_origin_closure_signatures( - current_context, closure_socket, compute_context_cache); + current_context, *src_closure_socket, compute_context_cache); if (source_signatures.is_empty()) { return {NodeSyncState::NoSyncSource}; } @@ -163,9 +179,11 @@ static ClosureSyncState get_sync_state_evaluate_closure(const SpaceNode &snode, void sync_sockets_separate_bundle(SpaceNode &snode, bNode &separate_bundle_node, - ReportList *reports) + ReportList *reports, + const bNodeSocket *src_bundle_socket) { - const BundleSyncState sync_state = get_sync_state_separate_bundle(snode, separate_bundle_node); + const BundleSyncState sync_state = get_sync_state_separate_bundle( + snode, separate_bundle_node, src_bundle_socket); switch (sync_state.state) { case NodeSyncState::Synced: return; @@ -200,9 +218,13 @@ void sync_sockets_separate_bundle(SpaceNode &snode, BKE_ntree_update_tag_node_property(snode.edittree, &separate_bundle_node); } -void sync_sockets_combine_bundle(SpaceNode &snode, bNode &combine_bundle_node, ReportList *reports) +void sync_sockets_combine_bundle(SpaceNode &snode, + bNode &combine_bundle_node, + ReportList *reports, + const bNodeSocket *src_bundle_socket) { - const BundleSyncState sync_state = get_sync_state_combine_bundle(snode, combine_bundle_node); + const BundleSyncState sync_state = get_sync_state_combine_bundle( + snode, combine_bundle_node, src_bundle_socket); switch (sync_state.state) { case NodeSyncState::Synced: return; @@ -240,10 +262,11 @@ void sync_sockets_combine_bundle(SpaceNode &snode, bNode &combine_bundle_node, R void sync_sockets_evaluate_closure(SpaceNode &snode, bNode &evaluate_closure_node, - ReportList *reports) + ReportList *reports, + const bNodeSocket *src_closure_socket) { - const ClosureSyncState sync_state = get_sync_state_evaluate_closure(snode, - evaluate_closure_node); + const ClosureSyncState sync_state = get_sync_state_evaluate_closure( + snode, evaluate_closure_node, src_closure_socket); switch (sync_state.state) { case NodeSyncState::Synced: return; @@ -297,9 +320,11 @@ void sync_sockets_evaluate_closure(SpaceNode &snode, void sync_sockets_closure(SpaceNode &snode, bNode &closure_input_node, bNode &closure_output_node, - ReportList *reports) + ReportList *reports, + const bNodeSocket *src_closure_socket) { - const ClosureSyncState sync_state = get_sync_state_closure_output(snode, closure_output_node); + const ClosureSyncState sync_state = get_sync_state_closure_output( + snode, closure_output_node, src_closure_socket); switch (sync_state.state) { case NodeSyncState::Synced: return; diff --git a/source/blender/nodes/intern/trace_values.cc b/source/blender/nodes/intern/trace_values.cc index b12ae8d8357..7b183a038d0 100644 --- a/source/blender/nodes/intern/trace_values.cc +++ b/source/blender/nodes/intern/trace_values.cc @@ -8,6 +8,7 @@ #include "NOD_geometry_nodes_closure_location.hh" #include "NOD_geometry_nodes_closure_signature.hh" #include "NOD_node_in_compute_context.hh" +#include "NOD_trace_values.hh" #include "BKE_compute_context_cache.hh" #include "BKE_node_tree_zones.hh"