Patch #34204: [Render Animation] Fails with "Error: Specified sample_fmt is not suppo...
[blender.git] / source / blender / blenkernel / intern / node.c
index 56b1c0a..974a564 100644 (file)
 
 #include "DNA_action_types.h"
 #include "DNA_anim_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
 #include "DNA_node_types.h"
 #include "DNA_node_types.h"
 #include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_world_types.h"
 
 #include "BLI_string.h"
 #include "BLI_math.h"
@@ -58,8 +62,6 @@
 #include "BKE_library.h"
 #include "BKE_main.h"
 #include "BKE_node.h"
-#include "BKE_utildefines.h"
-#include "BKE_utildefines.h"
 
 #include "RNA_access.h"
 
@@ -91,8 +93,8 @@ bNodeTreeType *ntreeGetType(int type)
 static bNodeType *node_get_type(bNodeTree *ntree, int type)
 {
        bNodeType *ntype = ntreeGetType(ntree->type)->node_types.first;
-       for (; ntype; ntype= ntype->next)
-               if (ntype->type==type)
+       for (; ntype; ntype = ntype->next)
+               if (ntype->type == type)
                        return ntype;
        
        return NULL;
@@ -105,12 +107,12 @@ bNodeType *ntreeGetNodeType(bNodeTree *ntree)
 
 bNodeSocketType *ntreeGetSocketType(int type)
 {
-       static bNodeSocketType *types[NUM_SOCKET_TYPES]= {NULL};
+       static bNodeSocketType *types[NUM_SOCKET_TYPES] = {NULL};
        static int types_init = 1;
 
        if (types_init) {
                node_socket_type_init(types);
-               types_init= 0;
+               types_init = 0;
        }
 
        if (type < NUM_SOCKET_TYPES) {
@@ -125,8 +127,8 @@ void ntreeInitTypes(bNodeTree *ntree)
 {
        bNode *node, *next;
        
-       for (node= ntree->nodes.first; node; node= next) {
-               next= node->next;
+       for (node = ntree->nodes.first; node; node = next) {
+               next = node->next;
                
                node->typeinfo = node_get_type(ntree, node->type);
 
@@ -143,12 +145,13 @@ static bNodeSocket *make_socket(bNodeTree *UNUSED(ntree), int in_out, const char
 {
        bNodeSocket *sock;
        
-       sock= MEM_callocN(sizeof(bNodeSocket), "sock");
+       sock = MEM_callocN(sizeof(bNodeSocket), "sock");
        
        BLI_strncpy(sock->name, name, NODE_MAXSTR);
-       sock->limit = (in_out==SOCK_IN ? 1 : 0xFFF);
-       sock->type= type;
+       sock->limit = (in_out == SOCK_IN ? 1 : 0xFFF);
+       sock->type = type;
        sock->storage = NULL;
+       sock->flag |= SOCK_COLLAPSED;
        
        sock->default_value = node_socket_make_default_value(type);
        node_socket_init_default_value(type, sock->default_value);
@@ -159,9 +162,9 @@ static bNodeSocket *make_socket(bNodeTree *UNUSED(ntree), int in_out, const char
 bNodeSocket *nodeAddSocket(bNodeTree *ntree, bNode *node, int in_out, const char *name, int type)
 {
        bNodeSocket *sock = make_socket(ntree, in_out, name, type);
-       if (in_out==SOCK_IN)
+       if (in_out == SOCK_IN)
                BLI_addtail(&node->inputs, sock);
-       else if (in_out==SOCK_OUT)
+       else if (in_out == SOCK_OUT)
                BLI_addtail(&node->outputs, sock);
        
        node->update |= NODE_UPDATE;
@@ -172,9 +175,9 @@ bNodeSocket *nodeAddSocket(bNodeTree *ntree, bNode *node, int in_out, const char
 bNodeSocket *nodeInsertSocket(bNodeTree *ntree, bNode *node, int in_out, bNodeSocket *next_sock, const char *name, int type)
 {
        bNodeSocket *sock = make_socket(ntree, in_out, name, type);
-       if (in_out==SOCK_IN)
+       if (in_out == SOCK_IN)
                BLI_insertlinkbefore(&node->inputs, next_sock, sock);
-       else if (in_out==SOCK_OUT)
+       else if (in_out == SOCK_OUT)
                BLI_insertlinkbefore(&node->outputs, next_sock, sock);
        
        node->update |= NODE_UPDATE;
@@ -186,9 +189,9 @@ void nodeRemoveSocket(bNodeTree *ntree, bNode *node, bNodeSocket *sock)
 {
        bNodeLink *link, *next;
        
-       for (link= ntree->links.first; link; link= next) {
-               next= link->next;
-               if (link->fromsock==sock || link->tosock==sock) {
+       for (link = ntree->links.first; link; link = next) {
+               next = link->next;
+               if (link->fromsock == sock || link->tosock == sock) {
                        nodeRemLink(ntree, link);
                }
        }
@@ -208,17 +211,17 @@ void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node)
        bNodeSocket *sock;
        bNodeLink *link, *next;
        
-       for (link= ntree->links.first; link; link= next) {
-               next= link->next;
-               if (link->fromnode==node || link->tonode==node) {
+       for (link = ntree->links.first; link; link = next) {
+               next = link->next;
+               if (link->fromnode == node || link->tonode == node) {
                        nodeRemLink(ntree, link);
                }
        }
        
-       for (sock=node->inputs.first; sock; sock=sock->next)
+       for (sock = node->inputs.first; sock; sock = sock->next)
                node_socket_free_default_value(sock->type, sock->default_value);
        BLI_freelistN(&node->inputs);
-       for (sock=node->outputs.first; sock; sock=sock->next)
+       for (sock = node->outputs.first; sock; sock = sock->next)
                node_socket_free_default_value(sock->type, sock->default_value);
        BLI_freelistN(&node->outputs);
        
@@ -236,20 +239,20 @@ int nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **nodep, int *sockin
 {
        bNode *node;
        bNodeSocket *tsock;
-       int index= 0;
+       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) {
-                               if (in_out) *in_out= SOCK_IN;
+       for (node = ntree->nodes.first; node; node = node->next) {
+               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) {
-                               if (in_out) *in_out= SOCK_OUT;
+               for (index = 0, tsock = node->outputs.first; tsock; tsock = tsock->next, index++) {
+                       if (tsock == sock) {
+                               if (in_out) *in_out = SOCK_OUT;
                                break;
                        }
                }
@@ -258,12 +261,12 @@ int nodeFindNode(bNodeTree *ntree, bNodeSocket *sock, bNode **nodep, int *sockin
        }
 
        if (node) {
-               *nodep= node;
-               if (sockindex) *sockindex= index;
+               *nodep = node;
+               if (sockindex) *sockindex = index;
                return 1;
        }
        
-       *nodep= NULL;
+       *nodep = NULL;
        return 0;
 }
 
@@ -274,7 +277,7 @@ static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType
        /* bNodeSocket *sock; */ /* UNUSED */
 
        if (ntype->inputs) {
-               sockdef= ntype->inputs;
+               sockdef = ntype->inputs;
                while (sockdef->type != -1) {
                        /* sock = */ node_add_input_from_template(ntree, node, sockdef);
                        
@@ -282,7 +285,7 @@ static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType
                }
        }
        if (ntype->outputs) {
-               sockdef= ntype->outputs;
+               sockdef = ntype->outputs;
                while (sockdef->type != -1) {
                        /* sock = */ node_add_output_from_template(ntree, node, sockdef);
                        
@@ -302,7 +305,7 @@ bNode *nodeAddNode(bNodeTree *ntree, struct bNodeTemplate *ntemp)
        bNode *node;
        bNodeType *ntype;
        
-       ntype= node_get_type(ntree, ntemp->type);
+       ntype = node_get_type(ntree, ntemp->type);
        if (ntype == NULL) {
                printf("nodeAddNodeType() error: '%d' type invalid\n", ntemp->type);
                return NULL;
@@ -311,27 +314,30 @@ bNode *nodeAddNode(bNodeTree *ntree, struct bNodeTemplate *ntemp)
        if (!nodeValid(ntree, ntemp))
                return NULL;
        
-       node= MEM_callocN(sizeof(bNode), "new node");
-       node->type= ntype->type;
-       node->typeinfo= ntype;
-       node->flag= NODE_SELECT|ntype->flag;
-       node->width= ntype->width;
-       node->miniwidth= 42.0f;
-       node->height= ntype->height;
-       node->color[0] = node->color[1] = node->color[2] = 0.608;       /* default theme color */
+       node = MEM_callocN(sizeof(bNode), "new node");
+       node->type = ntype->type;
+       node->typeinfo = ntype;
+       node->flag = NODE_SELECT | ntype->flag;
+       node->width = ntype->width;
+       node->miniwidth = 42.0f;
+       node->height = ntype->height;
+       node->color[0] = node->color[1] = node->color[2] = 0.608;   /* default theme color */
        
        node_add_sockets_from_type(ntree, node, ntype);
 
        BLI_addtail(&ntree->nodes, node);
        
-       if (ntype->initfunc!=NULL)
+       if (ntype->initfunc != NULL)
                ntype->initfunc(ntree, node, ntemp);
 
        /* initialize the node name with the node label.
-        * note: do this after the initfunc so nodes get
-        * their data set which may be used in naming
+        * note: do this after the initfunc so nodes get their data set which may be used in naming
         * (node groups for example) */
-       BLI_strncpy(node->name, nodeLabel(node), NODE_MAXSTR);
+       /* XXX Do not use nodeLabel() here, it returns translated content, which should *only* be used
+        *     in UI, *never* in data...
+        *     This solution may be a bit rougher than nodeLabel()'s returned string, but it's simpler
+        *     than adding a "no translate" flag to this func (and labelfunc() as well). */
+       BLI_strncpy(node->name, node->typeinfo->name, NODE_MAXSTR);
        nodeUniqueName(ntree, node);
        
        ntree->update |= NTREE_UPDATE_NODES;
@@ -343,19 +349,23 @@ bNode *nodeAddNode(bNodeTree *ntree, struct bNodeTemplate *ntemp)
 /* ntree is the target tree */
 bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node)
 {
-       bNode *nnode= MEM_callocN(sizeof(bNode), "dupli node");
+       bNode *nnode = MEM_callocN(sizeof(bNode), "dupli node");
        bNodeSocket *sock, *oldsock;
+       bNodeLink *link, *oldlink;
 
-       *nnode= *node;
-       nodeUniqueName(ntree, nnode);
-       
-       BLI_addtail(&ntree->nodes, nnode);
+       *nnode = *node;
+       /* can be called for nodes outside a node tree (e.g. clipboard) */
+       if (ntree) {
+               nodeUniqueName(ntree, nnode);
+
+               BLI_addtail(&ntree->nodes, nnode);
+       }
 
        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;
-               sock->stack_index= 0;
+       oldsock = node->inputs.first;
+       for (sock = nnode->inputs.first; sock; sock = sock->next, oldsock = oldsock->next) {
+               oldsock->new_sock = sock;
+               sock->stack_index = 0;
                
                sock->default_value = node_socket_make_default_value(oldsock->type);
                node_socket_copy_default_value(oldsock->type, sock->default_value, oldsock->default_value);
@@ -367,10 +377,10 @@ bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node)
        }
        
        BLI_duplicatelist(&nnode->outputs, &node->outputs);
-       oldsock= node->outputs.first;
-       for (sock= nnode->outputs.first; sock; sock= sock->next, oldsock= oldsock->next) {
-               oldsock->new_sock= sock;
-               sock->stack_index= 0;
+       oldsock = node->outputs.first;
+       for (sock = nnode->outputs.first; sock; sock = sock->next, oldsock = oldsock->next) {
+               oldsock->new_sock = sock;
+               sock->stack_index = 0;
                
                sock->default_value = node_socket_make_default_value(oldsock->type);
                node_socket_copy_default_value(oldsock->type, sock->default_value, oldsock->default_value);
@@ -381,16 +391,37 @@ bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node)
                sock->cache = NULL;
        }
        
+       BLI_duplicatelist(&nnode->internal_links, &node->internal_links);
+       oldlink = node->internal_links.first;
+       for (link = nnode->internal_links.first; link; link = link->next, oldlink = oldlink->next) {
+               link->fromnode = nnode;
+               link->tonode = nnode;
+               link->fromsock = link->fromsock->new_sock;
+               link->tosock = link->tosock->new_sock;
+       }
+       
        /* don't increase node->id users, freenode doesn't decrement either */
        
        if (node->typeinfo->copystoragefunc)
                node->typeinfo->copystoragefunc(node, nnode);
        
-       node->new_node= nnode;
-       nnode->new_node= NULL;
-       nnode->preview= NULL;
+       node->new_node = nnode;
+       nnode->new_node = NULL;
        
-       ntree->update |= NTREE_UPDATE_NODES;
+       /* only shader nodes get pleasant preview updating this way, compo uses own system */
+       if (node->preview) {
+               if (ntree && (ntree->type == NTREE_SHADER)) {
+                       nnode->preview = MEM_dupallocN(node->preview);
+                       if (node->preview->rect)
+                               nnode->preview->rect = MEM_dupallocN(node->preview->rect);
+               }
+               else {
+                       nnode->preview = NULL;
+               }
+       }
+       
+       if (ntree)
+               ntree->update |= NTREE_UPDATE_NODES;
        
        return nnode;
 }
@@ -399,108 +430,115 @@ bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node)
 bNodeLink *nodeAddLink(bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, bNode *tonode, bNodeSocket *tosock)
 {
        bNodeSocket *sock;
-       bNodeLink *link= NULL; 
-       int from= 0, to= 0;
+       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)
+               for (sock = fromnode->outputs.first; sock; sock = sock->next)
+                       if (sock == fromsock)
                                break;
                if (sock)
-                       from= 1; /* OK */
+                       from = 1;  /* OK */
                else {
-                       for (sock= fromnode->inputs.first; sock; sock= sock->next)
-                               if (sock==fromsock)
+                       for (sock = fromnode->inputs.first; sock; sock = sock->next)
+                               if (sock == fromsock)
                                        break;
                        if (sock)
-                               from= -1; /* OK but flip */
+                               from = -1;  /* OK but flip */
                }
        }
-       else {
+       else if (ntree) {
                /* check tree sockets */
-               for (sock= ntree->inputs.first; sock; sock= sock->next)
-                       if (sock==fromsock)
+               for (sock = ntree->inputs.first; sock; sock = sock->next)
+                       if (sock == fromsock)
                                break;
                if (sock)
-                       from= 1; /* OK */
+                       from = 1;  /* OK */
                else {
-                       for (sock= ntree->outputs.first; sock; sock= sock->next)
-                               if (sock==fromsock)
+                       for (sock = ntree->outputs.first; sock; sock = sock->next)
+                               if (sock == fromsock)
                                        break;
                        if (sock)
-                               from= -1; /* OK but flip */
+                               from = -1;  /* OK but flip */
                }
        }
        if (tonode) {
-               for (sock= tonode->inputs.first; sock; sock= sock->next)
-                       if (sock==tosock)
+               for (sock = tonode->inputs.first; sock; sock = sock->next)
+                       if (sock == tosock)
                                break;
                if (sock)
-                       to= 1; /* OK */
+                       to = 1;  /* OK */
                else {
-                       for (sock= tonode->outputs.first; sock; sock= sock->next)
-                               if (sock==tosock)
+                       for (sock = tonode->outputs.first; sock; sock = sock->next)
+                               if (sock == tosock)
                                        break;
                        if (sock)
-                               to= -1; /* OK but flip */
+                               to = -1;  /* OK but flip */
                }
        }
-       else {
+       else if (ntree) {
                /* check tree sockets */
-               for (sock= ntree->outputs.first; sock; sock= sock->next)
-                       if (sock==tosock)
+               for (sock = ntree->outputs.first; sock; sock = sock->next)
+                       if (sock == tosock)
                                break;
                if (sock)
-                       to= 1; /* OK */
+                       to = 1;  /* OK */
                else {
-                       for (sock= ntree->inputs.first; sock; sock= sock->next)
-                               if (sock==tosock)
+                       for (sock = ntree->inputs.first; sock; sock = sock->next)
+                               if (sock == tosock)
                                        break;
                        if (sock)
-                               to= -1; /* OK but flip */
+                               to = -1;  /* OK but flip */
                }
        }
        
        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;
+               link = MEM_callocN(sizeof(bNodeLink), "link");
+               if (ntree)
+                       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;
+               link = MEM_callocN(sizeof(bNodeLink), "link");
+               if (ntree)
+                       BLI_addtail(&ntree->links, link);
+               link->fromnode = tonode;
+               link->fromsock = tosock;
+               link->tonode = fromnode;
+               link->tosock = fromsock;
        }
        
-       ntree->update |= NTREE_UPDATE_LINKS;
+       if (ntree)
+               ntree->update |= NTREE_UPDATE_LINKS;
        
        return link;
 }
 
 void nodeRemLink(bNodeTree *ntree, bNodeLink *link)
 {
-       BLI_remlink(&ntree->links, link);
+       /* can be called for links outside a node tree (e.g. clipboard) */
+       if (ntree)
+               BLI_remlink(&ntree->links, link);
+
        if (link->tosock)
-               link->tosock->link= NULL;
+               link->tosock->link = NULL;
        MEM_freeN(link);
        
-       ntree->update |= NTREE_UPDATE_LINKS;
+       if (ntree)
+               ntree->update |= NTREE_UPDATE_LINKS;
 }
 
 void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock)
 {
        bNodeLink *link, *next;
        
-       for (link= ntree->links.first; link; link= next) {
-               next= link->next;
-               if (link->fromsock==sock || link->tosock==sock) {
+       for (link = ntree->links.first; link; link = next) {
+               next = link->next;
+               if (link->fromsock == sock || link->tosock == sock) {
                        nodeRemLink(ntree, link);
                }
        }
@@ -511,23 +549,20 @@ void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock)
 void nodeInternalRelink(bNodeTree *ntree, bNode *node)
 {
        bNodeLink *link, *link_next;
-       ListBase intlinks;
        
-       if (!node->typeinfo->internal_connect)
+       if (node->internal_links.first == NULL)
                return;
        
-       intlinks = node->typeinfo->internal_connect(ntree, node);
-       
        /* store link pointers in output sockets, for efficient lookup */
-       for (link=intlinks.first; link; link=link->next)
+       for (link = node->internal_links.first; link; link = link->next)
                link->tosock->link = link;
        
        /* redirect downstream links */
-       for (link=ntree->links.first; link; link=link_next) {
+       for (link = ntree->links.first; link; link = link_next) {
                link_next = link->next;
                
                /* do we have internal link? */
-               if (link->fromnode==node) {
+               if (link->fromnode == node) {
                        if (link->fromsock->link) {
                                /* get the upstream input link */
                                bNodeLink *fromlink = link->fromsock->link->fromsock->link;
@@ -536,6 +571,12 @@ void nodeInternalRelink(bNodeTree *ntree, bNode *node)
                                        link->fromnode = fromlink->fromnode;
                                        link->fromsock = fromlink->fromsock;
                                        
+                                       /* if the up- or downstream link is invalid,
+                                        * the replacement link will be invalid too.
+                                        */
+                                       if (!(fromlink->flag & NODE_LINK_VALID))
+                                               link->flag &= ~NODE_LINK_VALID;
+                                       
                                        ntree->update |= NTREE_UPDATE_LINKS;
                                }
                                else
@@ -547,14 +588,12 @@ void nodeInternalRelink(bNodeTree *ntree, bNode *node)
        }
        
        /* remove remaining upstream links */
-       for (link=ntree->links.first; link; link=link_next) {
+       for (link = ntree->links.first; link; link = link_next) {
                link_next = link->next;
                
-               if (link->tonode==node)
+               if (link->tonode == node)
                        nodeRemLink(ntree, link);
        }
-       
-       BLI_freelistN(&intlinks);
 }
 
 void nodeToView(bNode *node, float x, float y, float *rx, float *ry)
@@ -581,9 +620,25 @@ void nodeFromView(bNode *node, float x, float y, float *rx, float *ry)
        }
 }
 
+int nodeAttachNodeCheck(bNode *node, bNode *parent)
+{
+       bNode *parent_recurse;
+       for (parent_recurse = node; parent_recurse; parent_recurse = parent_recurse->parent) {
+               if (parent_recurse == parent) {
+                       return TRUE;
+               }
+       }
+
+       return FALSE;
+}
+
 void nodeAttachNode(bNode *node, bNode *parent)
 {
        float locx, locy;
+
+       BLI_assert(parent->type == NODE_FRAME);
+       BLI_assert(nodeAttachNodeCheck(parent, node) == FALSE);
+
        nodeToView(node, 0.0f, 0.0f, &locx, &locy);
        
        node->parent = parent;
@@ -596,6 +651,9 @@ void nodeDetachNode(struct bNode *node)
        float locx, locy;
        
        if (node->parent) {
+
+               BLI_assert(node->parent->type == NODE_FRAME);
+
                /* transform to view space */
                nodeToView(node, 0.0f, 0.0f, &locx, &locy);
                node->locx = locx;
@@ -604,7 +662,7 @@ void nodeDetachNode(struct bNode *node)
        }
 }
 
-bNodeTree *ntreeAddTree(const char *name, int type, int nodetype)
+bNodeTree *ntreeAddTree(Main *bmain, const char *name, int type, int nodetype)
 {
        bNodeTree *ntree;
        bNodeType *ntype;
@@ -612,15 +670,15 @@ bNodeTree *ntreeAddTree(const char *name, int type, int nodetype)
        /* trees are created as local trees if they of compositor, material or texture type,
         * node groups and other tree types are created as library data.
         */
-       if (ELEM3(type, NTREE_COMPOSIT, NTREE_SHADER, NTREE_TEXTURE) && nodetype==0) {
-               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));
+       if (ELEM3(type, NTREE_COMPOSIT, NTREE_SHADER, NTREE_TEXTURE) && nodetype == 0) {
+               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));
        }
        else
-               ntree= BKE_libblock_alloc(&G.main->nodetree, ID_NT, name);
+               ntree = BKE_libblock_alloc(&bmain->nodetree, ID_NT, name);
        
-       ntree->type= type;
+       ntree->type = type;
        ntree->nodetype = nodetype;
        
        ntreeInitTypes(ntree);
@@ -641,60 +699,65 @@ bNodeTree *ntreeAddTree(const char *name, int type, int nodetype)
  * copying for internal use (threads for eg), where you wont want it to modify the
  * scene data.
  */
-static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, const short do_make_extern)
+static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, const short do_id_user, const short do_make_extern)
 {
        bNodeTree *newtree;
        bNode *node /*, *nnode */ /* UNUSED */, *last;
        bNodeLink *link;
        bNodeSocket *gsock, *oldgsock;
        
-       if (ntree==NULL) return NULL;
+       if (ntree == NULL) return NULL;
        
        /* is ntree part of library? */
-       for (newtree=G.main->nodetree.first; newtree; newtree= newtree->id.next)
-               if (newtree==ntree) break;
+       for (newtree = G.main->nodetree.first; newtree; newtree = newtree->id.next)
+               if (newtree == ntree) break;
        if (newtree) {
-               newtree= BKE_libblock_copy(&ntree->id);
+               newtree = BKE_libblock_copy(&ntree->id);
        }
        else {
-               newtree= MEM_dupallocN(ntree);
-               BKE_libblock_copy_data(&newtree->id, &ntree->id, TRUE); /* copy animdata and ID props */
+               newtree = MEM_dupallocN(ntree);
+               BKE_libblock_copy_data(&newtree->id, &ntree->id, true); /* copy animdata and ID props */
        }
 
        id_us_plus((ID *)newtree->gpd);
 
        /* in case a running nodetree is copied */
-       newtree->execdata= NULL;
+       newtree->execdata = NULL;
        
-       newtree->nodes.first= newtree->nodes.last= NULL;
-       newtree->links.first= newtree->links.last= NULL;
+       newtree->nodes.first = newtree->nodes.last = NULL;
+       newtree->links.first = newtree->links.last = NULL;
        
        last = ntree->nodes.last;
-       for (node= ntree->nodes.first; node; node= node->next) {
+       for (node = ntree->nodes.first; node; node = node->next) {
+
+               /* ntreeUserDecrefID inline */
+               if (do_id_user) {
+                       id_us_plus(node->id);
+               }
 
                if (do_make_extern) {
                        id_lib_extern(node->id);
                }
 
-               node->new_node= NULL;
-               /* nnode= */ nodeCopyNode(newtree, node);       /* sets node->new */
+               node->new_node = NULL;
+               /* nnode = */ nodeCopyNode(newtree, node);   /* sets node->new */
                
                /* make sure we don't copy new nodes again! */
-               if (node==last)
+               if (node == last)
                        break;
        }
        
        /* 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;
+       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);
                gsock->default_value = node_socket_make_default_value(oldgsock->type);
                node_socket_copy_default_value(oldgsock->type, gsock->default_value, oldgsock->default_value);
        }
        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;
+       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);
                gsock->default_value = node_socket_make_default_value(oldgsock->type);
                node_socket_copy_default_value(oldgsock->type, gsock->default_value, oldgsock->default_value);
@@ -702,7 +765,7 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, const short do_make_e
        
        /* copy links */
        BLI_duplicatelist(&newtree->links, &ntree->links);
-       for (link= newtree->links.first; link; link= link->next) {
+       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);
@@ -713,7 +776,7 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, const short do_make_e
        }
        
        /* update node->parent pointers */
-       for (node=newtree->nodes.first; node; node=node->next) {
+       for (node = newtree->nodes.first; node; node = node->next) {
                if (node->parent)
                        node->parent = node->parent->new_node;
        }
@@ -721,22 +784,56 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, const short do_make_e
        return newtree;
 }
 
+bNodeTree *ntreeCopyTree_ex(bNodeTree *ntree, const short do_id_user)
+{
+       return ntreeCopyTree_internal(ntree, do_id_user, TRUE);
+}
 bNodeTree *ntreeCopyTree(bNodeTree *ntree)
 {
-       return ntreeCopyTree_internal(ntree, TRUE);
+       return ntreeCopyTree_ex(ntree, TRUE);
 }
 
 /* use when duplicating scenes */
-void ntreeSwitchID(bNodeTree *ntree, ID *id_from, ID *id_to)
+void ntreeSwitchID_ex(bNodeTree *ntree, ID *id_from, ID *id_to, const short do_id_user)
 {
        bNode *node;
+
+       if (id_from == id_to) {
+               /* should never happen but may as well skip if it does */
+               return;
+       }
+
        /* for scene duplication only */
-       for (node= ntree->nodes.first; node; node= node->next) {
-               if (node->id==id_from) {
-                       node->id= id_to;
+       for (node = ntree->nodes.first; node; node = node->next) {
+               if (node->id == id_from) {
+                       if (do_id_user) {
+                               id_us_min(id_from);
+                               id_us_plus(id_to);
+                       }
+
+                       node->id = id_to;
                }
        }
 }
+void ntreeSwitchID(bNodeTree *ntree, ID *id_from, ID *id_to)
+{
+       ntreeSwitchID_ex(ntree, id_from, id_to, TRUE);
+}
+
+void ntreeUserIncrefID(bNodeTree *ntree)
+{
+       bNode *node;
+       for (node = ntree->nodes.first; node; node = node->next) {
+               id_us_plus(node->id);
+       }
+}
+void ntreeUserDecrefID(bNodeTree *ntree)
+{
+       bNode *node;
+       for (node = ntree->nodes.first; node; node = node->next) {
+               id_us_min(node->id);
+       }
+}
 
 /* *************** preview *********** */
 /* if node->preview, then we assume the rect to exist */
@@ -747,34 +844,34 @@ void nodeFreePreview(bNode *node)
                if (node->preview->rect)
                        MEM_freeN(node->preview->rect);
                MEM_freeN(node->preview);
-               node->preview= NULL;
-       }       
+               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");
+       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)
+       if (xsize == 0 || ysize == 0)
                return;
        
        /* sanity checks & initialize */
        if (node->preview->rect) {
-               if (node->preview->xsize!=xsize && node->preview->ysize!=ysize) {
+               if (node->preview->xsize != xsize && node->preview->ysize != ysize) {
                        MEM_freeN(node->preview->rect);
-                       node->preview->rect= NULL;
+                       node->preview->rect = NULL;
                }
        }
        
-       if (node->preview->rect==NULL) {
-               node->preview->rect= MEM_callocN(4*xsize + xsize*ysize*sizeof(char)*4, "node preview rect");
-               node->preview->xsize= xsize;
-               node->preview->ysize= ysize;
+       if (node->preview->rect == NULL) {
+               node->preview->rect = MEM_callocN(4 * xsize + xsize * ysize * sizeof(char) * 4, "node preview rect");
+               node->preview->xsize = xsize;
+               node->preview->ysize = ysize;
        }
        /* no clear, makes nicer previews */
 }
@@ -783,15 +880,15 @@ void ntreeInitPreview(bNodeTree *ntree, int xsize, int ysize)
 {
        bNode *node;
        
-       if (ntree==NULL)
+       if (ntree == NULL)
                return;
        
-       for (node= ntree->nodes.first; node; node= node->next) {
-               if (node->typeinfo->flag & NODE_PREVIEW)        /* hrms, check for closed nodes? */
+       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))
+               if (node->type == NODE_GROUP && (node->flag & NODE_GROUP_EDIT))
                        ntreeInitPreview((bNodeTree *)node->id, xsize, ysize);
-       }               
+       }
 }
 
 static void nodeClearPreview(bNode *node)
@@ -805,27 +902,27 @@ void ntreeClearPreview(bNodeTree *ntree)
 {
        bNode *node;
        
-       if (ntree==NULL)
+       if (ntree == NULL)
                return;
        
-       for (node= ntree->nodes.first; node; node= node->next) {
+       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))
+               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[4], int x, int y, int do_manage)
+void nodeAddToPreview(bNode *node, const float col[4], int x, int y, int do_manage)
 {
-       bNodePreview *preview= node->preview;
+       bNodePreview *preview = node->preview;
        if (preview) {
-               if (x>=0 && y>=0) {
-                       if (x<preview->xsize && y<preview->ysize) {
-                               unsigned char *tar= preview->rect+ 4*((preview->xsize*y) + x);
+               if (x >= 0 && y >= 0) {
+                       if (x < preview->xsize && y < preview->ysize) {
+                               unsigned char *tar = preview->rect + 4 * ((preview->xsize * y) + x);
                                
                                if (do_manage) {
                                        linearrgb_to_srgb_uchar4(tar, col);
@@ -849,22 +946,22 @@ void nodeUnlinkNode(bNodeTree *ntree, bNode *node)
        bNodeSocket *sock;
        ListBase *lb;
        
-       for (link= ntree->links.first; link; link= next) {
-               next= link->next;
+       for (link = ntree->links.first; link; link = next) {
+               next = link->next;
                
-               if (link->fromnode==node) {
-                       lb= &node->outputs;
+               if (link->fromnode == node) {
+                       lb = &node->outputs;
                        if (link->tonode)
                                link->tonode->update |= NODE_UPDATE;
                }
-               else if (link->tonode==node)
-                       lb= &node->inputs;
+               else if (link->tonode == node)
+                       lb = &node->inputs;
                else
-                       lb= NULL;
+                       lb = NULL;
 
                if (lb) {
-                       for (sock= lb->first; sock; sock= sock->next) {
-                               if (link->fromsock==sock || link->tosock==sock)
+                       for (sock = lb->first; sock; sock = sock->next) {
+                               if (link->fromsock == sock || link->tosock == sock)
                                        break;
                        }
                        if (sock) {
@@ -877,56 +974,71 @@ void nodeUnlinkNode(bNodeTree *ntree, bNode *node)
 static void node_unlink_attached(bNodeTree *ntree, bNode *parent)
 {
        bNode *node;
-       for (node=ntree->nodes.first; node; node=node->next) {
+       for (node = ntree->nodes.first; node; node = node->next) {
                if (node->parent == parent)
                        nodeDetachNode(node);
        }
 }
 
+/** \note caller needs to manage node->id user */
 void nodeFreeNode(bNodeTree *ntree, bNode *node)
 {
-       bNodeTreeType *treetype= ntreeGetType(ntree->type);
        bNodeSocket *sock, *nextsock;
        
-       /* remove all references to this node */
-       nodeUnlinkNode(ntree, node);
-       node_unlink_attached(ntree, node);
-       
-       BLI_remlink(&ntree->nodes, node);
+       /* can be called for nodes outside a node tree (e.g. clipboard) */
+       if (ntree) {
+               bNodeTreeType *treetype = ntreeGetType(ntree->type);
+
+               /* remove all references to this node */
+               nodeUnlinkNode(ntree, node);
+               node_unlink_attached(ntree, node);
+
+               BLI_remlink(&ntree->nodes, node);
+
+               if (treetype->free_node_cache)
+                       treetype->free_node_cache(ntree, node);
+               
+               /* texture node has bad habit of keeping exec data around */
+               if (ntree->type == NTREE_TEXTURE && ntree->execdata) {
+                       ntreeTexEndExecTree(ntree->execdata, 1);
+                       ntree->execdata = NULL;
+               }
+       }
        
        /* since it is called while free database, node->id is undefined */
        
-       if (treetype->free_node_cache)
-               treetype->free_node_cache(ntree, node);
-       
        if (node->typeinfo && node->typeinfo->freestoragefunc)
                node->typeinfo->freestoragefunc(node);
        
-       for (sock=node->inputs.first; sock; sock = nextsock) {
+       for (sock = node->inputs.first; sock; sock = nextsock) {
                nextsock = sock->next;
                node_socket_free_default_value(sock->type, sock->default_value);
                MEM_freeN(sock);
        }
-       for (sock=node->outputs.first; sock; sock = nextsock) {
+       for (sock = node->outputs.first; sock; sock = nextsock) {
                nextsock = sock->next;
                node_socket_free_default_value(sock->type, sock->default_value);
                MEM_freeN(sock);
        }
 
+       BLI_freelistN(&node->internal_links);
+
        nodeFreePreview(node);
 
        MEM_freeN(node);
        
-       ntree->update |= NTREE_UPDATE_NODES;
+       if (ntree)
+               ntree->update |= NTREE_UPDATE_NODES;
 }
 
 /* do not free ntree itself here, BKE_libblock_free calls this function too */
-void ntreeFreeTree(bNodeTree *ntree)
+void ntreeFreeTree_ex(bNodeTree *ntree, const short do_id_user)
 {
+       bNodeTree *tntree;
        bNode *node, *next;
        bNodeSocket *sock;
        
-       if (ntree==NULL) return;
+       if (ntree == NULL) return;
        
        /* XXX hack! node trees should not store execution graphs at all.
         * This should be removed when old tree types no longer require it.
@@ -935,15 +1047,13 @@ void ntreeFreeTree(bNodeTree *ntree)
         */
        if (ntree->execdata) {
                switch (ntree->type) {
-               case NTREE_COMPOSIT:
-                       ntreeCompositEndExecTree(ntree->execdata, 1);
-                       break;
-               case NTREE_SHADER:
-                       ntreeShaderEndExecTree(ntree->execdata, 1);
-                       break;
-               case NTREE_TEXTURE:
-                       ntreeTexEndExecTree(ntree->execdata, 1);
-                       break;
+                       case NTREE_SHADER:
+                               ntreeShaderEndExecTree(ntree->execdata, 1);
+                               break;
+                       case NTREE_TEXTURE:
+                               ntreeTexEndExecTree(ntree->execdata, 1);
+                               ntree->execdata = NULL;
+                               break;
                }
        }
        
@@ -951,28 +1061,56 @@ void ntreeFreeTree(bNodeTree *ntree)
        
        id_us_min((ID *)ntree->gpd);
 
-       BLI_freelistN(&ntree->links);   /* do first, then unlink_node goes fast */
+       BLI_freelistN(&ntree->links);   /* do first, then unlink_node goes fast */
        
-       for (node= ntree->nodes.first; node; node= next) {
-               next= node->next;
+       for (node = ntree->nodes.first; node; node = next) {
+               next = node->next;
+
+               /* ntreeUserIncrefID inline */
+
+               /* XXX, this is correct, however when freeing the entire database
+                * this ends up accessing freed data which isn't properly unlinking
+                * its self from scene nodes, SO - for now prefer invalid usercounts
+                * on free rather then bad memory access - Campbell */
+#if 0
+               if (do_id_user) {
+                       id_us_min(node->id);
+               }
+#else
+               (void)do_id_user;
+#endif
+
                nodeFreeNode(ntree, node);
        }
        
-       for (sock=ntree->inputs.first; sock; sock=sock->next)
+       for (sock = ntree->inputs.first; sock; sock = sock->next)
                node_socket_free_default_value(sock->type, sock->default_value);
        BLI_freelistN(&ntree->inputs);
-       for (sock=ntree->outputs.first; sock; sock=sock->next)
+       for (sock = ntree->outputs.first; sock; sock = sock->next)
                node_socket_free_default_value(sock->type, sock->default_value);
        BLI_freelistN(&ntree->outputs);
+       
+       /* if ntree is not part of library, free the libblock data explicitly */
+       for (tntree = G.main->nodetree.first; tntree; tntree = tntree->id.next)
+               if (tntree == ntree)
+                       break;
+       if (tntree == NULL) {
+               BKE_libblock_free_data(&ntree->id);
+       }
+}
+/* same as ntreeFreeTree_ex but always manage users */
+void ntreeFreeTree(bNodeTree *ntree)
+{
+       ntreeFreeTree_ex(ntree, TRUE);
 }
 
 void ntreeFreeCache(bNodeTree *ntree)
 {
        bNodeTreeType *treetype;
        
-       if (ntree==NULL) return;
+       if (ntree == NULL) return;
        
-       treetype= ntreeGetType(ntree->type);
+       treetype = ntreeGetType(ntree->type);
        if (treetype->free_cache)
                treetype->free_cache(ntree);
 }
@@ -982,45 +1120,46 @@ void ntreeSetOutput(bNodeTree *ntree)
        bNode *node;
 
        /* find the active outputs, might become tree type dependent handler */
-       for (node= ntree->nodes.first; node; node= node->next) {
-               if (node->typeinfo->nclass==NODE_CLASS_OUTPUT) {
+       for (node = ntree->nodes.first; node; node = node->next) {
+               if (node->typeinfo->nclass == NODE_CLASS_OUTPUT) {
                        bNode *tnode;
-                       int output= 0;
+                       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)
+                       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) {
+                       for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) {
+                               if (tnode->typeinfo->nclass == NODE_CLASS_OUTPUT) {
                                        
-                                       if (ntree->type==NTREE_COMPOSIT) {
+                                       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->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)
+                                                               if (output > 1)
                                                                        tnode->flag &= ~NODE_DO_OUTPUT;
                                                        }
                                                }
                                        }
                                        else {
                                                /* same type */
-                                               if (tnode->type==node->type) {
+                                               if (tnode->type == node->type) {
                                                        if (tnode->flag & NODE_DO_OUTPUT) {
                                                                output++;
-                                                               if (output>1)
+                                                               if (output > 1)
                                                                        tnode->flag &= ~NODE_DO_OUTPUT;
                                                        }
                                                }
                                        }
                                }
                        }
-                       if (output==0)
+                       if (output == 0)
                                node->flag |= NODE_DO_OUTPUT;
                }
        }
@@ -1029,6 +1168,18 @@ void ntreeSetOutput(bNodeTree *ntree)
         * might be different for editor or for "real" use... */
 }
 
+bNodeTree *ntreeFromID(ID *id)
+{
+       switch (GS(id->name)) {
+               case ID_MA:  return ((Material *)id)->nodetree;
+               case ID_LA:  return ((Lamp *)id)->nodetree;
+               case ID_WO:  return ((World *)id)->nodetree;
+               case ID_TE:  return ((Tex *)id)->nodetree;
+               case ID_SCE: return ((Scene *)id)->nodetree;
+               default: return NULL;
+       }
+}
+
 typedef struct MakeLocalCallData {
        ID *group_id;
        ID *new_id;
@@ -1037,28 +1188,32 @@ typedef struct MakeLocalCallData {
 
 static void ntreeMakeLocal_CheckLocal(void *calldata, ID *owner_id, bNodeTree *ntree)
 {
-       MakeLocalCallData *cd= (MakeLocalCallData*)calldata;
+       MakeLocalCallData *cd = (MakeLocalCallData *)calldata;
        bNode *node;
        
        /* find if group is in tree */
-       for (node= ntree->nodes.first; node; node= node->next) {
+       for (node = ntree->nodes.first; node; node = node->next) {
                if (node->id == cd->group_id) {
-                       if (owner_id->lib) cd->lib= 1;
-                       else cd->local= 1;
+                       if (owner_id->lib) {
+                               cd->lib = TRUE;
+                       }
+                       else {
+                               cd->local = TRUE;
+                       }
                }
        }
 }
 
 static void ntreeMakeLocal_LinkNew(void *calldata, ID *owner_id, bNodeTree *ntree)
 {
-       MakeLocalCallData *cd= (MakeLocalCallData*)calldata;
+       MakeLocalCallData *cd = (MakeLocalCallData *)calldata;
        bNode *node;
        
        /* find if group is in tree */
-       for (node= ntree->nodes.first; node; node= node->next) {
+       for (node = ntree->nodes.first; node; node = node->next) {
                if (node->id == cd->group_id) {
-                       if (owner_id->lib==NULL) {
-                               node->id= cd->new_id;
+                       if (owner_id->lib == NULL) {
+                               node->id = cd->new_id;
                                cd->new_id->us++;
                                cd->group_id->us--;
                        }
@@ -1068,8 +1223,8 @@ static void ntreeMakeLocal_LinkNew(void *calldata, ID *owner_id, bNodeTree *ntre
 
 void ntreeMakeLocal(bNodeTree *ntree)
 {
-       Main *bmain= G.main;
-       bNodeTreeType *treetype= ntreeGetType(ntree->type);
+       Main *bmain = G.main;
+       bNodeTreeType *treetype = ntreeGetType(ntree->type);
        MakeLocalCallData cd;
        
        /* - only lib users: do nothing
@@ -1077,8 +1232,8 @@ void ntreeMakeLocal(bNodeTree *ntree)
         * - mixed: make copy
         */
        
-       if (ntree->id.lib==NULL) return;
-       if (ntree->id.us==1) {
+       if (ntree->id.lib == NULL) return;
+       if (ntree->id.us == 1) {
                id_clear_lib_data(bmain, (ID *)ntree);
                return;
        }
@@ -1092,14 +1247,14 @@ void ntreeMakeLocal(bNodeTree *ntree)
        treetype->foreach_nodetree(G.main, &cd, &ntreeMakeLocal_CheckLocal);
        
        /* if all users are local, we simply make tree local */
-       if (cd.local && cd.lib==0) {
+       if (cd.local && cd.lib == 0) {
                id_clear_lib_data(bmain, (ID *)ntree);
        }
        else if (cd.local && cd.lib) {
                /* this is the mixed case, we copy the tree and assign it to local users */
-               bNodeTree *newtree= ntreeCopyTree(ntree);
+               bNodeTree *newtree = ntreeCopyTree(ntree);
                
-               newtree->id.us= 0;
+               newtree->id.us = 0;
                
 
                cd.new_id = &newtree->id;
@@ -1109,18 +1264,18 @@ void ntreeMakeLocal(bNodeTree *ntree)
 
 int ntreeNodeExists(bNodeTree *ntree, bNode *testnode)
 {
-       bNode *node= ntree->nodes.first;
-       for (; node; node= node->next)
-               if (node==testnode)
+       bNode *node = ntree->nodes.first;
+       for (; node; node = node->next)
+               if (node == testnode)
                        return 1;
        return 0;
 }
 
 int ntreeOutputExists(bNode *node, bNodeSocket *testsock)
 {
-       bNodeSocket *sock= node->outputs.first;
-       for (; sock; sock= sock->next)
-               if (sock==testsock)
+       bNodeSocket *sock = node->outputs.first;
+       for (; sock; sock = sock->next)
+               if (sock == testsock)
                        return 1;
        return 0;
 }
@@ -1128,33 +1283,33 @@ int ntreeOutputExists(bNode *node, bNodeSocket *testsock)
 /* returns localized tree for execution in threads */
 bNodeTree *ntreeLocalize(bNodeTree *ntree)
 {
-       bNodeTreeType *ntreetype= ntreeGetType(ntree->type);
+       bNodeTreeType *ntreetype = ntreeGetType(ntree->type);
 
        bNodeTree *ltree;
        bNode *node;
        
-       bAction *action_backup= NULL, *tmpact_backup= NULL;
+       bAction *action_backup = NULL, *tmpact_backup = NULL;
        
        /* Workaround for copying an action on each render!
         * set action to NULL so animdata actions don't get copied */
-       AnimData *adt= BKE_animdata_from_id(&ntree->id);
+       AnimData *adt = BKE_animdata_from_id(&ntree->id);
 
        if (adt) {
-               action_backup= adt->action;
-               tmpact_backup= adt->tmpact;
+               action_backup = adt->action;
+               tmpact_backup = adt->tmpact;
 
-               adt->action= NULL;
-               adt->tmpact= NULL;
+               adt->action = NULL;
+               adt->tmpact = NULL;
        }
 
        /* node copy func */
-       ltree = ntreeCopyTree_internal(ntree, FALSE);
+       ltree = ntreeCopyTree_internal(ntree, FALSE, FALSE);
 
        if (adt) {
-               AnimData *ladt= BKE_animdata_from_id(&ltree->id);
+               AnimData *ladt = BKE_animdata_from_id(&ltree->id);
 
-               adt->action= ladt->action= action_backup;
-               adt->tmpact= ladt->tmpact= tmpact_backup;
+               adt->action = ladt->action = action_backup;
+               adt->tmpact = ladt->tmpact = tmpact_backup;
 
                if (action_backup) action_backup->id.us++;
                if (tmpact_backup) tmpact_backup->id.us++;
@@ -1165,9 +1320,9 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
        /* ensures only a single output node is enabled */
        ntreeSetOutput(ntree);
 
-       for (node= ntree->nodes.first; node; node= node->next) {
+       for (node = ntree->nodes.first; node; node = node->next) {
                /* store new_node pointer to original */
-               node->new_node->new_node= node;
+               node->new_node->new_node = node;
        }
 
        if (ntreetype->localize)
@@ -1181,7 +1336,7 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
 /* is called by jobs manager, outside threads, so it doesnt happen during draw */
 void ntreeLocalSync(bNodeTree *localtree, bNodeTree *ntree)
 {
-       bNodeTreeType *ntreetype= ntreeGetType(ntree->type);
+       bNodeTreeType *ntreetype = ntreeGetType(ntree->type);
 
        if (ntreetype->local_sync)
                ntreetype->local_sync(localtree, ntree);
@@ -1191,16 +1346,16 @@ void ntreeLocalSync(bNodeTree *localtree, bNodeTree *ntree)
 /* we have to assume the editor already changed completely */
 void ntreeLocalMerge(bNodeTree *localtree, bNodeTree *ntree)
 {
-       bNodeTreeType *ntreetype= ntreeGetType(ntree->type);
+       bNodeTreeType *ntreetype = ntreeGetType(ntree->type);
        bNode *lnode;
        
        /* move over the compbufs and previews */
-       for (lnode= localtree->nodes.first; lnode; lnode= lnode->next) {
+       for (lnode = localtree->nodes.first; lnode; lnode = lnode->next) {
                if (ntreeNodeExists(ntree, lnode->new_node)) {
                        if (lnode->preview && lnode->preview->rect) {
                                nodeFreePreview(lnode->new_node);
-                               lnode->new_node->preview= lnode->preview;
-                               lnode->preview= NULL;
+                               lnode->new_node->preview = lnode->preview;
+                               lnode->preview = NULL;
                        }
                }
        }
@@ -1208,7 +1363,7 @@ void ntreeLocalMerge(bNodeTree *localtree, bNodeTree *ntree)
        if (ntreetype->local_merge)
                ntreetype->local_merge(localtree, ntree);
 
-       ntreeFreeTree(localtree);
+       ntreeFreeTree_ex(localtree, FALSE);
        MEM_freeN(localtree);
 }
 
@@ -1219,7 +1374,7 @@ int ntreeHasType(bNodeTree *ntree, int type)
        bNode *node;
        
        if (ntree)
-               for (node= ntree->nodes.first; node; node= node->next)
+               for (node = ntree->nodes.first; node; node = node->next)
                        if (node->type == type)
                                return 1;
        return 0;
@@ -1229,10 +1384,10 @@ bNodeLink *nodeFindLink(bNodeTree *ntree, bNodeSocket *from, bNodeSocket *to)
 {
        bNodeLink *link;
        
-       for (link= ntree->links.first; link; link= link->next) {
-               if (link->fromsock==from && link->tosock==to)
+       for (link = ntree->links.first; link; link = link->next) {
+               if (link->fromsock == from && link->tosock == to)
                        return link;
-               if (link->fromsock==to && link->tosock==from)   /* hrms? */
+               if (link->fromsock == to && link->tosock == from) /* hrms? */
                        return link;
        }
        return NULL;
@@ -1241,10 +1396,10 @@ bNodeLink *nodeFindLink(bNodeTree *ntree, bNodeSocket *from, bNodeSocket *to)
 int nodeCountSocketLinks(bNodeTree *ntree, bNodeSocket *sock)
 {
        bNodeLink *link;
-       int tot= 0;
+       int tot = 0;
        
-       for (link= ntree->links.first; link; link= link->next) {
-               if (link->fromsock==sock || link->tosock==sock)
+       for (link = ntree->links.first; link; link = link->next) {
+               if (link->fromsock == sock || link->tosock == sock)
                        tot++;
        }
        return tot;
@@ -1254,9 +1409,9 @@ bNode *nodeGetActive(bNodeTree *ntree)
 {
        bNode *node;
        
-       if (ntree==NULL) return NULL;
+       if (ntree == NULL) return NULL;
        
-       for (node= ntree->nodes.first; node; node= node->next)
+       for (node = ntree->nodes.first; node; node = node->next)
                if (node->flag & NODE_ACTIVE)
                        break;
        return node;
@@ -1267,19 +1422,19 @@ bNode *nodeGetActiveID(bNodeTree *ntree, short idtype)
 {
        bNode *node;
        
-       if (ntree==NULL) return NULL;
+       if (ntree == NULL) return NULL;
 
        /* check for group edit */
-       for (node= ntree->nodes.first; node; node= node->next)
+       for (node = ntree->nodes.first; node; node = node->next)
                if (node->flag & NODE_GROUP_EDIT)
                        break;
 
        if (node)
-               ntree= (bNodeTree*)node->id;
+               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)
+       for (node = ntree->nodes.first; node; node = node->next)
+               if (node->id && GS(node->id->name) == idtype)
                        if (node->flag & NODE_ACTIVE_ID)
                                break;
 
@@ -1289,24 +1444,24 @@ bNode *nodeGetActiveID(bNodeTree *ntree, short idtype)
 int nodeSetActiveID(bNodeTree *ntree, short idtype, ID *id)
 {
        bNode *node;
-       int ok= FALSE;
+       int ok = FALSE;
 
-       if (ntree==NULL) return ok;
+       if (ntree == NULL) return ok;
 
        /* check for group edit */
-       for (node= ntree->nodes.first; node; node= node->next)
+       for (node = ntree->nodes.first; node; node = node->next)
                if (node->flag & NODE_GROUP_EDIT)
                        break;
 
        if (node)
-               ntree= (bNodeTree*)node->id;
+               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 (id && ok==FALSE && node->id==id) {
+       for (node = ntree->nodes.first; node; node = node->next) {
+               if (node->id && GS(node->id->name) == idtype) {
+                       if (id && ok == FALSE && node->id == id) {
                                node->flag |= NODE_ACTIVE_ID;
-                               ok= TRUE;
+                               ok = TRUE;
                        }
                        else {
                                node->flag &= ~NODE_ACTIVE_ID;
@@ -1323,10 +1478,10 @@ void nodeClearActiveID(bNodeTree *ntree, short idtype)
 {
        bNode *node;
        
-       if (ntree==NULL) return;
+       if (ntree == NULL) return;
        
-       for (node= ntree->nodes.first; node; node= node->next)
-               if (node->id && GS(node->id->name)==idtype)
+       for (node = ntree->nodes.first; node; node = node->next)
+               if (node->id && GS(node->id->name) == idtype)
                        node->flag &= ~NODE_ACTIVE_ID;
 }
 
@@ -1334,9 +1489,9 @@ void nodeClearActive(bNodeTree *ntree)
 {
        bNode *node;
 
-       if (ntree==NULL) return;
+       if (ntree == NULL) return;
 
-       for (node= ntree->nodes.first; node; node= node->next)
+       for (node = ntree->nodes.first; node; node = node->next)
                node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_ID);
 }
 
@@ -1347,7 +1502,7 @@ void nodeSetActive(bNodeTree *ntree, bNode *node)
        bNode *tnode;
        
        /* make sure only one node is active, and only one per ID type */
-       for (tnode= ntree->nodes.first; tnode; tnode= tnode->next) {
+       for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) {
                tnode->flag &= ~NODE_ACTIVE;
                
                if (node->id && tnode->id) {
@@ -1383,24 +1538,178 @@ void nodeSocketSetType(bNodeSocket *sock, int type)
        node_socket_free_default_value(old_type, old_default_value);
 }
 
+/* ************** Node Clipboard *********** */
+
+#define USE_NODE_CB_VALIDATE
+
+#ifdef USE_NODE_CB_VALIDATE
+/**
+ * This data structure is to validate the node on creation,
+ * otherwise we may reference missing data.
+ *
+ * Currently its only used for ID's, but nodes may one day
+ * reference other pointers which need validation.
+ */
+typedef struct bNodeClipboardExtraInfo {
+       struct bNodeClipboardExtraInfo *next, *prev;
+       ID  *id;
+       char id_name[MAX_ID_NAME];
+       char library_name[FILE_MAX];
+} bNodeClipboardExtraInfo;
+#endif  /* USE_NODE_CB_VALIDATE */
+
+
+typedef struct bNodeClipboard {
+       ListBase nodes;
+
+#ifdef USE_NODE_CB_VALIDATE
+       ListBase nodes_extra_info;
+#endif
+
+       ListBase links;
+       int type;
+} bNodeClipboard;
+
+bNodeClipboard node_clipboard = {{0}};
+
+void BKE_node_clipboard_init(struct bNodeTree *ntree)
+{
+       node_clipboard.type = ntree->type;
+}
+
+void BKE_node_clipboard_clear(void)
+{
+       bNode *node, *node_next;
+       bNodeLink *link, *link_next;
+       
+       for (link = node_clipboard.links.first; link; link = link_next) {
+               link_next = link->next;
+               nodeRemLink(NULL, link);
+       }
+       node_clipboard.links.first = node_clipboard.links.last = NULL;
+       
+       for (node = node_clipboard.nodes.first; node; node = node_next) {
+               node_next = node->next;
+               nodeFreeNode(NULL, node);
+       }
+       node_clipboard.nodes.first = node_clipboard.nodes.last = NULL;
+
+#ifdef USE_NODE_CB_VALIDATE
+       BLI_freelistN(&node_clipboard.nodes_extra_info);
+#endif
+}
+
+/* return FALSE when one or more ID's are lost */
+int BKE_node_clipboard_validate(void)
+{
+       int ok = TRUE;
+
+#ifdef USE_NODE_CB_VALIDATE
+       bNodeClipboardExtraInfo *node_info;
+       bNode *node;
+
+
+       /* lists must be aligned */
+       BLI_assert(BLI_countlist(&node_clipboard.nodes) ==
+                  BLI_countlist(&node_clipboard.nodes_extra_info));
+
+       for (node = node_clipboard.nodes.first, node_info = node_clipboard.nodes_extra_info.first;
+            node;
+            node = node->next, node_info = node_info->next)
+       {
+               /* validate the node against the stored node info */
+
+               /* re-assign each loop since we may clear,
+                * open a new file where the ID is valid, and paste again */
+               node->id = node_info->id;
+
+               /* currently only validate the ID */
+               if (node->id) {
+                       ListBase *lb = which_libbase(G.main, GS(node_info->id_name));
+                       BLI_assert(lb != NULL);
+
+                       if (BLI_findindex(lb, node_info->id) == -1) {
+                               /* may assign NULL */
+                               node->id = BLI_findstring(lb, node_info->id_name + 2, offsetof(ID, name) + 2);
+
+                               if (node->id == NULL) {
+                                       ok = FALSE;
+                               }
+                       }
+               }
+       }
+#endif  /* USE_NODE_CB_VALIDATE */
+
+       return ok;
+}
+
+void BKE_node_clipboard_add_node(bNode *node)
+{
+#ifdef USE_NODE_CB_VALIDATE
+       /* add extra info */
+       bNodeClipboardExtraInfo *node_info = MEM_mallocN(sizeof(bNodeClipboardExtraInfo), "bNodeClipboardExtraInfo");
+
+       node_info->id = node->id;
+       if (node->id) {
+               BLI_strncpy(node_info->id_name, node->id->name, sizeof(node_info->id_name));
+               if (node->id->lib) {
+                       BLI_strncpy(node_info->library_name, node->id->lib->filepath, sizeof(node_info->library_name));
+               }
+               else {
+                       node_info->library_name[0] = '\0';
+               }
+       }
+       else {
+               node_info->id_name[0] = '\0';
+               node_info->library_name[0] = '\0';
+       }
+       BLI_addtail(&node_clipboard.nodes_extra_info, node_info);
+       /* end extra info */
+#endif  /* USE_NODE_CB_VALIDATE */
+
+       /* add node */
+       BLI_addtail(&node_clipboard.nodes, node);
+
+}
+
+void BKE_node_clipboard_add_link(bNodeLink *link)
+{
+       BLI_addtail(&node_clipboard.links, link);
+}
+
+const ListBase *BKE_node_clipboard_get_nodes(void)
+{
+       return &node_clipboard.nodes;
+}
+
+const ListBase *BKE_node_clipboard_get_links(void)
+{
+       return &node_clipboard.links;
+}
+
+int BKE_node_clipboard_get_type(void)
+{
+       return node_clipboard.type;
+}
+
 /* ************** dependency stuff *********** */
 
 /* node is guaranteed to be not checked before */
-static int node_get_deplist_recurs(bNode *node, bNode ***nsort)
+static int node_get_deplist_recurs(bNodeTree *ntree, bNode *node, bNode ***nsort)
 {
        bNode *fromnode;
-       bNodeSocket *sock;
+       bNodeLink *link;
        int level = 0xFFF;
        
        node->done = TRUE;
        
        /* check linked nodes */
-       for (sock= node->inputs.first; sock; sock= sock->next) {
-               if (sock->link) {
-                       fromnode= sock->link->fromnode;
+       for (link = ntree->links.first; link; link = link->next) {
+               if (link->tonode == node) {
+                       fromnode = link->fromnode;
                        if (fromnode) {
-                               if (fromnode->done==0)
-                                       fromnode->level= node_get_deplist_recurs(fromnode, nsort);
+                               if (fromnode->done == 0)
+                                       fromnode->level = node_get_deplist_recurs(ntree, fromnode, nsort);
                                if (fromnode->level <= level)
                                        level = fromnode->level - 1;
                        }
@@ -1409,14 +1718,14 @@ static int node_get_deplist_recurs(bNode *node, bNode ***nsort)
        
        /* check parent node */
        if (node->parent) {
-               if (node->parent->done==0)
-                       node->parent->level= node_get_deplist_recurs(node->parent, nsort);
+               if (node->parent->done == 0)
+                       node->parent->level = node_get_deplist_recurs(ntree, node->parent, nsort);
                if (node->parent->level <= level)
                        level = node->parent->level - 1;
        }
        
        if (nsort) {
-               **nsort= node;
+               **nsort = node;
                (*nsort)++;
        }
        
@@ -1427,24 +1736,24 @@ void ntreeGetDependencyList(struct bNodeTree *ntree, struct bNode ***deplist, in
 {
        bNode *node, **nsort;
        
-       *totnodes=0;
+       *totnodes = 0;
        
        /* first clear data */
-       for (node= ntree->nodes.first; node; node= node->next) {
+       for (node = ntree->nodes.first; node; node = node->next) {
                node->done = FALSE;
                (*totnodes)++;
        }
-       if (*totnodes==0) {
+       if (*totnodes == 0) {
                *deplist = NULL;
                return;
        }
        
-       nsort= *deplist= MEM_callocN((*totnodes)*sizeof(bNode*), "sorted node array");
+       nsort = *deplist = MEM_callocN((*totnodes) * sizeof(bNode *), "sorted node array");
        
        /* recursive check */
-       for (node= ntree->nodes.first; node; node= node->next) {
-               if (node->done==0) {
-                       node->level= node_get_deplist_recurs(node, &nsort);
+       for (node = ntree->nodes.first; node; node = node->next) {
+               if (node->done == 0) {
+                       node->level = node_get_deplist_recurs(ntree, node, &nsort);
                }
        }
 }
@@ -1455,14 +1764,14 @@ static void ntree_update_node_level(bNodeTree *ntree)
        bNode *node;
        
        /* first clear tag */
-       for (node= ntree->nodes.first; node; node= node->next) {
+       for (node = ntree->nodes.first; node; node = node->next) {
                node->done = FALSE;
        }
        
        /* recursive check */
-       for (node= ntree->nodes.first; node; node= node->next) {
-               if (node->done==0) {
-                       node->level= node_get_deplist_recurs(node, NULL);
+       for (node = ntree->nodes.first; node; node = node->next) {
+               if (node->done == 0) {
+                       node->level = node_get_deplist_recurs(ntree, node, NULL);
                }
        }
 }
@@ -1474,25 +1783,25 @@ static void ntree_update_link_pointers(bNodeTree *ntree)
        bNodeLink *link;
        
        /* first clear data */
-       for (node= ntree->nodes.first; node; node= node->next) {
-               for (sock= node->inputs.first; sock; sock= sock->next) {
-                       sock->link= NULL;
+       for (node = ntree->nodes.first; node; node = node->next) {
+               for (sock = node->inputs.first; sock; sock = sock->next) {
+                       sock->link = NULL;
                        sock->flag &= ~SOCK_IN_USE;
                }
-               for (sock= node->outputs.first; sock; sock= sock->next) {
+               for (sock = node->outputs.first; sock; sock = sock->next) {
                        sock->flag &= ~SOCK_IN_USE;
                }
        }
-       for (sock= ntree->inputs.first; sock; sock= sock->next) {
+       for (sock = ntree->inputs.first; sock; sock = sock->next) {
                sock->flag &= ~SOCK_IN_USE;
        }
-       for (sock= ntree->outputs.first; sock; sock= sock->next) {
-               sock->link= NULL;
+       for (sock = ntree->outputs.first; sock; sock = sock->next) {
+               sock->link = NULL;
                sock->flag &= ~SOCK_IN_USE;
        }
 
-       for (link= ntree->links.first; link; link= link->next) {
-               link->tosock->link= link;
+       for (link = ntree->links.first; link; link = link->next) {
+               link->tosock->link = link;
                
                link->fromsock->flag |= SOCK_IN_USE;
                link->tosock->flag |= SOCK_IN_USE;
@@ -1517,10 +1826,10 @@ static void ntree_validate_links(bNodeTree *ntree)
 
 static void ntree_verify_nodes_cb(void *calldata, struct ID *UNUSED(owner_id), struct bNodeTree *ntree)
 {
-       ID *id= (ID*)calldata;
+       ID *id = (ID *)calldata;
        bNode *node;
        
-       for (node=ntree->nodes.first; node; node=node->next)
+       for (node = ntree->nodes.first; node; node = node->next)
                if (node->typeinfo->verifyfunc)
                        node->typeinfo->verifyfunc(ntree, node, id);
 }
@@ -1531,21 +1840,21 @@ void ntreeVerifyNodes(struct Main *main, struct ID *id)
        bNodeTree *ntree;
        int n;
        
-       for (n=0; n < NUM_NTREE_TYPES; ++n) {
-               ntreetype= ntreeGetType(n);
+       for (n = 0; n < NUM_NTREE_TYPES; ++n) {
+               ntreetype = ntreeGetType(n);
                if (ntreetype && ntreetype->foreach_nodetree)
                        ntreetype->foreach_nodetree(main, id, ntree_verify_nodes_cb);
        }
-       for (ntree=main->nodetree.first; ntree; ntree=ntree->id.next)
+       for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next)
                ntree_verify_nodes_cb(id, NULL, ntree);
 }
 
 void ntreeUpdateTree(bNodeTree *ntree)
 {
-       bNodeTreeType *ntreetype= ntreeGetType(ntree->type);
+       bNodeTreeType *ntreetype = ntreeGetType(ntree->type);
        bNode *node;
        
-       if (ntree->update & (NTREE_UPDATE_LINKS|NTREE_UPDATE_NODES)) {
+       if (ntree->update & (NTREE_UPDATE_LINKS | NTREE_UPDATE_NODES)) {
                /* set the bNodeSocket->link pointers */
                ntree_update_link_pointers(ntree);
                
@@ -1554,20 +1863,20 @@ void ntreeUpdateTree(bNodeTree *ntree)
        }
        
        /* update individual nodes */
-       for (node=ntree->nodes.first; node; node=node->next) {
+       for (node = ntree->nodes.first; node; node = node->next) {
                /* node tree update tags override individual node update flags */
                if ((node->update & NODE_UPDATE) || (ntree->update & NTREE_UPDATE)) {
                        if (ntreetype->update_node)
                                ntreetype->update_node(ntree, node);
                        else if (node->typeinfo->updatefunc)
                                node->typeinfo->updatefunc(ntree, node);
+                       
+                       nodeUpdateInternalLinks(ntree, node);
                }
-               /* clear update flag */
-               node->update = 0;
        }
        
        /* check link validity */
-       if (ntree->update & (NTREE_UPDATE_LINKS|NTREE_UPDATE_NODES))
+       if (ntree->update & (NTREE_UPDATE_LINKS | NTREE_UPDATE_NODES))
                ntree_validate_links(ntree);
        
        /* generic tree update callback */
@@ -1577,7 +1886,7 @@ void ntreeUpdateTree(bNodeTree *ntree)
                /* Trees can be associated with a specific node type (i.e. group nodes),
                 * in that case a tree update function may be defined by that node type.
                 */
-               bNodeType *ntype= node_get_type(ntree, ntree->nodetype);
+               bNodeType *ntype = node_get_type(ntree, ntree->nodetype);
                if (ntype && ntype->updatetreefunc)
                        ntype->updatetreefunc(ntree);
        }
@@ -1585,18 +1894,24 @@ void ntreeUpdateTree(bNodeTree *ntree)
        /* XXX hack, should be done by depsgraph!! */
        ntreeVerifyNodes(G.main, &ntree->id);
        
-       /* clear the update flag */
+       /* clear update flags */
+       for (node = ntree->nodes.first; node; node = node->next) {
+               node->update = 0;
+       }
        ntree->update = 0;
 }
 
 void nodeUpdate(bNodeTree *ntree, bNode *node)
 {
-       bNodeTreeType *ntreetype= ntreeGetType(ntree->type);
+       bNodeTreeType *ntreetype = ntreeGetType(ntree->type);
        
        if (ntreetype->update_node)
                ntreetype->update_node(ntree, node);
        else if (node->typeinfo->updatefunc)
                node->typeinfo->updatefunc(ntree, node);
+       
+       nodeUpdateInternalLinks(ntree, node);
+       
        /* clear update flag */
        node->update = 0;
 }
@@ -1613,8 +1928,8 @@ int nodeUpdateID(bNodeTree *ntree, ID *id)
        ntreetype = ntreeGetType(ntree->type);
        
        if (ntreetype->update_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;
                                node->update |= NODE_UPDATE_ID;
                                ntreetype->update_node(ntree, node);
@@ -1624,8 +1939,8 @@ int nodeUpdateID(bNodeTree *ntree, ID *id)
                }
        }
        else {
-               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;
                                node->update |= NODE_UPDATE_ID;
                                if (node->typeinfo->updatefunc)
@@ -1636,15 +1951,27 @@ int nodeUpdateID(bNodeTree *ntree, ID *id)
                }
        }
        
+       for (node = ntree->nodes.first; node; node = node->next) {
+               nodeUpdateInternalLinks(ntree, node);
+       }
+       
        return change;
 }
 
+void nodeUpdateInternalLinks(bNodeTree *ntree, bNode *node)
+{
+       BLI_freelistN(&node->internal_links);
+       
+       if (node->typeinfo && node->typeinfo->update_internal_links)
+               node->typeinfo->update_internal_links(ntree, node);
+}
+
 
 /* ************* node type access ********** */
 
 int nodeValid(bNodeTree *ntree, bNodeTemplate *ntemp)
 {
-       bNodeType *ntype= node_get_type(ntree, ntemp->type);
+       bNodeType *ntype = node_get_type(ntree, ntemp->type);
        if (ntype) {
                if (ntype->validfunc)
                        return ntype->validfunc(ntree, ntemp);
@@ -1655,9 +1982,9 @@ int nodeValid(bNodeTree *ntree, bNodeTemplate *ntemp)
                return 0;
 }
 
-const charnodeLabel(bNode *node)
+const char *nodeLabel(bNode *node)
 {
-       if (node->label[0]!='\0')
+       if (node->label[0] != '\0')
                return node->label;
        else if (node->typeinfo->labelfunc)
                return node->typeinfo->labelfunc(node);
@@ -1711,12 +2038,11 @@ void node_type_base(bNodeTreeType *ttype, bNodeType *ntype, int type, const char
 
        /* Default muting stuff. */
        if (ttype)
-               ntype->internal_connect = ttype->internal_connect;
+               ntype->update_internal_links = ttype->update_internal_links;
 
        /* default size values */
-       ntype->width = 140;
-       ntype->minwidth = 100;
-       ntype->maxwidth = 320;
+       node_type_size_preset(ntype, NODE_SIZE_DEFAULT);
+       
        ntype->height = 100;
        ntype->minheight = 30;
        ntype->maxheight = FLT_MAX;
@@ -1748,6 +2074,21 @@ void node_type_size(struct bNodeType *ntype, int width, int minwidth, int maxwid
                ntype->maxwidth = maxwidth;
 }
 
+void node_type_size_preset(struct bNodeType *ntype, eNodeSizePreset size)
+{
+       switch (size) {
+               case NODE_SIZE_DEFAULT:
+                       node_type_size(ntype, 140, 100, 320);
+                       break;
+               case NODE_SIZE_SMALL:
+                       node_type_size(ntype, 100, 80, 320);
+                       break;
+               case NODE_SIZE_LARGE:
+                       node_type_size(ntype, 140, 120, 500);
+                       break;
+       }
+}
+
 void node_type_storage(bNodeType *ntype, const char *storagename, void (*freestoragefunc)(struct bNode *), void (*copystoragefunc)(struct bNode *, struct bNode *))
 {
        if (storagename)
@@ -1769,8 +2110,8 @@ void node_type_template(struct bNodeType *ntype, struct bNodeTemplate (*template
 }
 
 void node_type_update(struct bNodeType *ntype,
-                                         void (*updatefunc)(struct bNodeTree *ntree, struct bNode *node),
-                                         void (*verifyfunc)(struct bNodeTree *ntree, struct bNode *node, struct ID *id))
+                      void (*updatefunc)(struct bNodeTree *ntree, struct bNode *node),
+                      void (*verifyfunc)(struct bNodeTree *ntree, struct bNode *node, struct ID *id))
 {
        ntype->updatefunc = updatefunc;
        ntype->verifyfunc = verifyfunc;
@@ -1783,9 +2124,9 @@ void node_type_tree(struct bNodeType *ntype, void (*inittreefunc)(struct bNodeTr
 }
 
 void node_type_group_edit(struct bNodeType *ntype,
-                                                 struct bNodeTree *(*group_edit_get)(struct bNode *node),
-                                                 struct bNodeTree *(*group_edit_set)(struct bNode *node, int edit),
-                                                 void (*group_edit_clear)(struct bNode *node))
+                          struct bNodeTree *(*group_edit_get)(struct bNode *node),
+                          struct bNodeTree *(*group_edit_set)(struct bNode *node, int edit),
+                          void (*group_edit_clear)(struct bNode *node))
 {
        ntype->group_edit_get = group_edit_get;
        ntype->group_edit_set = group_edit_set;
@@ -1798,18 +2139,18 @@ void node_type_exec(struct bNodeType *ntype, void (*execfunc)(void *data, struct
 }
 
 void node_type_exec_new(struct bNodeType *ntype,
-                                               void *(*initexecfunc)(struct bNode *node),
-                                               void (*freeexecfunc)(struct bNode *node, void *nodedata),
-                                               void (*newexecfunc)(void *data, int thread, struct bNode *, void *nodedata, struct bNodeStack **, struct bNodeStack **))
+                        void *(*initexecfunc)(struct bNode *node),
+                        void (*freeexecfunc)(struct bNode *node, void *nodedata),
+                        void (*newexecfunc)(void *data, int thread, struct bNode *, void *nodedata, struct bNodeStack **, struct bNodeStack **))
 {
        ntype->initexecfunc = initexecfunc;
        ntype->freeexecfunc = freeexecfunc;
        ntype->newexecfunc = newexecfunc;
 }
 
-void node_type_internal_connect(bNodeType *ntype, ListBase (*internal_connect)(bNodeTree *, bNode *))
+void node_type_internal_links(bNodeType *ntype, void (*update_internal_links)(bNodeTree *, bNode *))
 {
-       ntype->internal_connect = internal_connect;
+       ntype->update_internal_links = update_internal_links;
 }
 
 void node_type_gpu(struct bNodeType *ntype, int (*gpufunc)(struct GPUMaterial *mat, struct bNode *node, struct GPUNodeStack *in, struct GPUNodeStack *out))
@@ -1829,10 +2170,10 @@ void node_type_compatibility(struct bNodeType *ntype, short compatibility)
 
 static bNodeType *is_nodetype_registered(ListBase *typelist, int type) 
 {
-       bNodeType *ntype= typelist->first;
+       bNodeType *ntype = typelist->first;
        
-       for (;ntype; ntype= ntype->next )
-               if (ntype->type==type)
+       for (; ntype; ntype = ntype->next)
+               if (ntype->type == type)
                        return ntype;
        
        return NULL;
@@ -1841,10 +2182,28 @@ static bNodeType *is_nodetype_registered(ListBase *typelist, int type)
 void nodeRegisterType(bNodeTreeType *ttype, bNodeType *ntype) 
 {
        ListBase *typelist = &(ttype->node_types);
-       bNodeType *found= is_nodetype_registered(typelist, ntype->type);
+       bNodeType *found = is_nodetype_registered(typelist, ntype->type);
        
-       if (found==NULL)
+       if (found == NULL)
                BLI_addtail(typelist, ntype);
+       
+       /* Associate the RNA struct type with the bNodeType.
+        * Dynamically registered nodes will create an RNA type at runtime
+        * and call RNA_struct_blender_type_set, so this only needs to be done for old RNA types
+        * created in makesrna, which can not be associated to a bNodeType immediately,
+        * since bNodeTypes are registered afterward ...
+        */
+       #define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \
+       if (ID == ntype->type) { \
+               StructRNA *srna = RNA_struct_find(STRINGIFY_ARG(Category##StructName)); \
+               BLI_assert(srna != NULL); \
+               RNA_struct_blender_type_set(srna, ntype); \
+       }
+       
+       /* XXX hack, this file will be moved to the nodes folder in customnodes branch,
+        * then this stupid include path is not needed any more.
+        */
+       #include "intern/rna_nodetree_types.h"
 }
 
 static void registerCompositNodes(bNodeTreeType *ttype)
@@ -1853,8 +2212,6 @@ static void registerCompositNodes(bNodeTreeType *ttype)
        register_node_type_reroute(ttype);
        
        register_node_type_cmp_group(ttype);
-//     register_node_type_cmp_forloop(ttype);
-//     register_node_type_cmp_whileloop(ttype);
        
        register_node_type_cmp_rlayers(ttype);
        register_node_type_cmp_image(ttype);
@@ -1884,6 +2241,7 @@ static void registerCompositNodes(bNodeTreeType *ttype)
        register_node_type_cmp_normal(ttype);
        register_node_type_cmp_curve_vec(ttype);
        register_node_type_cmp_map_value(ttype);
+       register_node_type_cmp_map_range(ttype);
        register_node_type_cmp_normalize(ttype);
        
        register_node_type_cmp_filter(ttype);
@@ -1892,6 +2250,8 @@ static void registerCompositNodes(bNodeTreeType *ttype)
        register_node_type_cmp_bilateralblur(ttype);
        register_node_type_cmp_vecblur(ttype);
        register_node_type_cmp_dilateerode(ttype);
+       register_node_type_cmp_inpaint(ttype);
+       register_node_type_cmp_despeckle(ttype);
        register_node_type_cmp_defocus(ttype);
        
        register_node_type_cmp_valtorgb(ttype);
@@ -1940,6 +2300,7 @@ static void registerCompositNodes(bNodeTreeType *ttype)
        register_node_type_cmp_bokehimage(ttype);
        register_node_type_cmp_bokehblur(ttype);
        register_node_type_cmp_switch(ttype);
+       register_node_type_cmp_pixelate(ttype);
 
        register_node_type_cmp_mask(ttype);
        register_node_type_cmp_trackpos(ttype);
@@ -1951,8 +2312,6 @@ static void registerShaderNodes(bNodeTreeType *ttype)
        register_node_type_reroute(ttype);
        
        register_node_type_sh_group(ttype);
-       //register_node_type_sh_forloop(ttype);
-       //register_node_type_sh_whileloop(ttype);
 
        register_node_type_sh_output(ttype);
        register_node_type_sh_material(ttype);
@@ -1988,16 +2347,24 @@ static void registerShaderNodes(bNodeTreeType *ttype)
        register_node_type_sh_layer_weight(ttype);
        register_node_type_sh_tex_coord(ttype);
        register_node_type_sh_particle_info(ttype);
+       register_node_type_sh_hair_info(ttype);
+       register_node_type_sh_bump(ttype);
+       register_node_type_sh_script(ttype);
+       register_node_type_sh_tangent(ttype);
+       register_node_type_sh_normal_map(ttype);
 
        register_node_type_sh_background(ttype);
+       register_node_type_sh_bsdf_anisotropic(ttype);
        register_node_type_sh_bsdf_diffuse(ttype);
        register_node_type_sh_bsdf_glossy(ttype);
        register_node_type_sh_bsdf_glass(ttype);
+       register_node_type_sh_bsdf_refraction(ttype);
        register_node_type_sh_bsdf_translucent(ttype);
        register_node_type_sh_bsdf_transparent(ttype);
        register_node_type_sh_bsdf_velvet(ttype);
        register_node_type_sh_emission(ttype);
        register_node_type_sh_holdout(ttype);
+       register_node_type_sh_ambient_occlusion(ttype);
        //register_node_type_sh_volume_transparent(ttype);
        //register_node_type_sh_volume_isotropic(ttype);
        register_node_type_sh_mix_shader(ttype);
@@ -2017,6 +2384,7 @@ static void registerShaderNodes(bNodeTreeType *ttype)
        register_node_type_sh_tex_gradient(ttype);
        register_node_type_sh_tex_magic(ttype);
        register_node_type_sh_tex_checker(ttype);
+       register_node_type_sh_tex_brick(ttype);
 }
 
 static void registerTextureNodes(bNodeTreeType *ttype)
@@ -2025,8 +2393,6 @@ static void registerTextureNodes(bNodeTreeType *ttype)
        register_node_type_reroute(ttype);
        
        register_node_type_tex_group(ttype);
-//     register_node_type_tex_forloop(ttype);
-//     register_node_type_tex_whileloop(ttype);
        
        register_node_type_tex_math(ttype);
        register_node_type_tex_mix_rgb(ttype);
@@ -2070,7 +2436,7 @@ static void registerTextureNodes(bNodeTreeType *ttype)
 static void free_typeinfos(ListBase *list)
 {
        bNodeType *ntype, *next;
-       for (ntype=list->first; ntype; ntype=next) {
+       for (ntype = list->first; ntype; ntype = next) {
                next = ntype->next;
 
                if (ntype->needs_free)
@@ -2080,6 +2446,10 @@ static void free_typeinfos(ListBase *list)
 
 void init_nodesystem(void) 
 {
+       /* init clipboard */
+       node_clipboard.nodes.first = node_clipboard.nodes.last = NULL;
+       node_clipboard.links.first = node_clipboard.links.last = NULL;
+       
        registerCompositNodes(ntreeGetType(NTREE_COMPOSIT));
        registerShaderNodes(ntreeGetType(NTREE_SHADER));
        registerTextureNodes(ntreeGetType(NTREE_TEXTURE));
@@ -2102,14 +2472,14 @@ void clear_scene_in_nodes(Main *bmain, Scene *sce)
        Scene *sce1;
        bNode *node;
 
-       for (sce1= bmain->scene.first; sce1; sce1=sce1->id.next) {
-               if (sce1!=sce) {
+       for (sce1 = bmain->scene.first; sce1; sce1 = sce1->id.next) {
+               if (sce1 != sce) {
                        if (sce1->nodetree) {
-                               for (node= sce1->nodetree->nodes.first; node; node= node->next) {
-                                       if (node->type==CMP_NODE_R_LAYERS) {
-                                               Scene *nodesce= (Scene *)node->id;
+                               for (node = sce1->nodetree->nodes.first; node; node = node->next) {
+                                       if (node->type == CMP_NODE_R_LAYERS) {
+                                               Scene *nodesce = (Scene *)node->id;
                                                
-                                               if (nodesce==sce) node->id = NULL;
+                                               if (nodesce == sce) node->id = NULL;
                                        }
                                }
                        }