svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r20855:20928
[blender.git] / source / blender / blenkernel / intern / node.c
index 78005346335f316fa7f794dff272891112c92fb1..0f42ba0d2e281ccfc3ce1f2cf801740e52c05b46 100644 (file)
  * ***** END GPL LICENSE BLOCK *****
  */
 
+#ifndef DISABLE_PYTHON
+#include <Python.h>
+#endif
+
 #include <stdlib.h>
 #include <string.h>
 
@@ -34,6 +38,8 @@
 #include "DNA_image_types.h"
 #include "DNA_node_types.h"
 #include "DNA_material_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_text_types.h"
 #include "DNA_scene_types.h"
 
 #include "BKE_blender.h"
@@ -44,6 +50,7 @@
 #include "BKE_main.h"
 #include "BKE_node.h"
 #include "BKE_texture.h"
+#include "BKE_text.h"
 #include "BKE_utildefines.h"
 
 #include "BLI_arithb.h"
 #include "RE_render_ext.h"             /* <- ibuf_sample() */
 
 #include "CMP_node.h"
+#include "intern/CMP_util.h"   /* stupid include path... */
+
 #include "SHD_node.h"
+#include "TEX_node.h"
+#include "intern/TEX_util.h"
 
-/* not very important, but the stack solver likes to know a maximum */
-#define MAX_SOCKET     64
+#include "GPU_extensions.h"
+#include "GPU_material.h"
 
 static ListBase empty_list = {NULL, NULL};
 ListBase node_all_composit = {NULL, NULL};
 ListBase node_all_shaders = {NULL, NULL};
+ListBase node_all_textures = {NULL, NULL};
 
 /* ************** Type stuff **********  */
 
-static bNodeType *node_get_type(bNodeTree *ntree, int type, bNodeTree *ngroup)
+static bNodeType *node_get_type(bNodeTree *ntree, int type, bNodeTree *ngroup, ID *id)
 {
        if(type==NODE_GROUP) {
                if(ngroup && GS(ngroup->id.name)==ID_NT) {
@@ -83,7 +95,7 @@ static bNodeType *node_get_type(bNodeTree *ntree, int type, bNodeTree *ngroup)
        else {
                bNodeType *ntype = ntree->alltypes.first;
                for(; ntype; ntype= ntype->next)
-                       if(ntype->type==type)
+                       if(ntype->type==type && id==ntype->id )
                                return ntype;
                
                return NULL;
@@ -98,6 +110,8 @@ void ntreeInitTypes(bNodeTree *ntree)
                ntree->alltypes= node_all_shaders;
        else if(ntree->type==NTREE_COMPOSIT)
                ntree->alltypes= node_all_composit;
+       else if(ntree->type==NTREE_TEXTURE)
+               ntree->alltypes= node_all_textures;
        else {
                ntree->alltypes= empty_list;
                printf("Error: no type definitions for nodes\n");
@@ -105,7 +119,27 @@ void ntreeInitTypes(bNodeTree *ntree)
        
        for(node= ntree->nodes.first; node; node= next) {
                next= node->next;
-               node->typeinfo= node_get_type(ntree, node->type, (bNodeTree *)node->id);
+               if(node->type==NODE_DYNAMIC) {
+                       bNodeType *stype= NULL;
+                       if(node->id==NULL) { /* empty script node */
+                               stype= node_get_type(ntree, node->type, NULL, NULL);
+                       } else { /* not an empty script node */
+                               stype= node_get_type(ntree, node->type, NULL, node->id);
+                               if(!stype) {
+                                       stype= node_get_type(ntree, node->type, NULL, NULL);
+                                       /* needed info if the pynode script fails now: */
+                                       if (node->id) node->storage= ntree;
+                               } else {
+                                       node->custom1= 0;
+                                       node->custom1= BSET(node->custom1,NODE_DYNAMIC_ADDEXIST);
+                               }
+                       }
+                       node->typeinfo= stype;
+                       node->typeinfo->initfunc(node);
+               } else {
+                       node->typeinfo= node_get_type(ntree, node->type, (bNodeTree *)node->id, NULL);
+               }
+
                if(node->typeinfo==NULL) {
                        printf("Error: Node type %s doesn't exist anymore, removed\n", node->name);
                        nodeFreeNode(ntree, node);
@@ -115,6 +149,18 @@ void ntreeInitTypes(bNodeTree *ntree)
        ntree->init |= NTREE_TYPE_INIT;
 }
 
+/* updates node with (modified) bNodeType.. this should be done for all trees */
+void ntreeUpdateType(bNodeTree *ntree, bNodeType *ntype)
+{
+       bNode *node;
+
+       for(node= ntree->nodes.first; node; node= node->next) {
+               if(node->typeinfo== ntype) {
+                       nodeUpdateType(ntree, node, ntype);
+               }
+       }
+}
+
 /* only used internal... we depend on type definitions! */
 static bNodeSocket *node_add_socket_type(ListBase *lb, bNodeSocketType *stype)
 {
@@ -137,7 +183,7 @@ static bNodeSocket *node_add_socket_type(ListBase *lb, bNodeSocketType *stype)
        
        if(lb)
                BLI_addtail(lb, sock);
-       
+
        return sock;
 }
 
@@ -239,7 +285,7 @@ void ntreeVerifyTypes(bNodeTree *ntree)
 /* ************** Group stuff ********** */
 
 bNodeType node_group_typeinfo= {
-       /* next,prev   */   NULL, NULL,
+       /* next,prev   */       NULL, NULL,
        /* type code   */       NODE_GROUP,
        /* name        */       "Group",
        /* width+range */       120, 60, 200,
@@ -248,8 +294,11 @@ bNodeType node_group_typeinfo= {
        /* output sock */       NULL,
        /* storage     */       "",
        /* execfunc    */       NULL,
-       /* butfunc         */   NULL,
-       /* initfunc    */   NULL
+       /* butfunc     */       NULL,
+       /* initfunc    */       NULL,
+       /* freestoragefunc    */        NULL,
+       /* copystoragefunc    */        NULL,
+       /* id          */       NULL
 };
 
 /* tag internal sockets */
@@ -264,7 +313,7 @@ static void group_tag_internal_sockets(bNodeTree *ngroup)
                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->intern= sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL);
        }
        /* set tag */
        for(link= ngroup->links.first; link; link= link->next) {
@@ -349,13 +398,13 @@ void ntreeMakeOwnType(bNodeTree *ngroup)
        }
        
        /* make own type struct */
-       ngroup->owntype= MEM_mallocN(sizeof(bNodeType), "group type");
+       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_mallocN(sizeof(bNodeSocketType)*(totin+1), "bNodeSocketType");
+               bNodeSocketType *inputs= MEM_callocN(sizeof(bNodeSocketType)*(totin+1), "bNodeSocketType");
                a= 0;
                
                for(node= ngroup->nodes.first; node; node= node->next) {
@@ -380,7 +429,7 @@ void ntreeMakeOwnType(bNodeTree *ngroup)
        /* output type arrays */
        if(totout) {
                bNodeSocketType *stype;
-               bNodeSocketType *outputs= MEM_mallocN(sizeof(bNodeSocketType)*(totout+1), "bNodeSocketType");
+               bNodeSocketType *outputs= MEM_callocN(sizeof(bNodeSocketType)*(totout+1), "bNodeSocketType");
                a= 0;
                
                for(node= ngroup->nodes.first; node; node= node->next) {
@@ -480,6 +529,28 @@ bNode *nodeMakeGroupFromSelected(bNodeTree *ntree)
                        BLI_addtail(&ngroup->nodes, node);
                        node->locx-= 0.5f*(min[0]+max[0]);
                        node->locy-= 0.5f*(min[1]+max[1]);
+
+                       /* set selin and selout of the nodetree */
+                       for(sock= node->inputs.first; sock; sock= sock->next) {
+                               if(sock->flag & SOCK_SEL) {
+                                       ngroup->selin= sock;
+                                       break;
+                               }
+                       }
+                       for(sock= node->outputs.first; sock; sock= sock->next) {
+                               if(sock->flag & SOCK_SEL) {
+                                       ngroup->selout= sock;
+                                       break;
+                               }
+                       }
+
+                       /* 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;
                }
        }
 
@@ -496,7 +567,7 @@ bNode *nodeMakeGroupFromSelected(bNodeTree *ntree)
        ntreeMakeOwnType(ngroup);
        
        /* make group node */
-       gnode= nodeAddNodeType(ntree, NODE_GROUP, ngroup);
+       gnode= nodeAddNodeType(ntree, NODE_GROUP, ngroup, NULL);
        gnode->locx= 0.5f*(min[0]+max[0]);
        gnode->locy= 0.5f*(min[1]+max[1]);
        
@@ -535,6 +606,10 @@ bNode *nodeMakeGroupFromSelected(bNodeTree *ntree)
                        }
                }
        }
+
+       /* update node levels */
+       ntreeSolveOrder(ntree);
+
        return gnode;
 }
 
@@ -592,6 +667,28 @@ void nodeVerifyGroup(bNodeTree *ngroup)
                        }
                }
        }
+       else if(ngroup->type==NTREE_TEXTURE) {
+               Tex *tx;
+               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);
+                               }
+                       }
+               }
+       }
 }
 
 /* also to check all users of groups. Now only used in editor for hide/unhide */
@@ -648,9 +745,30 @@ void nodeGroupSocketUseFlags(bNodeTree *ngroup)
                        }
                }
        }
+       else if(ngroup->type==NTREE_TEXTURE) {
+               Tex *tx;
+               for(tx= G.main->tex.first; tx; tx= tx->id.next) {
+                       if(tx->nodetree) {
+                               for(node= tx->nodetree->nodes.first; node; node= node->next) {
+                                       if(node->id==(ID *)ngroup) {
+                                               for(sock= node->inputs.first; sock; sock= sock->next)
+                                                       if(sock->link)
+                                                               if(sock->tosock) 
+                                                                       sock->tosock->flag |= SOCK_IN_USE;
+                                               for(sock= node->outputs.first; sock; sock= sock->next)
+                                                       if(nodeCountSocketLinks(tx->nodetree, sock))
+                                                               if(sock->tosock) 
+                                                                       sock->tosock->flag |= SOCK_IN_USE;
+                                       }
+                               }
+                       }
+               }
+       }
+       
 }
 
-static void find_node_with_socket(bNodeTree *ntree, bNodeSocket *sock, bNode **nodep, int *sockindex)
+/* finds a node based on given socket */
+int nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **nodep, int *sockindex)
 {
        bNode *node;
        bNodeSocket *tsock;
@@ -668,13 +786,15 @@ static void find_node_with_socket(bNodeTree *ntree, bNodeSocket *sock, bNode **n
                if(tsock)
                        break;
        }
+
        if(node) {
                *nodep= node;
-               *sockindex= index;
-       }
-       else {
-               *nodep= NULL;
+               if(sockindex) *sockindex= index;
+               return 1;
        }
+       
+       *nodep= NULL;
+       return 0;
 }
 
 /* returns 1 if its OK */
@@ -714,7 +834,7 @@ int nodeGroupUnGroup(bNodeTree *ntree, bNode *gnode)
        for(link= ntree->links.first; link; link= link->next) {
                if(link->tonode==gnode) {
                        /* link->tosock->tosock is on the node we look for */
-                       find_node_with_socket(ngroup, link->tosock->tosock, &nextn, &index);
+                       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 {
@@ -724,7 +844,7 @@ int nodeGroupUnGroup(bNodeTree *ntree, bNode *gnode)
                }
                else if(link->fromnode==gnode) {
                        /* link->fromsock->tosock is on the node we look for */
-                       find_node_with_socket(ngroup, link->fromsock->tosock, &nextn, &index);
+                       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");
                        else {
@@ -746,98 +866,163 @@ int nodeGroupUnGroup(bNodeTree *ntree, bNode *gnode)
        return 1;
 }
 
-/* ************** Add stuff ********** */
+void nodeCopyGroup(bNode *gnode)
+{
+       bNodeSocket *sock;
+
+       gnode->id->us--;
+       gnode->id= (ID *)ntreeCopyTree((bNodeTree *)gnode->id, 0);
+
+       /* new_sock was set in nodeCopyNode */
+       for(sock=gnode->inputs.first; sock; sock=sock->next)
+               if(sock->tosock)
+                       sock->tosock= sock->tosock->new_sock;
 
-bNode *nodeAddNodeType(bNodeTree *ntree, int type, bNodeTree *ngroup)
+       for(sock=gnode->outputs.first; sock; sock=sock->next)
+               if(sock->tosock)
+                       sock->tosock= sock->tosock->new_sock;
+}
+
+/* ************** Add stuff ********** */
+void nodeAddSockets(bNode *node, bNodeType *ntype)
 {
-       bNode *node;
-       bNodeType *ntype= node_get_type(ntree, type, ngroup);
        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++;
+               }
+       }
+}
+
+
+bNode *nodeAddNodeType(bNodeTree *ntree, int type, bNodeTree *ngroup, ID *id)
+{
+       bNode *node= NULL;
+       bNodeType *ntype= NULL;
+
+       if(type>=NODE_DYNAMIC_MENU) {
+               int a=0, idx= type-NODE_DYNAMIC_MENU;
+               ntype= ntree->alltypes.first;
+               while(ntype) {
+                       if(ntype->type==NODE_DYNAMIC) {
+                               if(a==idx)
+                                       break;
+                               a++;
+                       }
+                       ntype= ntype->next;
+               }
+       } else
+               ntype= node_get_type(ntree, type, ngroup, id);
+
        node= MEM_callocN(sizeof(bNode), "new node");
        BLI_addtail(&ntree->nodes, node);
        node->typeinfo= ntype;
-       
+       if(type>=NODE_DYNAMIC_MENU)
+               node->custom2= type; /* for node_dynamic_init */
+
        if(ngroup)
                BLI_strncpy(node->name, ngroup->id.name+2, NODE_MAXSTR);
+       else if(type>NODE_DYNAMIC_MENU) {
+               BLI_strncpy(node->name, ntype->id->name+2, NODE_MAXSTR);
+       }
        else
                BLI_strncpy(node->name, ntype->name, NODE_MAXSTR);
        node->type= ntype->type;
        node->flag= NODE_SELECT|ntype->flag;
        node->width= ntype->width;
        node->miniwidth= 42.0f;         /* small value only, allows print of first chars */
-       
+
        if(type==NODE_GROUP)
                node->id= (ID *)ngroup;
+
+       /* need init handler later? */
+       /* got it-bob*/
+       if(ntype->initfunc!=NULL)
+               ntype->initfunc(node);
        
-       if(ntype->inputs) {
-               stype= ntype->inputs;
-               while(stype->type != -1) {
-                       node_add_socket_type(&node->inputs, stype);
-                       stype++;
-               }
+       if(type==TEX_NODE_OUTPUT)
+               ntreeTexAssignIndex(ntree, node);
+
+       nodeAddSockets(node, ntype);
+       
+       return node;
+}
+
+void nodeMakeDynamicType(bNode *node)
+{
+       /* find SH_DYNAMIC_NODE ntype */
+       bNodeType *ntype= node_all_shaders.first;
+       while(ntype) {
+               if(ntype->type==NODE_DYNAMIC && ntype->id==NULL)
+                       break;
+               ntype= ntype->next;
        }
-       if(ntype->outputs) {
-               stype= ntype->outputs;
-               while(stype->type != -1) {
-                       node_add_socket_type(&node->outputs, stype);
-                       stype++;
-               }
+
+       /* make own type struct to fill */
+       if(ntype) {
+               /*node->typeinfo= MEM_dupallocN(ntype);*/
+               bNodeType *newtype= MEM_callocN(sizeof(bNodeType), "dynamic bNodeType");
+               *newtype= *ntype;
+               newtype->name= BLI_strdup(ntype->name);
+               node->typeinfo= newtype;
        }
-       
-       /* need init handler later? */
-   /* got it-bob*/
-   if(ntype->initfunc!=NULL)
-      ntype->initfunc(node);
+}
 
-   return node;
+void nodeUpdateType(bNodeTree *ntree, bNode* node, bNodeType *ntype)
+{
+       verify_socket_list(ntree, &node->inputs, ntype->inputs);
+       verify_socket_list(ntree, &node->outputs, ntype->outputs);
 }
 
 /* keep socket listorder identical, for copying links */
 /* ntree is the target tree */
-bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node)
+bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node, int internal)
 {
        bNode *nnode= MEM_callocN(sizeof(bNode), "dupli node");
-       bNodeSocket *sock;
+       bNodeSocket *sock, *oldsock;
 
        *nnode= *node;
        BLI_addtail(&ntree->nodes, nnode);
        
-       duplicatelist(&nnode->inputs, &node->inputs);
-       for(sock= nnode->inputs.first; sock; sock= sock->next)
-               sock->own_index= 0;
+       BLI_duplicatelist(&nnode->inputs, &node->inputs);
+       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;
+       }
        
-       duplicatelist(&nnode->outputs, &node->outputs);
-       for(sock= nnode->outputs.first; sock; sock= sock->next) {
-               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;
        }
        
-       if(nnode->id)
-               nnode->id->us++;
+       /* don't increase node->id users, freenode doesn't decrement either */
        
-       if(nnode->storage) {
-               /* another candidate for handlerizing! */
-               if(ntree->type==NTREE_SHADER) {
-                       if(node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB)
-                               nnode->storage= curvemapping_copy(node->storage);
-                       else 
-                               nnode->storage= MEM_dupallocN(nnode->storage);
-               }
-               else if(ntree->type==NTREE_COMPOSIT) {
-                       if(ELEM3(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB))
-                               nnode->storage= curvemapping_copy(node->storage);
-                       else 
-                               nnode->storage= MEM_dupallocN(nnode->storage);
-               }
-               else 
-                       nnode->storage= MEM_dupallocN(nnode->storage);
-       }
+       if(node->typeinfo->copystoragefunc)
+               node->typeinfo->copystoragefunc(node, nnode);
        
        node->new_node= nnode;
        nnode->new_node= NULL;
        nnode->preview= NULL;
+       
+       if(node->type==TEX_NODE_OUTPUT)
+               ntreeTexAssignIndex(ntree, node);
 
        return nnode;
 }
@@ -870,6 +1055,14 @@ bNodeTree *ntreeAddTree(int type)
        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, "NTComposit 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;
@@ -904,19 +1097,42 @@ bNodeTree *ntreeCopyTree(bNodeTree *ntree, int internal_select)
                
                node->new_node= NULL;
                if(internal_select==0 || (node->flag & NODE_SELECT)) {
-                       nnode= nodeCopyNode(newtree, node);     /* sets node->new */
+                       nnode= nodeCopyNode(newtree, node, internal_select);    /* sets node->new */
                        if(internal_select) {
                                node->flag &= ~NODE_SELECT;
                                nnode->flag |= NODE_SELECT;
                        }
                        node->flag &= ~NODE_ACTIVE;
+
+                       /* deselect original sockets */
+                       for(sock= node->inputs.first; sock; sock= sock->next) {
+                               if(sock->flag & SOCK_SEL) sock->flag&= ~SOCK_SEL;
+                       }
+                       for(sock= node->outputs.first; sock; sock= sock->next) {
+                               if(sock->flag & SOCK_SEL) sock->flag&= ~SOCK_SEL;
+                       }
+                       
+                       /* set tree selin and selout to new sockets */
+                       for(sock= nnode->inputs.first; sock; sock= sock->next) {
+                               if(sock->flag & SOCK_SEL) {
+                                       ntree->selin= sock;
+                                       break;
+                               }
+                       }
+                       for(sock= nnode->outputs.first; sock; sock= sock->next) {
+                               if(sock->flag & SOCK_SEL) {
+                                       ntree->selout= sock;
+                                       break;
+                               }
+                       }
                }
                if(node==last) break;
        }
        
        /* check for copying links */
        for(link= ntree->links.first; link; link= link->next) {
-               if(link->fromnode->new_node && link->tonode->new_node) {
+               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++) {
@@ -950,10 +1166,108 @@ bNodeTree *ntreeCopyTree(bNodeTree *ntree, int internal_select)
        return newtree;
 }
 
+/* *************** preview *********** */
+/* if node->preview, then we assume the rect to exist */
+
+static void node_free_preview(bNode *node)
+{
+       if(node->preview) {
+               if(node->preview->rect)
+                       MEM_freeN(node->preview->rect);
+               MEM_freeN(node->preview);
+               node->preview= NULL;
+       }       
+}
+
+static void node_init_preview(bNode *node, int xsize, int ysize)
+{
+       
+       if(node->preview==NULL) {
+               node->preview= MEM_callocN(sizeof(bNodePreview), "node preview");
+               //              printf("added preview %s\n", node->name);
+       }
+       
+       /* node previews can get added with variable size this way */
+       if(xsize==0 || ysize==0)
+               return;
+       
+       /* sanity checks & initialize */
+       if(node->preview->rect) {
+               if(node->preview->xsize!=xsize && node->preview->ysize!=ysize) {
+                       MEM_freeN(node->preview->rect);
+                       node->preview->rect= NULL;
+               }
+       }
+       
+       if(node->preview->rect==NULL) {
+               node->preview->rect= MEM_callocN(4*xsize + xsize*ysize*sizeof(float)*4, "node preview rect");
+               node->preview->xsize= xsize;
+               node->preview->ysize= ysize;
+       }
+}
+
+void ntreeInitPreview(bNodeTree *ntree, int xsize, int ysize)
+{
+       bNode *node;
+       
+       if(ntree==NULL)
+               return;
+       
+       for(node= ntree->nodes.first; node; node= node->next) {
+               if(node->typeinfo->flag & NODE_PREVIEW) /* hrms, check for closed nodes? */
+                       node_init_preview(node, xsize, ysize);
+               if(node->type==NODE_GROUP && (node->flag & NODE_GROUP_EDIT))
+                       ntreeInitPreview((bNodeTree *)node->id, xsize, ysize);
+       }               
+}
+
+static void nodeClearPreview(bNode *node)
+{
+       if(node->preview && node->preview->rect)
+               memset(node->preview->rect, 0, MEM_allocN_len(node->preview->rect));
+}
+
+/* use it to enforce clear */
+void ntreeClearPreview(bNodeTree *ntree)
+{
+       bNode *node;
+       
+       if(ntree==NULL)
+               return;
+       
+       for(node= ntree->nodes.first; node; node= node->next) {
+               if(node->typeinfo->flag & NODE_PREVIEW)
+                       nodeClearPreview(node);
+               if(node->type==NODE_GROUP && (node->flag & NODE_GROUP_EDIT))
+                       ntreeClearPreview((bNodeTree *)node->id);
+       }               
+}
+
+/* hack warning! this function is only used for shader previews, and 
+since it gets called multiple times per pixel for Ztransp we only
+add the color once. Preview gets cleared before it starts render though */
+void nodeAddToPreview(bNode *node, float *col, int x, int y)
+{
+       bNodePreview *preview= node->preview;
+       if(preview) {
+               if(x>=0 && y>=0) {
+                       if(x<preview->xsize && y<preview->ysize) {
+                               float *tar= preview->rect+ 4*((preview->xsize*y) + x);
+                               //if(tar[0]==0.0f) {
+                               QUATCOPY(tar, col);
+                               //}
+                       }
+                       //else printf("prv out bound x y %d %d\n", x, y);
+               }
+               //else printf("prv out bound x y %d %d\n", x, y);
+       }
+}
+
+
 /* ************** Free stuff ********** */
 
 /* goes over entire tree */
-static void node_unlink_node(bNodeTree *ntree, bNode *node)
+void nodeUnlinkNode(bNodeTree *ntree, bNode *node)
 {
        bNodeLink *link, *next;
        bNodeSocket *sock;
@@ -997,7 +1311,7 @@ static void composit_free_node_cache(bNode *node)
 
 void nodeFreeNode(bNodeTree *ntree, bNode *node)
 {
-       node_unlink_node(ntree, node);
+       nodeUnlinkNode(ntree, node);
        BLI_remlink(&ntree->nodes, node);
 
        /* since it is called while free database, node->id is undefined */
@@ -1007,28 +1321,12 @@ void nodeFreeNode(bNodeTree *ntree, bNode *node)
        BLI_freelistN(&node->inputs);
        BLI_freelistN(&node->outputs);
        
-       if(node->preview) {
-               if(node->preview->rect)
-                       MEM_freeN(node->preview->rect);
-               MEM_freeN(node->preview);
-       }
-       if(node->storage) {
-               /* could be handlerized at some point, now only 1 exception still */
-               if(ntree->type==NTREE_SHADER) {
-                       if(node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB)
-                               curvemapping_free(node->storage);
-                       else 
-                               MEM_freeN(node->storage);
-               }
-               else if(ntree->type==NTREE_COMPOSIT) {
-                       if(ELEM3(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB))
-                               curvemapping_free(node->storage);
-                       else 
-                               MEM_freeN(node->storage);
-               }
-               else 
-                       MEM_freeN(node->storage);
+       node_free_preview(node);
+
+       if(node->typeinfo && node->typeinfo->freestoragefunc) {
+               node->typeinfo->freestoragefunc(node);
        }
+
        MEM_freeN(node);
 }
 
@@ -1119,8 +1417,24 @@ void ntreeMakeLocal(bNodeTree *ntree)
                        }
                }
        }
-       
-       /* if all users are local, we simply make tree local */
+       else if(ntree->type==NTREE_TEXTURE) {
+               Tex *tx;
+               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 *)ntree) {
+                                               if(tx->id.lib) lib= 1;
+                                               else local= 1;
+                                       }
+                               }
+                       }
+               }
+       }
+       
+       /* if all users are local, we simply make tree local */
        if(local && lib==0) {
                ntree->id.lib= NULL;
                ntree->id.flag= LIB_LOCAL;
@@ -1170,6 +1484,25 @@ void ntreeMakeLocal(bNodeTree *ntree)
                                }
                        }
                }
+               else if(ntree->type==NTREE_TEXTURE) {
+                       Tex *tx;
+                       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 *)ntree) {
+                                                       if(tx->id.lib==NULL) {
+                                                               node->id= &newtree->id;
+                                                               newtree->id.us++;
+                                                               ntree->id.us--;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
        }
 }
 
@@ -1230,11 +1563,21 @@ bNode *nodeGetActiveID(bNodeTree *ntree, short idtype)
        bNode *node;
        
        if(ntree==NULL) return NULL;
+
+       /* check for group edit */
+    for(node= ntree->nodes.first; node; node= node->next)
+               if(node->flag & NODE_GROUP_EDIT)
+                       break;
+
+       if(node)
+               ntree= (bNodeTree*)node->id;
        
+       /* now find active node with this id */
        for(node= ntree->nodes.first; node; node= node->next)
                if(node->id && GS(node->id->name)==idtype)
                        if(node->flag & NODE_ACTIVE_ID)
                                break;
+
        return node;
 }
 
@@ -1404,7 +1747,8 @@ void ntreeSolveOrder(bNodeTree *ntree)
                might be different for editor or for "real" use... */
 }
 
-/* should be callback! */
+/* Should be callback! */
+/* Do not call execs here */
 void NodeTagChanged(bNodeTree *ntree, bNode *node)
 {
        if(ntree->type==NTREE_COMPOSIT) {
@@ -1412,14 +1756,8 @@ void NodeTagChanged(bNodeTree *ntree, bNode *node)
 
                for(sock= node->outputs.first; sock; sock= sock->next) {
                        if(sock->ns.data) {
-                               free_compbuf(sock->ns.data);
-                               sock->ns.data= NULL;
-                               
-                               //if(node->preview && node->preview->rect) {
-                               //      MEM_freeN(node->preview->rect);
-                               //      node->preview->rect= NULL;
-                               //}
-                                       
+                               //free_compbuf(sock->ns.data);
+                               //sock->ns.data= NULL;
                        }
                }
                node->need_exec= 1;
@@ -1441,95 +1779,6 @@ void NodeTagIDChanged(bNodeTree *ntree, ID *id)
 }
 
 
-/* *************** preview *********** */
-
-/* if node->preview, then we assume the rect to exist */
-
-static void nodeInitPreview(bNode *node, int xsize, int ysize)
-{
-       
-       if(node->preview==NULL) {
-               node->preview= MEM_callocN(sizeof(bNodePreview), "node preview");
-//             printf("added preview %s\n", node->name);
-       }
-       
-       /* node previews can get added with variable size this way */
-       if(xsize==0 || ysize==0)
-               return;
-       
-       /* sanity checks & initialize */
-       if(node->preview->rect) {
-               if(node->preview->xsize!=xsize && node->preview->ysize!=ysize) {
-                       MEM_freeN(node->preview->rect);
-                       node->preview->rect= NULL;
-               }
-       }
-       
-       if(node->preview->rect==NULL) {
-               node->preview->rect= MEM_callocN(4*xsize + xsize*ysize*sizeof(float)*4, "node preview rect");
-               node->preview->xsize= xsize;
-               node->preview->ysize= ysize;
-       }
-}
-
-void ntreeInitPreview(bNodeTree *ntree, int xsize, int ysize)
-{
-       bNode *node;
-       
-       if(ntree==NULL)
-               return;
-       
-       for(node= ntree->nodes.first; node; node= node->next) {
-               if(node->typeinfo->flag & NODE_PREVIEW) /* hrms, check for closed nodes? */
-                       nodeInitPreview(node, xsize, ysize);
-               if(node->type==NODE_GROUP && (node->flag & NODE_GROUP_EDIT))
-                       ntreeInitPreview((bNodeTree *)node->id, xsize, ysize);
-       }               
-}
-
-static void nodeClearPreview(bNode *node)
-{
-       if(node->preview && node->preview->rect)
-               memset(node->preview->rect, 0, MEM_allocN_len(node->preview->rect));
-}
-
-/* use it to enforce clear */
-void ntreeClearPreview(bNodeTree *ntree)
-{
-       bNode *node;
-       
-       if(ntree==NULL)
-               return;
-       
-       for(node= ntree->nodes.first; node; node= node->next) {
-               if(node->typeinfo->flag & NODE_PREVIEW)
-                       nodeClearPreview(node);
-               if(node->type==NODE_GROUP && (node->flag & NODE_GROUP_EDIT))
-                       ntreeClearPreview((bNodeTree *)node->id);
-       }               
-}
-
-/* hack warning! this function is only used for shader previews, and 
-   since it gets called multiple times per pixel for Ztransp we only
-   add the color once. Preview gets cleared before it starts render though */
-void nodeAddToPreview(bNode *node, float *col, int x, int y)
-{
-       bNodePreview *preview= node->preview;
-       if(preview) {
-               if(x>=0 && y>=0) {
-                       if(x<preview->xsize && y<preview->ysize) {
-                               float *tar= preview->rect+ 4*((preview->xsize*y) + x);
-                               if(tar[0]==0.0f) {
-                                       QUATCOPY(tar, col);
-                               }
-                       }
-                       //else printf("prv out bound x y %d %d\n", x, y);
-               }
-               //else printf("prv out bound x y %d %d\n", x, y);
-       }
-}
-
-
 
 /* ******************* executing ************* */
 
@@ -1649,16 +1898,20 @@ static void composit_begin_exec(bNodeTree *ntree, int is_group)
        bNodeSocket *sock;
        
        for(node= ntree->nodes.first; node; node= node->next) {
+               
+               /* initialize needed for groups */
+               node->exec= 0;  
+               
                if(is_group==0) {
                        for(sock= node->outputs.first; sock; sock= sock->next) {
-                               bNodeStack *ns= ntree->stack[0] + sock->stack_index;
+                               bNodeStack *ns= ntree->stack + sock->stack_index;
                                
                                if(sock->ns.data) {
                                        ns->data= sock->ns.data;
                                        sock->ns.data= NULL;
                                }
                        }
-               }               
+               }
                /* cannot initialize them while using in threads */
                if(ELEM3(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB)) {
                        curvemapping_initialize(node->storage);
@@ -1684,7 +1937,7 @@ static void composit_end_exec(bNodeTree *ntree, int is_group)
                        bNodeSocket *sock;
                
                        for(sock= node->outputs.first; sock; sock= sock->next) {
-                               ns= ntree->stack[0] + sock->stack_index;
+                               ns= ntree->stack + sock->stack_index;
                                if(ns->data) {
                                        sock->ns.data= ns->data;
                                        ns->data= NULL;
@@ -1702,7 +1955,7 @@ static void composit_end_exec(bNodeTree *ntree, int is_group)
        
        if(is_group==0) {
                /* internally, group buffers are not stored */
-               for(ns= ntree->stack[0], a=0; a<ntree->stacksize; a++, ns++) {
+               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);
@@ -1737,21 +1990,68 @@ static void group_tag_used_outputs(bNode *gnode, bNodeStack *stack)
        }
 }
 
+/* notes below are ancient! (ton) */
 /* stack indices make sure all nodes only write in allocated data, for making it thread safe */
 /* only root tree gets the stack, to enable instances to have own stack entries */
-/* only two threads now! */
 /* per tree (and per group) unique indices are created */
 /* the index_ext we need to be able to map from groups to the group-node own stack */
 
+typedef struct bNodeThreadStack {
+       struct bNodeThreadStack *next, *prev;
+       bNodeStack *stack;
+       int used;
+} bNodeThreadStack;
+
+static bNodeThreadStack *ntreeGetThreadStack(bNodeTree *ntree, int thread)
+{
+       ListBase *lb= &ntree->threadstack[thread];
+       bNodeThreadStack *nts;
+       
+       for(nts=lb->first; nts; nts=nts->next) {
+               if(!nts->used) {
+                       nts->used= 1;
+                       return nts;
+               }
+       }
+       nts= MEM_callocN(sizeof(bNodeThreadStack), "bNodeThreadStack");
+       nts->stack= MEM_dupallocN(ntree->stack);
+       nts->used= 1;
+       BLI_addtail(lb, nts);
+
+       return nts;
+}
+
+static void ntreeReleaseThreadStack(bNodeThreadStack *nts)
+{
+       nts->used= 0;
+}
+
+/* free texture delegates */
+static void tex_end_exec(bNodeTree *ntree)
+{
+       bNodeThreadStack *nts;
+       bNodeStack *ns;
+       int th, a;
+       
+       if(ntree->threadstack)
+               for(th=0; th<BLENDER_MAX_THREADS; th++)
+                       for(nts=ntree->threadstack[th].first; nts; nts=nts->next)
+                               for(ns= nts->stack, a=0; a<ntree->stacksize; a++, ns++)
+                                       if(ns->data)
+                                               MEM_freeN(ns->data);
+                                               
+}
+
 void ntreeBeginExecTree(bNodeTree *ntree)
 {
        /* let's make it sure */
        if(ntree->init & NTREE_EXEC_INIT)
                return;
        
-       /* allocate the stack pointer array */
-       ntree->stack= MEM_callocN(BLENDER_MAX_THREADS*sizeof(void *), "stack array");
-       
+       /* allocate the thread stack listbase array */
+       if(ntree->type!=NTREE_COMPOSIT)
+               ntree->threadstack= MEM_callocN(BLENDER_MAX_THREADS*sizeof(ListBase), "thread stack array");
+
        /* goes recursive over all groups */
        ntree->stacksize= ntree_begin_exec_tree(ntree);
 
@@ -1761,7 +2061,7 @@ void ntreeBeginExecTree(bNodeTree *ntree)
                int a;
                
                /* allocate the base stack */
-               ns=ntree->stack[0]= MEM_callocN(ntree->stacksize*sizeof(bNodeStack), "node stack");
+               ns=ntree->stack= MEM_callocN(ntree->stacksize*sizeof(bNodeStack), "node stack");
                
                /* tag inputs, the get_stack() gives own socket stackdata if not in use */
                for(a=0; a<ntree->stacksize; a++, ns++) ns->hasinput= 1;
@@ -1769,26 +2069,39 @@ void ntreeBeginExecTree(bNodeTree *ntree)
                /* tag used outputs, so we know when we can skip operations */
                for(node= ntree->nodes.first; node; node= node->next) {
                        bNodeSocket *sock;
+                       
+                       /* composite has own need_exec tag handling */
+                       if(ntree->type!=NTREE_COMPOSIT)
+                               node->need_exec= 1;
+
                        for(sock= node->inputs.first; sock; sock= sock->next) {
                                if(sock->link) {
-                                       ns= ntree->stack[0] + sock->link->fromsock->stack_index;
+                                       ns= ntree->stack + sock->link->fromsock->stack_index;
                                        ns->hasoutput= 1;
                                        ns->sockettype= sock->link->fromsock->type;
                                }
                                else
                                        sock->ns.sockettype= sock->type;
+                               
+                               if(sock->link) {
+                                       bNodeLink *link= sock->link;
+                                       /* this is the test for a cyclic case */
+                                       if(link->fromnode && link->tonode) {
+                                               if(link->fromnode->level >= link->tonode->level && link->tonode->level!=0xFFF);
+                                               else {
+                                                       node->need_exec= 0;
+                                               }
+                                       }
+                               }
                        }
+                       
                        if(node->type==NODE_GROUP && node->id)
-                               group_tag_used_outputs(node, ntree->stack[0]);
+                               group_tag_used_outputs(node, ntree->stack);
+                       
                }
                
-               /* composite does 1 node per thread, so no multiple stacks needed */
                if(ntree->type==NTREE_COMPOSIT)
                        composit_begin_exec(ntree, 0);
-               else {
-                       for(a=1; a<BLENDER_MAX_THREADS; a++)
-                               ntree->stack[a]= MEM_dupallocN(ntree->stack[0]);
-               }
        }
        
        ntree->init |= NTREE_EXEC_INIT;
@@ -1798,21 +2111,31 @@ void ntreeEndExecTree(bNodeTree *ntree)
 {
        
        if(ntree->init & NTREE_EXEC_INIT) {
+               bNodeThreadStack *nts;
                int a;
                
                /* another callback candidate! */
                if(ntree->type==NTREE_COMPOSIT)
                        composit_end_exec(ntree, 0);
+               else if(ntree->type==NTREE_TEXTURE)
+                       tex_end_exec(ntree);
                
                if(ntree->stack) {
-                       for(a=0; a<BLENDER_MAX_THREADS; a++)
-                               if(ntree->stack[a])
-                                       MEM_freeN(ntree->stack[a]);
-               
                        MEM_freeN(ntree->stack);
                        ntree->stack= NULL;
                }
 
+               if(ntree->threadstack) {
+                       for(a=0; a<BLENDER_MAX_THREADS; a++) {
+                               for(nts=ntree->threadstack[a].first; nts; nts=nts->next)
+                                       if (nts->stack) MEM_freeN(nts->stack);
+                               BLI_freelistN(&ntree->threadstack[a]);
+                       }
+
+                       MEM_freeN(ntree->threadstack);
+                       ntree->threadstack= NULL;
+               }
+
                ntree->init &= ~NTREE_EXEC_INIT;
        }
 }
@@ -1841,32 +2164,61 @@ void ntreeExecTree(bNodeTree *ntree, void *callerdata, int thread)
        bNodeStack *nsin[MAX_SOCKET];   /* arbitrary... watch this */
        bNodeStack *nsout[MAX_SOCKET];  /* arbitrary... watch this */
        bNodeStack *stack;
+       bNodeThreadStack *nts = NULL;
        
        /* only when initialized */
        if((ntree->init & NTREE_EXEC_INIT)==0)
                ntreeBeginExecTree(ntree);
                
-       stack= ntree->stack[thread];
+       /* composite does 1 node per thread, so no multiple stacks needed */
+       if(ntree->type==NTREE_COMPOSIT) {
+               stack= ntree->stack;
+       }
+       else {
+               nts= ntreeGetThreadStack(ntree, thread);
+               stack= nts->stack;
+       }
        
        for(node= ntree->nodes.first; node; node= node->next) {
-               if(node->typeinfo->execfunc) {
-                       node_get_stack(node, stack, nsin, nsout);
-                       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); 
+               if(node->need_exec) {
+                       if(node->typeinfo->execfunc) {
+                               node_get_stack(node, stack, nsin, nsout);
+                               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); 
+                       }
                }
        }
+
+       if(nts)
+               ntreeReleaseThreadStack(nts);
 }
 
 
 /* ***************************** threaded version for execute composite nodes ************* */
+/* these are nodes without input, only giving values */
+/* or nodes with only value inputs */
+static int node_only_value(bNode *node)
+{
+       bNodeSocket *sock;
+       
+       if(ELEM3(node->type, CMP_NODE_TIME, CMP_NODE_VALUE, CMP_NODE_RGB))
+               return 1;
+       
+       /* doing this for all node types goes wrong. memory free errors */
+       if(node->inputs.first && node->type==CMP_NODE_MAP_VALUE) {
+               int retval= 1;
+               for(sock= node->inputs.first; sock; sock= sock->next) {
+                       if(sock->link)
+                               retval &= node_only_value(sock->link->fromnode);
+               }
+               return retval;
+       }
+       return 0;
+}
 
-#define NODE_PROCESSING        1
-#define NODE_READY             2
-#define NODE_FINISHED  4
-#define NODE_FREEBUFS  8
 
 /* not changing info, for thread callback */
 typedef struct ThreadData {
@@ -1879,11 +2231,18 @@ static void *exec_composite_node(void *node_v)
        bNodeStack *nsin[MAX_SOCKET];   /* arbitrary... watch this */
        bNodeStack *nsout[MAX_SOCKET];  /* arbitrary... watch this */
        bNode *node= node_v;
-       ThreadData *thd= (ThreadData *)node->new_node; /* abuse */
+       ThreadData *thd= (ThreadData *)node->threaddata;
        
        node_get_stack(node, thd->stack, nsin, nsout);
        
-       if(node->typeinfo->execfunc) {
+       if((node->flag & NODE_MUTED) && (!node_only_value(node))) {
+               /* viewers we execute, for feedback to user */
+               if(ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) 
+                       node->typeinfo->execfunc(thd->rd, node, nsin, nsout);
+               else
+                       node_compo_pass_on(node, nsin, nsout);
+       }
+       else if(node->typeinfo->execfunc) {
                node->typeinfo->execfunc(thd->rd, node, nsin, nsout);
        }
        else if(node->type==NODE_GROUP && node->id) {
@@ -1894,27 +2253,6 @@ static void *exec_composite_node(void *node_v)
        return 0;
 }
 
-/* these are nodes without input, only giving values */
-/* or nodes with only value inputs */
-static int node_only_value(bNode *node)
-{
-       bNodeSocket *sock;
-       
-       if(ELEM3(node->type, CMP_NODE_TIME, CMP_NODE_VALUE, CMP_NODE_RGB))
-               return 1;
-       
-       /* doing this for all node types goes wrong. memory free errors */
-       if(node->inputs.first && node->type==CMP_NODE_MAP_VALUE) {
-               int retval= 1;
-               for(sock= node->inputs.first; sock; sock= sock->next) {
-                       if(sock->link)
-                               retval &= node_only_value(sock->link->fromnode);
-               }
-               return retval;
-       }
-       return 0;
-}
-
 /* return total of executable nodes, for timecursor */
 /* only compositor uses it */
 static int setExecutableNodes(bNodeTree *ntree, ThreadData *thd)
@@ -1957,8 +2295,10 @@ static int setExecutableNodes(bNodeTree *ntree, ThreadData *thd)
                        /* is sock in use? */
                        else if(sock->link) {
                                bNodeLink *link= sock->link;
+                               
                                /* this is the test for a cyclic case */
-                               if(link->fromnode->level >= link->tonode->level && link->tonode->level!=0xFFF) {
+                               if(link->fromnode==NULL || link->tonode==NULL);
+                               else if(link->fromnode->level >= link->tonode->level && link->tonode->level!=0xFFF) {
                                        if(link->fromnode->need_exec) {
                                                node->need_exec= 1;
                                                break;
@@ -1988,7 +2328,7 @@ static int setExecutableNodes(bNodeTree *ntree, ThreadData *thd)
                }
                else {
                        /* tag for getExecutableNode() */
-                       node->exec= NODE_READY|NODE_FINISHED;
+                       node->exec= NODE_READY|NODE_FINISHED|NODE_SKIPPED;
                        
                }
        }
@@ -2037,7 +2377,7 @@ 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[0] + sock->stack_index;
+                               bNodeStack *ns= ntree->stack + sock->stack_index;
                                if(ns->data) {
                                        free_compbuf(ns->data);
                                        ns->data= NULL;
@@ -2091,14 +2431,14 @@ void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview)
        
        /* setup callerdata for thread callback */
        thdata.rd= rd;
-       thdata.stack= ntree->stack[0];
+       thdata.stack= ntree->stack;
        
        /* fixed seed, for example noise texture */
        BLI_srandom(rd->cfra);
 
        /* sets need_exec tags in nodes */
        totnode= setExecutableNodes(ntree, &thdata);
-       
+
        BLI_init_threads(&threads, exec_composite_node, rd->threads);
        
        while(rendering) {
@@ -2106,17 +2446,17 @@ void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview)
                if(BLI_available_threads(&threads)) {
                        node= getExecutableNode(ntree);
                        if(node) {
-
+                               
                                if(ntree->timecursor)
-                                       ntree->timecursor(totnode);
+                                       ntree->timecursor(ntree->tch, totnode);
                                if(ntree->stats_draw) {
                                        char str[64];
                                        sprintf(str, "Compositing %d %s", totnode, node->name);
-                                       ntree->stats_draw(str);
+                                       ntree->stats_draw(ntree->sdh, str);
                                }
                                totnode--;
                                
-                               node->new_node = (bNode *)&thdata;
+                               node->threaddata = &thdata;
                                node->exec= NODE_PROCESSING;
                                BLI_insert_thread(&threads, node);
                        }
@@ -2128,7 +2468,7 @@ void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview)
                
                rendering= 0;
                /* test for ESC */
-               if(ntree->test_break && ntree->test_break()) {
+               if(ntree->test_break && ntree->test_break(ntree->tbh)) {
                        for(node= ntree->nodes.first; node; node= node->next)
                                node->exec |= NODE_READY;
                }
@@ -2137,7 +2477,7 @@ void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview)
                for(node= ntree->nodes.first; node; node= node->next) {
                        if(node->exec & NODE_READY) {
                                if((node->exec & NODE_FINISHED)==0) {
-                                       BLI_remove_thread(&threads, node);
+                                       BLI_remove_thread(&threads, node); /* this waits for running thread to finish btw */
                                        node->exec |= NODE_FINISHED;
                                        
                                        /* freeing unused buffers */
@@ -2149,93 +2489,326 @@ void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview)
                }
        }
        
-       
        BLI_end_threads(&threads);
        
        ntreeEndExecTree(ntree);
+}
+
+
+/* ********** copy composite tree entirely, to allow threaded exec ******************* */
+/* ***************** do NOT execute this in a thread!               ****************** */
+
+/* returns localized composite tree for execution in threads */
+/* local tree then owns all compbufs */
+bNodeTree *ntreeLocalize(bNodeTree *ntree)
+{
+       bNodeTree *ltree= ntreeCopyTree(ntree, 0);
+       bNode *node;
+       bNodeSocket *sock;
+       
+       /* move over the compbufs */
+       /* right after ntreeCopyTree() oldsock pointers are valid */
+       for(node= ntree->nodes.first; node; node= node->next) {
+               
+               /* store new_node pointer to original */
+               node->new_node->new_node= node;
+               /* 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 *)BKE_image_copy((Image *)node->id);
+                               else
+                                       node->new_node->id= NULL;
+                       }
+               }
+               
+               for(sock= node->outputs.first; sock; sock= sock->next) {
+                       
+                       sock->new_sock->ns.data= sock->ns.data;
+                       sock->ns.data= NULL;
+                       sock->new_sock->new_sock= sock;
+               }
+       }
        
+       return ltree;
+}
+
+static int node_exists(bNodeTree *ntree, bNode *testnode)
+{
+       bNode *node= ntree->nodes.first;
+       for(; node; node= node->next)
+               if(node==testnode)
+                       return 1;
+       return 0;
+}
+
+static int outsocket_exists(bNode *node, bNodeSocket *testsock)
+{
+       bNodeSocket *sock= node->outputs.first;
+       for(; sock; sock= sock->next)
+               if(sock==testsock)
+                       return 1;
+       return 0;
 }
 
 
+/* sync local composite with real tree */
+/* local composite is supposed to be running, be careful moving previews! */
+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(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;
+                               }
+                       }
+               }
+       }
+}
+
+/* merge local tree results back, and free local tree */
+/* we have to assume the editor already changed completely */
+void ntreeLocalMerge(bNodeTree *localtree, bNodeTree *ntree)
+{
+       bNode *lnode;
+       bNodeSocket *lsock;
+       
+       /* move over the compbufs and previews */
+       for(lnode= localtree->nodes.first; lnode; lnode= lnode->next) {
+               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;
+                       }
+                       
+                       if(ELEM(lnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
+                               if(lnode->id && (lnode->flag & NODE_DO_OUTPUT)) {
+                                       /* image_merge does sanity check for pointers */
+                                       BKE_image_merge((Image *)lnode->new_node->id, (Image *)lnode->id);
+                               }
+                       }
+                       
+                       for(lsock= lnode->outputs.first; lsock; lsock= lsock->next) {
+                               if(outsocket_exists(lnode->new_node, lsock->new_sock)) {
+                                       lsock->new_sock->ns.data= lsock->ns.data;
+                                       lsock->ns.data= NULL;
+                                       lsock->new_sock= NULL;
+                               }
+                       }
+               }
+       }
+       ntreeFreeTree(localtree);
+       MEM_freeN(localtree);
+}
+
+/* *********************************************** */
+
+/* GPU material from shader nodes */
+
+static void gpu_from_node_stack(ListBase *sockets, bNodeStack **ns, GPUNodeStack *gs)
+{
+       bNodeSocket *sock;
+       int i;
+
+       for (sock=sockets->first, i=0; sock; sock=sock->next, i++) {
+               memset(&gs[i], 0, sizeof(gs[i]));
+
+       QUATCOPY(gs[i].vec, ns[i]->vec);
+               gs[i].link= ns[i]->data;
+
+               if (sock->type == SOCK_VALUE)
+                       gs[i].type= GPU_FLOAT;
+               else if (sock->type == SOCK_VECTOR)
+                       gs[i].type= GPU_VEC3;
+               else if (sock->type == SOCK_RGBA)
+                       gs[i].type= GPU_VEC4;
+               else
+                       gs[i].type= GPU_NONE;
+
+               gs[i].name = "";
+               gs[i].hasinput= ns[i]->hasinput && ns[i]->data;
+               gs[i].hasoutput= ns[i]->hasinput && ns[i]->data;
+               gs[i].sockettype= ns[i]->sockettype;
+       }
+
+       gs[i].type= GPU_NONE;
+}
+
+static void data_from_gpu_stack(ListBase *sockets, bNodeStack **ns, GPUNodeStack *gs)
+{
+       bNodeSocket *sock;
+       int i;
+
+       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)
+{
+       bNode *node;
+       bNodeTree *ntree= (bNodeTree *)gnode->id;
+       bNodeStack *nsin[MAX_SOCKET];   /* arbitrary... watch this */
+       bNodeStack *nsout[MAX_SOCKET];  /* arbitrary... watch this */
+       GPUNodeStack gpuin[MAX_SOCKET+1], gpuout[MAX_SOCKET+1];
+       int doit = 0;
+       
+       if(ntree==NULL) return;
+       
+       stack+= gnode->stack_index;
+               
+       for(node= ntree->nodes.first; node; node= node->next) {
+               if(node->typeinfo->gpufunc) {
+                       group_node_get_stack(node, stack, nsin, nsout, in, out);
+
+                       doit = 0;
+                       
+                       /* for groups, only execute outputs for edited group */
+                       if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) {
+                               if(gnode->flag & NODE_GROUP_EDIT)
+                                       if(node->flag & NODE_DO_OUTPUT)
+                                               doit = 1;
+                       }
+                       else
+                               doit = 1;
+
+                       if(doit)  {
+                               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);
+                       }
+               }
+       }
+}
+
+void ntreeGPUMaterialNodes(bNodeTree *ntree, GPUMaterial *mat)
+{
+       bNode *node;
+       bNodeStack *stack;
+       bNodeStack *nsin[MAX_SOCKET];   /* arbitrary... watch this */
+       bNodeStack *nsout[MAX_SOCKET];  /* arbitrary... watch this */
+       GPUNodeStack gpuin[MAX_SOCKET+1], gpuout[MAX_SOCKET+1];
+
+       if((ntree->init & NTREE_EXEC_INIT)==0)
+               ntreeBeginExecTree(ntree);
+
+       stack= ntree->stack;
+
+       for(node= ntree->nodes.first; node; node= node->next) {
+               if(node->typeinfo->gpufunc) {
+                       node_get_stack(node, stack, nsin, nsout);
+                       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);
+               }
+       }
+
+       ntreeEndExecTree(ntree);
+}
+
 /* **************** call to switch lamploop for material node ************ */
 
 void (*node_shader_lamp_loop)(struct ShadeInput *, struct ShadeResult *);
 
 void set_node_shader_lamp_loop(void (*lamp_loop_func)(ShadeInput *, ShadeResult *))
 {
-   node_shader_lamp_loop= lamp_loop_func;
+       node_shader_lamp_loop= lamp_loop_func;
 }
 
 /* clumsy checking... should do dynamic outputs once */
 static void force_hidden_passes(bNode *node, int passflag)
 {
-   bNodeSocket *sock;
-
-   for(sock= node->outputs.first; sock; sock= sock->next)
-      sock->flag &= ~SOCK_UNAVAIL;
-
-   sock= BLI_findlink(&node->outputs, RRES_OUT_Z);
-   if(!(passflag & SCE_PASS_Z)) sock->flag |= SOCK_UNAVAIL;
-   sock= BLI_findlink(&node->outputs, RRES_OUT_NORMAL);
-   if(!(passflag & SCE_PASS_NORMAL)) sock->flag |= SOCK_UNAVAIL;
-   sock= BLI_findlink(&node->outputs, RRES_OUT_VEC);
-   if(!(passflag & SCE_PASS_VECTOR)) sock->flag |= SOCK_UNAVAIL;
-   sock= BLI_findlink(&node->outputs, RRES_OUT_UV);
-   if(!(passflag & SCE_PASS_UV)) sock->flag |= SOCK_UNAVAIL;
-   sock= BLI_findlink(&node->outputs, RRES_OUT_RGBA);
-   if(!(passflag & SCE_PASS_RGBA)) sock->flag |= SOCK_UNAVAIL;
-   sock= BLI_findlink(&node->outputs, RRES_OUT_DIFF);
-   if(!(passflag & SCE_PASS_DIFFUSE)) sock->flag |= SOCK_UNAVAIL;
-   sock= BLI_findlink(&node->outputs, RRES_OUT_SPEC);
-   if(!(passflag & SCE_PASS_SPEC)) sock->flag |= SOCK_UNAVAIL;
-   sock= BLI_findlink(&node->outputs, RRES_OUT_SHADOW);
-   if(!(passflag & SCE_PASS_SHADOW)) sock->flag |= SOCK_UNAVAIL;
-   sock= BLI_findlink(&node->outputs, RRES_OUT_AO);
-   if(!(passflag & SCE_PASS_AO)) sock->flag |= SOCK_UNAVAIL;
-   sock= BLI_findlink(&node->outputs, RRES_OUT_REFLECT);
-   if(!(passflag & SCE_PASS_REFLECT)) sock->flag |= SOCK_UNAVAIL;
-   sock= BLI_findlink(&node->outputs, RRES_OUT_REFRACT);
-   if(!(passflag & SCE_PASS_REFRACT)) sock->flag |= SOCK_UNAVAIL;
-   sock= BLI_findlink(&node->outputs, RRES_OUT_RADIO);
-   if(!(passflag & SCE_PASS_RADIO)) sock->flag |= SOCK_UNAVAIL;
-   sock= BLI_findlink(&node->outputs, RRES_OUT_INDEXOB);
-   if(!(passflag & SCE_PASS_INDEXOB)) sock->flag |= SOCK_UNAVAIL;
-
+       bNodeSocket *sock;
+       
+       for(sock= node->outputs.first; sock; sock= sock->next)
+               sock->flag &= ~SOCK_UNAVAIL;
+       
+       sock= BLI_findlink(&node->outputs, RRES_OUT_Z);
+       if(!(passflag & SCE_PASS_Z)) sock->flag |= SOCK_UNAVAIL;
+       sock= BLI_findlink(&node->outputs, RRES_OUT_NORMAL);
+       if(!(passflag & SCE_PASS_NORMAL)) sock->flag |= SOCK_UNAVAIL;
+       sock= BLI_findlink(&node->outputs, RRES_OUT_VEC);
+       if(!(passflag & SCE_PASS_VECTOR)) sock->flag |= SOCK_UNAVAIL;
+       sock= BLI_findlink(&node->outputs, RRES_OUT_UV);
+       if(!(passflag & SCE_PASS_UV)) sock->flag |= SOCK_UNAVAIL;
+       sock= BLI_findlink(&node->outputs, RRES_OUT_RGBA);
+       if(!(passflag & SCE_PASS_RGBA)) sock->flag |= SOCK_UNAVAIL;
+       sock= BLI_findlink(&node->outputs, RRES_OUT_DIFF);
+       if(!(passflag & SCE_PASS_DIFFUSE)) sock->flag |= SOCK_UNAVAIL;
+       sock= BLI_findlink(&node->outputs, RRES_OUT_SPEC);
+       if(!(passflag & SCE_PASS_SPEC)) sock->flag |= SOCK_UNAVAIL;
+       sock= BLI_findlink(&node->outputs, RRES_OUT_SHADOW);
+       if(!(passflag & SCE_PASS_SHADOW)) sock->flag |= SOCK_UNAVAIL;
+       sock= BLI_findlink(&node->outputs, RRES_OUT_AO);
+       if(!(passflag & SCE_PASS_AO)) sock->flag |= SOCK_UNAVAIL;
+       sock= BLI_findlink(&node->outputs, RRES_OUT_REFLECT);
+       if(!(passflag & SCE_PASS_REFLECT)) sock->flag |= SOCK_UNAVAIL;
+       sock= BLI_findlink(&node->outputs, RRES_OUT_REFRACT);
+       if(!(passflag & SCE_PASS_REFRACT)) sock->flag |= SOCK_UNAVAIL;
+       sock= BLI_findlink(&node->outputs, RRES_OUT_RADIO);
+       if(!(passflag & SCE_PASS_RADIO)) sock->flag |= SOCK_UNAVAIL;
+       sock= BLI_findlink(&node->outputs, RRES_OUT_INDEXOB);
+       if(!(passflag & SCE_PASS_INDEXOB)) sock->flag |= SOCK_UNAVAIL;
+       sock= BLI_findlink(&node->outputs, RRES_OUT_MIST);
+       if(!(passflag & SCE_PASS_MIST)) sock->flag |= SOCK_UNAVAIL;
+       
 }
 
 /* based on rules, force sockets hidden always */
-void ntreeCompositForceHidden(bNodeTree *ntree)
-{
-   bNode *node;
-
-   if(ntree==NULL) return;
-
-   for(node= ntree->nodes.first; node; node= node->next) {
-      if( node->type==CMP_NODE_R_LAYERS) {
-         Scene *sce= node->id?(Scene *)node->id:G.scene; /* G.scene is WEAK! */
-         SceneRenderLayer *srl= BLI_findlink(&sce->r.layers, node->custom1);
-         if(srl)
-            force_hidden_passes(node, srl->passflag);
-      }
-      else if( node->type==CMP_NODE_IMAGE) {
-         Image *ima= (Image *)node->id;
-         if(ima) {
-            if(ima->rr) {
-               ImageUser *iuser= node->storage;
-               RenderLayer *rl= BLI_findlink(&ima->rr->layers, iuser->layer);
-               if(rl)
-                  force_hidden_passes(node, rl->passflag);
-               else
-                  force_hidden_passes(node, 0);
-            }
-            else if(ima->type!=IMA_TYPE_MULTILAYER) {  /* if ->rr not yet read we keep inputs */
-               force_hidden_passes(node, RRES_OUT_Z);
-            }
-         }
-         else
-            force_hidden_passes(node, 0);
-      }
-   }
+void ntreeCompositForceHidden(bNodeTree *ntree, Scene *curscene)
+{
+       bNode *node;
+       
+       if(ntree==NULL) return;
+       
+       for(node= ntree->nodes.first; node; node= node->next) {
+               if( node->type==CMP_NODE_R_LAYERS) {
+                       Scene *sce= node->id?(Scene *)node->id:curscene;
+                       SceneRenderLayer *srl= BLI_findlink(&sce->r.layers, node->custom1);
+                       if(srl)
+                               force_hidden_passes(node, srl->passflag);
+               }
+               else if( node->type==CMP_NODE_IMAGE) {
+                       Image *ima= (Image *)node->id;
+                       if(ima) {
+                               if(ima->rr) {
+                                       ImageUser *iuser= node->storage;
+                                       RenderLayer *rl= BLI_findlink(&ima->rr->layers, iuser->layer);
+                                       if(rl)
+                                               force_hidden_passes(node, rl->passflag);
+                                       else
+                                               force_hidden_passes(node, 0);
+                               }
+                               else if(ima->type!=IMA_TYPE_MULTILAYER) {       /* if ->rr not yet read we keep inputs */
+                                       force_hidden_passes(node, RRES_OUT_Z);
+                               }
+                               else
+                                       force_hidden_passes(node, 0);
+                       }
+                       else
+                               force_hidden_passes(node, 0);
+               }
+       }
 
 }
 
@@ -2243,76 +2816,97 @@ void ntreeCompositForceHidden(bNodeTree *ntree)
 /* need to do all scenes, to prevent errors when you re-render 1 scene */
 void ntreeCompositTagRender(Scene *curscene)
 {
-   Scene *sce;
-
-   for(sce= G.main->scene.first; sce; sce= sce->id.next) {
-      if(sce->nodetree) {
-         bNode *node;
-
-         for(node= sce->nodetree->nodes.first; node; node= node->next) {
-            if(node->id==(ID *)curscene || node->type==CMP_NODE_COMPOSITE)
-               NodeTagChanged(sce->nodetree, node);
-         }
-      }
-   }
+       Scene *sce;
+       
+       for(sce= G.main->scene.first; sce; sce= sce->id.next) {
+               if(sce->nodetree) {
+                       bNode *node;
+                       
+                       for(node= sce->nodetree->nodes.first; node; node= node->next) {
+                               if(node->id==(ID *)curscene || node->type==CMP_NODE_COMPOSITE)
+                                       NodeTagChanged(sce->nodetree, node);
+                       }
+               }
+       }
 }
 
 /* tags nodes that have animation capabilities */
 int ntreeCompositTagAnimated(bNodeTree *ntree)
 {
-   bNode *node;
-   int tagged= 0;
-
-   if(ntree==NULL) return 0;
-
-   for(node= ntree->nodes.first; node; node= node->next) {
-      if(node->type==CMP_NODE_IMAGE) {
-         Image *ima= (Image *)node->id;
-         if(ima && ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
-            NodeTagChanged(ntree, node);
-            tagged= 1;
-         }
-      }
-      else if(node->type==CMP_NODE_TIME) {
-         NodeTagChanged(ntree, node);
-         tagged= 1;
-      }
-      else if(node->type==CMP_NODE_R_LAYERS) {
-         NodeTagChanged(ntree, node);
-         tagged= 1;
-      }
-      else if(node->type==NODE_GROUP) {
-         if( ntreeCompositTagAnimated((bNodeTree *)node->id) ) {
-            NodeTagChanged(ntree, node);
-         }
-      }
-   }
-
-   return tagged;
+       bNode *node;
+       int tagged= 0;
+       
+       if(ntree==NULL) return 0;
+       
+       for(node= ntree->nodes.first; node; node= node->next) {
+               if(node->type==CMP_NODE_IMAGE) {
+                       Image *ima= (Image *)node->id;
+                       if(ima && ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
+                               NodeTagChanged(ntree, node);
+                               tagged= 1;
+                       }
+               }
+               else if(node->type==CMP_NODE_TIME) {
+                       NodeTagChanged(ntree, node);
+                       tagged= 1;
+               }
+               else if(node->type==CMP_NODE_R_LAYERS) {
+                       NodeTagChanged(ntree, node);
+                       tagged= 1;
+               }
+               else if(node->type==NODE_GROUP) {
+                       if( ntreeCompositTagAnimated((bNodeTree *)node->id) ) {
+                               NodeTagChanged(ntree, node);
+                       }
+               }
+       }
+       
+       return tagged;
 }
 
 
 /* called from image window preview */
 void ntreeCompositTagGenerators(bNodeTree *ntree)
 {
-   bNode *node;
-
-   if(ntree==NULL) return;
+       bNode *node;
+       
+       if(ntree==NULL) return;
+       
+       for(node= ntree->nodes.first; node; node= node->next) {
+               if( ELEM(node->type, CMP_NODE_R_LAYERS, CMP_NODE_IMAGE))
+                       NodeTagChanged(ntree, node);
+       }
+}
 
-   for(node= ntree->nodes.first; node; node= node->next) {
-      if( ELEM(node->type, CMP_NODE_R_LAYERS, CMP_NODE_IMAGE))
-         NodeTagChanged(ntree, node);
-   }
+int ntreeTexTagAnimated(bNodeTree *ntree)
+{
+       bNode *node;
+       
+       if(ntree==NULL) return 0;
+       
+       for(node= ntree->nodes.first; node; node= node->next) {
+               if(node->type==TEX_NODE_CURVE_TIME) {
+                       NodeTagChanged(ntree, node);
+                       return 1;
+               }
+               else if(node->type==NODE_GROUP) {
+                       if( ntreeTexTagAnimated((bNodeTree *)node->id) ) {
+                               return 1;
+                       }
+               }
+       }
+       
+       return 0;
 }
 
 /* ************* node definition init ********** */
 
-static bNodeType *is_nodetype_registered(ListBase *typelist, int type) 
+static bNodeType *is_nodetype_registered(ListBase *typelist, int type, ID *id
 {
        bNodeType *ntype= typelist->first;
        
        for(;ntype; ntype= ntype->next )
-               if(ntype->type==type)
+               if(ntype->type==type && ntype->id==id)
                        return ntype;
        
        return NULL;
@@ -2321,10 +2915,10 @@ static bNodeType *is_nodetype_registered(ListBase *typelist, int type)
 /* type can be from a static array, we make copy for duplicate types (like group) */
 void nodeRegisterType(ListBase *typelist, const bNodeType *ntype) 
 {
-       bNodeType *found= is_nodetype_registered(typelist, ntype->type);
+       bNodeType *found= is_nodetype_registered(typelist, ntype->type, ntype->id);
        
        if(found==NULL) {
-               bNodeType *ntypen= MEM_mallocN(sizeof(bNodeType), "node type");
+               bNodeType *ntypen= MEM_callocN(sizeof(bNodeType), "node type");
                *ntypen= *ntype;
                BLI_addtail(typelist, ntypen);
        }
@@ -2348,19 +2942,25 @@ static void registerCompositNodes(ListBase *ntypelist)
        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_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);
@@ -2374,7 +2974,8 @@ static void registerCompositNodes(ListBase *ntypelist)
        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_chroma);
        nodeRegisterType(ntypelist, &cmp_node_channel_matte);
@@ -2385,8 +2986,12 @@ static void registerCompositNodes(ListBase *ntypelist)
        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);
 }
 
 static void registerShaderNodes(ListBase *ntypelist) 
@@ -2406,21 +3011,104 @@ static void registerShaderNodes(ListBase *ntypelist)
        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);
+}
+
+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);
+}
+
+static void remove_dynamic_typeinfos(ListBase *list)
+{
+       bNodeType *ntype= list->first;
+       bNodeType *next= NULL;
+       while(ntype) {
+               next= ntype->next;
+               if(ntype->type==NODE_DYNAMIC && ntype->id!=NULL) {
+                       BLI_remlink(list, ntype);
+                       if(ntype->inputs) {
+                               bNodeSocketType *sock= ntype->inputs;
+                               while(sock->type!=-1) {
+                                       MEM_freeN(sock->name);
+                                       sock++;
+                               }
+                               MEM_freeN(ntype->inputs);
+                       }
+                       if(ntype->outputs) {
+                               bNodeSocketType *sock= ntype->outputs;
+                               while(sock->type!=-1) {
+                                       MEM_freeN(sock->name);
+                                       sock++;
+                               }
+                               MEM_freeN(ntype->outputs);
+                       }
+                       if(ntype->name) {
+                               MEM_freeN(ntype->name);
+                       }
+                       MEM_freeN(ntype);
+               }
+               ntype= next;
+       }
 }
 
 void init_nodesystem(void) 
 {
        registerCompositNodes(&node_all_composit);
        registerShaderNodes(&node_all_shaders);
+       registerTextureNodes(&node_all_textures);
 }
 
 void free_nodesystem(void) 
 {
+       /*remove_dynamic_typeinfos(&node_all_composit);*/ /* unused for now */
        BLI_freelistN(&node_all_composit);
+       remove_dynamic_typeinfos(&node_all_shaders);
        BLI_freelistN(&node_all_shaders);
+       BLI_freelistN(&node_all_textures);
 }
-
-