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