Geometry Nodes: improve link-drag-search for bundle and closure nodes

This adds support for creating Combine Bundle, Separate Bundle and Evaluate Closure
nodes using link drag search in some cases that were not previously supported.

Pull Request: https://projects.blender.org/blender/blender/pulls/143835
This commit is contained in:
Jacques Lucke
2025-08-02 14:09:06 +02:00
parent 69dee02d4f
commit f271a48b6b
5 changed files with 98 additions and 35 deletions

View File

@@ -56,6 +56,8 @@ class LinkSearchOpParams {
* and connect it to the socket the link drag started from (#socket).
*/
void connect_available_socket(bNode &new_node, StringRef socket_name);
void connect_available_socket_by_identifier(bNode &new_node, StringRef socket_identifier);
void connect_socket(bNode &new_node, bNodeSocket &new_socket);
/**
* Like #connect_available_socket, but also calls the node's update function.
*/

View File

@@ -138,20 +138,32 @@ static void node_geo_exec(GeoNodeExecParams params)
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
{
const bNodeSocket &other_socket = params.other_socket();
if (other_socket.type != SOCK_BUNDLE) {
return;
}
if (other_socket.in_out == SOCK_OUT) {
return;
if (!CombineBundleItemsAccessor::supports_socket_type(other_socket.typeinfo->type,
params.node_tree().type))
{
return;
}
params.add_item("Item", [](LinkSearchOpParams &params) {
bNode &node = params.add_node("NodeCombineBundle");
const auto *item =
socket_items::add_item_with_socket_type_and_name<CombineBundleItemsAccessor>(
params.node_tree, node, params.socket.typeinfo->type, params.socket.name);
params.update_and_connect_available_socket(node, item->name);
});
}
else {
if (other_socket.type != SOCK_BUNDLE) {
return;
}
params.add_item("Bundle", [](LinkSearchOpParams &params) {
bNode &node = params.add_node("NodeCombineBundle");
params.connect_available_socket(node, "Bundle");
params.add_item("Bundle", [](LinkSearchOpParams &params) {
bNode &node = params.add_node("NodeCombineBundle");
params.connect_available_socket(node, "Bundle");
SpaceNode &snode = *CTX_wm_space_node(&params.C);
sync_sockets_combine_bundle(snode, node, nullptr);
});
SpaceNode &snode = *CTX_wm_space_node(&params.C);
sync_sockets_combine_bundle(snode, node, nullptr);
});
}
}
static void node_blend_write(const bNodeTree & /*tree*/, const bNode &node, BlendWriter &writer)

View File

@@ -136,20 +136,41 @@ static const bNodeSocket *node_internally_linked_input(const bNodeTree & /*tree*
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
{
const bNodeSocket &other_socket = params.other_socket();
if (other_socket.type != SOCK_CLOSURE) {
return;
}
if (other_socket.in_out == SOCK_IN) {
params.add_item("Item", [](LinkSearchOpParams &params) {
bNode &node = params.add_node("NodeEvaluateClosure");
const auto *item =
socket_items::add_item_with_socket_type_and_name<EvaluateClosureOutputItemsAccessor>(
params.node_tree, node, params.socket.typeinfo->type, params.socket.name);
params.update_and_connect_available_socket(node, item->name);
});
return;
}
if (other_socket.type == SOCK_CLOSURE) {
params.add_item("Closure", [](LinkSearchOpParams &params) {
bNode &node = params.add_node("NodeEvaluateClosure");
params.connect_available_socket(node, "Closure");
params.add_item("Closure", [](LinkSearchOpParams &params) {
bNode &node = params.add_node("NodeEvaluateClosure");
params.connect_available_socket(node, "Closure");
SpaceNode &snode = *CTX_wm_space_node(&params.C);
sync_sockets_evaluate_closure(snode, node, nullptr);
});
SpaceNode &snode = *CTX_wm_space_node(&params.C);
sync_sockets_evaluate_closure(snode, node, nullptr);
});
}
if (EvaluateClosureInputItemsAccessor::supports_socket_type(other_socket.typeinfo->type,
params.node_tree().type))
{
params.add_item(
"Item",
[](LinkSearchOpParams &params) {
bNode &node = params.add_node("NodeEvaluateClosure");
const auto *item =
socket_items::add_item_with_socket_type_and_name<EvaluateClosureInputItemsAccessor>(
params.node_tree, node, params.socket.typeinfo->type, params.socket.name);
nodes::update_node_declaration_and_sockets(params.node_tree, node);
params.connect_available_socket_by_identifier(
node, EvaluateClosureInputItemsAccessor::socket_identifier_for_item(*item));
},
other_socket.type == SOCK_CLOSURE ? -1 : 0);
}
}
static void node_operators()

View File

@@ -185,20 +185,32 @@ static void node_geo_exec(GeoNodeExecParams params)
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
{
const bNodeSocket &other_socket = params.other_socket();
if (other_socket.type != SOCK_BUNDLE) {
return;
}
if (other_socket.in_out == SOCK_IN) {
return;
if (!SeparateBundleItemsAccessor::supports_socket_type(other_socket.typeinfo->type,
params.node_tree().type))
{
return;
}
params.add_item("Item", [](LinkSearchOpParams &params) {
bNode &node = params.add_node("NodeSeparateBundle");
const auto *item =
socket_items::add_item_with_socket_type_and_name<SeparateBundleItemsAccessor>(
params.node_tree, node, params.socket.typeinfo->type, params.socket.name);
params.update_and_connect_available_socket(node, item->name);
});
}
else {
if (other_socket.type != SOCK_BUNDLE) {
return;
}
params.add_item("Bundle", [](LinkSearchOpParams &params) {
bNode &node = params.add_node("NodeSeparateBundle");
params.connect_available_socket(node, "Bundle");
params.add_item("Bundle", [](LinkSearchOpParams &params) {
bNode &node = params.add_node("NodeSeparateBundle");
params.connect_available_socket(node, "Bundle");
SpaceNode &snode = *CTX_wm_space_node(&params.C);
sync_sockets_separate_bundle(snode, node, nullptr);
});
SpaceNode &snode = *CTX_wm_space_node(&params.C);
sync_sockets_separate_bundle(snode, node, nullptr);
});
}
}
static void node_blend_write(const bNodeTree & /*tree*/, const bNode &node, BlendWriter &writer)

View File

@@ -4,6 +4,7 @@
#include <fmt/format.h>
#include "BLI_listbase.h"
#include "BLI_set.hh"
#include "BKE_context.hh"
@@ -72,11 +73,26 @@ void LinkSearchOpParams::connect_available_socket(bNode &new_node, StringRef soc
BLI_assert_unreachable();
return;
}
bke::node_add_link(node_tree, new_node, *new_node_socket, node, socket);
if (in_out == SOCK_OUT) {
this->connect_socket(new_node, *new_node_socket);
}
void LinkSearchOpParams::connect_available_socket_by_identifier(bNode &new_node,
const StringRef socket_identifier)
{
const eNodeSocketInOut in_out = this->socket.in_out == SOCK_IN ? SOCK_OUT : SOCK_IN;
bNodeSocket *new_node_socket = bke::node_find_socket(new_node, in_out, socket_identifier);
BLI_assert(new_node_socket);
this->connect_socket(new_node, *new_node_socket);
}
void LinkSearchOpParams::connect_socket(bNode &new_node, bNodeSocket &new_socket)
{
bke::node_add_link(this->node_tree, new_node, new_socket, this->node, this->socket);
if (new_socket.in_out == SOCK_OUT) {
/* If the old socket already contained a value, then transfer it to a new one, from
* which this value will get there. */
bke::node_socket_move_default_value(*CTX_data_main(&C), node_tree, socket, *new_node_socket);
bke::node_socket_move_default_value(
*CTX_data_main(&C), this->node_tree, this->socket, new_socket);
}
}