Fix #106208: data-block socket defaults not used for node group #107179

Merged
Jacques Lucke merged 5 commits from JacquesLucke/blender:node-group-default-id into main 2023-04-20 22:27:58 +02:00
3 changed files with 78 additions and 15 deletions

View File

@ -158,6 +158,12 @@ class StringBuilder : public SocketDeclarationBuilder<String> {
class IDSocketDeclaration : public SocketDeclaration {
public:
const char *idname;
/**

Maybe add , since bNode::idpointers are remapped asID pointers change, but pointers in socket declarations are not managed the same way.

Maybe add `, since `bNode::id` pointers are remapped as `ID` pointers change, but pointers in socket declarations are not managed the same way.`
* Get the default ID pointer for this socket. This is a function to avoid dangling pointers,
* since bNode::id pointers are remapped as ID pointers change, but pointers in socket
* declarations are not managed the same way.
*/
std::function<ID *(const bNode &node)> default_value_fn;
public:
IDSocketDeclaration(const char *idname);

View File

@ -124,7 +124,41 @@ bool nodeGroupPoll(const bNodeTree *nodetree,
namespace blender::nodes {
static SocketDeclarationPtr declaration_for_interface_socket(const bNodeSocket &io_socket)
static std::function<ID *(const bNode &node)> get_default_id_getter(const bNodeTree &ntree,
const bNodeSocket &io_socket)
{
const int socket_index = io_socket.in_out == SOCK_IN ? BLI_findindex(&ntree.inputs, &io_socket) :
BLI_findindex(&ntree.outputs, &io_socket);
/* Avoid capturing pointers that can become dangling. */
return [in_out = io_socket.in_out, socket_index](const bNode &node) -> ID * {
if (node.id == nullptr) {
return nullptr;
}
if (GS(node.id->name) != ID_NT) {
return nullptr;
}
const bNodeTree &ntree = *reinterpret_cast<const bNodeTree *>(node.id);
const bNodeSocket *io_socket;
if (in_out == SOCK_IN) {
/* Better be safe than sorry when the underlying node group changed. */

Hmm, why would the socket index be out of bounds here? Does this function object live past some changes to the group interface? If so, maybe worth noting that in a comment.

Hmm, why would the socket index be out of bounds here? Does this function object live past some changes to the group interface? If so, maybe worth noting that in a comment.

The problem is, I don't think we know for sure how long this will live currently. At least I don't know.

The problem is, I don't think we know for sure how long this will live currently. At least I don't know.

save -> safe

`save` -> `safe`
if (socket_index < ntree.interface_inputs().size()) {
io_socket = ntree.interface_inputs()[socket_index];
}
}
else {
if (socket_index < ntree.interface_outputs().size()) {
io_socket = ntree.interface_outputs()[socket_index];
}
}
if (io_socket == nullptr) {
return nullptr;
}
return *static_cast<ID **>(io_socket->default_value);
};
}
static SocketDeclarationPtr declaration_for_interface_socket(const bNodeTree &ntree,
const bNodeSocket &io_socket)
{
SocketDeclarationPtr dst;
switch (io_socket.type) {
@ -184,24 +218,39 @@ static SocketDeclarationPtr declaration_for_interface_socket(const bNodeSocket &
dst = std::move(decl);
break;
}
case SOCK_OBJECT:
dst = std::make_unique<decl::Object>();
case SOCK_OBJECT: {
auto value = std::make_unique<decl::Object>();
value->default_value_fn = get_default_id_getter(ntree, io_socket);
dst = std::move(value);
break;
case SOCK_IMAGE:
dst = std::make_unique<decl::Image>();
}
case SOCK_IMAGE: {
auto value = std::make_unique<decl::Image>();
value->default_value_fn = get_default_id_getter(ntree, io_socket);
dst = std::move(value);
break;
}
case SOCK_GEOMETRY:
dst = std::make_unique<decl::Geometry>();
break;
case SOCK_COLLECTION:
dst = std::make_unique<decl::Collection>();
case SOCK_COLLECTION: {
auto value = std::make_unique<decl::Collection>();
value->default_value_fn = get_default_id_getter(ntree, io_socket);
dst = std::move(value);
break;
case SOCK_TEXTURE:
dst = std::make_unique<decl::Texture>();
}
case SOCK_TEXTURE: {
auto value = std::make_unique<decl::Texture>();
value->default_value_fn = get_default_id_getter(ntree, io_socket);
dst = std::move(value);
break;
case SOCK_MATERIAL:
dst = std::make_unique<decl::Material>();
}
case SOCK_MATERIAL: {
auto value = std::make_unique<decl::Material>();
value->default_value_fn = get_default_id_getter(ntree, io_socket);
dst = std::move(value);
break;
}
case SOCK_CUSTOM:
std::unique_ptr<decl::Custom> decl = std::make_unique<decl::Custom>();
decl->idname_ = io_socket.idname;
@ -232,10 +281,10 @@ void node_group_declare_dynamic(const bNodeTree & /*node_tree*/,
r_declaration.skip_updating_sockets = false;
LISTBASE_FOREACH (const bNodeSocket *, input, &group->inputs) {
r_declaration.inputs.append(declaration_for_interface_socket(*input));
r_declaration.inputs.append(declaration_for_interface_socket(*group, *input));
}
LISTBASE_FOREACH (const bNodeSocket *, output, &group->outputs) {
r_declaration.outputs.append(declaration_for_interface_socket(*output));
r_declaration.outputs.append(declaration_for_interface_socket(*group, *output));
}
}
@ -450,7 +499,7 @@ static void group_input_declare_dynamic(const bNodeTree &node_tree,
NodeDeclaration &r_declaration)
{
LISTBASE_FOREACH (const bNodeSocket *, input, &node_tree.inputs) {
r_declaration.outputs.append(declaration_for_interface_socket(*input));
r_declaration.outputs.append(declaration_for_interface_socket(node_tree, *input));
r_declaration.outputs.last()->in_out = SOCK_OUT;
}
r_declaration.outputs.append(extend_declaration(SOCK_OUT));
@ -461,7 +510,7 @@ static void group_output_declare_dynamic(const bNodeTree &node_tree,
NodeDeclaration &r_declaration)
{
LISTBASE_FOREACH (const bNodeSocket *, input, &node_tree.outputs) {
r_declaration.inputs.append(declaration_for_interface_socket(*input));
r_declaration.inputs.append(declaration_for_interface_socket(node_tree, *input));
r_declaration.inputs.last()->in_out = SOCK_IN;
}
r_declaration.inputs.append(extend_declaration(SOCK_IN));

View File

@ -3,6 +3,7 @@
#include "NOD_socket_declarations.hh"
#include "NOD_socket_declarations_geometry.hh"
#include "BKE_lib_id.h"
#include "BKE_node.h"
#include "BKE_node_runtime.hh"
@ -435,6 +436,13 @@ bNodeSocket &IDSocketDeclaration::build(bNodeTree &ntree, bNode &node) const
{
bNodeSocket &socket = *nodeAddSocket(
&ntree, &node, this->in_out, this->idname, this->identifier.c_str(), this->name.c_str());
if (this->default_value_fn) {
ID *id = this->default_value_fn(node);
/* Assumes that all ID sockets like #bNodeSocketValueObject and #bNodeSocketValueImage have the
* ID pointer at the start of the struct. */
*static_cast<ID **>(socket.default_value) = id;

C-style cast here

C-style cast here
id_us_plus(id);
}
this->set_common_flags(socket);
return socket;
}