Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Ebb <matt@mke3.net>2010-01-05 09:49:29 +0300
committerMatt Ebb <matt@mke3.net>2010-01-05 09:49:29 +0300
commitd16ea70f51236d5272d9c93e25277974f1a7766b (patch)
treef1a1eb32359cceda6cdd81f883476a39e94a1845 /source/blender
parent6e6560d9248e7bfad45409d6eb86640d7017d9f3 (diff)
* 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
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/editors/space_node/node_edit.c227
-rw-r--r--source/blender/editors/space_node/node_header.c13
-rw-r--r--source/blender/editors/space_node/node_intern.h2
3 files changed, 134 insertions, 108 deletions
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index f2b3ed29067..05926782a0d 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -1353,95 +1353,155 @@ static int node_socket_hilights(SpaceNode *snode, int in_out)
/* ****************** 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 @@ void NODE_OT_link(wmOperatorType *ot)
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);
diff --git a/source/blender/editors/space_node/node_header.c b/source/blender/editors/space_node/node_header.c
index 6426856dfdd..d8a14c6412b 100644
--- a/source/blender/editors/space_node/node_header.c
+++ b/source/blender/editors/space_node/node_header.c
@@ -78,8 +78,17 @@ static void do_node_add(bContext *C, void *arg, int event)
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);
}
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index ff88b4fde77..1ff2f7d7128 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -81,7 +81,7 @@ void node_deselectall(SpaceNode *snode);
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);