Blender V2.61 - r43446

node_shader_dynamic.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version. 
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2007 Blender Foundation.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): Nathan Letwory
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 /* TODO, support python3.x */
00034 #undef WITH_PYTHON 
00035 
00036 #ifdef WITH_PYTHON
00037 #include <Python.h>
00038 #include <compile.h>
00039 #include <eval.h>
00040 #endif
00041 
00042 #include "DNA_text_types.h"
00043 #include "BKE_text.h"
00044 
00045 
00046 // XXX
00047 #if 0
00048 #ifdef WITH_PYTHON
00049 #include "api2_2x/Node.h"
00050 #include "api2_2x/gen_utils.h"
00051 #include "BPY_extern.h"
00052 #endif
00053 #endif
00054 
00055 #include "node_shader_util.h"
00056 
00057 // XXX
00058 #if 0
00059 static void node_dynamic_setup(bNode *node);
00060 static void node_dynamic_exec_cb(void *data, bNode *node, bNodeStack **in, bNodeStack **out);
00061 static void node_dynamic_free_storage_cb(bNode *node);
00062 
00063 #ifdef WITH_PYTHON
00064 static PyObject *init_dynamicdict(void)
00065 {
00066     PyObject *newscriptdict, *item;
00067     PyGILState_STATE gilstate = PyGILState_Ensure();
00068 
00069     newscriptdict= PyDict_New();
00070 
00071     PyDict_SetItemString(newscriptdict, "__builtins__", PyEval_GetBuiltins());
00072     item= PyString_FromString("__main__");
00073     PyDict_SetItemString(newscriptdict, "__name__", item);
00074     Py_DECREF(item);
00075 
00076     PyGILState_Release(gilstate);
00077 
00078     return newscriptdict;
00079 }
00080 #endif
00081 
00082 static bNodeType *node_dynamic_find_typeinfo(ListBase *list, ID *id)
00083 {
00084     bNodeType *ntype = list->first;
00085 
00086     while(ntype) {
00087         if (ntype->type == NODE_DYNAMIC && ntype->id == id)
00088             break;
00089         ntype = ntype->next;
00090     }
00091 
00092     return ntype; /* NULL if doesn't exist */
00093 }
00094 
00095 static void node_dynamic_free_typeinfo_sockets(bNodeType *tinfo)
00096 {
00097     bNodeSocketTemplate *sock;
00098 
00099     if (!tinfo) return;
00100 
00101     if (tinfo->inputs) {
00102         sock = tinfo->inputs;
00103         while (sock->type != -1) {
00104             MEM_freeN(sock->name);
00105             sock++;
00106         }
00107         MEM_freeN(tinfo->inputs);
00108         tinfo->inputs = NULL;
00109     }
00110     if (tinfo->outputs) {
00111         sock = tinfo->outputs;
00112         while (sock->type != -1) {
00113             MEM_freeN(sock->name);
00114             sock++;
00115         }
00116         MEM_freeN(tinfo->outputs);
00117         tinfo->outputs = NULL;
00118     }
00119 }
00120 
00121 static void node_dynamic_free_typeinfo(bNodeType *tinfo)
00122 {
00123     if (!tinfo) return;
00124 
00125     node_dynamic_free_typeinfo_sockets(tinfo);
00126 
00127     if (tinfo->name) { MEM_freeN(tinfo->name); }
00128 
00129     MEM_freeN(tinfo);
00130 }
00131 
00132 static void node_dynamic_free_sockets(bNode *node)
00133 {
00134     BLI_freelistN(&node->inputs);
00135     BLI_freelistN(&node->outputs);
00136 }
00137 
00138 /* For now we just remove the socket links. It's the safest
00139  * route, since an update in the script may change completely the
00140  * inputs and outputs. Trying to recreate the node links would be
00141  * nicer for pynode authors, though. */
00142 static void node_dynamic_update_socket_links(bNode *node, bNodeTree *ntree)
00143 {
00144     if (ntree) {
00145         nodeVerifyType(ntree, node);
00146     }
00147     else {
00148         Material *ma;
00149 
00150         for (ma= G.main->mat.first; ma; ma= ma->id.next) {
00151             if (ma->nodetree) {
00152                 bNode *nd;
00153                 for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) {
00154                     if (nd == node) nodeVerifyType(ma->nodetree, node);
00155                 }
00156             }
00157         }
00158     }
00159 }
00160 
00161 static void node_dynamic_free_storage_cb(bNode *node)
00162 {
00163 #ifdef WITH_PYTHON
00164     NodeScriptDict *nsd;
00165     PyObject *pydict;
00166     BPy_Node *pynode;
00167 
00168     if (!node->storage) return;
00169     nsd = (NodeScriptDict *)(node->storage);
00170     pydict = nsd->dict;
00171     if (pydict) {
00172         Py_DECREF(pydict);
00173     }
00174     pynode = nsd->node;
00175     if (pynode) {
00176         Py_DECREF(pynode);
00177     }
00178 #endif
00179     MEM_freeN(node->storage);
00180     node->storage = NULL;
00181 }
00182 
00183 /* Disable pynode when its script fails */
00184 static void node_dynamic_disable(bNode *node)
00185 {
00186     node->custom1 = 0;
00187     node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ERROR);
00188 }
00189 
00190 /* Disable all pynodes using the given text (script) id */
00191 static void node_dynamic_disable_all_by_id(ID *id)
00192 {
00193 #ifdef WITH_PYTHON
00194     Material *ma; /* XXX hardcoded for shaders */
00195 
00196     for (ma= G.main->mat.first; ma; ma= ma->id.next) {
00197         if (ma->nodetree) {
00198             bNode *nd;
00199             bNodeTree *ntree = ma->nodetree;
00200             for (nd= ntree->nodes.first; nd; nd= nd->next) {
00201                 if (nd->id == id) {
00202                     nd->custom1 = 0;
00203                     nd->custom1 = BSET(nd->custom1, NODE_DYNAMIC_ERROR);
00204                 }
00205             }
00206         }
00207     }
00208 #endif
00209 }
00210 
00211 static void node_rem_socklist_links(bNodeTree *ntree, ListBase *lb)
00212 {
00213     bNodeLink *link, *next;
00214     bNodeSocket *sock;
00215 
00216     if (!lb) return;
00217 
00218     for (sock= lb->first; sock; sock= sock->next) {
00219         for (link= ntree->links.first; link; link= next) {
00220             next= link->next;
00221             if (link->fromsock==sock || link->tosock==sock) {
00222                 nodeRemLink(ntree, link);
00223             }
00224         }
00225     }
00226 }
00227 
00228 /* XXX hardcoded for shaders */
00229 static void node_dynamic_rem_all_links(bNodeType *tinfo)
00230 {
00231     Material *ma;
00232     int in, out;
00233 
00234     in = tinfo->inputs ? 1 : 0;
00235     out = tinfo->outputs ? 1 : 0;
00236 
00237     if (!in && !out) return;
00238 
00239     for (ma= G.main->mat.first; ma; ma= ma->id.next) {
00240         if (ma->nodetree) {
00241             bNode *nd;
00242             bNodeTree *ntree = ma->nodetree;
00243             for (nd= ntree->nodes.first; nd; nd= nd->next) {
00244                 if (nd->typeinfo == tinfo) {
00245                     if (in)
00246                         node_rem_socklist_links(ntree, &nd->inputs);
00247                     if (out)
00248                         node_rem_socklist_links(ntree, &nd->outputs);
00249                 }
00250             }
00251         }
00252     }
00253 }
00254 
00255 /* node_dynamic_reset: clean a pynode, getting rid of all
00256  * data dynamically created for it. */
00257 static void node_dynamic_reset(bNode *node, int unlink_text)
00258 {
00259     bNodeType *tinfo, *tinfo_default;
00260     Material *ma;
00261 
00262     tinfo = node->typeinfo;
00263     tinfo_default = node_dynamic_find_typeinfo(&node_all_shaders, NULL);
00264 
00265     if ((tinfo == tinfo_default) && unlink_text) {
00266         ID *textID = node->id;
00267     /* already at default (empty) state, which happens if this node's
00268      * script failed to parse at the first stage: definition. We're here
00269      * because its text was removed from Blender. */
00270         for (ma= G.main->mat.first; ma; ma= ma->id.next) {
00271             if (ma->nodetree) {
00272                 bNode *nd;
00273                 for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) {
00274                     if (nd->id == textID) {
00275                         nd->id = NULL;
00276                         nd->custom1 = 0;
00277                         nd->custom1 = BSET(nd->custom1, NODE_DYNAMIC_NEW);
00278                         BLI_strncpy(nd->name, "Dynamic", 8);
00279                         return;
00280                     }
00281                 }
00282             }
00283         }
00284     }
00285 
00286     node_dynamic_rem_all_links(tinfo);
00287     node_dynamic_free_typeinfo_sockets(tinfo);
00288 
00289     /* reset all other XXX shader nodes sharing this typeinfo */
00290     for (ma= G.main->mat.first; ma; ma= ma->id.next) {
00291         if (ma->nodetree) {
00292             bNode *nd;
00293             for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) {
00294                 if (nd->typeinfo == tinfo) {
00295                     node_dynamic_free_storage_cb(nd);
00296                     node_dynamic_free_sockets(nd);
00297                     //node_dynamic_update_socket_links(nd, ma->nodetree);
00298                     nd->typeinfo = tinfo_default;
00299                     if (unlink_text) {
00300                         nd->id = NULL;
00301                         nd->custom1 = 0;
00302                         nd->custom1 = BSET(nd->custom1, NODE_DYNAMIC_NEW);
00303                         BLI_strncpy(nd->name, "Dynamic", 8);
00304                     }
00305                 }
00306             }
00307         }
00308     }
00309 
00310     /* XXX hardcoded for shaders: */
00311     if (tinfo->id) { BLI_remlink(&node_all_shaders, tinfo); }
00312     node_dynamic_free_typeinfo(tinfo);
00313 }
00314 
00315 /* Special case of the above function: for working pynodes
00316  * that were saved on a .blend but fail for some reason when
00317  * the file is opened. We need this because pynodes are initialized
00318  * before G.main. */
00319 static void node_dynamic_reset_loaded(bNode *node)
00320 {
00321     bNodeType *tinfo = node->typeinfo;
00322 
00323     node_dynamic_rem_all_links(tinfo);
00324     node_dynamic_free_typeinfo_sockets(tinfo);
00325     node_dynamic_free_storage_cb(node);
00326     /* XXX hardcoded for shaders: */
00327     if (tinfo->id) { BLI_remlink(&node_all_shaders, tinfo); }
00328 
00329     node_dynamic_free_typeinfo(tinfo);
00330     node->typeinfo = node_dynamic_find_typeinfo(&node_all_shaders, NULL);
00331 }
00332 
00333 int nodeDynamicUnlinkText(ID *txtid)
00334 {
00335     Material *ma;
00336     bNode *nd;
00337 
00338     /* find one node that uses this text */
00339     for (ma= G.main->mat.first; ma; ma= ma->id.next) {
00340         if (ma->nodetree) {
00341             for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) {
00342                 if ((nd->type == NODE_DYNAMIC) && (nd->id == txtid)) {
00343                     node_dynamic_reset(nd, 1); /* found, reset all */
00344                     return 1;
00345                 }
00346             }
00347         }
00348     }
00349     return 0; /* no pynodes used this text */
00350 }
00351 
00352 static void node_dynamic_pyerror_print(bNode *node)
00353 {
00354 #ifdef WITH_PYTHON
00355     PyGILState_STATE gilstate = PyGILState_Ensure();
00356 
00357     fprintf(stderr, "\nError in dynamic node script \"%s\":\n", node->name);
00358     if (PyErr_Occurred()) {
00359         PyErr_Print();
00360         PyErr_Clear();
00361         PySys_SetObject("last_traceback", NULL);
00362     }
00363     else { fprintf(stderr, "Not a valid dynamic node Python script.\n"); }
00364 
00365     PyGILState_Release(gilstate);
00366 #endif
00367 }
00368 
00369 static void node_dynamic_register_type(bNode *node)
00370 {
00371     nodeRegisterType(&node_all_shaders, node->typeinfo);
00372     /* nodeRegisterType copied it to a new one, so we
00373      * free the typeinfo itself, but not what it
00374      * points to: */
00375     MEM_freeN(node->typeinfo);
00376     node->typeinfo = node_dynamic_find_typeinfo(&node_all_shaders, node->id);
00377     MEM_freeN(node->typeinfo->name);
00378     node->typeinfo->name = BLI_strdup(node->name);
00379 }
00380 
00381 #ifdef WITH_PYTHON
00382 /* node_dynamic_get_pynode:
00383  * Find the pynode definition from the script */
00384 static PyObject *node_dynamic_get_pynode(PyObject *dict)
00385 {
00386     PyObject *key= NULL;
00387     Py_ssize_t pos = 0;
00388     PyObject *value = NULL;
00389 
00390     /* script writer specified a node? */
00391     value = PyDict_GetItemString(dict, "__node__");
00392 
00393     if (value) {
00394         if (PyObject_TypeCheck(value, &PyType_Type)) {
00395             Py_INCREF(value);
00396             return value;
00397         }
00398         else {
00399             PyErr_SetString(PyExc_TypeError,
00400                 "expected class object derived from Scripted node");
00401             return NULL;
00402         }
00403     }
00404 
00405     /* case not, search for it in the script's global dictionary */
00406     while (PyDict_Next(dict, &pos, &key, &value)) {
00407         /* skip names we know belong to other available objects */
00408         if (strcmp("Socket", PyString_AsString(key)) == 0)
00409             continue;
00410         else if (strcmp("Scripted", PyString_AsString(key)) == 0)
00411             continue;
00412         /* naive: we grab the first ob of type 'type': */
00413         else if (PyObject_TypeCheck(value, &PyType_Type)) {
00414             Py_INCREF(value);
00415             return value;
00416         }
00417     }
00418 
00419     PyErr_SetString(PyExc_TypeError,
00420         "no PyNode definition found in the script!");
00421     return NULL;
00422 }
00423 #endif /* WITH_PYTHON */
00424 
00425 static int node_dynamic_parse(struct bNode *node)
00426 {
00427 #ifndef WITH_PYTHON
00428     return -1;
00429 #else
00430     PyObject *dict= NULL;
00431     PyObject *pynode_data= NULL;
00432     PyObject *pynode= NULL;
00433     PyObject *args= NULL;
00434     NodeScriptDict *nsd = NULL;
00435     PyObject *pyresult = NULL;
00436     char *buf = NULL;
00437     int is_valid_script = 0;
00438     PyGILState_STATE gilstate;
00439 
00440     if (!node->id || !node->storage)
00441         return 0;
00442 
00443     /* READY, no need to be here */
00444     if (BTST(node->custom1, NODE_DYNAMIC_READY))
00445         return 0;
00446 
00447     /* for threading */
00448     gilstate = PyGILState_Ensure();
00449 
00450     nsd = (NodeScriptDict *)node->storage;
00451 
00452     dict = (PyObject *)(nsd->dict);
00453     buf = txt_to_buf((Text *)node->id);
00454 
00455     pyresult = PyRun_String(buf, Py_file_input, dict, dict);
00456 
00457     MEM_freeN(buf);
00458 
00459     if (!pyresult) {
00460         if (BTST(node->custom1, NODE_DYNAMIC_LOADED)) {
00461             node_dynamic_disable(node);
00462         } else {
00463         node_dynamic_disable_all_by_id(node->id);
00464         }
00465         node_dynamic_pyerror_print(node);
00466         PyGILState_Release(gilstate);
00467         return -1;
00468     }
00469 
00470     Py_DECREF(pyresult);
00471 
00472     pynode_data = node_dynamic_get_pynode(dict);
00473 
00474     if (pynode_data) {
00475         BPy_NodeSocketLists *socklists = Node_CreateSocketLists(node);
00476 
00477         args = Py_BuildValue("(O)", socklists);
00478 
00479         /* init it to get the input and output sockets */
00480         pynode = PyObject_Call(pynode_data, args, NULL);
00481 
00482         Py_DECREF(pynode_data);
00483         Py_DECREF(socklists);
00484         Py_DECREF(args);
00485 
00486         if (!PyErr_Occurred() && pynode && pytype_is_pynode(pynode)) {
00487             InitNode((BPy_Node *)(pynode), node);
00488             nsd->node = pynode;
00489             node->typeinfo->execfunc = node_dynamic_exec_cb;
00490             is_valid_script = 1;
00491 
00492             /* for NEW, LOADED, REPARSE */
00493             if (BNTST(node->custom1, NODE_DYNAMIC_ADDEXIST)) {
00494                 node->typeinfo->pydict = dict;
00495                 node->typeinfo->pynode = pynode;
00496                 node->typeinfo->id = node->id;
00497                 if (BNTST(node->custom1, NODE_DYNAMIC_LOADED))
00498                     nodeAddSockets(node, node->typeinfo);
00499                 if (BNTST(node->custom1, NODE_DYNAMIC_REPARSE))
00500                     node_dynamic_register_type(node);
00501             }
00502 
00503             node->custom1 = 0;
00504             node->custom1 = BSET(node->custom1, NODE_DYNAMIC_READY);
00505         }
00506     }
00507 
00508     PyGILState_Release(gilstate);
00509 
00510     if (!is_valid_script) { /* not a valid pynode script */
00511         node_dynamic_disable_all_by_id(node->id);
00512         node_dynamic_pyerror_print(node);
00513         return -1;
00514     }
00515 
00516     return 0;
00517 #endif
00518 }
00519 
00520 /* node_dynamic_setup: prepare for execution (state: NODE_DYNAMIC_READY)
00521  * pynodes already linked to a script (node->id != NULL). */
00522 static void node_dynamic_setup(bNode *node)
00523 {
00524 #ifdef WITH_PYTHON
00525     NodeScriptDict *nsd = NULL;
00526     bNodeTree *nodetree = NULL;
00527     bNodeType *ntype = NULL;
00528     PyGILState_STATE gilstate;
00529 
00530     /* Possible cases:
00531      * NEW
00532      * ADDEXIST
00533      * LOADED
00534      * REPARSE
00535      * ERROR
00536      * READY
00537      */
00538 
00539     /* NEW, but not linked to a script: link default (empty) typeinfo */
00540     if (!node->id) {
00541         node->typeinfo = node_dynamic_find_typeinfo(&node_all_shaders,
00542                 NULL);
00543         return;
00544     }
00545 
00546     /* READY, no need to be here */
00547     if (BTST(node->custom1, NODE_DYNAMIC_READY))
00548         return;
00549 
00550     gilstate = PyGILState_Ensure();
00551 
00552     /* ERROR, reset to (empty) defaults */
00553     if (BCLR(node->custom1, NODE_DYNAMIC_ERROR) == 0) {
00554         node_dynamic_reset(node, 0);
00555         PyGILState_Release(gilstate);
00556         return;
00557     }
00558 
00559     /* User asked to update this pynode, prepare it for reparsing */
00560     if (BTST(node->custom1, NODE_DYNAMIC_REPARSE)) {
00561         int needs_parsing = 1;
00562 
00563         node->custom1 = BSET(node->custom1, NODE_DYNAMIC_NEW);
00564 
00565         if (BTST(node->custom1, NODE_DYNAMIC_ERROR)) {
00566             node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_REPARSE);
00567             ntype = node_dynamic_find_typeinfo(&node_all_shaders, node->id);
00568 
00569             if (ntype) {
00570                 node->typeinfo = ntype;
00571                 node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ADDEXIST);
00572                 node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_ERROR);
00573                 needs_parsing = 0;
00574             }
00575             else { nodeMakeDynamicType(node); }
00576 
00577         } else {
00578             node_dynamic_rem_all_links(node->typeinfo);
00579             node_dynamic_free_typeinfo_sockets(node->typeinfo);
00580             node_dynamic_update_socket_links(node, NULL);
00581             node_dynamic_free_storage_cb(node);
00582         }
00583 
00584         if (needs_parsing) {
00585             nsd = MEM_callocN(sizeof(NodeScriptDict), "node script dictionary");
00586             nsd->dict = init_dynamicdict();
00587             node->storage = nsd;
00588             /* prepared, now reparse: */
00589             node_dynamic_parse(node);
00590             PyGILState_Release(gilstate);
00591             return;
00592         }
00593     }
00594     else if (BTST(node->custom1, NODE_DYNAMIC_LOADED)) {
00595         /* when loading from a .blend we don't have G.main yet, so we
00596          * quickly abuse node->storage in ntreeInitTypes (node.c) to have
00597          * our nodetree ptr (needed if a pynode script that worked before
00598          * saving the .blend for some reason fails upon loading): */
00599         nodetree = (bNodeTree *)node->storage;
00600         node->storage = NULL;
00601     }
00602 
00603     if (node->storage)
00604         fprintf(stderr, "\nDEBUG: PYNODES ERROR: non NULL node->storage in node_dynamic_setup()\n");
00605 
00606     nsd = MEM_callocN(sizeof(NodeScriptDict), "node script dictionary");
00607     node->storage = nsd;
00608     
00609     /* NEW, LOADED or REPARSE */
00610     if (BNTST(node->custom1, NODE_DYNAMIC_ADDEXIST)) {
00611         /* check if there's already a bNodeType linked to this script */
00612         /* (XXX hardcoded for shader nodes for now) */
00613         ntype = node_dynamic_find_typeinfo(&node_all_shaders, node->id);
00614 
00615         if (ntype) { /* if so, reuse it */
00616             node->typeinfo = ntype;
00617             /* so this is actually an ADDEXIST type */
00618             node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ADDEXIST);
00619         }
00620         else { /* create bNodeType for this pynode */
00621             nodeMakeDynamicType(node);
00622             nsd->dict = init_dynamicdict();
00623             if ((node_dynamic_parse(node) == -1) && nodetree) {
00624                 node_dynamic_reset_loaded(node);
00625             }
00626             PyGILState_Release(gilstate);
00627             return;
00628         }
00629     }
00630 
00631     /* ADDEXIST: new pynode linked to an already registered dynamic type,
00632      * we just reuse existing py dict and pynode */
00633     nsd->dict = node->typeinfo->pydict;
00634     nsd->node = node->typeinfo->pynode;
00635 
00636     Py_INCREF((PyObject *)(nsd->dict));
00637     Py_INCREF((PyObject *)(nsd->node));
00638 
00639     if (BTST(node->custom1, NODE_DYNAMIC_NEW)) {
00640         nodeAddSockets(node, node->typeinfo);
00641         node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_NEW);
00642     }
00643 
00644     node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_ADDEXIST);
00645     node->custom1 = BSET(node->custom1, NODE_DYNAMIC_READY);
00646 
00647     PyGILState_Release(gilstate);
00648 #endif /* WITH_PYTHON */
00649     return;
00650 }
00651 
00652 /* node_dynamic_init_cb callback: called when a pynode is created.
00653  * The pynode type is passed via node->custom2. It can be:
00654  *  0: for loaded empty nodes
00655  *  NODE_DYNAMIC_MENU: for the default Dynamic node type
00656  *  > NODE_DYNAMIC_MENU: for the new types defined by scripts
00657 */
00658 static void node_dynamic_init_cb(bNode *node)
00659 {
00660     int type = node->custom2;
00661 
00662     node->custom2 = 0;
00663 
00664     if (type >= NODE_DYNAMIC_MENU) {
00665         node->custom1 = 0;
00666 
00667         if (type == NODE_DYNAMIC_MENU) {
00668             node->custom1 = BSET(node->custom1, NODE_DYNAMIC_NEW);
00669             return;
00670         }
00671 
00672         node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ADDEXIST);
00673         node->id = node->typeinfo->id;
00674     }
00675 
00676     node_dynamic_setup(node);
00677 }
00678 
00679 /* node_dynamic_copy_cb: pynode copy callback */
00680 static void node_dynamic_copy_cb(bNode *orig_node, bNode *new_node)
00681 {
00682 #ifndef WITH_PYTHON
00683     return;
00684 #else
00685     NodeScriptDict *nsd;
00686     PyGILState_STATE gilstate;
00687 
00688     if (!orig_node->storage) return;
00689 
00690     nsd = (NodeScriptDict *)(orig_node->storage);
00691     new_node->storage = MEM_dupallocN(orig_node->storage);
00692 
00693     gilstate = PyGILState_Ensure();
00694 
00695     if (nsd->node)
00696         Py_INCREF((PyObject *)(nsd->node));
00697     if (nsd->dict)
00698         Py_INCREF((PyObject *)(nsd->dict));
00699 
00700     PyGILState_Release(gilstate);
00701 #endif
00702 }
00703 
00704 /* node_dynamic_exec_cb: the execution callback called per pixel
00705  * during rendering. */
00706 static void node_dynamic_exec_cb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
00707 {
00708 #ifndef WITH_PYTHON
00709     return;
00710 #else
00711     BPy_Node *mynode = NULL;
00712     NodeScriptDict *nsd = NULL;
00713     PyObject *pyresult = NULL;
00714     PyObject *args = NULL;
00715     ShadeInput *shi;
00716     PyGILState_STATE gilstate;
00717 
00718     if (!node->id)
00719         return;
00720 
00721     /*if (G.scene->r.threads > 1)
00722         return;*/
00723 
00724     if (BTST2(node->custom1, NODE_DYNAMIC_NEW, NODE_DYNAMIC_REPARSE)) {
00725         node_dynamic_setup(node);
00726         return;
00727     }
00728 
00729     if (BTST(node->custom1, NODE_DYNAMIC_ERROR)) {
00730         if (node->storage) node_dynamic_setup(node);
00731         return;
00732     }
00733 
00734     if (BTST(node->custom1, NODE_DYNAMIC_READY)) {
00735         nsd = (NodeScriptDict *)node->storage;
00736         mynode = (BPy_Node *)(nsd->node);
00737 
00738 
00739         if (mynode && PyCallable_Check((PyObject *)mynode)) {
00740 
00741             gilstate = PyGILState_Ensure();
00742 
00743             mynode->node = node;
00744             shi = ((ShaderCallData *)data)->shi;
00745 
00746             Node_SetStack(mynode, in, NODE_INPUTSTACK);
00747             Node_SetStack(mynode, out, NODE_OUTPUTSTACK);
00748             Node_SetShi(mynode, shi);
00749 
00750             args=Py_BuildValue("()");
00751             pyresult= PyObject_Call((PyObject *)mynode, args, NULL);
00752             Py_DECREF(args);
00753 
00754             if (!pyresult) {
00755                 PyGILState_Release(gilstate);
00756                 node_dynamic_disable_all_by_id(node->id);
00757                 node_dynamic_pyerror_print(node);
00758                 node_dynamic_setup(node);
00759                 return;
00760             }
00761             Py_DECREF(pyresult);
00762             PyGILState_Release(gilstate);
00763         }
00764     }
00765 #endif
00766 }
00767 
00768 void register_node_type_sh_dynamic(bNodeTreeType *ttype)
00769 {
00770     static bNodeType ntype;
00771     
00772     node_type_base(ttype, &ntype, NODE_DYNAMIC, "Dynamic", NODE_CLASS_OP_DYNAMIC, NODE_OPTIONS, NULL, NULL);
00773     node_type_compatibility(&ntype, NODE_OLD_SHADING);
00774     node_type_size(&ntype, 150, 60, 300);
00775     node_type_init(&ntype, node_dynamic_init_cb);
00776     node_type_storage(&ntype, "NodeScriptDict", node_dynamic_free_storage_cb, node_dynamic_copy_cb);
00777     node_type_exec(&ntype, node_dynamic_exec_cb);
00778     
00779     nodeRegisterType(ttype, &ntype);
00780 }
00781 
00782 #else
00783 
00784 void register_node_type_sh_dynamic(bNodeTreeType *ttype)
00785 {
00786     static bNodeType ntype;
00787     
00788     node_type_base(ttype, &ntype, NODE_DYNAMIC, "Dynamic", NODE_CLASS_OP_DYNAMIC, 0);
00789     node_type_compatibility(&ntype, NODE_OLD_SHADING);
00790     
00791     nodeRegisterType(ttype, &ntype);
00792 }
00793 
00794 #endif