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