Blender  V2.59
SHD_dynamic.c
Go to the documentation of this file.
00001 /*
00002  * $Id: SHD_dynamic.c 35237 2011-02-27 20:13:22Z jesterking $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version. 
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2007 Blender Foundation.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  *
00025  * Contributor(s): Nathan Letwory
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  */
00029 
00035 /* TODO, support python3.x */
00036 #undef WITH_PYTHON 
00037 
00038 #ifdef WITH_PYTHON
00039 #include <Python.h>
00040 #include <compile.h>
00041 #include <eval.h>
00042 #endif
00043 
00044 #include "DNA_text_types.h"
00045 #include "BKE_text.h"
00046 
00047 
00048 // XXX
00049 #if 0
00050 #ifdef WITH_PYTHON
00051 #include "api2_2x/Node.h"
00052 #include "api2_2x/gen_utils.h"
00053 #include "BPY_extern.h"
00054 #endif
00055 #endif
00056 
00057 #include "../SHD_util.h"
00058 
00059 // XXX
00060 #if 0
00061 static void node_dynamic_setup(bNode *node);
00062 static void node_dynamic_exec_cb(void *data, bNode *node, bNodeStack **in, bNodeStack **out);
00063 static void node_dynamic_free_storage_cb(bNode *node);
00064 
00065 #ifdef WITH_PYTHON
00066 static PyObject *init_dynamicdict(void) {
00067         PyObject *newscriptdict, *item;
00068         PyGILState_STATE gilstate = PyGILState_Ensure();
00069 
00070         newscriptdict= PyDict_New();
00071 
00072         PyDict_SetItemString(newscriptdict, "__builtins__", PyEval_GetBuiltins());
00073         item= PyString_FromString("__main__");
00074         PyDict_SetItemString(newscriptdict, "__name__", item);
00075         Py_DECREF(item);
00076 
00077         PyGILState_Release(gilstate);
00078 
00079         return newscriptdict;
00080 }
00081 #endif
00082 
00083 static bNodeType *node_dynamic_find_typeinfo(ListBase *list, ID *id)
00084 {
00085         bNodeType *ntype = list->first;
00086 
00087         while(ntype) {
00088                 if (ntype->type == NODE_DYNAMIC && ntype->id == id)
00089                         break;
00090                 ntype = ntype->next;
00091         }
00092 
00093         return ntype; /* NULL if doesn't exist */
00094 }
00095 
00096 static void node_dynamic_free_typeinfo_sockets(bNodeType *tinfo)
00097 {
00098         bNodeSocketType *sock;
00099 
00100         if (!tinfo) return;
00101 
00102         if (tinfo->inputs) {
00103                 sock = tinfo->inputs;
00104                 while (sock->type != -1) {
00105                         MEM_freeN(sock->name);
00106                         sock++;
00107                 }
00108                 MEM_freeN(tinfo->inputs);
00109                 tinfo->inputs = NULL;
00110         }
00111         if (tinfo->outputs) {
00112                 sock = tinfo->outputs;
00113                 while (sock->type != -1) {
00114                         MEM_freeN(sock->name);
00115                         sock++;
00116                 }
00117                 MEM_freeN(tinfo->outputs);
00118                 tinfo->outputs = NULL;
00119         }
00120 }
00121 
00122 static void node_dynamic_free_typeinfo(bNodeType *tinfo)
00123 {
00124         if (!tinfo) return;
00125 
00126         node_dynamic_free_typeinfo_sockets(tinfo);
00127 
00128         if (tinfo->name) { MEM_freeN(tinfo->name); }
00129 
00130         MEM_freeN(tinfo);
00131 }
00132 
00133 static void node_dynamic_free_sockets(bNode *node)
00134 {
00135         BLI_freelistN(&node->inputs);
00136         BLI_freelistN(&node->outputs);
00137 }
00138 
00139 /* For now we just remove the socket links. It's the safest
00140  * route, since an update in the script may change completely the
00141  * inputs and outputs. Trying to recreate the node links would be
00142  * nicer for pynode authors, though. */
00143 static void node_dynamic_update_socket_links(bNode *node, bNodeTree *ntree)
00144 {
00145         if (ntree) {
00146                 nodeVerifyType(ntree, node);
00147         }
00148         else {
00149                 Material *ma;
00150 
00151                 for (ma= G.main->mat.first; ma; ma= ma->id.next) {
00152                         if (ma->nodetree) {
00153                                 bNode *nd;
00154                                 for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) {
00155                                         if (nd == node) nodeVerifyType(ma->nodetree, node);
00156                                 }
00157                         }
00158                 }
00159         }
00160 }
00161 
00162 static void node_dynamic_free_storage_cb(bNode *node)
00163 {
00164 #ifdef WITH_PYTHON
00165         NodeScriptDict *nsd;
00166         PyObject *pydict;
00167         BPy_Node *pynode;
00168 
00169         if (!node->storage) return;
00170         nsd = (NodeScriptDict *)(node->storage);
00171         pydict = nsd->dict;
00172         if (pydict) {
00173                 Py_DECREF(pydict);
00174         }
00175         pynode = nsd->node;
00176         if (pynode) {
00177                 Py_DECREF(pynode);
00178         }
00179 #endif
00180         MEM_freeN(node->storage);
00181         node->storage = NULL;
00182 }
00183 
00184 /* Disable pynode when its script fails */
00185 static void node_dynamic_disable(bNode *node)
00186 {
00187         node->custom1 = 0;
00188         node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ERROR);
00189 }
00190 
00191 /* Disable all pynodes using the given text (script) id */
00192 static void node_dynamic_disable_all_by_id(ID *id)
00193 {
00194 #ifdef WITH_PYTHON
00195         Material *ma; /* XXX hardcoded for shaders */
00196 
00197         for (ma= G.main->mat.first; ma; ma= ma->id.next) {
00198                 if (ma->nodetree) {
00199                         bNode *nd;
00200                         bNodeTree *ntree = ma->nodetree;
00201                         for (nd= ntree->nodes.first; nd; nd= nd->next) {
00202                                 if (nd->id == id) {
00203                                         nd->custom1 = 0;
00204                                         nd->custom1 = BSET(nd->custom1, NODE_DYNAMIC_ERROR);
00205                                 }
00206                         }
00207                 }
00208         }
00209 #endif
00210 }
00211 
00212 static void node_rem_socklist_links(bNodeTree *ntree, ListBase *lb)
00213 {
00214         bNodeLink *link, *next;
00215         bNodeSocket *sock;
00216 
00217         if (!lb) return;
00218 
00219         for (sock= lb->first; sock; sock= sock->next) {
00220                 for (link= ntree->links.first; link; link= next) {
00221                         next= link->next;
00222                         if (link->fromsock==sock || link->tosock==sock) {
00223                                 nodeRemLink(ntree, link);
00224                         }
00225                 }
00226         }
00227 }
00228 
00229 /* XXX hardcoded for shaders */
00230 static void node_dynamic_rem_all_links(bNodeType *tinfo)
00231 {
00232         Material *ma;
00233         int in, out;
00234 
00235         in = tinfo->inputs ? 1 : 0;
00236         out = tinfo->outputs ? 1 : 0;
00237 
00238         if (!in && !out) return;
00239 
00240         for (ma= G.main->mat.first; ma; ma= ma->id.next) {
00241                 if (ma->nodetree) {
00242                         bNode *nd;
00243                         bNodeTree *ntree = ma->nodetree;
00244                         for (nd= ntree->nodes.first; nd; nd= nd->next) {
00245                                 if (nd->typeinfo == tinfo) {
00246                                         if (in)
00247                                                 node_rem_socklist_links(ntree, &nd->inputs);
00248                                         if (out)
00249                                                 node_rem_socklist_links(ntree, &nd->outputs);
00250                                 }
00251                         }
00252                 }
00253         }
00254 }
00255 
00256 /* node_dynamic_reset: clean a pynode, getting rid of all
00257  * data dynamically created for it. */
00258 static void node_dynamic_reset(bNode *node, int unlink_text)
00259 {
00260         bNodeType *tinfo, *tinfo_default;
00261         Material *ma;
00262 
00263         tinfo = node->typeinfo;
00264         tinfo_default = node_dynamic_find_typeinfo(&node_all_shaders, NULL);
00265 
00266         if ((tinfo == tinfo_default) && unlink_text) {
00267                 ID *textID = node->id;
00268         /* already at default (empty) state, which happens if this node's
00269          * script failed to parse at the first stage: definition. We're here
00270          * because its text was removed from Blender. */
00271                 for (ma= G.main->mat.first; ma; ma= ma->id.next) {
00272                         if (ma->nodetree) {
00273                                 bNode *nd;
00274                                 for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) {
00275                                         if (nd->id == textID) {
00276                                                 nd->id = NULL;
00277                                                 nd->custom1 = 0;
00278                                                 nd->custom1 = BSET(nd->custom1, NODE_DYNAMIC_NEW);
00279                                                 BLI_strncpy(nd->name, "Dynamic", 8);
00280                                                 return;
00281                                         }
00282                                 }
00283                         }
00284                 }
00285         }
00286 
00287         node_dynamic_rem_all_links(tinfo);
00288         node_dynamic_free_typeinfo_sockets(tinfo);
00289 
00290         /* reset all other XXX shader nodes sharing this typeinfo */
00291         for (ma= G.main->mat.first; ma; ma= ma->id.next) {
00292                 if (ma->nodetree) {
00293                         bNode *nd;
00294                         for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) {
00295                                 if (nd->typeinfo == tinfo) {
00296                                         node_dynamic_free_storage_cb(nd);
00297                                         node_dynamic_free_sockets(nd);
00298                                         //node_dynamic_update_socket_links(nd, ma->nodetree);
00299                                         nd->typeinfo = tinfo_default;
00300                                         if (unlink_text) {
00301                                                 nd->id = NULL;
00302                                                 nd->custom1 = 0;
00303                                                 nd->custom1 = BSET(nd->custom1, NODE_DYNAMIC_NEW);
00304                                                 BLI_strncpy(nd->name, "Dynamic", 8);
00305                                         }
00306                                 }
00307                         }
00308                 }
00309         }
00310 
00311         /* XXX hardcoded for shaders: */
00312         if (tinfo->id) { BLI_remlink(&node_all_shaders, tinfo); }
00313         node_dynamic_free_typeinfo(tinfo);
00314 }
00315 
00316 /* Special case of the above function: for working pynodes
00317  * that were saved on a .blend but fail for some reason when
00318  * the file is opened. We need this because pynodes are initialized
00319  * before G.main. */
00320 static void node_dynamic_reset_loaded(bNode *node)
00321 {
00322         bNodeType *tinfo = node->typeinfo;
00323 
00324         node_dynamic_rem_all_links(tinfo);
00325         node_dynamic_free_typeinfo_sockets(tinfo);
00326         node_dynamic_free_storage_cb(node);
00327         /* XXX hardcoded for shaders: */
00328         if (tinfo->id) { BLI_remlink(&node_all_shaders, tinfo); }
00329 
00330         node_dynamic_free_typeinfo(tinfo);
00331         node->typeinfo = node_dynamic_find_typeinfo(&node_all_shaders, NULL);
00332 }
00333 
00334 int nodeDynamicUnlinkText(ID *txtid) {
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         int type = node->custom2;
00660 
00661         node->custom2 = 0;
00662 
00663         if (type >= NODE_DYNAMIC_MENU) {
00664                 node->custom1 = 0;
00665 
00666                 if (type == NODE_DYNAMIC_MENU) {
00667                         node->custom1 = BSET(node->custom1, NODE_DYNAMIC_NEW);
00668                         return;
00669                 }
00670 
00671                 node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ADDEXIST);
00672                 node->id = node->typeinfo->id;
00673         }
00674 
00675         node_dynamic_setup(node);
00676 }
00677 
00678 /* node_dynamic_copy_cb: pynode copy callback */
00679 static void node_dynamic_copy_cb(bNode *orig_node, bNode *new_node)
00680 {
00681 #ifndef WITH_PYTHON
00682         return;
00683 #else
00684         NodeScriptDict *nsd;
00685         PyGILState_STATE gilstate;
00686 
00687         if (!orig_node->storage) return;
00688 
00689         nsd = (NodeScriptDict *)(orig_node->storage);
00690         new_node->storage = MEM_dupallocN(orig_node->storage);
00691 
00692         gilstate = PyGILState_Ensure();
00693 
00694         if (nsd->node)
00695                 Py_INCREF((PyObject *)(nsd->node));
00696         if (nsd->dict)
00697                 Py_INCREF((PyObject *)(nsd->dict));
00698 
00699         PyGILState_Release(gilstate);
00700 #endif
00701 }
00702 
00703 /* node_dynamic_exec_cb: the execution callback called per pixel
00704  * during rendering. */
00705 static void node_dynamic_exec_cb(void *data, bNode *node, bNodeStack **in, bNodeStack **out) {
00706 #ifndef WITH_PYTHON
00707         return;
00708 #else
00709         BPy_Node *mynode = NULL;
00710         NodeScriptDict *nsd = NULL;
00711         PyObject *pyresult = NULL;
00712         PyObject *args = NULL;
00713         ShadeInput *shi;
00714         PyGILState_STATE gilstate;
00715 
00716         if (!node->id)
00717                 return;
00718 
00719         /*if (G.scene->r.threads > 1)
00720                 return;*/
00721 
00722         if (BTST2(node->custom1, NODE_DYNAMIC_NEW, NODE_DYNAMIC_REPARSE)) {
00723                 node_dynamic_setup(node);
00724                 return;
00725         }
00726 
00727         if (BTST(node->custom1, NODE_DYNAMIC_ERROR)) {
00728                 if (node->storage) node_dynamic_setup(node);
00729                 return;
00730         }
00731 
00732         if (BTST(node->custom1, NODE_DYNAMIC_READY)) {
00733                 nsd = (NodeScriptDict *)node->storage;
00734                 mynode = (BPy_Node *)(nsd->node);
00735 
00736 
00737                 if (mynode && PyCallable_Check((PyObject *)mynode)) {
00738 
00739                         gilstate = PyGILState_Ensure();
00740 
00741                         mynode->node = node;
00742                         shi = ((ShaderCallData *)data)->shi;
00743 
00744                         Node_SetStack(mynode, in, NODE_INPUTSTACK);
00745                         Node_SetStack(mynode, out, NODE_OUTPUTSTACK);
00746                         Node_SetShi(mynode, shi);
00747 
00748                         args=Py_BuildValue("()");
00749                         pyresult= PyObject_Call((PyObject *)mynode, args, NULL);
00750                         Py_DECREF(args);
00751 
00752                         if (!pyresult) {
00753                                 PyGILState_Release(gilstate);
00754                                 node_dynamic_disable_all_by_id(node->id);
00755                                 node_dynamic_pyerror_print(node);
00756                                 node_dynamic_setup(node);
00757                                 return;
00758                         }
00759                         Py_DECREF(pyresult);
00760                         PyGILState_Release(gilstate);
00761                 }
00762         }
00763 #endif
00764 }
00765 
00766 void register_node_type_sh_dynamic(ListBase *lb)
00767 {
00768         static bNodeType ntype;
00769         
00770         node_type_base(&ntype, NODE_DYNAMIC, "Dynamic", NODE_CLASS_OP_DYNAMIC, NODE_OPTIONS, NULL, NULL);
00771         node_type_size(&ntype, 150, 60, 300);
00772         node_type_init(&ntype, node_dynamic_init_cb);
00773         node_type_storage(&ntype, "NodeScriptDict", node_dynamic_free_storage_cb, node_dynamic_copy_cb);
00774         node_type_exec(&ntype, node_dynamic_exec_cb);
00775         
00776         nodeRegisterType(lb, &ntype);
00777 }
00778 
00779 #else
00780 
00781 void register_node_type_sh_dynamic(ListBase *lb)
00782 {
00783         static bNodeType ntype;
00784         
00785         node_type_base(&ntype, NODE_DYNAMIC, "Dynamic", NODE_CLASS_OP_DYNAMIC, 0, NULL, NULL);
00786         
00787         nodeRegisterType(lb, &ntype);
00788 }
00789 
00790 #endif
00791 
00792