Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/BKE_node.h34
-rw-r--r--source/blender/blenkernel/BKE_utildefines.h20
-rw-r--r--source/blender/blenkernel/SConscript1
-rw-r--r--source/blender/blenkernel/intern/node.c200
-rw-r--r--source/blender/blenloader/intern/readfile.c19
-rw-r--r--source/blender/blenloader/intern/writefile.c2
-rw-r--r--source/blender/makesdna/DNA_node_types.h4
-rw-r--r--source/blender/nodes/SConscript4
-rw-r--r--source/blender/nodes/SHD_node.h2
-rw-r--r--source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c645
-rw-r--r--source/blender/python/SConscript4
-rw-r--r--source/blender/python/api2_2x/Blender.c2
-rw-r--r--source/blender/python/api2_2x/Node.c718
-rw-r--r--source/blender/python/api2_2x/Node.h14
-rw-r--r--source/blender/src/drawnode.c98
-rw-r--r--source/blender/src/drawtext.c5
-rw-r--r--source/blender/src/editnode.c19
-rw-r--r--source/blender/src/toolbox.c24
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);
}