Ejemplo n.º 1
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);
}
Ejemplo n.º 2
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;
}