merge with/from trunk at r35190
[blender.git] / source / blender / blenkernel / intern / node.c
index eb09ecf2e6e6d451dd17a7e7726a2ef8446a738d..53bac9171ae0144a92c751f9645e8ef947d05d63 100644 (file)
@@ -1,4 +1,4 @@
-/**
+/*
  * $Id$
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
  * ***** END GPL LICENSE BLOCK *****
  */
 
-#ifndef DISABLE_PYTHON
+#ifdef WITH_PYTHON
 #include <Python.h>
 #endif
 
+#include "MEM_guardedalloc.h"
+
 #include <stdlib.h>
 #include <stddef.h>
 #include <string.h>
+#include <limits.h>
 
 #include "DNA_anim_types.h"
+#include "DNA_action_types.h"
+#include "DNA_node_types.h"
+
+#include "BLI_listbase.h"
 
 #include "RNA_access.h"
 
+#include "BKE_animsys.h"
+#include "BKE_action.h"
 #include "BKE_fcurve.h"
-#include "BKE_animsys.h" /* BKE_free_animdata only */
-
+#include "BKE_node.h"
+#include "BKE_utildefines.h"
+#include "BKE_node.h"
 
 #include "PIL_time.h"
 
-
 #include "CMP_node.h"
 #include "intern/CMP_util.h"   /* stupid include path... */
 
@@ -62,22 +71,14 @@ ListBase node_all_textures = {NULL, NULL};
 
 /* ************** Type stuff **********  */
 
-static bNodeType *node_get_type(bNodeTree *ntree, int type, bNodeTree *ngroup, ID *id)
+static bNodeType *node_get_type(bNodeTree *ntree, int type, ID *id)
 {
-       if(type==NODE_GROUP) {
-               if(ngroup && GS(ngroup->id.name)==ID_NT) {
-                       return ngroup->owntype;
-               }
-               return NULL;
-       }
-       else {
-               bNodeType *ntype = ntree->alltypes.first;
-               for(; ntype; ntype= ntype->next)
-                       if(ntype->type==type && id==ntype->id )
-                               return ntype;
-               
-               return NULL;
-       }
+       bNodeType *ntype = ntree->alltypes.first;
+       for(; ntype; ntype= ntype->next)
+               if(ntype->type==type && id==ntype->id )
+                       return ntype;
+       
+       return NULL;
 }
 
 void ntreeInitTypes(bNodeTree *ntree)
@@ -100,11 +101,11 @@ void ntreeInitTypes(bNodeTree *ntree)
                if(node->type==NODE_DYNAMIC) {
                        bNodeType *stype= NULL;
                        if(node->id==NULL) { /* empty script node */
-                               stype= node_get_type(ntree, node->type, NULL, NULL);
+                               stype= node_get_type(ntree, node->type, NULL);
                        } else { /* not an empty script node */
-                               stype= node_get_type(ntree, node->type, NULL, node->id);
+                               stype= node_get_type(ntree, node->type, node->id);
                                if(!stype) {
-                                       stype= node_get_type(ntree, node->type, NULL, NULL);
+                                       stype= node_get_type(ntree, node->type, NULL);
                                        /* needed info if the pynode script fails now: */
                                        if (node->id) node->storage= ntree;
                                } else {
@@ -116,7 +117,7 @@ void ntreeInitTypes(bNodeTree *ntree)
                        if(node->typeinfo)
                                node->typeinfo->initfunc(node);
                } else {
-                       node->typeinfo= node_get_type(ntree, node->type, (bNodeTree *)node->id, NULL);
+                       node->typeinfo= node_get_type(ntree, node->type, NULL);
                }
 
                if(node->typeinfo==NULL) {
@@ -150,9 +151,6 @@ 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;
@@ -166,6 +164,30 @@ static bNodeSocket *node_add_socket_type(ListBase *lb, bNodeSocketType *stype)
        return sock;
 }
 
+static bNodeSocket *node_add_group_socket(ListBase *lb, bNodeSocket *gsock)
+{
+       bNodeSocket *sock= MEM_callocN(sizeof(bNodeSocket), "sock");
+       
+       /* make a copy of the group socket */
+       *sock = *gsock;
+       sock->link = NULL;
+       sock->next = sock->prev = NULL;
+       sock->new_sock = NULL;
+       sock->ns.data = NULL;
+       
+       sock->own_index = gsock->own_index;
+       sock->groupsock = gsock;
+       /* XXX hack: group socket input/output roles are inverted internally,
+        * need to change the limit value when making actual node sockets from them.
+        */
+       sock->limit = (gsock->limit==1 ? 0xFFF : 1);
+       
+       if(lb)
+               BLI_addtail(lb, sock);
+
+       return sock;
+}
+
 static void node_rem_socket(bNodeTree *ntree, ListBase *lb, bNodeSocket *sock)
 {
        bNodeLink *link, *next;
@@ -186,18 +208,16 @@ static bNodeSocket *verify_socket(ListBase *lb, bNodeSocketType *stype)
        bNodeSocket *sock;
        
        for(sock= lb->first; sock; sock= sock->next) {
-               /* 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(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->ns.min= stype->min;
                sock->ns.max= stype->max;
-               sock->tosock= stype->internsock;
                
                BLI_remlink(lb, sock);
                
@@ -208,6 +228,37 @@ static bNodeSocket *verify_socket(ListBase *lb, bNodeSocketType *stype)
        }
 }
 
+static bNodeSocket *verify_group_socket(ListBase *lb, bNodeSocket *gsock)
+{
+       bNodeSocket *sock;
+       
+       for(sock= lb->first; sock; sock= sock->next) {
+               if(sock->own_index==gsock->own_index)
+                               break;
+       }
+       if(sock) {
+               sock->groupsock = gsock;
+               
+               strcpy(sock->name, gsock->name);
+               sock->type= gsock->type;
+               
+               /* XXX hack: group socket input/output roles are inverted internally,
+                * need to change the limit value when making actual node sockets from them.
+                */
+               sock->limit = (gsock->limit==1 ? 0xFFF : 1);
+               
+               sock->ns.min= gsock->ns.min;
+               sock->ns.max= gsock->ns.max;
+               
+               BLI_remlink(lb, sock);
+               
+               return sock;
+       }
+       else {
+               return node_add_group_socket(NULL, gsock);
+       }
+}
+
 static void verify_socket_list(bNodeTree *ntree, ListBase *lb, bNodeSocketType *stype_first)
 {
        bNodeSocketType *stype;
@@ -236,15 +287,41 @@ static void verify_socket_list(bNodeTree *ntree, ListBase *lb, bNodeSocketType *
        }
 }
 
-void nodeVerifyType(bNodeTree *ntree, bNode *node)
+static void verify_group_socket_list(bNodeTree *ntree, ListBase *lb, ListBase *glb)
 {
-       bNodeType *ntype= node->typeinfo;
+       bNodeSocket *gsock;
        
-       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);
+       /* step by step compare */
+       for (gsock= glb->first; gsock; gsock=gsock->next) {
+               /* abusing new_sock pointer for verification here! only used inside this function */
+               gsock->new_sock= verify_group_socket(lb, gsock);
+       }
+       /* leftovers are removed */
+       while(lb->first)
+               node_rem_socket(ntree, lb, lb->first);
+       /* and we put back the verified sockets */
+       for (gsock= glb->first; gsock; gsock=gsock->next) {
+               BLI_addtail(lb, gsock->new_sock);
+               gsock->new_sock = NULL;
+       }
+}
+
+void nodeVerifyType(bNodeTree *ntree, bNode *node)
+{
+       /* node groups don't have static sock lists, but use external sockets from the tree instead */
+       if (node->type==NODE_GROUP) {
+               bNodeTree *ngroup= (bNodeTree*)node->id;
+               if (ngroup) {
+                       verify_group_socket_list(ntree, &node->inputs, &ngroup->inputs);
+                       verify_group_socket_list(ntree, &node->outputs, &ngroup->outputs);
+               }
+       }
+       else {
+               bNodeType *ntype= node->typeinfo;
+               if(ntype) {
+                       verify_socket_list(ntree, &node->inputs, ntype->inputs);
+                       verify_socket_list(ntree, &node->outputs, ntype->outputs);
+               }
        }
 }
 
@@ -263,193 +340,38 @@ void ntreeVerifyTypes(bNodeTree *ntree)
 
 /* ************** Group stuff ********** */
 
-bNodeType node_group_typeinfo= {
-       /* next,prev   */       NULL, NULL,
-       /* 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    */       NULL,
-       /* butfunc     */       NULL,
-       /* initfunc    */       NULL,
-       /* freestoragefunc    */        NULL,
-       /* copystoragefunc    */        NULL,
-       /* id          */       NULL
-};
-
-/* 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|SOCK_UNAVAIL);
-       }
-       /* 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;
-       }
+/* XXX group typeinfo struct is used directly in ntreeMakeOwnType, needs cleanup */
+static bNodeType ntype_group;
 
-       /* 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)
+/* groups display their internal tree name as label */
+static const char *group_label(bNode *node)
 {
-       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);
+       return node->id->name+2;
 }
 
-
-/* nodetrees can be used as groups, so we need typeinfo structs generated */
-void ntreeMakeOwnType(bNodeTree *ngroup)
+void register_node_type_group(ListBase *lb)
 {
-       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;
-       }
+       node_type_base(&ntype_group, NODE_GROUP, "Group", NODE_CLASS_GROUP, NODE_OPTIONS, NULL, NULL);
+       node_type_size(&ntype_group, 120, 60, 200);
+       node_type_label(&ntype_group, group_label);
        
-       /* 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_callocN(sizeof(bNodeType), "group type");
-       *ngroup->owntype= node_group_typeinfo; /* copy data, for init */
-       
-       /* input type arrays */
-       if(totin) {
-               bNodeSocketType *stype;
-               bNodeSocketType *inputs= MEM_callocN(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_callocN(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! */
+       nodeRegisterType(lb, &ntype_group);
 }
 
-
-static bNodeSocket *groupnode_find_tosock(bNode *gnode, int index)
+static bNodeSocket *find_group_node_input(bNode *gnode, bNodeSocket *gsock)
 {
        bNodeSocket *sock;
-       
-       for(sock= gnode->inputs.first; sock; sock= sock->next)
-               if(sock->to_index==index)
+       for (sock=gnode->inputs.first; sock; sock=sock->next)
+               if (sock->groupsock == gsock)
                        return sock;
        return NULL;
 }
 
-static bNodeSocket *groupnode_find_fromsock(bNode *gnode, int index)
+static bNodeSocket *find_group_node_output(bNode *gnode, bNodeSocket *gsock)
 {
        bNodeSocket *sock;
-       
-       for(sock= gnode->outputs.first; sock; sock= sock->next)
-               if(sock->to_index==index)
+       for (sock=gnode->outputs.first; sock; sock=sock->next)
+               if (sock->groupsock == gsock)
                        return sock;
        return NULL;
 }
@@ -458,8 +380,9 @@ bNode *nodeMakeGroupFromSelected(bNodeTree *ntree)
 {
        bNodeLink *link, *linkn;
        bNode *node, *gnode, *nextn;
-       bNodeSocket *sock;
        bNodeTree *ngroup;
+       bNodeSocket *gsock;
+       ListBase anim_basepaths = {NULL, NULL};
        float min[2], max[2];
        int totnode=0;
        
@@ -481,9 +404,9 @@ bNode *nodeMakeGroupFromSelected(bNodeTree *ntree)
        /* 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)
+               if(link->fromnode && link->tonode && link->fromnode->flag & NODE_SELECT)
                        link->tonode->done |= 1;
-               if(link->tonode->flag & NODE_SELECT)
+               if(link->fromnode && link->tonode && link->tonode->flag & NODE_SELECT)
                        link->fromnode->done |= 2;
        }       
        
@@ -496,41 +419,50 @@ bNode *nodeMakeGroupFromSelected(bNodeTree *ntree)
                return NULL;
        
        /* OK! new nodetree */
-       ngroup= alloc_libblock(&G.main->nodetree, ID_NT, "NodeGroup");
-       ngroup->type= ntree->type;
-       ngroup->alltypes= ntree->alltypes;
+       ngroup= ntreeAddTree("NodeGroup", ntree->type, TRUE);
        
        /* move nodes over */
        for(node= ntree->nodes.first; node; node= nextn) {
                nextn= node->next;
                if(node->flag & NODE_SELECT) {
+                       /* 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));
+                       }
+                       
+                       /* change node-collection membership */
                        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]);
-
-                       /* set socket own_index to zero since it can still have a value
-                        * from being in a group before, otherwise it doesn't get a unique
-                        * index in group_verify_own_indices */
-                       for(sock= node->inputs.first; sock; sock= sock->next)
-                               sock->own_index= 0;
-                       for(sock= node->outputs.first; sock; sock= sock->next)
-                               sock->own_index= 0;
                }
        }
 
-       /* 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);
+       /* 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);
                }
        }
        
-       /* now we can make own group typeinfo */
-       ntreeMakeOwnType(ngroup);
-       
        /* make group node */
        gnode= nodeAddNodeType(ntree, NODE_GROUP, ngroup, NULL);
        gnode->locx= 0.5f*(min[0]+max[0]);
@@ -540,35 +472,29 @@ bNode *nodeMakeGroupFromSelected(bNodeTree *ntree)
        for(link= ntree->links.first; link; link= linkn) {
                linkn= link->next;
                
-               if(link->tonode->flag & NODE_SELECT) {
-                       link->tonode= gnode;
-                       sock= groupnode_find_tosock(gnode, link->tosock->own_index);
-                       if(sock==NULL) {
-                               nodeRemLink(ntree, link);       
-                               printf("Removed link, cannot mix internal and external sockets in group\n");
-                       }
-                       else link->tosock= sock;
+               if(link->fromnode && link->tonode && (link->fromnode->flag & link->tonode->flag & NODE_SELECT)) {
+                       BLI_remlink(&ntree->links, link);
+                       BLI_addtail(&ngroup->links, link);
                }
-               else if(link->fromnode->flag & NODE_SELECT) {
-                       link->fromnode= gnode;
-                       sock= groupnode_find_fromsock(gnode, link->fromsock->own_index);
-                       if(sock==NULL) {
-                               nodeRemLink(ntree, link);       
-                               printf("Removed link, cannot mix internal and external sockets in group\n");
-                       }
-                       else link->fromsock= sock;
+               else if(link->tonode && (link->tonode->flag & NODE_SELECT)) {
+                       gsock = nodeGroupExposeSocket(ngroup, link->tosock, SOCK_IN);
+                       link->tosock->link = nodeAddLink(ngroup, NULL, gsock, link->tonode, link->tosock);
+                       link->tosock = node_add_group_socket(&gnode->inputs, gsock);
+                       link->tonode = gnode;
                }
-       }
-       
-       /* initialize variables of unused input sockets */
-       for(node= ngroup->nodes.first; node; node= node->next) {
-               for(sock= node->inputs.first; sock; sock= sock->next) {
-                       if(sock->intern==0) {
-                               bNodeSocket *nsock= groupnode_find_tosock(gnode, sock->own_index);
-                               if(nsock) {
-                                       QUATCOPY(nsock->ns.vec, sock->ns.vec);
-                               }
+               else if(link->fromnode && (link->fromnode->flag & NODE_SELECT)) {
+                       /* search for existing group node socket */
+                       for (gsock=ngroup->outputs.first; gsock; gsock=gsock->next)
+                               if (gsock->link && gsock->link->fromsock==link->fromsock)
+                                       break;
+                       if (!gsock) {
+                               gsock = nodeGroupExposeSocket(ngroup, link->fromsock, SOCK_OUT);
+                               gsock->link = nodeAddLink(ngroup, link->fromnode, link->fromsock, NULL, gsock);
+                               link->fromsock = node_add_group_socket(&gnode->outputs, gsock);
                        }
+                       else
+                               link->fromsock = find_group_node_output(gnode, gsock);
+                       link->fromnode = gnode;
                }
        }
 
@@ -578,35 +504,21 @@ bNode *nodeMakeGroupFromSelected(bNodeTree *ntree)
        return gnode;
 }
 
-/* note: ungroup: group_indices zero! */
-
 /* here's a nasty little one, need to check users... */
 /* should become callbackable... */
-void nodeVerifyGroup(bNodeTree *ngroup)
+void nodeGroupVerify(bNodeTree *ngroup)
 {
-       
        /* group changed, so we rebuild the type definition */
-       ntreeMakeOwnType(ngroup);
+//     ntreeMakeGroupSockets(ngroup);
        
        if(ngroup->type==NTREE_SHADER) {
                Material *ma;
                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);
-                               }
+                                               nodeVerifyType(ma->nodetree, node);
                        }
                }
        }
@@ -615,20 +527,9 @@ void nodeVerifyGroup(bNodeTree *ngroup)
                for(sce= G.main->scene.first; sce; sce= sce->id.next) {
                        if(sce->nodetree) {
                                bNode *node;
-                               
-                               /* find if group is in tree */
                                for(node= sce->nodetree->nodes.first; node; node= node->next)
                                        if(node->id == (ID *)ngroup)
-                                               break;
-                               
-                               if(node) {
-                                       /* set all type pointers OK */
-                                       ntreeInitTypes(sce->nodetree);
-                                       
-                                       for(node= sce->nodetree->nodes.first; node; node= node->next)
-                                               if(node->id == (ID *)ngroup)
-                                                       nodeVerifyType(sce->nodetree, node);
-                               }
+                                               nodeVerifyType(sce->nodetree, node);
                        }
                }
        }
@@ -637,20 +538,9 @@ void nodeVerifyGroup(bNodeTree *ngroup)
                for(tx= G.main->tex.first; tx; tx= tx->id.next) {
                        if(tx->nodetree) {
                                bNode *node;
-                               
-                               /* find if group is in tree */
                                for(node= tx->nodetree->nodes.first; node; node= node->next)
                                        if(node->id == (ID *)ngroup)
-                                               break;
-                               
-                               if(node) {
-                                       /* set all type pointers OK */
-                                       ntreeInitTypes(tx->nodetree);
-                                       
-                                       for(node= tx->nodetree->nodes.first; node; node= node->next)
-                                               if(node->id == (ID *)ngroup)
-                                                       nodeVerifyType(tx->nodetree, node);
-                               }
+                                               nodeVerifyType(tx->nodetree, node);
                        }
                }
        }
@@ -677,15 +567,15 @@ void nodeGroupSocketUseFlags(bNodeTree *ngroup)
                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) {
+                                       if(node->id==&ngroup->id) {
                                                for(sock= node->inputs.first; sock; sock= sock->next)
                                                        if(sock->link)
-                                                               if(sock->tosock) 
-                                                                       sock->tosock->flag |= SOCK_IN_USE;
+                                                               if(sock->groupsock) 
+                                                                       sock->groupsock->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;
+                                                               if(sock->groupsock) 
+                                                                       sock->groupsock->flag |= SOCK_IN_USE;
                                        }
                                }
                        }
@@ -699,12 +589,12 @@ void nodeGroupSocketUseFlags(bNodeTree *ngroup)
                                        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;
+                                                               if(sock->groupsock) 
+                                                                       sock->groupsock->flag |= SOCK_IN_USE;
                                                for(sock= node->outputs.first; sock; sock= sock->next)
                                                        if(nodeCountSocketLinks(sce->nodetree, sock))
-                                                               if(sock->tosock) 
-                                                                       sock->tosock->flag |= SOCK_IN_USE;
+                                                               if(sock->groupsock) 
+                                                                       sock->groupsock->flag |= SOCK_IN_USE;
                                        }
                                }
                        }
@@ -718,12 +608,12 @@ void nodeGroupSocketUseFlags(bNodeTree *ngroup)
                                        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;
+                                                               if(sock->groupsock) 
+                                                                       sock->groupsock->flag |= SOCK_IN_USE;
                                                for(sock= node->outputs.first; sock; sock= sock->next)
                                                        if(nodeCountSocketLinks(tx->nodetree, sock))
-                                                               if(sock->tosock) 
-                                                                       sock->tosock->flag |= SOCK_IN_USE;
+                                                               if(sock->groupsock) 
+                                                                       sock->groupsock->flag |= SOCK_IN_USE;
                                        }
                                }
                        }
@@ -738,21 +628,27 @@ bNode *nodeFindNodebyName(bNodeTree *ntree, const char *name)
 }
 
 /* finds a node based on given socket */
-int nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **nodep, int *sockindex)
+int nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **nodep, int *sockindex, int *in_out)
 {
        bNode *node;
        bNodeSocket *tsock;
        int index= 0;
        
        for(node= ntree->nodes.first; node; node= node->next) {
-               for(index=0, tsock= node->inputs.first; tsock; tsock= tsock->next, index++)
-                       if(tsock==sock)
+               for(index=0, tsock= node->inputs.first; tsock; tsock= tsock->next, index++) {
+                       if(tsock==sock) {
+                               if (in_out) *in_out= SOCK_IN;
                                break;
+                       }
+               }
                if(tsock)
                        break;
-               for(index=0, tsock= node->outputs.first; tsock; tsock= tsock->next, index++)
-                       if(tsock==sock)
+               for(index=0, tsock= node->outputs.first; tsock; tsock= tsock->next, index++) {
+                       if(tsock==sock) {
+                               if (in_out) *in_out= SOCK_OUT;
                                break;
+                       }
+               }
                if(tsock)
                        break;
        }
@@ -773,7 +669,7 @@ int nodeGroupUnGroup(bNodeTree *ntree, bNode *gnode)
        bNodeLink *link, *linkn;
        bNode *node, *nextn;
        bNodeTree *ngroup, *wgroup;
-       int index;
+       ListBase anim_basepaths = {NULL, NULL};
        
        ngroup= (bNodeTree *)gnode->id;
        if(ngroup==NULL) return 0;
@@ -781,98 +677,261 @@ int nodeGroupUnGroup(bNodeTree *ntree, bNode *gnode)
        /* clear new pointers, set in copytree */
        for(node= ntree->nodes.first; node; node= node->next)
                node->new_node= NULL;
-
-       wgroup= ntreeCopyTree(ngroup, 0);
+       
+       /* wgroup is a temporary copy of the NodeTree we're merging in
+        *      - all of wgroup's nodes are transferred across to their new home
+        *      - ngroup (i.e. the source NodeTree) is left unscathed
+        */
+       wgroup= ntreeCopyTree(ngroup);
        
        /* add the nodes into the ntree */
        for(node= wgroup->nodes.first; node; node= nextn) {
                nextn= node->next;
+               
+               /* 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 (wgroup->adt) {
+                       PointerRNA ptr;
+                       char *path;
+                       
+                       RNA_pointer_create(&wgroup->id, &RNA_Node, node, &ptr);
+                       path = RNA_path_from_ID_to_struct(&ptr);
+                       
+                       if (path)
+                               BLI_addtail(&anim_basepaths, BLI_genericNodeN(path));
+               }
+               
+               /* migrate node */
                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 */
+       
+       /* restore external 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 */
-                       nodeFindNode(ngroup, link->tosock->tosock, &nextn, &index);
-                       if(nextn==NULL) printf("wrong stuff!\n");
-                       else if(nextn->new_node==NULL) printf("wrong stuff too!\n");
-                       else {
-                               link->tonode= nextn->new_node;
-                               link->tosock= BLI_findlink(&link->tonode->inputs, index);
+               if (link->fromnode==gnode) {
+                       if (link->fromsock->groupsock) {
+                               bNodeSocket *gsock= link->fromsock->groupsock;
+                               if (gsock->link) {
+                                       if (gsock->link->fromnode) {
+                                               /* NB: using the new internal copies here! the groupsock pointer still maps to the old tree */
+                                               link->fromnode = (gsock->link->fromnode ? gsock->link->fromnode->new_node : NULL);
+                                               link->fromsock = gsock->link->fromsock->new_sock;
+                                       }
+                                       else {
+                                               /* group output directly maps to group input */
+                                               bNodeSocket *insock= find_group_node_input(gnode, gsock->link->fromsock);
+                                               if (insock->link) {
+                                                       link->fromnode = insock->link->fromnode;
+                                                       link->fromsock = insock->link->fromsock;
+                                               }
+                                       }
+                               }
+                               else {
+                                       /* constant group output: copy the stack value to the external socket.
+                                        * the link is kept here until all possible external users have been fixed.
+                                        */
+                                       QUATCOPY(link->tosock->ns.vec, gsock->ns.vec);
+                               }
                        }
                }
-               else if(link->fromnode==gnode) {
-                       /* link->fromsock->tosock is on the node we look for */
-                       nodeFindNode(ngroup, link->fromsock->tosock, &nextn, &index);
-                       if(nextn==NULL) printf("1 wrong stuff!\n");
-                       else if(nextn->new_node==NULL) printf("1 wrong stuff too!\n");
+       }
+       /* remove internal output links, these are not used anymore */
+       for(link=wgroup->links.first; link; link= linkn) {
+               linkn = link->next;
+               if (!link->tonode)
+                       nodeRemLink(wgroup, link);
+       }
+       /* restore links from internal nodes */
+       for(link= wgroup->links.first; link; link= link->next) {
+               /* indicates link to group input */
+               if (!link->fromnode) {
+                       /* NB: can't use find_group_node_input here,
+                        * because gnode sockets still point to the old tree!
+                        */
+                       bNodeSocket *insock;
+                       for (insock= gnode->inputs.first; insock; insock= insock->next)
+                               if (insock->groupsock->new_sock == link->fromsock)
+                                       break;
+                       if (insock->link) {
+                               link->fromnode = insock->link->fromnode;
+                               link->fromsock = insock->link->fromsock;
+                       }
                        else {
-                               link->fromnode= nextn->new_node;
-                               link->fromsock= BLI_findlink(&link->fromnode->outputs, index);
+                               /* uses group constant input. copy the input value and remove the dead link. */
+                               QUATCOPY(link->tosock->ns.vec, insock->ns.vec);
+                               nodeRemLink(wgroup, link);
                        }
                }
        }
        
-       /* remove the gnode & work tree */
-       free_libblock(&G.main->nodetree, wgroup);
+       /* add internal links to the ntree */
+       for(link= wgroup->links.first; link; link= linkn) {
+               linkn= link->next;
+               BLI_remlink(&wgroup->links, link);
+               BLI_addtail(&ntree->links, link);
+       }
+       
+       /* and copy across the animation */
+       if (wgroup->adt) {
+               LinkData *ld, *ldn=NULL;
+               bAction *waction;
+               
+               /* firstly, wgroup needs to temporary dummy action that can be destroyed, as it shares copies */
+               waction = wgroup->adt->action = copy_action(wgroup->adt->action);
+               
+               /* now perform the moving */
+               BKE_animdata_separate_by_basepath(&wgroup->id, &ntree->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);
+               }
+               
+               /* free temp action too */
+               free_libblock(&G.main->action, waction);
+       }
        
+       /* delete the group instance. this also removes old input links! */
        nodeFreeNode(ntree, gnode);
        
+       /* free the group tree (takes care of user count) */
+       free_libblock(&G.main->nodetree, wgroup);
+       
        /* solve order goes fine, but the level tags not... doing it twice works for now. solve this once */
+       /* XXX is this still necessary with new groups? it may have been caused by non-updated sock->link pointers. lukas */
        ntreeSolveOrder(ntree);
        ntreeSolveOrder(ntree);
 
        return 1;
 }
 
-void nodeCopyGroup(bNode *gnode)
+void nodeGroupCopy(bNode *gnode)
 {
        bNodeSocket *sock;
 
        gnode->id->us--;
-       gnode->id= (ID *)ntreeCopyTree((bNodeTree *)gnode->id, 0);
+       gnode->id= (ID *)ntreeCopyTree((bNodeTree *)gnode->id);
 
        /* new_sock was set in nodeCopyNode */
        for(sock=gnode->inputs.first; sock; sock=sock->next)
-               if(sock->tosock)
-                       sock->tosock= sock->tosock->new_sock;
+               if(sock->groupsock)
+                       sock->groupsock= sock->groupsock->new_sock;
 
        for(sock=gnode->outputs.first; sock; sock=sock->next)
-               if(sock->tosock)
-                       sock->tosock= sock->tosock->new_sock;
+               if(sock->groupsock)
+                       sock->groupsock= sock->groupsock->new_sock;
+}
+
+bNodeSocket *nodeGroupAddSocket(bNodeTree *ngroup, const char *name, int type, int in_out)
+{
+       bNodeSocket *gsock = MEM_callocN(sizeof(bNodeSocket), "bNodeSocket");
+       
+       strncpy(gsock->name, name, sizeof(gsock->name));
+       gsock->type = type;
+       gsock->ns.sockettype = type;
+       gsock->ns.min = INT_MIN;
+       gsock->ns.max = INT_MAX;
+       zero_v4(gsock->ns.vec);
+       gsock->ns.data = NULL;
+       gsock->flag = 0;
+
+       gsock->next = gsock->prev = NULL;
+       gsock->new_sock = NULL;
+       gsock->link = NULL;
+       gsock->ns.data = NULL;
+       /* assign new unique index */
+       gsock->own_index = ngroup->cur_index++;
+       gsock->limit = (in_out==SOCK_IN ? 0xFFF : 1);
+       
+       BLI_addtail(in_out==SOCK_IN ? &ngroup->inputs : &ngroup->outputs, gsock);
+       
+       return gsock;
+}
+
+bNodeSocket *nodeGroupExposeSocket(bNodeTree *ngroup, bNodeSocket *sock, int in_out)
+{
+       bNodeSocket *gsock= nodeGroupAddSocket(ngroup, sock->name, sock->type, in_out);
+       /* initialize the default socket value */
+       QUATCOPY(gsock->ns.vec, sock->ns.vec);
+       return gsock;
+}
+
+void nodeGroupExposeAllSockets(bNodeTree *ngroup)
+{
+       bNode *node;
+       bNodeSocket *sock, *gsock;
+       
+       for (node=ngroup->nodes.first; node; node=node->next) {
+               for (sock=node->inputs.first; sock; sock=sock->next) {
+                       if (!sock->link && !(sock->flag & SOCK_HIDDEN)) {
+                               gsock = nodeGroupAddSocket(ngroup, sock->name, sock->type, SOCK_IN);
+                               /* initialize the default socket value */
+                               QUATCOPY(gsock->ns.vec, sock->ns.vec);
+                               sock->link = nodeAddLink(ngroup, NULL, gsock, node, sock);
+                       }
+               }
+               for (sock=node->outputs.first; sock; sock=sock->next) {
+                       if (nodeCountSocketLinks(ngroup, sock)==0 && !(sock->flag & SOCK_HIDDEN)) {
+                               gsock = nodeGroupAddSocket(ngroup, sock->name, sock->type, SOCK_OUT);
+                               /* initialize the default socket value */
+                               QUATCOPY(gsock->ns.vec, sock->ns.vec);
+                               gsock->link = nodeAddLink(ngroup, node, sock, NULL, gsock);
+                       }
+               }
+       }
+}
+
+void nodeGroupRemoveSocket(bNodeTree *ngroup, bNodeSocket *gsock, int in_out)
+{
+       nodeRemSocketLinks(ngroup, gsock);
+       switch (in_out) {
+       case SOCK_IN:   BLI_remlink(&ngroup->inputs, gsock);    break;
+       case SOCK_OUT:  BLI_remlink(&ngroup->outputs, gsock);   break;
+       }
 }
 
 /* ************** Add stuff ********** */
 void nodeAddSockets(bNode *node, bNodeType *ntype)
 {
-       bNodeSocketType *stype;
-
-       if(ntype->inputs) {
-               stype= ntype->inputs;
-               while(stype->type != -1) {
-                       node_add_socket_type(&node->inputs, stype);
-                       stype++;
+       if (node->type==NODE_GROUP) {
+               bNodeTree *ntree= (bNodeTree*)node->id;
+               if (ntree) {
+                       bNodeSocket *gsock;
+                       for (gsock=ntree->inputs.first; gsock; gsock=gsock->next)
+                               node_add_group_socket(&node->inputs, gsock);
+                       for (gsock=ntree->outputs.first; gsock; gsock=gsock->next)
+                               node_add_group_socket(&node->outputs, gsock);
                }
        }
-       if(ntype->outputs) {
-               stype= ntype->outputs;
-               while(stype->type != -1) {
-                       node_add_socket_type(&node->outputs, stype);
-                       stype++;
+       else {
+               bNodeSocketType *stype;
+               
+               if(ntype->inputs) {
+                       stype= ntype->inputs;
+                       while(stype->type != -1) {
+                               node_add_socket_type(&node->inputs, stype);
+                               stype++;
+                       }
+               }
+               if(ntype->outputs) {
+                       stype= ntype->outputs;
+                       while(stype->type != -1) {
+                               node_add_socket_type(&node->outputs, stype);
+                               stype++;
+                       }
                }
        }
 }
+
 /* Find the first available, non-duplicate name for a given node */
 void nodeUniqueName(bNodeTree *ntree, bNode *node)
 {
@@ -884,6 +943,11 @@ bNode *nodeAddNodeType(bNodeTree *ntree, int type, bNodeTree *ngroup, ID *id)
        bNode *node= NULL;
        bNodeType *ntype= NULL;
 
+       if (ngroup && BLI_findindex(&G.main->nodetree, ngroup)==-1) {
+               printf("nodeAddNodeType() error: '%s' not in main->nodetree\n", ngroup->id.name);
+               return NULL;
+       }
+
        if(type>=NODE_DYNAMIC_MENU) {
                int a=0, idx= type-NODE_DYNAMIC_MENU;
                ntype= ntree->alltypes.first;
@@ -896,7 +960,7 @@ bNode *nodeAddNodeType(bNodeTree *ntree, int type, bNodeTree *ngroup, ID *id)
                        ntype= ntype->next;
                }
        } else
-               ntype= node_get_type(ntree, type, ngroup, id);
+               ntype= node_get_type(ntree, type, id);
 
        node= MEM_callocN(sizeof(bNode), "new node");
        BLI_addtail(&ntree->nodes, node);
@@ -960,7 +1024,7 @@ void nodeUpdateType(bNodeTree *ntree, bNode* node, bNodeType *ntype)
 
 /* keep socket listorder identical, for copying links */
 /* ntree is the target tree */
-bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node, int internal)
+bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node)
 {
        bNode *nnode= MEM_callocN(sizeof(bNode), "dupli node");
        bNodeSocket *sock, *oldsock;
@@ -974,15 +1038,11 @@ bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node, int internal)
        oldsock= node->inputs.first;
        for(sock= nnode->inputs.first; sock; sock= sock->next, oldsock= oldsock->next) {
                oldsock->new_sock= sock;
-               if(internal)
-                       sock->own_index= 0;
        }
        
        BLI_duplicatelist(&nnode->outputs, &node->outputs);
        oldsock= node->outputs.first;
        for(sock= nnode->outputs.first; sock; sock= sock->next, oldsock= oldsock->next) {
-               if(internal)
-                       sock->own_index= 0;
                sock->stack_index= 0;
                sock->ns.data= NULL;
                oldsock->new_sock= sock;
@@ -1000,15 +1060,61 @@ bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node, int internal)
        return nnode;
 }
 
+/* fromsock and tosock can be NULL */
+/* also used via rna api, so we check for proper input output direction */
 bNodeLink *nodeAddLink(bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, bNode *tonode, bNodeSocket *tosock)
 {
-       bNodeLink *link= MEM_callocN(sizeof(bNodeLink), "link");
+       bNodeSocket *sock;
+       bNodeLink *link= NULL; 
+       int from= 0, to= 0;
+       
+       if(fromnode) {
+               /* test valid input */
+               for(sock= fromnode->outputs.first; sock; sock= sock->next)
+                       if(sock==fromsock)
+                               break;
+               if(sock)
+                       from= 1; /* OK */
+               else {
+                       for(sock= fromnode->inputs.first; sock; sock= sock->next)
+                               if(sock==fromsock)
+                                       break;
+                       if(sock)
+                               from= -1; /* OK but flip */
+               }
+       }
+       if(tonode) {
+               for(sock= tonode->inputs.first; sock; sock= sock->next)
+                       if(sock==tosock)
+                               break;
+               if(sock)
+                       to= 1; /* OK */
+               else {
+                       for(sock= tonode->outputs.first; sock; sock= sock->next)
+                               if(sock==tosock)
+                                       break;
+                       if(sock)
+                               to= -1; /* OK but flip */
+               }
+       }
        
-       BLI_addtail(&ntree->links, link);
-       link->fromnode= fromnode;
-       link->fromsock= fromsock;
-       link->tonode= tonode;
-       link->tosock= tosock;
+       /* this allows NULL sockets to work */
+       if(from >= 0 && to >= 0) {
+               link= MEM_callocN(sizeof(bNodeLink), "link");
+               BLI_addtail(&ntree->links, link);
+               link->fromnode= fromnode;
+               link->fromsock= fromsock;
+               link->tonode= tonode;
+               link->tosock= tosock;
+       }
+       else if(from <= 0 && to <= 0) {
+               link= MEM_callocN(sizeof(bNodeLink), "link");
+               BLI_addtail(&ntree->links, link);
+               link->fromnode= tonode;
+               link->fromsock= tosock;
+               link->tonode= fromnode;
+               link->tosock= fromsock;
+       }
        
        return link;
 }
@@ -1034,104 +1140,83 @@ void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock)
 }
 
 
-bNodeTree *ntreeAddTree(int type)
+bNodeTree *ntreeAddTree(const char *name, int type, const short is_group)
 {
-       bNodeTree *ntree= MEM_callocN(sizeof(bNodeTree), "new node tree");
+       bNodeTree *ntree;
+
+       if (is_group)
+               ntree= alloc_libblock(&G.main->nodetree, ID_NT, name);
+       else {
+               ntree= MEM_callocN(sizeof(bNodeTree), "new node tree");
+               *( (short *)ntree->id.name )= ID_NT; /* not "type", as that is ntree->type */
+               BLI_strncpy(ntree->id.name+2, name, sizeof(ntree->id.name));
+       }
+
        ntree->type= type;
        ntree->alltypes.first = NULL;
        ntree->alltypes.last = NULL;
 
-       /* this helps RNA identify ID pointers as nodetree */
-       if(ntree->type==NTREE_SHADER)
-               BLI_strncpy(ntree->id.name, "NTShader Nodetree", sizeof(ntree->id.name));
-       else if(ntree->type==NTREE_COMPOSIT)
-               BLI_strncpy(ntree->id.name, "NTCompositing Nodetree", sizeof(ntree->id.name));
-       else if(ntree->type==NTREE_TEXTURE)
-               BLI_strncpy(ntree->id.name, "NTTexture Nodetree", sizeof(ntree->id.name));
-       
        ntreeInitTypes(ntree);
        return ntree;
 }
 
 /* Warning: this function gets called during some rather unexpected times
- *     - internal_select is only 1 when used for duplicating selected nodes (i.e. Shift-D duplicate operator)
  *     - this gets called when executing compositing updates (for threaded previews)
  *     - when the nodetree datablock needs to be copied (i.e. when users get copied)
  *     - for scene duplication use ntreeSwapID() after so we dont have stale pointers.
  */
-bNodeTree *ntreeCopyTree(bNodeTree *ntree, int internal_select)
+bNodeTree *ntreeCopyTree(bNodeTree *ntree)
 {
        bNodeTree *newtree;
        bNode *node, *nnode, *last;
-       bNodeLink *link, *nlink;
-       bNodeSocket *sock;
-       int a;
+       bNodeLink *link;
+       bNodeSocket *gsock, *oldgsock;
        
        if(ntree==NULL) return NULL;
        
-       if(internal_select==0) {
-               /* is ntree part of library? */
-               for(newtree=G.main->nodetree.first; newtree; newtree= newtree->id.next)
-                       if(newtree==ntree) break;
-               if(newtree) {
-                       newtree= copy_libblock(ntree);
-               } else {
-                       newtree= MEM_dupallocN(ntree);
-                       copy_libblock_data(&newtree->id, &ntree->id); /* copy animdata and ID props */
-               }
-               newtree->nodes.first= newtree->nodes.last= NULL;
-               newtree->links.first= newtree->links.last= NULL;
+       /* is ntree part of library? */
+       for(newtree=G.main->nodetree.first; newtree; newtree= newtree->id.next)
+               if(newtree==ntree) break;
+       if(newtree) {
+               newtree= copy_libblock(ntree);
+       } else {
+               newtree= MEM_dupallocN(ntree);
+               copy_libblock_data(&newtree->id, &ntree->id, TRUE); /* copy animdata and ID props */
        }
-       else
-               newtree= ntree;
+       newtree->nodes.first= newtree->nodes.last= NULL;
+       newtree->links.first= newtree->links.last= NULL;
        
-       last= ntree->nodes.last;
+       last = ntree->nodes.last;
        for(node= ntree->nodes.first; node; node= node->next) {
-               
                node->new_node= NULL;
-               if(internal_select==0 || (node->flag & NODE_SELECT)) {
-                       nnode= nodeCopyNode(newtree, node, internal_select);    /* sets node->new */
-                       if(internal_select) {
-                               node->flag &= ~(NODE_SELECT|NODE_ACTIVE);
-                               nnode->flag |= NODE_SELECT;
-                       }
-               }
+               nnode= nodeCopyNode(newtree, node);     /* sets node->new */
                if(node==last) break;
        }
        
-       /* check for copying links */
-       for(link= ntree->links.first; link; link= link->next) {
-               if(link->fromnode==NULL || link->tonode==NULL);
-               else if(link->fromnode->new_node && link->tonode->new_node) {
-                       nlink= nodeAddLink(newtree, link->fromnode->new_node, NULL, link->tonode->new_node, NULL);
-                       /* sockets were copied in order */
-                       for(a=0, sock= link->fromnode->outputs.first; sock; sock= sock->next, a++) {
-                               if(sock==link->fromsock)
-                                       break;
-                       }
-                       nlink->fromsock= BLI_findlink(&link->fromnode->new_node->outputs, a);
-                       
-                       for(a=0, sock= link->tonode->inputs.first; sock; sock= sock->next, a++) {
-                               if(sock==link->tosock)
-                                       break;
-                       }
-                       nlink->tosock= BLI_findlink(&link->tonode->new_node->inputs, a);
-               }
+       /* socket definition for group usage */
+       BLI_duplicatelist(&newtree->inputs, &ntree->inputs);
+       for(gsock= newtree->inputs.first, oldgsock= ntree->inputs.first; gsock; gsock=gsock->next, oldgsock=oldgsock->next) {
+               oldgsock->new_sock= gsock;
+               gsock->groupsock = (oldgsock->groupsock ? oldgsock->groupsock->new_sock : NULL);
        }
        
-       /* 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);
-               }
+       BLI_duplicatelist(&newtree->outputs, &ntree->outputs);
+       for(gsock= newtree->outputs.first, oldgsock= ntree->outputs.first; gsock; gsock=gsock->next, oldgsock=oldgsock->next) {
+               oldgsock->new_sock= gsock;
+               gsock->groupsock = (oldgsock->groupsock ? oldgsock->groupsock->new_sock : NULL);
+       }
+
+       /* copy links */
+       BLI_duplicatelist(&newtree->links, &ntree->links);
+       for(link= newtree->links.first; link; link= link->next) {
+               link->fromnode = (link->fromnode ? link->fromnode->new_node : NULL);
+               link->fromsock = (link->fromsock ? link->fromsock->new_sock : NULL);
+               link->tonode = (link->tonode ? link->tonode->new_node : NULL);
+               link->tosock = (link->tosock ? link->tosock->new_sock : NULL);
+               /* update the link socket's pointer */
+               if (link->tosock)
+                       link->tosock->link = link;
        }
-       /* weird this is required... there seem to be link pointers wrong still? */
-       /* anyhoo, doing this solves crashes on copying entire tree (copy scene) and delete nodes */
-       ntreeSolveOrder(newtree);
 
        return newtree;
 }
@@ -1182,12 +1267,11 @@ static void node_init_preview(bNode *node, int xsize, int ysize)
        }
        
        if(node->preview->rect==NULL) {
-               node->preview->rect= MEM_callocN(4*xsize + xsize*ysize*sizeof(float)*4, "node preview rect");
+               node->preview->rect= MEM_callocN(4*xsize + xsize*ysize*sizeof(char)*4, "node preview rect");
                node->preview->xsize= xsize;
                node->preview->ysize= ysize;
        }
-       else
-               memset(node->preview->rect, 0, 4*xsize + xsize*ysize*sizeof(float)*4);
+       /* no clear, makes nicer previews */
 }
 
 void ntreeInitPreview(bNodeTree *ntree, int xsize, int ysize)
@@ -1237,12 +1321,18 @@ void nodeAddToPreview(bNode *node, float *col, int x, int y)
                if(x>=0 && y>=0) {
                        if(x<preview->xsize && y<preview->ysize) {
                                unsigned char *tar= preview->rect+ 4*((preview->xsize*y) + x);
-                               //if(tar[0]==0.0f) {
-                               tar[0]= FTOCHAR(col[0]);
-                               tar[1]= FTOCHAR(col[1]);
-                               tar[2]= FTOCHAR(col[2]);
+                               
+                               if(TRUE) {
+                                       tar[0]= FTOCHAR(linearrgb_to_srgb(col[0]));
+                                       tar[1]= FTOCHAR(linearrgb_to_srgb(col[1]));
+                                       tar[2]= FTOCHAR(linearrgb_to_srgb(col[2]));
+                               }
+                               else {
+                                       tar[0]= FTOCHAR(col[0]);
+                                       tar[1]= FTOCHAR(col[1]);
+                                       tar[2]= FTOCHAR(col[2]);
+                               }
                                tar[3]= FTOCHAR(col[3]);
-                               //}
                        }
                        //else printf("prv out bound x y %d %d\n", x, y);
                }
@@ -1265,7 +1355,8 @@ void nodeUnlinkNode(bNodeTree *ntree, bNode *node)
                
                if(link->fromnode==node) {
                        lb= &node->outputs;
-                       NodeTagChanged(ntree, link->tonode);
+                       if (link->tonode)
+                               NodeTagChanged(ntree, link->tonode);
                }
                else if(link->tonode==node)
                        lb= &node->inputs;
@@ -1335,13 +1426,8 @@ void ntreeFreeTree(bNodeTree *ntree)
                nodeFreeNode(ntree, node);
        }
        
-       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);
-       }
+       BLI_freelistN(&ntree->inputs);
+       BLI_freelistN(&ntree->outputs);
 }
 
 void ntreeFreeCache(bNodeTree *ntree)
@@ -1367,9 +1453,9 @@ void ntreeMakeLocal(bNodeTree *ntree)
        
        if(ntree->id.lib==NULL) return;
        if(ntree->id.us==1) {
-               ntree->id.lib= 0;
+               ntree->id.lib= NULL;
                ntree->id.flag= LIB_LOCAL;
-               new_id(0, (ID *)ntree, 0);
+               new_id(NULL, (ID *)ntree, NULL);
                return;
        }
        
@@ -1427,11 +1513,11 @@ void ntreeMakeLocal(bNodeTree *ntree)
        if(local && lib==0) {
                ntree->id.lib= NULL;
                ntree->id.flag= LIB_LOCAL;
-               new_id(0, (ID *)ntree, 0);
+               new_id(NULL, (ID *)ntree, NULL);
        }
        else if(local && lib) {
                /* this is the mixed case, we copy the tree and assign it to local users */
-               bNodeTree *newtree= ntreeCopyTree(ntree, 0);
+               bNodeTree *newtree= ntreeCopyTree(ntree);
                
                newtree->id.us= 0;
                
@@ -1675,7 +1761,7 @@ static int node_recurs_check(bNode *node, bNode ***nsort, int level)
                if(sock->link) {
                        has_inputlinks= 1;
                        fromnode= sock->link->fromnode;
-                       if(fromnode->done==0) {
+                       if(fromnode && fromnode->done==0) {
                                fromnode->level= node_recurs_check(fromnode, nsort, level);
                        }
                }
@@ -1684,10 +1770,63 @@ static int node_recurs_check(bNode *node, bNode ***nsort, int level)
        **nsort= node;
        (*nsort)++;
        
-       if(has_inputlinks)
-               return level;
-       else 
-               return 0xFFF;
+       if(has_inputlinks)
+               return level;
+       else 
+               return 0xFFF;
+}
+
+
+static void ntreeSetOutput(bNodeTree *ntree)
+{
+       bNode *node;
+
+       /* find the active outputs, might become tree type dependant handler */
+       for(node= ntree->nodes.first; node; node= node->next) {
+               if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) {
+                       bNode *tnode;
+                       int output= 0;
+                       
+                       /* we need a check for which output node should be tagged like this, below an exception */
+                       if(node->type==CMP_NODE_OUTPUT_FILE)
+                          continue;
+                          
+                       /* there is more types having output class, each one is checked */
+                       for(tnode= ntree->nodes.first; tnode; tnode= tnode->next) {
+                               if(tnode->typeinfo->nclass==NODE_CLASS_OUTPUT) {
+                                       
+                                       if(ntree->type==NTREE_COMPOSIT) {
+                                                       
+                                               /* same type, exception for viewer */
+                                               if(tnode->type==node->type ||
+                                                  (ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER) &&
+                                                       ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))) {
+                                                       if(tnode->flag & NODE_DO_OUTPUT) {
+                                                               output++;
+                                                               if(output>1)
+                                                                       tnode->flag &= ~NODE_DO_OUTPUT;
+                                                       }
+                                               }
+                                       }
+                                       else {
+                                               /* same type */
+                                               if(tnode->type==node->type) {
+                                                       if(tnode->flag & NODE_DO_OUTPUT) {
+                                                               output++;
+                                                               if(output>1)
+                                                                       tnode->flag &= ~NODE_DO_OUTPUT;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       if(output==0)
+                               node->flag |= NODE_DO_OUTPUT;
+               }
+       }
+       
+       /* here we could recursively set which nodes have to be done,
+               might be different for editor or for "real" use... */
 }
 
 void ntreeSolveOrder(bNodeTree *ntree)
@@ -1708,6 +1847,9 @@ void ntreeSolveOrder(bNodeTree *ntree)
                for(sock= node->inputs.first; sock; sock= sock->next)
                        sock->link= NULL;
        }
+       /* clear group socket links */
+       for(sock= ntree->outputs.first; sock; sock= sock->next)
+               sock->link= NULL;
        if(totnode==0)
                return;
        
@@ -1738,38 +1880,11 @@ void ntreeSolveOrder(bNodeTree *ntree)
        }
        
        MEM_freeN(nodesort);
-       
-       /* find the active outputs, might become tree type dependant handler */
-       for(node= ntree->nodes.first; node; node= node->next) {
-               if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) {
-                       bNode *tnode;
-                       int output= 0;
-                       
-                       /* we need a check for which output node should be tagged like this, below an exception */
-                       if(node->type==CMP_NODE_OUTPUT_FILE)
-                          continue;
-                          
-                       /* there is more types having output class, each one is checked */
-                       for(tnode= ntree->nodes.first; tnode; tnode= tnode->next) {
-                               if(tnode->typeinfo->nclass==NODE_CLASS_OUTPUT) {
-                                       if(tnode->type==node->type) {
-                                               if(tnode->flag & NODE_DO_OUTPUT) {
-                                                       output++;
-                                                       if(output>1)
-                                                               tnode->flag &= ~NODE_DO_OUTPUT;
-                                               }
-                                       }
-                               }
-                       }
-                       if(output==0)
-                               node->flag |= NODE_DO_OUTPUT;
-               }
-       }
-       
-       /* here we could recursively set which nodes have to be done,
-               might be different for editor or for "real" use... */
+
+       ntreeSetOutput(ntree);
 }
 
+
 /* Should be callback! */
 /* Do not call execs here */
 void NodeTagChanged(bNodeTree *ntree, bNode *node)
@@ -1787,51 +1902,65 @@ void NodeTagChanged(bNodeTree *ntree, bNode *node)
        }
 }
 
-void NodeTagIDChanged(bNodeTree *ntree, ID *id)
+int NodeTagIDChanged(bNodeTree *ntree, ID *id)
 {
-       if(id==NULL)
-               return;
+       int change = FALSE;
+
+       if(ELEM(NULL, id, ntree))
+               return change;
        
        if(ntree->type==NTREE_COMPOSIT) {
                bNode *node;
                
-               for(node= ntree->nodes.first; node; node= node->next)
-                       if(node->id==id)
+               for(node= ntree->nodes.first; node; node= node->next) {
+                       if(node->id==id) {
+                               change= TRUE;
                                NodeTagChanged(ntree, node);
+                       }
+               }
        }
+       
+       return change;
 }
 
 
 
 /* ******************* executing ************* */
 
+/* for a given socket, find the actual stack entry */
+static bNodeStack *get_socket_stack(bNodeStack *stack, bNodeSocket *sock, bNodeStack **gin)
+{
+       switch (sock->stack_type) {
+       case SOCK_STACK_LOCAL:
+               return stack + sock->stack_index;
+       case SOCK_STACK_EXTERN:
+               return (gin ? gin[sock->stack_index] : NULL);
+       case SOCK_STACK_CONST:
+               return sock->stack_ptr;
+       }
+       return NULL;
+}
+
 /* see notes at ntreeBeginExecTree */
-static void group_node_get_stack(bNode *node, bNodeStack *stack, bNodeStack **in, bNodeStack **out, bNodeStack **gin, bNodeStack **gout)
+static void node_get_stack(bNode *node, bNodeStack *stack, bNodeStack **in, bNodeStack **out, bNodeStack **gin)
 {
        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;
+       if (in) {
+               for(sock= node->inputs.first; sock; sock= sock->next) {
+                       *(in++) = get_socket_stack(stack, sock, gin);
                }
-               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];
+       if (out) {
+               for(sock= node->outputs.first; sock; sock= sock->next) {
+                       *(out++) = get_socket_stack(stack, sock, gin);
+               }
        }
 }
 
-static void node_group_execute(bNodeStack *stack, void *data, bNode *gnode, bNodeStack **in, bNodeStack **out)
+static void node_group_execute(bNodeStack *stack, void *data, bNode *gnode, bNodeStack **in)
 {
        bNode *node;
        bNodeTree *ntree= (bNodeTree *)gnode->id;
@@ -1844,7 +1973,7 @@ static void node_group_execute(bNodeStack *stack, void *data, bNode *gnode, bNod
                
        for(node= ntree->nodes.first; node; node= node->next) {
                if(node->typeinfo->execfunc) {
-                       group_node_get_stack(node, stack, nsin, nsout, in, out);
+                       node_get_stack(node, stack, nsin, nsout, in);
                        
                        /* for groups, only execute outputs for edited group */
                        if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) {
@@ -1856,19 +1985,27 @@ static void node_group_execute(bNodeStack *stack, void *data, bNode *gnode, bNod
                }
        }
        
-       /* free internal group output nodes */
-       if(ntree->type==NTREE_COMPOSIT) {
-               for(node= ntree->nodes.first; node; node= node->next) {
-                       if(node->typeinfo->execfunc) {
-                               bNodeSocket *sock;
-                               
-                               for(sock= node->outputs.first; sock; sock= sock->next) {
-                                       if(sock->intern) {
-                                               bNodeStack *ns= stack + sock->stack_index;
-                                               if(ns->data) {
-                                                       free_compbuf(ns->data);
-                                                       ns->data= NULL;
-                                               }
+       /* free internal buffers */
+       if (ntree->type==NTREE_COMPOSIT) {
+               bNodeSocket *sock;
+               bNodeStack *ns;
+               for (sock=ntree->outputs.first; sock; sock=sock->next) {
+                       /* use the hasoutput flag to tag external sockets */
+                       if (sock->stack_type==SOCK_STACK_LOCAL) {
+                               ns= get_socket_stack(stack, sock, in);
+                               ns->hasoutput = 0;
+                       }
+               }
+               /* now free all stacks that are not used from outside */
+               for (node=ntree->nodes.first; node; node=node->next) {
+                       for (sock=node->outputs.first; sock; sock=sock->next) {
+                               if (sock->stack_type==SOCK_STACK_LOCAL ) {
+                                       ns= get_socket_stack(stack, sock, in);
+                                       if (ns->hasoutput!=0 && ns->data) {
+                                               free_compbuf(ns->data);
+                                               ns->data = NULL;
+                                               /* reset the flag */
+                                               ns->hasoutput = 1;
                                        }
                                }
                        }
@@ -1876,37 +2013,134 @@ static void node_group_execute(bNodeStack *stack, void *data, bNode *gnode, bNod
        }
 }
 
+static int set_stack_indexes_default(bNode *node, int index)
+{
+       bNodeSocket *sock;
+       
+       for (sock=node->inputs.first; sock; sock=sock->next) {
+               if (sock->link && sock->link->fromsock) {
+                       sock->stack_type = sock->link->fromsock->stack_type;
+                       sock->stack_index = sock->link->fromsock->stack_index;
+                       sock->stack_ptr = sock->link->fromsock->stack_ptr;
+               }
+               else {
+                       sock->stack_type = SOCK_STACK_CONST;
+                       sock->stack_index = -1;
+                       sock->stack_ptr = &sock->ns;
+               }
+       }
+       
+       for (sock=node->outputs.first; sock; sock=sock->next) {
+               sock->stack_type = SOCK_STACK_LOCAL;
+               sock->stack_index = index++;
+               sock->stack_ptr = NULL;
+       }
+       
+       return index;
+}
+
+static int ntree_begin_exec_tree(bNodeTree *ntree);
+static int set_stack_indexes_group(bNode *node, int index)
+{
+       bNodeTree *ngroup= (bNodeTree*)node->id;
+       bNodeSocket *sock;
+       
+       if((ngroup->init & NTREE_TYPE_INIT)==0)
+               ntreeInitTypes(ngroup);
+       
+       node->stack_index = index;
+       index += ntree_begin_exec_tree(ngroup);
+       
+       for (sock=node->inputs.first; sock; sock=sock->next) {
+               if (sock->link && sock->link->fromsock) {
+                       sock->stack_type = sock->link->fromsock->stack_type;
+                       sock->stack_index = sock->link->fromsock->stack_index;
+                       sock->stack_ptr = sock->link->fromsock->stack_ptr;
+               }
+               else {
+                       sock->stack_type = SOCK_STACK_CONST;
+                       sock->stack_index = -1;
+                       sock->stack_ptr = &sock->ns;
+               }
+       }
+       
+       /* identify group node outputs from internal group sockets */
+       for(sock= node->outputs.first; sock; sock= sock->next) {
+               if (sock->groupsock) {
+                       bNodeSocket *insock, *gsock = sock->groupsock;
+                       switch (gsock->stack_type) {
+                       case SOCK_STACK_EXTERN:
+                               /* extern stack is resolved for this group node instance */
+                               insock= find_group_node_input(node, gsock->link->fromsock);
+                               sock->stack_type = insock->stack_type;
+                               sock->stack_index = insock->stack_index;
+                               sock->stack_ptr = insock->stack_ptr;
+                               break;
+                       case SOCK_STACK_LOCAL:
+                               sock->stack_type = SOCK_STACK_LOCAL;
+                               /* local stack index must be offset by group node instance */
+                               sock->stack_index = gsock->stack_index + node->stack_index;
+                               sock->stack_ptr = NULL;
+                               break;
+                       case SOCK_STACK_CONST:
+                               sock->stack_type = SOCK_STACK_CONST;
+                               sock->stack_index = -1;
+                               sock->stack_ptr = gsock->stack_ptr;
+                               break;
+                       }
+               }
+               else {
+                       sock->stack_type = SOCK_STACK_LOCAL;
+                       sock->stack_index = index++;
+                       sock->stack_ptr = NULL;
+               }
+       }
+       
+       return index;
+}
+
 /* recursively called for groups */
 /* we set all trees on own local indices, but put a total counter
    in the groups, so each instance of a group has own stack */
 static int ntree_begin_exec_tree(bNodeTree *ntree)
 {
        bNode *node;
-       bNodeSocket *sock;
-       int index= 0, index_in= 0, index_out= 0;
+       bNodeSocket *gsock;
+       int index= 0, i;
        
        if((ntree->init & NTREE_TYPE_INIT)==0)
                ntreeInitTypes(ntree);
        
+       /* group inputs are numbered 0..totinputs, so external stack can easily be addressed */
+       i = 0;
+       for(gsock=ntree->inputs.first; gsock; gsock = gsock->next) {
+               gsock->stack_type = SOCK_STACK_EXTERN;
+               gsock->stack_index = i++;
+               gsock->stack_ptr = NULL;
+       }
+       
        /* 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++;
+               /* XXX can this be done by a generic one-for-all function?
+                * otherwise should use node-type callback.
+                */
+               if(node->type==NODE_GROUP)
+                       index = set_stack_indexes_group(node, index);
+               else
+                       index = set_stack_indexes_default(node, index);
+       }
+       
+       /* group outputs */
+       for(gsock=ntree->outputs.first; gsock; gsock = gsock->next) {
+               if (gsock->link && gsock->link->fromsock) {
+                       gsock->stack_type = gsock->link->fromsock->stack_type;
+                       gsock->stack_index = gsock->link->fromsock->stack_index;
+                       gsock->stack_ptr = gsock->link->fromsock->stack_ptr;
                }
-               
-               if(node->type==NODE_GROUP) {
-                       if(node->id) {
-                               node->stack_index= index;
-                               index+= ntree_begin_exec_tree((bNodeTree *)node->id);
-                       }
+               else {
+                       gsock->stack_type = SOCK_STACK_CONST;
+                       gsock->stack_index = -1;
+                       gsock->stack_ptr = &gsock->ns;
                }
        }
        
@@ -1914,7 +2148,7 @@ static int ntree_begin_exec_tree(bNodeTree *ntree)
 }
 
 /* copy socket compbufs to stack, initialize usage of curve nodes */
-static void composit_begin_exec(bNodeTree *ntree, int is_group)
+static void composit_begin_exec(bNodeTree *ntree, bNodeStack *stack)
 {
        bNode *node;
        bNodeSocket *sock;
@@ -1924,16 +2158,14 @@ static void composit_begin_exec(bNodeTree *ntree, int is_group)
                /* initialize needed for groups */
                node->exec= 0;  
                
-               if(is_group==0) {
-                       for(sock= node->outputs.first; sock; sock= sock->next) {
-                               bNodeStack *ns= ntree->stack + sock->stack_index;
-                               
-                               if(sock->ns.data) {
-                                       ns->data= sock->ns.data;
-                                       sock->ns.data= NULL;
-                               }
+               for(sock= node->outputs.first; sock; sock= sock->next) {
+                       bNodeStack *ns= get_socket_stack(stack, sock, NULL);
+                       if(ns && sock->ns.data) {
+                               ns->data= sock->ns.data;
+                               sock->ns.data= NULL;
                        }
                }
+               
                /* cannot initialize them while using in threads */
                if(ELEM4(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT)) {
                        curvemapping_initialize(node->storage);
@@ -1941,75 +2173,60 @@ static void composit_begin_exec(bNodeTree *ntree, int is_group)
                                curvemapping_premultiply(node->storage, 0);
                }
                if(node->type==NODE_GROUP)
-                       composit_begin_exec((bNodeTree *)node->id, 1);
+                       composit_begin_exec((bNodeTree *)node->id, stack + node->stack_index);
 
        }
 }
 
 /* copy stack compbufs to sockets */
-static void composit_end_exec(bNodeTree *ntree, int is_group)
+static void composit_end_exec(bNodeTree *ntree, bNodeStack *stack)
 {
-       extern void print_compbuf(char *str, struct CompBuf *cbuf);
        bNode *node;
        bNodeStack *ns;
-       int a;
 
        for(node= ntree->nodes.first; node; node= node->next) {
-               if(is_group==0) {
-                       bNodeSocket *sock;
+               bNodeSocket *sock;
                
-                       for(sock= node->outputs.first; sock; sock= sock->next) {
-                               ns= ntree->stack + sock->stack_index;
-                               if(ns->data) {
-                                       sock->ns.data= ns->data;
-                                       ns->data= NULL;
-                               }
+               for(sock= node->outputs.first; sock; sock= sock->next) {
+                       ns = get_socket_stack(stack, sock, NULL);
+                       if(ns && ns->data) {
+                               sock->ns.data= ns->data;
+                               ns->data= NULL;
                        }
                }
+               
                if(node->type==CMP_NODE_CURVE_RGB)
                        curvemapping_premultiply(node->storage, 1);
                
                if(node->type==NODE_GROUP)
-                       composit_end_exec((bNodeTree *)node->id, 1);
+                       composit_end_exec((bNodeTree *)node->id, stack + node->stack_index);
 
                node->need_exec= 0;
        }
-       
-       if(is_group==0) {
-               /* internally, group buffers are not stored */
-               for(ns= ntree->stack, a=0; a<ntree->stacksize; a++, ns++) {
-                       if(ns->data) {
-                               printf("freed leftover buffer from stack\n");
-                               free_compbuf(ns->data);
-                               ns->data= NULL;
-                       }
-               }
-       }
 }
 
-static void group_tag_used_outputs(bNode *gnode, bNodeStack *stack)
+static void group_tag_used_outputs(bNode *gnode, bNodeStack *stack, bNodeStack **gin)
 {
        bNodeTree *ntree= (bNodeTree *)gnode->id;
        bNode *node;
+       bNodeSocket *sock;
        
        stack+= gnode->stack_index;
        
        for(node= ntree->nodes.first; node; node= node->next) {
                if(node->typeinfo->execfunc) {
-                       bNodeSocket *sock;
-                       
                        for(sock= node->inputs.first; sock; sock= sock->next) {
-                               if(sock->intern) {
-                                       if(sock->link) {
-                                               bNodeStack *ns= stack + sock->link->fromsock->stack_index;
-                                               ns->hasoutput= 1;
-                                               ns->sockettype= sock->link->fromsock->type;
-                                       }
-                                       else
-                                               sock->ns.sockettype= sock->type;
-                               }
+                               bNodeStack *ns = get_socket_stack(stack, sock, gin);
+                               ns->hasoutput= 1;
                        }
                }
+               
+               /* set stack types (for local stack entries) */
+               for(sock= node->outputs.first; sock; sock= sock->next) {
+                       bNodeStack *ns = get_socket_stack(stack, sock, NULL);
+                       if (ns)
+                               ns->sockettype = sock->type;
+               }
        }
 }
 
@@ -2067,6 +2284,8 @@ static void tex_end_exec(bNodeTree *ntree)
 
 void ntreeBeginExecTree(bNodeTree *ntree)
 {
+       bNodeStack *nsin[MAX_SOCKET];   /* arbitrary... watch this */
+       
        /* let's make it sure */
        if(ntree->init & NTREE_EXEC_INIT)
                return;
@@ -2098,13 +2317,9 @@ void ntreeBeginExecTree(bNodeTree *ntree)
                                node->need_exec= 1;
 
                        for(sock= node->inputs.first; sock; sock= sock->next) {
-                               if(sock->link) {
-                                       ns= ntree->stack + sock->link->fromsock->stack_index;
-                                       ns->hasoutput= 1;
-                                       ns->sockettype= sock->link->fromsock->type;
-                               }
-                               else
-                                       sock->ns.sockettype= sock->type;
+                               ns = get_socket_stack(ntree->stack, sock, NULL);
+                               if (ns)
+                                       ns->hasoutput = 1;
                                
                                if(sock->link) {
                                        bNodeLink *link= sock->link;
@@ -2118,13 +2333,21 @@ void ntreeBeginExecTree(bNodeTree *ntree)
                                }
                        }
                        
-                       if(node->type==NODE_GROUP && node->id)
-                               group_tag_used_outputs(node, ntree->stack);
+                       /* set stack types (for local stack entries) */
+                       for(sock= node->outputs.first; sock; sock= sock->next) {
+                               ns = get_socket_stack(ntree->stack, sock, NULL);
+                               if (ns)
+                                       ns->sockettype = sock->type;
+                       }
                        
+                       if(node->type==NODE_GROUP && node->id) {
+                               node_get_stack(node, ntree->stack, nsin, NULL, NULL);
+                               group_tag_used_outputs(node, ntree->stack, nsin);
+                       }
                }
                
                if(ntree->type==NTREE_COMPOSIT)
-                       composit_begin_exec(ntree, 0);
+                       composit_begin_exec(ntree, ntree->stack);
        }
        
        ntree->init |= NTREE_EXEC_INIT;
@@ -2132,14 +2355,24 @@ void ntreeBeginExecTree(bNodeTree *ntree)
 
 void ntreeEndExecTree(bNodeTree *ntree)
 {
+       bNodeStack *ns;
        
        if(ntree->init & NTREE_EXEC_INIT) {
                bNodeThreadStack *nts;
                int a;
                
                /* another callback candidate! */
-               if(ntree->type==NTREE_COMPOSIT)
-                       composit_end_exec(ntree, 0);
+               if(ntree->type==NTREE_COMPOSIT) {
+                       composit_end_exec(ntree, ntree->stack);
+                       
+                       for(ns= ntree->stack, a=0; a<ntree->stacksize; a++, ns++) {
+                               if(ns->data) {
+                                       printf("freed leftover buffer from stack\n");
+                                       free_compbuf(ns->data);
+                                       ns->data= NULL;
+                               }
+                       }
+               }
                else if(ntree->type==NTREE_TEXTURE)
                        tex_end_exec(ntree);
                
@@ -2163,23 +2396,6 @@ void ntreeEndExecTree(bNodeTree *ntree)
        }
 }
 
-static void node_get_stack(bNode *node, bNodeStack *stack, bNodeStack **in, bNodeStack **out)
-{
-       bNodeSocket *sock;
-       
-       /* build pointer stack */
-       for(sock= node->inputs.first; sock; sock= sock->next) {
-               if(sock->link)
-                       *(in++)= stack + sock->link->fromsock->stack_index;
-               else
-                       *(in++)= &sock->ns;
-       }
-       
-       for(sock= node->outputs.first; sock; sock= sock->next) {
-               *(out++)= stack + sock->stack_index;
-       }
-}
-
 /* nodes are presorted, so exec is in order of list */
 void ntreeExecTree(bNodeTree *ntree, void *callerdata, int thread)
 {
@@ -2192,7 +2408,7 @@ void ntreeExecTree(bNodeTree *ntree, void *callerdata, int thread)
        /* only when initialized */
        if((ntree->init & NTREE_EXEC_INIT)==0)
                ntreeBeginExecTree(ntree);
-               
+       
        /* composite does 1 node per thread, so no multiple stacks needed */
        if(ntree->type==NTREE_COMPOSIT) {
                stack= ntree->stack;
@@ -2205,12 +2421,12 @@ void ntreeExecTree(bNodeTree *ntree, void *callerdata, int thread)
        for(node= ntree->nodes.first; node; node= node->next) {
                if(node->need_exec) {
                        if(node->typeinfo->execfunc) {
-                               node_get_stack(node, stack, nsin, nsout);
+                               node_get_stack(node, stack, nsin, nsout, NULL);
                                node->typeinfo->execfunc(callerdata, node, nsin, nsout);
                        }
                        else if(node->type==NODE_GROUP && node->id) {
-                               node_get_stack(node, stack, nsin, nsout);
-                               node_group_execute(stack, callerdata, node, nsin, nsout); 
+                               node_get_stack(node, stack, nsin, NULL, NULL);
+                               node_group_execute(stack, callerdata, node, nsin);
                        }
                }
        }
@@ -2256,7 +2472,7 @@ static void *exec_composite_node(void *node_v)
        bNode *node= node_v;
        ThreadData *thd= (ThreadData *)node->threaddata;
        
-       node_get_stack(node, thd->stack, nsin, nsout);
+       node_get_stack(node, thd->stack, nsin, nsout, NULL);
        
        if((node->flag & NODE_MUTED) && (!node_only_value(node))) {
                /* viewers we execute, for feedback to user */
@@ -2269,11 +2485,11 @@ static void *exec_composite_node(void *node_v)
                node->typeinfo->execfunc(thd->rd, node, nsin, nsout);
        }
        else if(node->type==NODE_GROUP && node->id) {
-               node_group_execute(thd->stack, thd->rd, node, nsin, nsout); 
+               node_group_execute(thd->stack, thd->rd, node, nsin); 
        }
        
        node->exec |= NODE_READY;
-       return 0;
+       return NULL;
 }
 
 /* return total of executable nodes, for timecursor */
@@ -2297,7 +2513,7 @@ static int setExecutableNodes(bNodeTree *ntree, ThreadData *thd)
        for(node= ntree->nodes.first; node; node= node->next) {
                int a;
                
-               node_get_stack(node, thd->stack, nsin, nsout);
+               node_get_stack(node, thd->stack, nsin, nsout, NULL);
                
                /* test the outputs */
                /* skip value-only nodes (should be in type!) */
@@ -2362,7 +2578,7 @@ static int setExecutableNodes(bNodeTree *ntree, ThreadData *thd)
                for(node= ntree->nodes.first; node; node= node->next) {
                        if(node->need_exec==0 && node_only_value(node)) {
                                if(node->typeinfo->execfunc) {
-                                       node_get_stack(node, thd->stack, nsin, nsout);
+                                       node_get_stack(node, thd->stack, nsin, nsout, NULL);
                                        node->typeinfo->execfunc(thd->rd, node, nsin, nsout);
                                }
                        }
@@ -2400,8 +2616,8 @@ static void freeExecutableNode(bNodeTree *ntree)
        for(node= ntree->nodes.first; node; node= node->next) {
                if(node->exec & NODE_FREEBUFS) {
                        for(sock= node->outputs.first; sock; sock= sock->next) {
-                               bNodeStack *ns= ntree->stack + sock->stack_index;
-                               if(ns->data) {
+                               bNodeStack *ns= get_socket_stack(ntree->stack, sock, NULL);
+                               if(ns && ns->data) {
                                        free_compbuf(ns->data);
                                        ns->data= NULL;
                                        // printf("freed buf node %s \n", node->name);
@@ -2421,7 +2637,7 @@ static bNode *getExecutableNode(bNodeTree *ntree)
                        
                        /* input sockets should be ready */
                        for(sock= node->inputs.first; sock; sock= sock->next) {
-                               if(sock->link)
+                               if(sock->link && sock->link->fromnode)
                                        if((sock->link->fromnode->exec & NODE_READY)==0)
                                                break;
                        }
@@ -2432,6 +2648,25 @@ static bNode *getExecutableNode(bNodeTree *ntree)
        return NULL;
 }
 
+/* check if texture nodes need exec or end */
+static  void ntree_composite_texnode(bNodeTree *ntree, int init)
+{
+       bNode *node;
+       
+       for(node= ntree->nodes.first; node; node= node->next) {
+               if(node->type==CMP_NODE_TEXTURE && node->id) {
+                       Tex *tex= (Tex *)node->id;
+                       if(tex->nodetree && tex->use_nodes) {
+                               /* has internal flag to detect it only does it once */
+                               if(init)
+                                       ntreeBeginExecTree(tex->nodetree); 
+                               else
+                                       ntreeEndExecTree(tex->nodetree);
+                       }
+               }
+       }
+
+}
 
 /* optimized tree execute test for compositing */
 void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview)
@@ -2447,6 +2682,7 @@ void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview)
                ntreeInitPreview(ntree, 0, 0);
        
        ntreeBeginExecTree(ntree);
+       ntree_composite_texnode(ntree, 1);
        
        /* prevent unlucky accidents */
        if(G.background)
@@ -2459,6 +2695,9 @@ void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview)
        /* fixed seed, for example noise texture */
        BLI_srandom(rd->cfra);
 
+       /* ensures only a single output node is enabled */
+       ntreeSetOutput(ntree);
+
        /* sets need_exec tags in nodes */
        curnode = totnode= setExecutableNodes(ntree, &thdata);
 
@@ -2469,7 +2708,6 @@ void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview)
                if(BLI_available_threads(&threads)) {
                        node= getExecutableNode(ntree);
                        if(node) {
-                               
                                if(ntree->progress && totnode)
                                        ntree->progress(ntree->prh, (1.0 - curnode/(float)totnode));
                                if(ntree->stats_draw) {
@@ -2544,7 +2782,7 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
        }
 
        /* node copy func */
-       ltree= ntreeCopyTree(ntree, 0);
+       ltree= ntreeCopyTree(ntree);
 
        if(adt) {
                AnimData *ladt= BKE_animdata_from_id(&ltree->id);
@@ -2557,9 +2795,10 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
                
        }
        /* end animdata uglyness */
-       
-       /* move over the compbufs */
-       /* right after ntreeCopyTree() oldsock pointers are valid */
+
+       /* ensures only a single output node is enabled */
+       ntreeSetOutput(ntree);
+
        for(node= ntree->nodes.first; node; node= node->next) {
                
                /* store new_node pointer to original */
@@ -2567,22 +2806,27 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
                /* ensure new user input gets handled ok */
                node->need_exec= 0;
                
-               if(ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
-                       if(node->id) {
-                               if(node->flag & NODE_DO_OUTPUT)
-                                       node->new_node->id= (ID *)copy_image((Image *)node->id);
-                               else
-                                       node->new_node->id= NULL;
-                       }
-               }
-               
-               for(sock= node->outputs.first; sock; sock= sock->next) {
+               if(ntree->type==NTREE_COMPOSIT) {
+                       /* move over the compbufs */
+                       /* right after ntreeCopyTree() oldsock pointers are valid */
                        
-                       sock->new_sock->ns.data= sock->ns.data;
-                       compbuf_set_node(sock->new_sock->ns.data, node->new_node);
+                       if(ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
+                               if(node->id) {
+                                       if(node->flag & NODE_DO_OUTPUT)
+                                               node->new_node->id= (ID *)copy_image((Image *)node->id);
+                                       else
+                                               node->new_node->id= NULL;
+                               }
+                       }
                        
-                       sock->ns.data= NULL;
-                       sock->new_sock->new_sock= sock;
+                       for(sock= node->outputs.first; sock; sock= sock->next) {
+                               
+                               sock->new_sock->ns.data= sock->ns.data;
+                               compbuf_set_node(sock->new_sock->ns.data, node->new_node);
+                               
+                               sock->ns.data= NULL;
+                               sock->new_sock->new_sock= sock;
+                       }
                }
        }
        
@@ -2610,19 +2854,38 @@ static int outsocket_exists(bNode *node, bNodeSocket *testsock)
 
 /* sync local composite with real tree */
 /* local composite is supposed to be running, be careful moving previews! */
+/* is called by jobs manager, outside threads, so it doesnt happen during draw */
 void ntreeLocalSync(bNodeTree *localtree, bNodeTree *ntree)
 {
        bNode *lnode;
        
-       /* move over the compbufs and previews */
-       for(lnode= localtree->nodes.first; lnode; lnode= lnode->next) {
-               if( (lnode->exec & NODE_READY) && !(lnode->exec & NODE_SKIPPED) ) {
+       if(ntree->type==NTREE_COMPOSIT) {
+               /* move over the compbufs and previews */
+               for(lnode= localtree->nodes.first; lnode; lnode= lnode->next) {
+                       if( (lnode->exec & NODE_READY) && !(lnode->exec & NODE_SKIPPED) ) {
+                               if(node_exists(ntree, lnode->new_node)) {
+                                       
+                                       if(lnode->preview && lnode->preview->rect) {
+                                               node_free_preview(lnode->new_node);
+                                               lnode->new_node->preview= lnode->preview;
+                                               lnode->preview= NULL;
+                                       }
+                               }
+                       }
+               }
+       }
+       else if(ntree->type==NTREE_SHADER) {
+               /* copy over contents of previews */
+               for(lnode= localtree->nodes.first; lnode; lnode= lnode->next) {
                        if(node_exists(ntree, lnode->new_node)) {
+                               bNode *node= lnode->new_node;
                                
-                               if(lnode->preview && lnode->preview->rect) {
-                                       node_free_preview(lnode->new_node);
-                                       lnode->new_node->preview= lnode->preview;
-                                       lnode->preview= NULL;
+                               if(node->preview && node->preview->rect) {
+                                       if(lnode->preview && lnode->preview->rect) {
+                                               int xsize= node->preview->xsize;
+                                               int ysize= node->preview->ysize;
+                                               memcpy(node->preview->rect, lnode->preview->rect, 4*xsize + xsize*ysize*sizeof(char)*4);
+                                       }
                                }
                        }
                }
@@ -2693,7 +2956,7 @@ static void gpu_from_node_stack(ListBase *sockets, bNodeStack **ns, GPUNodeStack
 
                gs[i].name = "";
                gs[i].hasinput= ns[i]->hasinput && ns[i]->data;
-               gs[i].hasoutput= ns[i]->hasinput && ns[i]->data;
+               gs[i].hasoutput= ns[i]->hasoutput && ns[i]->data;
                gs[i].sockettype= ns[i]->sockettype;
        }
 
@@ -2707,13 +2970,11 @@ static void data_from_gpu_stack(ListBase *sockets, bNodeStack **ns, GPUNodeStack
 
        for (sock=sockets->first, i=0; sock; sock=sock->next, i++) {
                ns[i]->data= gs[i].link;
-               ns[i]->hasinput= gs[i].hasinput && gs[i].link;
-               ns[i]->hasoutput= gs[i].hasoutput;
                ns[i]->sockettype= gs[i].sockettype;
        }
 }
 
-static void gpu_node_group_execute(bNodeStack *stack, GPUMaterial *mat, bNode *gnode, bNodeStack **in, bNodeStack **out)
+static void gpu_node_group_execute(bNodeStack *stack, GPUMaterial *mat, bNode *gnode, bNodeStack **in)
 {
        bNode *node;
        bNodeTree *ntree= (bNodeTree *)gnode->id;
@@ -2728,7 +2989,7 @@ static void gpu_node_group_execute(bNodeStack *stack, GPUMaterial *mat, bNode *g
                
        for(node= ntree->nodes.first; node; node= node->next) {
                if(node->typeinfo->gpufunc) {
-                       group_node_get_stack(node, stack, nsin, nsout, in, out);
+                       node_get_stack(node, stack, nsin, nsout, in);
 
                        doit = 0;
                        
@@ -2766,15 +3027,15 @@ void ntreeGPUMaterialNodes(bNodeTree *ntree, GPUMaterial *mat)
 
        for(node= ntree->nodes.first; node; node= node->next) {
                if(node->typeinfo->gpufunc) {
-                       node_get_stack(node, stack, nsin, nsout);
+                       node_get_stack(node, stack, nsin, nsout, NULL);
                        gpu_from_node_stack(&node->inputs, nsin, gpuin);
                        gpu_from_node_stack(&node->outputs, nsout, gpuout);
                        if(node->typeinfo->gpufunc(mat, node, gpuin, gpuout))
                                data_from_gpu_stack(&node->outputs, nsout, gpuout);
                }
                else if(node->type==NODE_GROUP && node->id) {
-                       node_get_stack(node, stack, nsin, nsout);
-                       gpu_node_group_execute(stack, mat, node, nsin, nsout);
+                       node_get_stack(node, stack, nsin, nsout, NULL);
+                       gpu_node_group_execute(stack, mat, node, nsin);
                }
        }
 
@@ -2884,6 +3145,8 @@ void ntreeCompositTagRender(Scene *curscene)
                        for(node= sce->nodetree->nodes.first; node; node= node->next) {
                                if(node->id==(ID *)curscene || node->type==CMP_NODE_COMPOSITE)
                                        NodeTagChanged(sce->nodetree, node);
+                               else if(node->type==CMP_NODE_TEXTURE) /* uses scene sizex/sizey */
+                                       NodeTagChanged(sce->nodetree, node);
                        }
                }
        }
@@ -2899,7 +3162,7 @@ static int node_animation_properties(bNodeTree *ntree, bNode *node)
        
        /* check to see if any of the node's properties have fcurves */
        RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr);
-       lb = RNA_struct_defined_properties(ptr.type);
+       lb = RNA_struct_type_properties(ptr.type);
        
        for (link=lb->first; link; link=link->next) {
                int driven, len=1, index;
@@ -2961,10 +3224,7 @@ int ntreeCompositTagAnimated(bNodeTree *ntree)
                        NodeTagChanged(ntree, node);
                        tagged= 1;
                }
-               else if(node->type==CMP_NODE_R_LAYERS) {
-                       NodeTagChanged(ntree, node);
-                       tagged= 1;
-               }
+               /* here was tag render layer, but this is called after a render, so re-composites fail */
                else if(node->type==NODE_GROUP) {
                        if( ntreeCompositTagAnimated((bNodeTree *)node->id) ) {
                                NodeTagChanged(ntree, node);
@@ -2989,6 +3249,21 @@ void ntreeCompositTagGenerators(bNodeTree *ntree)
        }
 }
 
+/* XXX after render animation system gets a refresh, this call allows composite to end clean */
+void ntreeClearTags(bNodeTree *ntree)
+{
+       bNode *node;
+       
+       if(ntree==NULL) return;
+       
+       for(node= ntree->nodes.first; node; node= node->next) {
+               node->need_exec= 0;
+               if(node->type==NODE_GROUP)
+                       ntreeClearTags((bNodeTree *)node->id);
+       }
+}
+
+
 int ntreeTexTagAnimated(bNodeTree *ntree)
 {
        bNode *node;
@@ -3012,6 +3287,62 @@ int ntreeTexTagAnimated(bNodeTree *ntree)
 
 /* ************* node definition init ********** */
 
+void node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag,
+                                       struct bNodeSocketType *inputs, struct bNodeSocketType *outputs)
+{
+       memset(ntype, 0, sizeof(bNodeType));
+       
+       ntype->type = type;
+       ntype->name = name;
+       ntype->nclass = nclass;
+       ntype->flag = flag;
+       
+       ntype->inputs = inputs;
+       ntype->outputs = outputs;
+       
+       /* default size values */
+       ntype->width = 140;
+       ntype->minwidth = 100;
+       ntype->maxwidth = 320;
+}
+
+void node_type_init(bNodeType *ntype, void (*initfunc)(struct bNode *))
+{
+       ntype->initfunc = initfunc;
+}
+
+void node_type_size(struct bNodeType *ntype, int width, int minwidth, int maxwidth)
+{
+       ntype->width = width;
+       ntype->minwidth = minwidth;
+       ntype->maxwidth = maxwidth;
+}
+
+void node_type_storage(bNodeType *ntype, const char *storagename, void (*freestoragefunc)(struct bNode *), void (*copystoragefunc)(struct bNode *, struct bNode *))
+{
+       if (storagename)
+               strncpy(ntype->storagename, storagename, sizeof(ntype->storagename));
+       else
+               ntype->storagename[0] = '\0';
+       ntype->copystoragefunc = copystoragefunc;
+       ntype->freestoragefunc = freestoragefunc;
+}
+
+void node_type_exec(struct bNodeType *ntype, void (*execfunc)(void *data, struct bNode *, struct bNodeStack **, struct bNodeStack **))
+{
+       ntype->execfunc = execfunc;
+}
+
+void node_type_gpu(struct bNodeType *ntype, int (*gpufunc)(struct GPUMaterial *mat, struct bNode *node, struct GPUNodeStack *in, struct GPUNodeStack *out))
+{
+       ntype->gpufunc = gpufunc;
+}
+
+void node_type_label(struct bNodeType *ntype, const char *(*labelfunc)(struct bNode *))
+{
+       ntype->labelfunc = labelfunc;
+}
+
 static bNodeType *is_nodetype_registered(ListBase *typelist, int type, ID *id) 
 {
        bNodeType *ntype= typelist->first;
@@ -3037,147 +3368,150 @@ void nodeRegisterType(ListBase *typelist, const bNodeType *ntype)
 
 static void registerCompositNodes(ListBase *ntypelist)
 {
-       nodeRegisterType(ntypelist, &node_group_typeinfo);
-       nodeRegisterType(ntypelist, &cmp_node_rlayers);
-       nodeRegisterType(ntypelist, &cmp_node_image);
-       nodeRegisterType(ntypelist, &cmp_node_texture);
-       nodeRegisterType(ntypelist, &cmp_node_value);
-       nodeRegisterType(ntypelist, &cmp_node_rgb);
-       nodeRegisterType(ntypelist, &cmp_node_curve_time);
-       
-       nodeRegisterType(ntypelist, &cmp_node_composite);
-       nodeRegisterType(ntypelist, &cmp_node_viewer);
-       nodeRegisterType(ntypelist, &cmp_node_splitviewer);
-       nodeRegisterType(ntypelist, &cmp_node_output_file);
-       nodeRegisterType(ntypelist, &cmp_node_view_levels);
-       
-       nodeRegisterType(ntypelist, &cmp_node_curve_rgb);
-       nodeRegisterType(ntypelist, &cmp_node_mix_rgb);
-       nodeRegisterType(ntypelist, &cmp_node_hue_sat);
-       nodeRegisterType(ntypelist, &cmp_node_brightcontrast);
-       nodeRegisterType(ntypelist, &cmp_node_gamma);
-       nodeRegisterType(ntypelist, &cmp_node_invert);
-       nodeRegisterType(ntypelist, &cmp_node_alphaover);
-       nodeRegisterType(ntypelist, &cmp_node_zcombine);
-       nodeRegisterType(ntypelist, &cmp_node_colorbalance);
-       nodeRegisterType(ntypelist, &cmp_node_huecorrect);
-       
-       nodeRegisterType(ntypelist, &cmp_node_normal);
-       nodeRegisterType(ntypelist, &cmp_node_curve_vec);
-       nodeRegisterType(ntypelist, &cmp_node_map_value);
-       nodeRegisterType(ntypelist, &cmp_node_normalize);
-       
-       nodeRegisterType(ntypelist, &cmp_node_filter);
-       nodeRegisterType(ntypelist, &cmp_node_blur);
-       nodeRegisterType(ntypelist, &cmp_node_dblur);
-       nodeRegisterType(ntypelist, &cmp_node_bilateralblur);
-       nodeRegisterType(ntypelist, &cmp_node_vecblur);
-       nodeRegisterType(ntypelist, &cmp_node_dilateerode);
-       nodeRegisterType(ntypelist, &cmp_node_defocus);
-       
-       nodeRegisterType(ntypelist, &cmp_node_valtorgb);
-       nodeRegisterType(ntypelist, &cmp_node_rgbtobw);
-       nodeRegisterType(ntypelist, &cmp_node_setalpha);
-       nodeRegisterType(ntypelist, &cmp_node_idmask);
-       nodeRegisterType(ntypelist, &cmp_node_math);
-       nodeRegisterType(ntypelist, &cmp_node_seprgba);
-       nodeRegisterType(ntypelist, &cmp_node_combrgba);
-       nodeRegisterType(ntypelist, &cmp_node_sephsva);
-       nodeRegisterType(ntypelist, &cmp_node_combhsva);
-       nodeRegisterType(ntypelist, &cmp_node_sepyuva);
-       nodeRegisterType(ntypelist, &cmp_node_combyuva);
-       nodeRegisterType(ntypelist, &cmp_node_sepycca);
-       nodeRegisterType(ntypelist, &cmp_node_combycca);
-       nodeRegisterType(ntypelist, &cmp_node_premulkey);
-       
-       nodeRegisterType(ntypelist, &cmp_node_diff_matte);
-       nodeRegisterType(ntypelist, &cmp_node_distance_matte);
-       nodeRegisterType(ntypelist, &cmp_node_chroma_matte);
-       nodeRegisterType(ntypelist, &cmp_node_color_matte);
-       nodeRegisterType(ntypelist, &cmp_node_channel_matte);
-       nodeRegisterType(ntypelist, &cmp_node_color_spill);
-       nodeRegisterType(ntypelist, &cmp_node_luma_matte);
-       
-       nodeRegisterType(ntypelist, &cmp_node_translate);
-       nodeRegisterType(ntypelist, &cmp_node_rotate);
-       nodeRegisterType(ntypelist, &cmp_node_scale);
-       nodeRegisterType(ntypelist, &cmp_node_flip);
-       nodeRegisterType(ntypelist, &cmp_node_crop);
-       nodeRegisterType(ntypelist, &cmp_node_displace);
-       nodeRegisterType(ntypelist, &cmp_node_mapuv);
-       nodeRegisterType(ntypelist, &cmp_node_glare);
-       nodeRegisterType(ntypelist, &cmp_node_tonemap);
-       nodeRegisterType(ntypelist, &cmp_node_lensdist);
+       register_node_type_group(ntypelist);
+       
+       register_node_type_cmp_rlayers(ntypelist);
+       register_node_type_cmp_image(ntypelist);
+       register_node_type_cmp_texture(ntypelist);
+       register_node_type_cmp_value(ntypelist);
+       register_node_type_cmp_rgb(ntypelist);
+       register_node_type_cmp_curve_time(ntypelist);
+       
+       register_node_type_cmp_composite(ntypelist);
+       register_node_type_cmp_viewer(ntypelist);
+       register_node_type_cmp_splitviewer(ntypelist);
+       register_node_type_cmp_output_file(ntypelist);
+       register_node_type_cmp_view_levels(ntypelist);
+       
+       register_node_type_cmp_curve_rgb(ntypelist);
+       register_node_type_cmp_mix_rgb(ntypelist);
+       register_node_type_cmp_hue_sat(ntypelist);
+       register_node_type_cmp_brightcontrast(ntypelist);
+       register_node_type_cmp_gamma(ntypelist);
+       register_node_type_cmp_invert(ntypelist);
+       register_node_type_cmp_alphaover(ntypelist);
+       register_node_type_cmp_zcombine(ntypelist);
+       register_node_type_cmp_colorbalance(ntypelist);
+       register_node_type_cmp_huecorrect(ntypelist);
+       
+       register_node_type_cmp_normal(ntypelist);
+       register_node_type_cmp_curve_vec(ntypelist);
+       register_node_type_cmp_map_value(ntypelist);
+       register_node_type_cmp_normalize(ntypelist);
+       
+       register_node_type_cmp_filter(ntypelist);
+       register_node_type_cmp_blur(ntypelist);
+       register_node_type_cmp_dblur(ntypelist);
+       register_node_type_cmp_bilateralblur(ntypelist);
+       register_node_type_cmp_vecblur(ntypelist);
+       register_node_type_cmp_dilateerode(ntypelist);
+       register_node_type_cmp_defocus(ntypelist);
+       
+       register_node_type_cmp_valtorgb(ntypelist);
+       register_node_type_cmp_rgbtobw(ntypelist);
+       register_node_type_cmp_setalpha(ntypelist);
+       register_node_type_cmp_idmask(ntypelist);
+       register_node_type_cmp_math(ntypelist);
+       register_node_type_cmp_seprgba(ntypelist);
+       register_node_type_cmp_combrgba(ntypelist);
+       register_node_type_cmp_sephsva(ntypelist);
+       register_node_type_cmp_combhsva(ntypelist);
+       register_node_type_cmp_sepyuva(ntypelist);
+       register_node_type_cmp_combyuva(ntypelist);
+       register_node_type_cmp_sepycca(ntypelist);
+       register_node_type_cmp_combycca(ntypelist);
+       register_node_type_cmp_premulkey(ntypelist);
+       
+       register_node_type_cmp_diff_matte(ntypelist);
+       register_node_type_cmp_distance_matte(ntypelist);
+       register_node_type_cmp_chroma_matte(ntypelist);
+       register_node_type_cmp_color_matte(ntypelist);
+       register_node_type_cmp_channel_matte(ntypelist);
+       register_node_type_cmp_color_spill(ntypelist);
+       register_node_type_cmp_luma_matte(ntypelist);
+       
+       register_node_type_cmp_translate(ntypelist);
+       register_node_type_cmp_rotate(ntypelist);
+       register_node_type_cmp_scale(ntypelist);
+       register_node_type_cmp_flip(ntypelist);
+       register_node_type_cmp_crop(ntypelist);
+       register_node_type_cmp_displace(ntypelist);
+       register_node_type_cmp_mapuv(ntypelist);
+       register_node_type_cmp_glare(ntypelist);
+       register_node_type_cmp_tonemap(ntypelist);
+       register_node_type_cmp_lensdist(ntypelist);
 }
 
 static void registerShaderNodes(ListBase *ntypelist) 
 {
-       nodeRegisterType(ntypelist, &node_group_typeinfo);
-       nodeRegisterType(ntypelist, &sh_node_output);
-       nodeRegisterType(ntypelist, &sh_node_mix_rgb);
-       nodeRegisterType(ntypelist, &sh_node_valtorgb);
-       nodeRegisterType(ntypelist, &sh_node_rgbtobw);
-       nodeRegisterType(ntypelist, &sh_node_normal);
-       nodeRegisterType(ntypelist, &sh_node_geom);
-       nodeRegisterType(ntypelist, &sh_node_mapping);
-       nodeRegisterType(ntypelist, &sh_node_curve_vec);
-       nodeRegisterType(ntypelist, &sh_node_curve_rgb);
-       nodeRegisterType(ntypelist, &sh_node_math);
-       nodeRegisterType(ntypelist, &sh_node_vect_math);
-       nodeRegisterType(ntypelist, &sh_node_squeeze);
-       nodeRegisterType(ntypelist, &sh_node_camera);
-       nodeRegisterType(ntypelist, &sh_node_material);
-       nodeRegisterType(ntypelist, &sh_node_material_ext);
-       nodeRegisterType(ntypelist, &sh_node_value);
-       nodeRegisterType(ntypelist, &sh_node_rgb);
-       nodeRegisterType(ntypelist, &sh_node_texture);
-       nodeRegisterType(ntypelist, &node_dynamic_typeinfo);
-       nodeRegisterType(ntypelist, &sh_node_invert);
-       nodeRegisterType(ntypelist, &sh_node_seprgb);
-       nodeRegisterType(ntypelist, &sh_node_combrgb);
-       nodeRegisterType(ntypelist, &sh_node_hue_sat);
+       register_node_type_group(ntypelist);
+       
+       register_node_type_sh_output(ntypelist);
+       register_node_type_sh_mix_rgb(ntypelist);
+       register_node_type_sh_valtorgb(ntypelist);
+       register_node_type_sh_rgbtobw(ntypelist);
+       register_node_type_sh_normal(ntypelist);
+       register_node_type_sh_geom(ntypelist);
+       register_node_type_sh_mapping(ntypelist);
+       register_node_type_sh_curve_vec(ntypelist);
+       register_node_type_sh_curve_rgb(ntypelist);
+       register_node_type_sh_math(ntypelist);
+       register_node_type_sh_vect_math(ntypelist);
+       register_node_type_sh_squeeze(ntypelist);
+       register_node_type_sh_camera(ntypelist);
+       register_node_type_sh_material(ntypelist);
+       register_node_type_sh_material_ext(ntypelist);
+       register_node_type_sh_value(ntypelist);
+       register_node_type_sh_rgb(ntypelist);
+       register_node_type_sh_texture(ntypelist);
+//     register_node_type_sh_dynamic(ntypelist);
+       register_node_type_sh_invert(ntypelist);
+       register_node_type_sh_seprgb(ntypelist);
+       register_node_type_sh_combrgb(ntypelist);
+       register_node_type_sh_hue_sat(ntypelist);
 }
 
 static void registerTextureNodes(ListBase *ntypelist)
 {
-       nodeRegisterType(ntypelist, &node_group_typeinfo);
-       nodeRegisterType(ntypelist, &tex_node_math);
-       nodeRegisterType(ntypelist, &tex_node_mix_rgb);
-       nodeRegisterType(ntypelist, &tex_node_valtorgb);
-       nodeRegisterType(ntypelist, &tex_node_rgbtobw);
-       nodeRegisterType(ntypelist, &tex_node_valtonor);
-       nodeRegisterType(ntypelist, &tex_node_curve_rgb);
-       nodeRegisterType(ntypelist, &tex_node_curve_time);
-       nodeRegisterType(ntypelist, &tex_node_invert);
-       nodeRegisterType(ntypelist, &tex_node_hue_sat);
-       nodeRegisterType(ntypelist, &tex_node_coord);
-       nodeRegisterType(ntypelist, &tex_node_distance);
-       nodeRegisterType(ntypelist, &tex_node_compose);
-       nodeRegisterType(ntypelist, &tex_node_decompose);
-       
-       nodeRegisterType(ntypelist, &tex_node_output);
-       nodeRegisterType(ntypelist, &tex_node_viewer);
-       
-       nodeRegisterType(ntypelist, &tex_node_checker);
-       nodeRegisterType(ntypelist, &tex_node_texture);
-       nodeRegisterType(ntypelist, &tex_node_bricks);
-       nodeRegisterType(ntypelist, &tex_node_image);
-       
-       nodeRegisterType(ntypelist, &tex_node_rotate);
-       nodeRegisterType(ntypelist, &tex_node_translate);
-       nodeRegisterType(ntypelist, &tex_node_scale);
-       nodeRegisterType(ntypelist, &tex_node_at);
-       
-       nodeRegisterType(ntypelist, &tex_node_proc_voronoi);
-       nodeRegisterType(ntypelist, &tex_node_proc_blend);
-       nodeRegisterType(ntypelist, &tex_node_proc_magic);
-       nodeRegisterType(ntypelist, &tex_node_proc_marble);
-       nodeRegisterType(ntypelist, &tex_node_proc_clouds);
-       nodeRegisterType(ntypelist, &tex_node_proc_wood);
-       nodeRegisterType(ntypelist, &tex_node_proc_musgrave);
-       nodeRegisterType(ntypelist, &tex_node_proc_noise);
-       nodeRegisterType(ntypelist, &tex_node_proc_stucci);
-       nodeRegisterType(ntypelist, &tex_node_proc_distnoise);
+       register_node_type_group(ntypelist);
+       
+       register_node_type_tex_math(ntypelist);
+       register_node_type_tex_mix_rgb(ntypelist);
+       register_node_type_tex_valtorgb(ntypelist);
+       register_node_type_tex_rgbtobw(ntypelist);
+       register_node_type_tex_valtonor(ntypelist);
+       register_node_type_tex_curve_rgb(ntypelist);
+       register_node_type_tex_curve_time(ntypelist);
+       register_node_type_tex_invert(ntypelist);
+       register_node_type_tex_hue_sat(ntypelist);
+       register_node_type_tex_coord(ntypelist);
+       register_node_type_tex_distance(ntypelist);
+       register_node_type_tex_compose(ntypelist);
+       register_node_type_tex_decompose(ntypelist);
+       
+       register_node_type_tex_output(ntypelist);
+       register_node_type_tex_viewer(ntypelist);
+       
+       register_node_type_tex_checker(ntypelist);
+       register_node_type_tex_texture(ntypelist);
+       register_node_type_tex_bricks(ntypelist);
+       register_node_type_tex_image(ntypelist);
+       
+       register_node_type_tex_rotate(ntypelist);
+       register_node_type_tex_translate(ntypelist);
+       register_node_type_tex_scale(ntypelist);
+       register_node_type_tex_at(ntypelist);
+       
+       register_node_type_tex_proc_voronoi(ntypelist);
+       register_node_type_tex_proc_blend(ntypelist);
+       register_node_type_tex_proc_magic(ntypelist);
+       register_node_type_tex_proc_marble(ntypelist);
+       register_node_type_tex_proc_clouds(ntypelist);
+       register_node_type_tex_proc_wood(ntypelist);
+       register_node_type_tex_proc_musgrave(ntypelist);
+       register_node_type_tex_proc_noise(ntypelist);
+       register_node_type_tex_proc_stucci(ntypelist);
+       register_node_type_tex_proc_distnoise(ntypelist);
 }
 
 static void remove_dynamic_typeinfos(ListBase *list)
@@ -3191,7 +3525,7 @@ static void remove_dynamic_typeinfos(ListBase *list)
                        if(ntype->inputs) {
                                bNodeSocketType *sock= ntype->inputs;
                                while(sock->type!=-1) {
-                                       MEM_freeN(sock->name);
+                                       MEM_freeN((void *)sock->name);
                                        sock++;
                                }
                                MEM_freeN(ntype->inputs);
@@ -3199,13 +3533,13 @@ static void remove_dynamic_typeinfos(ListBase *list)
                        if(ntype->outputs) {
                                bNodeSocketType *sock= ntype->outputs;
                                while(sock->type!=-1) {
-                                       MEM_freeN(sock->name);
+                                       MEM_freeN((void *)sock->name);
                                        sock++;
                                }
                                MEM_freeN(ntype->outputs);
                        }
                        if(ntype->name) {
-                               MEM_freeN(ntype->name);
+                               MEM_freeN((void *)ntype->name);
                        }
                        MEM_freeN(ntype);
                }