Fix #106208: Initialize socket value by declaration callback if value is data block #106816

Closed
Iliya Katushenock wants to merge 4 commits from mod_moder:default_value_cb into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
3 changed files with 96 additions and 10 deletions
Showing only changes of commit 78164f1edc - Show all commits

View File

@ -7,8 +7,11 @@
#include "RNA_types.h"
#include "BLI_color.hh"
#include "BLI_function_ref.hh"
#include "BLI_math_vector_types.hh"
using BlenderObjectPtr = Object *;
namespace blender::nodes::decl {
class FloatBuilder;
@ -162,22 +165,53 @@ class IDSocketDeclaration : public SocketDeclaration {
public:
IDSocketDeclaration(const char *idname);
virtual void construct_default_value(bNode &node, bNodeSocket &socket) const = 0;
bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
bNodeSocket &update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const override;
bool can_connect(const bNodeSocket &socket) const override;
};
class ObjectBuilder;
class Object : public IDSocketDeclaration {
public:
using Builder = SocketDeclarationBuilder<Object>;
std::function<BlenderObjectPtr(const bNode *node)> object_cb;
void construct_default_value(bNode &node, bNodeSocket &socket) const
{
printf("1!\n");
if (!this->object_cb) {
return;
}
printf("2!\n");
printf("%p, %p, %p;\n", &socket, this->object_cb(&node), nullptr);
printf("3!\n");
socket.default_value_typed<bNodeSocketValueObject>()->value = this->object_cb(&node);
printf("4!\n");
}
friend ObjectBuilder;
public:
using Builder = ObjectBuilder;
Object();
};
class ObjectBuilder : public SocketDeclarationBuilder<Object> {
public:
ObjectBuilder &default_value_cb(std::function<BlenderObjectPtr(const bNode *node)> object_cb);
};
class Material : public IDSocketDeclaration {
public:
using Builder = SocketDeclarationBuilder<Material>;
void construct_default_value(bNode & /*node*/, bNodeSocket & /*socket*/) const
{
return;
}
Material();
};
@ -185,6 +219,10 @@ class Material : public IDSocketDeclaration {
class Collection : public IDSocketDeclaration {
public:
using Builder = SocketDeclarationBuilder<Collection>;
void construct_default_value(bNode & /*node*/, bNodeSocket & /*socket*/) const
{
return;
}
Collection();
};
@ -192,6 +230,10 @@ class Collection : public IDSocketDeclaration {
class Texture : public IDSocketDeclaration {
public:
using Builder = SocketDeclarationBuilder<Texture>;
void construct_default_value(bNode & /*node*/, bNodeSocket & /*socket*/) const
{
return;
}
Texture();
};
@ -199,7 +241,10 @@ class Texture : public IDSocketDeclaration {
class Image : public IDSocketDeclaration {
public:
using Builder = SocketDeclarationBuilder<Image>;
void construct_default_value(bNode & /*node*/, bNodeSocket & /*socket*/) const
{
return;
}
Image();
};
@ -367,6 +412,19 @@ inline ColorBuilder &ColorBuilder::default_value(const ColorGeometry4f value)
/** \} */
/* -------------------------------------------------------------------- */
/** \name #ColorBuilder Inline Methods
* \{ */
inline ObjectBuilder &ObjectBuilder::default_value_cb(
std::function<BlenderObjectPtr(const bNode *node)> object_cb)
{
decl_->object_cb = std::move(object_cb);
return *this;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name #StringBuilder Inline Methods
* \{ */

View File

@ -124,8 +124,10 @@ bool nodeGroupPoll(const bNodeTree *nodetree,
namespace blender::nodes {
static SocketDeclarationPtr declaration_for_interface_socket(const bNodeSocket &io_socket)
static SocketDeclarationPtr declaration_for_interface_socket(const bNodeSocket &io_socket,
const bNodeTree *node_group)
{
printf("= %p;\n", node_group);
SocketDeclarationPtr dst;
switch (io_socket.type) {
case SOCK_FLOAT: {
Review

I agree that we need to avoid ID pointers in the declarations. But this solves one problem by creating another: Now we have the bNodeTree bound in the callback.

A weak pointer of some kind seems to be needed here, so that ID management code does not have to worry about references stored in node declarations.

I agree that we need to avoid ID pointers in the declarations. But this solves one problem by creating another: Now we have the `bNodeTree` bound in the callback. A weak pointer of some kind seems to be needed here, so that ID management code does not have to worry about references stored in node declarations.

Trees cause refresh on their own. That is, it must be safe.
It would be possible to add a requirement to the topology cache in order to find a node from the socket and take its pointer to the tree. But this can increase the overhead. Or we can pass a node. But at one point it may require also a tree as well ... there is not enough some context

Trees cause refresh on their own. That is, it must be safe. It would be possible to add a requirement to the topology cache in order to find a node from the socket and take its pointer to the tree. But this can increase the overhead. Or we can pass a node. But at one point it may require also a tree as well ... there is not enough some context
@ -184,9 +186,28 @@ static SocketDeclarationPtr declaration_for_interface_socket(const bNodeSocket &
dst = std::move(decl);
break;
}
case SOCK_OBJECT:
dst = std::make_unique<decl::Object>();
break;
case SOCK_OBJECT: {
std::unique_ptr<decl::Object> decl = std::make_unique<decl::Object>();
std::string socket_name = io_socket.name;
decl->object_cb =
[node_group, socket_name = std::move(socket_name)](const bNode * /*node*/) -> Object * {
printf(" - %p\n", node_group);
printf(" - 1\n");
if (node_group == nullptr) {
return nullptr;
}
printf(" - 2\n");
LISTBASE_FOREACH (const bNodeSocket *, input, &node_group->inputs) {
if (StringRef(input->name) == StringRef(socket_name)) {
return const_cast<Object *>(
input->default_value_typed<bNodeSocketValueObject>()->value);
}
}
printf(" - 3\n");
return nullptr;
};
dst = std::move(decl);
} break;
case SOCK_IMAGE:
dst = std::make_unique<decl::Image>();
break;
@ -232,10 +253,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(*input, group));
}
LISTBASE_FOREACH (const bNodeSocket *, output, &group->outputs) {
r_declaration.outputs.append(declaration_for_interface_socket(*output));
r_declaration.outputs.append(declaration_for_interface_socket(*output, group));
}
}
@ -450,7 +471,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(*input, &node_tree));
r_declaration.outputs.last()->in_out = SOCK_OUT;
}
r_declaration.outputs.append(extend_declaration(SOCK_OUT));
@ -461,7 +482,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(*input, &node_tree));
r_declaration.inputs.last()->in_out = SOCK_IN;
}
r_declaration.inputs.append(extend_declaration(SOCK_IN));

View File

@ -436,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());
this->set_common_flags(socket);
if (const auto *ptr = dynamic_cast<const Object *>(this)) {
printf("Start\n");
ptr->construct_default_value(node, socket);
printf("End\n");
}
return socket;
}