diff options
-rw-r--r-- | source/blender/blenkernel/BKE_node.h | 34 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_utildefines.h | 20 | ||||
-rw-r--r-- | source/blender/blenkernel/SConscript | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/node.c | 200 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 19 | ||||
-rw-r--r-- | source/blender/blenloader/intern/writefile.c | 2 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_node_types.h | 4 | ||||
-rw-r--r-- | source/blender/nodes/SConscript | 4 | ||||
-rw-r--r-- | source/blender/nodes/SHD_node.h | 2 | ||||
-rw-r--r-- | source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c | 645 | ||||
-rw-r--r-- | source/blender/python/SConscript | 4 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Blender.c | 2 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Node.c | 718 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Node.h | 14 | ||||
-rw-r--r-- | source/blender/src/drawnode.c | 98 | ||||
-rw-r--r-- | source/blender/src/drawtext.c | 5 | ||||
-rw-r--r-- | source/blender/src/editnode.c | 19 | ||||
-rw-r--r-- | source/blender/src/toolbox.c | 24 |
18 files changed, 1266 insertions, 549 deletions
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index f324c5d693c..bad7f0e90be 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -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 diff --git a/source/blender/blenkernel/BKE_utildefines.h b/source/blender/blenkernel/BKE_utildefines.h index fc22f6787b1..aa2be236d36 100644 --- a/source/blender/blenkernel/BKE_utildefines.h +++ b/source/blender/blenkernel/BKE_utildefines.h @@ -171,20 +171,22 @@ /* 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) ) diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript index f8f2f0b9f57..1bb98239a68 100644 --- a/source/blender/blenkernel/SConscript +++ b/source/blender/blenkernel/SConscript @@ -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'] diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 43a6f2091de..f30ad81bf0c 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -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*/ +} diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 33fe1b36f52..fa580220799 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -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 */ diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index d9766af6ba1..0804ec9689c 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -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); diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 0b462a46753..0e2805c88b7 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -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 { diff --git a/source/blender/nodes/SConscript b/source/blender/nodes/SConscript index 0460848b4a5..cc7cde6fc26 100644 --- a/source/blender/nodes/SConscript +++ b/source/blender/nodes/SConscript @@ -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] ) diff --git a/source/blender/nodes/SHD_node.h b/source/blender/nodes/SHD_node.h index 8064a543ca0..d75d7c9f568 100644 --- a/source/blender/nodes/SHD_node.h +++ b/source/blender/nodes/SHD_node.h @@ -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 diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c b/source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c index 1ba777a0533..c198e73a3bf 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c @@ -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 }; diff --git a/source/blender/python/SConscript b/source/blender/python/SConscript index 9cd245394b0..f608787d66d 100644 --- a/source/blender/python/SConscript +++ b/source/blender/python/SConscript @@ -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') diff --git a/source/blender/python/api2_2x/Blender.c b/source/blender/python/api2_2x/Blender.c index db47d6550c2..46f7b9da79f 100644 --- a/source/blender/python/api2_2x/Blender.c +++ b/source/blender/python/api2_2x/Blender.c @@ -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()); diff --git a/source/blender/python/api2_2x/Node.c b/source/blender/python/api2_2x/Node.c index 2871eda9432..195b61a39ea 100644 --- a/source/blender/python/api2_2x/Node.c +++ b/source/blender/python/api2_2x/Node.c @@ -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) diff --git a/source/blender/python/api2_2x/Node.h b/source/blender/python/api2_2x/Node.h index 434d0aa684a..ce42527342a 100644 --- a/source/blender/python/api2_2x/Node.h +++ b/source/blender/python/api2_2x/Node.h @@ -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 diff --git a/source/blender/src/drawnode.c b/source/blender/src/drawnode.c index 561c193dfdb..5c426cdb395 100644 --- a/source/blender/src/drawnode.c +++ b/source/blender/src/drawnode.c @@ -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); diff --git a/source/blender/src/drawtext.c b/source/blender/src/drawtext.c index b4026746a35..fff1d768b93 100644 --- a/source/blender/src/drawtext.c +++ b/source/blender/src/drawtext.c @@ -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) { diff --git a/source/blender/src/editnode.c b/source/blender/src/editnode.c index 8fc11c68891..a4e3137b242 100644 --- a/source/blender/src/editnode.c +++ b/source/blender/src/editnode.c @@ -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) { diff --git a/source/blender/src/toolbox.c b/source/blender/src/toolbox.c index 671628bf5c7..1ad355b5e81 100644 --- a/source/blender/src/toolbox.c +++ b/source/blender/src/toolbox.c @@ -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); } |