Nodes: use node storage to store type of reroute node
The reroute node used to be a bit special in the sense that its data type was only stored in the sockets. However, typically, the ground truth data should be stored in the node storage and then the socket types are derived from that. For users, there should not be a noticable difference. However, from Python it's not possible to modify the socket type directly on the socket anymore. This is forbidden for other built-in nodes already too. Instead, one can use the new `reroute_node.socket_idname` property to change the type of a node. This internally also recreates the sockets with the correct type. Pull Request: https://projects.blender.org/blender/blender/pulls/121146
This commit is contained in:
committed by
Jacques Lucke
parent
3c8d4becc8
commit
c40dc9aa03
@@ -31,7 +31,7 @@ extern "C" {
|
||||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 23
|
||||
#define BLENDER_FILE_SUBVERSION 24
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and cancel loading the file, showing a warning to
|
||||
|
||||
@@ -2780,6 +2780,22 @@ static void add_image_editor_asset_shelf(Main &bmain)
|
||||
}
|
||||
}
|
||||
|
||||
static void node_reroute_add_storage(bNodeTree &tree)
|
||||
{
|
||||
for (bNode *node : tree.all_nodes()) {
|
||||
if (node->is_reroute()) {
|
||||
if (node->storage != nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const bNodeSocket &input = *static_cast<const bNodeSocket *>(node->inputs.first);
|
||||
NodeReroute *data = MEM_cnew<NodeReroute>(__func__);
|
||||
STRNCPY(data->type_idname, input.idname);
|
||||
node->storage = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* It was possible that curve attributes were initialized to 0 even if that is not allowed for some
|
||||
* attributes.
|
||||
@@ -4640,6 +4656,13 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
||||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 403, 24)) {
|
||||
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
|
||||
node_reroute_add_storage(*ntree);
|
||||
}
|
||||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always bump subversion in BKE_blender_version.h when adding versioning
|
||||
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.
|
||||
|
||||
@@ -1018,6 +1018,12 @@ typedef struct NodeFrame {
|
||||
short label_size;
|
||||
} NodeFrame;
|
||||
|
||||
typedef struct NodeReroute {
|
||||
/** Name of the socket type (e.g. `NodeSocketFloat`). */
|
||||
char type_idname[64];
|
||||
|
||||
} NodeReroute;
|
||||
|
||||
/** \note This one has been replaced with #ImageUser, keep it for do_versions(). */
|
||||
typedef struct NodeImageAnim {
|
||||
int frames DNA_DEPRECATED;
|
||||
|
||||
@@ -271,11 +271,7 @@ static void rna_NodeSocket_type_set(PointerRNA *ptr, int value)
|
||||
blender::bke::node_find_node(ntree, sock, &node, nullptr);
|
||||
if (node->type != NODE_CUSTOM) {
|
||||
/* Can't change the socket type on built-in nodes like this. */
|
||||
if (!node->is_reroute()) {
|
||||
/* TODO: Refactor reroute node to avoid direct change of the socket type in built-in node and
|
||||
* use proper node method for this. */
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
blender::bke::node_modify_socket_type_static(ntree, node, sock, value, 0);
|
||||
}
|
||||
|
||||
@@ -4119,6 +4119,27 @@ static void rna_NodeConvertColorSpace_to_color_space_set(PointerRNA *ptr, int va
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_reroute_node_socket_type_set(PointerRNA *ptr, const char *value)
|
||||
{
|
||||
const bNodeTree &ntree = *reinterpret_cast<bNodeTree *>(ptr->owner_id);
|
||||
blender::bke::bNodeTreeType *ntree_type = ntree.typeinfo;
|
||||
|
||||
bNode &node = *static_cast<bNode *>(ptr->data);
|
||||
|
||||
blender::bke::bNodeSocketType *socket_type = blender::bke::node_socket_type_find(value);
|
||||
if (socket_type == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (socket_type->subtype != PROP_NONE) {
|
||||
return;
|
||||
}
|
||||
if (ntree_type->valid_socket_type && !ntree_type->valid_socket_type(ntree_type, socket_type)) {
|
||||
return;
|
||||
}
|
||||
NodeReroute *storage = static_cast<NodeReroute *>(node.storage);
|
||||
STRNCPY(storage->type_idname, value);
|
||||
}
|
||||
|
||||
static const EnumPropertyItem *rna_NodeConvertColorSpace_color_space_itemf(bContext * /*C*/,
|
||||
PointerRNA * /*ptr*/,
|
||||
PropertyRNA * /*prop*/,
|
||||
@@ -10228,6 +10249,17 @@ static void rna_def_function_node(BlenderRNA *brna)
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static void def_reroute(StructRNA *srna)
|
||||
{
|
||||
RNA_def_struct_sdna_from(srna, "NodeReroute", "storage");
|
||||
|
||||
PropertyRNA *prop = RNA_def_property(srna, "socket_idname", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, nullptr, "type_idname");
|
||||
RNA_def_property_string_funcs(prop, nullptr, nullptr, "rna_reroute_node_socket_type_set");
|
||||
RNA_def_property_ui_text(prop, "Type of socket", "");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
|
||||
}
|
||||
|
||||
static void rna_def_internal_node(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
|
||||
@@ -336,10 +336,16 @@ class Extend : public SocketDeclaration {
|
||||
|
||||
class ExtendBuilder : public SocketDeclarationBuilder<Extend> {};
|
||||
|
||||
class CustomTypeBuilder;
|
||||
|
||||
class Custom : public SocketDeclaration {
|
||||
public:
|
||||
static constexpr eNodeSocketDatatype static_socket_type = SOCK_CUSTOM;
|
||||
|
||||
friend CustomTypeBuilder;
|
||||
|
||||
using Builder = CustomTypeBuilder;
|
||||
|
||||
const char *idname_;
|
||||
std::function<void(bNode &node, bNodeSocket &socket, const char *data_path)> init_socket_fn;
|
||||
|
||||
@@ -349,6 +355,11 @@ class Custom : public SocketDeclaration {
|
||||
bool can_connect(const bNodeSocket &socket) const override;
|
||||
};
|
||||
|
||||
class CustomTypeBuilder : public SocketDeclarationBuilder<Custom> {
|
||||
public:
|
||||
CustomTypeBuilder &idname(const char *name);
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name #FloatBuilder Inline Methods
|
||||
* \{ */
|
||||
@@ -529,6 +540,18 @@ inline Image::Image() : IDSocketDeclaration("NodeSocketImage") {}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name #CustomTypeBuilder Inline Methods
|
||||
* \{ */
|
||||
|
||||
inline CustomTypeBuilder &CustomTypeBuilder::idname(const char *idname)
|
||||
{
|
||||
decl_->idname_ = idname;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
SocketDeclarationPtr create_extend_declaration(const eNodeSocketInOut in_out);
|
||||
|
||||
} // namespace blender::nodes::decl
|
||||
|
||||
@@ -23,7 +23,7 @@ DefNode(Node, NODE_FRAME, def_frame, "FRAME"
|
||||
DefNode(Node, NODE_GROUP, def_group, "GROUP", Group, "Group", "")
|
||||
DefNode(Node, NODE_GROUP_INPUT, def_group_input, "GROUP_INPUT", GroupInput, "Group Input", "Expose connected data from inside a node group as inputs to its interface")
|
||||
DefNode(Node, NODE_GROUP_OUTPUT, def_group_output, "GROUP_OUTPUT", GroupOutput, "Group Output", "Output data from inside of a node group")
|
||||
DefNode(Node, NODE_REROUTE, 0, "REROUTE", Reroute, "Reroute", "A single-socket organization tool that supports one input and multiple outputs")
|
||||
DefNode(Node, NODE_REROUTE, def_reroute, "REROUTE", Reroute, "Reroute", "A single-socket organization tool that supports one input and multiple outputs")
|
||||
|
||||
DefNode(ShaderNode, SH_NODE_RGB, 0, "RGB", RGB, "RGB", "A color picker")
|
||||
DefNode(ShaderNode, SH_NODE_VALUE, 0, "VALUE", Value, "Value", "Input numerical values to other nodes in the tree")
|
||||
|
||||
@@ -572,15 +572,24 @@ void register_node_type_frame()
|
||||
/** \name Node Re-Route
|
||||
* \{ */
|
||||
|
||||
static void node_reroute_init(bNodeTree *ntree, bNode *node)
|
||||
static void node_reroute_declare(blender::nodes::NodeDeclarationBuilder &b)
|
||||
{
|
||||
/* NOTE: Cannot use socket templates for this, since it would reset the socket type
|
||||
* on each file read via the template verification procedure.
|
||||
*/
|
||||
blender::bke::node_add_static_socket(
|
||||
ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, "Input", "Input");
|
||||
blender::bke::node_add_static_socket(
|
||||
ntree, node, SOCK_OUT, SOCK_RGBA, PROP_NONE, "Output", "Output");
|
||||
const bNode *node = b.node_or_null();
|
||||
if (node == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const blender::StringRefNull socket_idname(
|
||||
static_cast<const NodeReroute *>(node->storage)->type_idname);
|
||||
b.add_input<blender::nodes::decl::Custom>("Input").idname(socket_idname.c_str());
|
||||
b.add_output<blender::nodes::decl::Custom>("Output").idname(socket_idname.c_str());
|
||||
}
|
||||
|
||||
static void node_reroute_init(bNodeTree * /*ntree*/, bNode *node)
|
||||
{
|
||||
NodeReroute *data = MEM_cnew<NodeReroute>(__func__);
|
||||
STRNCPY(data->type_idname, "NodeSocketColor");
|
||||
node->storage = data;
|
||||
}
|
||||
|
||||
void register_node_type_reroute()
|
||||
@@ -590,7 +599,9 @@ void register_node_type_reroute()
|
||||
ntype->free_self = (void (*)(blender::bke::bNodeType *))MEM_freeN;
|
||||
|
||||
blender::bke::node_type_base(ntype, NODE_REROUTE, "Reroute", NODE_CLASS_LAYOUT);
|
||||
ntype->declare = node_reroute_declare;
|
||||
ntype->initfunc = node_reroute_init;
|
||||
node_type_storage(ntype, "NodeReroute", node_free_standard_storage, node_copy_standard_storage);
|
||||
|
||||
blender::bke::node_register_type(ntype);
|
||||
}
|
||||
@@ -674,17 +685,9 @@ void ntree_update_reroute_nodes(bNodeTree *ntree)
|
||||
for (const auto item : reroute_types.items()) {
|
||||
bNode *reroute_node = item.key;
|
||||
const blender::bke::bNodeSocketType *socket_type = item.value;
|
||||
bNodeSocket *input_socket = (bNodeSocket *)reroute_node->inputs.first;
|
||||
bNodeSocket *output_socket = (bNodeSocket *)reroute_node->outputs.first;
|
||||
|
||||
if (input_socket->typeinfo != socket_type) {
|
||||
blender::bke::node_modify_socket_type(
|
||||
ntree, reroute_node, input_socket, socket_type->idname);
|
||||
}
|
||||
if (output_socket->typeinfo != socket_type) {
|
||||
blender::bke::node_modify_socket_type(
|
||||
ntree, reroute_node, output_socket, socket_type->idname);
|
||||
}
|
||||
NodeReroute *storage = static_cast<NodeReroute *>(reroute_node->storage);
|
||||
STRNCPY(storage->type_idname, socket_type->idname);
|
||||
blender::nodes::update_node_declaration_and_sockets(*ntree, *reroute_node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user