Nodes: Move data-block default values with link drag search

When creating nodes by dragging a link, it can be convenient to
transfer values from input socket. For reference values, like images,
this may be necessary to avoid unnecessary data-block users. This
patch starts adding such a system. At this moment this only makes sense
for one node (Image Input), but this can be extended to work with other
reference types, different non-reference types and support auto-casting
(if a float is transferred to the Integer Input node).

See task: https://projects.blender.org/blender/blender/issues/102854
Original patch: https://archive.blender.org/developer/D16735

Pull Request: https://projects.blender.org/blender/blender/pulls/105972
This commit is contained in:
illua1 2023-04-03 19:33:39 +02:00 committed by Hans Goudey
parent e7f395dd20
commit 9726e4a0ad
4 changed files with 109 additions and 0 deletions

View File

@ -735,6 +735,18 @@ bNode *node_copy_with_mapping(bNodeTree *dst_tree,
bNode *node_copy(bNodeTree *dst_tree, const bNode &src_node, int flag, bool use_unique);
/**
* Move socket default from \a src (input socket) to locations specified by \a dst (output socket).
* Result value moved in specific location. (potentially multiple group nodes socket values, if \a
* dst is a group input node).
* \note Conceptually, the effect should be such that the evaluation of
* this graph again returns the value in src.
*/
void node_socket_move_default_value(Main &bmain,
bNodeTree &tree,
bNodeSocket &src,
bNodeSocket &dst);
/**
* Free the node itself.
*

View File

@ -2403,6 +2403,94 @@ bNode *node_copy_with_mapping(bNodeTree *dst_tree,
return node_dst;
}
static void for_each_node_group_instance(Main &bmain,
const bNodeTree &node_group,
const Span<int> tree_types_to_lookup,
const FunctionRef<void(bNode &)> func)
{
LISTBASE_FOREACH (bNodeTree *, other_group, &bmain.nodetrees) {
if (!tree_types_to_lookup.contains(other_group->type)) {
continue;
}
if (other_group == &node_group) {
continue;
}
other_group->ensure_topology_cache();
for (bNode *node : other_group->group_nodes()) {
if (node->id == &node_group.id) {
func(*node);
}
}
}
}
void node_socket_move_default_value(Main &bmain,
bNodeTree &tree,
bNodeSocket &src,
bNodeSocket &dst)
{
tree.ensure_topology_cache();
bNode &dst_node = dst.owner_node();
bNode &src_node = src.owner_node();
if (src.is_multi_input()) {
/* Multi input sockets no have value. */
return;
}
if (ELEM(NODE_REROUTE, dst_node.type, src_node.type)) {
/* Reroute node can't have ownership of socket value directly. */
return;
}
if (dst.type != src.type) {
/* It could be possible to support conversion in future. */
return;
}
ID **src_socket_value = nullptr;
Vector<ID **> dst_values;
switch (dst.type) {
case SOCK_IMAGE: {
Image **tmp_socket_value = &src.default_value_typed<bNodeSocketValueImage>()->value;
src_socket_value = reinterpret_cast<ID **>(tmp_socket_value);
if (*src_socket_value == nullptr) {
break;
}
switch (dst_node.type) {
case GEO_NODE_IMAGE: {
dst_values.append(&dst_node.id);
break;
}
case NODE_GROUP_INPUT: {
for_each_node_group_instance(bmain, tree, {NTREE_GEOMETRY}, [&](bNode &node_group) {
bNodeSocket &socket = node_group.input_by_identifier(dst.identifier);
Image **tmp_dst_value = &socket.default_value_typed<bNodeSocketValueImage>()->value;
dst_values.append(reinterpret_cast<ID **>(tmp_dst_value));
});
break;
}
default: {
break;
}
}
break;
}
default: {
break;
}
}
for (ID **dst_value : dst_values) {
*dst_value = *src_socket_value;
id_us_plus(*dst_value);
}
id_us_min(*src_socket_value);
*src_socket_value = nullptr;
}
bNode *node_copy(bNodeTree *dst_tree, const bNode &src_node, const int flag, const bool use_unique)
{
Map<const bNodeSocket *, bNodeSocket *> socket_map;

View File

@ -114,6 +114,9 @@ static void add_group_input_node_fn(nodes::LinkSearchOpParams &params)
/* Unhide the socket for the new input in the new node and make a connection to it. */
socket->flag &= ~SOCK_HIDDEN;
nodeAddLink(&params.node_tree, &group_input, socket, &params.node, &params.socket);
bke::node_socket_move_default_value(
*CTX_data_main(&params.C), params.node_tree, params.socket, *socket);
}
static void add_existing_group_input_fn(nodes::LinkSearchOpParams &params,

View File

@ -2,6 +2,7 @@
#include "BLI_set.hh"
#include "BKE_context.h"
#include "BKE_node.h"
#include "UI_interface.h"
@ -55,6 +56,11 @@ void LinkSearchOpParams::connect_available_socket(bNode &new_node, StringRef soc
return;
}
nodeAddLink(&node_tree, &new_node, new_node_socket, &node, &socket);
if (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);
}
}
bNode &LinkSearchOpParams::add_node(StringRef idname)