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

Merged
Hans Goudey merged 17 commits from mod_moder/blender:move_value_by_link into main 2023-04-03 19:33:49 +02:00
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);
mod_moder marked this conversation as resolved Outdated

Sorry I should have found this this last time. I tried to update your PR directly but couldn't quite figure it out. This comment is a bit out of date. How about this?

/**
 * Move socket default from \a src to locations specified by \a dst (potentially multiple group
 * nodes socket values, if \a dst is a group input node).
 */
Sorry I should have found this this last time. I tried to update your PR directly but couldn't quite figure it out. This comment is a bit out of date. How about this? ``` /** * Move socket default from \a src to locations specified by \a dst (potentially multiple group * nodes socket values, if \a dst is a group input node). */ ```

I was thinking about expanding with a description of the cases that may now be.
But given the plans to expand this functionality, is it correct to talk about it in a comment in header file?

I was thinking about expanding with a description of the cases that may now be. But given the plans to expand this functionality, is it correct to talk about it in a comment in header file?

Maybe not, it's fine to keep it simple too. It's just nice to clarify that it doesn't just move to dst's default value

Maybe not, it's fine to keep it simple too. It's just nice to clarify that it doesn't _just_ move to dst's default value
/**
* 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()) {
mod_moder marked this conversation as resolved Outdated

Better to find the socket with the identifier in case we change group nodes to not store all the (hidden) sockets in the future.

Better to find the socket with the identifier in case we change group nodes to not store all the (hidden) sockets in the future.

There is some confusion here, it seems.
Hidden sockets that are inaccessible to built-in nodes will be deleted.
But if the user just doesn't want to see them, we shouldn't want to delete them, does it seem redundant that the node declaration store the hidden states for all sockets of all nodes?
So, for group nodes, created sockets will always exist..

There is some confusion here, it seems. Hidden sockets that are inaccessible to built-in nodes will be deleted. But if the user just doesn't want to see them, we shouldn't want to delete them, does it seem redundant that the node declaration store the hidden states for all sockets of all nodes? So, for group nodes, created sockets will always exist..

My point is, it's just less fragile to use identifiers rather than indices, and it gives us more flexibility in the future, for very little downside.

My point is, it's just less fragile to use identifiers rather than indices, and it gives us more flexibility in the future, for very little downside.
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)