diff options
Diffstat (limited to 'source/blender/nodes')
-rw-r--r-- | source/blender/nodes/shader/node_shader_tree.c | 114 |
1 files changed, 113 insertions, 1 deletions
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c index 26973d619d9..311bf43f3e8 100644 --- a/source/blender/nodes/shader/node_shader_tree.c +++ b/source/blender/nodes/shader/node_shader_tree.c @@ -36,6 +36,7 @@ #include "BLI_listbase.h" #include "BLI_threads.h" #include "BLI_utildefines.h" +#include "BLI_alloca.h" #include "BLT_translation.h" @@ -202,6 +203,113 @@ static void ntree_shader_link_builtin_normal(bNodeTree *ntree, bNode *displacement_node, bNodeSocket *displacement_socket); +static bNodeSocket *ntree_shader_node_find_input(bNode *node, + const char *identifier); + +static bNode *ntree_group_output_node(bNodeTree *ntree); + +static bNode *ntree_shader_relink_output_from_group(bNodeTree *ntree, + bNode *group_node, + bNode *sh_output_node, + int target) +{ + int i; + bNodeTree *group_ntree = (bNodeTree *)group_node->id; + + int sock_len = BLI_listbase_count(&sh_output_node->inputs); + bNodeSocket **group_surface_sockets = BLI_array_alloca(group_surface_sockets, sock_len); + + /* Create output sockets to plug output connection to. */ + i = 0; + for (bNodeSocket *sock = sh_output_node->inputs.first; sock; sock = sock->next, ++i) { + group_surface_sockets[i] = + ntreeAddSocketInterface(group_ntree, + SOCK_OUT, + sock->typeinfo->idname, + sock->name); + } + + bNode *group_output_node = ntree_group_output_node(group_ntree); + + /* If no group output node is present, we need to create one. */ + if (group_output_node == NULL) { + group_output_node = nodeAddStaticNode(NULL, group_ntree, NODE_GROUP_OUTPUT); + } + + /* Need to update tree so all node instances nodes gets proper sockets. */ + node_group_verify(ntree, group_node, &group_ntree->id); + node_group_output_verify(group_ntree, group_output_node, &group_ntree->id); + ntreeUpdateTree(G.main, group_ntree); + + /* Remove other shader output nodes so that only the new one can be selected as active. */ + for (bNode *node = ntree->nodes.first; node; node = node->next) { + if (ELEM(node->type, SH_NODE_OUTPUT_MATERIAL, + SH_NODE_OUTPUT_WORLD, + SH_NODE_OUTPUT_LIGHT)) + { + nodeFreeNode(ntree, node); + } + } + + /* Create new shader output node outside the group. */ + bNode *new_output_node = nodeAddStaticNode(NULL, ntree, sh_output_node->type); + new_output_node->custom1 = target; + + i = 0; + for (bNodeSocket *sock = sh_output_node->inputs.first; sock; sock = sock->next, ++i) { + if (sock->link != NULL) { + /* Link the shader output node incoming link to the group output sockets */ + bNodeSocket *group_output_node_surface_input_sock = nodeFindSocket(group_output_node, + SOCK_IN, + group_surface_sockets[i]->identifier); + nodeAddLink(group_ntree, + sock->link->fromnode, sock->link->fromsock, + group_output_node, group_output_node_surface_input_sock); + + /* Link the group output sockets to the new shader output node. */ + bNodeSocket *group_node_surface_output = nodeFindSocket(group_node, + SOCK_OUT, + group_surface_sockets[i]->identifier); + bNodeSocket *output_node_surface_input = ntree_shader_node_find_input(new_output_node, sock->name); + + nodeAddLink(ntree, + group_node, group_node_surface_output, + new_output_node, output_node_surface_input); + } + } + + ntreeUpdateTree(G.main, group_ntree); + ntreeUpdateTree(G.main, ntree); + + return new_output_node; +} + +static bNode *ntree_shader_output_node_from_group(bNodeTree *ntree, int target) +{ + bNode *output_node = NULL; + + /* Search if node groups do not contain valid output nodes (recursively). */ + for (bNode *node = ntree->nodes.first; node; node = node->next) { + if (!ELEM(node->type, NODE_GROUP)){ + continue; + } + if (node->id != NULL) { + output_node = ntree_shader_output_node_from_group((bNodeTree *)node->id, target); + + if (output_node == NULL) { + output_node = ntreeShaderOutputNode((bNodeTree *)node->id, target); + } + + if (output_node != NULL) { + /* Output is inside this group node. Create relink to make the output outside the group. */ + output_node = ntree_shader_relink_output_from_group(ntree, node, output_node, target); + break; + } + } + } + return output_node; +} + /* Find an output node of the shader tree. * * NOTE: it will only return output which is NOT in the group, which isn't how @@ -694,9 +802,13 @@ void ntree_shader_tag_nodes(bNodeTree *ntree, bNode *output_node, nTreeTags *tag /* This one needs to work on a local tree. */ void ntreeGPUMaterialNodes(bNodeTree *localtree, GPUMaterial *mat, bool *has_surface_output, bool *has_volume_output) { - bNode *output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE); bNodeTreeExec *exec; + /* Extract output nodes from inside nodegroups. */ + ntree_shader_output_node_from_group(localtree, SHD_OUTPUT_EEVEE); + + bNode *output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE); + ntree_shader_groups_expand_inputs(localtree); /* Perform all needed modifications on the tree in order to support |