* Merge of PyNodes to trunk. Finally!
authorNathan Letwory <nathan@letworyinteractive.com>
Sat, 9 Feb 2008 23:17:15 +0000 (23:17 +0000)
committerNathan Letwory <nathan@letworyinteractive.com>
Sat, 9 Feb 2008 23:17:15 +0000 (23:17 +0000)
  See http://wiki.blender.org/index.php/BlenderDev/PyNodes and
  http://wiki.blender.org/index.php/BlenderDev/PyNodes/API
  For current documentation.

  Very very big thanks go to William Germano for fixing the memory issues left
  and for improving on the code.

  In the coming time documentation will be finalised and further stabilising
  of PyNodes is to be expected.

18 files changed:
source/blender/blenkernel/BKE_node.h
source/blender/blenkernel/BKE_utildefines.h
source/blender/blenkernel/SConscript
source/blender/blenkernel/intern/node.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/makesdna/DNA_node_types.h
source/blender/nodes/SConscript
source/blender/nodes/SHD_node.h
source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c
source/blender/python/SConscript
source/blender/python/api2_2x/Blender.c
source/blender/python/api2_2x/Node.c
source/blender/python/api2_2x/Node.h
source/blender/src/drawnode.c
source/blender/src/drawtext.c
source/blender/src/editnode.c
source/blender/src/toolbox.c

index f324c5d693cdea741cb0d416d1ee9dd23006ed79..bad7f0e90be68dea26b646e0cea3e9d1c0e3a9a3 100644 (file)
@@ -87,8 +87,8 @@ typedef struct bNodeType {
        
        /* for use with dynamic typedefs */
        ID *id;
-       void *script; /* holds pointer to python script */
-       void *dict; /* holds pointer to python script dictionary (scope)*/
+       void *pynode; /* holds pointer to python script */
+       void *pydict; /* holds pointer to python script dictionary (scope)*/
 
 } bNodeType;
 
@@ -103,13 +103,14 @@ typedef struct bNodeType {
 #define NODE_CLASS_INPUT               0
 #define NODE_CLASS_OUTPUT              1
 #define NODE_CLASS_OP_COLOR            3
-#define NODE_CLASS_OP_VECTOR           4
-#define NODE_CLASS_OP_FILTER           5
+#define NODE_CLASS_OP_VECTOR   4
+#define NODE_CLASS_OP_FILTER   5
 #define NODE_CLASS_GROUP               6
 #define NODE_CLASS_FILE                        7
-#define NODE_CLASS_CONVERTOR           8
+#define NODE_CLASS_CONVERTOR   8
 #define NODE_CLASS_MATTE               9
 #define NODE_CLASS_DISTORT             10
+#define NODE_CLASS_OP_DYNAMIC  11
 
 /* ************** GENERIC API, TREES *************** */
 
@@ -119,6 +120,7 @@ struct bNodeTree *ntreeAddTree(int type);
 void                   ntreeInitTypes(struct bNodeTree *ntree);
 
 void                   ntreeMakeOwnType(struct bNodeTree *ntree);
+void                   ntreeUpdateType(struct bNodeTree *ntree, struct bNodeType *ntype);
 void                   ntreeFreeTree(struct bNodeTree *ntree);
 struct bNodeTree *ntreeCopyTree(struct bNodeTree *ntree, int internal_select);
 void                   ntreeMakeLocal(struct bNodeTree *ntree);
@@ -144,7 +146,12 @@ void                       nodeVerifyType(struct bNodeTree *ntree, struct bNode *node);
 void                   nodeAddToPreview(struct bNode *, float *, int, int);
 
 void                   nodeUnlinkNode(struct bNodeTree *ntree, struct bNode *node);
-struct bNode   *nodeAddNodeType(struct bNodeTree *ntree, int type, struct bNodeTree *ngroup);
+void                   nodeAddSockets(struct bNode *node, struct bNodeType *ntype);
+struct bNode   *nodeAddNodeType(struct bNodeTree *ntree, int type, struct bNodeTree *ngroup, struct ID *id);
+void                   nodeRegisterType(struct ListBase *typelist, const struct bNodeType *ntype) ;
+void                   nodeUpdateType(struct bNodeTree *ntree, struct bNode* node, struct bNodeType *ntype);
+void                   nodeMakeDynamicType(struct bNode *node);
+int                            nodeDynamicUnlinkText(struct ID *txtid);
 void                   nodeFreeNode(struct bNodeTree *ntree, struct bNode *node);
 struct bNode   *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node);
 
@@ -176,6 +183,7 @@ void                        nodeGroupSocketUseFlags(struct bNodeTree *ngroup);
 
 #define NODE_GROUP             2
 #define NODE_GROUP_MENU                1000
+#define NODE_DYNAMIC_MENU      4000
 
 extern bNodeType node_group_typeinfo;
 
@@ -192,7 +200,7 @@ struct ShadeResult;
 #define SH_NODE_OUTPUT         1
 
 #define SH_NODE_MATERIAL       100
-#define SH_NODE_RGB            101
+#define SH_NODE_RGB                    101
 #define SH_NODE_VALUE          102
 #define SH_NODE_MIX_RGB                103
 #define SH_NODE_VALTORGB       104
@@ -212,12 +220,21 @@ struct ShadeResult;
 #define SH_NODE_SEPRGB         120
 #define SH_NODE_COMBRGB                121
 #define SH_NODE_HUE_SAT                122
-
+#define NODE_DYNAMIC           123
 
 /* custom defines options for Material node */
 #define SH_NODE_MAT_DIFF   1
 #define SH_NODE_MAT_SPEC   2
 #define SH_NODE_MAT_NEG    4
+/* custom defines: states for Script node. These are bit indices */
+#define NODE_DYNAMIC_READY     0 /* 1 */
+#define NODE_DYNAMIC_LOADED    1 /* 2 */
+#define NODE_DYNAMIC_NEW       2 /* 4 */
+#define NODE_DYNAMIC_UPDATED   3 /* 8 */
+#define NODE_DYNAMIC_ADDEXIST  4 /* 16 */
+#define NODE_DYNAMIC_ERROR     5 /* 32 */
+#define NODE_DYNAMIC_REPARSE   6 /* 64 */
+#define NODE_DYNAMIC_SET       15 /* sign */
 
 /* the type definitions array */
 extern struct ListBase node_all_shaders;
@@ -350,5 +367,6 @@ void free_compbuf(struct CompBuf *cbuf); /* internal...*/
 
 void init_nodesystem(void);
 void free_nodesystem(void);
+void reinit_nodesystem(void);
 
 #endif
index fc22f6787b130f2be64dc05bf3716f7c7bc483a7..aa2be236d36098c7e66b7fa9545a93382ff437bf 100644 (file)
 
 /* This one rotates the bytes in an int */
 #define SWITCH_INT(a) { \
-    char s_i, *p_i; \
-    p_i= (char *)&(a); \
-    s_i=p_i[0]; p_i[0]=p_i[3]; p_i[3]=s_i; \
-    s_i=p_i[1]; p_i[1]=p_i[2]; p_i[2]=s_i; }
+       char s_i, *p_i; \
+       p_i= (char *)&(a); \
+       s_i=p_i[0]; p_i[0]=p_i[3]; p_i[3]=s_i; \
+       s_i=p_i[1]; p_i[1]=p_i[2]; p_i[2]=s_i; }
 
 #define SWITCH_SHORT(a)        { \
-    char s_i, *p_i; \
-               p_i= (char *)&(a); \
-                       s_i=p_i[0]; p_i[0]=p_i[1]; p_i[1]=s_i; }
+       char s_i, *p_i; \
+       p_i= (char *)&(a); \
+       s_i=p_i[0]; p_i[0]=p_i[1]; p_i[1]=s_i; }
 
 
 /* Bit operations */
-#define BTST(a,b)     ( ( (a) & 1<<(b) )!=0 )   
-#define BSET(a,b)     ( (a) | 1<<(b) )
+#define BTST(a,b)      ( ( (a) & 1<<(b) )!=0 )   
+#define BNTST(a,b)     ( ( (a) & 1<<(b) )==0 )
+#define BTST2(a,b,c)   ( BTST( (a), (b) ) || BTST( (a), (c) ) )
+#define BSET(a,b)      ( (a) | 1<<(b) )
 #define BCLR(a,b)      ( (a) & ~(1<<(b)) )
 /* bit-row */
 #define BROW(min, max) (((max)>=31? 0xFFFFFFFF: (1<<(max+1))-1) - ((min)? ((1<<(min))-1):0) )
index f8f2f0b9f57f89be09faa7bd60b63ce905c39ee9..1bb98239a6868b3bd19773b0bd63342bfdf48fd7 100644 (file)
@@ -11,6 +11,7 @@ incs += ' #/extern/bullet2/src'
 incs += ' #/intern/bmfont'
 incs += ' #/intern/opennl/extern'
 
+incs += ' ' + env['BF_PYTHON_INC']
 incs += ' ' + env['BF_OPENGL_INC']
 incs += ' ' + env['BF_ZLIB_INC']
 incs += ' ' + env['BF_SDL_INC']
index 43a6f2091dec1879433ae883a316233e031d4341..f30ad81bf0c299515a5ca07ebd3b7865dacb883b 100644 (file)
@@ -27,6 +27,7 @@
  * ***** END GPL LICENSE BLOCK *****
  */
 
+#include <Python.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -34,6 +35,7 @@
 #include "DNA_image_types.h"
 #include "DNA_node_types.h"
 #include "DNA_material_types.h"
+#include "DNA_text_types.h"
 #include "DNA_scene_types.h"
 
 #include "BKE_blender.h"
@@ -44,6 +46,7 @@
 #include "BKE_main.h"
 #include "BKE_node.h"
 #include "BKE_texture.h"
+#include "BKE_text.h"
 #include "BKE_utildefines.h"
 
 #include "BLI_arithb.h"
@@ -72,7 +75,7 @@ ListBase node_all_shaders = {NULL, NULL};
 
 /* ************** Type stuff **********  */
 
-static bNodeType *node_get_type(bNodeTree *ntree, int type, bNodeTree *ngroup)
+static bNodeType *node_get_type(bNodeTree *ntree, int type, bNodeTree *ngroup, ID *id)
 {
        if(type==NODE_GROUP) {
                if(ngroup && GS(ngroup->id.name)==ID_NT) {
@@ -83,7 +86,7 @@ static bNodeType *node_get_type(bNodeTree *ntree, int type, bNodeTree *ngroup)
        else {
                bNodeType *ntype = ntree->alltypes.first;
                for(; ntype; ntype= ntype->next)
-                       if(ntype->type==type)
+                       if(ntype->type==type && id==ntype->id )
                                return ntype;
                
                return NULL;
@@ -105,7 +108,27 @@ void ntreeInitTypes(bNodeTree *ntree)
        
        for(node= ntree->nodes.first; node; node= next) {
                next= node->next;
-               node->typeinfo= node_get_type(ntree, node->type, (bNodeTree *)node->id);
+               if(node->type==NODE_DYNAMIC) {
+                       bNodeType *stype= NULL;
+                       if(node->id==NULL) { /* empty script node */
+                               stype= node_get_type(ntree, node->type, NULL, NULL);
+                       } else { /* not an empty script node */
+                               stype= node_get_type(ntree, node->type, NULL, node->id);
+                               if(!stype) {
+                                       stype= node_get_type(ntree, node->type, NULL, NULL);
+                                       /* needed info if the pynode script fails now: */
+                                       if (node->id) node->storage= ntree;
+                               } else {
+                                       node->custom1= 0;
+                                       node->custom1= BSET(node->custom1,NODE_DYNAMIC_ADDEXIST);
+                               }
+                       }
+                       node->typeinfo= stype;
+                       node->typeinfo->initfunc(node);
+               } else {
+                       node->typeinfo= node_get_type(ntree, node->type, (bNodeTree *)node->id, NULL);
+               }
+
                if(node->typeinfo==NULL) {
                        printf("Error: Node type %s doesn't exist anymore, removed\n", node->name);
                        nodeFreeNode(ntree, node);
@@ -115,6 +138,18 @@ void ntreeInitTypes(bNodeTree *ntree)
        ntree->init |= NTREE_TYPE_INIT;
 }
 
+/* updates node with (modified) bNodeType.. this should be done for all trees */
+void ntreeUpdateType(bNodeTree *ntree, bNodeType *ntype)
+{
+       bNode *node;
+
+       for(node= ntree->nodes.first; node; node= node->next) {
+               if(node->typeinfo== ntype) {
+                       nodeUpdateType(ntree, node, ntype);
+               }
+       }
+}
+
 /* only used internal... we depend on type definitions! */
 static bNodeSocket *node_add_socket_type(ListBase *lb, bNodeSocketType *stype)
 {
@@ -137,7 +172,7 @@ static bNodeSocket *node_add_socket_type(ListBase *lb, bNodeSocketType *stype)
        
        if(lb)
                BLI_addtail(lb, sock);
-       
+
        return sock;
 }
 
@@ -513,7 +548,7 @@ bNode *nodeMakeGroupFromSelected(bNodeTree *ntree)
        ntreeMakeOwnType(ngroup);
        
        /* make group node */
-       gnode= nodeAddNodeType(ntree, NODE_GROUP, ngroup);
+       gnode= nodeAddNodeType(ntree, NODE_GROUP, ngroup, NULL);
        gnode->locx= 0.5f*(min[0]+max[0]);
        gnode->locy= 0.5f*(min[1]+max[1]);
        
@@ -767,29 +802,10 @@ int nodeGroupUnGroup(bNodeTree *ntree, bNode *gnode)
 }
 
 /* ************** Add stuff ********** */
-
-bNode *nodeAddNodeType(bNodeTree *ntree, int type, bNodeTree *ngroup)
+void nodeAddSockets(bNode *node, bNodeType *ntype)
 {
-       bNode *node;
-       bNodeType *ntype= node_get_type(ntree, type, ngroup);
        bNodeSocketType *stype;
-       
-       node= MEM_callocN(sizeof(bNode), "new node");
-       BLI_addtail(&ntree->nodes, node);
-       node->typeinfo= ntype;
-       
-       if(ngroup)
-               BLI_strncpy(node->name, ngroup->id.name+2, NODE_MAXSTR);
-       else
-               BLI_strncpy(node->name, ntype->name, NODE_MAXSTR);
-       node->type= ntype->type;
-       node->flag= NODE_SELECT|ntype->flag;
-       node->width= ntype->width;
-       node->miniwidth= 42.0f;         /* small value only, allows print of first chars */
-       
-       if(type==NODE_GROUP)
-               node->id= (ID *)ngroup;
-       
+
        if(ntype->inputs) {
                stype= ntype->inputs;
                while(stype->type != -1) {
@@ -804,13 +820,84 @@ bNode *nodeAddNodeType(bNodeTree *ntree, int type, bNodeTree *ngroup)
                        stype++;
                }
        }
-       
+}
+
+
+bNode *nodeAddNodeType(bNodeTree *ntree, int type, bNodeTree *ngroup, ID *id)
+{
+       bNode *node= NULL;
+       bNodeType *ntype= NULL;
+
+       if(type>=NODE_DYNAMIC_MENU) {
+               int a=0, idx= type-NODE_DYNAMIC_MENU;
+               ntype= ntree->alltypes.first;
+               while(ntype) {
+                       if(ntype->type==NODE_DYNAMIC) {
+                               if(a==idx)
+                                       break;
+                               a++;
+                       }
+                       ntype= ntype->next;
+               }
+       } else
+               ntype= node_get_type(ntree, type, ngroup, id);
+
+       node= MEM_callocN(sizeof(bNode), "new node");
+       BLI_addtail(&ntree->nodes, node);
+       node->typeinfo= ntype;
+       if(type>=NODE_DYNAMIC_MENU)
+               node->custom2= type; /* for node_dynamic_init */
+
+       if(ngroup)
+               BLI_strncpy(node->name, ngroup->id.name+2, NODE_MAXSTR);
+       else if(type>NODE_DYNAMIC_MENU) {
+               BLI_strncpy(node->name, ntype->id->name+2, NODE_MAXSTR);
+       }
+       else
+               BLI_strncpy(node->name, ntype->name, NODE_MAXSTR);
+       node->type= ntype->type;
+       node->flag= NODE_SELECT|ntype->flag;
+       node->width= ntype->width;
+       node->miniwidth= 42.0f;         /* small value only, allows print of first chars */
+
+       if(type==NODE_GROUP)
+               node->id= (ID *)ngroup;
+
        /* need init handler later? */
-   /* got it-bob*/
-   if(ntype->initfunc!=NULL)
-      ntype->initfunc(node);
+       /* got it-bob*/
+       if(ntype->initfunc!=NULL)
+               ntype->initfunc(node);
+
+       nodeAddSockets(node, ntype);
+
+       return node;
+}
+
+void nodeMakeDynamicType(bNode *node)
+{
+       /* find SH_DYNAMIC_NODE ntype */
+       bNodeType *ntype= node_all_shaders.first;
+       while(ntype) {
+               if(ntype->type==NODE_DYNAMIC && ntype->id==NULL)
+                       break;
+               ntype= ntype->next;
+       }
 
-   return node;
+       /* make own type struct to fill */
+       if(ntype) {
+               /*node->typeinfo= MEM_dupallocN(ntype);*/
+               bNodeType *newtype= MEM_callocN(sizeof(bNodeType), "dynamic bNodeType");
+               *newtype= *ntype;
+               newtype->name= BLI_strdup(ntype->name);
+               node->typeinfo= newtype;
+       }
+}
+
+
+void nodeUpdateType(bNodeTree *ntree, bNode* node, bNodeType *ntype)
+{
+       verify_socket_list(ntree, &node->inputs, ntype->inputs);
+       verify_socket_list(ntree, &node->outputs, ntype->outputs);
 }
 
 /* keep socket listorder identical, for copying links */
@@ -1042,6 +1129,7 @@ void nodeFreeNode(bNodeTree *ntree, bNode *node)
        if(node->typeinfo && node->typeinfo->freestoragefunc) {
                node->typeinfo->freestoragefunc(node);
        }
+
        MEM_freeN(node);
 }
 
@@ -2322,12 +2410,12 @@ void ntreeCompositTagGenerators(bNodeTree *ntree)
 
 /* ************* node definition init ********** */
 
-static bNodeType *is_nodetype_registered(ListBase *typelist, int type) 
+static bNodeType *is_nodetype_registered(ListBase *typelist, int type, ID *id
 {
        bNodeType *ntype= typelist->first;
        
        for(;ntype; ntype= ntype->next )
-               if(ntype->type==type)
+               if(ntype->type==type && ntype->id==id)
                        return ntype;
        
        return NULL;
@@ -2336,10 +2424,10 @@ static bNodeType *is_nodetype_registered(ListBase *typelist, int type)
 /* type can be from a static array, we make copy for duplicate types (like group) */
 void nodeRegisterType(ListBase *typelist, const bNodeType *ntype) 
 {
-       bNodeType *found= is_nodetype_registered(typelist, ntype->type);
+       bNodeType *found= is_nodetype_registered(typelist, ntype->type, ntype->id);
        
        if(found==NULL) {
-               bNodeType *ntypen= MEM_mallocN(sizeof(bNodeType), "node type");
+               bNodeType *ntypen= MEM_callocN(sizeof(bNodeType), "node type");
                *ntypen= *ntype;
                BLI_addtail(typelist, ntypen);
        }
@@ -2409,7 +2497,6 @@ static void registerCompositNodes(ListBase *ntypelist)
        nodeRegisterType(ntypelist, &cmp_node_crop);
        nodeRegisterType(ntypelist, &cmp_node_displace);
        nodeRegisterType(ntypelist, &cmp_node_mapuv);
-
        nodeRegisterType(ntypelist, &cmp_node_glare);
        nodeRegisterType(ntypelist, &cmp_node_tonemap);
        nodeRegisterType(ntypelist, &cmp_node_lensdist);
@@ -2436,12 +2523,46 @@ static void registerShaderNodes(ListBase *ntypelist)
        nodeRegisterType(ntypelist, &sh_node_value);
        nodeRegisterType(ntypelist, &sh_node_rgb);
        nodeRegisterType(ntypelist, &sh_node_texture);
+       nodeRegisterType(ntypelist, &node_dynamic_typeinfo);
        nodeRegisterType(ntypelist, &sh_node_invert);
        nodeRegisterType(ntypelist, &sh_node_seprgb);
        nodeRegisterType(ntypelist, &sh_node_combrgb);
        nodeRegisterType(ntypelist, &sh_node_hue_sat);
 }
 
+static void remove_dynamic_typeinfos(ListBase *list)
+{
+       bNodeType *ntype= list->first;
+       bNodeType *next= NULL;
+       while(ntype) {
+               next= ntype->next;
+               if(ntype->type==NODE_DYNAMIC && ntype->id!=NULL) {
+                       BLI_remlink(list, ntype);
+                       if(ntype->inputs) {
+                               bNodeSocketType *sock= ntype->inputs;
+                               while(sock->type!=-1) {
+                                       MEM_freeN(sock->name);
+                                       sock++;
+                               }
+                               MEM_freeN(ntype->inputs);
+                       }
+                       if(ntype->outputs) {
+                               bNodeSocketType *sock= ntype->outputs;
+                               while(sock->type!=-1) {
+                                       MEM_freeN(sock->name);
+                                       sock++;
+                               }
+                               MEM_freeN(ntype->outputs);
+                       }
+                       if(ntype->name) {
+                               MEM_freeN(ntype->name);
+                       }
+                       MEM_freeN(ntype);
+               }
+               ntype= next;
+       }
+}
+
 void init_nodesystem(void) 
 {
        registerCompositNodes(&node_all_composit);
@@ -2450,8 +2571,15 @@ void init_nodesystem(void)
 
 void free_nodesystem(void) 
 {
+       /*remove_dynamic_typeinfos(&node_all_composit);*/ /* unused for now */
        BLI_freelistN(&node_all_composit);
+       remove_dynamic_typeinfos(&node_all_shaders);
        BLI_freelistN(&node_all_shaders);
 }
 
+void reinit_nodesystem(void)
+{
+       /*remove_dynamic_typeinfos(&node_all_composit);*/ /* unused for now */
+       /*remove_dynamic_typeinfos(&node_all_shaders);*//*crash on undo/redo*/
+}
 
index 33fe1b36f52ee5a9126f3f0321d30d99ca6d2966..fa58022079960debd89bb165f1b624973f6c8261 100644 (file)
@@ -1453,11 +1453,18 @@ static void lib_link_nodetree(FileData *fd, Main *main)
 }
 
 /* verify types for nodes and groups, all data has to be read */
-static void lib_verify_nodetree(Main *main)
+/* open = 0: appending/linking, open = 1: open new file (need to clean out dynamic
+ * typedefs*/
+static void lib_verify_nodetree(Main *main, int open)
 {
        Scene *sce;
        Material *ma;
        bNodeTree *ntree;
+
+       /* this crashes blender on undo/redo
+       if(open==1) {
+               reinit_nodesystem();
+       }*/
        
        /* now create the own typeinfo structs an verify nodes */
        /* here we still assume no groups in groups */
@@ -1494,6 +1501,12 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
        
        link_list(fd, &ntree->nodes);
        for(node= ntree->nodes.first; node; node= node->next) {
+               if(node->type == NODE_DYNAMIC) {
+                       node->custom1= 0;
+                       node->custom1= BSET(node->custom1, NODE_DYNAMIC_LOADED);
+                       node->typeinfo= NULL;
+               }
+
                node->storage= newdataadr(fd, node->storage);
                if(node->storage) {
                        
@@ -7546,7 +7559,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, BlendReadError *error_r)
        blo_join_main(&fd->mainlist);
 
        lib_link_all(fd, bfd->main);
-       lib_verify_nodetree(bfd->main);
+       lib_verify_nodetree(bfd->main, 1);
        fix_relpaths_library(fd->filename, bfd->main); /* make all relative paths, relative to the open blend file */
        
        if(fg)
@@ -8508,7 +8521,7 @@ static Library* library_append( Scene *scene, char* file, char *dir, int idcode,
        G.main= fd->mainlist.first;
 
        lib_link_all(fd, G.main);
-       lib_verify_nodetree(G.main);
+       lib_verify_nodetree(G.main, 0);
        fix_relpaths_library(G.sce, G.main); /* make all relative paths, relative to the open blend file */
 
        /* give a base to loose objects. If group append, do it for objects too */
index d9766af6ba11884bb661a3c504f33fc7e48c37d7..0804ec9689cdd83cce7bc36ac4c8cc572be840bd 100644 (file)
@@ -452,7 +452,7 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree)
                writestruct(wd, DATA, "bNode", 1, node);
 
        for(node= ntree->nodes.first; node; node= node->next) {
-               if(node->storage) {
+               if(node->storage && node->type!=NODE_DYNAMIC) {
                        /* could be handlerized at some point, now only 1 exception still */
                        if(ntree->type==NTREE_SHADER && (node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB))
                                write_curvemapping(wd, node->storage);
index 0b462a46753bd4ebc1cece0cdb7bf487adfb28f8..0e2805c88b7d20f1812b05baf091d7266f9cef6a 100644 (file)
@@ -258,6 +258,10 @@ typedef struct NodeDefocus {
        float fstop, maxblur, bthresh, scale;
 } NodeDefocus;
 
+typedef struct NodeScriptDict {
+       void *dict; /* for PyObject *dict */
+       void *node; /* for BPy_Node *node */
+} NodeScriptDict;
 
 /* qdn: glare node */
 typedef struct NodeGlare {
index 0460848b4a5547571688c8e21adfa0ff2643d44f..cc7cde6fc266826910ae04269a857be105c6808c 100644 (file)
@@ -13,7 +13,7 @@ incs += ' ../blenloader ../quicktime'
 incs += ' ../blenkernel ../renderconverter '
 
 
-
+incs += ' ' + env['BF_PYTHON_INC']
 incs += ' ' + env['BF_OPENGL_INC']
 incs += ' ' + env['BF_ZLIB_INC']
 incs += ' ' + env['BF_SDL_INC']
@@ -41,6 +41,6 @@ if env['WITH_BF_QUICKTIME'] == 1:
     defs += ' WITH_QUICKTIME'
     incs += ' ' + env['BF_QUICKTIME_INC']
 
-defs += ' WITH_CCGSUBSURF'
+defs += ' WITH_CCGSUBSURF USE_PYNODES '
 
 env.BlenderLib ( libname = 'nodes', sources = sources, includes = Split(incs), defines = Split(defs), libtype=['core','player'], priority = [65, 20] )
index 8064a543ca003a275ed9c24af77dbb90d24910d4..d75d7c9f568d07fd086794dc4e09cb2bacdf71a9 100644 (file)
@@ -56,13 +56,13 @@ extern bNodeType sh_node_curve_rgb;
 extern bNodeType sh_node_math;
 extern bNodeType sh_node_vect_math;
 extern bNodeType sh_node_squeeze;
+extern bNodeType node_dynamic_typeinfo;
 extern bNodeType sh_node_material_ext;
 extern bNodeType sh_node_invert;
 extern bNodeType sh_node_seprgb;
 extern bNodeType sh_node_combrgb;
 extern bNodeType sh_node_hue_sat;
 
-
 #endif
 
 
index 1ba777a0533fdfa47f778cd3b176aa7d9e5da320..c198e73a3bfd9f0399ba468824e6f804bad85cc5 100644 (file)
@@ -34,6 +34,7 @@
 
 #include "DNA_text_types.h"
 #include "BKE_text.h"
+#include "BKE_utildefines.h"
 
 #include "api2_2x/Node.h"
 #include "api2_2x/gen_utils.h"
@@ -41,6 +42,9 @@
 
 #include "../SHD_util.h"
 
+static void node_dynamic_setup(bNode *node);
+static void node_dynamic_exec_cb(void *data, bNode *node, bNodeStack **in, bNodeStack **out);
+
 static PyObject *init_dynamicdict(void) {
        PyObject *newscriptdict= PyDict_New();
        PyDict_SetItemString(newscriptdict, "__builtins__", PyEval_GetBuiltins());
@@ -48,198 +52,575 @@ static PyObject *init_dynamicdict(void) {
        return newscriptdict;
 }
 
+/* unused for now
 static void free_dynamicdict(PyObject *dict) {
-       if(dict!=NULL) {
+       if (dict!=NULL) {
                Py_DECREF(dict);
        }
 }
+*/
 
-static void node_dynamic_init(bNode *node) {
-       NodeScriptDict *nsd= MEM_callocN(sizeof(NodeScriptDict), "node script dictionary");
-       int type= node->custom2;
-       node->custom2= 0;
-       node->storage= nsd;
-       if(type>=NODE_DYNAMIC_MENU) {
-               if(type==NODE_DYNAMIC_MENU) {
-                       nodeMakeDynamicType(node);
-                       node->custom1= SH_NODE_DYNAMIC_NEW;
-               } else {
-                       node->custom1= SH_NODE_DYNAMIC_ADDEXIST;
+static bNodeType *node_dynamic_find_typeinfo(ListBase *list, ID *id)
+{
+       bNodeType *ntype = list->first;
+
+       while(ntype) {
+               if (ntype->type == NODE_DYNAMIC && ntype->id == id)
+                       break;
+               ntype = ntype->next;
+       }
+
+       return ntype; /* NULL if doesn't exist */
+}
+
+static void node_dynamic_free_typeinfo_sockets(bNodeType *tinfo)
+{
+       bNodeSocketType *sock;
+
+       if (!tinfo) return;
+
+       if (tinfo->inputs) {
+               sock = tinfo->inputs;
+               while (sock->type != -1) {
+                       MEM_freeN(sock->name);
+                       sock++;
+               }
+               MEM_freeN(tinfo->inputs);
+               tinfo->inputs = NULL;
+       }
+       if (tinfo->outputs) {
+               sock = tinfo->outputs;
+               while (sock->type != -1) {
+                       MEM_freeN(sock->name);
+                       sock++;
+               }
+               MEM_freeN(tinfo->outputs);
+               tinfo->outputs = NULL;
+       }
+}
+
+static void node_dynamic_free_typeinfo(bNodeType *tinfo)
+{
+       if (!tinfo) return;
+
+       node_dynamic_free_typeinfo_sockets(tinfo);
+
+       if (tinfo->name) { MEM_freeN(tinfo->name); }
+
+       MEM_freeN(tinfo);
+}
+
+static void node_dynamic_free_sockets(bNode *node)
+{
+       BLI_freelistN(&node->inputs);
+       BLI_freelistN(&node->outputs);
+}
+
+/* For now we just remove the socket links. It's the safest
+ * route, since an update in the script may change completely the
+ * inputs and outputs. Trying to recreate the node links would be
+ * nicer for pynode authors, though. */
+static void node_dynamic_update_socket_links(bNode *node, bNodeTree *ntree)
+{
+       if (ntree) {
+               nodeVerifyType(ntree, node);
+       }
+       else {
+               Material *ma;
+
+               for (ma= G.main->mat.first; ma; ma= ma->id.next) {
+                       if (ma->nodetree) {
+                               bNode *nd;
+                               for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) {
+                                       if (nd == node) nodeVerifyType(ma->nodetree, node);
+                               }
+                       }
                }
-               node->id= node->typeinfo->id;
-               nodeDynamicParse(node);
-       } else {
-               if(node->custom1== SH_NODE_DYNAMIC_LOADED) {
-                       nodeMakeDynamicType(node);
-                       nodeDynamicParse(node);
-               } else if(node->custom1== SH_NODE_DYNAMIC_ADDEXIST)
-                       nodeDynamicParse(node);
        }
 }
 
-static void node_dynamic_free(bNode *node)
+static void node_dynamic_free_storage_cb(bNode *node)
 {
-       NodeScriptDict *nsd= (NodeScriptDict *)(node->storage);
-       BPy_Node *pynode= nsd->node;
-       Py_XDECREF(pynode);
-       free_dynamicdict((PyObject *)(nsd->dict));
+       NodeScriptDict *nsd;
+       PyObject *pydict;
+       BPy_Node *pynode;
+
+       if (!node->storage) return;
+
+       nsd = (NodeScriptDict *)(node->storage);
+       pydict = nsd->dict;
+       if (pydict) {
+               Py_DECREF(pydict);
+       }
+       pynode = nsd->node;
+       if (pynode) {
+               Py_DECREF(pynode);
+       }
        MEM_freeN(node->storage);
+       node->storage = NULL;
 }
 
-static void node_dynamic_copy(bNode *orig_node, bNode *new_node)
+/* Disable pynode when its script fails */
+static void node_dynamic_disable(bNode *node)
 {
-       NodeScriptDict *nsd= (NodeScriptDict *)(orig_node->storage);
-       new_node->storage= MEM_dupallocN(orig_node->storage);
-       if(nsd->node)
-               Py_INCREF((PyObject *)(nsd->node));
-       if(nsd->dict)
-               Py_INCREF((PyObject *)(nsd->dict));
+       node->custom1 = 0;
+       node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ERROR);
 }
 
-static void node_dynamic_exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) {
-       BPy_Node *mynode = NULL;
-       NodeScriptDict *nsd = NULL;
-       PyObject *pyresult = NULL;
-       PyObject *args = NULL;
-       ShadeInput *shi= ((ShaderCallData *)data)->shi;
+/* Disable all pynodes using the given text (script) id */
+static void node_dynamic_disable_all_by_id(ID *id)
+{
+       Material *ma; /* XXX hardcoded for shaders */
 
-       if(node->custom1==SH_NODE_DYNAMIC_NEW) {
-               nodeDynamicParse(node);
-               return;
+       for (ma= G.main->mat.first; ma; ma= ma->id.next) {
+               if (ma->nodetree) {
+                       bNode *nd;
+                       bNodeTree *ntree = ma->nodetree;
+                       for (nd= ntree->nodes.first; nd; nd= nd->next) {
+                               if (nd->id == id) {
+                                       nd->custom1 = 0;
+                                       nd->custom1 = BSET(nd->custom1, NODE_DYNAMIC_ERROR);
+                               }
+                       }
+               }
        }
+}
 
-       if(node->custom2<0)
-               return;
+static void node_rem_socklist_links(bNodeTree *ntree, ListBase *lb)
+{
+       bNodeLink *link, *next;
+       bNodeSocket *sock;
 
-       if(node->custom1==SH_NODE_DYNAMIC_READY || node->custom1==SH_NODE_DYNAMIC_UPDATED) {
-               if(node->custom1== SH_NODE_DYNAMIC_UPDATED)
-                       node->custom1= SH_NODE_DYNAMIC_READY;
+       if (!lb) return;
 
-               nsd = (NodeScriptDict *)node->storage;
+       for (sock= lb->first; sock; sock= sock->next) {
+               for (link= ntree->links.first; link; link= next) {
+                       next= link->next;
+                       if (link->fromsock==sock || link->tosock==sock) {
+                               nodeRemLink(ntree, link);
+                       }
+               }
+       }
+}
 
-               mynode = (BPy_Node *)(nsd->node);
-               if(mynode && PyCallable_Check((PyObject *)mynode)) {
-                       mynode->node= node;
-                       Node_SetStack(mynode, in, NODE_INPUTSTACK);
-                       Node_SetStack(mynode, out, NODE_OUTPUTSTACK);
-                       Node_SetShi(mynode, shi);
-                       args=Py_BuildValue("()");
-                       pyresult= PyObject_Call((PyObject *)mynode, args, NULL);
-                       if(!pyresult) {
-                               if(PyErr_Occurred()) {
-                                       PyErr_Print();
-                                       node->custom2= -1;
-                               } else {
-                                       printf("PyObject_Call __call__ failed\n");
+/* XXX hardcoded for shaders */
+static void node_dynamic_rem_all_links(bNodeType *tinfo)
+{
+       Material *ma;
+       int in, out;
+
+       in = tinfo->inputs ? 1 : 0;
+       out = tinfo->outputs ? 1 : 0;
+
+       for (ma= G.main->mat.first; ma; ma= ma->id.next) {
+               if (ma->nodetree) {
+                       bNode *nd;
+                       bNodeTree *ntree = ma->nodetree;
+                       for (nd= ntree->nodes.first; nd; nd= nd->next) {
+                               if (nd->typeinfo == tinfo) {
+                                       if (in)
+                                               node_rem_socklist_links(ntree, &nd->inputs);
+                                       if (out)
+                                               node_rem_socklist_links(ntree, &nd->outputs);
+                               }
+                       }
+               }
+       }
+}
+
+/* node_dynamic_reset: clean a pynode, getting rid of all
+ * data dynamically created for it.
+ * ntree is used only in a special case: for working pynodes
+ * that were saved on a .blend but fail for some reason when
+ * the file is opened. We need it because pynodes are initialized
+ * before G.main. */
+static void node_dynamic_reset(bNode *node, bNodeTree *ntree)
+{
+       bNodeType *tinfo, *tinfo_default;
+       Material *ma;
+
+       tinfo = node->typeinfo;
+       tinfo_default = node_dynamic_find_typeinfo(&node_all_shaders, NULL);
+
+       node_dynamic_rem_all_links(tinfo);
+       node_dynamic_free_typeinfo_sockets(tinfo);
+
+       if (!ntree) { node_dynamic_free_sockets(node); }
+
+       //wnode_dynamic_update_socket_links(node, ntree);
+       node_dynamic_free_storage_cb(node);
+
+       /* XXX hardcoded for shaders: */
+       if (node->typeinfo->id) { BLI_remlink(&node_all_shaders, tinfo); }
+
+       node->typeinfo = tinfo_default;
+
+       /* reset all other XXX shader nodes sharing this typeinfo */
+       for (ma= G.main->mat.first; ma; ma= ma->id.next) {
+               if (ma->nodetree) {
+                       bNode *nd;
+                       for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) {
+                               if (nd->typeinfo == tinfo) {
+                                       node_dynamic_free_storage_cb(nd);
+                                       node_dynamic_free_sockets(nd);
+                                       nd->typeinfo = tinfo_default;
                                }
                        }
-                       Py_XDECREF(pyresult);
-                       Py_DECREF(args);
                }
        }
+
+       node_dynamic_free_typeinfo(tinfo);
 }
 
-void nodeDynamicParse(struct bNode *node)
+int nodeDynamicUnlinkText(ID *txtid) {
+       Material *ma;
+       int unlinked= 0;
+
+       for (ma= G.main->mat.first; ma; ma= ma->id.next) {
+               if (ma->nodetree) {
+                       bNode *nd, *nd2 = NULL;
+                       for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) {
+                               if ((nd->type == NODE_DYNAMIC) && (nd->id == txtid)) {
+                                       nd->id = NULL;
+                                       nd->custom1 = 0;
+                                       nd->custom1 = BSET(nd->custom1, NODE_DYNAMIC_NEW);
+                                       BLI_strncpy(nd->name, "Dynamic", 8);
+                                       nd2 = nd; /* so we have a ptr to one of them */
+                                       unlinked++;
+                               }
+                       }
+                       /* clean uneeded dynamic data from all nodes that shared
+                        * this text: */
+                       if (nd2) node_dynamic_reset(nd2, NULL);
+               }
+       }
+
+       return unlinked;
+}
+
+static void node_dynamic_pyerror_print(bNode *node)
+{
+       fprintf(stderr, "\nError in dynamic node script \"%s\":\n", node->name);
+       if (PyErr_Occurred()) { PyErr_Print(); }
+       else { fprintf(stderr, "Not a valid dynamic node Python script.\n"); }
+}
+
+static int node_dynamic_parse(struct bNode *node)
 {
-       BPy_Node *pynode= NULL;
        PyObject *dict= NULL;
        PyObject *key= NULL;
        PyObject *value= NULL;
-       PyObject *testinst= NULL;
+       PyObject *pynode= NULL;
        PyObject *args= NULL;
-       int pos = 0;
-       NodeScriptDict *nsd= NULL;
+       NodeScriptDict *nsd = NULL;
        PyObject *pyresult = NULL;
-       PyObject *pycompiled = NULL;
-       Text *txt = NULL;
-       char *buf= NULL;
+       char *buf = NULL;
+       int pos = 0, is_valid_script = 0;
+
+       if (!node->id || !node->storage)
+               return 0;
 
-       if(! node->id) {
+       /* READY, no need to be here */
+       if (BTST(node->custom1, NODE_DYNAMIC_READY))
+               return 0;
+
+       nsd = (NodeScriptDict *)node->storage;
+
+       dict = (PyObject *)(nsd->dict);
+       buf = txt_to_buf((Text *)node->id);
+
+       pyresult = PyRun_String(buf, Py_file_input, dict, dict);
+
+       MEM_freeN(buf);
+
+       if (!pyresult) {
+               node_dynamic_disable(node);
+               node_dynamic_pyerror_print(node);
+               return -1;
+       }
+
+       Py_DECREF(pyresult);
+
+       while (PyDict_Next( (PyObject *)(nsd->dict), &pos, &key, &value)) {
+               /* look for the node object */
+               if (PyObject_TypeCheck(value, &PyType_Type)==1) {
+                       BPy_NodeSockets *sockets = Node_CreateSockets(node);
+
+                       args = Py_BuildValue("(O)", sockets);
+
+                       /* init it to get the input and output sockets */
+                       pynode = PyObject_Call(value, args, NULL);
+
+                       Py_DECREF(sockets);
+                       Py_DECREF(args);
+
+                       if (!PyErr_Occurred() && pynode && PyObject_TypeCheck(pynode, &Node_Type)==1) {
+                               InitNode((BPy_Node *)(pynode), node);
+                               nsd->node = pynode;
+                               node->typeinfo->execfunc = node_dynamic_exec_cb;
+                               is_valid_script = 1;
+
+                               /* for NEW, LOADED, REPARSE */
+                               if (BNTST(node->custom1, NODE_DYNAMIC_ADDEXIST)) {
+                                       node->typeinfo->pydict = dict;
+                                       node->typeinfo->pynode = pynode;
+                                       node->typeinfo->id = node->id;
+                                       nodeAddSockets(node, node->typeinfo);
+                                       if (BNTST(node->custom1, NODE_DYNAMIC_REPARSE)) {
+                                               nodeRegisterType(&node_all_shaders, node->typeinfo);
+                                               /* nodeRegisterType copied it to a new one, so we
+                                                * free the typeinfo itself, but not what it
+                                                * points to: */
+                                               MEM_freeN(node->typeinfo);
+                                               node->typeinfo = node_dynamic_find_typeinfo(&node_all_shaders, node->id);
+                                               MEM_freeN(node->typeinfo->name);
+                                               node->typeinfo->name = BLI_strdup(node->name);
+                                       }
+                               }
+
+                               node->custom1 = 0;
+                               node->custom1 = BSET(node->custom1, NODE_DYNAMIC_READY);
+                               break;
+                       }
+                       break;
+               }
+       }
+
+       if (!is_valid_script) { /* not a valid pynode script */
+               node_dynamic_disable(node);
+               node_dynamic_pyerror_print(node);
+               return -1;
+       }
+
+       return 0;
+}
+
+/* node_dynamic_setup: prepare for execution (state: NODE_DYNAMIC_READY)
+ * pynodes already linked to a script (node->id != NULL). */
+static void node_dynamic_setup(bNode *node)
+{
+       NodeScriptDict *nsd = NULL;
+       bNodeTree *nodetree = NULL;
+       bNodeType *ntype = NULL;
+
+       /* Possible cases:
+        * NEW
+        * ADDEXIST
+        * LOADED
+        * REPARSE
+        * ERROR
+        * READY
+        */
+
+       /* NEW, but not linked to a script: link default (empty) typeinfo */
+       if (!node->id) {
+               node->typeinfo = node_dynamic_find_typeinfo(&node_all_shaders,
+                               NULL);
                return;
        }
 
-       if(node->custom1!=SH_NODE_DYNAMIC_READY) {
-               txt = (Text *)node->id;
-               nsd = (NodeScriptDict *)node->storage;
+       /* READY, no need to be here */
+       if (BTST(node->custom1, NODE_DYNAMIC_READY))
+               return;
 
-               if(nsd->dict==NULL && (node->custom1==SH_NODE_DYNAMIC_NEW||node->custom1==SH_NODE_DYNAMIC_LOADED)) {
-                       nsd->dict= init_dynamicdict();
-               } else if(nsd->dict==NULL && node->custom1==SH_NODE_DYNAMIC_ADDEXIST) {
-                       nsd->dict= node->typeinfo->pydict;
-                       nsd->node= node->typeinfo->pynode;
-                       Py_INCREF((PyObject *)(nsd->dict));
-                       Py_INCREF((PyObject *)(nsd->node));
-                       node->custom1= SH_NODE_DYNAMIC_READY;
+       /* ERROR, reset to (empty) defaults */
+       if (BCLR(node->custom1, NODE_DYNAMIC_ERROR) == 0) {
+               node_dynamic_reset(node, NULL);
+               return;
+       }
+
+       /* User asked to update this pynode, prepare it for reparsing */
+       if (BTST(node->custom1, NODE_DYNAMIC_REPARSE)) {
+               int needs_parsing = 1;
+
+               node->custom1 = BSET(node->custom1, NODE_DYNAMIC_NEW);
+
+               if (BTST(node->custom1, NODE_DYNAMIC_ERROR)) {
+                       node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_REPARSE);
+                       ntype = node_dynamic_find_typeinfo(&node_all_shaders, node->id);
+
+                       if (ntype) {
+                               node->typeinfo = ntype;
+                               node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ADDEXIST);
+                               node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_ERROR);
+                               needs_parsing = 0;
+                       }
+                       else { nodeMakeDynamicType(node); }
+
+               } else {
+                       node_dynamic_free_typeinfo_sockets(node->typeinfo);
+                       node_dynamic_update_socket_links(node, NULL);
+                       node_dynamic_free_storage_cb(node);
+               }
+
+               if (needs_parsing) {
+                       nsd = MEM_callocN(sizeof(NodeScriptDict), "node script dictionary");
+                       nsd->dict = init_dynamicdict();
+                       node->storage = nsd;
+                       /* prepared, now reparse: */
+                       node_dynamic_parse(node);
                        return;
                }
-               dict= (PyObject *)(nsd->dict);
+       }
+       else if (BTST(node->custom1, NODE_DYNAMIC_LOADED)) {
+               /* when loading from a .blend we don't have G.main yet, so we
+                * quickly abuse node->storage in ntreeInitTypes (node.c) to have
+                * our nodetree ptr (needed if a pynode script that worked before
+                * saving the .blend for some reason fails upon loading): */
+               nodetree = (bNodeTree *)node->storage;
+               node->storage = NULL;
+       }
 
-               if(node->custom1!=SH_NODE_DYNAMIC_ADDEXIST) {
-                       buf = txt_to_buf( txt );
-                       /*printf("Running script (%s, %d)...", node->name, node->custom1);*/
-                       pyresult = PyRun_String(buf, Py_file_input, dict, dict);
-                       /*printf(" done\n");*/
+       if (node->storage)
+               fprintf(stderr, "\nDEBUG: PYNODES ERROR: non NULL node->storage in node_dynamic_setup()\n");
 
-                       MEM_freeN(buf);
+       nsd = MEM_callocN(sizeof(NodeScriptDict), "node script dictionary");
+       node->storage = nsd;
+       
+       /* NEW, LOADED or REPARSE */
+       if (BNTST(node->custom1, NODE_DYNAMIC_ADDEXIST)) {
+               /* check if there's already a bNodeType linked to this script */
+               /* (XXX hardcoded for shader nodes for now) */
+               ntype = node_dynamic_find_typeinfo(&node_all_shaders, node->id);
 
-                       if(!pyresult) {
-                               if(PyErr_Occurred()) {
-                                       PyErr_Print();
-                               }
-                               Py_XDECREF(pyresult);
-                               return;
+               if (ntype) { /* if so, reuse it */
+                       node->typeinfo = ntype;
+                       /* so this is actually an ADDEXIST type */
+                       node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ADDEXIST);
+               }
+               else { /* create bNodeType for this pynode */
+                       nodeMakeDynamicType(node);
+                       nsd->dict = init_dynamicdict();
+                       if ((node_dynamic_parse(node) == -1) && nodetree) {
+                               node_dynamic_reset(node, nodetree);
                        }
+                       return;
+               }
+       }
 
-                       Py_DECREF(pyresult);
+       /* ADDEXIST: new pynode linked to an already registered dynamic type,
+        * we just reuse existing py dict and pynode */
+       nsd->dict = node->typeinfo->pydict;
+       nsd->node = node->typeinfo->pynode;
+       Py_INCREF((PyObject *)(nsd->dict));
+       Py_INCREF((PyObject *)(nsd->node));
 
-                       while(PyDict_Next( (PyObject *)(nsd->dict), &pos, &key, &value) ) {
-                               if(PyObject_TypeCheck(value, &PyType_Type)==1) {
-                                       BPy_DefinitionMap *outputdef= Node_CreateOutputDefMap(node);
-                                       BPy_DefinitionMap *inputdef= Node_CreateInputDefMap(node);
-
-                                       args= Py_BuildValue("(OO)", inputdef, outputdef);
-                                       testinst= PyObject_Call(value, args, NULL);
-
-                                       Py_DECREF(outputdef);
-                                       Py_DECREF(inputdef);
-                                       if(testinst && PyObject_TypeCheck(testinst, &Node_Type)==1) {
-                                               Py_INCREF(testinst);
-                                               Py_INCREF(dict);
-                                               InitNode((BPy_Node *)(testinst), node);
-                                               nsd->node= testinst;
-                                               node->typeinfo->execfunc= node_dynamic_exec;
-                                               if(node->custom1== SH_NODE_DYNAMIC_NEW || node->custom1== SH_NODE_DYNAMIC_LOADED) {
-                                                       node->typeinfo->pynode= testinst;
-                                                       node->typeinfo->pydict= nsd->dict;
-                                                       node->typeinfo->id= node->id;
-                                                       nodeAddSockets(node, node->typeinfo);
-                                                       nodeRegisterType(&node_all_shaders, node->typeinfo);
-                                                       node->custom1= SH_NODE_DYNAMIC_READY;
-                                               }
-                                               break;
-                                       }
-                                       Py_DECREF(args);
-                               }
-                       }
+       if (BTST(node->custom1, NODE_DYNAMIC_NEW)) {
+               nodeAddSockets(node, node->typeinfo);
+               node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_NEW);
+       }
+
+       node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_ADDEXIST);
+       node->custom1 = BSET(node->custom1, NODE_DYNAMIC_READY);
+
+       return;
+}
+
+/* node_dynamic_init_cb callback: called when a pynode is created.
+ * The pynode type is passed via node->custom2. It can be:
+ *  0: for loaded empty nodes
+ *  NODE_DYNAMIC_MENU: for the default Dynamic node type
+ *  > NODE_DYNAMIC_MENU: for the new types defined by scripts
+*/
+static void node_dynamic_init_cb(bNode *node) {
+       int type = node->custom2;
+
+       node->custom2 = 0;
+
+       if (type >= NODE_DYNAMIC_MENU) {
+               node->custom1 = 0;
+
+               if (type == NODE_DYNAMIC_MENU) {
+                       node->custom1 = BSET(node->custom1, NODE_DYNAMIC_NEW);
+                       return;
                }
+
+               node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ADDEXIST);
+               node->id = node->typeinfo->id;
        }
+
+       node_dynamic_setup(node);
 }
 
+/* node_dynamic_copy_cb: pynode copy callback */
+static void node_dynamic_copy_cb(bNode *orig_node, bNode *new_node)
+{
+       NodeScriptDict *nsd;
+
+       if (!orig_node->storage) return;
+
+       nsd = (NodeScriptDict *)(orig_node->storage);
+       new_node->storage = MEM_dupallocN(orig_node->storage);
+
+       if (nsd->node)
+               Py_INCREF((PyObject *)(nsd->node));
+       if (nsd->dict)
+               Py_INCREF((PyObject *)(nsd->dict));
+}
+
+/* node_dynamic_exec_cb: the execution callback called per pixel
+ * during rendering. */
+static void node_dynamic_exec_cb(void *data, bNode *node, bNodeStack **in, bNodeStack **out) {
+       BPy_Node *mynode = NULL;
+       NodeScriptDict *nsd = NULL;
+       PyObject *pyresult = NULL;
+       PyObject *args = NULL;
+       ShadeInput *shi;
+
+       if (!node->id)
+               return;
+
+       if (BTST2(node->custom1, NODE_DYNAMIC_NEW, NODE_DYNAMIC_REPARSE)) {
+               node_dynamic_setup(node);
+               return;
+       }
+
+       if (BTST(node->custom1, NODE_DYNAMIC_ERROR)) {
+               if (node->storage) node_dynamic_setup(node);
+               return;
+       }
+
+       if (BTST(node->custom1, NODE_DYNAMIC_READY)) {
+               nsd = (NodeScriptDict *)node->storage;
+
+               mynode = (BPy_Node *)(nsd->node);
+               if (mynode && PyCallable_Check((PyObject *)mynode)) {
+                       mynode->node = node;
+                       shi = ((ShaderCallData *)data)->shi;
+
+                       Node_SetStack(mynode, in, NODE_INPUTSTACK);
+                       Node_SetStack(mynode, out, NODE_OUTPUTSTACK);
+                       Node_SetShi(mynode, shi);
+
+                       args=Py_BuildValue("()");
+                       pyresult= PyObject_Call((PyObject *)mynode, args, NULL);
+                       Py_DECREF(args);
+
+                       if (!pyresult) {
+                               node_dynamic_disable_all_by_id(node->id);
+                               node_dynamic_pyerror_print(node);
+                               node_dynamic_setup(node);
+                               return;
+                       }
+                       Py_DECREF(pyresult);
+               }
+       }
+}
 
-bNodeType sh_node_dynamic = {
+bNodeType node_dynamic_typeinfo = {
        /* next, prev  */       NULL, NULL,
-       /* type code   */       SH_NODE_DYNAMIC,
+       /* type code   */       NODE_DYNAMIC,
        /* name        */       "Dynamic",
        /* width+range */       150, 60, 300,
        /* class+opts  */       NODE_CLASS_OP_DYNAMIC, NODE_OPTIONS,
        /* input sock  */       NULL,
        /* output sock */       NULL,
        /* storage     */       "NodeScriptDict",
-       /* execfunc    */       node_dynamic_exec,
+       /* execfunc    */       node_dynamic_exec_cb,
        /* butfunc     */       NULL,
-       /* initfunc    */       node_dynamic_init,
-       /* freefunc    */       node_dynamic_free,
-       /* copyfunc    */       node_dynamic_copy,
+       /* initfunc    */       node_dynamic_init_cb,
+       /* freefunc    */       node_dynamic_free_storage_cb,
+       /* copyfunc    */       node_dynamic_copy_cb,
        /* id          */       NULL
 };
 
index 9cd245394b0ca2a57a956e11619a36fef4119ba0..f608787d66da9a6f0344a2bdc0e8d2c13d9163bf 100644 (file)
@@ -3,7 +3,7 @@ Import ('env')
 
 sources = Split('BPY_interface.c BPY_menus.c') + env.Glob('api2_2x/*.c')
 
-incs = 'api2_2x ../blenkernel ../blenlib ../blenloader'
+incs = 'api2_2x ../blenkernel ../nodes ../blenlib ../blenloader'
 incs += ' ../render/extern/include ../radiosity/extern/include'
 incs += ' ../makesdna #intern/guardedalloc #intern/bmfont ../imbuf ../include'
 incs += ' ' + env['BF_PYTHON_INC']
@@ -20,6 +20,8 @@ if env['WITH_BF_QUICKTIME']==1:
 if env['WITH_BF_OPENEXR'] == 1:
     defs.append('WITH_OPENEXR')
 
+defs.append('USE_PYNODES')
+
 if env['WITH_BF_FFMPEG'] == 1:
     defs.append('WITH_FFMPEG')
 
index db47d6550c28fa58dcf056a5284d68dac85526ee..46f7b9da79f6ff537b1e43a834dce92d01c02ad1 100644 (file)
@@ -85,6 +85,7 @@ struct ID; /*keep me up here */
 #include "Metaball.h"
 #include "Modifier.h"
 #include "NMesh.h"
+#include "Node.h"
 #include "Object.h"
 #include "Group.h"
 #include "Registry.h"
@@ -1047,6 +1048,7 @@ void M_Blender_Init(void)
        PyDict_SetItemString(dict, "Geometry", Geometry_Init());
        PyDict_SetItemString(dict, "Modifier", Modifier_Init());
        PyDict_SetItemString(dict, "NMesh", NMesh_Init());
+       PyDict_SetItemString(dict, "Node", Node_Init());
        PyDict_SetItemString(dict, "Noise", Noise_Init());
        PyDict_SetItemString(dict, "Object", Object_Init());
        PyDict_SetItemString(dict, "Group", Group_Init());
index 2871eda9432c226047ba7e08983f682818efd40b..195b61a39eae2133287136622834ef7a76573323 100644 (file)
@@ -1,5 +1,5 @@
 /* 
- * $Id: Node.c 10454 2007-04-04 11:27:43Z jesterking $
+ * $Id$
  *
  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
  *
@@ -36,6 +36,7 @@
 #include "BKE_global.h"
 #include "BKE_main.h"
 #include "BKE_node.h"
+#include "BKE_utildefines.h"
 
 #include "DNA_material_types.h"
 
@@ -48,138 +49,199 @@ static PyObject *Node_repr( BPy_Node * self );
 static int Node_compare(BPy_Node *a, BPy_Node *b);
 static PyObject *ShadeInput_repr( BPy_ShadeInput * self );
 static int ShadeInput_compare(BPy_ShadeInput *a, BPy_ShadeInput *b);
+static BPy_ShadeInput *ShadeInput_CreatePyObject(ShadeInput *shi);
 
 /**
- * Take the descriptions from dict and create sockets for those in socks
+ * Take the descriptions from list and create sockets for those in socks
  * socks is a socketstack from a bNodeTypeInfo
  */
-static int dict_socks_to_typeinfo(PyObject *dict, bNodeSocketType **socks, int len, int stage) {
-       int a = 0, pos = 0;
-       PyObject *key = NULL, *value = NULL;
+static int list_socks_to_typeinfo(PyObject *tuple, bNodeSocketType **socks, int stage, int limit) {
+       int len = 0, a = 0, pos = 0, retval = 0;
+       //wPyObject *key = NULL, *value = NULL;
+       PyObject *item, *arg;
        bNodeSocketType *newsocks = NULL;
+       char *s_name = NULL;
+       int s_type = SOCK_VALUE;
+       float s_val[4], s_min, s_max;
 
-       if(stage!=SH_NODE_DYNAMIC_READY && stage!=SH_NODE_DYNAMIC_ADDEXIST) {
-               newsocks = MEM_callocN(sizeof(bNodeSocketType)*(len+1), "bNodeSocketType");
-
-               if (dict) {
-                       if(PyDict_Check(dict)) {
-                               while(PyDict_Next(dict, &pos, &key, &value)) {
-                                       if(PyTuple_Check(value) && PyTuple_Size(value)==7) {
-                                               newsocks[a].name = BLI_strdup(PyString_AsString(key));
-                                               newsocks[a].type = (int)(PyInt_AsLong(PyTuple_GetItem(value, 0)));
-                                               newsocks[a].val1 = (float)(PyFloat_AsDouble(PyTuple_GetItem(value, 1)));
-                                               newsocks[a].val2 = (float)(PyFloat_AsDouble(PyTuple_GetItem(value, 2)));
-                                               newsocks[a].val3 = (float)(PyFloat_AsDouble(PyTuple_GetItem(value, 3)));
-                                               newsocks[a].val4 = (float)(PyFloat_AsDouble(PyTuple_GetItem(value, 4)));
-                                               newsocks[a].min = (float)(PyFloat_AsDouble(PyTuple_GetItem(value, 5)));
-                                               newsocks[a].max = (float)(PyFloat_AsDouble(PyTuple_GetItem(value, 6)));
-                                               a++;
-                                       }
-                               }
-                       } else {
-                               return(EXPP_ReturnIntError( PyExc_AttributeError, "INPUT must be a dict"));
-                       }
+       if (BTST2(stage, NODE_DYNAMIC_READY, NODE_DYNAMIC_ADDEXIST))
+               return 0; /* already has sockets */
+
+       len = PyTuple_Size(tuple);
+
+       newsocks = MEM_callocN(sizeof(bNodeSocketType)*(len+1), "bNodeSocketType in Node.c");
+
+       for (pos = 0, a = 0; pos< len; pos++, a++) {
+               /* default socket values: */
+               s_name = NULL;
+               s_type = SOCK_VALUE;
+               s_min = 0.0f;
+               s_max = 1.0f;
+               s_val[0] = s_val[1] = s_val[2] = s_val[3] = 1.0f;
+
+               item = PyTuple_GetItem(tuple, pos);
+
+               if (!PySequence_Check(item)) {
+                       PyErr_SetString(PyExc_AttributeError, "a socket must be a List of Lists or Tuples");
+                       retval = -1;
+                       break;
                }
-               newsocks[a].type = -1;
-               if(*socks) {
-                       int b = 0;
-                       while((*socks)[b].type!=-1) {
-                               MEM_freeN((*socks)[b].name);
-                               (*socks)[b].name = NULL;
-                               b++;
-                       }
-                       MEM_freeN(*socks);
+
+               arg = PySequence_Tuple(item);
+
+               if (!PyArg_ParseTuple(arg, "s|iffffff", &s_name, &s_type,
+                                       &s_min, &s_max,
+                                       &s_val[0], &s_val[1], &s_val[2], &s_val[3] )) {
+                       PyErr_SetString(PyExc_AttributeError, "socket definitions require a string and optionally an int and 6 floats");
+                       retval = -1;
+                       Py_DECREF(arg);
+                       break;
                }
-               *socks = newsocks;
+
+               newsocks[a].name = BLI_strdupn(s_name, NODE_MAXSTR);
+               newsocks[a].type = s_type;
+               newsocks[a].min = s_min;
+               newsocks[a].max = s_max;
+               newsocks[a].val1 = s_val[0];
+               newsocks[a].val2 = s_val[1];
+               newsocks[a].val3 = s_val[2];
+               newsocks[a].val4 = s_val[3];
+               newsocks[a].limit = limit;
+
+               Py_DECREF(arg);
        }
-       return 0;
+
+       newsocks[a].type = -1;
+
+       *socks = newsocks;
+
+       return retval;
 }
 
-/* Get number of complying entries in a dict.
+/* Get number of complying entries in a list.
  *
  */
-static int num_dict_sockets(PyObject *dict) {
-       int a = 0, pos = 0;
-       PyObject *key = NULL, *value = NULL;
-       while(PyDict_Next(dict, &pos, &key, &value)) {
-               if(PyTuple_Check(value) && PyTuple_Size(value)==7)
-                       a++;
+/* unused
+static int num_list_sockets(PyObject *list) {
+       int size = 0;
+       int i = 0, count = 0;
+       PyObject *element = NULL;
+
+       size = PyList_Size(list);
+       for(i = 0; i < size; i++) {
+               element = PyList_GetItem(list, i);
+               //wPy_INCREF(element);
+               if(PyList_Check(element) && PyList_Size(element) == 8)
+                       count++;
+               //wPy_DECREF(element);
        }
-       return a;
+       return count;
+}
+*/
+static void NodeSockets_dealloc(BPy_NodeSockets *self)
+{
+       Py_DECREF(self->input);
+       Py_DECREF(self->output);
+       self->ob_type->tp_free((PyObject *)self);
 }
 
-static int Map_socketdef(PyObject *self, PyObject *args, void *closure)
+static PyObject *Map_socketdef_getter(BPy_NodeSockets *self, void *closure)
 {
-       int newincnt = 0, newoutcnt = 0;
-       bNode *node = NULL;
-       BPy_DefinitionMap *defs= NULL;
+       PyObject *sockets = NULL;
 
-       Py_INCREF(args);
-       Py_INCREF(self);
+       switch ((int)closure) {
+               case 'I': /* inputs */
+                       Py_INCREF(self->input);
+                       sockets = self->input;
+                       break;
+               case 'O': /* outputs */
+                       Py_INCREF(self->output);
+                       sockets = self->output;
+                       break;
+               default:
+                       fprintf(stderr, "DEBUG pynodes: wrong option in Map_socketdef_getter\n");
+                       Py_INCREF(Py_None);
+                       sockets = Py_None;
+                       break;
+       }
+
+       return sockets;
+}
+
+static int Map_socketdef(BPy_NodeSockets *self, PyObject *args, void *closure)
+{
+       bNode *node = NULL;
+       PyObject *tuple = NULL;
 
-       defs= (BPy_DefinitionMap *)self;
-       node= defs->node;
+       node = self->node;
 
        if(!node) {
-               fprintf(stderr,"! no bNode in BPy_Node (Map_socketdef)\n");
+               fprintf(stderr,"DEBUG pynodes: No bNode in BPy_Node (Map_socketdef)\n");
                return 0;
        }
 
-       if(node->custom1==SH_NODE_DYNAMIC_READY && node->custom1==SH_NODE_DYNAMIC_ADDEXIST)
+       if(BTST2(node->custom1, NODE_DYNAMIC_READY, NODE_DYNAMIC_ADDEXIST))
                return 0;
 
        switch((int)closure) {
                case 'I':
                        if (args) {
-                               if(PyDict_Check(args)) {
-                                       newincnt = num_dict_sockets(args);
-                                       dict_socks_to_typeinfo(args, &(node->typeinfo->inputs), newincnt, node->custom1);
+                               if(PySequence_Check(args)) {
+                                       tuple = PySequence_Tuple(args);
+                                       list_socks_to_typeinfo(tuple, &(node->typeinfo->inputs), node->custom1, 1);
+                                       Py_DECREF(self->input);
+                                       self->input = tuple;
                                } else {
-                                       Py_DECREF(self);
-                                       Py_DECREF(args);
-                                       return(EXPP_ReturnIntError( PyExc_AttributeError, "INPUT must be a dict"));
+                                       return(EXPP_ReturnIntError( PyExc_AttributeError, "INPUT must be a List of Lists or Tuples"));
                                }
                        }
                        break;
                case 'O':
                        if (args) {
-                               if(PyDict_Check(args)) {
-                                       newoutcnt = num_dict_sockets(args);
-                                       dict_socks_to_typeinfo(args, &(node->typeinfo->outputs), newoutcnt, node->custom1);
+                               if(PyList_Check(args)) {
+                                       tuple = PySequence_Tuple(args);
+                                       list_socks_to_typeinfo(tuple, &(node->typeinfo->outputs), node->custom1, 0);
+                                       Py_DECREF(self->output);
+                                       self->output = tuple;
                                } else {
-                                       Py_DECREF(self);
-                                       Py_DECREF(args);
-                                       return(EXPP_ReturnIntError( PyExc_AttributeError, "OUTPUT must be a dict"));
+                                       return(EXPP_ReturnIntError( PyExc_AttributeError, "OUTPUT must be a List of Lists or Tuples"));
                                }
                        }
                        break;
                default:
-                       fprintf(stderr, "Hrm, why we got no dict? Todo: figure out proper complaint to scripter\n");
+                       fprintf(stderr,"DEBUG pynodes: got no list in Map_socketdef\n");
                        break;
        }
-       Py_DECREF(self);
-       Py_DECREF(args);
        return 0;
 }
 
-static PyGetSetDef InputDefMap_getseters[] = {
-       {"definitions", (getter)NULL, (setter)Map_socketdef,
-               "Set the inputs definition (dictionary)",
+static PyGetSetDef NodeSockets_getseters[] = {
+       {"input", (getter)Map_socketdef_getter, (setter)Map_socketdef,
+               "Set this node's input sockets (list of lists or tuples)",
+               (void *)'I'},
+       {"i" /*alias*/, (getter)Map_socketdef_getter, (setter)Map_socketdef,
+               "Set this node's input sockets (list of lists or tuples)",
                (void *)'I'},
+       {"output", (getter)Map_socketdef_getter, (setter)Map_socketdef,
+               "Set this node's output sockets (list of lists or tuples)",
+               (void *)'O'},
+       {"o" /*alias*/, (getter)Map_socketdef_getter, (setter)Map_socketdef,
+               "Set this node's output sockets (list of lists or tuples)",
+               (void *)'O'},
        {NULL,NULL,NULL,NULL,NULL}  /* Sentinel */
 };
 
-PyTypeObject InputDefMap_Type = {
+PyTypeObject NodeSockets_Type = {
        PyObject_HEAD_INIT( NULL )  /* required py macro */
        0,                          /* ob_size */
        /*  For printing, in format "<module>.<name>" */
-       "Blender.Node.InputDefinitions",           /* char *tp_name; */
-       sizeof( BPy_DefinitionMap ),       /* int tp_basicsize; */
+       "Blender.Node.Sockets",           /* char *tp_name; */
+       sizeof( BPy_NodeSockets ),       /* int tp_basicsize; */
        0,                          /* tp_itemsize;  For allocation */
 
        /* Methods to implement standard operations */
 
-       NULL,/* destructor tp_dealloc; */
+       (destructor)NodeSockets_dealloc,/* destructor tp_dealloc; */
        NULL,                       /* printfunc tp_print; */
        NULL,                       /* getattrfunc tp_getattr; */
        NULL,                       /* setattrfunc tp_setattr; */
@@ -229,7 +291,7 @@ PyTypeObject InputDefMap_Type = {
   /*** Attribute descriptor and subclassing stuff ***/
        0, //BPy_MVertSeq_methods,       /* struct PyMethodDef *tp_methods; */
        NULL,                       /* struct PyMemberDef *tp_members; */
-       InputDefMap_getseters,                       /* struct PyGetSetDef *tp_getset; */
+       NodeSockets_getseters,      /* struct PyGetSetDef *tp_getset; */
        NULL,                       /* struct _typeobject *tp_base; */
        NULL,                       /* PyObject *tp_dict; */
        NULL,                       /* descrgetfunc tp_descr_get; */
@@ -251,127 +313,48 @@ PyTypeObject InputDefMap_Type = {
        NULL
 };
 
-BPy_DefinitionMap *Node_CreateInputDefMap(bNode *node) {
-       BPy_DefinitionMap *map = PyObject_NEW(BPy_DefinitionMap, &InputDefMap_Type);
-       map->node = node;
-       return map;
+BPy_NodeSockets *Node_CreateSockets(bNode *node) {
+       BPy_NodeSockets *sockets = PyObject_NEW(BPy_NodeSockets, &NodeSockets_Type);
+       sockets->node = node;
+       sockets->input = PyList_New(0);
+       sockets->output = PyList_New(0);
+       return sockets;
 }
 
 /***************************************/
 
-static PyGetSetDef OutputDefMap_getseters[] = {
-       {"definitions", (getter)NULL, (setter)Map_socketdef,
-               "Set the outputs definition (dictionary)",
-               (void *)'O'},
-       {NULL,NULL,NULL,NULL,NULL}  /* Sentinel */
-};
-
-PyTypeObject OutputDefMap_Type = {
-       PyObject_HEAD_INIT( NULL )  /* required py macro */
-       0,                          /* ob_size */
-       /*  For printing, in format "<module>.<name>" */
-       "Blender.Node.OutputDefinitions",           /* char *tp_name; */
-       sizeof( BPy_DefinitionMap ),       /* int tp_basicsize; */
-       0,                          /* tp_itemsize;  For allocation */
-
-       /* Methods to implement standard operations */
-
-       NULL,/* destructor tp_dealloc; */
-       NULL,                       /* printfunc tp_print; */
-       NULL,                       /* getattrfunc tp_getattr; */
-       NULL,                       /* setattrfunc tp_setattr; */
-       NULL,                       /* cmpfunc tp_compare; */
-       NULL,                       /* reprfunc tp_repr; */
-
-       /* Method suites for standard classes */
-
-       NULL,                                           /* PyNumberMethods *tp_as_number; */
-       NULL,                                       /* PySequenceMethods *tp_as_sequence; */
-       NULL,      /* PyMappingMethods *tp_as_mapping; */
-
-       /* More standard operations (here for binary compatibility) */
-
-       NULL,                       /* hashfunc tp_hash; */
-       NULL,                       /* ternaryfunc tp_call; */
-       NULL,                       /* reprfunc tp_str; */
-       NULL,                       /* getattrofunc tp_getattro; */
-       NULL,                       /* setattrofunc tp_setattro; */
-
-       /* Functions to access object as input/output buffer */
-       NULL,                       /* PyBufferProcs *tp_as_buffer; */
-
-  /*** Flags to define presence of optional/expanded features ***/
-       Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
-
-       NULL,                       /*  char *tp_doc;  Documentation string */
-  /*** Assigned meaning in release 2.0 ***/
-       /* call function for all accessible objects */
-       NULL,                       /* traverseproc tp_traverse; */
-
-       /* delete references to contained objects */
-       NULL,                       /* inquiry tp_clear; */
-
-  /***  Assigned meaning in release 2.1 ***/
-  /*** rich comparisons ***/
-       NULL,                       /* richcmpfunc tp_richcompare; */
-
-  /***  weak reference enabler ***/
-       0,                          /* long tp_weaklistoffset; */
-
-  /*** Added in release 2.2 ***/
-       /*   Iterators */
-       0, //( getiterfunc) MVertSeq_getIter, /* getiterfunc tp_iter; */
-       0, //( iternextfunc ) MVertSeq_nextIter, /* iternextfunc tp_iternext; */
+static int sockinmap_len ( BPy_SockMap * self) {
+       bNode *node = self->node;
+       bNodeType *tinfo;
+       int a = 0;
 
-  /*** Attribute descriptor and subclassing stuff ***/
-       0, //BPy_MVertSeq_methods,       /* struct PyMethodDef *tp_methods; */
-       NULL,                       /* struct PyMemberDef *tp_members; */
-       OutputDefMap_getseters,                       /* struct PyGetSetDef *tp_getset; */
-       NULL,                       /* struct _typeobject *tp_base; */
-       NULL,                       /* PyObject *tp_dict; */
-       NULL,                       /* descrgetfunc tp_descr_get; */
-       NULL,                       /* descrsetfunc tp_descr_set; */
-       0,                          /* long tp_dictoffset; */
-       NULL,                       /* initproc tp_init; */
-       NULL,                       /* allocfunc tp_alloc; */
-       NULL,                       /* newfunc tp_new; */
-       /*  Low-level free-memory routine */
-       NULL,                       /* freefunc tp_free;  */
-       /* For PyObject_IS_GC */
-       NULL,                       /* inquiry tp_is_gc;  */
-       NULL,                       /* PyObject *tp_bases; */
-       /* method resolution order */
-       NULL,                       /* PyObject *tp_mro;  */
-       NULL,                       /* PyObject *tp_cache; */
-       NULL,                       /* PyObject *tp_subclasses; */
-       NULL,                       /* PyObject *tp_weaklist; */
-       NULL
-};
+       if (!node) return 0;
 
-BPy_DefinitionMap *Node_CreateOutputDefMap(bNode *node) {
-       BPy_DefinitionMap *map = PyObject_NEW(BPy_DefinitionMap, &OutputDefMap_Type);
-       map->node = node;
-       return map;
-}
+       tinfo = node->typeinfo;
 
-/***************************************/
+       if (BNTST(node->custom1, NODE_DYNAMIC_READY)) return 0;
 
-static int sockinmap_len ( BPy_SockMap * self) {
-       int a = 0;
-       if(self->typeinfo) {
-               while(self->typeinfo->inputs[a].type!=-1)
+       if (tinfo && tinfo->inputs) {
+               while(self->node->typeinfo->inputs[a].type!=-1)
                        a++;
        }
        return a;
 }
 
 static int sockinmap_has_key( BPy_SockMap *self, PyObject *key) {
+       bNode *node = self->node;
+       bNodeType *tinfo;
+       char *strkey = NULL;
        int a = 0;
-       char *strkey = PyString_AsString(key);
 
-       if(self->typeinfo){
-               while(self->typeinfo->inputs[a].type!=-1) {
-                       if(BLI_strcaseeq(self->typeinfo->inputs[a].name, strkey)) {
+       if (!node) return -1;
+
+       tinfo = node->typeinfo;
+       strkey = PyString_AsString(key);
+
+       if(tinfo && tinfo->inputs){
+               while(self->node->typeinfo->inputs[a].type!=-1) {
+                       if(BLI_strcaseeq(self->node->typeinfo->inputs[a].name, strkey)) {
                                return a;
                        }
                        a++;
@@ -380,39 +363,46 @@ static int sockinmap_has_key( BPy_SockMap *self, PyObject *key) {
        return -1;
 }
 
-PyObject *sockinmap_subscript(BPy_SockMap *self, PyObject *idx) {
-       int a, _idx;
-       a = sockinmap_len(self);
+PyObject *sockinmap_subscript(BPy_SockMap *self, PyObject *pyidx) {
+       int idx;
+
+       if (!self->node)
+               return EXPP_ReturnPyObjError(PyExc_RuntimeError, "no access to Blender node data!");
 
-       if (PyString_Check(idx)) {
-               _idx = sockinmap_has_key( self, idx);
+       if (PyString_Check(pyidx)) {
+               idx = sockinmap_has_key(self, pyidx);
        }
-       else if(PyInt_Check(idx)) {
-               PyErr_SetString(PyExc_ValueError, "int index not implemented");
-               Py_RETURN_NONE;
+       else if(PyInt_Check(pyidx)) {
+               int len = sockinmap_len(self);
+               idx = (int)PyInt_AsLong(pyidx);
+               if (idx < 0 || idx >= len)
+                       return EXPP_ReturnPyObjError(PyExc_IndexError, "index out of range");
        }
-       else if (PySlice_Check(idx)) {
-               PyErr_SetString(PyExc_ValueError, "slices not implemented");
-               Py_RETURN_NONE;
+       else if (PySlice_Check(pyidx)) {
+               return EXPP_ReturnPyObjError(PyExc_ValueError, "slices not implemented");
        } else {
-               PyErr_SetString(PyExc_IndexError, "Index must be string");
-               Py_RETURN_NONE;
+               return EXPP_ReturnPyObjError(PyExc_IndexError, "index must be an int or a string");
        }
 
+       if(idx<0) { /* we're not as nice as Python */
+               return EXPP_ReturnPyObjError(PyExc_IndexError, "invalid socket index");
+       }
        
-       switch(self->typeinfo->inputs[_idx].type) {
+       switch(self->node->typeinfo->inputs[idx].type) {
                case SOCK_VALUE:
-                       return Py_BuildValue("f", self->stack[_idx]->vec[0]);
+                       return Py_BuildValue("f", self->stack[idx]->vec[0]);
                        break;
                case SOCK_VECTOR:
-                       return Py_BuildValue("(fff)", self->stack[_idx]->vec[0], self->stack[_idx]->vec[1], self->stack[_idx]->vec[2]);
+                       return Py_BuildValue("(fff)", self->stack[idx]->vec[0], self->stack[idx]->vec[1], self->stack[idx]->vec[2]);
                        break;
                case SOCK_RGBA:
-                       return Py_BuildValue("(ffff)", self->stack[_idx]->vec[0], self->stack[_idx]->vec[1], self->stack[_idx]->vec[2], self->stack[_idx]->vec[3]);
+                       /* otherwise RGBA tuple */
+                       return Py_BuildValue("(ffff)", self->stack[idx]->vec[0], self->stack[idx]->vec[1], self->stack[idx]->vec[2], self->stack[idx]->vec[3]);
                        break;
                default:
                        break;
        }
+
        Py_RETURN_NONE;
 }
 
@@ -506,21 +496,35 @@ PyTypeObject SockInMap_Type = {
 };
 
 static int sockoutmap_len ( BPy_SockMap * self) {
+       bNode *node = self->node;
+       bNodeType *tinfo;
        int a = 0;
-       if(self->typeinfo) {
-               while(self->typeinfo->outputs[a].type!=-1)
+
+       if (!node) return 0;
+
+       tinfo = node->typeinfo;
+
+       if (tinfo && tinfo->outputs) {
+               while(self->node->typeinfo->outputs[a].type!=-1)
                        a++;
        }
        return a;
 }
 
 static int sockoutmap_has_key( BPy_SockMap *self, PyObject *key) {
+       bNode *node = self->node;
+       bNodeType *tinfo;
        int a = 0;
-       char *strkey = PyString_AsString(key);
+       char *strkey = NULL;
+
+       if (!node) return -1;
+
+       tinfo = node->typeinfo;
+       strkey = PyString_AsString(key);
 
-       if(self->typeinfo){
-               while(self->typeinfo->outputs[a].type!=-1) {
-                       if(BLI_strcaseeq(self->typeinfo->outputs[a].name, strkey)) {
+       if(tinfo && tinfo->outputs){
+               while(self->node->typeinfo->outputs[a].type!=-1) {
+                       if(BLI_strcaseeq(self->node->typeinfo->outputs[a].name, strkey)) {
                                return a;
                        }
                        a++;
@@ -529,51 +533,89 @@ static int sockoutmap_has_key( BPy_SockMap *self, PyObject *key) {
        return -1;
 }
 
-static int sockoutmap_assign_subscript(BPy_SockMap *self, PyObject *idx, PyObject *value) {
-       int a, _idx;
-       a = sockoutmap_len(self);
-       if(PyInt_Check(idx)) {
-               _idx = (int)PyInt_AsLong(idx);
+static int sockoutmap_assign_subscript(BPy_SockMap *self, PyObject *pyidx, PyObject *value) {
+       int i, idx, len, wanted_len = 0, ret = -1;
+       PyObject *val;
+       PyObject **items;
+
+       if (!self->node)
+               return EXPP_ReturnIntError(PyExc_RuntimeError, "no access to Blender node data!");
+
+       if (PyInt_Check(pyidx)) {
+               idx = (int)PyInt_AsLong(pyidx);
+               if (idx < 0 || idx >= sockinmap_len(self))
+                       return EXPP_ReturnIntError(PyExc_IndexError, "index out of range");
        }
-       else if (PyString_Check(idx)) {
-               _idx = sockoutmap_has_key( self, idx);
+       else if (PyString_Check(pyidx)) {
+               idx = sockoutmap_has_key(self, pyidx);
        }
-       else if (PySlice_Check(idx)) {
-        PyErr_SetString(PyExc_ValueError, "slices not implemented, yet");
-        return -1;
-    } else {
-        PyErr_SetString(PyExc_IndexError, "Index must be int or string");
-               return -1;
-    }
-       if(_idx > -1) {
-               switch(self->typeinfo->outputs[_idx].type) {
-                       case SOCK_VALUE:
-                               if(PyTuple_Size(value)==1)
-                                       self->stack[_idx]->vec[0] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 0));
-                               return 0;
-                               break;
-                       case SOCK_VECTOR:
-                               if(PyTuple_Size(value)==3) {
-                                       self->stack[_idx]->vec[0] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 0));
-                                       self->stack[_idx]->vec[1] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 1));
-                                       self->stack[_idx]->vec[2] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 2));
-                               }
-                               return 0;
-                               break;
-                       case SOCK_RGBA:
-                               if(PyTuple_Size(value)==4) {
-                                       self->stack[_idx]->vec[0] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 0));
-                                       self->stack[_idx]->vec[1] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 1));
-                                       self->stack[_idx]->vec[2] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 2));
-                                       self->stack[_idx]->vec[3] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 3));
-                               }
-                               return 0;
-                               break;
-                       default:
-                               break;
+       else if (PySlice_Check(pyidx)) {
+               return EXPP_ReturnIntError(PyExc_ValueError, "slices not yet implemented");
+       } else {
+               return EXPP_ReturnIntError(PyExc_IndexError, "index must be a positive int or a string");
+       }
+
+       if (idx < 0)
+               return EXPP_ReturnIntError(PyExc_IndexError, "index must be a positive int or a string");
+
+       val = PySequence_Fast(value, "expected a numeric tuple or list");
+       if (!val) return -1;
+
+       len = PySequence_Fast_GET_SIZE(val);
+
+       if (len == 0) {
+               Py_DECREF(val);
+               return EXPP_ReturnIntError(PyExc_AttributeError, "expected a non-empty numeric tuple or list");
+       }
+
+       items = PySequence_Fast_ITEMS(val);
+
+       for (i = 0; i < len; i++) {
+               if (!PyNumber_Check(items[i])) {
+                       Py_DECREF(val);
+                       return EXPP_ReturnIntError(PyExc_AttributeError, "expected a *numeric* tuple or list");
                }
        }
-       return 0;
+
+       switch(self->node->typeinfo->outputs[idx].type) {
+               case SOCK_VALUE:
+                       wanted_len = 1;
+                       if (len == 1) {
+                               self->stack[idx]->vec[0] = (float)PyFloat_AsDouble(items[0]);
+                               ret = 0;
+                       }
+                       break;
+               case SOCK_VECTOR:
+                       wanted_len = 3;
+                       if (len == 3) {
+                               self->stack[idx]->vec[0] = (float)PyFloat_AsDouble(items[0]);
+                               self->stack[idx]->vec[1] = (float)PyFloat_AsDouble(items[1]);
+                               self->stack[idx]->vec[2] = (float)PyFloat_AsDouble(items[2]);
+                               ret = 0;
+                       }
+                       break;
+               case SOCK_RGBA:
+                       wanted_len = 4;
+                       if (len == 4) {
+                               self->stack[idx]->vec[0] = (float)PyFloat_AsDouble(items[0]);
+                               self->stack[idx]->vec[1] = (float)PyFloat_AsDouble(items[1]);
+                               self->stack[idx]->vec[2] = (float)PyFloat_AsDouble(items[2]);
+                               self->stack[idx]->vec[3] = (float)PyFloat_AsDouble(items[3]);
+                               ret = 0;
+                       }
+                       break;
+               default:
+                       break;
+       }
+
+       Py_DECREF(val);
+
+       if (ret == -1) {
+               PyErr_SetString(PyExc_AttributeError, "wrong number of items in list or tuple");
+               fprintf(stderr, "\nExpected %d numeric values, got %d.", wanted_len, len);
+       }
+
+       return ret;
 }
 
 /* write only */
@@ -667,14 +709,14 @@ PyTypeObject SockOutMap_Type = {
 
 
 static BPy_SockMap *Node_CreateInputMap(bNode *node, bNodeStack **stack) {
-       BPy_SockMap *map= PyObject_NEW(BPy_SockMap, &SockInMap_Type);
-       map->typeinfo= node->typeinfo;
-       map->stack= stack;
+       BPy_SockMap *map = PyObject_NEW(BPy_SockMap, &SockInMap_Type);
+       map->node = node;
+       map->stack = stack;
        return map;
 }
 
 static PyObject *Node_GetInputMap(BPy_Node *self) {
-       BPy_SockMap *inmap= Node_CreateInputMap(self->node, self->in);
+       BPy_SockMap *inmap = Node_CreateInputMap(self->node, self->in);
        return (PyObject *)(inmap);
 }
 
@@ -685,11 +727,11 @@ static PyObject *Node_GetInputMap(BPy_Node *self) {
 #define TEXTURE                                4
 #define PIXEL                          5
 #define COLOR                          6
-#define SPECULAR                       7
-#define MIRROR                         8
-#define AMBIENT                                9
-#define AMBIENTFACTOR          10
-#define EMITFACTOR                     11
+#define SPECULAR_COLOR         7
+#define MIRROR_COLOR           8
+#define AMBIENT_COLOR          9
+#define AMBIENT                                10
+#define EMIT                           11
 #define DISPLACE                       12
 #define STRAND                         13
 #define STRESS                         14
@@ -704,80 +746,80 @@ static PyObject *Node_GetInputMap(BPy_Node *self) {
 #define STRAND_D                       37
 
 static PyObject *ShadeInput_getAttribute(BPy_ShadeInput *self, void *type) {
-       PyObject *obj= NULL;
+       PyObject *obj = NULL;
        if(self->shi) {
                switch((int)type) {
                        case SURFACEVIEWVECTOR:
-                               obj= Py_BuildValue("(fff)", self->shi->view[0], self->shi->view[1], self->shi->view[2]);
+                               obj = Py_BuildValue("(fff)", self->shi->view[0], self->shi->view[1], self->shi->view[2]);
                                break;
                        case VIEWNORMAL:
-                               obj= Py_BuildValue("(fff)", self->shi->vn[0], self->shi->vn[1], self->shi->vn[2]);
+                               obj = Py_BuildValue("(fff)", self->shi->vn[0], self->shi->vn[1], self->shi->vn[2]);
                                break;
                        case SURFACENORMAL:
-                               obj= Py_BuildValue("(fff)", self->shi->facenor[0], self->shi->facenor[1], self->shi->facenor[2]);
+                               obj = Py_BuildValue("(fff)", self->shi->facenor[0], self->shi->facenor[1], self->shi->facenor[2]);
                                break;
                        case GLOBALTEXTURE:
-                               obj= Py_BuildValue("(fff)", self->shi->gl[0], self->shi->gl[1], self->shi->gl[2]);
+                               obj = Py_BuildValue("(fff)", self->shi->gl[0], self->shi->gl[1], self->shi->gl[2]);
                                break;
                        case TEXTURE:
-                               obj= Py_BuildValue("(fff)", self->shi->lo[0], self->shi->lo[1], self->shi->lo[2]);
+                               obj = Py_BuildValue("(fff)", self->shi->lo[0], self->shi->lo[1], self->shi->lo[2]);
                                break;
                        case PIXEL:
-                               obj= Py_BuildValue("(ii)", self->shi->xs, self->shi->ys);
+                               obj = Py_BuildValue("(ii)", self->shi->xs, self->shi->ys);
                                break;
                        case COLOR:
-                               obj= Py_BuildValue("(fff)", self->shi->r, self->shi->g, self->shi->b);
+                               obj = Py_BuildValue("(fff)", self->shi->r, self->shi->g, self->shi->b);
                                break;
-                       case SPECULAR:
-                               obj= Py_BuildValue("(fff)", self->shi->specr, self->shi->specg, self->shi->specb);
+                       case SPECULAR_COLOR:
+                               obj = Py_BuildValue("(fff)", self->shi->specr, self->shi->specg, self->shi->specb);
                                break;
-                       case MIRROR:
-                               obj= Py_BuildValue("(fff)", self->shi->mirr, self->shi->mirg, self->shi->mirb);
+                       case MIRROR_COLOR:
+                               obj = Py_BuildValue("(fff)", self->shi->mirr, self->shi->mirg, self->shi->mirb);
                                break;
-                       case AMBIENT:
-                               obj= Py_BuildValue("(fff)", self->shi->ambr, self->shi->ambg, self->shi->ambb);
+                       case AMBIENT_COLOR:
+                               obj = Py_BuildValue("(fff)", self->shi->ambr, self->shi->ambg, self->shi->ambb);
                                break;
-                       case AMBIENTFACTOR:
-                               obj= PyFloat_FromDouble((double)(self->shi->amb));
+                       case AMBIENT:
+                               obj = PyFloat_FromDouble((double)(self->shi->amb));
                                break;
-                       case EMITFACTOR:
-                               obj= PyFloat_FromDouble((double)(self->shi->emit));
+                       case EMIT:
+                               obj = PyFloat_FromDouble((double)(self->shi->emit));
                                break;
                        case DISPLACE:
-                               obj= Py_BuildValue("(fff)", self->shi->displace[0], self->shi->displace[1], self->shi->displace[2]);
+                               obj = Py_BuildValue("(fff)", self->shi->displace[0], self->shi->displace[1], self->shi->displace[2]);
                                break;
                        case STRAND:
-                               obj= PyFloat_FromDouble((double)(self->shi->strand));
+                               obj = PyFloat_FromDouble((double)(self->shi->strandco));
                                break;
                        case STRESS:
-                               obj= PyFloat_FromDouble((double)(self->shi->stress));
+                               obj = PyFloat_FromDouble((double)(self->shi->stress));
                                break;
                        case TANGENT:
-                               obj= Py_BuildValue("(fff)", self->shi->tang[0], self->shi->tang[1], self->shi->tang[2]);
+                               obj = Py_BuildValue("(fff)", self->shi->tang[0], self->shi->tang[1], self->shi->tang[2]);
                                break;
                        case SURFACE_D:
-                               obj= Py_BuildValue("(fff)(fff)", self->shi->dxco[0], self->shi->dxco[1], self->shi->dxco[2], self->shi->dyco[0], self->shi->dyco[1], self->shi->dyco[2]);
+                               obj = Py_BuildValue("(fff)(fff)", self->shi->dxco[0], self->shi->dxco[1], self->shi->dxco[2], self->shi->dyco[0], self->shi->dyco[1], self->shi->dyco[2]);
                                break;
                        case TEXTURE_D:
-                               obj= Py_BuildValue("(fff)(fff)", self->shi->dxlo[0], self->shi->dxlo[1], self->shi->dxlo[2], self->shi->dylo[0], self->shi->dylo[1], self->shi->dylo[2]);
+                               obj = Py_BuildValue("(fff)(fff)", self->shi->dxlo[0], self->shi->dxlo[1], self->shi->dxlo[2], self->shi->dylo[0], self->shi->dylo[1], self->shi->dylo[2]);
                                break;
                        case GLOBALTEXTURE_D:
-                               obj= Py_BuildValue("(fff)(fff)", self->shi->dxgl[0], self->shi->dxgl[1], self->shi->dxgl[2], self->shi->dygl[0], self->shi->dygl[1], self->shi->dygl[2]);
+                               obj = Py_BuildValue("(fff)(fff)", self->shi->dxgl[0], self->shi->dxgl[1], self->shi->dxgl[2], self->shi->dygl[0], self->shi->dygl[1], self->shi->dygl[2]);
                                break;
                        case REFLECTION_D:
-                               obj= Py_BuildValue("(fff)(fff)", self->shi->dxref[0], self->shi->dxref[1], self->shi->dxref[2], self->shi->dyref[0], self->shi->dyref[1], self->shi->dyref[2]);
+                               obj = Py_BuildValue("(fff)(fff)", self->shi->dxref[0], self->shi->dxref[1], self->shi->dxref[2], self->shi->dyref[0], self->shi->dyref[1], self->shi->dyref[2]);
                                break;
                        case NORMAL_D:
-                               obj= Py_BuildValue("(fff)(fff)", self->shi->dxno[0], self->shi->dxno[1], self->shi->dxno[2], self->shi->dyno[0], self->shi->dyno[1], self->shi->dyno[2]);
+                               obj = Py_BuildValue("(fff)(fff)", self->shi->dxno[0], self->shi->dxno[1], self->shi->dxno[2], self->shi->dyno[0], self->shi->dyno[1], self->shi->dyno[2]);
                                break;
                        case STICKY_D:
-                               obj= Py_BuildValue("(fff)(fff)", self->shi->dxsticky[0], self->shi->dxsticky[1], self->shi->dxsticky[2], self->shi->dysticky[0], self->shi->dysticky[1], self->shi->dysticky[2]);
+                               obj = Py_BuildValue("(fff)(fff)", self->shi->dxsticky[0], self->shi->dxsticky[1], self->shi->dxsticky[2], self->shi->dysticky[0], self->shi->dysticky[1], self->shi->dysticky[2]);
                                break;
                        case REFRACT_D:
-                               obj= Py_BuildValue("(fff)(fff)", self->shi->dxrefract[0], self->shi->dxrefract[1], self->shi->dxrefract[2], self->shi->dyrefract[0], self->shi->dyrefract[1], self->shi->dyrefract[2]);
+                               obj = Py_BuildValue("(fff)(fff)", self->shi->dxrefract[0], self->shi->dxrefract[1], self->shi->dxrefract[2], self->shi->dyrefract[0], self->shi->dyrefract[1], self->shi->dyrefract[2]);
                                break;
                        case STRAND_D:
-                               obj= Py_BuildValue("(ff)", self->shi->dxstrand, self->shi->dystrand);
+                               obj = Py_BuildValue("(ff)", self->shi->dxstrand, self->shi->dystrand);
                                break;
                        default:
                                break;
@@ -792,27 +834,26 @@ static PyObject *ShadeInput_getAttribute(BPy_ShadeInput *self, void *type) {
 
 static BPy_SockMap *Node_CreateOutputMap(bNode *node, bNodeStack **stack) {
        BPy_SockMap *map = PyObject_NEW(BPy_SockMap, &SockOutMap_Type);
-       map->typeinfo= node->typeinfo;
-       map->stack= stack;
+       map->node = node;
+       map->stack = stack;
        return map;
 }
 
 static PyObject *Node_GetOutputMap(BPy_Node *self) {
-       BPy_SockMap *outmap= Node_CreateOutputMap(self->node, self->out);
+       BPy_SockMap *outmap = Node_CreateOutputMap(self->node, self->out);
        return (PyObject *)outmap;
 }
 
 static PyObject *Node_GetShi(BPy_Node *self) {
-       BPy_ShadeInput *shi= ShadeInput_CreatePyObject(self->shi);
+       BPy_ShadeInput *shi = ShadeInput_CreatePyObject(self->shi);
        return (PyObject *)shi;
-
 }
 
 static PyObject *node_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
        PyObject *self;
        assert(type!=NULL && type->tp_alloc!=NULL);
-       self= type->tp_alloc(type, 1);
+       self = type->tp_alloc(type, 1);
        return self;
 }
 
@@ -822,17 +863,29 @@ static int node_init(BPy_Node *self, PyObject *args, PyObject *kwds)
 }
 
 static PyGetSetDef BPy_Node_getseters[] = {
-       {"ins",
+       {"input",
+               (getter)Node_GetInputMap, (setter)NULL,
+               "Get the input sockets mapping (dictionary)",
+               NULL},
+       {"i", /* alias */
                (getter)Node_GetInputMap, (setter)NULL,
-               "Get the ShadeInput mapping (dictionary)",
+               "Get the input sockets mapping (dictionary)",
+               NULL},
+       {"output",
+               (getter)Node_GetOutputMap, (setter)NULL,
+               "Get the output sockets mapping (dictionary)",
                NULL},
-       {"outs",
+       {"o", /* alias */
                (getter)Node_GetOutputMap, (setter)NULL,
-               "Get the ShadeInput mapping (dictionary)",
+               "Get the output sockets mapping (dictionary)",
                NULL},
        {"shi",
                (getter)Node_GetShi, (setter)NULL,
-               "Get the ShadeInput (ShadeInput)",
+               "Get the Shade Input data (ShadeInput)",
+               NULL},
+       {"s", /* alias */
+               (getter)Node_GetShi, (setter)NULL,
+               "Get the Shade Input data (ShadeInput)",
                NULL},
        {NULL,NULL,NULL,NULL,NULL}  /* Sentinel */
 };
@@ -842,19 +895,19 @@ static PyGetSetDef BPy_ShadeInput_getseters[] = {
          (getter)ShadeInput_getAttribute, (setter)NULL,
          "Get the current texture coordinate (tuple)",
          (void*)TEXTURE},
-       {"texture_global",
+       {"textureGlobal",
          (getter)ShadeInput_getAttribute, (setter)NULL,
          "Get the current global texture coordinate (tuple)",
          (void*)GLOBALTEXTURE},
-       {"surface_normal",
+       {"surfaceNormal",
          (getter)ShadeInput_getAttribute, (setter)NULL,
          "Get the current surface normal (tuple)",
          (void*)SURFACENORMAL},
-       {"view_normal",
+       {"viewNormal",
          (getter)ShadeInput_getAttribute, (setter)NULL,
          "Get the current view normal (tuple)",
          (void*)VIEWNORMAL},
-       {"surface_view_vec",
+       {"surfaceViewVector",
          (getter)ShadeInput_getAttribute, (setter)NULL,
          "Get the vector pointing to the viewpoint from the point being shaded (tuple)",
          (void*)SURFACEVIEWVECTOR},
@@ -866,26 +919,26 @@ static PyGetSetDef BPy_ShadeInput_getseters[] = {
          (getter)ShadeInput_getAttribute, (setter)NULL,
          "Get the color for the point being shaded (tuple)",
          (void*)COLOR},
-       {"specular",
+       {"specularColor",
          (getter)ShadeInput_getAttribute, (setter)NULL,
          "Get the specular color for the point being shaded (tuple)",
-         (void*)SPECULAR},
-       {"mirror",
+         (void*)SPECULAR_COLOR},
+       {"mirrorColor",
          (getter)ShadeInput_getAttribute, (setter)NULL,
          "Get the mirror color for the point being shaded (tuple)",
-         (void*)MIRROR},
-       {"ambient",
+         (void*)MIRROR_COLOR},
+       {"ambientColor",
          (getter)ShadeInput_getAttribute, (setter)NULL,
          "Get the ambient color for the point being shaded (tuple)",
-         (void*)AMBIENT},
-       {"ambient_factor",
+         (void*)AMBIENT_COLOR},
+       {"ambient",
          (getter)ShadeInput_getAttribute, (setter)NULL,
          "Get the ambient factor for the point being shaded (float)",
-         (void*)AMBIENTFACTOR},
-       {"emit_factor",
+         (void*)AMBIENT},
+       {"emit",
          (getter)ShadeInput_getAttribute, (setter)NULL,
          "Get the emit factor for the point being shaded (float)",
-         (void*)EMITFACTOR},
+         (void*)EMIT},
        {"displace",
          (getter)ShadeInput_getAttribute, (setter)NULL,
          "Get the displace vector for the point being shaded (tuple)",
@@ -902,38 +955,38 @@ static PyGetSetDef BPy_ShadeInput_getseters[] = {
          (getter)ShadeInput_getAttribute, (setter)NULL,
          "Get the tangent vector (tuple)",
          (void*)TANGENT},
-       {"surface_d",
+       {"surfaceD",
          (getter)ShadeInput_getAttribute, (setter)NULL,
          "Get the surface d (tuple of tuples)",
          (void*)SURFACE_D},
-       {"texture_d",
+       {"textureD",
          (getter)ShadeInput_getAttribute, (setter)NULL,
          "Get the texture d (tuple of tuples)",
          (void*)TEXTURE_D},
-       {"texture_global_d",
+       {"textureGlobalD",
          (getter)ShadeInput_getAttribute, (setter)NULL,
          "Get the global texture d (tuple of tuples)",
          (void*)GLOBALTEXTURE_D},
-       {"reflection_d",
+       {"reflectionD",
          (getter)ShadeInput_getAttribute, (setter)NULL,
          "Get the reflection d (tuple of tuples)",
          (void*)REFLECTION_D},
-       {"normal_d",
+       {"normalD",
          (getter)ShadeInput_getAttribute, (setter)NULL,
          "Get the normal d (tuple of tuples)",
          (void*)NORMAL_D},
-       {"sticky_d",
+       {"stickyD",
          (getter)ShadeInput_getAttribute, (setter)NULL,
          "Get the sticky d (tuple of tuples)",
          (void*)STICKY_D},
-       {"refract_d",
+       {"refractD",
          (getter)ShadeInput_getAttribute, (setter)NULL,
          "Get the refract d (tuple of tuples)",
          (void*)REFRACT_D},
-       {"strand_d",
+       {"strandD",
          (getter)ShadeInput_getAttribute, (setter)NULL,
          "Get the strand d (tuple)",
-         (void*)REFRACT_D},
+         (void*)STRAND_D},
        {NULL,NULL,NULL,NULL,NULL}  /* Sentinel */
 };
 
@@ -1101,7 +1154,6 @@ PyTypeObject ShadeInput_Type = {
        NULL
 };
 
-
 /* Initialise Node module */
 PyObject *Node_Init(void)
 {
@@ -1111,9 +1163,7 @@ PyObject *Node_Init(void)
                return NULL;
        if( PyType_Ready( &ShadeInput_Type ) < 0 )
                return NULL;
-       if( PyType_Ready( &OutputDefMap_Type ) < 0 )
-               return NULL;
-       if( PyType_Ready( &InputDefMap_Type ) < 0 )
+       if( PyType_Ready( &NodeSockets_Type ) < 0 )
                return NULL;
        if( PyType_Ready( &SockInMap_Type ) < 0 )
                return NULL;
@@ -1135,7 +1185,7 @@ PyObject *Node_Init(void)
 static int Node_compare(BPy_Node *a, BPy_Node *b)
 {
        bNode *pa = a->node, *pb = b->node;
-       return (pa==pb) ? 0 : -1;
+       return (pa == pb) ? 0 : -1;
 }
 
 static PyObject *Node_repr(BPy_Node *self)
@@ -1154,13 +1204,13 @@ BPy_Node *Node_CreatePyObject(bNode *node)
                return (BPy_Node *)(EXPP_ReturnPyObjError(PyExc_MemoryError, "couldn't create BPy_Node object"));
        }
 
-       pynode->node= node;
+       pynode->node = node;
 
        return pynode;
 }
 
 void InitNode(BPy_Node *self, bNode *node) {
-       self->node= node;
+       self->node = node;
 }
 
 bNode *Node_FromPyObject(PyObject *pyobj)
@@ -1170,16 +1220,16 @@ bNode *Node_FromPyObject(PyObject *pyobj)
 
 void Node_SetStack(BPy_Node *self, bNodeStack **stack, int type)
 {
-       if(type==NODE_INPUTSTACK) {
-               self->in= stack;
-       } else if(type==NODE_OUTPUTSTACK) {
-               self->out= stack;
+       if(type == NODE_INPUTSTACK) {
+               self->in = stack;
+       } else if(type == NODE_OUTPUTSTACK) {
+               self->out = stack;
        }
 }
 
 void Node_SetShi(BPy_Node *self, ShadeInput *shi)
 {
-       self->shi= shi;
+       self->shi = shi;
 }
 
 /*********************/
@@ -1187,12 +1237,12 @@ void Node_SetShi(BPy_Node *self, ShadeInput *shi)
 static int ShadeInput_compare(BPy_ShadeInput *a, BPy_ShadeInput *b)
 {
        ShadeInput *pa = a->shi, *pb = b->shi;
-       return (pa==pb) ? 0 : -1;
+       return (pa == pb) ? 0 : -1;
 }
 
 static PyObject *ShadeInput_repr(BPy_ShadeInput *self)
 {
-       return PyString_FromFormat( "[ShadeInput @ \"%p\"]", self);
+       return PyString_FromFormat( "[ShadeInput at \"%p\"]", self);
 }
 
 BPy_ShadeInput *ShadeInput_CreatePyObject(ShadeInput *shi)
index 434d0aa684a9215b422618f4e6711a7e4cfd13df..ce42527342acd7cd6d24005d29364b05da7ac2d6 100644 (file)
@@ -1,5 +1,5 @@
 /* 
- * $Id: Node.h 10449 2007-04-03 11:24:11Z jesterking $
+ * $Id$
  *
  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
  *
@@ -56,14 +56,16 @@ typedef struct BPy_ShadeInput {
 
 typedef struct {
        PyObject_VAR_HEAD
-       bNodeType *typeinfo;
+       bNode* node;
        bNodeStack **stack;
 } BPy_SockMap;
 
 typedef struct {
        PyObject_HEAD
        bNode *node;
-} BPy_DefinitionMap;
+       PyObject *input;
+       PyObject *output;
+} BPy_NodeSockets;
 
 typedef struct BPy_Node {
        PyObject_HEAD
@@ -76,13 +78,9 @@ typedef struct BPy_Node {
 extern PyObject *Node_Init(void);
 extern void InitNode(BPy_Node *self, bNode *node);
 extern BPy_Node *Node_CreatePyObject(bNode *node);
-extern BPy_DefinitionMap *Node_CreateOutputDefMap(bNode *node);
-extern BPy_DefinitionMap *Node_CreateInputDefMap(bNode *node);
+extern BPy_NodeSockets *Node_CreateSockets(bNode *node);
 extern void Node_SetStack(BPy_Node *self, bNodeStack **stack, int type);
 extern void Node_SetShi(BPy_Node *self, ShadeInput *shi);
-extern BPy_ShadeInput *ShadeInput_CreatePyObject(ShadeInput *shi);
-extern void Node_dealloc(BPy_Node *self);
-extern void ShadeInput_dealloc(BPy_ShadeInput *self);
 
 #define NODE_INPUTSTACK                0
 #define NODE_OUTPUTSTACK       1
index 561c193dfdb92aa097560c1e652656492b0263f8..5c426cdb39506e4522905b3bfa673e72b8a65ddf 100644 (file)
@@ -48,6 +48,7 @@
 #include "DNA_space_types.h"
 #include "DNA_screen_types.h"
 #include "DNA_texture_types.h"
+#include "DNA_text_types.h"
 #include "DNA_userdef_types.h"
 
 #include "BKE_global.h"
@@ -58,6 +59,7 @@
 #include "BKE_node.h"
 #include "BKE_object.h"
 #include "BKE_texture.h"
+#include "BKE_text.h"
 #include "BKE_utildefines.h"
 
 #include "CMP_node.h"
@@ -442,6 +444,36 @@ static void node_browse_tex_cb(void *ntree_v, void *node_v)
        node->menunr= 0;
 }
 
+static void node_dynamic_update_cb(void *ntree_v, void *node_v)
+{
+       Material *ma;
+       bNode *node= (bNode *)node_v;
+       ID *id= node->id;
+       int error= 0;
+
+       if (BTST(node->custom1, NODE_DYNAMIC_ERROR)) error= 1;
+
+       /* Users only have to press the "update" button in one pynode
+        * and we also update all others sharing the same script */
+       for (ma= G.main->mat.first; ma; ma= ma->id.next) {
+               if (ma->nodetree) {
+                       bNode *nd;
+                       for (nd= ma->nodetree->nodes.first; nd; nd= nd->next) {
+                               if ((nd->type == NODE_DYNAMIC) && (nd->id == id)) {
+                                       nd->custom1= 0;
+                                       nd->custom1= BSET(nd->custom1, NODE_DYNAMIC_REPARSE);
+                                       nd->menunr= 0;
+                                       if (error)
+                                               nd->custom1= BSET(nd->custom1, NODE_DYNAMIC_ERROR);
+                               }
+                       }
+               }
+       }
+
+       allqueue(REDRAWBUTSSHADING, 0);
+       allqueue(REDRAWNODE, 0);
+}
+
 static int node_buts_texture(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
 {
        if(block) {
@@ -483,6 +515,31 @@ static int node_buts_math(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *b
 
 /* ****************** BUTTON CALLBACKS FOR SHADER NODES ***************** */
 
+static void node_browse_text_cb(void *ntree_v, void *node_v)
+{
+       bNodeTree *ntree= ntree_v;
+       bNode *node= node_v;
+       ID *oldid;
+       
+       if(node->menunr<1) return;
+       
+       if(node->id) {
+               node->id->us--;
+       }
+       oldid= node->id;
+       node->id= BLI_findlink(&G.main->text, node->menunr-1);
+       id_us_plus(node->id);
+       BLI_strncpy(node->name, node->id->name+2, 21); /* huh? why 21? */
+
+       node->custom1= BSET(node->custom1, NODE_DYNAMIC_NEW);
+       
+       nodeSetActive(ntree, node);
+
+       allqueue(REDRAWBUTSSHADING, 0);
+       allqueue(REDRAWNODE, 0);
+
+       node->menunr= 0;
+}
 
 static void node_mat_alone_cb(void *node_v, void *unused)
 {
@@ -709,6 +766,42 @@ static int node_shader_buts_geometry(uiBlock *block, bNodeTree *ntree, bNode *no
        return 40;
 }
 
+static int node_shader_buts_dynamic(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr) 
+{ 
+       if (block) { 
+               uiBut *bt;
+               SpaceNode *snode= curarea->spacedata.first;
+               short dy= (short)butr->ymin;
+               int xoff=0;
+
+               /* B_NODE_EXEC is handled in butspace.c do_node_buts */
+               if(!node->id) {
+                               char *strp;
+                               IDnames_to_pupstring(&strp, NULL, "", &(G.main->text), NULL, NULL);
+                               node->menunr= 0;
+                               bt= uiDefButS(block, MENU, B_NODE_EXEC/*+node->nr*/, strp, 
+                                                               butr->xmin, dy, 19, 19, 
+                                                               &node->menunr, 0, 0, 0, 0, "Browses existing choices");
+                               uiButSetFunc(bt, node_browse_text_cb, ntree, node);
+                               xoff=19;
+                               if(strp) MEM_freeN(strp);       
+               }
+               else {
+                       bt = uiDefBut(block, BUT, B_NOP, "Update",
+                                       butr->xmin+xoff, butr->ymin+20, 50, 19,
+                                       &node->menunr, 0.0, 19.0, 0, 0, "Refresh this node (and all others that use the same script)");
+                       uiButSetFunc(bt, node_dynamic_update_cb, ntree, node);
+
+                       if (BTST(node->custom1, NODE_DYNAMIC_ERROR)) {
+                               BIF_ThemeColor(TH_REDALERT);
+                               ui_rasterpos_safe(butr->xmin + xoff, butr->ymin + 5, snode->aspect);
+                               snode_drawstring(snode, "Error! Check console...", butr->xmax - butr->xmin);
+                       }
+               }
+       }
+       return 20+19; 
+}
+
 /* only once called */
 static void node_shader_set_butfunc(bNodeType *ntype)
 {
@@ -755,6 +848,9 @@ static void node_shader_set_butfunc(bNodeType *ntype)
                case SH_NODE_GEOMETRY:
                        ntype->butfunc= node_shader_buts_geometry;
                        break;
+               case NODE_DYNAMIC:
+                       ntype->butfunc= node_shader_buts_dynamic;
+                       break;
                default:
                        ntype->butfunc= NULL;
        }
@@ -2680,7 +2776,7 @@ static void node_draw_basis(ScrArea *sa, SpaceNode *snode, bNode *node)
        uiSetRoundBox(8);
        uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax-NODE_DY, BASIS_RAD);
        glDisable(GL_BLEND);
-       
+
        /* scaling indicator */
        node_scaling_widget(TH_NODE, snode->aspect, rct->xmax-BASIS_RAD*snode->aspect, rct->ymin, rct->xmax, rct->ymin+BASIS_RAD*snode->aspect);
 
index b4026746a35652d1633b63c7dba5cef36fe69109..fff1d768b93ce679856ac119683fe1e12ff16041 100644 (file)
@@ -62,6 +62,7 @@
 #include "BKE_text.h"
 #include "BKE_global.h"
 #include "BKE_main.h"
+#include "BKE_node.h"
 
 #include "BIF_gl.h"
 #include "BIF_glutil.h"
@@ -1180,6 +1181,10 @@ void unlink_text(Text *text)
        if (BPY_check_all_scriptlinks (text)) {
                allqueue(REDRAWBUTSSCRIPT, 0);
        }
+       /* equivalently for pynodes: */
+       if (nodeDynamicUnlinkText ((ID*)text)) {
+               allqueue(REDRAWNODE, 0);
+       }
 
        for (scr= G.main->screen.first; scr; scr= scr->id.next) {
                for (area= scr->areabase.first; area; area= area->next) {
index 8fc11c68891171e1d06c13959bbb78e9bc60e3c7..a4e3137b2428df17d0799f383a8551bda48ddac2 100644 (file)
@@ -336,10 +336,10 @@ void node_shader_default(Material *ma)
        
        ma->nodetree= ntreeAddTree(NTREE_SHADER);
        
-       out= nodeAddNodeType(ma->nodetree, SH_NODE_OUTPUT, NULL);
+       out= nodeAddNodeType(ma->nodetree, SH_NODE_OUTPUT, NULL, NULL);
        out->locx= 300.0f; out->locy= 300.0f;
        
-       in= nodeAddNodeType(ma->nodetree, SH_NODE_MATERIAL, NULL);
+       in= nodeAddNodeType(ma->nodetree, SH_NODE_MATERIAL, NULL, NULL);
        in->locx= 10.0f; in->locy= 300.0f;
        nodeSetActive(ma->nodetree, in);
        
@@ -366,10 +366,10 @@ void node_composit_default(Scene *sce)
        
        sce->nodetree= ntreeAddTree(NTREE_COMPOSIT);
        
-       out= nodeAddNodeType(sce->nodetree, CMP_NODE_COMPOSITE, NULL);
+       out= nodeAddNodeType(sce->nodetree, CMP_NODE_COMPOSITE, NULL, NULL);
        out->locx= 300.0f; out->locy= 400.0f;
        
-       in= nodeAddNodeType(sce->nodetree, CMP_NODE_R_LAYERS, NULL);
+       in= nodeAddNodeType(sce->nodetree, CMP_NODE_R_LAYERS, NULL, NULL);
        in->locx= 10.0f; in->locy= 400.0f;
        nodeSetActive(sce->nodetree, in);
        
@@ -624,7 +624,7 @@ static void node_addgroup(SpaceNode *snode)
        if(val>=0) {
                ngroup= BLI_findlink(&G.main->nodetree, val);
                if(ngroup) {
-                       bNode *node= nodeAddNodeType(snode->edittree, NODE_GROUP, ngroup);
+                       bNode *node= nodeAddNodeType(snode->edittree, NODE_GROUP, ngroup, NULL);
                        
                        /* generics */
                        if(node) {
@@ -1523,7 +1523,10 @@ bNode *node_add_node(SpaceNode *snode, int type, float locx, float locy)
        
        node_deselectall(snode, 0);
        
-       if(type>=NODE_GROUP_MENU) {
+       if(type>=NODE_DYNAMIC_MENU) {
+               node= nodeAddNodeType(snode->edittree, type, NULL, NULL);
+       }
+       else if(type>=NODE_GROUP_MENU) {
                if(snode->edittree!=snode->nodetree) {
                        error("Can not add a Group in a Group");
                        return NULL;
@@ -1531,11 +1534,11 @@ bNode *node_add_node(SpaceNode *snode, int type, float locx, float locy)
                else {
                        bNodeTree *ngroup= BLI_findlink(&G.main->nodetree, type-NODE_GROUP_MENU);
                        if(ngroup)
-                               node= nodeAddNodeType(snode->edittree, NODE_GROUP, ngroup);
+                               node= nodeAddNodeType(snode->edittree, NODE_GROUP, ngroup, NULL);
                }
        }
        else
-               node= nodeAddNodeType(snode->edittree, type, NULL);
+               node= nodeAddNodeType(snode->edittree, type, NULL, NULL);
        
        /* generics */
        if(node) {
index 671628bf5c75c1149ba86dede14185a8770a5e48..1ad355b5e811c1235493b16666498cfca3cd4462 100644 (file)
@@ -1570,6 +1570,7 @@ static TBitem tb_node_addsh[]= {
        {       0, "Vector",            4, NULL},
        {       0, "Convertor", 5, NULL},
        {       0, "Group",             6, NULL},
+       {       0, "Dynamic",   7, NULL},
        {  -1, "",                      0, NULL}};
 
 static TBitem tb_node_addcomp[]= {
@@ -1582,6 +1583,7 @@ static TBitem tb_node_addcomp[]= {
        {       0, "Matte",             7, NULL},
        {       0, "Distort",   8, NULL},
        {       0, "Group",             9, NULL},
+       {       0, "Dynamic",   10, NULL},
        {       -1, "",                 0, NULL}};
 
 /* do_node_addmenu() in header_node.c, prototype in BSE_headerbuttons.h */
@@ -1630,11 +1632,21 @@ static TBitem *node_add_sublevel(ListBase *storage, bNodeTree *ntree, int nodecl
                }
        }
        else {
-               bNodeType *ntype= ntree->alltypes.first;
-               for(a=0; ntype; ntype= ntype->next) {
-                       if( ntype->nclass == nodeclass ) {
-                               addmenu[a].name= ntype->name;
-                               addmenu[a].retval= ntype->type;
+               bNodeType *type= ntree->alltypes.first;
+               int script=0;
+               for(a=0; type; type= type->next) {
+                       if( type->nclass == nodeclass ) {
+                               if(type->type == NODE_DYNAMIC) {
+                                       if(type->id)
+                                               addmenu[a].name= type->id->name+2;
+                                       else
+                                               addmenu[a].name= type->name;
+                                       addmenu[a].retval= NODE_DYNAMIC_MENU+script;
+                                       script++;
+                               } else {
+                                       addmenu[a].name= type->name;
+                                       addmenu[a].retval= type->type;
+                               }
                                a++;
                        }
                }
@@ -2130,6 +2142,7 @@ void toolbox_n(void)
                        menu1[3].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_OP_VECTOR);
                        menu1[4].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_CONVERTOR);
                        menu1[5].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_GROUP);
+                       menu1[6].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_OP_DYNAMIC);
                }
                else if(snode->treetype==NTREE_COMPOSIT) {
                        menu1[0].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_INPUT);
@@ -2141,6 +2154,7 @@ void toolbox_n(void)
                        menu1[6].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_MATTE);
                        menu1[7].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_DISTORT);
                        menu1[8].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_GROUP);
+                       menu1[9].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_OP_DYNAMIC);
 
                }