void BKE_linestyle_default_shader(const bContext *C, FreestyleLineStyle *linestyle) { bNode *uv_along_stroke, *input_texure, *output_linestyle; bNodeSocket *fromsock, *tosock; bNodeTree *ntree; BLI_assert(linestyle->nodetree == NULL); ntree = ntreeAddTree(NULL, "stroke_shader", "ShaderNodeTree"); linestyle->nodetree = ntree; uv_along_stroke = nodeAddStaticNode(C, ntree, SH_NODE_UVALONGSTROKE); uv_along_stroke->locx = 0.0f; uv_along_stroke->locy = 300.0f; uv_along_stroke->custom1 = 0; // use_tips input_texure = nodeAddStaticNode(C, ntree, SH_NODE_TEX_IMAGE); input_texure->locx = 200.0f; input_texure->locy = 300.0f; output_linestyle = nodeAddStaticNode(C, ntree, SH_NODE_OUTPUT_LINESTYLE); output_linestyle->locx = 400.0f; output_linestyle->locy = 300.0f; output_linestyle->custom1 = MA_RAMP_BLEND; output_linestyle->custom2 = 0; // use_clamp nodeSetActive(ntree, input_texure); fromsock = BLI_findlink(&uv_along_stroke->outputs, 0); // UV tosock = BLI_findlink(&input_texure->inputs, 0); // UV nodeAddLink(ntree, uv_along_stroke, fromsock, input_texure, tosock); fromsock = BLI_findlink(&input_texure->outputs, 0); // Color tosock = BLI_findlink(&output_linestyle->inputs, 0); // Color nodeAddLink(ntree, input_texure, fromsock, output_linestyle, tosock); ntreeUpdateTree(CTX_data_main(C), ntree); }
/* Re-link displacement output to unconnected normal sockets via bump node. * This way material with have proper displacement in the viewport. */ static void ntree_shader_relink_displacement(bNodeTree *ntree, short compatibility) { if (compatibility != NODE_NEW_SHADING) { /* We can only deal with new shading system here. */ return; } bNode *displacement_node; bNodeSocket *displacement_socket; bNodeLink *displacement_link; if (!ntree_shader_has_displacement(ntree, &displacement_node, &displacement_socket, &displacement_link)) { /* There is no displacement output connected, nothing to re-link. */ return; } /* We have to disconnect displacement output socket, otherwise we'll have * cycles in the Cycles material :) */ nodeRemLink(ntree, displacement_link); /* We can't connect displacement to normal directly, use bump node for that * and hope that it gives good enough approximation. */ bNode *bump_node = nodeAddStaticNode(NULL, ntree, SH_NODE_BUMP); bNodeSocket *bump_input_socket = ntree_shader_node_find_input(bump_node, "Height"); bNodeSocket *bump_output_socket = ntree_shader_node_find_output(bump_node, "Normal"); BLI_assert(bump_input_socket != NULL); BLI_assert(bump_output_socket != NULL); /* Connect bump node to where displacement output was originally * connected to. */ nodeAddLink(ntree, displacement_node, displacement_socket, bump_node, bump_input_socket); /* Connect all free-standing Normal inputs. */ ntree_shader_link_builtin_normal(ntree, bump_node, bump_output_socket, displacement_node, displacement_socket); /* TODO(sergey): Reconnect Geometry Info->Normal sockets to the new * bump node. */ /* We modified the tree, it needs to be updated now. */ ntreeUpdateTree(G.main, ntree); }
static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree, bNode *gnode) { bNodeTree *ngroup = (bNodeTree *)gnode->id; bNodeLink *link, *linkn; bNode *node, *nextn; bNodeSocket *sock; ListBase anim_basepaths = {NULL, NULL}; float min[2], max[2], center[2]; int totselect; int expose_all = FALSE; bNode *input_node, *output_node; /* XXX rough guess, not nice but we don't have access to UI constants here ... */ static const float offsetx = 200; static const float offsety = 0.0f; /* deselect all nodes in the target tree */ for (node = ngroup->nodes.first; node; node = node->next) nodeSetSelected(node, FALSE); totselect = node_get_selected_minmax(ntree, gnode, min, max); add_v2_v2v2(center, min, max); mul_v2_fl(center, 0.5f); /* auto-add interface for "solo" nodes */ if (totselect == 1) expose_all = TRUE; /* move nodes over */ for (node = ntree->nodes.first; node; node = nextn) { nextn = node->next; if (node_group_make_use_node(node, gnode)) { /* keep track of this node's RNA "base" path (the part of the pat identifying the node) * if the old nodetree has animation data which potentially covers this node */ if (ntree->adt) { PointerRNA ptr; char *path; RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr); path = RNA_path_from_ID_to_struct(&ptr); if (path) BLI_addtail(&anim_basepaths, BLI_genericNodeN(path)); } /* ensure valid parent pointers, detach if parent stays outside the group */ if (node->parent && !(node->parent->flag & NODE_SELECT)) nodeDetachNode(node); /* change node-collection membership */ BLI_remlink(&ntree->nodes, node); BLI_addtail(&ngroup->nodes, node); /* ensure unique node name in the ngroup */ nodeUniqueName(ngroup, node); } } /* move animation data over */ if (ntree->adt) { LinkData *ld, *ldn = NULL; BKE_animdata_separate_by_basepath(&ntree->id, &ngroup->id, &anim_basepaths); /* paths + their wrappers need to be freed */ for (ld = anim_basepaths.first; ld; ld = ldn) { ldn = ld->next; MEM_freeN(ld->data); BLI_freelinkN(&anim_basepaths, ld); } } /* node groups don't use internal cached data */ ntreeFreeCache(ngroup); /* create input node */ input_node = nodeAddStaticNode(C, ngroup, NODE_GROUP_INPUT); input_node->locx = min[0] - center[0] - offsetx; input_node->locy = -offsety; /* create output node */ output_node = nodeAddStaticNode(C, ngroup, NODE_GROUP_OUTPUT); output_node->locx = max[0] - center[0] + offsetx; output_node->locy = -offsety; /* relink external sockets */ for (link = ntree->links.first; link; link = linkn) { int fromselect = node_group_make_use_node(link->fromnode, gnode); int toselect = node_group_make_use_node(link->tonode, gnode); linkn = link->next; if ((fromselect && link->tonode == gnode) || (toselect && link->fromnode == gnode)) { /* remove all links to/from the gnode. * this can remove link information, but there's no general way to preserve it. */ nodeRemLink(ntree, link); } else if (fromselect && toselect) { BLI_remlink(&ntree->links, link); BLI_addtail(&ngroup->links, link); } else if (toselect) { bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, link->tonode, link->tosock); bNodeSocket *input_sock; /* update the group node and interface node sockets, * so the new interface socket can be linked. */ node_group_verify(ntree, gnode, (ID *)ngroup); node_group_input_verify(ngroup, input_node, (ID *)ngroup); /* create new internal link */ input_sock = node_group_input_find_socket(input_node, iosock->identifier); nodeAddLink(ngroup, input_node, input_sock, link->tonode, link->tosock); /* redirect external link */ link->tonode = gnode; link->tosock = node_group_find_input_socket(gnode, iosock->identifier); } else if (fromselect) { bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, link->fromnode, link->fromsock); bNodeSocket *output_sock; /* update the group node and interface node sockets, * so the new interface socket can be linked. */ node_group_verify(ntree, gnode, (ID *)ngroup); node_group_output_verify(ngroup, output_node, (ID *)ngroup); /* create new internal link */ output_sock = node_group_output_find_socket(output_node, iosock->identifier); nodeAddLink(ngroup, link->fromnode, link->fromsock, output_node, output_sock); /* redirect external link */ link->fromnode = gnode; link->fromsock = node_group_find_output_socket(gnode, iosock->identifier); } } /* move nodes in the group to the center */ for (node = ngroup->nodes.first; node; node = node->next) { if (node_group_make_use_node(node, gnode) && !node->parent) { node->locx -= center[0]; node->locy -= center[1]; } } /* expose all unlinked sockets too */ if (expose_all) { for (node = ngroup->nodes.first; node; node = node->next) { if (node_group_make_use_node(node, gnode)) { for (sock = node->inputs.first; sock; sock = sock->next) { bNodeSocket *iosock, *input_sock; int skip = FALSE; for (link = ngroup->links.first; link; link = link->next) { if (link->tosock == sock) { skip = TRUE; break; } } if (skip) continue; iosock = ntreeAddSocketInterfaceFromSocket(ngroup, node, sock); node_group_input_verify(ngroup, input_node, (ID *)ngroup); /* create new internal link */ input_sock = node_group_input_find_socket(input_node, iosock->identifier); nodeAddLink(ngroup, input_node, input_sock, node, sock); } for (sock = node->outputs.first; sock; sock = sock->next) { bNodeSocket *iosock, *output_sock; int skip = FALSE; for (link = ngroup->links.first; link; link = link->next) if (link->fromsock == sock) skip = TRUE; if (skip) continue; iosock = ntreeAddSocketInterfaceFromSocket(ngroup, node, sock); node_group_output_verify(ngroup, output_node, (ID *)ngroup); /* create new internal link */ output_sock = node_group_output_find_socket(output_node, iosock->identifier); nodeAddLink(ngroup, node, sock, output_node, output_sock); } } } } /* update of the group tree */ ngroup->update |= NTREE_UPDATE | NTREE_UPDATE_LINKS; /* update of the tree containing the group instance node */ ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; }
/* add new node connected to this socket, or replace an existing one */ static void node_socket_add_replace(const bContext *C, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to, int type, NodeLinkItem *item) { bNode *node_from; bNodeSocket *sock_from_tmp; bNode *node_prev = NULL; /* unlink existing node */ if (sock_to->link) { node_prev = sock_to->link->fromnode; nodeRemLink(ntree, sock_to->link); } /* find existing node that we can use */ for (node_from = ntree->nodes.first; node_from; node_from = node_from->next) if (node_from->type == type) break; if (node_from) if (node_from->inputs.first || node_from->typeinfo->draw_buttons || node_from->typeinfo->draw_buttons_ex) node_from = NULL; if (node_prev && node_prev->type == type && node_link_item_compare(node_prev, item)) { /* keep the previous node if it's the same type */ node_from = node_prev; } else if (!node_from) { node_from = nodeAddStaticNode(C, ntree, type); if (node_prev != NULL) { /* If we're replacing existing node, use it's location. */ node_from->locx = node_prev->locx; node_from->locy = node_prev->locy; node_from->offsetx = node_prev->offsetx; node_from->offsety = node_prev->offsety; } else { /* Avoid exact intersection of nodes. * TODO(sergey): Still not ideal, but better than nothing. */ int index = BLI_findindex(&node_to->inputs, sock_to); BLI_assert(index != -1); node_from->locx = node_to->locx - (node_from->typeinfo->width + 50); node_from->locy = node_to->locy - (node_from->typeinfo->height * index); } node_link_item_apply(node_from, item); } nodeSetActive(ntree, node_from); /* add link */ sock_from_tmp = BLI_findlink(&node_from->outputs, item->socket_index); nodeAddLink(ntree, node_from, sock_from_tmp, node_to, sock_to); sock_to->flag &= ~SOCK_COLLAPSED; /* copy input sockets from previous node */ if (node_prev && node_from != node_prev) { bNodeSocket *sock_prev, *sock_from; for (sock_prev = node_prev->inputs.first; sock_prev; sock_prev = sock_prev->next) { for (sock_from = node_from->inputs.first; sock_from; sock_from = sock_from->next) { if (nodeCountSocketLinks(ntree, sock_from) >= sock_from->limit) continue; if (STREQ(sock_prev->name, sock_from->name) && sock_prev->type == sock_from->type) { bNodeLink *link = sock_prev->link; if (link && link->fromnode) { nodeAddLink(ntree, link->fromnode, link->fromsock, node_from, sock_from); nodeRemLink(ntree, link); } node_socket_copy_default_value(sock_from, sock_prev); } } } /* also preserve mapping for texture nodes */ if (node_from->typeinfo->nclass == NODE_CLASS_TEXTURE && node_prev->typeinfo->nclass == NODE_CLASS_TEXTURE) { memcpy(node_from->storage, node_prev->storage, sizeof(NodeTexBase)); } /* remove node */ node_remove_linked(ntree, node_prev); } nodeUpdate(ntree, node_from); nodeUpdate(ntree, node_to); ntreeUpdateTree(CTX_data_main(C), ntree); ED_node_tag_update_nodetree(CTX_data_main(C), ntree); }
static void ntree_shader_link_builtin_group_normal( bNodeTree *ntree, bNode *group_node, bNode *node_from, bNodeSocket *socket_from, bNode *displacement_node, bNodeSocket *displacement_socket) { bNodeTree *group_ntree = (bNodeTree *)group_node->id; /* Create input socket to plug displacement connection to. */ bNodeSocket *group_normal_socket = ntreeAddSocketInterface(group_ntree, SOCK_IN, "NodeSocketVector", "Normal"); /* Need to update tree so all node instances nodes gets proper sockets. */ bNode *group_input_node = ntreeFindType(group_ntree, NODE_GROUP_INPUT); node_group_verify(ntree, group_node, &group_ntree->id); if (group_input_node) node_group_input_verify(group_ntree, group_input_node, &group_ntree->id); ntreeUpdateTree(G.main, group_ntree); /* Assumes sockets are always added at the end. */ bNodeSocket *group_node_normal_socket = group_node->inputs.last; if (displacement_node == group_node) { /* If displacement is coming from this node group we need to perform * some internal re-linking in order to avoid cycles. */ bNode *group_output_node = ntreeFindType(group_ntree, NODE_GROUP_OUTPUT); BLI_assert(group_output_node != NULL); bNodeSocket *group_output_node_displacement_socket = nodeFindSocket(group_output_node, SOCK_IN, displacement_socket->identifier); bNodeLink *group_displacement_link = group_output_node_displacement_socket->link; if (group_displacement_link == NULL) { /* Displacement output is not connected to anything, can just stop * right away. */ return; } /* This code is similar to ntree_shader_relink_displacement() */ bNode *group_displacement_node = group_displacement_link->fromnode; bNodeSocket *group_displacement_socket = group_displacement_link->fromsock; /* Create and link bump node. * Can't re-use bump node from parent tree because it'll cause cycle. */ bNode *bump_node = nodeAddStaticNode(NULL, group_ntree, SH_NODE_BUMP); bNodeSocket *bump_input_socket = ntree_shader_node_find_input(bump_node, "Height"); bNodeSocket *bump_output_socket = ntree_shader_node_find_output(bump_node, "Normal"); BLI_assert(bump_input_socket != NULL); BLI_assert(bump_output_socket != NULL); nodeAddLink(group_ntree, group_displacement_node, group_displacement_socket, bump_node, bump_input_socket); /* Relink normals inside of the instanced tree. */ ntree_shader_link_builtin_normal(group_ntree, bump_node, bump_output_socket, group_displacement_node, group_displacement_socket); ntreeUpdateTree(G.main, group_ntree); } else if (group_input_node) { /* Connect group node normal input. */ nodeAddLink(ntree, node_from, socket_from, group_node, group_node_normal_socket); BLI_assert(group_input_node != NULL); bNodeSocket *group_input_node_normal_socket = nodeFindSocket(group_input_node, SOCK_OUT, group_normal_socket->identifier); BLI_assert(group_input_node_normal_socket != NULL); /* Relink normals inside of the instanced tree. */ ntree_shader_link_builtin_normal(group_ntree, group_input_node, group_input_node_normal_socket, displacement_node, displacement_socket); ntreeUpdateTree(G.main, group_ntree); } }