Compare commits
47 Commits
tmp-volume
...
temp-nodes
Author | SHA1 | Date | |
---|---|---|---|
ea2db47a0b | |||
eaa17cfae2 | |||
082449b737 | |||
b1bbd33ed6 | |||
96609ade04 | |||
844b3ed472 | |||
392f4481a7 | |||
612c0ae3c8 | |||
1847b63d27 | |||
dd32b8fc97 | |||
06b5ceb0c4 | |||
ef89ba2b34 | |||
399fc4af2a | |||
92a16d0193 | |||
e76e8fe87a | |||
0c87d9b8f7 | |||
d5b2979ad5 | |||
b60fc1c4c8 | |||
4052267be7 | |||
60210762e0 | |||
13d984cfaa | |||
195a271bab | |||
ddee26288d | |||
af5a9b5748 | |||
109f18df71 | |||
450693ea6b | |||
f06635bfde | |||
21a8d7c69b | |||
1ffe27c438 | |||
86b9b61371 | |||
a2992774ac | |||
cc57344527 | |||
e4139476bf | |||
80a3bed01a | |||
439761d15c | |||
7b4dcec3ec | |||
f4d52d060b | |||
a90642816c | |||
8a27da7b3b | |||
c174184385 | |||
660e240acf | |||
f509bd37b1 | |||
542bff5e94 | |||
d82166833a | |||
64297ec8ad | |||
510155ed5c | |||
59b1eb145d |
@@ -104,6 +104,7 @@ namespace nodes {
|
||||
class DNode;
|
||||
class NodeMultiFunctionBuilder;
|
||||
class GeoNodeExecParams;
|
||||
class NodeDeclaration;
|
||||
class NodeDeclarationBuilder;
|
||||
class GatherLinkSearchOpParams;
|
||||
} // namespace nodes
|
||||
@@ -118,6 +119,9 @@ using CPPTypeHandle = blender::CPPType;
|
||||
using NodeMultiFunctionBuildFunction = void (*)(blender::nodes::NodeMultiFunctionBuilder &builder);
|
||||
using NodeGeometryExecFunction = void (*)(blender::nodes::GeoNodeExecParams params);
|
||||
using NodeDeclareFunction = void (*)(blender::nodes::NodeDeclarationBuilder &builder);
|
||||
using NodeDeclareDynamicFunction = void (*)(const bNodeTree &tree,
|
||||
const bNode &node,
|
||||
blender::nodes::NodeDeclaration &r_declaration);
|
||||
using SocketGetCPPValueFunction = void (*)(const struct bNodeSocket &socket, void *r_value);
|
||||
using SocketGetGeometryNodesCPPValueFunction = void (*)(const struct bNodeSocket &socket,
|
||||
void *r_value);
|
||||
@@ -137,6 +141,7 @@ typedef void *NodeGetCompositorShaderNodeFunction;
|
||||
typedef void *NodeMultiFunctionBuildFunction;
|
||||
typedef void *NodeGeometryExecFunction;
|
||||
typedef void *NodeDeclareFunction;
|
||||
typedef void *NodeDeclareDynamicFunction;
|
||||
typedef void *NodeGatherSocketLinkOperationsFunction;
|
||||
typedef void *SocketGetCPPTypeFunction;
|
||||
typedef void *SocketGetGeometryNodesCPPTypeFunction;
|
||||
@@ -173,11 +178,6 @@ typedef struct bNodeSocketType {
|
||||
struct bNode *node,
|
||||
struct bNodeSocket *sock,
|
||||
const char *data_path);
|
||||
void (*interface_verify_socket)(struct bNodeTree *ntree,
|
||||
const struct bNodeSocket *interface_socket,
|
||||
struct bNode *node,
|
||||
struct bNodeSocket *sock,
|
||||
const char *data_path);
|
||||
void (*interface_from_socket)(struct bNodeTree *ntree,
|
||||
struct bNodeSocket *interface_socket,
|
||||
const struct bNode *node,
|
||||
@@ -306,8 +306,8 @@ typedef struct bNodeType {
|
||||
const struct bNodeTree *nodetree,
|
||||
const char **r_disabled_hint);
|
||||
|
||||
/* optional handling of link insertion */
|
||||
void (*insert_link)(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link);
|
||||
/* optional handling of link insertion. Returns false if the link shouldn't be created. */
|
||||
bool (*insert_link)(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link);
|
||||
|
||||
void (*free_self)(struct bNodeType *ntype);
|
||||
|
||||
@@ -344,8 +344,13 @@ typedef struct bNodeType {
|
||||
|
||||
/* Declares which sockets the node has. */
|
||||
NodeDeclareFunction declare;
|
||||
/* Different nodes of this type can have different declarations. */
|
||||
bool declaration_is_dynamic;
|
||||
/**
|
||||
* Declare which sockets the node has for declarations that aren't static per node type.
|
||||
* In other words, defining this callback means that different nodes of this type can have
|
||||
* different declarations and different sockets.
|
||||
*/
|
||||
NodeDeclareDynamicFunction declare_dynamic;
|
||||
|
||||
/* Declaration to be used when it is not dynamic. */
|
||||
NodeDeclarationHandle *fixed_declaration;
|
||||
|
||||
|
@@ -1378,7 +1378,7 @@ void nodeRegisterType(bNodeType *nt)
|
||||
BLI_assert(nt->idname[0] != '\0');
|
||||
BLI_assert(nt->poll != nullptr);
|
||||
|
||||
if (nt->declare && !nt->declaration_is_dynamic) {
|
||||
if (nt->declare && !nt->declare_dynamic) {
|
||||
if (nt->fixed_declaration == nullptr) {
|
||||
nt->fixed_declaration = new blender::nodes::NodeDeclaration();
|
||||
blender::nodes::build_node_declaration(*nt, *nt->fixed_declaration);
|
||||
@@ -2990,7 +2990,7 @@ void node_free_node(bNodeTree *ntree, bNode *node)
|
||||
MEM_freeN(node->prop);
|
||||
}
|
||||
|
||||
if (node->typeinfo->declaration_is_dynamic) {
|
||||
if (node->typeinfo->declare_dynamic) {
|
||||
delete node->runtime->declaration;
|
||||
}
|
||||
|
||||
@@ -3602,7 +3602,7 @@ bool nodeDeclarationEnsureOnOutdatedNode(bNodeTree * /*ntree*/, bNode *node)
|
||||
if (node->typeinfo->declare == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (node->typeinfo->declaration_is_dynamic) {
|
||||
if (node->typeinfo->declare_dynamic) {
|
||||
node->runtime->declaration = new blender::nodes::NodeDeclaration();
|
||||
blender::nodes::build_node_declaration(*node->typeinfo, *node->runtime->declaration);
|
||||
}
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#include "MOD_nodes.h"
|
||||
|
||||
#include "NOD_node_declaration.hh"
|
||||
#include "NOD_socket.h"
|
||||
#include "NOD_texture.h"
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
@@ -538,7 +539,6 @@ class NodeTreeMainUpdater {
|
||||
|
||||
void update_individual_nodes(bNodeTree &ntree)
|
||||
{
|
||||
Vector<bNode *> group_inout_nodes;
|
||||
for (bNode *node : ntree.all_nodes()) {
|
||||
nodeDeclarationEnsure(&ntree, node);
|
||||
if (this->should_update_individual_node(ntree, *node)) {
|
||||
@@ -549,18 +549,9 @@ class NodeTreeMainUpdater {
|
||||
if (ntype.updatefunc) {
|
||||
ntype.updatefunc(&ntree, node);
|
||||
}
|
||||
}
|
||||
if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
|
||||
group_inout_nodes.append(node);
|
||||
}
|
||||
}
|
||||
/* The update function of group input/output nodes may add new interface sockets. When that
|
||||
* happens, all the input/output nodes have to be updated again. In the future it would be
|
||||
* better to move this functionality out of the node update function into the operator that's
|
||||
* supposed to create the new interface socket. */
|
||||
if (ntree.runtime->changed_flag & NTREE_CHANGED_INTERFACE) {
|
||||
for (bNode *node : group_inout_nodes) {
|
||||
node->typeinfo->updatefunc(&ntree, node);
|
||||
if (ntype.declare_dynamic) {
|
||||
nodes::update_node_declaration_and_sockets(ntree, *node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -575,22 +566,8 @@ class NodeTreeMainUpdater {
|
||||
}
|
||||
if (ntree.runtime->changed_flag & NTREE_CHANGED_LINK) {
|
||||
ntree.ensure_topology_cache();
|
||||
/* Node groups currently always rebuilt their sockets when they are updated.
|
||||
* So avoid calling the update method when no new link was added to it. */
|
||||
if (node.type == NODE_GROUP_INPUT) {
|
||||
if (node.output_sockets().last()->is_directly_linked()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (node.type == NODE_GROUP_OUTPUT) {
|
||||
if (node.input_sockets().last()->is_directly_linked()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Currently we have no way to tell if a node needs to be updated when a link changed. */
|
||||
return true;
|
||||
}
|
||||
/* Currently we have no way to tell if a node needs to be updated when a link changed. */
|
||||
return true;
|
||||
}
|
||||
if (ntree.runtime->changed_flag & NTREE_CHANGED_INTERFACE) {
|
||||
if (ELEM(node.type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include "BKE_node_tree_update.h"
|
||||
#include "BKE_screen.h"
|
||||
|
||||
#include "NOD_socket.h"
|
||||
#include "NOD_socket_search_link.hh"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
@@ -198,7 +199,7 @@ static void search_link_ops_for_asset_metadata(const bNodeTree &node_tree,
|
||||
DEG_relations_tag_update(&bmain);
|
||||
|
||||
/* Create the inputs and outputs on the new node. */
|
||||
node.typeinfo->group_update_func(¶ms.node_tree, &node);
|
||||
nodes::update_node_declaration_and_sockets(params.node_tree, node);
|
||||
|
||||
bNodeSocket *new_node_socket = bke::node_find_enabled_socket(
|
||||
node, in_out, socket_property->name);
|
||||
|
@@ -933,9 +933,9 @@ static void node_group_make_insert_selected(const bContext &C,
|
||||
}
|
||||
nodeRebuildIDVector(&ntree);
|
||||
|
||||
node_group_update(&ntree, gnode);
|
||||
node_group_input_update(&group, input_node);
|
||||
node_group_output_update(&group, output_node);
|
||||
/* Update input and output node first, since the group node declaration can depend on them. */
|
||||
nodes::update_node_declaration_and_sockets(group, *input_node);
|
||||
nodes::update_node_declaration_and_sockets(group, *output_node);
|
||||
|
||||
/* move nodes in the group to the center */
|
||||
for (bNode *node : nodes_to_move) {
|
||||
@@ -956,6 +956,7 @@ static void node_group_make_insert_selected(const bContext &C,
|
||||
nodeRemLink(&ntree, link);
|
||||
}
|
||||
|
||||
/* Handle links to the new group inputs. */
|
||||
for (const auto item : input_links.items()) {
|
||||
const char *interface_identifier = item.value.interface_socket->identifier;
|
||||
bNodeSocket *input_socket = node_group_input_find_socket(input_node, interface_identifier);
|
||||
@@ -969,23 +970,17 @@ static void node_group_make_insert_selected(const bContext &C,
|
||||
link->fromnode = input_node;
|
||||
link->fromsock = input_socket;
|
||||
}
|
||||
|
||||
/* Add a new link outside of the group. */
|
||||
bNodeSocket *group_node_socket = node_group_find_input_socket(gnode, interface_identifier);
|
||||
nodeAddLink(&ntree, item.value.from_node, item.key, gnode, group_node_socket);
|
||||
}
|
||||
|
||||
/* Handle links to new group outputs. */
|
||||
for (const OutputLinkInfo &info : output_links) {
|
||||
/* Create a new link inside of the group. */
|
||||
const char *io_identifier = info.interface_socket->identifier;
|
||||
bNodeSocket *output_sock = node_group_output_find_socket(output_node, io_identifier);
|
||||
nodeAddLink(&group, info.link->fromnode, info.link->fromsock, output_node, output_sock);
|
||||
|
||||
/* Reconnect the link to the group node instead of the node now inside the group. */
|
||||
info.link->fromnode = gnode;
|
||||
info.link->fromsock = node_group_find_output_socket(gnode, io_identifier);
|
||||
}
|
||||
|
||||
/* Handle new links inside the group. */
|
||||
for (const NewInternalLinkInfo &info : new_internal_links) {
|
||||
const char *io_identifier = info.interface_socket->identifier;
|
||||
if (info.socket->in_out == SOCK_IN) {
|
||||
@@ -997,6 +992,25 @@ static void node_group_make_insert_selected(const bContext &C,
|
||||
nodeAddLink(&group, info.node, info.socket, output_node, output_socket);
|
||||
}
|
||||
}
|
||||
|
||||
bke::node_field_inferencing::update_field_inferencing(group);
|
||||
nodes::update_node_declaration_and_sockets(ntree, *gnode);
|
||||
|
||||
/* Add new links to inputs outside of the group. */
|
||||
for (const auto item : input_links.items()) {
|
||||
const char *interface_identifier = item.value.interface_socket->identifier;
|
||||
bNodeSocket *group_node_socket = node_group_find_input_socket(gnode, interface_identifier);
|
||||
nodeAddLink(&ntree, item.value.from_node, item.key, gnode, group_node_socket);
|
||||
}
|
||||
|
||||
/* Add new links to outputs outside the group. */
|
||||
for (const OutputLinkInfo &info : output_links) {
|
||||
/* Reconnect the link to the group node instead of the node now inside the group. */
|
||||
info.link->fromnode = gnode;
|
||||
info.link->fromsock = node_group_find_output_socket(gnode, info.interface_socket->identifier);
|
||||
}
|
||||
|
||||
ED_node_tree_propagate_change(&C, bmain, nullptr);
|
||||
}
|
||||
|
||||
static bNode *node_group_make_from_nodes(const bContext &C,
|
||||
@@ -1051,8 +1065,6 @@ static int node_group_make_exec(bContext *C, wmOperator *op)
|
||||
}
|
||||
}
|
||||
|
||||
ED_node_tree_propagate_change(C, bmain, nullptr);
|
||||
|
||||
WM_event_add_notifier(C, NC_NODE | NA_ADDED, nullptr);
|
||||
|
||||
/* We broke relations in node tree, need to rebuild them in the graphs. */
|
||||
@@ -1105,7 +1117,6 @@ static int node_group_insert_exec(bContext *C, wmOperator *op)
|
||||
SpaceNode *snode = CTX_wm_space_node(C);
|
||||
bNodeTree *ntree = snode->edittree;
|
||||
const char *node_idname = node_group_idname(C);
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
||||
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
|
||||
|
||||
@@ -1137,7 +1148,6 @@ static int node_group_insert_exec(bContext *C, wmOperator *op)
|
||||
|
||||
nodeSetActive(ntree, gnode);
|
||||
ED_node_tree_push(snode, ngroup, gnode);
|
||||
ED_node_tree_propagate_change(C, bmain, nullptr);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
@@ -902,10 +902,14 @@ static void add_dragged_links_to_tree(bContext &C, bNodeLinkDrag &nldrag)
|
||||
/* Before actually adding the link let nodes perform special link insertion handling. */
|
||||
bNodeLink *new_link = MEM_new<bNodeLink>(__func__, link);
|
||||
if (link.fromnode->typeinfo->insert_link) {
|
||||
link.fromnode->typeinfo->insert_link(&ntree, link.fromnode, new_link);
|
||||
if (!link.fromnode->typeinfo->insert_link(&ntree, link.fromnode, new_link)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (link.tonode->typeinfo->insert_link) {
|
||||
link.tonode->typeinfo->insert_link(&ntree, link.tonode, new_link);
|
||||
if (!link.tonode->typeinfo->insert_link(&ntree, link.tonode, new_link)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add link to the node tree. */
|
||||
|
@@ -1738,7 +1738,7 @@ static void rna_Node_update_reg(bNodeTree *ntree, bNode *node)
|
||||
RNA_parameter_list_free(&list);
|
||||
}
|
||||
|
||||
static void rna_Node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
|
||||
static bool rna_Node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
|
||||
{
|
||||
extern FunctionRNA rna_Node_insert_link_func;
|
||||
|
||||
@@ -1754,6 +1754,7 @@ static void rna_Node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
|
||||
node->typeinfo->rna_ext.call(NULL, &ptr, func, &list);
|
||||
|
||||
RNA_parameter_list_free(&list);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void rna_Node_init(const bContext *C, PointerRNA *ptr)
|
||||
@@ -3386,9 +3387,6 @@ static StructRNA *rna_NodeCustomGroup_register(Main *bmain,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* this updates the group node instance from the tree's interface */
|
||||
nt->group_update_func = node_group_update;
|
||||
|
||||
nodeRegisterType(nt);
|
||||
|
||||
/* update while blender is running */
|
||||
@@ -3412,7 +3410,6 @@ static StructRNA *rna_GeometryNodeCustomGroup_register(Main *bmain,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nt->group_update_func = node_group_update;
|
||||
nt->type = NODE_CUSTOM_GROUP;
|
||||
|
||||
register_node_type_geo_custom_group(nt);
|
||||
@@ -3441,7 +3438,6 @@ static StructRNA *rna_ShaderNodeCustomGroup_register(Main *bmain,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nt->group_update_func = node_group_update;
|
||||
nt->type = NODE_CUSTOM_GROUP;
|
||||
|
||||
register_node_type_sh_custom_group(nt);
|
||||
@@ -3467,7 +3463,6 @@ static StructRNA *rna_CompositorNodeCustomGroup_register(Main *bmain,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nt->group_update_func = node_group_update;
|
||||
nt->type = NODE_CUSTOM_GROUP;
|
||||
|
||||
register_node_type_cmp_custom_group(nt);
|
||||
|
@@ -17,16 +17,24 @@ extern "C" {
|
||||
|
||||
struct bNodeSocket *node_group_find_input_socket(struct bNode *groupnode, const char *identifier);
|
||||
struct bNodeSocket *node_group_find_output_socket(struct bNode *groupnode, const char *identifier);
|
||||
/** Make sure all group node in ntree, which use ngroup, are sync'd. */
|
||||
void node_group_update(struct bNodeTree *ntree, struct bNode *node);
|
||||
|
||||
struct bNodeSocket *node_group_input_find_socket(struct bNode *node, const char *identifier);
|
||||
struct bNodeSocket *node_group_output_find_socket(struct bNode *node, const char *identifier);
|
||||
void node_group_input_update(struct bNodeTree *ntree, struct bNode *node);
|
||||
void node_group_output_update(struct bNodeTree *ntree, struct bNode *node);
|
||||
|
||||
void node_internal_links_create(struct bNodeTree *ntree, struct bNode *node);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
void node_group_declare_dynamic(const bNodeTree &node_tree,
|
||||
const bNode &node,
|
||||
NodeDeclaration &r_declaration);
|
||||
|
||||
} // namespace blender::nodes
|
||||
|
||||
#endif
|
||||
|
@@ -160,6 +160,7 @@ class SocketDeclaration {
|
||||
InputSocketFieldType input_field_type = InputSocketFieldType::None;
|
||||
OutputFieldDependency output_field_dependency;
|
||||
|
||||
private:
|
||||
/** The priority of the input for determining the domain of the node. See
|
||||
* realtime_compositor::InputDescriptor for more information. */
|
||||
int compositor_domain_priority_ = 0;
|
||||
@@ -461,6 +462,11 @@ class NodeDeclaration {
|
||||
Vector<SocketDeclarationPtr> outputs;
|
||||
std::unique_ptr<aal::RelationsInNode> anonymous_attribute_relations_;
|
||||
|
||||
/** Leave the sockets in place, even if they don't match the declaration. Used for dynamic
|
||||
* declarations when the information used to build the declaration is missing, but might become
|
||||
* available again in the future. */
|
||||
bool skip_updating_sockets = false;
|
||||
|
||||
friend NodeDeclarationBuilder;
|
||||
|
||||
bool matches(const bNode &node) const;
|
||||
@@ -523,6 +529,9 @@ void id_or_index(const bNode &node, void *r_value);
|
||||
} // namespace implicit_field_inputs
|
||||
|
||||
void build_node_declaration(const bNodeType &typeinfo, NodeDeclaration &r_declaration);
|
||||
void build_node_declaration_dynamic(const bNodeTree &node_tree,
|
||||
const bNode &node,
|
||||
NodeDeclaration &r_declaration);
|
||||
|
||||
template<typename SocketDecl>
|
||||
typename SocketDeclarationBuilder<SocketDecl>::Self &SocketDeclarationBuilder<
|
||||
|
@@ -36,3 +36,13 @@ void register_standard_node_socket_types(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
void update_node_declaration_and_sockets(bNodeTree &ntree, bNode &node);
|
||||
|
||||
} // namespace blender::nodes
|
||||
|
||||
#endif
|
||||
|
@@ -104,6 +104,7 @@ class Bool : public SocketDeclaration {
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -124,6 +125,7 @@ class Color : public SocketDeclaration {
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -144,6 +146,7 @@ class String : public SocketDeclaration {
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -216,6 +219,34 @@ class Shader : public SocketDeclaration {
|
||||
class ShaderBuilder : public SocketDeclarationBuilder<Shader> {
|
||||
};
|
||||
|
||||
class ExtendBuilder;
|
||||
|
||||
class Extend : public SocketDeclaration {
|
||||
private:
|
||||
friend ExtendBuilder;
|
||||
|
||||
public:
|
||||
using Builder = ExtendBuilder;
|
||||
|
||||
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 ExtendBuilder : public SocketDeclarationBuilder<Extend> {
|
||||
};
|
||||
|
||||
class Custom : public SocketDeclaration {
|
||||
public:
|
||||
const char *idname_;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name #FloatBuilder Inline Methods
|
||||
* \{ */
|
||||
|
@@ -32,7 +32,7 @@ void register_node_type_cmp_group()
|
||||
|
||||
node_type_size(&ntype, 140, 60, 400);
|
||||
ntype.labelfunc = node_group_label;
|
||||
ntype.group_update_func = node_group_update;
|
||||
ntype.declare_dynamic = blender::nodes::node_group_declare_dynamic;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@@ -3,11 +3,41 @@
|
||||
#include "BKE_node.h"
|
||||
|
||||
#include "NOD_geometry.h"
|
||||
#include "NOD_node_declaration.hh"
|
||||
|
||||
#include "NOD_common.h"
|
||||
#include "node_common.h"
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
static void node_declare(const bNodeTree &node_tree,
|
||||
const bNode &node,
|
||||
NodeDeclaration &r_declaration)
|
||||
{
|
||||
const bNodeTree *group = reinterpret_cast<const bNodeTree *>(node.id);
|
||||
if (!group) {
|
||||
return;
|
||||
}
|
||||
node_group_declare_dynamic(node_tree, node, r_declaration);
|
||||
if (!node.id) {
|
||||
return;
|
||||
}
|
||||
if (ID_IS_LINKED(&group->id) && (group->id.tag & LIB_TAG_MISSING)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const FieldInferencingInterface &field_interface = *group->runtime->field_inferencing_interface;
|
||||
for (const int i : r_declaration.inputs.index_range()) {
|
||||
r_declaration.inputs[i]->input_field_type = field_interface.inputs[i];
|
||||
}
|
||||
for (const int i : r_declaration.outputs.index_range()) {
|
||||
r_declaration.outputs[i]->output_field_dependency = field_interface.outputs[i];
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::nodes
|
||||
|
||||
void register_node_type_geo_group()
|
||||
{
|
||||
static bNodeType ntype;
|
||||
@@ -23,7 +53,7 @@ void register_node_type_geo_group()
|
||||
|
||||
node_type_size(&ntype, 140, 60, 400);
|
||||
ntype.labelfunc = node_group_label;
|
||||
ntype.group_update_func = node_group_update;
|
||||
ntype.declare_dynamic = blender::nodes::node_declare;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
@@ -30,7 +30,11 @@
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "NOD_common.h"
|
||||
#include "NOD_node_declaration.hh"
|
||||
#include "NOD_register.hh"
|
||||
#include "NOD_socket.h"
|
||||
#include "NOD_socket_declarations.hh"
|
||||
#include "NOD_socket_declarations_geometry.hh"
|
||||
#include "node_common.h"
|
||||
#include "node_util.h"
|
||||
|
||||
@@ -120,124 +124,124 @@ bool nodeGroupPoll(const bNodeTree *nodetree,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void add_new_socket_from_interface(bNodeTree &node_tree,
|
||||
bNode &node,
|
||||
const bNodeSocket &interface_socket,
|
||||
const eNodeSocketInOut in_out)
|
||||
{
|
||||
bNodeSocket *socket = nodeAddSocket(&node_tree,
|
||||
&node,
|
||||
in_out,
|
||||
interface_socket.idname,
|
||||
interface_socket.identifier,
|
||||
interface_socket.name);
|
||||
namespace blender::nodes {
|
||||
|
||||
if (interface_socket.typeinfo->interface_init_socket) {
|
||||
interface_socket.typeinfo->interface_init_socket(
|
||||
&node_tree, &interface_socket, &node, socket, "interface");
|
||||
static SocketDeclarationPtr declaration_for_interface_socket(const bNodeSocket &io_socket)
|
||||
{
|
||||
SocketDeclarationPtr dst;
|
||||
switch (io_socket.type) {
|
||||
case SOCK_FLOAT: {
|
||||
const auto &value = *io_socket.default_value_typed<bNodeSocketValueFloat>();
|
||||
std::unique_ptr<decl::Float> decl = std::make_unique<decl::Float>();
|
||||
decl->subtype = PropertySubType(io_socket.typeinfo->subtype);
|
||||
decl->default_value = value.value;
|
||||
decl->soft_min_value = value.min;
|
||||
decl->soft_max_value = value.max;
|
||||
dst = std::move(decl);
|
||||
break;
|
||||
}
|
||||
case SOCK_VECTOR: {
|
||||
const auto &value = *io_socket.default_value_typed<bNodeSocketValueVector>();
|
||||
std::unique_ptr<decl::Vector> decl = std::make_unique<decl::Vector>();
|
||||
decl->subtype = PropertySubType(io_socket.typeinfo->subtype);
|
||||
decl->default_value = value.value;
|
||||
decl->soft_min_value = value.min;
|
||||
decl->soft_max_value = value.max;
|
||||
dst = std::move(decl);
|
||||
break;
|
||||
}
|
||||
case SOCK_RGBA: {
|
||||
const auto &value = *io_socket.default_value_typed<bNodeSocketValueRGBA>();
|
||||
std::unique_ptr<decl::Color> decl = std::make_unique<decl::Color>();
|
||||
decl->default_value = value.value;
|
||||
dst = std::move(decl);
|
||||
break;
|
||||
}
|
||||
case SOCK_SHADER: {
|
||||
std::unique_ptr<decl::Shader> decl = std::make_unique<decl::Shader>();
|
||||
dst = std::move(decl);
|
||||
break;
|
||||
}
|
||||
case SOCK_BOOLEAN: {
|
||||
const auto &value = *io_socket.default_value_typed<bNodeSocketValueBoolean>();
|
||||
std::unique_ptr<decl::Bool> decl = std::make_unique<decl::Bool>();
|
||||
decl->default_value = value.value;
|
||||
dst = std::move(decl);
|
||||
break;
|
||||
}
|
||||
case SOCK_INT: {
|
||||
const auto &value = *io_socket.default_value_typed<bNodeSocketValueInt>();
|
||||
std::unique_ptr<decl::Int> decl = std::make_unique<decl::Int>();
|
||||
decl->subtype = PropertySubType(io_socket.typeinfo->subtype);
|
||||
decl->default_value = value.value;
|
||||
decl->soft_min_value = value.min;
|
||||
decl->soft_max_value = value.max;
|
||||
dst = std::move(decl);
|
||||
break;
|
||||
}
|
||||
case SOCK_STRING: {
|
||||
const auto &value = *io_socket.default_value_typed<bNodeSocketValueString>();
|
||||
std::unique_ptr<decl::String> decl = std::make_unique<decl::String>();
|
||||
decl->default_value = value.value;
|
||||
dst = std::move(decl);
|
||||
break;
|
||||
}
|
||||
case SOCK_OBJECT:
|
||||
dst = std::make_unique<decl::Object>();
|
||||
break;
|
||||
case SOCK_IMAGE:
|
||||
dst = std::make_unique<decl::Image>();
|
||||
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;
|
||||
dst = std::move(decl);
|
||||
break;
|
||||
}
|
||||
dst->name = io_socket.name;
|
||||
dst->identifier = io_socket.identifier;
|
||||
dst->in_out = eNodeSocketInOut(io_socket.in_out);
|
||||
dst->description = io_socket.description;
|
||||
dst->hide_value = io_socket.flag & SOCK_HIDE_VALUE;
|
||||
dst->compact = io_socket.flag & SOCK_COMPACT;
|
||||
return dst;
|
||||
}
|
||||
|
||||
void node_group_declare_dynamic(const bNodeTree & /*node_tree*/,
|
||||
const bNode &node,
|
||||
NodeDeclaration &r_declaration)
|
||||
{
|
||||
const bNodeTree *group = reinterpret_cast<const bNodeTree *>(node.id);
|
||||
if (!group) {
|
||||
return;
|
||||
}
|
||||
if (ID_IS_LINKED(&group->id) && (group->id.tag & LIB_TAG_MISSING)) {
|
||||
r_declaration.skip_updating_sockets = true;
|
||||
return;
|
||||
}
|
||||
r_declaration.skip_updating_sockets = false;
|
||||
|
||||
LISTBASE_FOREACH (const bNodeSocket *, input, &group->inputs) {
|
||||
r_declaration.inputs.append(declaration_for_interface_socket(*input));
|
||||
}
|
||||
LISTBASE_FOREACH (const bNodeSocket *, output, &group->outputs) {
|
||||
r_declaration.outputs.append(declaration_for_interface_socket(*output));
|
||||
}
|
||||
}
|
||||
|
||||
static void update_socket_to_match_interface(bNodeTree &node_tree,
|
||||
bNode &node,
|
||||
bNodeSocket &socket_to_update,
|
||||
const bNodeSocket &interface_socket)
|
||||
{
|
||||
strcpy(socket_to_update.name, interface_socket.name);
|
||||
|
||||
const int mask = SOCK_HIDE_VALUE;
|
||||
socket_to_update.flag = (socket_to_update.flag & ~mask) | (interface_socket.flag & mask);
|
||||
|
||||
/* Update socket type if necessary */
|
||||
if (socket_to_update.typeinfo != interface_socket.typeinfo) {
|
||||
nodeModifySocketType(&node_tree, &node, &socket_to_update, interface_socket.idname);
|
||||
}
|
||||
|
||||
if (interface_socket.typeinfo->interface_verify_socket) {
|
||||
interface_socket.typeinfo->interface_verify_socket(
|
||||
&node_tree, &interface_socket, &node, &socket_to_update, "interface");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for group nodes and group input/output nodes to update the list of input or output sockets
|
||||
* on a node to match the provided interface. Assumes that \a verify_lb is the node's matching
|
||||
* input or output socket list, depending on whether the node is a group input/output or a group
|
||||
* node.
|
||||
*/
|
||||
static void group_verify_socket_list(bNodeTree &node_tree,
|
||||
bNode &node,
|
||||
const ListBase &interface_sockets,
|
||||
ListBase &verify_lb,
|
||||
const eNodeSocketInOut in_out,
|
||||
const bool ensure_extend_socket_exists)
|
||||
{
|
||||
ListBase old_sockets = verify_lb;
|
||||
Vector<bNodeSocket *> ordered_old_sockets = old_sockets;
|
||||
BLI_listbase_clear(&verify_lb);
|
||||
|
||||
LISTBASE_FOREACH (const bNodeSocket *, interface_socket, &interface_sockets) {
|
||||
bNodeSocket *matching_socket = find_matching_socket(old_sockets, interface_socket->identifier);
|
||||
if (matching_socket) {
|
||||
/* If a socket with the same identifier exists in the previous socket list, update it
|
||||
* with the correct name, type, etc. Then move it from the old list to the new one. */
|
||||
update_socket_to_match_interface(node_tree, node, *matching_socket, *interface_socket);
|
||||
BLI_remlink(&old_sockets, matching_socket);
|
||||
BLI_addtail(&verify_lb, matching_socket);
|
||||
}
|
||||
else {
|
||||
/* If there was no socket with the same identifier already, simply create a new socket
|
||||
* based on the interface socket, which will already add it to the new list. */
|
||||
add_new_socket_from_interface(node_tree, node, *interface_socket, in_out);
|
||||
}
|
||||
}
|
||||
|
||||
if (ensure_extend_socket_exists) {
|
||||
bNodeSocket *last_socket = static_cast<bNodeSocket *>(old_sockets.last);
|
||||
if (last_socket != nullptr && STREQ(last_socket->identifier, "__extend__")) {
|
||||
BLI_remlink(&old_sockets, last_socket);
|
||||
BLI_addtail(&verify_lb, last_socket);
|
||||
}
|
||||
else {
|
||||
nodeAddSocket(&node_tree, &node, in_out, "NodeSocketVirtual", "__extend__", "");
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove leftover sockets that didn't match the node group's interface. */
|
||||
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, unused_socket, &old_sockets) {
|
||||
nodeRemoveSocket(&node_tree, &node, unused_socket);
|
||||
}
|
||||
|
||||
{
|
||||
/* Check if new sockets match the old sockets. */
|
||||
int index;
|
||||
LISTBASE_FOREACH_INDEX (bNodeSocket *, new_socket, &verify_lb, index) {
|
||||
if (index < ordered_old_sockets.size()) {
|
||||
if (ordered_old_sockets[index] != new_socket) {
|
||||
BKE_ntree_update_tag_interface(&node_tree);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void node_group_update(struct bNodeTree *ntree, struct bNode *node)
|
||||
{
|
||||
/* check inputs and outputs, and remove or insert them */
|
||||
if (node->id == nullptr) {
|
||||
nodeRemoveAllSockets(ntree, node);
|
||||
}
|
||||
else if (ID_IS_LINKED(node->id) && (node->id->tag & LIB_TAG_MISSING)) {
|
||||
/* Missing data-block, leave sockets unchanged so that when it comes back
|
||||
* the links remain valid. */
|
||||
}
|
||||
else {
|
||||
bNodeTree *ngroup = (bNodeTree *)node->id;
|
||||
group_verify_socket_list(*ntree, *node, ngroup->inputs, node->inputs, SOCK_IN, false);
|
||||
group_verify_socket_list(*ntree, *node, ngroup->outputs, node->outputs, SOCK_OUT, false);
|
||||
}
|
||||
}
|
||||
} // namespace blender::nodes
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -419,16 +423,6 @@ bool BKE_node_is_connected_to_output(const bNodeTree *ntree, const bNode *node)
|
||||
/** \name Node #GROUP_INPUT / #GROUP_OUTPUT
|
||||
* \{ */
|
||||
|
||||
static bool is_group_extension_socket(const bNode *node, const bNodeSocket *socket)
|
||||
{
|
||||
return socket->type == SOCK_CUSTOM && ELEM(node->type, NODE_GROUP_OUTPUT, NODE_GROUP_INPUT);
|
||||
}
|
||||
|
||||
static void node_group_input_init(bNodeTree *ntree, bNode *node)
|
||||
{
|
||||
node_group_input_update(ntree, node);
|
||||
}
|
||||
|
||||
bNodeSocket *node_group_input_find_socket(bNode *node, const char *identifier)
|
||||
{
|
||||
bNodeSocket *sock;
|
||||
@@ -440,59 +434,83 @@ bNodeSocket *node_group_input_find_socket(bNode *node, const char *identifier)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void node_group_input_update(bNodeTree *ntree, bNode *node)
|
||||
namespace blender::nodes {
|
||||
|
||||
static SocketDeclarationPtr extend_declaration(const eNodeSocketInOut in_out)
|
||||
{
|
||||
bNodeSocket *extsock = (bNodeSocket *)node->outputs.last;
|
||||
/* Adding a tree socket and verifying will remove the extension socket!
|
||||
* This list caches the existing links from the extension socket
|
||||
* so they can be recreated after verification. */
|
||||
Vector<bNodeLink> temp_links;
|
||||
|
||||
/* find links from the extension socket and store them */
|
||||
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
|
||||
if (nodeLinkIsHidden(link)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (link->fromsock == extsock) {
|
||||
temp_links.append(*link);
|
||||
nodeRemLink(ntree, link);
|
||||
}
|
||||
}
|
||||
|
||||
/* find valid link to expose */
|
||||
bNodeLink *exposelink = nullptr;
|
||||
for (bNodeLink &link : temp_links) {
|
||||
/* XXX Multiple sockets can be connected to the extension socket at once,
|
||||
* in that case the arbitrary first link determines name and type.
|
||||
* This could be improved by choosing the "best" type among all links,
|
||||
* whatever that means.
|
||||
*/
|
||||
if (!is_group_extension_socket(link.tonode, link.tosock)) {
|
||||
exposelink = &link;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (exposelink) {
|
||||
bNodeSocket *gsock = ntreeAddSocketInterfaceFromSocket(
|
||||
ntree, exposelink->tonode, exposelink->tosock);
|
||||
|
||||
node_group_input_update(ntree, node);
|
||||
bNodeSocket *newsock = node_group_input_find_socket(node, gsock->identifier);
|
||||
|
||||
/* redirect links from the extension socket */
|
||||
for (bNodeLink &link : temp_links) {
|
||||
bNodeLink *newlink = nodeAddLink(ntree, node, newsock, link.tonode, link.tosock);
|
||||
if (newlink->tosock->flag & SOCK_MULTI_INPUT) {
|
||||
newlink->multi_input_socket_index = link.multi_input_socket_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
group_verify_socket_list(*ntree, *node, ntree->inputs, node->outputs, SOCK_OUT, true);
|
||||
std::unique_ptr<decl::Extend> decl = std::make_unique<decl::Extend>();
|
||||
decl->name = "";
|
||||
decl->identifier = "__extend__";
|
||||
decl->in_out = in_out;
|
||||
return decl;
|
||||
}
|
||||
|
||||
static void group_input_declare_dynamic(const bNodeTree &node_tree,
|
||||
const bNode & /*node*/,
|
||||
NodeDeclaration &r_declaration)
|
||||
{
|
||||
LISTBASE_FOREACH (const bNodeSocket *, input, &node_tree.inputs) {
|
||||
r_declaration.outputs.append(declaration_for_interface_socket(*input));
|
||||
r_declaration.outputs.last()->in_out = SOCK_OUT;
|
||||
}
|
||||
r_declaration.outputs.append(extend_declaration(SOCK_OUT));
|
||||
}
|
||||
|
||||
static void group_output_declare_dynamic(const bNodeTree &node_tree,
|
||||
const bNode & /*node*/,
|
||||
NodeDeclaration &r_declaration)
|
||||
{
|
||||
LISTBASE_FOREACH (const bNodeSocket *, input, &node_tree.outputs) {
|
||||
r_declaration.inputs.append(declaration_for_interface_socket(*input));
|
||||
r_declaration.inputs.last()->in_out = SOCK_IN;
|
||||
}
|
||||
r_declaration.inputs.append(extend_declaration(SOCK_IN));
|
||||
}
|
||||
|
||||
static bool group_input_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
|
||||
{
|
||||
BLI_assert(link->tonode != node);
|
||||
BLI_assert(link->tosock->in_out == SOCK_IN);
|
||||
if (link->fromsock->identifier != StringRef("__extend__")) {
|
||||
return true;
|
||||
}
|
||||
if (link->tosock->identifier == StringRef("__extend__")) {
|
||||
/* Don't connect to other "extend" sockets. */
|
||||
return false;
|
||||
}
|
||||
const bNodeSocket *io_socket = ntreeAddSocketInterfaceFromSocket(
|
||||
ntree, link->tonode, link->tosock);
|
||||
if (!io_socket) {
|
||||
return false;
|
||||
}
|
||||
update_node_declaration_and_sockets(*ntree, *node);
|
||||
link->fromsock = node_group_input_find_socket(node, io_socket->identifier);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool group_output_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
|
||||
{
|
||||
BLI_assert(link->fromnode != node);
|
||||
BLI_assert(link->fromsock->in_out == SOCK_OUT);
|
||||
if (link->tosock->identifier != StringRef("__extend__")) {
|
||||
return true;
|
||||
}
|
||||
if (link->fromsock->identifier == StringRef("__extend__")) {
|
||||
/* Don't connect to other "extend" sockets. */
|
||||
return false;
|
||||
}
|
||||
const bNodeSocket *io_socket = ntreeAddSocketInterfaceFromSocket(
|
||||
ntree, link->fromnode, link->fromsock);
|
||||
if (!io_socket) {
|
||||
return false;
|
||||
}
|
||||
update_node_declaration_and_sockets(*ntree, *node);
|
||||
link->tosock = node_group_output_find_socket(node, io_socket->identifier);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace blender::nodes
|
||||
|
||||
void register_node_type_group_input()
|
||||
{
|
||||
/* used for all tree types, needs dynamic allocation */
|
||||
@@ -501,17 +519,12 @@ void register_node_type_group_input()
|
||||
|
||||
node_type_base(ntype, NODE_GROUP_INPUT, "Group Input", NODE_CLASS_INTERFACE);
|
||||
node_type_size(ntype, 140, 80, 400);
|
||||
ntype->initfunc = node_group_input_init;
|
||||
ntype->updatefunc = node_group_input_update;
|
||||
ntype->declare_dynamic = blender::nodes::group_input_declare_dynamic;
|
||||
ntype->insert_link = blender::nodes::group_input_insert_link;
|
||||
|
||||
nodeRegisterType(ntype);
|
||||
}
|
||||
|
||||
static void node_group_output_init(bNodeTree *ntree, bNode *node)
|
||||
{
|
||||
node_group_output_update(ntree, node);
|
||||
}
|
||||
|
||||
bNodeSocket *node_group_output_find_socket(bNode *node, const char *identifier)
|
||||
{
|
||||
bNodeSocket *sock;
|
||||
@@ -523,57 +536,6 @@ bNodeSocket *node_group_output_find_socket(bNode *node, const char *identifier)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void node_group_output_update(bNodeTree *ntree, bNode *node)
|
||||
{
|
||||
bNodeSocket *extsock = (bNodeSocket *)node->inputs.last;
|
||||
/* Adding a tree socket and verifying will remove the extension socket!
|
||||
* This list caches the existing links to the extension socket
|
||||
* so they can be recreated after verification. */
|
||||
Vector<bNodeLink> temp_links;
|
||||
|
||||
/* find links to the extension socket and store them */
|
||||
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
|
||||
if (nodeLinkIsHidden(link)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (link->tosock == extsock) {
|
||||
temp_links.append(*link);
|
||||
nodeRemLink(ntree, link);
|
||||
}
|
||||
}
|
||||
|
||||
/* find valid link to expose */
|
||||
bNodeLink *exposelink = nullptr;
|
||||
for (bNodeLink &link : temp_links) {
|
||||
/* XXX Multiple sockets can be connected to the extension socket at once,
|
||||
* in that case the arbitrary first link determines name and type.
|
||||
* This could be improved by choosing the "best" type among all links,
|
||||
* whatever that means.
|
||||
*/
|
||||
if (!is_group_extension_socket(link.fromnode, link.fromsock)) {
|
||||
exposelink = &link;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (exposelink) {
|
||||
/* XXX what if connecting virtual to virtual socket?? */
|
||||
bNodeSocket *gsock = ntreeAddSocketInterfaceFromSocket(
|
||||
ntree, exposelink->fromnode, exposelink->fromsock);
|
||||
|
||||
node_group_output_update(ntree, node);
|
||||
bNodeSocket *newsock = node_group_output_find_socket(node, gsock->identifier);
|
||||
|
||||
/* redirect links to the extension socket */
|
||||
for (bNodeLink &link : temp_links) {
|
||||
nodeAddLink(ntree, link.fromnode, link.fromsock, node, newsock);
|
||||
}
|
||||
}
|
||||
|
||||
group_verify_socket_list(*ntree, *node, ntree->outputs, node->inputs, SOCK_IN, true);
|
||||
}
|
||||
|
||||
void register_node_type_group_output()
|
||||
{
|
||||
/* used for all tree types, needs dynamic allocation */
|
||||
@@ -582,8 +544,8 @@ void register_node_type_group_output()
|
||||
|
||||
node_type_base(ntype, NODE_GROUP_OUTPUT, "Group Output", NODE_CLASS_INTERFACE);
|
||||
node_type_size(ntype, 140, 80, 400);
|
||||
ntype->initfunc = node_group_output_init;
|
||||
ntype->updatefunc = node_group_output_update;
|
||||
ntype->declare_dynamic = blender::nodes::group_output_declare_dynamic;
|
||||
ntype->insert_link = blender::nodes::group_output_insert_link;
|
||||
|
||||
ntype->no_muting = true;
|
||||
|
||||
|
@@ -16,6 +16,15 @@ void build_node_declaration(const bNodeType &typeinfo, NodeDeclaration &r_declar
|
||||
node_decl_builder.finalize();
|
||||
}
|
||||
|
||||
void build_node_declaration_dynamic(const bNodeTree &node_tree,
|
||||
const bNode &node,
|
||||
NodeDeclaration &r_declaration)
|
||||
{
|
||||
r_declaration.inputs.clear();
|
||||
r_declaration.outputs.clear();
|
||||
node.typeinfo->declare_dynamic(node_tree, node, r_declaration);
|
||||
}
|
||||
|
||||
void NodeDeclarationBuilder::finalize()
|
||||
{
|
||||
if (is_function_node_) {
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_node.h"
|
||||
#include "BKE_node_runtime.hh"
|
||||
#include "BKE_node_tree_update.h"
|
||||
|
||||
#include "DNA_collection_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
@@ -171,6 +172,8 @@ static void verify_socket_template_list(bNodeTree *ntree,
|
||||
}
|
||||
}
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
static void refresh_socket_list(bNodeTree &ntree,
|
||||
bNode &node,
|
||||
ListBase &sockets,
|
||||
@@ -232,6 +235,7 @@ static void refresh_socket_list(bNodeTree &ntree,
|
||||
}
|
||||
}
|
||||
new_sockets.add_new(new_socket);
|
||||
BKE_ntree_update_tag_socket_new(&ntree, new_socket);
|
||||
}
|
||||
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, old_socket, &sockets) {
|
||||
if (!new_sockets.contains(old_socket)) {
|
||||
@@ -249,10 +253,29 @@ static void refresh_node(bNodeTree &ntree,
|
||||
blender::nodes::NodeDeclaration &node_decl,
|
||||
bool do_id_user)
|
||||
{
|
||||
refresh_socket_list(ntree, node, node.inputs, node_decl.inputs, do_id_user);
|
||||
refresh_socket_list(ntree, node, node.outputs, node_decl.outputs, do_id_user);
|
||||
if (node_decl.skip_updating_sockets) {
|
||||
return;
|
||||
}
|
||||
if (!node_decl.matches(node)) {
|
||||
refresh_socket_list(ntree, node, node.inputs, node_decl.inputs, do_id_user);
|
||||
refresh_socket_list(ntree, node, node.outputs, node_decl.outputs, do_id_user);
|
||||
}
|
||||
nodeSocketDeclarationsUpdate(&node);
|
||||
}
|
||||
|
||||
void update_node_declaration_and_sockets(bNodeTree &ntree, bNode &node)
|
||||
{
|
||||
if (node.typeinfo->declare_dynamic) {
|
||||
if (!node.runtime->declaration) {
|
||||
node.runtime->declaration = new NodeDeclaration();
|
||||
}
|
||||
build_node_declaration_dynamic(ntree, node, *node.runtime->declaration);
|
||||
}
|
||||
refresh_node(ntree, node, *node.runtime->declaration, true);
|
||||
}
|
||||
|
||||
} // namespace blender::nodes
|
||||
|
||||
void node_verify_sockets(bNodeTree *ntree, bNode *node, bool do_id_user)
|
||||
{
|
||||
bNodeType *ntype = node->typeinfo;
|
||||
@@ -261,10 +284,7 @@ void node_verify_sockets(bNodeTree *ntree, bNode *node, bool do_id_user)
|
||||
}
|
||||
if (ntype->declare != nullptr) {
|
||||
nodeDeclarationEnsureOnOutdatedNode(ntree, node);
|
||||
if (!node->runtime->declaration->matches(*node)) {
|
||||
refresh_node(*ntree, *node, *node->runtime->declaration, do_id_user);
|
||||
}
|
||||
nodeSocketDeclarationsUpdate(node);
|
||||
refresh_node(*ntree, *node, *node->runtime->declaration, do_id_user);
|
||||
return;
|
||||
}
|
||||
/* Don't try to match socket lists when there are no templates.
|
||||
@@ -499,52 +519,6 @@ static void standard_node_socket_interface_init_socket(bNodeTree * /*ntree*/,
|
||||
node_socket_copy_default_value(sock, interface_socket);
|
||||
}
|
||||
|
||||
/* copies settings that are not changed for each socket instance */
|
||||
static void standard_node_socket_interface_verify_socket(bNodeTree * /*ntree*/,
|
||||
const bNodeSocket *interface_socket,
|
||||
bNode * /*node*/,
|
||||
bNodeSocket *sock,
|
||||
const char * /*data_path*/)
|
||||
{
|
||||
/* sanity check */
|
||||
if (sock->type != interface_socket->typeinfo->type) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* make sure both exist */
|
||||
if (!interface_socket->default_value) {
|
||||
return;
|
||||
}
|
||||
node_socket_init_default_value(sock);
|
||||
|
||||
switch (interface_socket->typeinfo->type) {
|
||||
case SOCK_FLOAT: {
|
||||
bNodeSocketValueFloat *toval = (bNodeSocketValueFloat *)sock->default_value;
|
||||
const bNodeSocketValueFloat *fromval = (const bNodeSocketValueFloat *)
|
||||
interface_socket->default_value;
|
||||
toval->min = fromval->min;
|
||||
toval->max = fromval->max;
|
||||
break;
|
||||
}
|
||||
case SOCK_INT: {
|
||||
bNodeSocketValueInt *toval = (bNodeSocketValueInt *)sock->default_value;
|
||||
const bNodeSocketValueInt *fromval = (const bNodeSocketValueInt *)
|
||||
interface_socket->default_value;
|
||||
toval->min = fromval->min;
|
||||
toval->max = fromval->max;
|
||||
break;
|
||||
}
|
||||
case SOCK_VECTOR: {
|
||||
bNodeSocketValueVector *toval = (bNodeSocketValueVector *)sock->default_value;
|
||||
const bNodeSocketValueVector *fromval = (const bNodeSocketValueVector *)
|
||||
interface_socket->default_value;
|
||||
toval->min = fromval->min;
|
||||
toval->max = fromval->max;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void standard_node_socket_interface_from_socket(bNodeTree * /*ntree*/,
|
||||
bNodeSocket *stemp,
|
||||
const bNode * /*node*/,
|
||||
@@ -592,7 +566,6 @@ static bNodeSocketType *make_standard_socket_type(int type, int subtype)
|
||||
|
||||
stype->interface_init_socket = standard_node_socket_interface_init_socket;
|
||||
stype->interface_from_socket = standard_node_socket_interface_from_socket;
|
||||
stype->interface_verify_socket = standard_node_socket_interface_verify_socket;
|
||||
|
||||
stype->use_link_limits_of_type = true;
|
||||
stype->input_link_limit = 1;
|
||||
|
@@ -234,6 +234,14 @@ bool Vector::matches(const bNodeSocket &socket) const
|
||||
if (socket.typeinfo->subtype != this->subtype) {
|
||||
return false;
|
||||
}
|
||||
const bNodeSocketValueVector &value = *static_cast<const bNodeSocketValueVector *>(
|
||||
socket.default_value);
|
||||
if (value.min != this->soft_min_value) {
|
||||
return false;
|
||||
}
|
||||
if (value.max != this->soft_max_value) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -257,6 +265,8 @@ bNodeSocket &Vector::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket
|
||||
this->set_common_flags(socket);
|
||||
bNodeSocketValueVector &value = *(bNodeSocketValueVector *)socket.default_value;
|
||||
value.subtype = this->subtype;
|
||||
value.min = this->soft_min_value;
|
||||
value.max = this->soft_max_value;
|
||||
STRNCPY(socket.name, this->name.c_str());
|
||||
return socket;
|
||||
}
|
||||
@@ -301,6 +311,17 @@ bool Bool::can_connect(const bNodeSocket &socket) const
|
||||
return basic_types_can_connect(*this, socket);
|
||||
}
|
||||
|
||||
bNodeSocket &Bool::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
|
||||
{
|
||||
if (socket.type != SOCK_BOOLEAN) {
|
||||
BLI_assert(socket.in_out == this->in_out);
|
||||
return this->build(ntree, node);
|
||||
}
|
||||
this->set_common_flags(socket);
|
||||
STRNCPY(socket.name, this->name.c_str());
|
||||
return socket;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@@ -346,6 +367,17 @@ bool Color::can_connect(const bNodeSocket &socket) const
|
||||
return basic_types_can_connect(*this, socket);
|
||||
}
|
||||
|
||||
bNodeSocket &Color::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
|
||||
{
|
||||
if (socket.type != SOCK_RGBA) {
|
||||
BLI_assert(socket.in_out == this->in_out);
|
||||
return this->build(ntree, node);
|
||||
}
|
||||
this->set_common_flags(socket);
|
||||
STRNCPY(socket.name, this->name.c_str());
|
||||
return socket;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@@ -382,6 +414,17 @@ bool String::can_connect(const bNodeSocket &socket) const
|
||||
return sockets_can_connect(*this, socket) && socket.type == SOCK_STRING;
|
||||
}
|
||||
|
||||
bNodeSocket &String::update_or_build(bNodeTree &ntree, bNode &node, bNodeSocket &socket) const
|
||||
{
|
||||
if (socket.type != SOCK_STRING) {
|
||||
BLI_assert(socket.in_out == this->in_out);
|
||||
return this->build(ntree, node);
|
||||
}
|
||||
this->set_common_flags(socket);
|
||||
STRNCPY(socket.name, this->name.c_str());
|
||||
return socket;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@@ -542,4 +585,77 @@ bool Shader::can_connect(const bNodeSocket &socket) const
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name #Extend
|
||||
* \{ */
|
||||
|
||||
bNodeSocket &Extend::build(bNodeTree &ntree, bNode &node) const
|
||||
{
|
||||
bNodeSocket &socket = *nodeAddSocket(&ntree,
|
||||
&node,
|
||||
this->in_out,
|
||||
"NodeSocketVirtual",
|
||||
this->identifier.c_str(),
|
||||
this->name.c_str());
|
||||
return socket;
|
||||
}
|
||||
|
||||
bool Extend::matches(const bNodeSocket &socket) const
|
||||
{
|
||||
if (socket.identifier != this->identifier) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Extend::can_connect(const bNodeSocket & /*socket*/) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bNodeSocket &Extend::update_or_build(bNodeTree & /*ntree*/,
|
||||
bNode & /*node*/,
|
||||
bNodeSocket &socket) const
|
||||
{
|
||||
return socket;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name #Custom
|
||||
* \{ */
|
||||
|
||||
bNodeSocket &Custom::build(bNodeTree &ntree, bNode &node) const
|
||||
{
|
||||
bNodeSocket &socket = *nodeAddSocket(
|
||||
&ntree, &node, this->in_out, idname_, this->identifier.c_str(), this->name.c_str());
|
||||
return socket;
|
||||
}
|
||||
|
||||
bool Custom::matches(const bNodeSocket &socket) const
|
||||
{
|
||||
if (!this->matches_common_data(socket)) {
|
||||
return false;
|
||||
}
|
||||
if (socket.type != SOCK_CUSTOM) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Custom::can_connect(const bNodeSocket &socket) const
|
||||
{
|
||||
return sockets_can_connect(*this, socket) && STREQ(socket.idname, idname_);
|
||||
}
|
||||
|
||||
bNodeSocket &Custom::update_or_build(bNodeTree & /*ntree*/,
|
||||
bNode & /*node*/,
|
||||
bNodeSocket &socket) const
|
||||
{
|
||||
return socket;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::nodes::decl
|
||||
|
@@ -324,19 +324,19 @@ static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link)
|
||||
bool node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link)
|
||||
{
|
||||
bNodeSocket *socket = link->tosock;
|
||||
|
||||
if (node != link->tonode) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* If we're not at the link limit of the target socket, we can skip
|
||||
* trying to move existing links to another socket. */
|
||||
const int to_link_limit = nodeSocketLinkLimit(socket);
|
||||
if (socket->runtime->total_inputs + 1 < to_link_limit) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH_MUTABLE (bNodeLink *, to_link, &ntree->links) {
|
||||
@@ -345,16 +345,17 @@ void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link)
|
||||
if (new_socket && new_socket != socket) {
|
||||
/* Attempt to redirect the existing link to the new socket. */
|
||||
to_link->tosock = new_socket;
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (new_socket == nullptr) {
|
||||
/* No possible replacement, remove the existing link. */
|
||||
nodeRemLink(ntree, to_link);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@@ -74,7 +74,7 @@ void node_combsep_color_label(const ListBase *sockets, NodeCombSepColorMode mode
|
||||
* already linked (and if its not an Multi Input Socket), we try to find a replacement socket for
|
||||
* the link that we try to overwrite and connect that previous link to the new socket.
|
||||
*/
|
||||
void node_insert_link_default(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link);
|
||||
bool node_insert_link_default(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link);
|
||||
|
||||
float node_socket_get_float(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock);
|
||||
void node_socket_set_float(struct bNodeTree *ntree,
|
||||
|
@@ -132,9 +132,8 @@ void search_link_ops_for_basic_node(GatherLinkSearchOpParams ¶ms)
|
||||
return;
|
||||
}
|
||||
|
||||
if (node_type.declaration_is_dynamic) {
|
||||
/* Dynamic declarations (whatever they end up being) aren't supported
|
||||
* by this function, but still avoid a crash in release builds. */
|
||||
if (node_type.declare_dynamic) {
|
||||
/* Dynamic declarations aren't supported here, but avoid crashing in release builds. */
|
||||
BLI_assert_unreachable();
|
||||
return;
|
||||
}
|
||||
|
@@ -95,7 +95,7 @@ void register_node_type_sh_group()
|
||||
|
||||
node_type_size(&ntype, 140, 60, 400);
|
||||
ntype.labelfunc = node_group_label;
|
||||
ntype.group_update_func = node_group_update;
|
||||
ntype.declare_dynamic = blender::nodes::node_group_declare_dynamic;
|
||||
ntype.gpu_fn = gpu_group_execute;
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
|
@@ -157,7 +157,7 @@ void register_node_type_tex_group(void)
|
||||
|
||||
node_type_size(&ntype, 140, 60, 400);
|
||||
ntype.labelfunc = node_group_label;
|
||||
ntype.group_update_func = node_group_update;
|
||||
ntype.declare_dynamic = blender::nodes::node_group_declare_dynamic;
|
||||
ntype.init_exec_fn = group_initexec;
|
||||
ntype.free_exec_fn = group_freeexec;
|
||||
ntype.exec_fn = group_execute;
|
||||
|
Reference in New Issue
Block a user