diff options
-rw-r--r-- | release/scripts/startup/nodeitems_builtins.py | 45 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_node_types.h | 5 | ||||
-rw-r--r-- | source/blender/makesrna/RNA_access.h | 1 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_nodetree.c | 16 | ||||
-rw-r--r-- | source/blender/nodes/intern/node_common.c | 169 |
5 files changed, 131 insertions, 105 deletions
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index 09820291222..f130a79ede0 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -94,9 +94,6 @@ def node_group_items(context): 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()) def contains_group(nodetree, group): @@ -123,6 +120,40 @@ def node_group_items(context): 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 def group_input_output_item_poll(context): space = context.space_data @@ -294,6 +325,8 @@ shader_node_categories = [ NodeItem("ShaderNodeScript"), ]), 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=[ NodeItem("NodeFrame"), NodeItem("NodeReroute"), @@ -409,6 +442,8 @@ compositor_node_categories = [ NodeItem("CompositorNodeCornerPin"), ]), 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=[ NodeItem("NodeFrame"), NodeItem("NodeReroute"), @@ -466,6 +501,8 @@ texture_node_categories = [ NodeItem("TextureNodeAt"), ]), 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=[ NodeItem("NodeFrame"), NodeItem("NodeReroute"), @@ -596,6 +633,8 @@ geometry_node_categories = [ NodeItem("GeometryNodeVolumeToMesh"), ]), 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=[ NodeItem("NodeFrame"), NodeItem("NodeReroute"), diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 5152098f57a..5c3cf3f340a 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -616,6 +616,11 @@ typedef struct bNodeSocketValueMaterial { } bNodeSocketValueMaterial; /* Data structs, for node->storage. */ + +typedef enum eNodeGroupInputOutputFlags { + NODE_GROUP_USE_EXTENSION_SOCKET = 1, +} eNodeGroupInputOutputFlags; + enum { CMP_NODE_MASKTYPE_ADD = 0, CMP_NODE_MASKTYPE_SUBTRACT = 1, diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 97615016016..08504b0d8c4 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -453,6 +453,7 @@ extern StructRNA RNA_NodeOutputFileSlotLayer; extern StructRNA RNA_NodeSocket; extern StructRNA RNA_NodeSocketInterface; extern StructRNA RNA_NodeSocketStandard; +extern StructRNA RNA_NodeSocketVirtual; extern StructRNA RNA_NodeTree; extern StructRNA RNA_NoiseGpencilModifier; extern StructRNA RNA_NoiseTexture; diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 3d4256db335..9696b05cf71 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -4650,6 +4650,13 @@ static void def_group_input(StructRNA *srna) RNA_def_property_struct_type(prop, "PropertyGroup"); RNA_def_property_flag(prop, PROP_IDPROPERTY); 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) @@ -4663,6 +4670,15 @@ static void def_group_output(StructRNA *srna) RNA_def_property_flag(prop, PROP_IDPROPERTY); 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); RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_DO_OUTPUT); RNA_def_property_ui_text( diff --git a/source/blender/nodes/intern/node_common.c b/source/blender/nodes/intern/node_common.c index b8c89d1db37..ef0bc18a49c 100644 --- a/source/blender/nodes/intern/node_common.c +++ b/source/blender/nodes/intern/node_common.c @@ -34,6 +34,7 @@ #include "BKE_node.h" +#include "RNA_access.h" #include "RNA_types.h" #include "MEM_guardedalloc.h" @@ -432,33 +433,25 @@ void BKE_node_tree_unlink_id(ID *id, struct bNodeTree *ntree) /** \name Node #GROUP_INPUT / #GROUP_OUTPUT * \{ */ -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) +/* Check if the extension socket is connected and expose internal sockets. */ +static void node_group_handle_extension(bNodeTree *ntree, bNode *node, ListBase *socket_list) { - bNodeSocket *sock; - for (sock = node->outputs.first; sock; sock = sock->next) { - if (STREQ(sock->identifier, identifier)) { - return sock; - } + bNodeSocket *extsock = socket_list->last; + if (!extsock) { + /* Can be called during initial update before the extension socket is added. */ + return; } - 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) -{ - bNodeSocket *extsock = node->outputs.last; - bNodeLink *link, *linknext, *exposelink; + bNodeLink *link, *linknext; /* 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. */ ListBase tmplinks; - /* find links from the extension socket and store them */ + /* Find links from the extension socket and store them. */ BLI_listbase_clear(&tmplinks); for (link = ntree->links.first; link; link = linknext) { linknext = link->next; @@ -466,7 +459,8 @@ void node_group_input_update(bNodeTree *ntree, bNode *node) 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"); *tlink = *link; BLI_addtail(&tmplinks, tlink); @@ -475,42 +469,69 @@ void node_group_input_update(bNodeTree *ntree, bNode *node) } } - /* find valid link to expose */ - exposelink = NULL; + /* Find valid link to expose. */ + bNode *expose_node = NULL; + bNodeSocket *expose_sock = NULL; 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. * This could be improved by choosing the "best" type among all links, * whatever that means. */ - if (link->tosock->type != SOCK_CUSTOM) { - exposelink = link; + if (link->fromsock == extsock && link->tosock->type != SOCK_CUSTOM) { + 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; } } - if (exposelink) { + if (expose_node && expose_sock) { bNodeSocket *gsock, *newsock; - gsock = ntreeAddSocketInterfaceFromSocket(ntree, exposelink->tonode, exposelink->tosock); + gsock = ntreeAddSocketInterfaceFromSocket(ntree, expose_node, expose_sock); - node_group_input_update(ntree, node); - newsock = node_group_input_find_socket(node, gsock->identifier); + if (node->typeinfo->updatefunc) { + node->typeinfo->updatefunc(ntree, node); + } + newsock = BLI_findstring(socket_list, gsock->identifier, offsetof(bNodeSocket, identifier)); /* redirect links from the extension socket */ 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); +} - /* 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->inputs, &node->outputs, SOCK_OUT); +bNodeSocket *node_group_input_find_socket(bNode *node, const char *identifier) +{ + return BLI_findstring(&node->outputs, identifier, offsetof(bNodeSocket, identifier)); +} + +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); - /* add virtual extension socket */ + if (use_extension_socket) { + /* Add virtual extension socket. */ nodeAddSocket(ntree, node, SOCK_OUT, "NodeSocketVirtual", "__extend__", ""); } } @@ -529,86 +550,30 @@ void register_node_type_group_input(void) nodeRegisterType(ntype); } -static void node_group_output_init(bNodeTree *ntree, bNode *node) +bNodeSocket *node_group_output_find_socket(bNode *node, const char *identifier) { - node_group_output_update(ntree, node); + return BLI_findstring(&node->inputs, identifier, offsetof(bNodeSocket, identifier)); } -bNodeSocket *node_group_output_find_socket(bNode *node, const char *identifier) +static void node_group_output_init(bNodeTree *ntree, bNode *node) { - bNodeSocket *sock; - for (sock = node->inputs.first; sock; sock = sock->next) { - if (STREQ(sock->identifier, identifier)) { - return sock; - } - } - return NULL; + node_group_output_update(ntree, node); } void node_group_output_update(bNodeTree *ntree, bNode *node) { - bNodeSocket *extsock = node->inputs.last; - 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; + const bool use_extension_socket = node->custom1 & NODE_GROUP_USE_EXTENSION_SOCKET; - /* find links to the extension socket and store them */ - BLI_listbase_clear(&tmplinks); - 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); - } + if (use_extension_socket) { + node_group_handle_extension(ntree, node, &node->inputs); } - /* find valid link to expose */ - exposelink = NULL; - for (link = tmplinks.first; link; link = link->next) { - /* 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) { - bNodeSocket *gsock, *newsock; - - /* 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); + /* Check group tree interface and remove or insert sockets as needed. */ + /* SOCK_IN/SOCK_OUT is inverted for interface nodes: Group output nodes have input sockets. */ + group_verify_socket_list(ntree, node, &ntree->outputs, &node->inputs, SOCK_IN); - /* add virtual extension socket */ + if (use_extension_socket) { + /* Add virtual extension socket */ nodeAddSocket(ntree, node, SOCK_IN, "NodeSocketVirtual", "__extend__", ""); } } |