diff options
Diffstat (limited to 'source/blender/blenkernel/intern/node.c')
-rw-r--r-- | source/blender/blenkernel/intern/node.c | 668 |
1 files changed, 627 insertions, 41 deletions
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index b267ebb2a11..ab4d755c868 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -32,8 +32,12 @@ #include "DNA_ID.h" #include "DNA_node_types.h" +#include "DNA_material_types.h" #include "BKE_blender.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_main.h" #include "BKE_node.h" #include "BKE_texture.h" #include "BKE_utildefines.h" @@ -43,16 +47,27 @@ #include "MEM_guardedalloc.h" -/* ************** Type stuff ********** */ +/* not very important, but the stack solver likes to know a maximum */ +#define MAX_SOCKET 64 -static bNodeType *nodeGetType(bNodeTree *ntree, int type) +#pragma mark /* ************** Type stuff ********** */ + +static bNodeType *node_get_type(bNodeTree *ntree, int type, bNodeTree *ngroup) { - bNodeType **typedefs= ntree->alltypes; - - while( *typedefs && (*typedefs)->type!=type) - typedefs++; - - return *typedefs; + if(type==NODE_GROUP) { + if(ngroup && GS(ngroup->id.name)==ID_NT) { + return ngroup->owntype; + } + return NULL; + } + else { + bNodeType **typedefs= ntree->alltypes; + + while( *typedefs && (*typedefs)->type!=type) + typedefs++; + + return *typedefs; + } } void ntreeInitTypes(bNodeTree *ntree) @@ -68,7 +83,7 @@ void ntreeInitTypes(bNodeTree *ntree) for(node= ntree->nodes.first; node; node= next) { next= node->next; - node->typeinfo= nodeGetType(ntree, node->type); + node->typeinfo= node_get_type(ntree, node->type, (bNodeTree *)node->id); if(node->typeinfo==NULL) { printf("Error: Node type %s doesn't exist anymore, removed\n", node->name); nodeFreeNode(ntree, node); @@ -88,6 +103,9 @@ static bNodeSocket *node_add_socket_type(ListBase *lb, bNodeSocketType *stype) else sock->limit= stype->limit; sock->type= stype->type; + sock->to_index= stype->own_index; + sock->tosock= stype->internsock; + sock->ns.vec[0]= stype->val1; sock->ns.vec[1]= stype->val2; sock->ns.vec[2]= stype->val3; @@ -119,14 +137,19 @@ static bNodeSocket *verify_socket(ListBase *lb, bNodeSocketType *stype) bNodeSocket *sock; for(sock= lb->first; sock; sock= sock->next) { - if(strncmp(sock->name, stype->name, NODE_MAXSTR)==0) - break; + /* both indices are zero for non-groups, otherwise it's a unique index */ + if(sock->to_index==stype->own_index) + if(strncmp(sock->name, stype->name, NODE_MAXSTR)==0) + break; } if(sock) { sock->type= stype->type; /* in future, read this from tydefs! */ if(stype->limit==0) sock->limit= 0xFFF; else sock->limit= stype->limit; + sock->tosock= stype->internsock; + BLI_remlink(lb, sock); + return sock; } else { @@ -162,37 +185,482 @@ static void verify_socket_list(bNodeTree *ntree, ListBase *lb, bNodeSocketType * } } +void nodeVerifyType(bNodeTree *ntree, bNode *node) +{ + bNodeType *ntype= node->typeinfo; + + if(ntype) { + /* might add some other verify stuff here */ + + verify_socket_list(ntree, &node->inputs, ntype->inputs); + verify_socket_list(ntree, &node->outputs, ntype->outputs); + } +} + void ntreeVerifyTypes(bNodeTree *ntree) { bNode *node; - bNodeType *ntype; if((ntree->init & NTREE_TYPE_INIT)==0) ntreeInitTypes(ntree); /* check inputs and outputs, and remove or insert them */ + for(node= ntree->nodes.first; node; node= node->next) + nodeVerifyType(ntree, node); + +} + +#pragma mark /* ************** Group stuff ********** */ + +/* prototype */ +static void node_group_exec_func(void *data, bNode *node, bNodeStack **in, bNodeStack **out); + +bNodeType node_group_typeinfo= { + /* type code */ NODE_GROUP, + /* name */ "Group", + /* width+range */ 120, 60, 200, + /* class+opts */ NODE_CLASS_GROUP, NODE_OPTIONS, + /* input sock */ NULL, + /* output sock */ NULL, + /* storage */ "", + /* execfunc */ node_group_exec_func, + +}; + +/* tag internal sockets */ +static void group_tag_internal_sockets(bNodeTree *ngroup) +{ + bNode *node; + bNodeSocket *sock; + bNodeLink *link; + + /* clear intern tag, but check already for hidden sockets */ + for(node= ngroup->nodes.first; node; node= node->next) { + for(sock= node->inputs.first; sock; sock= sock->next) + sock->intern= sock->flag & SOCK_HIDDEN; + for(sock= node->outputs.first; sock; sock= sock->next) + sock->intern= sock->flag & SOCK_HIDDEN; + } + /* set tag */ + for(link= ngroup->links.first; link; link= link->next) { + link->fromsock->intern= 1; + link->tosock->intern= 1; + } + + /* remove link pointer to external links (only happens on create group) */ + for(node= ngroup->nodes.first; node; node= node->next) { + for(sock= node->inputs.first; sock; sock= sock->next) + if(sock->intern==0) + sock->link= NULL; + } + + /* set all intern sockets to own_index zero, makes sure that later use won't mixup */ + for(node= ngroup->nodes.first; node; node= node->next) { + for(sock= node->inputs.first; sock; sock= sock->next) + if(sock->intern) + sock->own_index= 0; + for(sock= node->outputs.first; sock; sock= sock->next) + if(sock->intern) + sock->own_index= 0; + } +} + +/* after editing group, new sockets are zero */ +/* this routine ensures unique identifiers for zero sockets that are exposed */ +static void group_verify_own_indices(bNodeTree *ngroup) +{ + bNode *node; + bNodeSocket *sock; + + for(node= ngroup->nodes.first; node; node= node->next) { + for(sock= node->inputs.first; sock; sock= sock->next) + if(sock->own_index==0 && sock->intern==0) + sock->own_index= ++(ngroup->cur_index); + for(sock= node->outputs.first; sock; sock= sock->next) + if(sock->own_index==0 && sock->intern==0) + sock->own_index= ++(ngroup->cur_index); + } + printf("internal index %d\n", ngroup->cur_index); +} + + +/* nodetrees can be used as groups, so we need typeinfo structs generated */ +void ntreeMakeOwnType(bNodeTree *ngroup) +{ + bNode *node; + bNodeSocket *sock; + int totin= 0, totout=0, a; + + /* tags socket when internal linked */ + group_tag_internal_sockets(ngroup); + + /* ensure all sockets have own unique id */ + group_verify_own_indices(ngroup); + + /* counting stats */ + for(node= ngroup->nodes.first; node; node= node->next) { + if(node->type==NODE_GROUP) + break; + for(sock= node->inputs.first; sock; sock= sock->next) + if(sock->intern==0) + totin++; + for(sock= node->outputs.first; sock; sock= sock->next) + if(sock->intern==0) + totout++; + } + /* debug: nodetrees in nodetrees not handled yet */ + if(node) { + printf("group in group, not supported yet\n"); + return; + } + + /* free own type struct */ + if(ngroup->owntype) { + if(ngroup->owntype->inputs) + MEM_freeN(ngroup->owntype->inputs); + if(ngroup->owntype->outputs) + MEM_freeN(ngroup->owntype->outputs); + MEM_freeN(ngroup->owntype); + } + + /* make own type struct */ + ngroup->owntype= MEM_mallocN(sizeof(bNodeType), "group type"); + *ngroup->owntype= node_group_typeinfo; + + /* input type arrays */ + if(totin) { + bNodeSocketType *stype; + bNodeSocketType *inputs= MEM_mallocN(sizeof(bNodeSocketType)*(totin+1), "bNodeSocketType"); + a= 0; + + for(node= ngroup->nodes.first; node; node= node->next) { + /* nodes are presumed fully verified, stype and socket list are in sync */ + stype= node->typeinfo->inputs; + for(sock= node->inputs.first; sock; sock= sock->next, stype++) { + if(sock->intern==0) { + /* debug only print */ + if(stype==NULL || stype->type==-1) printf("group verification error %s\n", ngroup->id.name); + + inputs[a]= *stype; + inputs[a].own_index= sock->own_index; + inputs[a].internsock= sock; + a++; + } + } + } + inputs[a].type= -1; /* terminator code */ + ngroup->owntype->inputs= inputs; + } + + /* output type arrays */ + if(totout) { + bNodeSocketType *stype; + bNodeSocketType *outputs= MEM_mallocN(sizeof(bNodeSocketType)*(totout+1), "bNodeSocketType"); + a= 0; + + for(node= ngroup->nodes.first; node; node= node->next) { + /* nodes are presumed fully verified, stype and socket list are in sync */ + stype= node->typeinfo->outputs; + for(sock= node->outputs.first; sock; sock= sock->next, stype++) { + if(sock->intern==0) { + /* debug only print */ + if(stype==NULL || stype->type==-1) printf("group verification error %s\n", ngroup->id.name); + + outputs[a]= *stype; + outputs[a].own_index= sock->own_index; + outputs[a].internsock= sock; + a++; + } + } + } + outputs[a].type= -1; /* terminator code */ + ngroup->owntype->outputs= outputs; + } + + /* voila, the nodetree has the full definition for generating group-node instances! */ +} + + +static bNodeSocket *groupnode_find_tosock(bNode *gnode, int index) +{ + bNodeSocket *sock; + + for(sock= gnode->inputs.first; sock; sock= sock->next) + if(sock->to_index==index) + return sock; + return NULL; +} + +static bNodeSocket *groupnode_find_fromsock(bNode *gnode, int index) +{ + bNodeSocket *sock; + + for(sock= gnode->outputs.first; sock; sock= sock->next) + if(sock->to_index==index) + return sock; + return NULL; +} + +bNode *nodeMakeGroupFromSelected(bNodeTree *ntree) +{ + bNodeLink *link, *linkn; + bNode *node, *gnode, *nextn; + bNodeTree *ngroup; + float min[2], max[2]; + int totnode=0; + + INIT_MINMAX2(min, max); + + /* is there something to group? also do some clearing */ for(node= ntree->nodes.first; node; node= node->next) { - ntype= node->typeinfo; - if(ntype) { - /* might add some other verify stuff here */ - - verify_socket_list(ntree, &node->inputs, ntype->inputs); - verify_socket_list(ntree, &node->outputs, ntype->outputs); + 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->flag & NODE_SELECT) + link->tonode->done |= 1; + if(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= alloc_libblock(&G.main->nodetree, ID_NT, "NodeGroup"); + ngroup->type= ntree->type; + ngroup->alltypes= ntree->alltypes; + + /* move nodes over */ + for(node= ntree->nodes.first; node; node= nextn) { + nextn= node->next; + if(node->flag & NODE_SELECT) { + 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 links over */ + for(link= ntree->links.first; link; link= linkn) { + linkn= link->next; + if(link->fromnode->flag & link->tonode->flag & NODE_SELECT) { + BLI_remlink(&ntree->links, link); + BLI_addtail(&ngroup->links, link); } } + + /* now we can make own group typeinfo */ + ntreeMakeOwnType(ngroup); + + /* make group node */ + gnode= nodeAddNodeType(ntree, NODE_GROUP, ngroup); + 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= link->next) { + if(link->tonode->flag & NODE_SELECT) { + link->tonode= gnode; + link->tosock= groupnode_find_tosock(gnode, link->tosock->own_index); + if(link->tosock==NULL) printf("Bad!\n"); + } + else if(link->fromnode->flag & NODE_SELECT) { + link->fromnode= gnode; + link->fromsock= groupnode_find_fromsock(gnode, link->fromsock->own_index); + if(link->fromsock==NULL) printf("Bad!\n"); + } + } + + return gnode; } +/* note: ungroup: group_indices zero! */ +/* here's a nasty little one, need to check users... */ +/* should become callbackable... */ +void nodeVerifyGroup(bNodeTree *ngroup) +{ + Material *ma; + + /* group changed, so we rebuild the type definition */ + ntreeMakeOwnType(ngroup); + + if(ngroup->type==NTREE_SHADER) { + for(ma= G.main->mat.first; ma; ma= ma->id.next) { + if(ma->nodetree) { + bNode *node; + + /* find if group is in tree */ + for(node= ma->nodetree->nodes.first; node; node= node->next) + if(node->id == (ID *)ngroup) + break; + + if(node) { + /* set all type pointers OK */ + ntreeInitTypes(ma->nodetree); + + for(node= ma->nodetree->nodes.first; node; node= node->next) + if(node->id == (ID *)ngroup) + nodeVerifyType(ma->nodetree, node); + } + } + } + } +} -/* ************** Add stuff ********** */ +/* also to check all users... */ +/* should become callbackable... */ +void nodeGroupSocketUseFlags(bNodeTree *ngroup) +{ + bNode *node; + bNodeSocket *sock; + Material *ma; -/* not very important, but the stack solver likes to know a maximum */ -#define MAX_SOCKET 64 + /* clear flags */ + for(node= ngroup->nodes.first; node; node= node->next) { + for(sock= node->inputs.first; sock; sock= sock->next) + sock->flag &= ~SOCK_IN_USE; + for(sock= node->outputs.first; sock; sock= sock->next) + sock->flag &= ~SOCK_IN_USE; + } + + /* tag all thats in use */ + if(ngroup->type==NTREE_SHADER) { + for(ma= G.main->mat.first; ma; ma= ma->id.next) { + if(ma->nodetree) { + for(node= ma->nodetree->nodes.first; node; node= node->next) { + if(node->id==(ID *)ngroup) { + for(sock= node->inputs.first; sock; sock= sock->next) + if(sock->link) + if(sock->tosock) + sock->tosock->flag |= SOCK_IN_USE; + for(sock= node->outputs.first; sock; sock= sock->next) + if(nodeCountSocketLinks(ma->nodetree, sock)) + if(sock->tosock) + sock->tosock->flag |= SOCK_IN_USE; + } + } + } + } + } +} + +static void find_node_with_socket(bNodeTree *ntree, bNodeSocket *sock, bNode **nodep, int *sockindex) +{ + bNode *node; + bNodeSocket *tsock; + int index; + + for(node= ntree->nodes.first; node; node= node->next) { + for(index=0, tsock= node->inputs.first; tsock; tsock= tsock->next, index++) + if(tsock==sock) + break; + if(tsock) + break; + for(index=0, tsock= node->outputs.first; tsock; tsock= tsock->next, index++) + if(tsock==sock) + break; + if(tsock) + break; + } + if(node) { + *nodep= node; + *sockindex= index; + } + else { + *nodep= NULL; + } +} -bNode *nodeAddNodeType(bNodeTree *ntree, int type) +/* returns 1 if its OK */ +int nodeGroupUnGroup(bNodeTree *ntree, bNode *gnode) +{ + bNodeLink *link, *linkn; + bNode *node, *nextn; + bNodeTree *ngroup, *wgroup; + int index; + + ngroup= (bNodeTree *)gnode->id; + if(ngroup==NULL) return 0; + + /* clear new pointers, set in copytree */ + for(node= ntree->nodes.first; node; node= node->next) + node->new= NULL; + + wgroup= ntreeCopyTree(ngroup, 0); + + /* add the nodes into the ntree */ + for(node= wgroup->nodes.first; node; node= nextn) { + nextn= node->next; + BLI_remlink(&wgroup->nodes, node); + BLI_addtail(&ntree->nodes, node); + node->locx+= gnode->locx; + node->locy+= gnode->locy; + node->flag |= NODE_SELECT; + } + /* and the internal links */ + for(link= wgroup->links.first; link; link= linkn) { + linkn= link->next; + BLI_remlink(&wgroup->links, link); + BLI_addtail(&ntree->links, link); + } + + /* restore links to and from the gnode */ + for(link= ntree->links.first; link; link= link->next) { + if(link->tonode==gnode) { + /* link->tosock->tosock is on the node we look for */ + find_node_with_socket(ngroup, link->tosock->tosock, &nextn, &index); + if(nextn==NULL) printf("wrong stuff!\n"); + else if(nextn->new==NULL) printf("wrong stuff too!\n"); + else { + link->tonode= nextn->new; + link->tosock= BLI_findlink(&link->tonode->inputs, index); + } + } + else if(link->fromnode==gnode) { + /* link->fromsock->tosock is on the node we look for */ + find_node_with_socket(ngroup, link->fromsock->tosock, &nextn, &index); + if(nextn==NULL) printf("1 wrong stuff!\n"); + else if(nextn->new==NULL) printf("1 wrong stuff too!\n"); + else { + link->fromnode= nextn->new; + link->fromsock= BLI_findlink(&link->fromnode->outputs, index); + } + } + } + + /* remove the gnode & work tree */ + ntreeFreeTree(wgroup); + MEM_freeN(wgroup); + + nodeFreeNode(ntree, gnode); + + return 1; +} + +#pragma mark /* ************** Add stuff ********** */ + +bNode *nodeAddNodeType(bNodeTree *ntree, int type, bNodeTree *ngroup) { bNode *node; - bNodeType *ntype= nodeGetType(ntree, type); + bNodeType *ntype= node_get_type(ntree, type, ngroup); bNodeSocketType *stype; node= MEM_callocN(sizeof(bNode), "new node"); @@ -205,6 +673,9 @@ bNode *nodeAddNodeType(bNodeTree *ntree, int type) node->width= ntype->width; node->miniwidth= 15.0f; /* small value only, allows print of first chars */ + if(type==NODE_GROUP) + node->id= (ID *)ngroup; + if(ntype->inputs) { stype= ntype->inputs; while(stype->type != -1) { @@ -236,12 +707,19 @@ bNode *nodeAddNodeType(bNodeTree *ntree, int type) bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node) { bNode *nnode= MEM_callocN(sizeof(bNode), "dupli node"); - + bNodeSocket *sock; + *nnode= *node; BLI_addtail(&ntree->nodes, nnode); duplicatelist(&nnode->inputs, &node->inputs); + for(sock= nnode->inputs.first; sock; sock= sock->next) + sock->own_index= 0; + duplicatelist(&nnode->outputs, &node->outputs); + for(sock= nnode->outputs.first; sock; sock= sock->next) + sock->own_index= 0; + if(nnode->id) nnode->id->us++; @@ -286,7 +764,7 @@ bNodeTree *ntreeAddTree(int type) return ntree; } -/* ************** Free stuff ********** */ +#pragma mark /* ************** Free stuff ********** */ /* goes over entire tree */ static void node_unlink_node(bNodeTree *ntree, bNode *node) @@ -340,6 +818,7 @@ void nodeFreeNode(bNodeTree *ntree, bNode *node) MEM_freeN(node); } +/* do not free ntree itself here, free_libblock calls this function too */ void ntreeFreeTree(bNodeTree *ntree) { bNode *node, *next; @@ -350,7 +829,13 @@ void ntreeFreeTree(bNodeTree *ntree) } BLI_freelistN(&ntree->links); - MEM_freeN(ntree); + if(ntree->owntype) { + if(ntree->owntype->inputs) + MEM_freeN(ntree->owntype->inputs); + if(ntree->owntype->outputs) + MEM_freeN(ntree->owntype->outputs); + MEM_freeN(ntree->owntype); + } } bNodeTree *ntreeCopyTree(bNodeTree *ntree, int internal_select) @@ -404,10 +889,21 @@ bNodeTree *ntreeCopyTree(bNodeTree *ntree, int internal_select) nlink->tosock= BLI_findlink(&link->tonode->new->inputs, a); } } + + /* own type definition for group usage */ + if(internal_select==0) { + if(ntree->owntype) { + newtree->owntype= MEM_dupallocN(ntree->owntype); + if(ntree->owntype->inputs) + newtree->owntype->inputs= MEM_dupallocN(ntree->owntype->inputs); + if(ntree->owntype->outputs) + newtree->owntype->outputs= MEM_dupallocN(ntree->owntype->outputs); + } + } return newtree; } -/* ************ find stuff *************** */ +#pragma mark /* ************ find stuff *************** */ bNodeLink *nodeFindLink(bNodeTree *ntree, bNodeSocket *from, bNodeSocket *to) { @@ -492,7 +988,7 @@ void nodeSetActive(bNodeTree *ntree, bNode *node) node->flag |= NODE_ACTIVE_ID; } -/* ************** dependency stuff *********** */ +#pragma mark /* ************** dependency stuff *********** */ /* node is guaranteed to be not checked before */ static int node_recurs_check(bNode *node, bNode ***nsort, int level) @@ -592,7 +1088,7 @@ void ntreeSolveOrder(bNodeTree *ntree) } -/* *************** preview *********** */ +#pragma mark /* *************** preview *********** */ /* if node->preview, then we assume the rect to exist */ @@ -612,6 +1108,7 @@ static void nodeInitPreview(bNode *node, int xsize, int ysize) if(node->preview==NULL) { node->preview= MEM_callocN(sizeof(bNodePreview), "node preview"); + printf("added preview %s\n", node->name); } if(node->preview->rect==NULL) { node->preview->rect= MEM_callocN(4*xsize + xsize*ysize*sizeof(float)*4, "node preview rect"); @@ -620,6 +1117,16 @@ static void nodeInitPreview(bNode *node, int xsize, int ysize) } } +void ntreeInitPreview(bNodeTree *ntree, int xsize, int ysize) +{ + bNode *node; + + for(node= ntree->nodes.first; node; node= node->next) { + if(node->typeinfo->flag & NODE_PREVIEW) /* hrms, check for closed nodes? */ + nodeInitPreview(node, xsize, ysize); + } +} + void nodeAddToPreview(bNode *node, float *col, int x, int y) { bNodePreview *preview= node->preview; @@ -637,27 +1144,95 @@ void nodeAddToPreview(bNode *node, float *col, int x, int y) -/* ******************* executing ************* */ +#pragma mark /* ******************* executing ************* */ + +/* see notes at ntreeBeginExecTree */ +static void group_node_get_stack(bNode *node, bNodeStack *stack, bNodeStack **in, bNodeStack **out, bNodeStack **gin, bNodeStack **gout) +{ + bNodeSocket *sock; + + /* build pointer stack */ + for(sock= node->inputs.first; sock; sock= sock->next) { + if(sock->intern) { + /* yep, intern can have link or is hidden socket */ + if(sock->link) + *(in++)= stack + sock->link->fromsock->stack_index; + else + *(in++)= &sock->ns; + } + else + *(in++)= gin[sock->stack_index_ext]; + } + + for(sock= node->outputs.first; sock; sock= sock->next) { + if(sock->intern) + *(out++)= stack + sock->stack_index; + else + *(out++)= gout[sock->stack_index_ext]; + } +} + +static void node_group_exec_func(void *data, bNode *gnode, bNodeStack **in, bNodeStack **out) +{ + bNode *node; + bNodeTree *ntree= (bNodeTree *)gnode->id; + bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */ + bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */ + + if(ntree==NULL) return; + + if(ntree->init & NTREE_EXEC_INIT) { + for(node= ntree->nodes.first; node; node= node->next) { + if(node->typeinfo->execfunc) { + group_node_get_stack(node, ntree->stack, nsin, nsout, in, out); + node->typeinfo->execfunc(data, node, nsin, nsout); + } + } + } +} +/* stack indices make sure all nodes only write in allocated data, for making it thread safe */ +/* per tree (and per group) unique indices are created */ +/* the index_ext we need to be able to map from groups to the group-node own stack */ -void ntreeBeginExecTree(bNodeTree *ntree, int xsize, int ysize) +void ntreeBeginExecTree(bNodeTree *ntree) { bNode *node; bNodeSocket *sock; - int index= 0; + int index= 0, index_in= 0, index_out= 0; if((ntree->init & NTREE_TYPE_INIT)==0) ntreeInitTypes(ntree); + if(ntree->init & NTREE_EXEC_INIT) + return; /* create indices for stack, check preview */ for(node= ntree->nodes.first; node; node= node->next) { + + for(sock= node->inputs.first; sock; sock= sock->next) { + if(sock->intern==0) + sock->stack_index_ext= index_in++; + } + for(sock= node->outputs.first; sock; sock= sock->next) { sock->stack_index= index++; + if(sock->intern==0) + sock->stack_index_ext= index_out++; } - if(node->typeinfo->flag & NODE_PREVIEW) /* hrms, check for closed nodes? */ - nodeInitPreview(node, xsize, ysize); - + if(node->type==NODE_GROUP) { + if(node->id) { + + ntreeBeginExecTree((bNodeTree *)node->id); + + /* copy internal data from internal nodes to own input sockets */ + for(sock= node->inputs.first; sock; sock= sock->next) { + if(sock->tosock) { + sock->ns= sock->tosock->ns; + } + } + } + } } if(index) { bNodeStack *ns; @@ -672,12 +1247,24 @@ void ntreeBeginExecTree(bNodeTree *ntree, int xsize, int ysize) void ntreeEndExecTree(bNodeTree *ntree) { - if(ntree->stack) { - MEM_freeN(ntree->stack); - ntree->stack= NULL; - } + bNode *node; + + if(ntree->init & NTREE_EXEC_INIT) { + if(ntree->stack) { + MEM_freeN(ntree->stack); + ntree->stack= NULL; + } - ntree->init &= ~NTREE_EXEC_INIT; + ntree->init &= ~NTREE_EXEC_INIT; + + for(node= ntree->nodes.first; node; node= node->next) { + if(node->type==NODE_GROUP) { + if(node->id) { + ntreeEndExecTree((bNodeTree *)node->id); + } + } + } + } } static void node_get_stack(bNode *node, bNodeStack *stack, bNodeStack **in, bNodeStack **out) @@ -706,7 +1293,6 @@ void ntreeExecTree(bNodeTree *ntree) /* only when initialized */ if(ntree->init & NTREE_EXEC_INIT) { - for(node= ntree->nodes.first; node; node= node->next) { if(node->typeinfo->execfunc) { node_get_stack(node, ntree->stack, nsin, nsout); |