From 3a4f23aa78b5152c1adc253f48b6a591da0cf8f9 Mon Sep 17 00:00:00 2001 From: Willian Padovani Germano Date: Fri, 25 Apr 2008 16:35:52 +0000 Subject: == PyNodes == 1) Added support for a var called "__node__" in pynode scripts, that can be used to point to the desired pynode object, to make sure it is chosen. 2) Fixed a semi-obscure crash that could happen when reparsing a pynode script that was used by multiple nodes in different scenes. Memory corruption would happen if the reparsing failed during the recreation of the pynode object, not when executing it. --- .../blender/nodes/intern/SHD_nodes/SHD_dynamic.c | 136 ++++++++++++++------- 1 file changed, 90 insertions(+), 46 deletions(-) (limited to 'source/blender/nodes') diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c b/source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c index 36a3bd5b171..37bbb68ba03 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c @@ -160,11 +160,11 @@ static void node_dynamic_free_storage_cb(bNode *node) } /* Disable pynode when its script fails */ -static void node_dynamic_disable(bNode *node) +/*static void node_dynamic_disable(bNode *node) { node->custom1 = 0; node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ERROR); -} +}*/ /* Disable all pynodes using the given text (script) id */ static void node_dynamic_disable_all_by_id(ID *id) @@ -211,6 +211,8 @@ static void node_dynamic_rem_all_links(bNodeType *tinfo) in = tinfo->inputs ? 1 : 0; out = tinfo->outputs ? 1 : 0; + if (!in && !out) return; + for (ma= G.main->mat.first; ma; ma= ma->id.next) { if (ma->nodetree) { bNode *nd; @@ -248,6 +250,7 @@ static void node_dynamic_reset(bNode *node, int unlink_text) if (nd->typeinfo == tinfo) { node_dynamic_free_storage_cb(nd); node_dynamic_free_sockets(nd); + //node_dynamic_update_socket_links(nd, ma->nodetree); nd->typeinfo = tinfo_default; if (unlink_text) { nd->id = NULL; @@ -312,17 +315,69 @@ static void node_dynamic_pyerror_print(bNode *node) PyGILState_Release(gilstate); } +static void node_dynamic_register_type(bNode *node) +{ + nodeRegisterType(&node_all_shaders, node->typeinfo); + /* nodeRegisterType copied it to a new one, so we + * free the typeinfo itself, but not what it + * points to: */ + MEM_freeN(node->typeinfo); + node->typeinfo = node_dynamic_find_typeinfo(&node_all_shaders, node->id); + MEM_freeN(node->typeinfo->name); + node->typeinfo->name = BLI_strdup(node->name); +} + +/* node_dynamic_get_pynode: + * Find the pynode definition from the script */ +static PyObject *node_dynamic_get_pynode(PyObject *dict) +{ + PyObject *key= NULL; + Py_ssize_t pos = 0; + PyObject *value = NULL; + + /* script writer specified a node? */ + value = PyDict_GetItemString(dict, "__node__"); + + if (value) { + if (PyObject_TypeCheck(value, &PyType_Type)) { + Py_INCREF(value); + return value; + } + else { + PyErr_SetString(PyExc_TypeError, + "expected class object derived from Scripted node"); + return NULL; + } + } + + /* case not, search for it in the script's global dictionary */ + while (PyDict_Next(dict, &pos, &key, &value)) { + /* skip names we know belong to other available objects */ + if (strcmp("Socket", PyString_AsString(key)) == 0) + continue; + else if (strcmp("Scripted", PyString_AsString(key)) == 0) + continue; + /* naive: we grab the first ob of type 'type': */ + else if (PyObject_TypeCheck(value, &PyType_Type)) { + Py_INCREF(value); + return value; + } + } + + PyErr_SetString(PyExc_TypeError, + "no PyNode definition found in the script!"); + return NULL; +} + static int node_dynamic_parse(struct bNode *node) { PyObject *dict= NULL; - PyObject *key= NULL; - PyObject *value= NULL; + PyObject *pynode_data= NULL; PyObject *pynode= NULL; PyObject *args= NULL; NodeScriptDict *nsd = NULL; PyObject *pyresult = NULL; char *buf = NULL; - Py_ssize_t pos = 0; int is_valid_script = 0; PyGILState_STATE gilstate; @@ -346,7 +401,7 @@ static int node_dynamic_parse(struct bNode *node) MEM_freeN(buf); if (!pyresult) { - node_dynamic_disable(node); + node_dynamic_disable_all_by_id(node->id); node_dynamic_pyerror_print(node); PyGILState_Release(gilstate); return -1; @@ -354,58 +409,46 @@ static int node_dynamic_parse(struct bNode *node) Py_DECREF(pyresult); - while (PyDict_Next( (PyObject *)(nsd->dict), &pos, &key, &value)) { - /* look for the node object */ - if (strcmp("Socket", PyString_AsString(key)) == 0) - continue; /* XXX ugly, fix it */ - if (PyObject_TypeCheck(value, &PyType_Type)==1) { - BPy_NodeSocketLists *socklists = Node_CreateSocketLists(node); + pynode_data = node_dynamic_get_pynode(dict); - args = Py_BuildValue("(O)", socklists); + if (pynode_data) { + BPy_NodeSocketLists *socklists = Node_CreateSocketLists(node); - /* init it to get the input and output sockets */ - pynode = PyObject_Call(value, args, NULL); + args = Py_BuildValue("(O)", socklists); - Py_DECREF(socklists); - Py_DECREF(args); + /* init it to get the input and output sockets */ + pynode = PyObject_Call(pynode_data, args, NULL); - if (!PyErr_Occurred() && pynode && pytype_is_pynode(pynode)) { - InitNode((BPy_Node *)(pynode), node); - nsd->node = pynode; - node->typeinfo->execfunc = node_dynamic_exec_cb; - is_valid_script = 1; - - /* for NEW, LOADED, REPARSE */ - if (BNTST(node->custom1, NODE_DYNAMIC_ADDEXIST)) { - node->typeinfo->pydict = dict; - node->typeinfo->pynode = pynode; - node->typeinfo->id = node->id; - if (BNTST(node->custom1, NODE_DYNAMIC_LOADED)) - nodeAddSockets(node, node->typeinfo); - if (BNTST(node->custom1, NODE_DYNAMIC_REPARSE)) { - nodeRegisterType(&node_all_shaders, node->typeinfo); - /* nodeRegisterType copied it to a new one, so we - * free the typeinfo itself, but not what it - * points to: */ - MEM_freeN(node->typeinfo); - node->typeinfo = node_dynamic_find_typeinfo(&node_all_shaders, node->id); - MEM_freeN(node->typeinfo->name); - node->typeinfo->name = BLI_strdup(node->name); - } - } + Py_DECREF(pynode_data); + Py_DECREF(socklists); + Py_DECREF(args); + + if (!PyErr_Occurred() && pynode && pytype_is_pynode(pynode)) { + InitNode((BPy_Node *)(pynode), node); + nsd->node = pynode; + node->typeinfo->execfunc = node_dynamic_exec_cb; + is_valid_script = 1; - node->custom1 = 0; - node->custom1 = BSET(node->custom1, NODE_DYNAMIC_READY); - break; + /* for NEW, LOADED, REPARSE */ + if (BNTST(node->custom1, NODE_DYNAMIC_ADDEXIST)) { + node->typeinfo->pydict = dict; + node->typeinfo->pynode = pynode; + node->typeinfo->id = node->id; + if (BNTST(node->custom1, NODE_DYNAMIC_LOADED)) + nodeAddSockets(node, node->typeinfo); + if (BNTST(node->custom1, NODE_DYNAMIC_REPARSE)) + node_dynamic_register_type(node); } - //break; + + node->custom1 = 0; + node->custom1 = BSET(node->custom1, NODE_DYNAMIC_READY); } } PyGILState_Release(gilstate); if (!is_valid_script) { /* not a valid pynode script */ - node_dynamic_disable(node); + node_dynamic_disable_all_by_id(node->id); node_dynamic_pyerror_print(node); return -1; } @@ -470,6 +513,7 @@ static void node_dynamic_setup(bNode *node) else { nodeMakeDynamicType(node); } } else { + node_dynamic_rem_all_links(node->typeinfo); node_dynamic_free_typeinfo_sockets(node->typeinfo); node_dynamic_update_socket_links(node, NULL); node_dynamic_free_storage_cb(node); -- cgit v1.2.3