[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [25732] trunk/blender/source/blender/ editors/space_node: * Modifications to node editor 'make links' tool, after some requests by Soenke

Matt Ebb matt at mke3.net
Tue Jan 5 07:49:30 CET 2010


Revision: 25732
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=25732
Author:   broken
Date:     2010-01-05 07:49:29 +0100 (Tue, 05 Jan 2010)

Log Message:
-----------
* Modifications to node editor 'make links' tool, after some requests by Soenke

Now it automatically decides how to connect the nodes up, based on the node positions. This lets you do fun stuff like in this video: http://www.vimeo.com/8548698

Modified Paths:
--------------
    trunk/blender/source/blender/editors/space_node/node_edit.c
    trunk/blender/source/blender/editors/space_node/node_header.c
    trunk/blender/source/blender/editors/space_node/node_intern.h

Modified: trunk/blender/source/blender/editors/space_node/node_edit.c
===================================================================
--- trunk/blender/source/blender/editors/space_node/node_edit.c	2010-01-05 03:31:57 UTC (rev 25731)
+++ trunk/blender/source/blender/editors/space_node/node_edit.c	2010-01-05 06:49:29 UTC (rev 25732)
@@ -1353,95 +1353,155 @@
 
 /* ****************** Add *********************** */
 
-static bNodeSocket *get_next_outputsocket(bNodeSocket *sock, bNodeSocket **sockfrom, int totsock)
+
+typedef struct bNodeListItem {
+	struct bNodeListItem *next, *prev;
+	struct bNode *node;	
+} bNodeListItem;
+
+int sort_nodes_locx(void *a, void *b)
 {
-	int a;
+	bNodeListItem *nli1 = (bNodeListItem *)a;
+	bNodeListItem *nli2 = (bNodeListItem *)b;
+	bNode *node1 = nli1->node;
+	bNode *node2 = nli2->node;
 	
-	/* first try to find a sockets with matching name */
-	for (a=0; a<totsock; a++) {
-		if(sockfrom[a]) {
-			if(sock->type==sockfrom[a]->type) {
-				if (strcmp(sockfrom[a]->name, sock->name)==0)
-					return sockfrom[a];
-			}
+	if (node1->locx > node2->locx)
+		return 1;
+	else 
+		return 0;
+}
+
+static int socket_is_available(bNodeTree *ntree, bNodeSocket *sock, int allow_used)
+{
+	if (sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))
+		return 0;
+	
+	if (!allow_used) {
+		if (nodeCountSocketLinks(ntree, sock) > 0)
+			return 0;
+	}
+	return 1;
+}
+
+static bNodeSocket *best_socket_output(bNodeTree *ntree, bNode *node, bNodeSocket *sock_target, int allow_multiple)
+{
+	bNodeSocket *sock;
+	
+	/* first try to find a socket with a matching name */
+	for (sock=node->outputs.first; sock; sock=sock->next) {
+
+		if (!socket_is_available(ntree, sock, allow_multiple))
+			continue;
+
+		/* check for same types */
+		if (sock->type == sock_target->type) {
+			if (strcmp(sock->name, sock_target->name)==0)
+				return sock;
 		}
 	}
 	
 	/* otherwise settle for the first available socket of the right type */
-	for (a=0; a<totsock; a++) {
-		if(sockfrom[a]) {
-			if(sock->type==sockfrom[a]->type) {
-				return sockfrom[a];
-			}
+	for (sock=node->outputs.first; sock; sock=sock->next) {
+
+		if (!socket_is_available(ntree, sock, allow_multiple))
+			continue;
+		
+		/* check for same types */
+		if (sock->type == sock_target->type) {
+			return sock;
 		}
 	}
 	
 	return NULL;
 }
 
-void snode_autoconnect(SpaceNode *snode, bNode *node_to, int flag, int replace)
+/* this is a bit complicated, but designed to prioritise finding 
+ * sockets of higher types, such as image, first */
+static bNodeSocket *best_socket_input(bNodeTree *ntree, bNode *node, int num, int replace)
 {
-	bNodeSocket *sock, *sockfrom[8];
-	bNode *node, *nodefrom[8];
-	int totsock= 0, socktype=0;
-
-	if(node_to==NULL || node_to->inputs.first==NULL)
-		return;
-
-	/* connect first 1 socket type or first available socket now */
-	for(sock= node_to->inputs.first; sock; sock= sock->next) {
-		if (!replace && nodeCountSocketLinks(snode->edittree, sock))
-			continue;
-		if(socktype<sock->type)
-			socktype= sock->type;
+	bNodeSocket *sock;
+	int socktype, maxtype=0;
+	int a;
+	
+	for (sock=node->inputs.first; sock; sock=sock->next) {
+		maxtype = MAX2(sock->type, maxtype);
 	}
 	
-	/* find potential sockets, max 8 should work */
-	for(node= snode->edittree->nodes.first; node; node= node->next) {
-		if((node->flag & flag) && node!=node_to) {
-			for(sock= node->outputs.first; sock; sock= sock->next) {
-				if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
-					sockfrom[totsock]= sock;
-					nodefrom[totsock]= node;
-					totsock++;
-					if(totsock>7)
-						break;
-				}
+	/* find sockets of higher 'types' first (i.e. image) */
+	for (socktype=maxtype; socktype >= 0; socktype--) {
+		for (sock=node->inputs.first; sock; sock=sock->next) {
+			
+			if (!socket_is_available(ntree, sock, replace)) {
+				a++;
+				continue;
 			}
+				
+			if (sock->type == socktype) {
+				/* increment to make sure we don't keep finding 
+				 * the same socket on every attempt running this function */
+				a++;
+				if (a > num)
+					return sock;
+			}
 		}
-		if(totsock>7)
-			break;
 	}
+	
+	return NULL;
+}
 
-	/* now just get matching socket types and create links */
-	for(sock= node_to->inputs.first; sock; sock= sock->next) {
-		bNodeSocket *sock_from;
-		bNode *node_from;
+void snode_autoconnect(SpaceNode *snode, int allow_multiple, int replace)
+{
+	ListBase *nodelist = MEM_callocN(sizeof(ListBase), "items_list");
+	bNodeListItem *nli;
+	bNode *node;
+	int i;
+	
+	for(node= snode->edittree->nodes.first; node; node= node->next) {
+		if(node->flag & NODE_SELECT) {
+			nli = MEM_mallocN(sizeof(bNodeListItem), "temporary node list item");
+			nli->node = node;
+			BLI_addtail(nodelist, nli);
+		}
+	}
+	
+	/* sort nodes left to right */
+	BLI_sortlist(nodelist, sort_nodes_locx);
+	
+	for (nli=nodelist->first; nli; nli=nli->next) {
+		bNode *node_fr, *node_to;
+		bNodeSocket *sock_fr, *sock_to;
 		
-		if (sock->type != socktype)
-			continue;
+		if (nli->next == NULL) break;
 		
-		/* find a potential output socket and associated node */
-		sock_from = get_next_outputsocket(sock, sockfrom, totsock);
-		if (!sock_from)
-			continue;
-		nodeFindNode(snode->edittree, sock_from, &node_from, NULL);
+		node_fr = nli->node;
+		node_to = nli->next->node;
 		
-		/* then connect up the links */
-		if (replace) {
-			nodeRemSocketLinks(snode->edittree, sock);
-			nodeAddLink(snode->edittree, node_from, sock_from, node_to, sock);
-		} else {
-			if (nodeCountSocketLinks(snode->edittree, sock)==0)
-				nodeAddLink(snode->edittree, node_from, sock_from, node_to, sock);
+		/* check over input sockets first */
+		for (i=0; i<BLI_countlist(&node_to->inputs); i++) {
+			
+			/* find the best guess input socket */
+			sock_to = best_socket_input(snode->edittree, node_to, i, replace);
+			if (!sock_to) continue;
+			
+			/* check for an appropriate output socket to connect from */
+			sock_fr = best_socket_output(snode->edittree, node_fr, sock_to, allow_multiple);
+			if (!sock_fr) continue;
+			
+			/* then we can connect */
+			if (replace)
+				nodeRemSocketLinks(snode->edittree, sock_to);
+			nodeAddLink(snode->edittree, node_fr, sock_fr, node_to, sock_to);
+			break;
 		}
-		sock_from = NULL;
 	}
 	
 	ntreeSolveOrder(snode->edittree);
+	
+	BLI_freelistN(nodelist);
+	MEM_freeN(nodelist);
 }
 
-
 /* can be called from menus too, but they should do own undopush and redraws */
 bNode *node_add_node(SpaceNode *snode, Scene *scene, int type, float locx, float locy)
 {
@@ -1781,53 +1841,10 @@
 static int node_make_link_exec(bContext *C, wmOperator *op)
 {
 	SpaceNode *snode= CTX_wm_space_node(C);
-	bNode *fromnode, *tonode;
-	bNodeLink *link;
-	bNodeSocket *outsock= snode->edittree->selout;
-	bNodeSocket *insock= snode->edittree->selin;
 	int replace = RNA_boolean_get(op->ptr, "replace");
-	
-	if (!insock || !outsock) {
-		bNode *node;
-		
-		/* no socket selection, join nodes themselves, guessing connections */
-		tonode = nodeGetActive(snode->edittree);
-		
-		if (!tonode) {
-			BKE_report(op->reports, RPT_ERROR, "No active node");
-			return OPERATOR_CANCELLED;	
-		}
-		
-		/* store selection in temp test flag */
-		for(node= snode->edittree->nodes.first; node; node= node->next) {
-			if(node->flag & NODE_SELECT) node->flag |= NODE_TEST;
-			else node->flag &= ~NODE_TEST;
-		}
-		
-		snode_autoconnect(snode, tonode, NODE_TEST, replace);
-		node_tree_verify_groups(snode->nodetree);
-		snode_handle_recalc(C, snode);
-		
-		return OPERATOR_FINISHED;
-	}
-	
-	
-	if (nodeFindLink(snode->edittree, outsock, insock)) {
-		BKE_report(op->reports, RPT_ERROR, "There is already a link between these sockets");
-		return OPERATOR_CANCELLED;
-	}
 
-	if (nodeFindNode(snode->edittree, outsock, &fromnode, NULL) &&
-		nodeFindNode(snode->edittree, insock, &tonode, NULL)) 
-	{
-		link= nodeAddLink(snode->edittree, fromnode, outsock, tonode, insock);
-		NodeTagChanged(snode->edittree, tonode);
-		node_remove_extra_links(snode, insock, link);
-	}
-	else 
-		return OPERATOR_CANCELLED;
+	snode_autoconnect(snode, 0, replace);
 
-	ntreeSolveOrder(snode->edittree);
 	node_tree_verify_groups(snode->nodetree);
 	snode_handle_recalc(C, snode);
 	

Modified: trunk/blender/source/blender/editors/space_node/node_header.c
===================================================================
--- trunk/blender/source/blender/editors/space_node/node_header.c	2010-01-05 03:31:57 UTC (rev 25731)
+++ trunk/blender/source/blender/editors/space_node/node_header.c	2010-01-05 06:49:29 UTC (rev 25732)
@@ -78,8 +78,17 @@
 	
 	node= node_add_node(snode, CTX_data_scene(C), event, snode->mx, snode->my);
 	
-	/* uses test flag */
-	snode_autoconnect(snode, node, NODE_TEST, 0);
+	/* select previous selection before autoconnect */
+	for(node= snode->edittree->nodes.first; node; node= node->next) {
+		if(node->flag & NODE_TEST) node->flag |= NODE_SELECT;
+	}
+	
+	snode_autoconnect(snode, 1, 0);
+	
+	/* deselect after autoconnection */
+	for(node= snode->edittree->nodes.first; node; node= node->next) {
+		if(node->flag & NODE_TEST) node->flag &= ~NODE_SELECT;
+	}
 		
 	snode_handle_recalc(C, snode);
 }

Modified: trunk/blender/source/blender/editors/space_node/node_intern.h
===================================================================
--- trunk/blender/source/blender/editors/space_node/node_intern.h	2010-01-05 03:31:57 UTC (rev 25731)
+++ trunk/blender/source/blender/editors/space_node/node_intern.h	2010-01-05 06:49:29 UTC (rev 25732)
@@ -81,7 +81,7 @@
 void snode_composite_job(const struct bContext *C, ScrArea *sa);
 bNode *node_tree_get_editgroup(bNodeTree *ntree);
 void node_tree_verify_groups(bNodeTree *nodetree);
-void snode_autoconnect(SpaceNode *snode, bNode *node_to, int flag, int replace);
+void snode_autoconnect(SpaceNode *snode, int allow_multiple, int replace);
 int node_has_hidden_sockets(bNode *node);
 
 void NODE_OT_duplicate(struct wmOperatorType *ot);





More information about the Bf-blender-cvs mailing list