Fix #106208: Initialize socket value by declaration callback if value is data block #106816
|
@ -7,11 +7,8 @@
|
|||
#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;
|
||||
|
@ -161,68 +158,44 @@ class StringBuilder : public SocketDeclarationBuilder<String> {
|
|||
class IDSocketDeclaration : public SocketDeclaration {
|
||||
public:
|
||||
const char *idname;
|
||||
std::function<ID *(const bNodeSocket &socket)> init_socket_value_cd;
|
||||
|
||||
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;
|
||||
template<typename Declaration>
|
||||
class IDSocketDeclarationBuilder : public SocketDeclarationBuilder<Declaration> {
|
||||
public:
|
||||
IDSocketDeclarationBuilder &socket_value(
|
||||
std::function<ID *(const bNodeSocket &socket)> &&value_cb);
|
||||
};
|
||||
|
||||
class Object : public IDSocketDeclaration {
|
||||
public:
|
||||
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;
|
||||
friend IDSocketDeclarationBuilder<Object>;
|
||||
|
||||
public:
|
||||
using Builder = ObjectBuilder;
|
||||
using Builder = IDSocketDeclarationBuilder<Object>;
|
||||
|
||||
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;
|
||||
}
|
||||
using Builder = IDSocketDeclarationBuilder<Material>;
|
||||
|
||||
Material();
|
||||
};
|
||||
|
||||
class Collection : public IDSocketDeclaration {
|
||||
public:
|
||||
using Builder = SocketDeclarationBuilder<Collection>;
|
||||
void construct_default_value(bNode & /*node*/, bNodeSocket & /*socket*/) const
|
||||
{
|
||||
return;
|
||||
}
|
||||
using Builder = IDSocketDeclarationBuilder<Collection>;
|
||||
|
||||
Collection();
|
||||
};
|
||||
|
@ -230,10 +203,6 @@ class Collection : public IDSocketDeclaration {
|
|||
class Texture : public IDSocketDeclaration {
|
||||
public:
|
||||
using Builder = SocketDeclarationBuilder<Texture>;
|
||||
void construct_default_value(bNode & /*node*/, bNodeSocket & /*socket*/) const
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Texture();
|
||||
};
|
||||
|
@ -241,10 +210,7 @@ class Texture : public IDSocketDeclaration {
|
|||
class Image : public IDSocketDeclaration {
|
||||
public:
|
||||
using Builder = SocketDeclarationBuilder<Image>;
|
||||
void construct_default_value(bNode & /*node*/, bNodeSocket & /*socket*/) const
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Image();
|
||||
};
|
||||
|
||||
|
@ -416,10 +382,12 @@ 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)
|
||||
template<typename Declaration>
|
||||
inline IDSocketDeclarationBuilder<Declaration>
|
||||
&IDSocketDeclarationBuilder<Declaration>::socket_value(
|
||||
std::function<ID *(const bNodeSocket &socket)> &&value_cb)
|
||||
{
|
||||
decl_->object_cb = std::move(object_cb);
|
||||
decl_->init_socket_value_cd = std::move(value_cb);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include <cstddef>
|
||||
#include <cstring>
|
||||
|
||||
#include "DNA_collection_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_node_types.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
|
@ -124,10 +126,42 @@ bool nodeGroupPoll(const bNodeTree *nodetree,
|
|||
|
||||
namespace blender::nodes {
|
||||
|
||||
static std::function<ID *(const bNodeSocket &socket)> default_node_group_id_value(
|
||||
bNodeTree &node_group, StringRefNull socket_name_p)
|
||||
{
|
||||
std::string socket_name = socket_name_p;
|
||||
return [node_group = &node_group,
|
||||
|
||||
socket_name = std::move(socket_name)](const bNodeSocket & /*socket*/) -> ID * {
|
||||
LISTBASE_FOREACH (bNodeSocket *, input, &node_group->inputs) {
|
||||
if (StringRef(input->name) == StringRef(socket_name)) {
|
||||
switch (input->type) {
|
||||
case SOCK_OBJECT: {
|
||||
return &input->default_value_typed<bNodeSocketValueObject>()->value->id;
|
||||
}
|
||||
case SOCK_IMAGE: {
|
||||
return &input->default_value_typed<bNodeSocketValueImage>()->value->id;
|
||||
}
|
||||
case SOCK_TEXTURE: {
|
||||
return &input->default_value_typed<bNodeSocketValueTexture>()->value->id;
|
||||
}
|
||||
case SOCK_COLLECTION: {
|
||||
return &input->default_value_typed<bNodeSocketValueCollection>()->value->id;
|
||||
}
|
||||
case SOCK_MATERIAL: {
|
||||
return &input->default_value_typed<bNodeSocketValueMaterial>()->value->id;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
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: {
|
||||
|
@ -188,41 +222,62 @@ static SocketDeclarationPtr declaration_for_interface_socket(const bNodeSocket &
|
|||
}
|
||||
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;
|
||||
};
|
||||
if (node_group == nullptr) {
|
||||
dst = std::move(decl);
|
||||
break;
|
||||
}
|
||||
decl->init_socket_value_cd = default_node_group_id_value(
|
||||
*const_cast<bNodeTree *>(node_group), io_socket.name);
|
||||
dst = std::move(decl);
|
||||
} break;
|
||||
case SOCK_IMAGE:
|
||||
dst = std::make_unique<decl::Image>();
|
||||
break;
|
||||
}
|
||||
case SOCK_IMAGE: {
|
||||
std::unique_ptr<decl::Image> decl = std::make_unique<decl::Image>();
|
||||
if (node_group == nullptr) {
|
||||
dst = std::move(decl);
|
||||
break;
|
||||
}
|
||||
decl->init_socket_value_cd = default_node_group_id_value(
|
||||
*const_cast<bNodeTree *>(node_group), io_socket.name);
|
||||
dst = std::move(decl);
|
||||
break;
|
||||
}
|
||||
case SOCK_COLLECTION: {
|
||||
std::unique_ptr<decl::Collection> decl = std::make_unique<decl::Collection>();
|
||||
if (node_group == nullptr) {
|
||||
dst = std::move(decl);
|
||||
break;
|
||||
}
|
||||
decl->init_socket_value_cd = default_node_group_id_value(
|
||||
*const_cast<bNodeTree *>(node_group), io_socket.name);
|
||||
dst = std::move(decl);
|
||||
break;
|
||||
}
|
||||
case SOCK_TEXTURE: {
|
||||
std::unique_ptr<decl::Texture> decl = std::make_unique<decl::Texture>();
|
||||
if (node_group == nullptr) {
|
||||
dst = std::move(decl);
|
||||
break;
|
||||
}
|
||||
decl->init_socket_value_cd = default_node_group_id_value(
|
||||
*const_cast<bNodeTree *>(node_group), io_socket.name);
|
||||
dst = std::move(decl);
|
||||
break;
|
||||
}
|
||||
case SOCK_MATERIAL: {
|
||||
std::unique_ptr<decl::Material> decl = std::make_unique<decl::Material>();
|
||||
if (node_group == nullptr) {
|
||||
dst = std::move(decl);
|
||||
break;
|
||||
}
|
||||
decl->init_socket_value_cd = default_node_group_id_value(
|
||||
*const_cast<bNodeTree *>(node_group), io_socket.name);
|
||||
dst = std::move(decl);
|
||||
break;
|
||||
}
|
||||
case SOCK_GEOMETRY:
|
||||
dst = std::make_unique<decl::Geometry>();
|
||||
break;
|
||||
case SOCK_COLLECTION:
|
||||
dst = std::make_unique<decl::Collection>();
|
||||
break;
|
||||
case SOCK_TEXTURE:
|
||||
dst = std::make_unique<decl::Texture>();
|
||||
break;
|
||||
case SOCK_MATERIAL:
|
||||
dst = std::make_unique<decl::Material>();
|
||||
break;
|
||||
case SOCK_CUSTOM:
|
||||
std::unique_ptr<decl::Custom> decl = std::make_unique<decl::Custom>();
|
||||
decl->idname_ = io_socket.idname;
|
||||
|
|
|
@ -431,18 +431,48 @@ bNodeSocket &String::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket
|
|||
/** \name #IDSocketDeclaration
|
||||
* \{ */
|
||||
|
||||
static void id_socket_fill_value_try(ID *src, bNodeSocket &r_socket)
|
||||
{
|
||||
if (src == nullptr) {
|
||||
return;
|
||||
}
|
||||
switch ((ID_Type)GS(src->name)) {
|
||||
case ID_OB: {
|
||||
using TPtr = decltype(r_socket.default_value_typed<bNodeSocketValueObject>()->value);
|
||||
r_socket.default_value_typed<bNodeSocketValueObject>()->value = reinterpret_cast<TPtr>(src);
|
||||
}
|
||||
case ID_MA: {
|
||||
using TPtr = decltype(r_socket.default_value_typed<bNodeSocketValueMaterial>()->value);
|
||||
r_socket.default_value_typed<bNodeSocketValueMaterial>()->value = reinterpret_cast<TPtr>(
|
||||
src);
|
||||
}
|
||||
case ID_IM: {
|
||||
using TPtr = decltype(r_socket.default_value_typed<bNodeSocketValueImage>()->value);
|
||||
r_socket.default_value_typed<bNodeSocketValueImage>()->value = reinterpret_cast<TPtr>(src);
|
||||
}
|
||||
case ID_TE: {
|
||||
using TPtr = decltype(r_socket.default_value_typed<bNodeSocketValueTexture>()->value);
|
||||
r_socket.default_value_typed<bNodeSocketValueTexture>()->value = reinterpret_cast<TPtr>(src);
|
||||
}
|
||||
case ID_CO: {
|
||||
using TPtr = decltype(r_socket.default_value_typed<bNodeSocketValueCollection>()->value);
|
||||
r_socket.default_value_typed<bNodeSocketValueCollection>()->value = reinterpret_cast<TPtr>(
|
||||
src);
|
||||
}
|
||||
default: {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
if (this->init_socket_value_cd) {
|
||||
ID *scr_socket_value = this->init_socket_value_cd(socket);
|
||||
id_socket_fill_value_try(scr_socket_value, socket);
|
||||
}
|
||||
|
||||
return socket;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
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