Thank you Matt!, I've been missing this one, we had it (simpler) back in Plumiferos and I almost forgotten how useful it was, but is so much better now, I love how it connects automatically per socket type.
Is there any plan to add the Ctrl + LMB/RMB to automatically connect the active Viewer back? or any other implementation of it? without it compositing workflow is so slow =/ Cheers! * Pablo Vazquez CG Artist [email protected] http://www.venomgfx.com.ar On Tue, Jan 5, 2010 at 07:49, Matt Ebb <[email protected]> wrote: > 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); > > > _______________________________________________ > Bf-blender-cvs mailing list > [email protected] > http://lists.blender.org/mailman/listinfo/bf-blender-cvs > _______________________________________________ Bf-committers mailing list [email protected] http://lists.blender.org/mailman/listinfo/bf-committers
