Compare commits
14 Commits
tmp-eevee-
...
node-group
Author | SHA1 | Date | |
---|---|---|---|
fd7e8634fa | |||
f2fb5b6ff2 | |||
9bff211ac9 | |||
23209dc8f9 | |||
04379b5bde | |||
c21fc1687e | |||
f83f5ef6e7 | |||
0e8542ebb7 | |||
94f1726526 | |||
add2815723 | |||
7d66c04841 | |||
a91212e147 | |||
3366fc265b | |||
8cab5afe46 |
@@ -94,9 +94,6 @@ def node_group_items(context):
|
|||||||
|
|
||||||
yield NodeItemCustom(draw=group_tools_draw)
|
yield NodeItemCustom(draw=group_tools_draw)
|
||||||
|
|
||||||
yield NodeItem("NodeGroupInput", poll=group_input_output_item_poll)
|
|
||||||
yield NodeItem("NodeGroupOutput", poll=group_input_output_item_poll)
|
|
||||||
|
|
||||||
yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
|
yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
|
||||||
|
|
||||||
def contains_group(nodetree, group):
|
def contains_group(nodetree, group):
|
||||||
@@ -123,6 +120,40 @@ def node_group_items(context):
|
|||||||
settings={"node_tree": "bpy.data.node_groups[%r]" % group.name})
|
settings={"node_tree": "bpy.data.node_groups[%r]" % group.name})
|
||||||
|
|
||||||
|
|
||||||
|
def node_group_input_items(context):
|
||||||
|
if context is None:
|
||||||
|
return
|
||||||
|
space = context.space_data
|
||||||
|
if not space:
|
||||||
|
return
|
||||||
|
ntree = space.edit_tree
|
||||||
|
if not ntree:
|
||||||
|
return
|
||||||
|
|
||||||
|
for i, iosock in enumerate(ntree.inputs):
|
||||||
|
settings = dict()
|
||||||
|
settings["use_extension_socket"] = "False"
|
||||||
|
for k, _ in enumerate(ntree.inputs):
|
||||||
|
settings["outputs[{}].hide".format(k)] = "False" if k == i else "True"
|
||||||
|
yield NodeItem("NodeGroupInput", label=iosock.name, settings=settings, poll=group_input_output_item_poll)
|
||||||
|
|
||||||
|
|
||||||
|
def node_group_output_items(context):
|
||||||
|
if context is None:
|
||||||
|
return
|
||||||
|
space = context.space_data
|
||||||
|
if not space:
|
||||||
|
return
|
||||||
|
ntree = space.edit_tree
|
||||||
|
if not ntree:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Node groups are not added as single-socket nodes currently, because only one node can be active output.
|
||||||
|
# Dividing group output between multiple nodes will require changes to the "active output" concept (NODE_DO_OUTPUT flag).
|
||||||
|
|
||||||
|
yield NodeItem("NodeGroupOutput", poll=group_input_output_item_poll)
|
||||||
|
|
||||||
|
|
||||||
# only show input/output nodes inside node groups
|
# only show input/output nodes inside node groups
|
||||||
def group_input_output_item_poll(context):
|
def group_input_output_item_poll(context):
|
||||||
space = context.space_data
|
space = context.space_data
|
||||||
@@ -294,6 +325,8 @@ shader_node_categories = [
|
|||||||
NodeItem("ShaderNodeScript"),
|
NodeItem("ShaderNodeScript"),
|
||||||
]),
|
]),
|
||||||
ShaderNodeCategory("SH_NEW_GROUP", "Group", items=node_group_items),
|
ShaderNodeCategory("SH_NEW_GROUP", "Group", items=node_group_items),
|
||||||
|
ShaderNodeCategory("SH_NEW_GROUP_INPUTS", "Group Inputs", items=node_group_input_items),
|
||||||
|
ShaderNodeCategory("SH_NEW_GROUP_OUTPUTS", "Group Outputs", items=node_group_output_items),
|
||||||
ShaderNodeCategory("SH_NEW_LAYOUT", "Layout", items=[
|
ShaderNodeCategory("SH_NEW_LAYOUT", "Layout", items=[
|
||||||
NodeItem("NodeFrame"),
|
NodeItem("NodeFrame"),
|
||||||
NodeItem("NodeReroute"),
|
NodeItem("NodeReroute"),
|
||||||
@@ -409,6 +442,8 @@ compositor_node_categories = [
|
|||||||
NodeItem("CompositorNodeCornerPin"),
|
NodeItem("CompositorNodeCornerPin"),
|
||||||
]),
|
]),
|
||||||
CompositorNodeCategory("CMP_GROUP", "Group", items=node_group_items),
|
CompositorNodeCategory("CMP_GROUP", "Group", items=node_group_items),
|
||||||
|
CompositorNodeCategory("CMP_GROUP_INPUTS", "Group Inputs", items=node_group_input_items),
|
||||||
|
CompositorNodeCategory("CMP_GROUP_OUTPUTS", "Group Outputs", items=node_group_output_items),
|
||||||
CompositorNodeCategory("CMP_LAYOUT", "Layout", items=[
|
CompositorNodeCategory("CMP_LAYOUT", "Layout", items=[
|
||||||
NodeItem("NodeFrame"),
|
NodeItem("NodeFrame"),
|
||||||
NodeItem("NodeReroute"),
|
NodeItem("NodeReroute"),
|
||||||
@@ -466,6 +501,8 @@ texture_node_categories = [
|
|||||||
NodeItem("TextureNodeAt"),
|
NodeItem("TextureNodeAt"),
|
||||||
]),
|
]),
|
||||||
TextureNodeCategory("TEX_GROUP", "Group", items=node_group_items),
|
TextureNodeCategory("TEX_GROUP", "Group", items=node_group_items),
|
||||||
|
TextureNodeCategory("TEX_GROUP_INPUTS", "Group Inputs", items=node_group_input_items),
|
||||||
|
TextureNodeCategory("TEX_GROUP_OUTPUTS", "Group Outputs", items=node_group_output_items),
|
||||||
TextureNodeCategory("TEX_LAYOUT", "Layout", items=[
|
TextureNodeCategory("TEX_LAYOUT", "Layout", items=[
|
||||||
NodeItem("NodeFrame"),
|
NodeItem("NodeFrame"),
|
||||||
NodeItem("NodeReroute"),
|
NodeItem("NodeReroute"),
|
||||||
@@ -596,6 +633,8 @@ geometry_node_categories = [
|
|||||||
NodeItem("GeometryNodeVolumeToMesh"),
|
NodeItem("GeometryNodeVolumeToMesh"),
|
||||||
]),
|
]),
|
||||||
GeometryNodeCategory("GEO_GROUP", "Group", items=node_group_items),
|
GeometryNodeCategory("GEO_GROUP", "Group", items=node_group_items),
|
||||||
|
GeometryNodeCategory("GEO_GROUP_INPUTS", "Group Inputs", items=node_group_input_items),
|
||||||
|
GeometryNodeCategory("GEO_GROUP_OUTPUTS", "Group Outputs", items=node_group_output_items),
|
||||||
GeometryNodeCategory("GEO_LAYOUT", "Layout", items=[
|
GeometryNodeCategory("GEO_LAYOUT", "Layout", items=[
|
||||||
NodeItem("NodeFrame"),
|
NodeItem("NodeFrame"),
|
||||||
NodeItem("NodeReroute"),
|
NodeItem("NodeReroute"),
|
||||||
|
@@ -616,6 +616,11 @@ typedef struct bNodeSocketValueMaterial {
|
|||||||
} bNodeSocketValueMaterial;
|
} bNodeSocketValueMaterial;
|
||||||
|
|
||||||
/* Data structs, for node->storage. */
|
/* Data structs, for node->storage. */
|
||||||
|
|
||||||
|
typedef enum eNodeGroupInputOutputFlags {
|
||||||
|
NODE_GROUP_USE_EXTENSION_SOCKET = 1,
|
||||||
|
} eNodeGroupInputOutputFlags;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
CMP_NODE_MASKTYPE_ADD = 0,
|
CMP_NODE_MASKTYPE_ADD = 0,
|
||||||
CMP_NODE_MASKTYPE_SUBTRACT = 1,
|
CMP_NODE_MASKTYPE_SUBTRACT = 1,
|
||||||
|
@@ -453,6 +453,7 @@ extern StructRNA RNA_NodeOutputFileSlotLayer;
|
|||||||
extern StructRNA RNA_NodeSocket;
|
extern StructRNA RNA_NodeSocket;
|
||||||
extern StructRNA RNA_NodeSocketInterface;
|
extern StructRNA RNA_NodeSocketInterface;
|
||||||
extern StructRNA RNA_NodeSocketStandard;
|
extern StructRNA RNA_NodeSocketStandard;
|
||||||
|
extern StructRNA RNA_NodeSocketVirtual;
|
||||||
extern StructRNA RNA_NodeTree;
|
extern StructRNA RNA_NodeTree;
|
||||||
extern StructRNA RNA_NoiseGpencilModifier;
|
extern StructRNA RNA_NoiseGpencilModifier;
|
||||||
extern StructRNA RNA_NoiseTexture;
|
extern StructRNA RNA_NoiseTexture;
|
||||||
|
@@ -4650,6 +4650,13 @@ static void def_group_input(StructRNA *srna)
|
|||||||
RNA_def_property_struct_type(prop, "PropertyGroup");
|
RNA_def_property_struct_type(prop, "PropertyGroup");
|
||||||
RNA_def_property_flag(prop, PROP_IDPROPERTY);
|
RNA_def_property_flag(prop, PROP_IDPROPERTY);
|
||||||
RNA_def_property_ui_text(prop, "Interface", "Interface socket data");
|
RNA_def_property_ui_text(prop, "Interface", "Interface socket data");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "use_extension_socket", PROP_BOOLEAN, PROP_NONE);
|
||||||
|
RNA_def_property_boolean_sdna(prop, NULL, "custom1", NODE_GROUP_USE_EXTENSION_SOCKET);
|
||||||
|
RNA_def_property_boolean_default(prop, true);
|
||||||
|
RNA_def_property_ui_text(
|
||||||
|
prop, "Use Extension Socket", "Add a virtual socket to the node for extending the node group interface");
|
||||||
|
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void def_group_output(StructRNA *srna)
|
static void def_group_output(StructRNA *srna)
|
||||||
@@ -4663,6 +4670,15 @@ static void def_group_output(StructRNA *srna)
|
|||||||
RNA_def_property_flag(prop, PROP_IDPROPERTY);
|
RNA_def_property_flag(prop, PROP_IDPROPERTY);
|
||||||
RNA_def_property_ui_text(prop, "Interface", "Interface socket data");
|
RNA_def_property_ui_text(prop, "Interface", "Interface socket data");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "use_extension_socket", PROP_BOOLEAN, PROP_NONE);
|
||||||
|
RNA_def_property_boolean_sdna(prop, NULL, "custom1", NODE_GROUP_USE_EXTENSION_SOCKET);
|
||||||
|
RNA_def_property_boolean_default(prop, true);
|
||||||
|
RNA_def_property_ui_text(
|
||||||
|
prop,
|
||||||
|
"Use Extension Socket",
|
||||||
|
"Add a virtual socket to the node for extending the node group interface");
|
||||||
|
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
|
||||||
|
|
||||||
prop = RNA_def_property(srna, "is_active_output", PROP_BOOLEAN, PROP_NONE);
|
prop = RNA_def_property(srna, "is_active_output", PROP_BOOLEAN, PROP_NONE);
|
||||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_DO_OUTPUT);
|
RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_DO_OUTPUT);
|
||||||
RNA_def_property_ui_text(
|
RNA_def_property_ui_text(
|
||||||
|
@@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
#include "BKE_node.h"
|
#include "BKE_node.h"
|
||||||
|
|
||||||
|
#include "RNA_access.h"
|
||||||
#include "RNA_types.h"
|
#include "RNA_types.h"
|
||||||
|
|
||||||
#include "MEM_guardedalloc.h"
|
#include "MEM_guardedalloc.h"
|
||||||
@@ -121,8 +122,12 @@ bool nodeGroupPoll(bNodeTree *nodetree, bNodeTree *grouptree, const char **r_dis
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* used for both group nodes and interface nodes */
|
/* used for both group nodes and interface nodes */
|
||||||
static bNodeSocket *group_verify_socket(
|
static bNodeSocket *group_verify_socket(bNodeTree *ntree,
|
||||||
bNodeTree *ntree, bNode *gnode, bNodeSocket *iosock, ListBase *verify_lb, int in_out)
|
bNode *gnode,
|
||||||
|
bNodeSocket *iosock,
|
||||||
|
ListBase *verify_lb,
|
||||||
|
int in_out,
|
||||||
|
bool hide_new)
|
||||||
{
|
{
|
||||||
bNodeSocket *sock;
|
bNodeSocket *sock;
|
||||||
|
|
||||||
@@ -151,6 +156,9 @@ static bNodeSocket *group_verify_socket(
|
|||||||
else {
|
else {
|
||||||
sock = nodeAddSocket(ntree, gnode, in_out, iosock->idname, iosock->identifier, iosock->name);
|
sock = nodeAddSocket(ntree, gnode, in_out, iosock->idname, iosock->identifier, iosock->name);
|
||||||
|
|
||||||
|
if (hide_new) {
|
||||||
|
sock->flag |= SOCK_HIDDEN;
|
||||||
|
}
|
||||||
if (iosock->typeinfo->interface_init_socket) {
|
if (iosock->typeinfo->interface_init_socket) {
|
||||||
iosock->typeinfo->interface_init_socket(ntree, iosock, gnode, sock, "interface");
|
iosock->typeinfo->interface_init_socket(ntree, iosock, gnode, sock, "interface");
|
||||||
}
|
}
|
||||||
@@ -163,8 +171,12 @@ static bNodeSocket *group_verify_socket(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* used for both group nodes and interface nodes */
|
/* used for both group nodes and interface nodes */
|
||||||
static void group_verify_socket_list(
|
static void group_verify_socket_list(bNodeTree *ntree,
|
||||||
bNodeTree *ntree, bNode *gnode, ListBase *iosock_lb, ListBase *verify_lb, int in_out)
|
bNode *gnode,
|
||||||
|
ListBase *iosock_lb,
|
||||||
|
ListBase *verify_lb,
|
||||||
|
int in_out,
|
||||||
|
bool hide_new)
|
||||||
{
|
{
|
||||||
bNodeSocket *iosock, *sock, *nextsock;
|
bNodeSocket *iosock, *sock, *nextsock;
|
||||||
|
|
||||||
@@ -173,7 +185,7 @@ static void group_verify_socket_list(
|
|||||||
iosock = iosock_lb->first;
|
iosock = iosock_lb->first;
|
||||||
for (; iosock; iosock = iosock->next) {
|
for (; iosock; iosock = iosock->next) {
|
||||||
/* abusing new_sock pointer for verification here! only used inside this function */
|
/* abusing new_sock pointer for verification here! only used inside this function */
|
||||||
iosock->new_sock = group_verify_socket(ntree, gnode, iosock, verify_lb, in_out);
|
iosock->new_sock = group_verify_socket(ntree, gnode, iosock, verify_lb, in_out, hide_new);
|
||||||
}
|
}
|
||||||
/* leftovers are removed */
|
/* leftovers are removed */
|
||||||
for (sock = verify_lb->first; sock; sock = nextsock) {
|
for (sock = verify_lb->first; sock; sock = nextsock) {
|
||||||
@@ -203,8 +215,8 @@ void node_group_update(struct bNodeTree *ntree, struct bNode *node)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
bNodeTree *ngroup = (bNodeTree *)node->id;
|
bNodeTree *ngroup = (bNodeTree *)node->id;
|
||||||
group_verify_socket_list(ntree, node, &ngroup->inputs, &node->inputs, SOCK_IN);
|
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);
|
group_verify_socket_list(ntree, node, &ngroup->outputs, &node->outputs, SOCK_OUT, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -432,33 +444,25 @@ void BKE_node_tree_unlink_id(ID *id, struct bNodeTree *ntree)
|
|||||||
/** \name Node #GROUP_INPUT / #GROUP_OUTPUT
|
/** \name Node #GROUP_INPUT / #GROUP_OUTPUT
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
static void node_group_input_init(bNodeTree *ntree, bNode *node)
|
/* Check if the extension socket is connected and expose internal sockets. */
|
||||||
|
static void node_group_handle_extension(bNodeTree *ntree, bNode *node, ListBase *socket_list)
|
||||||
{
|
{
|
||||||
node_group_input_update(ntree, node);
|
bNodeSocket *extsock = socket_list->last;
|
||||||
}
|
if (!extsock) {
|
||||||
|
/* Can be called during initial update before the extension socket is added. */
|
||||||
bNodeSocket *node_group_input_find_socket(bNode *node, const char *identifier)
|
return;
|
||||||
{
|
|
||||||
bNodeSocket *sock;
|
|
||||||
for (sock = node->outputs.first; sock; sock = sock->next) {
|
|
||||||
if (STREQ(sock->identifier, identifier)) {
|
|
||||||
return sock;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return NULL;
|
/* This function should only be called when virtual sockets are enabled. */
|
||||||
}
|
BLI_assert(RNA_struct_is_a(extsock->typeinfo->ext_socket.srna, &RNA_NodeSocketVirtual));
|
||||||
|
|
||||||
void node_group_input_update(bNodeTree *ntree, bNode *node)
|
bNodeLink *link, *linknext;
|
||||||
{
|
|
||||||
bNodeSocket *extsock = node->outputs.last;
|
|
||||||
bNodeLink *link, *linknext, *exposelink;
|
|
||||||
/* Adding a tree socket and verifying will remove the extension socket!
|
/* Adding a tree socket and verifying will remove the extension socket!
|
||||||
* This list caches the existing links from the extension socket
|
* This list caches the existing links from the extension socket
|
||||||
* so they can be recreated after verification.
|
* so they can be recreated after verification.
|
||||||
*/
|
*/
|
||||||
ListBase tmplinks;
|
ListBase tmplinks;
|
||||||
|
|
||||||
/* find links from the extension socket and store them */
|
/* Find links from the extension socket and store them. */
|
||||||
BLI_listbase_clear(&tmplinks);
|
BLI_listbase_clear(&tmplinks);
|
||||||
for (link = ntree->links.first; link; link = linknext) {
|
for (link = ntree->links.first; link; link = linknext) {
|
||||||
linknext = link->next;
|
linknext = link->next;
|
||||||
@@ -466,7 +470,8 @@ void node_group_input_update(bNodeTree *ntree, bNode *node)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link->fromsock == extsock) {
|
/* Check both fromsock and tosock so it works for input as well as outputs. */
|
||||||
|
if (link->fromsock == extsock || link->tosock == extsock) {
|
||||||
bNodeLink *tlink = MEM_callocN(sizeof(bNodeLink), "temporary link");
|
bNodeLink *tlink = MEM_callocN(sizeof(bNodeLink), "temporary link");
|
||||||
*tlink = *link;
|
*tlink = *link;
|
||||||
BLI_addtail(&tmplinks, tlink);
|
BLI_addtail(&tmplinks, tlink);
|
||||||
@@ -475,42 +480,69 @@ void node_group_input_update(bNodeTree *ntree, bNode *node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find valid link to expose */
|
/* Find valid link to expose. */
|
||||||
exposelink = NULL;
|
bNode *expose_node = NULL;
|
||||||
|
bNodeSocket *expose_sock = NULL;
|
||||||
for (link = tmplinks.first; link; link = link->next) {
|
for (link = tmplinks.first; link; link = link->next) {
|
||||||
/* XXX Multiple sockets can be connected to the extension socket at once,
|
/* Multiple sockets can be connected to the extension socket at once,
|
||||||
* in that case the arbitrary first link determines name and type.
|
* in that case the arbitrary first link determines name and type.
|
||||||
* This could be improved by choosing the "best" type among all links,
|
* This could be improved by choosing the "best" type among all links,
|
||||||
* whatever that means.
|
* whatever that means.
|
||||||
*/
|
*/
|
||||||
if (link->tosock->type != SOCK_CUSTOM) {
|
if (link->fromsock == extsock && link->tosock->type != SOCK_CUSTOM) {
|
||||||
exposelink = link;
|
expose_node = link->tonode;
|
||||||
|
expose_sock = link->tosock;
|
||||||
|
}
|
||||||
|
else if (link->tosock == extsock && link->fromsock->type != SOCK_CUSTOM) {
|
||||||
|
expose_node = link->fromnode;
|
||||||
|
expose_sock = link->fromsock;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exposelink) {
|
if (expose_node && expose_sock) {
|
||||||
bNodeSocket *gsock, *newsock;
|
bNodeSocket *gsock, *newsock;
|
||||||
|
|
||||||
gsock = ntreeAddSocketInterfaceFromSocket(ntree, exposelink->tonode, exposelink->tosock);
|
gsock = ntreeAddSocketInterfaceFromSocket(ntree, expose_node, expose_sock);
|
||||||
|
|
||||||
node_group_input_update(ntree, node);
|
if (node->typeinfo->updatefunc) {
|
||||||
newsock = node_group_input_find_socket(node, gsock->identifier);
|
node->typeinfo->updatefunc(ntree, node);
|
||||||
|
}
|
||||||
|
newsock = BLI_findstring(socket_list, gsock->identifier, offsetof(bNodeSocket, identifier));
|
||||||
|
|
||||||
/* redirect links from the extension socket */
|
/* redirect links from the extension socket */
|
||||||
for (link = tmplinks.first; link; link = link->next) {
|
for (link = tmplinks.first; link; link = link->next) {
|
||||||
nodeAddLink(ntree, node, newsock, link->tonode, link->tosock);
|
nodeAddLink(ntree, node, newsock, expose_node, expose_sock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BLI_freelistN(&tmplinks);
|
BLI_freelistN(&tmplinks);
|
||||||
|
}
|
||||||
|
|
||||||
/* check inputs and outputs, and remove or insert them */
|
bNodeSocket *node_group_input_find_socket(bNode *node, const char *identifier)
|
||||||
{
|
{
|
||||||
/* value_in_out inverted for interface nodes to get correct socket value_property */
|
return BLI_findstring(&node->outputs, identifier, offsetof(bNodeSocket, identifier));
|
||||||
group_verify_socket_list(ntree, node, &ntree->inputs, &node->outputs, SOCK_OUT);
|
}
|
||||||
|
|
||||||
/* add virtual extension socket */
|
static void node_group_input_init(bNodeTree *ntree, bNode *node)
|
||||||
|
{
|
||||||
|
node_group_input_update(ntree, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void node_group_input_update(bNodeTree *ntree, bNode *node)
|
||||||
|
{
|
||||||
|
const bool use_extension_socket = node->custom1 & NODE_GROUP_USE_EXTENSION_SOCKET;
|
||||||
|
|
||||||
|
if (use_extension_socket) {
|
||||||
|
node_group_handle_extension(ntree, node, &node->outputs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check group tree interface and remove or insert sockets as needed. */
|
||||||
|
/* SOCK_IN/SOCK_OUT is inverted for interface nodes: Group input nodes have output sockets. */
|
||||||
|
group_verify_socket_list(ntree, node, &ntree->inputs, &node->outputs, SOCK_OUT, true);
|
||||||
|
|
||||||
|
if (use_extension_socket) {
|
||||||
|
/* Add virtual extension socket. */
|
||||||
nodeAddSocket(ntree, node, SOCK_OUT, "NodeSocketVirtual", "__extend__", "");
|
nodeAddSocket(ntree, node, SOCK_OUT, "NodeSocketVirtual", "__extend__", "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -529,86 +561,30 @@ void register_node_type_group_input(void)
|
|||||||
nodeRegisterType(ntype);
|
nodeRegisterType(ntype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bNodeSocket *node_group_output_find_socket(bNode *node, const char *identifier)
|
||||||
|
{
|
||||||
|
return BLI_findstring(&node->inputs, identifier, offsetof(bNodeSocket, identifier));
|
||||||
|
}
|
||||||
|
|
||||||
static void node_group_output_init(bNodeTree *ntree, bNode *node)
|
static void node_group_output_init(bNodeTree *ntree, bNode *node)
|
||||||
{
|
{
|
||||||
node_group_output_update(ntree, node);
|
node_group_output_update(ntree, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
bNodeSocket *node_group_output_find_socket(bNode *node, const char *identifier)
|
|
||||||
{
|
|
||||||
bNodeSocket *sock;
|
|
||||||
for (sock = node->inputs.first; sock; sock = sock->next) {
|
|
||||||
if (STREQ(sock->identifier, identifier)) {
|
|
||||||
return sock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void node_group_output_update(bNodeTree *ntree, bNode *node)
|
void node_group_output_update(bNodeTree *ntree, bNode *node)
|
||||||
{
|
{
|
||||||
bNodeSocket *extsock = node->inputs.last;
|
const bool use_extension_socket = node->custom1 & NODE_GROUP_USE_EXTENSION_SOCKET;
|
||||||
bNodeLink *link, *linknext, *exposelink;
|
|
||||||
/* 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.
|
|
||||||
*/
|
|
||||||
ListBase tmplinks;
|
|
||||||
|
|
||||||
/* find links to the extension socket and store them */
|
if (use_extension_socket) {
|
||||||
BLI_listbase_clear(&tmplinks);
|
node_group_handle_extension(ntree, node, &node->inputs);
|
||||||
for (link = ntree->links.first; link; link = linknext) {
|
|
||||||
linknext = link->next;
|
|
||||||
if (nodeLinkIsHidden(link)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (link->tosock == extsock) {
|
|
||||||
bNodeLink *tlink = MEM_callocN(sizeof(bNodeLink), "temporary link");
|
|
||||||
*tlink = *link;
|
|
||||||
BLI_addtail(&tmplinks, tlink);
|
|
||||||
|
|
||||||
nodeRemLink(ntree, link);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find valid link to expose */
|
/* Check group tree interface and remove or insert sockets as needed. */
|
||||||
exposelink = NULL;
|
/* SOCK_IN/SOCK_OUT is inverted for interface nodes: Group output nodes have input sockets. */
|
||||||
for (link = tmplinks.first; link; link = link->next) {
|
group_verify_socket_list(ntree, node, &ntree->outputs, &node->inputs, SOCK_IN, false);
|
||||||
/* 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 (link->fromsock->type != SOCK_CUSTOM) {
|
|
||||||
exposelink = link;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exposelink) {
|
if (use_extension_socket) {
|
||||||
bNodeSocket *gsock, *newsock;
|
/* Add virtual extension socket */
|
||||||
|
|
||||||
/* XXX what if connecting virtual to virtual socket?? */
|
|
||||||
gsock = ntreeAddSocketInterfaceFromSocket(ntree, exposelink->fromnode, exposelink->fromsock);
|
|
||||||
|
|
||||||
node_group_output_update(ntree, node);
|
|
||||||
newsock = node_group_output_find_socket(node, gsock->identifier);
|
|
||||||
|
|
||||||
/* redirect links to the extension socket */
|
|
||||||
for (link = tmplinks.first; link; link = link->next) {
|
|
||||||
nodeAddLink(ntree, link->fromnode, link->fromsock, node, newsock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BLI_freelistN(&tmplinks);
|
|
||||||
|
|
||||||
/* check inputs and outputs, and remove or insert them */
|
|
||||||
{
|
|
||||||
/* value_in_out inverted for interface nodes to get correct socket value_property */
|
|
||||||
group_verify_socket_list(ntree, node, &ntree->outputs, &node->inputs, SOCK_IN);
|
|
||||||
|
|
||||||
/* add virtual extension socket */
|
|
||||||
nodeAddSocket(ntree, node, SOCK_IN, "NodeSocketVirtual", "__extend__", "");
|
nodeAddSocket(ntree, node, SOCK_IN, "NodeSocketVirtual", "__extend__", "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user