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