The material "Dynamic" node (disabled anyway) had incomplete base type initialization...
[blender.git] / source / blender / nodes / intern / SHD_nodes / SHD_dynamic.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2007 Blender Foundation.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): Nathan Letwory
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 /* TODO, support python3.x */
31 #undef WITH_PYTHON 
32
33 #ifdef WITH_PYTHON
34 #include <Python.h>
35 #include <compile.h>
36 #include <eval.h>
37 #endif
38
39 #include "DNA_text_types.h"
40 #include "BKE_text.h"
41
42
43 // XXX
44 #if 0
45 #ifdef WITH_PYTHON
46 #include "api2_2x/Node.h"
47 #include "api2_2x/gen_utils.h"
48 #include "BPY_extern.h"
49 #endif
50 #endif
51
52 #include "../SHD_util.h"
53
54 // XXX
55 #if 0
56 static void node_dynamic_setup(bNode *node);
57 static void node_dynamic_exec_cb(void *data, bNode *node, bNodeStack **in, bNodeStack **out);
58 static void node_dynamic_free_storage_cb(bNode *node);
59
60 #ifdef WITH_PYTHON
61 static PyObject *init_dynamicdict(void) {
62         PyObject *newscriptdict, *item;
63         PyGILState_STATE gilstate = PyGILState_Ensure();
64
65         newscriptdict= PyDict_New();
66
67         PyDict_SetItemString(newscriptdict, "__builtins__", PyEval_GetBuiltins());
68         item= PyString_FromString("__main__");
69         PyDict_SetItemString(newscriptdict, "__name__", item);
70         Py_DECREF(item);
71
72         PyGILState_Release(gilstate);
73
74         return newscriptdict;
75 }
76 #endif
77
78 static bNodeType *node_dynamic_find_typeinfo(ListBase *list, ID *id)
79 {
80         bNodeType *ntype = list->first;
81
82         while(ntype) {
83                 if (ntype->type == NODE_DYNAMIC && ntype->id == id)
84                         break;
85                 ntype = ntype->next;
86         }
87
88         return ntype; /* NULL if doesn't exist */
89 }
90
91 static void node_dynamic_free_typeinfo_sockets(bNodeType *tinfo)
92 {
93         bNodeSocketType *sock;
94
95         if (!tinfo) return;
96
97         if (tinfo->inputs) {
98                 sock = tinfo->inputs;
99                 while (sock->type != -1) {
100                         MEM_freeN(sock->name);
101                         sock++;
102                 }
103                 MEM_freeN(tinfo->inputs);
104                 tinfo->inputs = NULL;
105         }
106         if (tinfo->outputs) {
107                 sock = tinfo->outputs;
108                 while (sock->type != -1) {
109                         MEM_freeN(sock->name);
110                         sock++;
111                 }
112                 MEM_freeN(tinfo->outputs);
113                 tinfo->outputs = NULL;
114         }
115 }
116
117 static void node_dynamic_free_typeinfo(bNodeType *tinfo)
118 {
119         if (!tinfo) return;
120
121         node_dynamic_free_typeinfo_sockets(tinfo);
122
123         if (tinfo->name) { MEM_freeN(tinfo->name); }
124
125         MEM_freeN(tinfo);
126 }
127
128 static void node_dynamic_free_sockets(bNode *node)
129 {
130         BLI_freelistN(&node->inputs);
131         BLI_freelistN(&node->outputs);
132 }
133
134 /* For now we just remove the socket links. It's the safest
135  * route, since an update in the script may change completely the
136  * inputs and outputs. Trying to recreate the node links would be
137  * nicer for pynode authors, though. */
138 static void node_dynamic_update_socket_links(bNode *node, bNodeTree *ntree)
139 {
140         if (ntree) {
141                 nodeVerifyType(ntree, node);
142         }
143         else {
144                 Material *ma;
145
146                 for (ma= G.main->mat.first; ma; ma= ma->id.next) {
147                         if (ma->nodetree) {
148                                 bNode *nd;
149                                 for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) {
150                                         if (nd == node) nodeVerifyType(ma->nodetree, node);
151                                 }
152                         }
153                 }
154         }
155 }
156
157 static void node_dynamic_free_storage_cb(bNode *node)
158 {
159 #ifdef WITH_PYTHON
160         NodeScriptDict *nsd;
161         PyObject *pydict;
162         BPy_Node *pynode;
163
164         if (!node->storage) return;
165         nsd = (NodeScriptDict *)(node->storage);
166         pydict = nsd->dict;
167         if (pydict) {
168                 Py_DECREF(pydict);
169         }
170         pynode = nsd->node;
171         if (pynode) {
172                 Py_DECREF(pynode);
173         }
174 #endif
175         MEM_freeN(node->storage);
176         node->storage = NULL;
177 }
178
179 /* Disable pynode when its script fails */
180 static void node_dynamic_disable(bNode *node)
181 {
182         node->custom1 = 0;
183         node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ERROR);
184 }
185
186 /* Disable all pynodes using the given text (script) id */
187 static void node_dynamic_disable_all_by_id(ID *id)
188 {
189 #ifdef WITH_PYTHON
190         Material *ma; /* XXX hardcoded for shaders */
191
192         for (ma= G.main->mat.first; ma; ma= ma->id.next) {
193                 if (ma->nodetree) {
194                         bNode *nd;
195                         bNodeTree *ntree = ma->nodetree;
196                         for (nd= ntree->nodes.first; nd; nd= nd->next) {
197                                 if (nd->id == id) {
198                                         nd->custom1 = 0;
199                                         nd->custom1 = BSET(nd->custom1, NODE_DYNAMIC_ERROR);
200                                 }
201                         }
202                 }
203         }
204 #endif
205 }
206
207 static void node_rem_socklist_links(bNodeTree *ntree, ListBase *lb)
208 {
209         bNodeLink *link, *next;
210         bNodeSocket *sock;
211
212         if (!lb) return;
213
214         for (sock= lb->first; sock; sock= sock->next) {
215                 for (link= ntree->links.first; link; link= next) {
216                         next= link->next;
217                         if (link->fromsock==sock || link->tosock==sock) {
218                                 nodeRemLink(ntree, link);
219                         }
220                 }
221         }
222 }
223
224 /* XXX hardcoded for shaders */
225 static void node_dynamic_rem_all_links(bNodeType *tinfo)
226 {
227         Material *ma;
228         int in, out;
229
230         in = tinfo->inputs ? 1 : 0;
231         out = tinfo->outputs ? 1 : 0;
232
233         if (!in && !out) return;
234
235         for (ma= G.main->mat.first; ma; ma= ma->id.next) {
236                 if (ma->nodetree) {
237                         bNode *nd;
238                         bNodeTree *ntree = ma->nodetree;
239                         for (nd= ntree->nodes.first; nd; nd= nd->next) {
240                                 if (nd->typeinfo == tinfo) {
241                                         if (in)
242                                                 node_rem_socklist_links(ntree, &nd->inputs);
243                                         if (out)
244                                                 node_rem_socklist_links(ntree, &nd->outputs);
245                                 }
246                         }
247                 }
248         }
249 }
250
251 /* node_dynamic_reset: clean a pynode, getting rid of all
252  * data dynamically created for it. */
253 static void node_dynamic_reset(bNode *node, int unlink_text)
254 {
255         bNodeType *tinfo, *tinfo_default;
256         Material *ma;
257
258         tinfo = node->typeinfo;
259         tinfo_default = node_dynamic_find_typeinfo(&node_all_shaders, NULL);
260
261         if ((tinfo == tinfo_default) && unlink_text) {
262                 ID *textID = node->id;
263         /* already at default (empty) state, which happens if this node's
264          * script failed to parse at the first stage: definition. We're here
265          * because its text was removed from Blender. */
266                 for (ma= G.main->mat.first; ma; ma= ma->id.next) {
267                         if (ma->nodetree) {
268                                 bNode *nd;
269                                 for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) {
270                                         if (nd->id == textID) {
271                                                 nd->id = NULL;
272                                                 nd->custom1 = 0;
273                                                 nd->custom1 = BSET(nd->custom1, NODE_DYNAMIC_NEW);
274                                                 BLI_strncpy(nd->name, "Dynamic", 8);
275                                                 return;
276                                         }
277                                 }
278                         }
279                 }
280         }
281
282         node_dynamic_rem_all_links(tinfo);
283         node_dynamic_free_typeinfo_sockets(tinfo);
284
285         /* reset all other XXX shader nodes sharing this typeinfo */
286         for (ma= G.main->mat.first; ma; ma= ma->id.next) {
287                 if (ma->nodetree) {
288                         bNode *nd;
289                         for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) {
290                                 if (nd->typeinfo == tinfo) {
291                                         node_dynamic_free_storage_cb(nd);
292                                         node_dynamic_free_sockets(nd);
293                                         //node_dynamic_update_socket_links(nd, ma->nodetree);
294                                         nd->typeinfo = tinfo_default;
295                                         if (unlink_text) {
296                                                 nd->id = NULL;
297                                                 nd->custom1 = 0;
298                                                 nd->custom1 = BSET(nd->custom1, NODE_DYNAMIC_NEW);
299                                                 BLI_strncpy(nd->name, "Dynamic", 8);
300                                         }
301                                 }
302                         }
303                 }
304         }
305
306         /* XXX hardcoded for shaders: */
307         if (tinfo->id) { BLI_remlink(&node_all_shaders, tinfo); }
308         node_dynamic_free_typeinfo(tinfo);
309 }
310
311 /* Special case of the above function: for working pynodes
312  * that were saved on a .blend but fail for some reason when
313  * the file is opened. We need this because pynodes are initialized
314  * before G.main. */
315 static void node_dynamic_reset_loaded(bNode *node)
316 {
317         bNodeType *tinfo = node->typeinfo;
318
319         node_dynamic_rem_all_links(tinfo);
320         node_dynamic_free_typeinfo_sockets(tinfo);
321         node_dynamic_free_storage_cb(node);
322         /* XXX hardcoded for shaders: */
323         if (tinfo->id) { BLI_remlink(&node_all_shaders, tinfo); }
324
325         node_dynamic_free_typeinfo(tinfo);
326         node->typeinfo = node_dynamic_find_typeinfo(&node_all_shaders, NULL);
327 }
328
329 int nodeDynamicUnlinkText(ID *txtid) {
330         Material *ma;
331         bNode *nd;
332
333         /* find one node that uses this text */
334         for (ma= G.main->mat.first; ma; ma= ma->id.next) {
335                 if (ma->nodetree) {
336                         for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) {
337                                 if ((nd->type == NODE_DYNAMIC) && (nd->id == txtid)) {
338                                         node_dynamic_reset(nd, 1); /* found, reset all */
339                                         return 1;
340                                 }
341                         }
342                 }
343         }
344         return 0; /* no pynodes used this text */
345 }
346
347 static void node_dynamic_pyerror_print(bNode *node)
348 {
349 #ifdef WITH_PYTHON
350         PyGILState_STATE gilstate = PyGILState_Ensure();
351
352         fprintf(stderr, "\nError in dynamic node script \"%s\":\n", node->name);
353         if (PyErr_Occurred()) {
354                 PyErr_Print();
355                 PyErr_Clear();
356                 PySys_SetObject("last_traceback", NULL);
357         }
358         else { fprintf(stderr, "Not a valid dynamic node Python script.\n"); }
359
360         PyGILState_Release(gilstate);
361 #endif
362 }
363
364 static void node_dynamic_register_type(bNode *node)
365 {
366         nodeRegisterType(&node_all_shaders, node->typeinfo);
367         /* nodeRegisterType copied it to a new one, so we
368          * free the typeinfo itself, but not what it
369          * points to: */
370         MEM_freeN(node->typeinfo);
371         node->typeinfo = node_dynamic_find_typeinfo(&node_all_shaders, node->id);
372         MEM_freeN(node->typeinfo->name);
373         node->typeinfo->name = BLI_strdup(node->name);
374 }
375
376 #ifdef WITH_PYTHON
377 /* node_dynamic_get_pynode:
378  * Find the pynode definition from the script */
379 static PyObject *node_dynamic_get_pynode(PyObject *dict)
380 {
381         PyObject *key= NULL;
382         Py_ssize_t pos = 0;
383         PyObject *value = NULL;
384
385         /* script writer specified a node? */
386         value = PyDict_GetItemString(dict, "__node__");
387
388         if (value) {
389                 if (PyObject_TypeCheck(value, &PyType_Type)) {
390                         Py_INCREF(value);
391                         return value;
392                 }
393                 else {
394                         PyErr_SetString(PyExc_TypeError,
395                                 "expected class object derived from Scripted node");
396                         return NULL;
397                 }
398         }
399
400         /* case not, search for it in the script's global dictionary */
401         while (PyDict_Next(dict, &pos, &key, &value)) {
402                 /* skip names we know belong to other available objects */
403                 if (strcmp("Socket", PyString_AsString(key)) == 0)
404                         continue;
405                 else if (strcmp("Scripted", PyString_AsString(key)) == 0)
406                         continue;
407                 /* naive: we grab the first ob of type 'type': */
408                 else if (PyObject_TypeCheck(value, &PyType_Type)) {
409                         Py_INCREF(value);
410                         return value;
411                 }
412         }
413
414         PyErr_SetString(PyExc_TypeError,
415                 "no PyNode definition found in the script!");
416         return NULL;
417 }
418 #endif /* WITH_PYTHON */
419
420 static int node_dynamic_parse(struct bNode *node)
421 {
422 #ifndef WITH_PYTHON
423         return -1;
424 #else
425         PyObject *dict= NULL;
426         PyObject *pynode_data= NULL;
427         PyObject *pynode= NULL;
428         PyObject *args= NULL;
429         NodeScriptDict *nsd = NULL;
430         PyObject *pyresult = NULL;
431         char *buf = NULL;
432         int is_valid_script = 0;
433         PyGILState_STATE gilstate;
434
435         if (!node->id || !node->storage)
436                 return 0;
437
438         /* READY, no need to be here */
439         if (BTST(node->custom1, NODE_DYNAMIC_READY))
440                 return 0;
441
442         /* for threading */
443         gilstate = PyGILState_Ensure();
444
445         nsd = (NodeScriptDict *)node->storage;
446
447         dict = (PyObject *)(nsd->dict);
448         buf = txt_to_buf((Text *)node->id);
449
450         pyresult = PyRun_String(buf, Py_file_input, dict, dict);
451
452         MEM_freeN(buf);
453
454         if (!pyresult) {
455                 if (BTST(node->custom1, NODE_DYNAMIC_LOADED)) {
456                         node_dynamic_disable(node);
457                 } else {
458                 node_dynamic_disable_all_by_id(node->id);
459                 }
460                 node_dynamic_pyerror_print(node);
461                 PyGILState_Release(gilstate);
462                 return -1;
463         }
464
465         Py_DECREF(pyresult);
466
467         pynode_data = node_dynamic_get_pynode(dict);
468
469         if (pynode_data) {
470                 BPy_NodeSocketLists *socklists = Node_CreateSocketLists(node);
471
472                 args = Py_BuildValue("(O)", socklists);
473
474                 /* init it to get the input and output sockets */
475                 pynode = PyObject_Call(pynode_data, args, NULL);
476
477                 Py_DECREF(pynode_data);
478                 Py_DECREF(socklists);
479                 Py_DECREF(args);
480
481                 if (!PyErr_Occurred() && pynode && pytype_is_pynode(pynode)) {
482                         InitNode((BPy_Node *)(pynode), node);
483                         nsd->node = pynode;
484                         node->typeinfo->execfunc = node_dynamic_exec_cb;
485                         is_valid_script = 1;
486
487                         /* for NEW, LOADED, REPARSE */
488                         if (BNTST(node->custom1, NODE_DYNAMIC_ADDEXIST)) {
489                                 node->typeinfo->pydict = dict;
490                                 node->typeinfo->pynode = pynode;
491                                 node->typeinfo->id = node->id;
492                                 if (BNTST(node->custom1, NODE_DYNAMIC_LOADED))
493                                         nodeAddSockets(node, node->typeinfo);
494                                 if (BNTST(node->custom1, NODE_DYNAMIC_REPARSE))
495                                         node_dynamic_register_type(node);
496                         }
497
498                         node->custom1 = 0;
499                         node->custom1 = BSET(node->custom1, NODE_DYNAMIC_READY);
500                 }
501         }
502
503         PyGILState_Release(gilstate);
504
505         if (!is_valid_script) { /* not a valid pynode script */
506                 node_dynamic_disable_all_by_id(node->id);
507                 node_dynamic_pyerror_print(node);
508                 return -1;
509         }
510
511         return 0;
512 #endif
513 }
514
515 /* node_dynamic_setup: prepare for execution (state: NODE_DYNAMIC_READY)
516  * pynodes already linked to a script (node->id != NULL). */
517 static void node_dynamic_setup(bNode *node)
518 {
519 #ifdef WITH_PYTHON
520         NodeScriptDict *nsd = NULL;
521         bNodeTree *nodetree = NULL;
522         bNodeType *ntype = NULL;
523         PyGILState_STATE gilstate;
524
525         /* Possible cases:
526          * NEW
527          * ADDEXIST
528          * LOADED
529          * REPARSE
530          * ERROR
531          * READY
532          */
533
534         /* NEW, but not linked to a script: link default (empty) typeinfo */
535         if (!node->id) {
536                 node->typeinfo = node_dynamic_find_typeinfo(&node_all_shaders,
537                                 NULL);
538                 return;
539         }
540
541         /* READY, no need to be here */
542         if (BTST(node->custom1, NODE_DYNAMIC_READY))
543                 return;
544
545         gilstate = PyGILState_Ensure();
546
547         /* ERROR, reset to (empty) defaults */
548         if (BCLR(node->custom1, NODE_DYNAMIC_ERROR) == 0) {
549                 node_dynamic_reset(node, 0);
550                 PyGILState_Release(gilstate);
551                 return;
552         }
553
554         /* User asked to update this pynode, prepare it for reparsing */
555         if (BTST(node->custom1, NODE_DYNAMIC_REPARSE)) {
556                 int needs_parsing = 1;
557
558                 node->custom1 = BSET(node->custom1, NODE_DYNAMIC_NEW);
559
560                 if (BTST(node->custom1, NODE_DYNAMIC_ERROR)) {
561                         node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_REPARSE);
562                         ntype = node_dynamic_find_typeinfo(&node_all_shaders, node->id);
563
564                         if (ntype) {
565                                 node->typeinfo = ntype;
566                                 node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ADDEXIST);
567                                 node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_ERROR);
568                                 needs_parsing = 0;
569                         }
570                         else { nodeMakeDynamicType(node); }
571
572                 } else {
573                         node_dynamic_rem_all_links(node->typeinfo);
574                         node_dynamic_free_typeinfo_sockets(node->typeinfo);
575                         node_dynamic_update_socket_links(node, NULL);
576                         node_dynamic_free_storage_cb(node);
577                 }
578
579                 if (needs_parsing) {
580                         nsd = MEM_callocN(sizeof(NodeScriptDict), "node script dictionary");
581                         nsd->dict = init_dynamicdict();
582                         node->storage = nsd;
583                         /* prepared, now reparse: */
584                         node_dynamic_parse(node);
585                         PyGILState_Release(gilstate);
586                         return;
587                 }
588         }
589         else if (BTST(node->custom1, NODE_DYNAMIC_LOADED)) {
590                 /* when loading from a .blend we don't have G.main yet, so we
591                  * quickly abuse node->storage in ntreeInitTypes (node.c) to have
592                  * our nodetree ptr (needed if a pynode script that worked before
593                  * saving the .blend for some reason fails upon loading): */
594                 nodetree = (bNodeTree *)node->storage;
595                 node->storage = NULL;
596         }
597
598         if (node->storage)
599                 fprintf(stderr, "\nDEBUG: PYNODES ERROR: non NULL node->storage in node_dynamic_setup()\n");
600
601         nsd = MEM_callocN(sizeof(NodeScriptDict), "node script dictionary");
602         node->storage = nsd;
603         
604         /* NEW, LOADED or REPARSE */
605         if (BNTST(node->custom1, NODE_DYNAMIC_ADDEXIST)) {
606                 /* check if there's already a bNodeType linked to this script */
607                 /* (XXX hardcoded for shader nodes for now) */
608                 ntype = node_dynamic_find_typeinfo(&node_all_shaders, node->id);
609
610                 if (ntype) { /* if so, reuse it */
611                         node->typeinfo = ntype;
612                         /* so this is actually an ADDEXIST type */
613                         node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ADDEXIST);
614                 }
615                 else { /* create bNodeType for this pynode */
616                         nodeMakeDynamicType(node);
617                         nsd->dict = init_dynamicdict();
618                         if ((node_dynamic_parse(node) == -1) && nodetree) {
619                                 node_dynamic_reset_loaded(node);
620                         }
621                         PyGILState_Release(gilstate);
622                         return;
623                 }
624         }
625
626         /* ADDEXIST: new pynode linked to an already registered dynamic type,
627          * we just reuse existing py dict and pynode */
628         nsd->dict = node->typeinfo->pydict;
629         nsd->node = node->typeinfo->pynode;
630
631         Py_INCREF((PyObject *)(nsd->dict));
632         Py_INCREF((PyObject *)(nsd->node));
633
634         if (BTST(node->custom1, NODE_DYNAMIC_NEW)) {
635                 nodeAddSockets(node, node->typeinfo);
636                 node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_NEW);
637         }
638
639         node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_ADDEXIST);
640         node->custom1 = BSET(node->custom1, NODE_DYNAMIC_READY);
641
642         PyGILState_Release(gilstate);
643 #endif /* WITH_PYTHON */
644         return;
645 }
646
647 /* node_dynamic_init_cb callback: called when a pynode is created.
648  * The pynode type is passed via node->custom2. It can be:
649  *  0: for loaded empty nodes
650  *  NODE_DYNAMIC_MENU: for the default Dynamic node type
651  *  > NODE_DYNAMIC_MENU: for the new types defined by scripts
652 */
653 static void node_dynamic_init_cb(bNode *node) {
654         int type = node->custom2;
655
656         node->custom2 = 0;
657
658         if (type >= NODE_DYNAMIC_MENU) {
659                 node->custom1 = 0;
660
661                 if (type == NODE_DYNAMIC_MENU) {
662                         node->custom1 = BSET(node->custom1, NODE_DYNAMIC_NEW);
663                         return;
664                 }
665
666                 node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ADDEXIST);
667                 node->id = node->typeinfo->id;
668         }
669
670         node_dynamic_setup(node);
671 }
672
673 /* node_dynamic_copy_cb: pynode copy callback */
674 static void node_dynamic_copy_cb(bNode *orig_node, bNode *new_node)
675 {
676 #ifndef WITH_PYTHON
677         return;
678 #else
679         NodeScriptDict *nsd;
680         PyGILState_STATE gilstate;
681
682         if (!orig_node->storage) return;
683
684         nsd = (NodeScriptDict *)(orig_node->storage);
685         new_node->storage = MEM_dupallocN(orig_node->storage);
686
687         gilstate = PyGILState_Ensure();
688
689         if (nsd->node)
690                 Py_INCREF((PyObject *)(nsd->node));
691         if (nsd->dict)
692                 Py_INCREF((PyObject *)(nsd->dict));
693
694         PyGILState_Release(gilstate);
695 #endif
696 }
697
698 /* node_dynamic_exec_cb: the execution callback called per pixel
699  * during rendering. */
700 static void node_dynamic_exec_cb(void *data, bNode *node, bNodeStack **in, bNodeStack **out) {
701 #ifndef WITH_PYTHON
702         return;
703 #else
704         BPy_Node *mynode = NULL;
705         NodeScriptDict *nsd = NULL;
706         PyObject *pyresult = NULL;
707         PyObject *args = NULL;
708         ShadeInput *shi;
709         PyGILState_STATE gilstate;
710
711         if (!node->id)
712                 return;
713
714         /*if (G.scene->r.threads > 1)
715                 return;*/
716
717         if (BTST2(node->custom1, NODE_DYNAMIC_NEW, NODE_DYNAMIC_REPARSE)) {
718                 node_dynamic_setup(node);
719                 return;
720         }
721
722         if (BTST(node->custom1, NODE_DYNAMIC_ERROR)) {
723                 if (node->storage) node_dynamic_setup(node);
724                 return;
725         }
726
727         if (BTST(node->custom1, NODE_DYNAMIC_READY)) {
728                 nsd = (NodeScriptDict *)node->storage;
729                 mynode = (BPy_Node *)(nsd->node);
730
731
732                 if (mynode && PyCallable_Check((PyObject *)mynode)) {
733
734                         gilstate = PyGILState_Ensure();
735
736                         mynode->node = node;
737                         shi = ((ShaderCallData *)data)->shi;
738
739                         Node_SetStack(mynode, in, NODE_INPUTSTACK);
740                         Node_SetStack(mynode, out, NODE_OUTPUTSTACK);
741                         Node_SetShi(mynode, shi);
742
743                         args=Py_BuildValue("()");
744                         pyresult= PyObject_Call((PyObject *)mynode, args, NULL);
745                         Py_DECREF(args);
746
747                         if (!pyresult) {
748                                 PyGILState_Release(gilstate);
749                                 node_dynamic_disable_all_by_id(node->id);
750                                 node_dynamic_pyerror_print(node);
751                                 node_dynamic_setup(node);
752                                 return;
753                         }
754                         Py_DECREF(pyresult);
755                         PyGILState_Release(gilstate);
756                 }
757         }
758 #endif
759 }
760
761 void register_node_type_sh_dynamic(ListBase *lb)
762 {
763         static bNodeType ntype;
764         
765         node_type_base(&ntype, NODE_DYNAMIC, "Dynamic", NODE_CLASS_OP_DYNAMIC, NODE_OPTIONS, NULL, NULL);
766         node_type_size(&ntype, 150, 60, 300);
767         node_type_init(&ntype, node_dynamic_init_cb);
768         node_type_storage(&ntype, "NodeScriptDict", node_dynamic_free_storage_cb, node_dynamic_copy_cb);
769         node_type_exec(&ntype, node_dynamic_exec_cb);
770         
771         nodeRegisterType(lb, &ntype);
772 }
773
774 #else
775
776 void register_node_type_sh_dynamic(ListBase *lb)
777 {
778         static bNodeType ntype;
779         
780         node_type_base(&ntype, NODE_DYNAMIC, "Dynamic", NODE_CLASS_OP_DYNAMIC, 0, NULL, NULL);
781         
782         nodeRegisterType(lb, &ntype);
783 }
784
785 #endif
786
787