Example #1
0
void node_group_expose_all_sockets(bNodeTree *ngroup)
{
	bNode *node;
	bNodeSocket *sock, *gsock;
	
	for (node=ngroup->nodes.first; node; node=node->next) {
		for (sock=node->inputs.first; sock; sock=sock->next) {
			if (!sock->link && !nodeSocketIsHidden(sock)) {
				gsock = node_group_add_socket(ngroup, sock->name, sock->type, SOCK_IN);
				
				/* initialize the default value. */
				node_socket_copy_default_value(gsock->type, gsock->default_value, sock->default_value);
				
				sock->link = nodeAddLink(ngroup, NULL, gsock, node, sock);
			}
		}
		for (sock=node->outputs.first; sock; sock=sock->next) {
			if (nodeCountSocketLinks(ngroup, sock)==0 && !nodeSocketIsHidden(sock)) {
				gsock = node_group_add_socket(ngroup, sock->name, sock->type, SOCK_OUT);
				
				/* initialize the default value. */
				node_socket_copy_default_value(gsock->type, gsock->default_value, sock->default_value);
				
				gsock->link = nodeAddLink(ngroup, node, sock, NULL, gsock);
			}
		}
	}
}
Example #2
0
/* Use specified node and socket as an input for unconnected normal sockets. */
static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
                                             bNode *node_from,
                                             bNodeSocket *socket_from)
{
	for (bNode *node = ntree->nodes.first; node != NULL; node = node->next) {
		if (node == node_from) {
			/* Don't connect node itself! */
			continue;
		}
		bNodeSocket *sock = ntree_shader_node_find_input(node, "Normal");
		/* TODO(sergey): Can we do something smarter here than just a name-based
		 * matching?
		 */
		if (sock == NULL) {
			/* There's no Normal input, nothing to link. */
			continue;
		}
		if (sock->link != NULL) {
			/* Something is linked to the normal input already. can't
			 * use other input for that.
			 */
			continue;
		}
		/* Create connection between specified node and the normal input. */
		nodeAddLink(ntree, node_from, socket_from, node, sock);
	}
}
Example #3
0
static 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;
	
	/* 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);
		}
	}
	
	/* 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_verify(ntree, node, (ID *)ntree);
		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);
}
Example #4
0
/* /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// */
static int connect_nodes(Main *bmain, bNodeTree *ntree, bNode *node_fr, bNodeSocket *sock_fr, bNode *node_to, bNodeSocket *sock_to)
{
    bNodeLink *link = nodeAddLink(ntree, node_fr, sock_fr, node_to, sock_to);
    ntreeUpdateTree(bmain, ntree);
    if (!(link->flag & NODE_LINK_VALID)) {
        nodeRemLink(ntree, link);
        return 0;
    }
    return 1;
} /* connect_nodes() */
Example #5
0
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);
}
Example #6
0
/* 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);
}
Example #7
0
static bool ntree_shader_relink_node_normal(bNodeTree *ntree,
        bNode *node,
        bNode *node_from,
        bNodeSocket *socket_from)
{
    bNodeSocket *sock = ntree_shader_node_find_input(node, "Normal");
    /* TODO(sergey): Can we do something smarter here than just a name-based
     * matching?
     */
    if (sock == NULL) {
        /* There's no Normal input, nothing to link. */
        return false;
    }
    if (sock->link != NULL) {
        /* Something is linked to the normal input already. can't
         * use other input for that.
         */
        return false;
    }
    /* Create connection between specified node and the normal input. */
    nodeAddLink(ntree, node_from, socket_from, node, sock);
    return true;
}
Example #8
0
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;
}
Example #9
0
/* returns 1 if its OK */
static int node_group_separate_selected(bNodeTree *ntree, bNodeTree *ngroup, float offx, float offy, int make_copy)
{
	bNodeLink *link, *link_next;
	bNode *node, *node_next, *newnode;
	ListBase anim_basepaths = {NULL, NULL};
	
	/* deselect all nodes in the target tree */
	for (node = ntree->nodes.first; node; node = node->next)
		nodeSetSelected(node, FALSE);
	
	/* clear new pointers, set in nodeCopyNode */
	for (node = ngroup->nodes.first; node; node = node->next)
		node->new_node = NULL;
	
	/* add selected nodes into the ntree */
	for (node = ngroup->nodes.first; node; node = node_next) {
		node_next = node->next;
		if (!(node->flag & NODE_SELECT))
			continue;
		
		/* ignore interface nodes */
		if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
			nodeSetSelected(node, FALSE);
			continue;
		}
		
		if (make_copy) {
			/* make a copy */
			newnode = nodeCopyNode(ngroup, node);
		}
		else {
			/* use the existing node */
			newnode = node;
		}
		
		/* keep track of this node's RNA "base" path (the part of the path identifying the node) 
		 * if the old nodetree has animation data which potentially covers this node
		 */
		if (ngroup->adt) {
			PointerRNA ptr;
			char *path;
			
			RNA_pointer_create(&ngroup->id, &RNA_Node, newnode, &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 inside the group */
		if (newnode->parent && !(newnode->parent->flag & NODE_SELECT))
			nodeDetachNode(newnode);
		
		/* migrate node */
		BLI_remlink(&ngroup->nodes, newnode);
		BLI_addtail(&ntree->nodes, newnode);
		
		/* ensure unique node name in the node tree */
		nodeUniqueName(ntree, newnode);

		if (!newnode->parent) {
			newnode->locx += offx;
			newnode->locy += offy;		
		}
	}
	
	/* add internal links to the ntree */
	for (link = ngroup->links.first; link; link = link_next) {
		int fromselect = (link->fromnode && (link->fromnode->flag & NODE_SELECT));
		int toselect = (link->tonode && (link->tonode->flag & NODE_SELECT));
		link_next = link->next;
		
		if (make_copy) {
			/* make a copy of internal links */
			if (fromselect && toselect)
				nodeAddLink(ntree, link->fromnode->new_node, link->fromsock->new_sock, link->tonode->new_node, link->tosock->new_sock);
		}
		else {
			/* move valid links over, delete broken links */
			if (fromselect && toselect) {
				BLI_remlink(&ngroup->links, link);
				BLI_addtail(&ntree->links, link);
			}
			else if (fromselect || toselect) {
				nodeRemLink(ngroup, link);
			}
		}
	}
	
	/* and copy across the animation,
	 * note that the animation data's action can be NULL here */
	if (ngroup->adt) {
		LinkData *ld, *ldn = NULL;
		
		/* now perform the moving */
		BKE_animdata_separate_by_basepath(&ngroup->id, &ntree->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);
		}
	}
	
	ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
	if (!make_copy)
		ngroup->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
	
	return 1;
}
Example #10
0
/* returns 1 if its OK */
static int node_group_ungroup(bNodeTree *ntree, bNode *gnode)
{
	bNodeLink *link, *linkn, *tlink;
	bNode *node, *nextnode;
	bNodeTree *ngroup, *wgroup;
	ListBase anim_basepaths = {NULL, NULL};
	
	ngroup = (bNodeTree *)gnode->id;
	
	/* clear new pointers, set in copytree */
	for (node = ntree->nodes.first; node; node = node->next)
		node->new_node = NULL;
	
	/* wgroup is a temporary copy of the NodeTree we're merging in
	 * - all of wgroup's nodes are transferred across to their new home
	 * - ngroup (i.e. the source NodeTree) is left unscathed
	 * - temp copy. don't change ID usercount
	 */
	wgroup = ntreeCopyTree_ex(ngroup, FALSE);
	
	/* Add the nodes into the ntree */
	for (node = wgroup->nodes.first; node; node = nextnode) {
		nextnode = node->next;
		
		/* Remove interface nodes.
		 * This also removes remaining links to and from interface nodes.
		 */
		if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
			nodeFreeNode(wgroup, node);
			continue;
		}
		
		/* keep track of this node's RNA "base" path (the part of the path identifying the node) 
		 * if the old nodetree has animation data which potentially covers this node
		 */
		if (wgroup->adt) {
			PointerRNA ptr;
			char *path;
			
			RNA_pointer_create(&wgroup->id, &RNA_Node, node, &ptr);
			path = RNA_path_from_ID_to_struct(&ptr);
			
			if (path)
				BLI_addtail(&anim_basepaths, BLI_genericNodeN(path));
		}
		
		/* migrate node */
		BLI_remlink(&wgroup->nodes, node);
		BLI_addtail(&ntree->nodes, node);
		
		/* ensure unique node name in the node tree */
		nodeUniqueName(ntree, node);
		
		if (!node->parent) {
			node->locx += gnode->locx;
			node->locy += gnode->locy;
		}
		
		node->flag |= NODE_SELECT;
	}
	
	/* Add internal links to the ntree */
	for (link = wgroup->links.first; link; link = linkn) {
		linkn = link->next;
		BLI_remlink(&wgroup->links, link);
		BLI_addtail(&ntree->links, link);
	}
	
	/* and copy across the animation,
	 * note that the animation data's action can be NULL here */
	if (wgroup->adt) {
		LinkData *ld, *ldn = NULL;
		bAction *waction;
		
		/* firstly, wgroup needs to temporary dummy action that can be destroyed, as it shares copies */
		waction = wgroup->adt->action = BKE_action_copy(wgroup->adt->action);
		
		/* now perform the moving */
		BKE_animdata_separate_by_basepath(&wgroup->id, &ntree->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);
		}
		
		/* free temp action too */
		if (waction) {
			BKE_libblock_free(&G.main->action, waction);
		}
	}
	
	/* free the group tree (takes care of user count) */
	BKE_libblock_free(&G.main->nodetree, wgroup);
	
	/* restore external links to and from the gnode */
	/* note: the nodes have been copied to intermediate wgroup first (so need to use new_node),
	 *       then transferred to ntree (new_node pointers remain valid).
	 */
	
	/* input links */
	for (link = ngroup->links.first; link; link = link->next) {
		if (link->fromnode->type == NODE_GROUP_INPUT) {
			const char *identifier = link->fromsock->identifier;
			int num_external_links = 0;
			
			/* find external links to this input */
			for (tlink = ntree->links.first; tlink; tlink = tlink->next) {
				if (tlink->tonode == gnode && STREQ(tlink->tosock->identifier, identifier)) {
					nodeAddLink(ntree, tlink->fromnode, tlink->fromsock, link->tonode->new_node, link->tosock->new_sock);
					++num_external_links;
				}
			}
			
			/* if group output is not externally linked,
			 * convert the constant input value to ensure somewhat consistent behavior */
			if (num_external_links == 0) {
				/* XXX TODO bNodeSocket *sock = node_group_find_input_socket(gnode, identifier);
				BLI_assert(sock);*/
				
				/* XXX TODO nodeSocketCopy(ntree, link->tosock->new_sock, link->tonode->new_node, ntree, sock, gnode);*/
			}
		}
	}
	
	/* output links */
	for (link = ntree->links.first; link; link = link->next) {
		if (link->fromnode == gnode) {
			const char *identifier = link->fromsock->identifier;
			int num_internal_links = 0;
			
			/* find internal links to this output */
			for (tlink = ngroup->links.first; tlink; tlink = tlink->next) {
				/* only use active output node */
				if (tlink->tonode->type == NODE_GROUP_OUTPUT && (tlink->tonode->flag & NODE_DO_OUTPUT)) {
					if (STREQ(tlink->tosock->identifier, identifier)) {
						nodeAddLink(ntree, tlink->fromnode->new_node, tlink->fromsock->new_sock, link->tonode, link->tosock);
						++num_internal_links;
					}
				}
			}
			
			/* if group output is not internally linked,
			 * convert the constant output value to ensure somewhat consistent behavior */
			if (num_internal_links == 0) {
				/* XXX TODO bNodeSocket *sock = node_group_find_output_socket(gnode, identifier);
				BLI_assert(sock);*/
				
				/* XXX TODO nodeSocketCopy(ntree, link->tosock, link->tonode, ntree, sock, gnode); */
			}
		}
	}
	
	/* delete the group instance */
	nodeFreeNode(ntree, gnode);
	
	ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
	
	return 1;
}
/* 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);
}
Example #12
0
bNode *node_group_make_from_selected(bNodeTree *ntree)
{
    bNodeLink *link, *linkn;
    bNode *node, *gnode, *nextn;
    bNodeTree *ngroup;
    bNodeSocket *gsock;
    ListBase anim_basepaths = {NULL, NULL};
    float min[2], max[2];
    int totnode=0;
    bNodeTemplate ntemp;

    INIT_MINMAX2(min, max);

    /* is there something to group? also do some clearing */
    for(node= ntree->nodes.first; node; node= node->next) {
        if(node->flag & NODE_SELECT) {
            /* no groups in groups */
            if(node->type==NODE_GROUP)
                return NULL;
            DO_MINMAX2( (&node->locx), min, max);
            totnode++;
        }
        node->done= 0;
    }
    if(totnode==0) return NULL;

    /* check if all connections are OK, no unselected node has both
    	inputs and outputs to a selection */
    for(link= ntree->links.first; link; link= link->next) {
        if(link->fromnode && link->tonode && link->fromnode->flag & NODE_SELECT)
            link->tonode->done |= 1;
        if(link->fromnode && link->tonode && link->tonode->flag & NODE_SELECT)
            link->fromnode->done |= 2;
    }

    for(node= ntree->nodes.first; node; node= node->next) {
        if((node->flag & NODE_SELECT)==0)
            if(node->done==3)
                break;
    }
    if(node)
        return NULL;

    /* OK! new nodetree */
    ngroup= ntreeAddTree("NodeGroup", ntree->type, NODE_GROUP);

    /* move nodes over */
    for(node= ntree->nodes.first; node; node= nextn) {
        nextn= node->next;
        if(node->flag & NODE_SELECT) {
            /* 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));
            }

            /* change node-collection membership */
            BLI_remlink(&ntree->nodes, node);
            BLI_addtail(&ngroup->nodes, node);

            node->locx-= 0.5f*(min[0]+max[0]);
            node->locy-= 0.5f*(min[1]+max[1]);
        }
    }

    /* 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);
        }
    }

    /* make group node */
    ntemp.type = NODE_GROUP;
    ntemp.ngroup = ngroup;
    gnode= nodeAddNode(ntree, &ntemp);
    gnode->locx= 0.5f*(min[0]+max[0]);
    gnode->locy= 0.5f*(min[1]+max[1]);

    /* relink external sockets */
    for(link= ntree->links.first; link; link= linkn) {
        linkn= link->next;

        if(link->fromnode && link->tonode && (link->fromnode->flag & link->tonode->flag & NODE_SELECT)) {
            BLI_remlink(&ntree->links, link);
            BLI_addtail(&ngroup->links, link);
        }
        else if(link->tonode && (link->tonode->flag & NODE_SELECT)) {
            gsock = node_group_expose_socket(ngroup, link->tosock, SOCK_IN);
            link->tosock->link = nodeAddLink(ngroup, NULL, gsock, link->tonode, link->tosock);
            link->tosock = node_group_add_extern_socket(ntree, &gnode->inputs, SOCK_IN, gsock);
            link->tonode = gnode;
        }
        else if(link->fromnode && (link->fromnode->flag & NODE_SELECT)) {
            /* search for existing group node socket */
            for (gsock=ngroup->outputs.first; gsock; gsock=gsock->next)
                if (gsock->link && gsock->link->fromsock==link->fromsock)
                    break;
            if (!gsock) {
                gsock = node_group_expose_socket(ngroup, link->fromsock, SOCK_OUT);
                gsock->link = nodeAddLink(ngroup, link->fromnode, link->fromsock, NULL, gsock);
                link->fromsock = node_group_add_extern_socket(ntree, &gnode->outputs, SOCK_OUT, gsock);
            }
            else
                link->fromsock = node_group_find_output(gnode, gsock);
            link->fromnode = gnode;
        }
    }

    ngroup->update |= NTREE_UPDATE;
    ntreeUpdateTree(ngroup);
    ntree->update |= NTREE_UPDATE_NODES|NTREE_UPDATE_LINKS;
    ntreeUpdateTree(ntree);

    return gnode;
}
Example #13
0
/* add new node connected to this socket, or replace an existing one */
static void node_socket_add_replace(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to, bNodeTemplate *ntemp, int sock_num)
{
	bNode *node_from;
	bNodeSocket *sock_from;
	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 == ntemp->type)
			break;

	if (node_from)
		if (!(node_from->inputs.first == NULL && !(node_from->typeinfo->flag & NODE_OPTIONS)))
			node_from = NULL;

	if (node_prev && node_prev->type == ntemp->type &&
		(ntemp->type != NODE_GROUP || node_prev->id == &ntemp->ngroup->id)) {
		/* keep the previous node if it's the same type */
		node_from = node_prev;
	}
	else if (!node_from) {
		node_from= nodeAddNode(ntree, ntemp);
		node_from->locx = node_to->locx - (node_from->typeinfo->width + 50);
		node_from->locy = node_to->locy;

		if (node_from->id)
			id_us_plus(node_from->id);
	}

	nodeSetActive(ntree, node_from);

	/* add link */
	sock_from = BLI_findlink(&node_from->outputs, sock_num);
	nodeAddLink(ntree, node_from, sock_from, node_to, sock_to);

	/* 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 (strcmp(sock_prev->name, sock_from->name) == 0 && 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_free_default_value(sock_from->type, sock_from->default_value);
					sock_from->default_value = node_socket_make_default_value(sock_from->type);
					node_socket_copy_default_value(sock_from->type, sock_from->default_value, sock_prev->default_value);
				}
			}
		}

		/* 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(ntree);

	ED_node_generic_update(bmain, ntree, node_to);
}
Example #14
0
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);
    }
}