Committing patch "[#27676] Change window size/resolution in realtime" by me.
[blender-staging.git] / source / blender / python / intern / bpy_driver.c
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  * Contributor(s): Willian P. Germano, Campbell Barton
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/python/intern/bpy_driver.c
24  *  \ingroup pythonintern
25  *
26  * This file defines the 'BPY_driver_exec' to execute python driver expressions,
27  * called by the animation system, there are also some utility functions
28  * to deal with the namespace used for driver execution.
29  */
30
31 /* ****************************************** */
32 /* Drivers - PyExpression Evaluation */
33
34 #include <Python.h>
35
36 #include "DNA_anim_types.h"
37
38 #include "BLI_listbase.h"
39 #include "BLI_math_base.h"
40
41 #include "BKE_fcurve.h"
42 #include "BKE_global.h"
43
44 #include "bpy_driver.h"
45
46 extern void BPY_update_rna_module(void);
47
48
49 /* for pydrivers (drivers using one-line Python expressions to express relationships between targets) */
50 PyObject *bpy_pydriver_Dict = NULL;
51
52 /* For faster execution we keep a special dictionary for pydrivers, with
53  * the needed modules and aliases.
54  */
55 int bpy_pydriver_create_dict(void)
56 {
57         PyObject *d, *mod;
58
59         /* validate namespace for driver evaluation */
60         if (bpy_pydriver_Dict) return -1;
61
62         d = PyDict_New();
63         if (d == NULL)
64                 return -1;
65         else
66                 bpy_pydriver_Dict = d;
67
68         /* import some modules: builtins, bpy, math, (Blender.noise)*/
69         PyDict_SetItemString(d, "__builtins__", PyEval_GetBuiltins());
70
71         mod = PyImport_ImportModule("math");
72         if (mod) {
73                 PyDict_Merge(d, PyModule_GetDict(mod), 0); /* 0 - dont overwrite existing values */
74                 Py_DECREF(mod);
75         }
76
77         /* add bpy to global namespace */
78         mod = PyImport_ImportModuleLevel((char *)"bpy", NULL, NULL, NULL, 0);
79         if (mod) {
80                 PyDict_SetItemString(bpy_pydriver_Dict, "bpy", mod);
81                 Py_DECREF(mod);
82         }
83
84         /* add noise to global namespace */
85         mod = PyImport_ImportModuleLevel((char *)"mathutils", NULL, NULL, NULL, 0);
86         if (mod) {
87                 PyObject *modsub = PyDict_GetItemString(PyModule_GetDict(mod), "noise");
88                 PyDict_SetItemString(bpy_pydriver_Dict, "noise", modsub);
89                 Py_DECREF(mod);
90         }
91
92         return 0;
93 }
94
95 /* note, this function should do nothing most runs, only when changing frame */
96 static PyObject *bpy_pydriver_InternStr__frame = NULL;
97 /* not thread safe but neither is python */
98 static float bpy_pydriver_evaltime_prev = FLT_MAX;
99
100 static void bpy_pydriver_update_dict(const float evaltime)
101 {
102         if (bpy_pydriver_evaltime_prev != evaltime) {
103
104                 /* currently only update the frame */
105                 if (bpy_pydriver_InternStr__frame == NULL) {
106                         bpy_pydriver_InternStr__frame = PyUnicode_FromString("frame");
107                 }
108
109                 PyDict_SetItem(bpy_pydriver_Dict,
110                                bpy_pydriver_InternStr__frame,
111                                PyFloat_FromDouble(evaltime));
112
113                 bpy_pydriver_evaltime_prev = evaltime;
114         }
115 }
116
117 /* Update function, it gets rid of pydrivers global dictionary, forcing
118  * BPY_driver_exec to recreate it. This function is used to force
119  * reloading the Blender text module "pydrivers.py", if available, so
120  * updates in it reach pydriver evaluation.
121  */
122 void BPY_driver_reset(void)
123 {
124         PyGILState_STATE gilstate;
125         int use_gil = 1; /* !PYC_INTERPRETER_ACTIVE; */
126
127         if (use_gil)
128                 gilstate = PyGILState_Ensure();
129
130         if (bpy_pydriver_Dict) { /* free the global dict used by pydrivers */
131                 PyDict_Clear(bpy_pydriver_Dict);
132                 Py_DECREF(bpy_pydriver_Dict);
133                 bpy_pydriver_Dict = NULL;
134         }
135
136         if (bpy_pydriver_InternStr__frame) {
137                 Py_DECREF(bpy_pydriver_InternStr__frame);
138                 bpy_pydriver_InternStr__frame = NULL;
139                 bpy_pydriver_evaltime_prev = FLT_MAX;
140         }
141
142         if (use_gil)
143                 PyGILState_Release(gilstate);
144
145         return;
146 }
147
148 /* error return function for BPY_eval_pydriver */
149 static void pydriver_error(ChannelDriver *driver)
150 {
151         driver->flag |= DRIVER_FLAG_INVALID; /* py expression failed */
152         fprintf(stderr, "\nError in Driver: The following Python expression failed:\n\t'%s'\n\n", driver->expression);
153
154         // BPy_errors_to_report(NULL); // TODO - reports
155         PyErr_Print();
156         PyErr_Clear();
157 }
158
159 /* This evals py driver expressions, 'expr' is a Python expression that
160  * should evaluate to a float number, which is returned.
161  *
162  * (old)note: PyGILState_Ensure() isnt always called because python can call
163  * the bake operator which intern starts a thread which calls scene update
164  * which does a driver update. to avoid a deadlock check PYC_INTERPRETER_ACTIVE
165  * if PyGILState_Ensure() is needed - see [#27683]
166  *
167  * (new)note: checking if python is running is not threadsafe [#28114]
168  * now release the GIL on python operator execution instead, using
169  * PyEval_SaveThread() / PyEval_RestoreThread() so we dont lock up blender.
170  */
171 float BPY_driver_exec(ChannelDriver *driver, const float evaltime)
172 {
173         PyObject *driver_vars = NULL;
174         PyObject *retval = NULL;
175         PyObject *expr_vars; /* speed up by pre-hashing string & avoids re-converting unicode strings for every execution */
176         PyObject *expr_code;
177         PyGILState_STATE gilstate;
178         int use_gil;
179
180         DriverVar *dvar;
181         double result = 0.0; /* default return */
182         char *expr = NULL;
183         short targets_ok = 1;
184         int i;
185
186         /* get the py expression to be evaluated */
187         expr = driver->expression;
188         if ((expr == NULL) || (expr[0] == '\0'))
189                 return 0.0f;
190
191         if (!(G.f & G_SCRIPT_AUTOEXEC)) {
192                 printf("skipping driver '%s', automatic scripts are disabled\n", driver->expression);
193                 return 0.0f;
194         }
195
196         use_gil = 1; /* !PYC_INTERPRETER_ACTIVE; */
197
198         if (use_gil)
199                 gilstate = PyGILState_Ensure();
200
201         /* needed since drivers are updated directly after undo where 'main' is
202          * re-allocated [#28807] */
203         BPY_update_rna_module();
204
205         /* init global dictionary for py-driver evaluation settings */
206         if (!bpy_pydriver_Dict) {
207                 if (bpy_pydriver_create_dict() != 0) {
208                         fprintf(stderr, "Pydriver error: couldn't create Python dictionary");
209                         if (use_gil)
210                                 PyGILState_Release(gilstate);
211                         return 0.0f;
212                 }
213         }
214
215         /* update global namespace */
216         bpy_pydriver_update_dict(evaltime);
217
218
219         if (driver->expr_comp == NULL)
220                 driver->flag |= DRIVER_FLAG_RECOMPILE;
221
222         /* compile the expression first if it hasn't been compiled or needs to be rebuilt */
223         if (driver->flag & DRIVER_FLAG_RECOMPILE) {
224                 Py_XDECREF(driver->expr_comp);
225                 driver->expr_comp = PyTuple_New(2);
226
227                 expr_code = Py_CompileString(expr, "<bpy driver>", Py_eval_input);
228                 PyTuple_SET_ITEM(((PyObject *)driver->expr_comp), 0, expr_code);
229
230                 driver->flag &= ~DRIVER_FLAG_RECOMPILE;
231                 driver->flag |= DRIVER_FLAG_RENAMEVAR; /* maybe this can be removed but for now best keep until were sure */
232         }
233         else {
234                 expr_code = PyTuple_GET_ITEM(((PyObject *)driver->expr_comp), 0);
235         }
236
237         if (driver->flag & DRIVER_FLAG_RENAMEVAR) {
238                 /* may not be set */
239                 expr_vars = PyTuple_GET_ITEM(((PyObject *)driver->expr_comp), 1);
240                 Py_XDECREF(expr_vars);
241
242                 expr_vars = PyTuple_New(BLI_countlist(&driver->variables));
243                 PyTuple_SET_ITEM(((PyObject *)driver->expr_comp), 1, expr_vars);
244
245                 for (dvar = driver->variables.first, i = 0; dvar; dvar = dvar->next) {
246                         PyTuple_SET_ITEM(expr_vars, i++, PyUnicode_FromString(dvar->name));
247                 }
248                 
249                 driver->flag &= ~DRIVER_FLAG_RENAMEVAR;
250         }
251         else {
252                 expr_vars = PyTuple_GET_ITEM(((PyObject *)driver->expr_comp), 1);
253         }
254
255         /* add target values to a dict that will be used as '__locals__' dict */
256         driver_vars = PyDict_New(); // XXX do we need to decref this?
257         for (dvar = driver->variables.first, i = 0; dvar; dvar = dvar->next) {
258                 PyObject *driver_arg = NULL;
259                 float tval = 0.0f;
260                 
261                 /* try to get variable value */
262                 tval = driver_get_variable_value(driver, dvar);
263                 driver_arg = PyFloat_FromDouble((double)tval);
264                 
265                 /* try to add to dictionary */
266                 /* if (PyDict_SetItemString(driver_vars, dvar->name, driver_arg)) { */
267                 if (PyDict_SetItem(driver_vars, PyTuple_GET_ITEM(expr_vars, i++), driver_arg) < 0) {
268                         /* this target failed - bad name */
269                         if (targets_ok) {
270                                 /* first one - print some extra info for easier identification */
271                                 fprintf(stderr, "\nBPY_driver_eval() - Error while evaluating PyDriver:\n");
272                                 targets_ok = 0;
273                         }
274                         
275                         fprintf(stderr, "\tBPY_driver_eval() - couldn't add variable '%s' to namespace\n", dvar->name);
276                         // BPy_errors_to_report(NULL); // TODO - reports
277                         PyErr_Print();
278                         PyErr_Clear();
279                 }
280         }
281
282
283 #if 0 // slow, with this can avoid all Py_CompileString above.
284         /* execute expression to get a value */
285         retval = PyRun_String(expr, Py_eval_input, bpy_pydriver_Dict, driver_vars);
286 #else
287         /* evaluate the compiled expression */
288         if (expr_code)
289                 retval = PyEval_EvalCode((void *)expr_code, bpy_pydriver_Dict, driver_vars);
290 #endif
291
292         /* decref the driver vars first...  */
293         Py_DECREF(driver_vars);
294
295         /* process the result */
296         if (retval == NULL) {
297                 pydriver_error(driver);
298         }
299         else if ((result = PyFloat_AsDouble(retval)) == -1.0 && PyErr_Occurred()) {
300                 pydriver_error(driver);
301                 Py_DECREF(retval);
302                 result = 0.0;
303         }
304         else {
305                 /* all fine, make sure the "invalid expression" flag is cleared */
306                 driver->flag &= ~DRIVER_FLAG_INVALID;
307                 Py_DECREF(retval);
308         }
309
310         if (use_gil)
311                 PyGILState_Release(gilstate);
312
313         if (finite(result)) {
314                 return (float)result;
315         }
316         else {
317                 fprintf(stderr, "\tBPY_driver_eval() - driver '%s' evaluates to '%f'\n", dvar->name, result);
318                 return 0.0f;
319         }
320 }