~siretart/ubuntu/utopic/blender/libav10

« back to all changes in this revision

Viewing changes to source/blender/nodes/shader/nodes/node_shader_dynamic.c

  • Committer: Package Import Robot
  • Author(s): Matteo F. Vescovi
  • Date: 2012-07-23 08:54:18 UTC
  • mfrom: (14.2.16 sid)
  • mto: (14.2.19 sid)
  • mto: This revision was merged to the branch mainline in revision 42.
  • Revision ID: package-import@ubuntu.com-20120723085418-9foz30v6afaf5ffs
Tags: 2.63a-2
* debian/: Cycles support added (Closes: #658075)
  For now, this top feature has been enabled only
  on [any-amd64 any-i386] architectures because
  of OpenImageIO failing on all others
* debian/: scripts installation path changed
  from /usr/lib to /usr/share:
  + debian/patches/: patchset re-worked for path changing
  + debian/control: "Breaks" field added on yafaray-exporter

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * ***** BEGIN GPL LICENSE BLOCK *****
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU General Public License
 
6
 * as published by the Free Software Foundation; either version 2
 
7
 * of the License, or (at your option) any later version. 
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software Foundation,
 
16
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
17
 *
 
18
 * The Original Code is Copyright (C) 2007 Blender Foundation.
 
19
 * All rights reserved.
 
20
 *
 
21
 * The Original Code is: all of this file.
 
22
 *
 
23
 * Contributor(s): Nathan Letwory
 
24
 *
 
25
 * ***** END GPL LICENSE BLOCK *****
 
26
 */
 
27
 
 
28
/** \file blender/nodes/shader/nodes/node_shader_dynamic.c
 
29
 *  \ingroup shdnodes
 
30
 */
 
31
 
 
32
 
 
33
/* TODO, support python3.x */
 
34
#undef WITH_PYTHON 
 
35
 
 
36
#ifdef WITH_PYTHON
 
37
#include <Python.h>
 
38
#include <compile.h>
 
39
#include <eval.h>
 
40
#endif
 
41
 
 
42
#include "DNA_text_types.h"
 
43
#include "BKE_text.h"
 
44
 
 
45
 
 
46
// XXX
 
47
#if 0
 
48
#ifdef WITH_PYTHON
 
49
#include "api2_2x/Node.h"
 
50
#include "api2_2x/gen_utils.h"
 
51
#include "BPY_extern.h"
 
52
#endif
 
53
#endif
 
54
 
 
55
#include "node_shader_util.h"
 
56
 
 
57
// XXX
 
58
#if 0
 
59
static void node_dynamic_setup(bNode *node);
 
60
static void node_dynamic_exec_cb(void *data, bNode *node, bNodeStack **in, bNodeStack **out);
 
61
static void node_dynamic_free_storage_cb(bNode *node);
 
62
 
 
63
#ifdef WITH_PYTHON
 
64
static PyObject *init_dynamicdict(void)
 
65
{
 
66
        PyObject *newscriptdict, *item;
 
67
        PyGILState_STATE gilstate = PyGILState_Ensure();
 
68
 
 
69
        newscriptdict= PyDict_New();
 
70
 
 
71
        PyDict_SetItemString(newscriptdict, "__builtins__", PyEval_GetBuiltins());
 
72
        item= PyString_FromString("__main__");
 
73
        PyDict_SetItemString(newscriptdict, "__name__", item);
 
74
        Py_DECREF(item);
 
75
 
 
76
        PyGILState_Release(gilstate);
 
77
 
 
78
        return newscriptdict;
 
79
}
 
80
#endif
 
81
 
 
82
static bNodeType *node_dynamic_find_typeinfo(ListBase *list, ID *id)
 
83
{
 
84
        bNodeType *ntype = list->first;
 
85
 
 
86
        while (ntype) {
 
87
                if (ntype->type == NODE_DYNAMIC && ntype->id == id)
 
88
                        break;
 
89
                ntype = ntype->next;
 
90
        }
 
91
 
 
92
        return ntype; /* NULL if doesn't exist */
 
93
}
 
94
 
 
95
static void node_dynamic_free_typeinfo_sockets(bNodeType *tinfo)
 
96
{
 
97
        bNodeSocketTemplate *sock;
 
98
 
 
99
        if (!tinfo) return;
 
100
 
 
101
        if (tinfo->inputs) {
 
102
                sock = tinfo->inputs;
 
103
                while (sock->type != -1) {
 
104
                        MEM_freeN(sock->name);
 
105
                        sock++;
 
106
                }
 
107
                MEM_freeN(tinfo->inputs);
 
108
                tinfo->inputs = NULL;
 
109
        }
 
110
        if (tinfo->outputs) {
 
111
                sock = tinfo->outputs;
 
112
                while (sock->type != -1) {
 
113
                        MEM_freeN(sock->name);
 
114
                        sock++;
 
115
                }
 
116
                MEM_freeN(tinfo->outputs);
 
117
                tinfo->outputs = NULL;
 
118
        }
 
119
}
 
120
 
 
121
static void node_dynamic_free_typeinfo(bNodeType *tinfo)
 
122
{
 
123
        if (!tinfo) return;
 
124
 
 
125
        node_dynamic_free_typeinfo_sockets(tinfo);
 
126
 
 
127
        if (tinfo->name) { MEM_freeN(tinfo->name); }
 
128
 
 
129
        MEM_freeN(tinfo);
 
130
}
 
131
 
 
132
static void node_dynamic_free_sockets(bNode *node)
 
133
{
 
134
        BLI_freelistN(&node->inputs);
 
135
        BLI_freelistN(&node->outputs);
 
136
}
 
137
 
 
138
/* For now we just remove the socket links. It's the safest
 
139
 * route, since an update in the script may change completely the
 
140
 * inputs and outputs. Trying to recreate the node links would be
 
141
 * nicer for pynode authors, though. */
 
142
static void node_dynamic_update_socket_links(bNode *node, bNodeTree *ntree)
 
143
{
 
144
        if (ntree) {
 
145
                nodeVerifyType(ntree, node);
 
146
        }
 
147
        else {
 
148
                Material *ma;
 
149
 
 
150
                for (ma= G.main->mat.first; ma; ma= ma->id.next) {
 
151
                        if (ma->nodetree) {
 
152
                                bNode *nd;
 
153
                                for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) {
 
154
                                        if (nd == node) nodeVerifyType(ma->nodetree, node);
 
155
                                }
 
156
                        }
 
157
                }
 
158
        }
 
159
}
 
160
 
 
161
static void node_dynamic_free_storage_cb(bNode *node)
 
162
{
 
163
#ifdef WITH_PYTHON
 
164
        NodeScriptDict *nsd;
 
165
        PyObject *pydict;
 
166
        BPy_Node *pynode;
 
167
 
 
168
        if (!node->storage) return;
 
169
        nsd = (NodeScriptDict *)(node->storage);
 
170
        pydict = nsd->dict;
 
171
        if (pydict) {
 
172
                Py_DECREF(pydict);
 
173
        }
 
174
        pynode = nsd->node;
 
175
        if (pynode) {
 
176
                Py_DECREF(pynode);
 
177
        }
 
178
#endif
 
179
        MEM_freeN(node->storage);
 
180
        node->storage = NULL;
 
181
}
 
182
 
 
183
/* Disable pynode when its script fails */
 
184
static void node_dynamic_disable(bNode *node)
 
185
{
 
186
        node->custom1 = 0;
 
187
        node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ERROR);
 
188
}
 
189
 
 
190
/* Disable all pynodes using the given text (script) id */
 
191
static void node_dynamic_disable_all_by_id(ID *id)
 
192
{
 
193
#ifdef WITH_PYTHON
 
194
        Material *ma; /* XXX hardcoded for shaders */
 
195
 
 
196
        for (ma= G.main->mat.first; ma; ma= ma->id.next) {
 
197
                if (ma->nodetree) {
 
198
                        bNode *nd;
 
199
                        bNodeTree *ntree = ma->nodetree;
 
200
                        for (nd= ntree->nodes.first; nd; nd= nd->next) {
 
201
                                if (nd->id == id) {
 
202
                                        nd->custom1 = 0;
 
203
                                        nd->custom1 = BSET(nd->custom1, NODE_DYNAMIC_ERROR);
 
204
                                }
 
205
                        }
 
206
                }
 
207
        }
 
208
#endif
 
209
}
 
210
 
 
211
static void node_rem_socklist_links(bNodeTree *ntree, ListBase *lb)
 
212
{
 
213
        bNodeLink *link, *next;
 
214
        bNodeSocket *sock;
 
215
 
 
216
        if (!lb) return;
 
217
 
 
218
        for (sock= lb->first; sock; sock= sock->next) {
 
219
                for (link= ntree->links.first; link; link= next) {
 
220
                        next= link->next;
 
221
                        if (link->fromsock==sock || link->tosock==sock) {
 
222
                                nodeRemLink(ntree, link);
 
223
                        }
 
224
                }
 
225
        }
 
226
}
 
227
 
 
228
/* XXX hardcoded for shaders */
 
229
static void node_dynamic_rem_all_links(bNodeType *tinfo)
 
230
{
 
231
        Material *ma;
 
232
        int in, out;
 
233
 
 
234
        in = tinfo->inputs ? 1 : 0;
 
235
        out = tinfo->outputs ? 1 : 0;
 
236
 
 
237
        if (!in && !out) return;
 
238
 
 
239
        for (ma= G.main->mat.first; ma; ma= ma->id.next) {
 
240
                if (ma->nodetree) {
 
241
                        bNode *nd;
 
242
                        bNodeTree *ntree = ma->nodetree;
 
243
                        for (nd= ntree->nodes.first; nd; nd= nd->next) {
 
244
                                if (nd->typeinfo == tinfo) {
 
245
                                        if (in)
 
246
                                                node_rem_socklist_links(ntree, &nd->inputs);
 
247
                                        if (out)
 
248
                                                node_rem_socklist_links(ntree, &nd->outputs);
 
249
                                }
 
250
                        }
 
251
                }
 
252
        }
 
253
}
 
254
 
 
255
/* node_dynamic_reset: clean a pynode, getting rid of all
 
256
 * data dynamically created for it. */
 
257
static void node_dynamic_reset(bNode *node, int unlink_text)
 
258
{
 
259
        bNodeType *tinfo, *tinfo_default;
 
260
        Material *ma;
 
261
 
 
262
        tinfo = node->typeinfo;
 
263
        tinfo_default = node_dynamic_find_typeinfo(&node_all_shaders, NULL);
 
264
 
 
265
        if ((tinfo == tinfo_default) && unlink_text) {
 
266
                ID *textID = node->id;
 
267
        /* already at default (empty) state, which happens if this node's
 
268
         * script failed to parse at the first stage: definition. We're here
 
269
         * because its text was removed from Blender. */
 
270
                for (ma= G.main->mat.first; ma; ma= ma->id.next) {
 
271
                        if (ma->nodetree) {
 
272
                                bNode *nd;
 
273
                                for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) {
 
274
                                        if (nd->id == textID) {
 
275
                                                nd->id = NULL;
 
276
                                                nd->custom1 = 0;
 
277
                                                nd->custom1 = BSET(nd->custom1, NODE_DYNAMIC_NEW);
 
278
                                                BLI_strncpy(nd->name, "Dynamic", 8);
 
279
                                                return;
 
280
                                        }
 
281
                                }
 
282
                        }
 
283
                }
 
284
        }
 
285
 
 
286
        node_dynamic_rem_all_links(tinfo);
 
287
        node_dynamic_free_typeinfo_sockets(tinfo);
 
288
 
 
289
        /* reset all other XXX shader nodes sharing this typeinfo */
 
290
        for (ma= G.main->mat.first; ma; ma= ma->id.next) {
 
291
                if (ma->nodetree) {
 
292
                        bNode *nd;
 
293
                        for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) {
 
294
                                if (nd->typeinfo == tinfo) {
 
295
                                        node_dynamic_free_storage_cb(nd);
 
296
                                        node_dynamic_free_sockets(nd);
 
297
                                        //node_dynamic_update_socket_links(nd, ma->nodetree);
 
298
                                        nd->typeinfo = tinfo_default;
 
299
                                        if (unlink_text) {
 
300
                                                nd->id = NULL;
 
301
                                                nd->custom1 = 0;
 
302
                                                nd->custom1 = BSET(nd->custom1, NODE_DYNAMIC_NEW);
 
303
                                                BLI_strncpy(nd->name, "Dynamic", 8);
 
304
                                        }
 
305
                                }
 
306
                        }
 
307
                }
 
308
        }
 
309
 
 
310
        /* XXX hardcoded for shaders: */
 
311
        if (tinfo->id) { BLI_remlink(&node_all_shaders, tinfo); }
 
312
        node_dynamic_free_typeinfo(tinfo);
 
313
}
 
314
 
 
315
/* Special case of the above function: for working pynodes
 
316
 * that were saved on a .blend but fail for some reason when
 
317
 * the file is opened. We need this because pynodes are initialized
 
318
 * before G.main. */
 
319
static void node_dynamic_reset_loaded(bNode *node)
 
320
{
 
321
        bNodeType *tinfo = node->typeinfo;
 
322
 
 
323
        node_dynamic_rem_all_links(tinfo);
 
324
        node_dynamic_free_typeinfo_sockets(tinfo);
 
325
        node_dynamic_free_storage_cb(node);
 
326
        /* XXX hardcoded for shaders: */
 
327
        if (tinfo->id) { BLI_remlink(&node_all_shaders, tinfo); }
 
328
 
 
329
        node_dynamic_free_typeinfo(tinfo);
 
330
        node->typeinfo = node_dynamic_find_typeinfo(&node_all_shaders, NULL);
 
331
}
 
332
 
 
333
int nodeDynamicUnlinkText(ID *txtid)
 
334
{
 
335
        Material *ma;
 
336
        bNode *nd;
 
337
 
 
338
        /* find one node that uses this text */
 
339
        for (ma= G.main->mat.first; ma; ma= ma->id.next) {
 
340
                if (ma->nodetree) {
 
341
                        for (nd= ma->nodetree->nodes.first; nd; nd = nd->next) {
 
342
                                if ((nd->type == NODE_DYNAMIC) && (nd->id == txtid)) {
 
343
                                        node_dynamic_reset(nd, 1); /* found, reset all */
 
344
                                        return 1;
 
345
                                }
 
346
                        }
 
347
                }
 
348
        }
 
349
        return 0; /* no pynodes used this text */
 
350
}
 
351
 
 
352
static void node_dynamic_pyerror_print(bNode *node)
 
353
{
 
354
#ifdef WITH_PYTHON
 
355
        PyGILState_STATE gilstate = PyGILState_Ensure();
 
356
 
 
357
        fprintf(stderr, "\nError in dynamic node script \"%s\":\n", node->name);
 
358
        if (PyErr_Occurred()) {
 
359
                PyErr_Print();
 
360
                PyErr_Clear();
 
361
                PySys_SetObject("last_traceback", NULL);
 
362
        }
 
363
        else { fprintf(stderr, "Not a valid dynamic node Python script.\n"); }
 
364
 
 
365
        PyGILState_Release(gilstate);
 
366
#endif
 
367
}
 
368
 
 
369
static void node_dynamic_register_type(bNode *node)
 
370
{
 
371
        nodeRegisterType(&node_all_shaders, node->typeinfo);
 
372
        /* nodeRegisterType copied it to a new one, so we
 
373
         * free the typeinfo itself, but not what it
 
374
         * points to: */
 
375
        MEM_freeN(node->typeinfo);
 
376
        node->typeinfo = node_dynamic_find_typeinfo(&node_all_shaders, node->id);
 
377
        MEM_freeN(node->typeinfo->name);
 
378
        node->typeinfo->name = BLI_strdup(node->name);
 
379
}
 
380
 
 
381
#ifdef WITH_PYTHON
 
382
/* node_dynamic_get_pynode:
 
383
 * Find the pynode definition from the script */
 
384
static PyObject *node_dynamic_get_pynode(PyObject *dict)
 
385
{
 
386
        PyObject *key= NULL;
 
387
        Py_ssize_t pos = 0;
 
388
        PyObject *value = NULL;
 
389
 
 
390
        /* script writer specified a node? */
 
391
        value = PyDict_GetItemString(dict, "__node__");
 
392
 
 
393
        if (value) {
 
394
                if (PyObject_TypeCheck(value, &PyType_Type)) {
 
395
                        Py_INCREF(value);
 
396
                        return value;
 
397
                }
 
398
                else {
 
399
                        PyErr_SetString(PyExc_TypeError,
 
400
                                "expected class object derived from Scripted node");
 
401
                        return NULL;
 
402
                }
 
403
        }
 
404
 
 
405
        /* case not, search for it in the script's global dictionary */
 
406
        while (PyDict_Next(dict, &pos, &key, &value)) {
 
407
                /* skip names we know belong to other available objects */
 
408
                if (strcmp("Socket", PyString_AsString(key)) == 0)
 
409
                        continue;
 
410
                else if (strcmp("Scripted", PyString_AsString(key)) == 0)
 
411
                        continue;
 
412
                /* naive: we grab the first ob of type 'type': */
 
413
                else if (PyObject_TypeCheck(value, &PyType_Type)) {
 
414
                        Py_INCREF(value);
 
415
                        return value;
 
416
                }
 
417
        }
 
418
 
 
419
        PyErr_SetString(PyExc_TypeError,
 
420
                "no PyNode definition found in the script!");
 
421
        return NULL;
 
422
}
 
423
#endif /* WITH_PYTHON */
 
424
 
 
425
static int node_dynamic_parse(struct bNode *node)
 
426
{
 
427
#ifndef WITH_PYTHON
 
428
        return -1;
 
429
#else
 
430
        PyObject *dict= NULL;
 
431
        PyObject *pynode_data= NULL;
 
432
        PyObject *pynode= NULL;
 
433
        PyObject *args= NULL;
 
434
        NodeScriptDict *nsd = NULL;
 
435
        PyObject *pyresult = NULL;
 
436
        char *buf = NULL;
 
437
        int is_valid_script = 0;
 
438
        PyGILState_STATE gilstate;
 
439
 
 
440
        if (!node->id || !node->storage)
 
441
                return 0;
 
442
 
 
443
        /* READY, no need to be here */
 
444
        if (BTST(node->custom1, NODE_DYNAMIC_READY))
 
445
                return 0;
 
446
 
 
447
        /* for threading */
 
448
        gilstate = PyGILState_Ensure();
 
449
 
 
450
        nsd = (NodeScriptDict *)node->storage;
 
451
 
 
452
        dict = (PyObject *)(nsd->dict);
 
453
        buf = txt_to_buf((Text *)node->id);
 
454
 
 
455
        pyresult = PyRun_String(buf, Py_file_input, dict, dict);
 
456
 
 
457
        MEM_freeN(buf);
 
458
 
 
459
        if (!pyresult) {
 
460
                if (BTST(node->custom1, NODE_DYNAMIC_LOADED)) {
 
461
                        node_dynamic_disable(node);
 
462
                }
 
463
                else {
 
464
                node_dynamic_disable_all_by_id(node->id);
 
465
                }
 
466
                node_dynamic_pyerror_print(node);
 
467
                PyGILState_Release(gilstate);
 
468
                return -1;
 
469
        }
 
470
 
 
471
        Py_DECREF(pyresult);
 
472
 
 
473
        pynode_data = node_dynamic_get_pynode(dict);
 
474
 
 
475
        if (pynode_data) {
 
476
                BPy_NodeSocketLists *socklists = Node_CreateSocketLists(node);
 
477
 
 
478
                args = Py_BuildValue("(O)", socklists);
 
479
 
 
480
                /* init it to get the input and output sockets */
 
481
                pynode = PyObject_Call(pynode_data, args, NULL);
 
482
 
 
483
                Py_DECREF(pynode_data);
 
484
                Py_DECREF(socklists);
 
485
                Py_DECREF(args);
 
486
 
 
487
                if (!PyErr_Occurred() && pynode && pytype_is_pynode(pynode)) {
 
488
                        InitNode((BPy_Node *)(pynode), node);
 
489
                        nsd->node = pynode;
 
490
                        node->typeinfo->execfunc = node_dynamic_exec_cb;
 
491
                        is_valid_script = 1;
 
492
 
 
493
                        /* for NEW, LOADED, REPARSE */
 
494
                        if (BNTST(node->custom1, NODE_DYNAMIC_ADDEXIST)) {
 
495
                                node->typeinfo->pydict = dict;
 
496
                                node->typeinfo->pynode = pynode;
 
497
                                node->typeinfo->id = node->id;
 
498
                                if (BNTST(node->custom1, NODE_DYNAMIC_LOADED))
 
499
                                        nodeAddSockets(node, node->typeinfo);
 
500
                                if (BNTST(node->custom1, NODE_DYNAMIC_REPARSE))
 
501
                                        node_dynamic_register_type(node);
 
502
                        }
 
503
 
 
504
                        node->custom1 = 0;
 
505
                        node->custom1 = BSET(node->custom1, NODE_DYNAMIC_READY);
 
506
                }
 
507
        }
 
508
 
 
509
        PyGILState_Release(gilstate);
 
510
 
 
511
        if (!is_valid_script) { /* not a valid pynode script */
 
512
                node_dynamic_disable_all_by_id(node->id);
 
513
                node_dynamic_pyerror_print(node);
 
514
                return -1;
 
515
        }
 
516
 
 
517
        return 0;
 
518
#endif
 
519
}
 
520
 
 
521
/* node_dynamic_setup: prepare for execution (state: NODE_DYNAMIC_READY)
 
522
 * pynodes already linked to a script (node->id != NULL). */
 
523
static void node_dynamic_setup(bNode *node)
 
524
{
 
525
#ifdef WITH_PYTHON
 
526
        NodeScriptDict *nsd = NULL;
 
527
        bNodeTree *nodetree = NULL;
 
528
        bNodeType *ntype = NULL;
 
529
        PyGILState_STATE gilstate;
 
530
 
 
531
        /* Possible cases:
 
532
         * NEW
 
533
         * ADDEXIST
 
534
         * LOADED
 
535
         * REPARSE
 
536
         * ERROR
 
537
         * READY
 
538
         */
 
539
 
 
540
        /* NEW, but not linked to a script: link default (empty) typeinfo */
 
541
        if (!node->id) {
 
542
                node->typeinfo = node_dynamic_find_typeinfo(&node_all_shaders,
 
543
                                NULL);
 
544
                return;
 
545
        }
 
546
 
 
547
        /* READY, no need to be here */
 
548
        if (BTST(node->custom1, NODE_DYNAMIC_READY))
 
549
                return;
 
550
 
 
551
        gilstate = PyGILState_Ensure();
 
552
 
 
553
        /* ERROR, reset to (empty) defaults */
 
554
        if (BCLR(node->custom1, NODE_DYNAMIC_ERROR) == 0) {
 
555
                node_dynamic_reset(node, 0);
 
556
                PyGILState_Release(gilstate);
 
557
                return;
 
558
        }
 
559
 
 
560
        /* User asked to update this pynode, prepare it for reparsing */
 
561
        if (BTST(node->custom1, NODE_DYNAMIC_REPARSE)) {
 
562
                int needs_parsing = 1;
 
563
 
 
564
                node->custom1 = BSET(node->custom1, NODE_DYNAMIC_NEW);
 
565
 
 
566
                if (BTST(node->custom1, NODE_DYNAMIC_ERROR)) {
 
567
                        node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_REPARSE);
 
568
                        ntype = node_dynamic_find_typeinfo(&node_all_shaders, node->id);
 
569
 
 
570
                        if (ntype) {
 
571
                                node->typeinfo = ntype;
 
572
                                node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ADDEXIST);
 
573
                                node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_ERROR);
 
574
                                needs_parsing = 0;
 
575
                        }
 
576
                        else { nodeMakeDynamicType(node); }
 
577
 
 
578
                }
 
579
                else {
 
580
                        node_dynamic_rem_all_links(node->typeinfo);
 
581
                        node_dynamic_free_typeinfo_sockets(node->typeinfo);
 
582
                        node_dynamic_update_socket_links(node, NULL);
 
583
                        node_dynamic_free_storage_cb(node);
 
584
                }
 
585
 
 
586
                if (needs_parsing) {
 
587
                        nsd = MEM_callocN(sizeof(NodeScriptDict), "node script dictionary");
 
588
                        nsd->dict = init_dynamicdict();
 
589
                        node->storage = nsd;
 
590
                        /* prepared, now reparse: */
 
591
                        node_dynamic_parse(node);
 
592
                        PyGILState_Release(gilstate);
 
593
                        return;
 
594
                }
 
595
        }
 
596
        else if (BTST(node->custom1, NODE_DYNAMIC_LOADED)) {
 
597
                /* when loading from a .blend we don't have G.main yet, so we
 
598
                 * quickly abuse node->storage in ntreeInitTypes (node.c) to have
 
599
                 * our nodetree ptr (needed if a pynode script that worked before
 
600
                 * saving the .blend for some reason fails upon loading): */
 
601
                nodetree = (bNodeTree *)node->storage;
 
602
                node->storage = NULL;
 
603
        }
 
604
 
 
605
        if (node->storage)
 
606
                fprintf(stderr, "\nDEBUG: PYNODES ERROR: non NULL node->storage in node_dynamic_setup()\n");
 
607
 
 
608
        nsd = MEM_callocN(sizeof(NodeScriptDict), "node script dictionary");
 
609
        node->storage = nsd;
 
610
        
 
611
        /* NEW, LOADED or REPARSE */
 
612
        if (BNTST(node->custom1, NODE_DYNAMIC_ADDEXIST)) {
 
613
                /* check if there's already a bNodeType linked to this script */
 
614
                /* (XXX hardcoded for shader nodes for now) */
 
615
                ntype = node_dynamic_find_typeinfo(&node_all_shaders, node->id);
 
616
 
 
617
                if (ntype) { /* if so, reuse it */
 
618
                        node->typeinfo = ntype;
 
619
                        /* so this is actually an ADDEXIST type */
 
620
                        node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ADDEXIST);
 
621
                }
 
622
                else { /* create bNodeType for this pynode */
 
623
                        nodeMakeDynamicType(node);
 
624
                        nsd->dict = init_dynamicdict();
 
625
                        if ((node_dynamic_parse(node) == -1) && nodetree) {
 
626
                                node_dynamic_reset_loaded(node);
 
627
                        }
 
628
                        PyGILState_Release(gilstate);
 
629
                        return;
 
630
                }
 
631
        }
 
632
 
 
633
        /* ADDEXIST: new pynode linked to an already registered dynamic type,
 
634
         * we just reuse existing py dict and pynode */
 
635
        nsd->dict = node->typeinfo->pydict;
 
636
        nsd->node = node->typeinfo->pynode;
 
637
 
 
638
        Py_INCREF((PyObject *)(nsd->dict));
 
639
        Py_INCREF((PyObject *)(nsd->node));
 
640
 
 
641
        if (BTST(node->custom1, NODE_DYNAMIC_NEW)) {
 
642
                nodeAddSockets(node, node->typeinfo);
 
643
                node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_NEW);
 
644
        }
 
645
 
 
646
        node->custom1 = BCLR(node->custom1, NODE_DYNAMIC_ADDEXIST);
 
647
        node->custom1 = BSET(node->custom1, NODE_DYNAMIC_READY);
 
648
 
 
649
        PyGILState_Release(gilstate);
 
650
#endif /* WITH_PYTHON */
 
651
        return;
 
652
}
 
653
 
 
654
/* node_dynamic_init_cb callback: called when a pynode is created.
 
655
 * The pynode type is passed via node->custom2. It can be:
 
656
 *  0: for loaded empty nodes
 
657
 *  NODE_DYNAMIC_MENU: for the default Dynamic node type
 
658
 *  > NODE_DYNAMIC_MENU: for the new types defined by scripts
 
659
 */
 
660
static void node_dynamic_init_cb(bNode *node)
 
661
{
 
662
        int type = node->custom2;
 
663
 
 
664
        node->custom2 = 0;
 
665
 
 
666
        if (type >= NODE_DYNAMIC_MENU) {
 
667
                node->custom1 = 0;
 
668
 
 
669
                if (type == NODE_DYNAMIC_MENU) {
 
670
                        node->custom1 = BSET(node->custom1, NODE_DYNAMIC_NEW);
 
671
                        return;
 
672
                }
 
673
 
 
674
                node->custom1 = BSET(node->custom1, NODE_DYNAMIC_ADDEXIST);
 
675
                node->id = node->typeinfo->id;
 
676
        }
 
677
 
 
678
        node_dynamic_setup(node);
 
679
}
 
680
 
 
681
/* node_dynamic_copy_cb: pynode copy callback */
 
682
static void node_dynamic_copy_cb(bNode *orig_node, bNode *new_node)
 
683
{
 
684
#ifndef WITH_PYTHON
 
685
        return;
 
686
#else
 
687
        NodeScriptDict *nsd;
 
688
        PyGILState_STATE gilstate;
 
689
 
 
690
        if (!orig_node->storage) return;
 
691
 
 
692
        nsd = (NodeScriptDict *)(orig_node->storage);
 
693
        new_node->storage = MEM_dupallocN(orig_node->storage);
 
694
 
 
695
        gilstate = PyGILState_Ensure();
 
696
 
 
697
        if (nsd->node)
 
698
                Py_INCREF((PyObject *)(nsd->node));
 
699
        if (nsd->dict)
 
700
                Py_INCREF((PyObject *)(nsd->dict));
 
701
 
 
702
        PyGILState_Release(gilstate);
 
703
#endif
 
704
}
 
705
 
 
706
/* node_dynamic_exec_cb: the execution callback called per pixel
 
707
 * during rendering. */
 
708
static void node_dynamic_exec_cb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
 
709
{
 
710
#ifndef WITH_PYTHON
 
711
        return;
 
712
#else
 
713
        BPy_Node *mynode = NULL;
 
714
        NodeScriptDict *nsd = NULL;
 
715
        PyObject *pyresult = NULL;
 
716
        PyObject *args = NULL;
 
717
        ShadeInput *shi;
 
718
        PyGILState_STATE gilstate;
 
719
 
 
720
        if (!node->id)
 
721
                return;
 
722
 
 
723
#if 0
 
724
        if (G.scene->r.threads > 1)
 
725
                return;
 
726
#endif
 
727
 
 
728
        if (BTST2(node->custom1, NODE_DYNAMIC_NEW, NODE_DYNAMIC_REPARSE)) {
 
729
                node_dynamic_setup(node);
 
730
                return;
 
731
        }
 
732
 
 
733
        if (BTST(node->custom1, NODE_DYNAMIC_ERROR)) {
 
734
                if (node->storage) node_dynamic_setup(node);
 
735
                return;
 
736
        }
 
737
 
 
738
        if (BTST(node->custom1, NODE_DYNAMIC_READY)) {
 
739
                nsd = (NodeScriptDict *)node->storage;
 
740
                mynode = (BPy_Node *)(nsd->node);
 
741
 
 
742
 
 
743
                if (mynode && PyCallable_Check((PyObject *)mynode)) {
 
744
 
 
745
                        gilstate = PyGILState_Ensure();
 
746
 
 
747
                        mynode->node = node;
 
748
                        shi = ((ShaderCallData *)data)->shi;
 
749
 
 
750
                        Node_SetStack(mynode, in, NODE_INPUTSTACK);
 
751
                        Node_SetStack(mynode, out, NODE_OUTPUTSTACK);
 
752
                        Node_SetShi(mynode, shi);
 
753
 
 
754
                        args=Py_BuildValue("()");
 
755
                        pyresult= PyObject_Call((PyObject *)mynode, args, NULL);
 
756
                        Py_DECREF(args);
 
757
 
 
758
                        if (!pyresult) {
 
759
                                PyGILState_Release(gilstate);
 
760
                                node_dynamic_disable_all_by_id(node->id);
 
761
                                node_dynamic_pyerror_print(node);
 
762
                                node_dynamic_setup(node);
 
763
                                return;
 
764
                        }
 
765
                        Py_DECREF(pyresult);
 
766
                        PyGILState_Release(gilstate);
 
767
                }
 
768
        }
 
769
#endif
 
770
}
 
771
 
 
772
void register_node_type_sh_dynamic(bNodeTreeType *ttype)
 
773
{
 
774
        static bNodeType ntype;
 
775
        
 
776
        node_type_base(ttype, &ntype, NODE_DYNAMIC, "Dynamic", NODE_CLASS_OP_DYNAMIC, NODE_OPTIONS, NULL, NULL);
 
777
        node_type_compatibility(&ntype, NODE_OLD_SHADING);
 
778
        node_type_size(&ntype, 150, 60, 300);
 
779
        node_type_init(&ntype, node_dynamic_init_cb);
 
780
        node_type_storage(&ntype, "NodeScriptDict", node_dynamic_free_storage_cb, node_dynamic_copy_cb);
 
781
        node_type_exec(&ntype, node_dynamic_exec_cb);
 
782
        
 
783
        nodeRegisterType(ttype, &ntype);
 
784
}
 
785
 
 
786
#else
 
787
 
 
788
void register_node_type_sh_dynamic(bNodeTreeType *ttype)
 
789
{
 
790
        static bNodeType ntype;
 
791
        
 
792
        node_type_base(ttype, &ntype, NODE_DYNAMIC, "Dynamic", NODE_CLASS_OP_DYNAMIC, 0);
 
793
        node_type_compatibility(&ntype, NODE_OLD_SHADING);
 
794
        
 
795
        nodeRegisterType(ttype, &ntype);
 
796
}
 
797
 
 
798
#endif