2022-02-11 09:07:11 +11:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
2011-02-27 20:10:08 +00:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup pythonintern
|
2011-11-05 08:21:12 +00:00
|
|
|
*
|
2011-11-05 08:40:07 +00:00
|
|
|
* This file defines the 'BPY_driver_exec' to execute python driver expressions,
|
2011-11-05 08:21:12 +00:00
|
|
|
* called by the animation system, there are also some utility functions
|
2022-03-15 15:17:55 +11:00
|
|
|
* to deal with the name-space used for driver execution.
|
2011-02-27 20:10:08 +00:00
|
|
|
*/
|
|
|
|
|
|
2010-04-24 10:08:07 +00:00
|
|
|
#include <Python.h>
|
|
|
|
|
|
2009-12-08 22:35:03 +00:00
|
|
|
#include "DNA_anim_types.h"
|
|
|
|
|
|
2010-01-05 10:54:54 +00:00
|
|
|
#include "BLI_listbase.h"
|
2010-03-15 18:52:22 +00:00
|
|
|
#include "BLI_math_base.h"
|
2019-03-26 03:57:39 +01:00
|
|
|
#include "BLI_string.h"
|
2010-01-05 10:54:54 +00:00
|
|
|
|
T77086 Animation: Passing Dependency Graph to Drivers
Custom driver functions need access to the dependency graph that is
triggering the evaluation of the driver. This patch passes the
dependency graph pointer through all the animation-related calls.
Instead of passing the evaluation time to functions, the code now passes
an `AnimationEvalContext` pointer:
```
typedef struct AnimationEvalContext {
struct Depsgraph *const depsgraph;
const float eval_time;
} AnimationEvalContext;
```
These structs are read-only, meaning that the code cannot change the
evaluation time. Note that the `depsgraph` pointer itself is const, but
it points to a non-const depsgraph.
FCurves and Drivers can be evaluated at a different time than the
current scene time, for example when evaluating NLA strips. This means
that, even though the current time is stored in the dependency graph, we
need an explicit evaluation time.
There are two functions that allow creation of `AnimationEvalContext`
objects:
- `BKE_animsys_eval_context_construct(Depsgraph *depsgraph, float
eval_time)`, which creates a new context object from scratch, and
- `BKE_animsys_eval_context_construct_at(AnimationEvalContext
*anim_eval_context, float eval_time)`, which can be used to create a
`AnimationEvalContext` with the same depsgraph, but at a different
time. This makes it possible to later add fields without changing any
of the code that just want to change the eval time.
This also provides a fix for T75553, although it does require a change
to the custom driver function. The driver should call
`custom_function(depsgraph)`, and the function should use that depsgraph
instead of information from `bpy.context`.
Reviewed By: brecht, sergey
Differential Revision: https://developer.blender.org/D8047
2020-07-17 17:38:09 +02:00
|
|
|
#include "BKE_animsys.h"
|
2020-05-01 12:43:12 +02:00
|
|
|
#include "BKE_fcurve_driver.h"
|
2010-02-27 01:27:22 +00:00
|
|
|
#include "BKE_global.h"
|
2022-07-07 12:30:47 +10:00
|
|
|
#include "BKE_idtype.h"
|
2009-12-08 22:35:03 +00:00
|
|
|
|
T77086 Animation: Passing Dependency Graph to Drivers
Custom driver functions need access to the dependency graph that is
triggering the evaluation of the driver. This patch passes the
dependency graph pointer through all the animation-related calls.
Instead of passing the evaluation time to functions, the code now passes
an `AnimationEvalContext` pointer:
```
typedef struct AnimationEvalContext {
struct Depsgraph *const depsgraph;
const float eval_time;
} AnimationEvalContext;
```
These structs are read-only, meaning that the code cannot change the
evaluation time. Note that the `depsgraph` pointer itself is const, but
it points to a non-const depsgraph.
FCurves and Drivers can be evaluated at a different time than the
current scene time, for example when evaluating NLA strips. This means
that, even though the current time is stored in the dependency graph, we
need an explicit evaluation time.
There are two functions that allow creation of `AnimationEvalContext`
objects:
- `BKE_animsys_eval_context_construct(Depsgraph *depsgraph, float
eval_time)`, which creates a new context object from scratch, and
- `BKE_animsys_eval_context_construct_at(AnimationEvalContext
*anim_eval_context, float eval_time)`, which can be used to create a
`AnimationEvalContext` with the same depsgraph, but at a different
time. This makes it possible to later add fields without changing any
of the code that just want to change the eval time.
This also provides a fix for T75553, although it does require a change
to the custom driver function. The driver should call
`custom_function(depsgraph)`, and the function should use that depsgraph
instead of information from `bpy.context`.
Reviewed By: brecht, sergey
Differential Revision: https://developer.blender.org/D8047
2020-07-17 17:38:09 +02:00
|
|
|
#include "RNA_access.h"
|
2022-03-14 16:54:46 +01:00
|
|
|
#include "RNA_prototypes.h"
|
T77086 Animation: Passing Dependency Graph to Drivers
Custom driver functions need access to the dependency graph that is
triggering the evaluation of the driver. This patch passes the
dependency graph pointer through all the animation-related calls.
Instead of passing the evaluation time to functions, the code now passes
an `AnimationEvalContext` pointer:
```
typedef struct AnimationEvalContext {
struct Depsgraph *const depsgraph;
const float eval_time;
} AnimationEvalContext;
```
These structs are read-only, meaning that the code cannot change the
evaluation time. Note that the `depsgraph` pointer itself is const, but
it points to a non-const depsgraph.
FCurves and Drivers can be evaluated at a different time than the
current scene time, for example when evaluating NLA strips. This means
that, even though the current time is stored in the dependency graph, we
need an explicit evaluation time.
There are two functions that allow creation of `AnimationEvalContext`
objects:
- `BKE_animsys_eval_context_construct(Depsgraph *depsgraph, float
eval_time)`, which creates a new context object from scratch, and
- `BKE_animsys_eval_context_construct_at(AnimationEvalContext
*anim_eval_context, float eval_time)`, which can be used to create a
`AnimationEvalContext` with the same depsgraph, but at a different
time. This makes it possible to later add fields without changing any
of the code that just want to change the eval time.
This also provides a fix for T75553, although it does require a change
to the custom driver function. The driver should call
`custom_function(depsgraph)`, and the function should use that depsgraph
instead of information from `bpy.context`.
Reviewed By: brecht, sergey
Differential Revision: https://developer.blender.org/D8047
2020-07-17 17:38:09 +02:00
|
|
|
#include "RNA_types.h"
|
|
|
|
|
|
2022-03-15 15:17:55 +11:00
|
|
|
#include "bpy_rna_driver.h" /* For #pyrna_driver_get_variable_value. */
|
2016-04-05 07:02:43 +10:00
|
|
|
|
2016-07-31 11:22:02 +10:00
|
|
|
#include "bpy_intern_string.h"
|
|
|
|
|
|
2011-02-14 18:20:10 +00:00
|
|
|
#include "bpy_driver.h"
|
T77086 Animation: Passing Dependency Graph to Drivers
Custom driver functions need access to the dependency graph that is
triggering the evaluation of the driver. This patch passes the
dependency graph pointer through all the animation-related calls.
Instead of passing the evaluation time to functions, the code now passes
an `AnimationEvalContext` pointer:
```
typedef struct AnimationEvalContext {
struct Depsgraph *const depsgraph;
const float eval_time;
} AnimationEvalContext;
```
These structs are read-only, meaning that the code cannot change the
evaluation time. Note that the `depsgraph` pointer itself is const, but
it points to a non-const depsgraph.
FCurves and Drivers can be evaluated at a different time than the
current scene time, for example when evaluating NLA strips. This means
that, even though the current time is stored in the dependency graph, we
need an explicit evaluation time.
There are two functions that allow creation of `AnimationEvalContext`
objects:
- `BKE_animsys_eval_context_construct(Depsgraph *depsgraph, float
eval_time)`, which creates a new context object from scratch, and
- `BKE_animsys_eval_context_construct_at(AnimationEvalContext
*anim_eval_context, float eval_time)`, which can be used to create a
`AnimationEvalContext` with the same depsgraph, but at a different
time. This makes it possible to later add fields without changing any
of the code that just want to change the eval time.
This also provides a fix for T75553, although it does require a change
to the custom driver function. The driver should call
`custom_function(depsgraph)`, and the function should use that depsgraph
instead of information from `bpy.context`.
Reviewed By: brecht, sergey
Differential Revision: https://developer.blender.org/D8047
2020-07-17 17:38:09 +02:00
|
|
|
#include "bpy_rna.h"
|
2011-02-14 18:20:10 +00:00
|
|
|
|
2018-06-11 20:00:03 +02:00
|
|
|
#include "BPY_extern.h"
|
|
|
|
|
|
2016-04-05 07:02:43 +10:00
|
|
|
#define USE_RNA_AS_PYOBJECT
|
2011-10-05 07:28:59 +00:00
|
|
|
|
2018-06-17 19:51:05 +02:00
|
|
|
#define USE_BYTECODE_WHITELIST
|
|
|
|
|
|
|
|
|
|
#ifdef USE_BYTECODE_WHITELIST
|
|
|
|
|
# include <opcode.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2011-12-26 12:26:11 +00:00
|
|
|
PyObject *bpy_pydriver_Dict = NULL;
|
2009-12-08 22:35:03 +00:00
|
|
|
|
2018-06-17 19:51:05 +02:00
|
|
|
#ifdef USE_BYTECODE_WHITELIST
|
|
|
|
|
static PyObject *bpy_pydriver_Dict__whitelist = NULL;
|
|
|
|
|
#endif
|
|
|
|
|
|
2010-11-27 02:39:51 +00:00
|
|
|
int bpy_pydriver_create_dict(void)
|
2009-12-08 22:35:03 +00:00
|
|
|
{
|
|
|
|
|
PyObject *d, *mod;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-15 15:17:55 +11:00
|
|
|
/* Validate name-space for driver evaluation. */
|
2019-03-30 06:12:48 +11:00
|
|
|
if (bpy_pydriver_Dict) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-12-26 12:26:11 +00:00
|
|
|
d = PyDict_New();
|
2019-03-30 06:12:48 +11:00
|
|
|
if (d == NULL) {
|
2009-12-08 22:35:03 +00:00
|
|
|
return -1;
|
2019-03-30 06:12:48 +11:00
|
|
|
}
|
2020-08-07 12:41:06 +02:00
|
|
|
|
|
|
|
|
bpy_pydriver_Dict = d;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-15 15:17:55 +11:00
|
|
|
/* Import some modules: `builtins`, `bpy`, `math`, `mathutils.noise`. */
|
2009-12-08 22:35:03 +00:00
|
|
|
PyDict_SetItemString(d, "__builtins__", PyEval_GetBuiltins());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-12-26 12:26:11 +00:00
|
|
|
mod = PyImport_ImportModule("math");
|
2009-12-08 22:35:03 +00:00
|
|
|
if (mod) {
|
2012-03-18 07:38:51 +00:00
|
|
|
PyDict_Merge(d, PyModule_GetDict(mod), 0); /* 0 - don't overwrite existing values */
|
2009-12-08 22:35:03 +00:00
|
|
|
Py_DECREF(mod);
|
|
|
|
|
}
|
2018-06-17 19:51:05 +02:00
|
|
|
#ifdef USE_BYTECODE_WHITELIST
|
|
|
|
|
PyObject *mod_math = mod;
|
|
|
|
|
#endif
|
2009-12-08 22:35:03 +00:00
|
|
|
|
2022-03-15 15:17:55 +11:00
|
|
|
/* Add `bpy` to global name-space. */
|
2013-03-17 18:30:31 +00:00
|
|
|
mod = PyImport_ImportModuleLevel("bpy", NULL, NULL, NULL, 0);
|
2009-12-08 22:35:03 +00:00
|
|
|
if (mod) {
|
|
|
|
|
PyDict_SetItemString(bpy_pydriver_Dict, "bpy", mod);
|
|
|
|
|
Py_DECREF(mod);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-15 15:17:55 +11:00
|
|
|
/* Add noise to global name-space. */
|
2013-03-17 18:30:31 +00:00
|
|
|
mod = PyImport_ImportModuleLevel("mathutils", NULL, NULL, NULL, 0);
|
2011-09-05 05:42:49 +00:00
|
|
|
if (mod) {
|
2011-12-26 12:26:11 +00:00
|
|
|
PyObject *modsub = PyDict_GetItemString(PyModule_GetDict(mod), "noise");
|
2011-12-07 00:36:57 +00:00
|
|
|
PyDict_SetItemString(bpy_pydriver_Dict, "noise", modsub);
|
2011-09-05 05:42:49 +00:00
|
|
|
Py_DECREF(mod);
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-04 13:20:59 +03:00
|
|
|
/* Add math utility functions. */
|
|
|
|
|
mod = PyImport_ImportModuleLevel("bl_math", NULL, NULL, NULL, 0);
|
|
|
|
|
if (mod) {
|
|
|
|
|
static const char *names[] = {"clamp", "lerp", "smoothstep", NULL};
|
|
|
|
|
|
|
|
|
|
for (const char **pname = names; *pname; ++pname) {
|
|
|
|
|
PyObject *func = PyDict_GetItemString(PyModule_GetDict(mod), *pname);
|
|
|
|
|
PyDict_SetItemString(bpy_pydriver_Dict, *pname, func);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Py_DECREF(mod);
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-17 19:51:05 +02:00
|
|
|
#ifdef USE_BYTECODE_WHITELIST
|
2022-03-15 15:17:55 +11:00
|
|
|
/* Setup the whitelist. */
|
2018-06-17 19:51:05 +02:00
|
|
|
{
|
|
|
|
|
bpy_pydriver_Dict__whitelist = PyDict_New();
|
|
|
|
|
const char *whitelist[] = {
|
|
|
|
|
/* builtins (basic) */
|
|
|
|
|
"all",
|
|
|
|
|
"any",
|
|
|
|
|
"len",
|
|
|
|
|
/* builtins (numeric) */
|
|
|
|
|
"max",
|
|
|
|
|
"min",
|
|
|
|
|
"pow",
|
|
|
|
|
"round",
|
|
|
|
|
"sum",
|
|
|
|
|
/* types */
|
|
|
|
|
"bool",
|
|
|
|
|
"float",
|
|
|
|
|
"int",
|
2020-07-04 13:20:59 +03:00
|
|
|
/* bl_math */
|
|
|
|
|
"clamp",
|
|
|
|
|
"lerp",
|
|
|
|
|
"smoothstep",
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-17 19:51:05 +02:00
|
|
|
NULL,
|
|
|
|
|
};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-17 19:51:05 +02:00
|
|
|
for (int i = 0; whitelist[i]; i++) {
|
|
|
|
|
PyDict_SetItemString(bpy_pydriver_Dict__whitelist, whitelist[i], Py_None);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-15 15:17:55 +11:00
|
|
|
/* Add all of `math` functions. */
|
2018-06-17 19:51:05 +02:00
|
|
|
if (mod_math != NULL) {
|
|
|
|
|
PyObject *mod_math_dict = PyModule_GetDict(mod_math);
|
|
|
|
|
PyObject *arg_key, *arg_value;
|
|
|
|
|
Py_ssize_t arg_pos = 0;
|
|
|
|
|
while (PyDict_Next(mod_math_dict, &arg_pos, &arg_key, &arg_value)) {
|
2021-02-13 22:57:01 +11:00
|
|
|
const char *arg_str = PyUnicode_AsUTF8(arg_key);
|
2018-06-17 19:51:05 +02:00
|
|
|
if (arg_str[0] && arg_str[1] != '_') {
|
|
|
|
|
PyDict_SetItem(bpy_pydriver_Dict__whitelist, arg_key, Py_None);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif /* USE_BYTECODE_WHITELIST */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-12-08 22:35:03 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-15 15:17:55 +11:00
|
|
|
/**
|
|
|
|
|
* \note this function should do nothing most runs, only when changing frame.
|
|
|
|
|
* Not thread safe but neither is Python.
|
|
|
|
|
*/
|
2016-07-31 11:43:24 +10:00
|
|
|
static struct {
|
|
|
|
|
float evaltime;
|
|
|
|
|
|
2022-03-15 15:17:55 +11:00
|
|
|
/* Borrowed reference to the `self` in `bpy_pydriver_Dict`
|
2016-07-31 11:43:24 +10:00
|
|
|
* keep for as long as the same self is used. */
|
|
|
|
|
PyObject *self;
|
2022-03-08 22:07:59 +11:00
|
|
|
BPy_StructRNA *depsgraph;
|
2016-07-31 11:43:24 +10:00
|
|
|
} g_pydriver_state_prev = {
|
|
|
|
|
.evaltime = FLT_MAX,
|
|
|
|
|
.self = NULL,
|
2022-03-08 22:07:59 +11:00
|
|
|
.depsgraph = NULL,
|
2016-07-31 11:43:24 +10:00
|
|
|
};
|
2011-11-17 07:08:09 +00:00
|
|
|
|
2016-07-31 11:22:02 +10:00
|
|
|
static void bpy_pydriver_namespace_update_frame(const float evaltime)
|
2011-11-17 07:08:09 +00:00
|
|
|
{
|
2016-07-31 11:43:24 +10:00
|
|
|
if (g_pydriver_state_prev.evaltime != evaltime) {
|
2016-07-14 17:28:28 +10:00
|
|
|
PyObject *item = PyFloat_FromDouble(evaltime);
|
2016-07-31 11:22:02 +10:00
|
|
|
PyDict_SetItem(bpy_pydriver_Dict, bpy_intern_str_frame, item);
|
2016-07-14 17:28:28 +10:00
|
|
|
Py_DECREF(item);
|
2011-11-17 07:08:09 +00:00
|
|
|
|
2016-07-31 11:43:24 +10:00
|
|
|
g_pydriver_state_prev.evaltime = evaltime;
|
2011-11-17 07:08:09 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-31 11:22:02 +10:00
|
|
|
static void bpy_pydriver_namespace_update_self(struct PathResolvedRNA *anim_rna)
|
2016-07-30 16:34:01 +10:00
|
|
|
{
|
2016-07-31 11:43:24 +10:00
|
|
|
if ((g_pydriver_state_prev.self == NULL) ||
|
|
|
|
|
(pyrna_driver_is_equal_anim_rna(anim_rna, g_pydriver_state_prev.self) == false))
|
|
|
|
|
{
|
|
|
|
|
PyObject *item = pyrna_driver_self_from_anim_rna(anim_rna);
|
|
|
|
|
PyDict_SetItem(bpy_pydriver_Dict, bpy_intern_str_self, item);
|
|
|
|
|
Py_DECREF(item);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-07-31 11:43:24 +10:00
|
|
|
g_pydriver_state_prev.self = item;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void bpy_pydriver_namespace_clear_self(void)
|
|
|
|
|
{
|
|
|
|
|
if (g_pydriver_state_prev.self) {
|
|
|
|
|
PyDict_DelItem(bpy_pydriver_Dict, bpy_intern_str_self);
|
|
|
|
|
|
|
|
|
|
g_pydriver_state_prev.self = NULL;
|
|
|
|
|
}
|
2016-07-30 16:34:01 +10:00
|
|
|
}
|
|
|
|
|
|
2022-03-08 22:07:59 +11:00
|
|
|
static PyObject *bpy_pydriver_depsgraph_as_pyobject(struct Depsgraph *depsgraph)
|
|
|
|
|
{
|
|
|
|
|
struct PointerRNA depsgraph_ptr;
|
|
|
|
|
RNA_pointer_create(NULL, &RNA_Depsgraph, depsgraph, &depsgraph_ptr);
|
|
|
|
|
return pyrna_struct_CreatePyObject(&depsgraph_ptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2022-03-15 15:17:55 +11:00
|
|
|
* Adds a variable `depsgraph` to the name-space. This can then be used to obtain evaluated
|
2023-02-12 14:37:16 +11:00
|
|
|
* data-blocks, and the current view layer and scene. See #75553.
|
2022-03-08 22:07:59 +11:00
|
|
|
*/
|
|
|
|
|
static void bpy_pydriver_namespace_update_depsgraph(struct Depsgraph *depsgraph)
|
|
|
|
|
{
|
|
|
|
|
/* This should never happen, but it's probably better to have None in Python
|
|
|
|
|
* than a NULL-wrapping Depsgraph Python struct. */
|
|
|
|
|
BLI_assert(depsgraph != NULL);
|
|
|
|
|
if (UNLIKELY(depsgraph == NULL)) {
|
|
|
|
|
PyDict_SetItem(bpy_pydriver_Dict, bpy_intern_str_depsgraph, Py_None);
|
|
|
|
|
g_pydriver_state_prev.depsgraph = NULL;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((g_pydriver_state_prev.depsgraph == NULL) ||
|
2022-09-25 15:14:13 +10:00
|
|
|
(depsgraph != g_pydriver_state_prev.depsgraph->ptr.data))
|
|
|
|
|
{
|
2022-03-08 22:07:59 +11:00
|
|
|
PyObject *item = bpy_pydriver_depsgraph_as_pyobject(depsgraph);
|
|
|
|
|
PyDict_SetItem(bpy_pydriver_Dict, bpy_intern_str_depsgraph, item);
|
|
|
|
|
Py_DECREF(item);
|
|
|
|
|
|
|
|
|
|
g_pydriver_state_prev.depsgraph = (BPy_StructRNA *)item;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-07 12:30:45 +10:00
|
|
|
void BPY_driver_exit(void)
|
2009-12-08 22:35:03 +00:00
|
|
|
{
|
2022-03-15 15:17:55 +11:00
|
|
|
if (bpy_pydriver_Dict) { /* Free the global dict used by python-drivers. */
|
2009-12-08 22:35:03 +00:00
|
|
|
PyDict_Clear(bpy_pydriver_Dict);
|
|
|
|
|
Py_DECREF(bpy_pydriver_Dict);
|
2011-12-26 12:26:11 +00:00
|
|
|
bpy_pydriver_Dict = NULL;
|
2009-12-08 22:35:03 +00:00
|
|
|
}
|
|
|
|
|
|
2018-06-17 19:51:05 +02:00
|
|
|
#ifdef USE_BYTECODE_WHITELIST
|
|
|
|
|
if (bpy_pydriver_Dict__whitelist) {
|
|
|
|
|
PyDict_Clear(bpy_pydriver_Dict__whitelist);
|
|
|
|
|
Py_DECREF(bpy_pydriver_Dict__whitelist);
|
|
|
|
|
bpy_pydriver_Dict__whitelist = NULL;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2016-07-31 11:43:24 +10:00
|
|
|
g_pydriver_state_prev.evaltime = FLT_MAX;
|
|
|
|
|
|
2022-03-15 15:17:55 +11:00
|
|
|
/* Freed when clearing driver dictionary. */
|
2016-07-31 11:43:24 +10:00
|
|
|
g_pydriver_state_prev.self = NULL;
|
2022-03-08 22:07:59 +11:00
|
|
|
g_pydriver_state_prev.depsgraph = NULL;
|
2022-07-07 12:30:45 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BPY_driver_reset(void)
|
|
|
|
|
{
|
|
|
|
|
PyGILState_STATE gilstate;
|
|
|
|
|
const bool use_gil = true; /* !PyC_IsInterpreterActive(); */
|
|
|
|
|
|
|
|
|
|
if (use_gil) {
|
|
|
|
|
gilstate = PyGILState_Ensure();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Currently exit/reset are practically the same besides the GIL check. */
|
|
|
|
|
BPY_driver_exit();
|
2011-11-17 07:08:09 +00:00
|
|
|
|
2019-03-30 06:12:48 +11:00
|
|
|
if (use_gil) {
|
2010-05-18 14:38:25 +00:00
|
|
|
PyGILState_Release(gilstate);
|
2019-03-30 06:12:48 +11:00
|
|
|
}
|
2009-12-08 22:35:03 +00:00
|
|
|
}
|
|
|
|
|
|
2022-07-07 12:30:47 +10:00
|
|
|
/**
|
2022-07-08 09:10:30 +10:00
|
|
|
* Error return function for #BPY_driver_exec.
|
2022-07-07 12:30:47 +10:00
|
|
|
*
|
|
|
|
|
* \param anim_rna: Used to show the target when printing the error to give additional context.
|
|
|
|
|
*/
|
|
|
|
|
static void pydriver_error(ChannelDriver *driver, const struct PathResolvedRNA *anim_rna)
|
2009-12-08 22:35:03 +00:00
|
|
|
{
|
2022-03-15 15:17:55 +11:00
|
|
|
driver->flag |= DRIVER_FLAG_INVALID; /* Python expression failed. */
|
2022-07-07 12:30:47 +10:00
|
|
|
|
|
|
|
|
const char *null_str = "<null>";
|
|
|
|
|
const ID *id = anim_rna->ptr.owner_id;
|
2009-12-08 22:35:03 +00:00
|
|
|
fprintf(stderr,
|
2022-07-07 12:30:47 +10:00
|
|
|
"\n"
|
|
|
|
|
"Error in PyDriver: expression failed: %s\n"
|
|
|
|
|
"For target: (type=%s, name=\"%s\", property=%s, property_index=%d)\n"
|
|
|
|
|
"\n",
|
|
|
|
|
driver->expression,
|
|
|
|
|
id ? BKE_idtype_idcode_to_name(GS(id->name)) : null_str,
|
|
|
|
|
id ? id->name + 2 : null_str,
|
|
|
|
|
anim_rna->prop ? RNA_property_identifier(anim_rna->prop) : null_str,
|
|
|
|
|
anim_rna->prop_index);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-07-03 23:08:40 +10:00
|
|
|
// BPy_errors_to_report(NULL); /* TODO: reports. */
|
2009-12-08 22:35:03 +00:00
|
|
|
PyErr_Print();
|
|
|
|
|
PyErr_Clear();
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-17 19:51:05 +02:00
|
|
|
#ifdef USE_BYTECODE_WHITELIST
|
|
|
|
|
|
2022-07-07 12:30:44 +10:00
|
|
|
# define OK_OP(op) [op] = true
|
2018-06-17 19:51:05 +02:00
|
|
|
|
2022-07-07 12:30:44 +10:00
|
|
|
static const bool secure_opcodes[255] = {
|
2022-07-05 13:41:55 +10:00
|
|
|
# if PY_VERSION_HEX >= 0x030b0000 /* Python 3.11 & newer. */
|
|
|
|
|
|
|
|
|
|
OK_OP(CACHE),
|
|
|
|
|
OK_OP(POP_TOP),
|
|
|
|
|
OK_OP(PUSH_NULL),
|
|
|
|
|
OK_OP(NOP),
|
|
|
|
|
OK_OP(UNARY_POSITIVE),
|
|
|
|
|
OK_OP(UNARY_NEGATIVE),
|
|
|
|
|
OK_OP(UNARY_NOT),
|
|
|
|
|
OK_OP(UNARY_INVERT),
|
|
|
|
|
OK_OP(BINARY_SUBSCR),
|
|
|
|
|
OK_OP(GET_LEN),
|
2022-07-12 16:05:13 +10:00
|
|
|
OK_OP(LIST_TO_TUPLE),
|
2022-07-05 13:41:55 +10:00
|
|
|
OK_OP(RETURN_VALUE),
|
|
|
|
|
OK_OP(SWAP),
|
|
|
|
|
OK_OP(BUILD_TUPLE),
|
|
|
|
|
OK_OP(BUILD_LIST),
|
|
|
|
|
OK_OP(BUILD_SET),
|
|
|
|
|
OK_OP(BUILD_MAP),
|
|
|
|
|
OK_OP(COMPARE_OP),
|
|
|
|
|
OK_OP(JUMP_FORWARD),
|
|
|
|
|
OK_OP(JUMP_IF_FALSE_OR_POP),
|
|
|
|
|
OK_OP(JUMP_IF_TRUE_OR_POP),
|
|
|
|
|
OK_OP(POP_JUMP_FORWARD_IF_FALSE),
|
|
|
|
|
OK_OP(POP_JUMP_FORWARD_IF_TRUE),
|
|
|
|
|
OK_OP(LOAD_GLOBAL),
|
|
|
|
|
OK_OP(IS_OP),
|
2022-07-12 16:05:13 +10:00
|
|
|
OK_OP(CONTAINS_OP),
|
2022-07-05 13:41:55 +10:00
|
|
|
OK_OP(BINARY_OP),
|
|
|
|
|
OK_OP(LOAD_FAST),
|
|
|
|
|
OK_OP(STORE_FAST),
|
|
|
|
|
OK_OP(DELETE_FAST),
|
|
|
|
|
OK_OP(POP_JUMP_FORWARD_IF_NOT_NONE),
|
|
|
|
|
OK_OP(POP_JUMP_FORWARD_IF_NONE),
|
|
|
|
|
OK_OP(BUILD_SLICE),
|
|
|
|
|
OK_OP(LOAD_DEREF),
|
|
|
|
|
OK_OP(STORE_DEREF),
|
|
|
|
|
OK_OP(RESUME),
|
2022-07-12 16:05:13 +10:00
|
|
|
OK_OP(LIST_EXTEND),
|
|
|
|
|
OK_OP(SET_UPDATE),
|
2023-02-09 11:30:25 +11:00
|
|
|
/* NOTE(@ideasman42): Don't enable dict manipulation, unless we can prove there is not way it
|
2022-07-12 16:05:13 +10:00
|
|
|
* can be used to manipulate the name-space (potentially allowing malicious code). */
|
|
|
|
|
# if 0
|
|
|
|
|
OK_OP(DICT_MERGE),
|
|
|
|
|
OK_OP(DICT_UPDATE),
|
|
|
|
|
# endif
|
2022-07-05 13:41:55 +10:00
|
|
|
OK_OP(POP_JUMP_BACKWARD_IF_NOT_NONE),
|
|
|
|
|
OK_OP(POP_JUMP_BACKWARD_IF_NONE),
|
|
|
|
|
OK_OP(POP_JUMP_BACKWARD_IF_FALSE),
|
|
|
|
|
OK_OP(POP_JUMP_BACKWARD_IF_TRUE),
|
|
|
|
|
|
|
|
|
|
/* Special cases. */
|
|
|
|
|
OK_OP(LOAD_CONST), /* Ok because constants are accepted. */
|
|
|
|
|
OK_OP(LOAD_NAME), /* Ok, because `PyCodeObject.names` is checked. */
|
|
|
|
|
OK_OP(CALL), /* Ok, because we check its "name" before calling. */
|
|
|
|
|
OK_OP(KW_NAMES), /* Ok, because it's used for calling functions with keyword arguments. */
|
|
|
|
|
OK_OP(PRECALL), /* Ok, because it's used for calling. */
|
|
|
|
|
|
|
|
|
|
# else /* Python 3.10 and older. */
|
|
|
|
|
|
2018-06-17 19:51:05 +02:00
|
|
|
OK_OP(POP_TOP),
|
|
|
|
|
OK_OP(ROT_TWO),
|
|
|
|
|
OK_OP(ROT_THREE),
|
|
|
|
|
OK_OP(DUP_TOP),
|
|
|
|
|
OK_OP(DUP_TOP_TWO),
|
2022-07-05 13:41:53 +10:00
|
|
|
OK_OP(ROT_FOUR),
|
2018-06-17 19:51:05 +02:00
|
|
|
OK_OP(NOP),
|
|
|
|
|
OK_OP(UNARY_POSITIVE),
|
|
|
|
|
OK_OP(UNARY_NEGATIVE),
|
|
|
|
|
OK_OP(UNARY_NOT),
|
|
|
|
|
OK_OP(UNARY_INVERT),
|
|
|
|
|
OK_OP(BINARY_MATRIX_MULTIPLY),
|
|
|
|
|
OK_OP(INPLACE_MATRIX_MULTIPLY),
|
|
|
|
|
OK_OP(BINARY_POWER),
|
|
|
|
|
OK_OP(BINARY_MULTIPLY),
|
|
|
|
|
OK_OP(BINARY_MODULO),
|
|
|
|
|
OK_OP(BINARY_ADD),
|
|
|
|
|
OK_OP(BINARY_SUBTRACT),
|
|
|
|
|
OK_OP(BINARY_SUBSCR),
|
|
|
|
|
OK_OP(BINARY_FLOOR_DIVIDE),
|
|
|
|
|
OK_OP(BINARY_TRUE_DIVIDE),
|
|
|
|
|
OK_OP(INPLACE_FLOOR_DIVIDE),
|
|
|
|
|
OK_OP(INPLACE_TRUE_DIVIDE),
|
2022-07-05 13:41:53 +10:00
|
|
|
OK_OP(GET_LEN),
|
2018-06-17 19:51:05 +02:00
|
|
|
OK_OP(INPLACE_ADD),
|
|
|
|
|
OK_OP(INPLACE_SUBTRACT),
|
|
|
|
|
OK_OP(INPLACE_MULTIPLY),
|
|
|
|
|
OK_OP(INPLACE_MODULO),
|
|
|
|
|
OK_OP(BINARY_LSHIFT),
|
|
|
|
|
OK_OP(BINARY_RSHIFT),
|
|
|
|
|
OK_OP(BINARY_AND),
|
|
|
|
|
OK_OP(BINARY_XOR),
|
|
|
|
|
OK_OP(BINARY_OR),
|
|
|
|
|
OK_OP(INPLACE_POWER),
|
|
|
|
|
OK_OP(INPLACE_LSHIFT),
|
|
|
|
|
OK_OP(INPLACE_RSHIFT),
|
|
|
|
|
OK_OP(INPLACE_AND),
|
|
|
|
|
OK_OP(INPLACE_XOR),
|
|
|
|
|
OK_OP(INPLACE_OR),
|
2022-07-12 16:05:13 +10:00
|
|
|
OK_OP(LIST_TO_TUPLE),
|
2018-06-17 19:51:05 +02:00
|
|
|
OK_OP(RETURN_VALUE),
|
2022-07-05 13:41:53 +10:00
|
|
|
OK_OP(ROT_N),
|
2018-06-17 19:51:05 +02:00
|
|
|
OK_OP(BUILD_TUPLE),
|
|
|
|
|
OK_OP(BUILD_LIST),
|
|
|
|
|
OK_OP(BUILD_SET),
|
|
|
|
|
OK_OP(BUILD_MAP),
|
|
|
|
|
OK_OP(COMPARE_OP),
|
|
|
|
|
OK_OP(JUMP_FORWARD),
|
|
|
|
|
OK_OP(JUMP_IF_FALSE_OR_POP),
|
|
|
|
|
OK_OP(JUMP_IF_TRUE_OR_POP),
|
|
|
|
|
OK_OP(JUMP_ABSOLUTE),
|
|
|
|
|
OK_OP(POP_JUMP_IF_FALSE),
|
|
|
|
|
OK_OP(POP_JUMP_IF_TRUE),
|
|
|
|
|
OK_OP(LOAD_GLOBAL),
|
2022-07-05 13:41:53 +10:00
|
|
|
OK_OP(IS_OP),
|
2022-07-12 16:05:13 +10:00
|
|
|
OK_OP(CONTAINS_OP),
|
2018-06-17 19:51:05 +02:00
|
|
|
OK_OP(LOAD_FAST),
|
|
|
|
|
OK_OP(STORE_FAST),
|
|
|
|
|
OK_OP(DELETE_FAST),
|
2022-07-05 13:41:53 +10:00
|
|
|
OK_OP(BUILD_SLICE),
|
2018-06-17 19:51:05 +02:00
|
|
|
OK_OP(LOAD_DEREF),
|
|
|
|
|
OK_OP(STORE_DEREF),
|
2022-07-12 16:05:13 +10:00
|
|
|
OK_OP(LIST_EXTEND),
|
|
|
|
|
OK_OP(SET_UPDATE),
|
2023-02-09 11:30:25 +11:00
|
|
|
/* NOTE(@ideasman42): Don't enable dict manipulation, unless we can prove there is not way it
|
2022-07-12 16:05:13 +10:00
|
|
|
* can be used to manipulate the name-space (potentially allowing malicious code). */
|
|
|
|
|
# if 0
|
|
|
|
|
OK_OP(DICT_MERGE),
|
|
|
|
|
OK_OP(DICT_UPDATE),
|
|
|
|
|
# endif
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-15 15:17:55 +11:00
|
|
|
/* Special cases. */
|
|
|
|
|
OK_OP(LOAD_CONST), /* Ok because constants are accepted. */
|
|
|
|
|
OK_OP(LOAD_NAME), /* Ok, because `PyCodeObject.names` is checked. */
|
|
|
|
|
OK_OP(CALL_FUNCTION), /* Ok, because we check its "name" before calling. */
|
2018-06-17 19:51:05 +02:00
|
|
|
OK_OP(CALL_FUNCTION_KW),
|
|
|
|
|
OK_OP(CALL_FUNCTION_EX),
|
2022-07-05 13:41:55 +10:00
|
|
|
|
|
|
|
|
# endif /* Python 3.10 and older. */
|
2018-06-17 19:51:05 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
# undef OK_OP
|
|
|
|
|
|
2022-07-12 16:05:13 +10:00
|
|
|
bool BPY_driver_secure_bytecode_test_ex(PyObject *expr_code,
|
|
|
|
|
PyObject *namespace_array[],
|
|
|
|
|
const bool verbose,
|
|
|
|
|
const char *error_prefix)
|
2018-06-17 19:51:05 +02:00
|
|
|
{
|
|
|
|
|
PyCodeObject *py_code = (PyCodeObject *)expr_code;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-17 19:51:05 +02:00
|
|
|
/* Check names. */
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < PyTuple_GET_SIZE(py_code->co_names); i++) {
|
|
|
|
|
PyObject *name = PyTuple_GET_ITEM(py_code->co_names, i);
|
2022-07-12 16:05:13 +10:00
|
|
|
const char *name_str = PyUnicode_AsUTF8(name);
|
2018-06-17 19:51:05 +02:00
|
|
|
bool contains_name = false;
|
2022-07-12 16:05:13 +10:00
|
|
|
for (int j = 0; namespace_array[j]; j++) {
|
|
|
|
|
if (PyDict_Contains(namespace_array[j], name)) {
|
2018-06-17 19:51:05 +02:00
|
|
|
contains_name = true;
|
|
|
|
|
break;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2018-06-17 19:51:05 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-07-12 16:05:13 +10:00
|
|
|
if ((contains_name == false) || (name_str[0] == '_')) {
|
|
|
|
|
if (verbose) {
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"\t%s: restricted access disallows name '%s', "
|
|
|
|
|
"enable auto-execution to support\n",
|
|
|
|
|
error_prefix,
|
|
|
|
|
name_str);
|
|
|
|
|
}
|
2018-06-17 19:51:05 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-17 19:51:05 +02:00
|
|
|
/* Check opcodes. */
|
|
|
|
|
{
|
2018-07-06 19:31:00 +02:00
|
|
|
const _Py_CODEUNIT *codestr;
|
2018-06-17 19:51:05 +02:00
|
|
|
Py_ssize_t code_len;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-07-05 13:41:55 +10:00
|
|
|
PyObject *co_code;
|
|
|
|
|
|
|
|
|
|
# if PY_VERSION_HEX >= 0x030b0000 /* Python 3.11 & newer. */
|
2022-07-07 12:30:40 +10:00
|
|
|
co_code = PyCode_GetCode(py_code);
|
|
|
|
|
if (UNLIKELY(!co_code)) {
|
|
|
|
|
PyErr_Print();
|
|
|
|
|
PyErr_Clear();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-07-05 13:41:55 +10:00
|
|
|
# else
|
|
|
|
|
co_code = py_code->co_code;
|
|
|
|
|
# endif
|
|
|
|
|
|
|
|
|
|
PyBytes_AsStringAndSize(co_code, (char **)&codestr, &code_len);
|
2018-07-06 19:31:00 +02:00
|
|
|
code_len /= sizeof(*codestr);
|
2022-07-07 12:30:40 +10:00
|
|
|
bool ok = true;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-07-07 12:30:44 +10:00
|
|
|
/* Loop over op-code's, the op-code arguments are ignored. */
|
2018-07-06 19:31:00 +02:00
|
|
|
for (Py_ssize_t i = 0; i < code_len; i++) {
|
|
|
|
|
const int opcode = _Py_OPCODE(codestr[i]);
|
2022-07-07 12:30:44 +10:00
|
|
|
if (secure_opcodes[opcode] == false) {
|
2022-07-12 16:05:13 +10:00
|
|
|
if (verbose) {
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"\t%s: restricted access disallows opcode '%d', "
|
|
|
|
|
"enable auto-execution to support\n",
|
|
|
|
|
error_prefix,
|
|
|
|
|
opcode);
|
|
|
|
|
}
|
2022-07-07 12:30:40 +10:00
|
|
|
ok = false;
|
|
|
|
|
break;
|
2018-06-17 19:51:05 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2022-07-07 12:30:40 +10:00
|
|
|
# if PY_VERSION_HEX >= 0x030b0000 /* Python 3.11 & newer. */
|
|
|
|
|
Py_DECREF(co_code);
|
|
|
|
|
# endif
|
|
|
|
|
if (!ok) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2018-06-17 19:51:05 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-17 19:51:05 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-12 16:05:13 +10:00
|
|
|
bool BPY_driver_secure_bytecode_test(PyObject *expr_code, PyObject *namespace, const bool verbose)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (!bpy_pydriver_Dict) {
|
|
|
|
|
if (bpy_pydriver_create_dict() != 0) {
|
|
|
|
|
fprintf(stderr, "%s: couldn't create Python dictionary\n", __func__);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return BPY_driver_secure_bytecode_test_ex(expr_code,
|
|
|
|
|
(PyObject *[]){
|
|
|
|
|
bpy_pydriver_Dict,
|
|
|
|
|
bpy_pydriver_Dict__whitelist,
|
|
|
|
|
namespace,
|
|
|
|
|
NULL,
|
|
|
|
|
},
|
|
|
|
|
verbose,
|
|
|
|
|
__func__);
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-17 19:51:05 +02:00
|
|
|
#endif /* USE_BYTECODE_WHITELIST */
|
2018-06-11 20:00:03 +02:00
|
|
|
float BPY_driver_exec(struct PathResolvedRNA *anim_rna,
|
|
|
|
|
ChannelDriver *driver,
|
|
|
|
|
ChannelDriver *driver_orig,
|
T77086 Animation: Passing Dependency Graph to Drivers
Custom driver functions need access to the dependency graph that is
triggering the evaluation of the driver. This patch passes the
dependency graph pointer through all the animation-related calls.
Instead of passing the evaluation time to functions, the code now passes
an `AnimationEvalContext` pointer:
```
typedef struct AnimationEvalContext {
struct Depsgraph *const depsgraph;
const float eval_time;
} AnimationEvalContext;
```
These structs are read-only, meaning that the code cannot change the
evaluation time. Note that the `depsgraph` pointer itself is const, but
it points to a non-const depsgraph.
FCurves and Drivers can be evaluated at a different time than the
current scene time, for example when evaluating NLA strips. This means
that, even though the current time is stored in the dependency graph, we
need an explicit evaluation time.
There are two functions that allow creation of `AnimationEvalContext`
objects:
- `BKE_animsys_eval_context_construct(Depsgraph *depsgraph, float
eval_time)`, which creates a new context object from scratch, and
- `BKE_animsys_eval_context_construct_at(AnimationEvalContext
*anim_eval_context, float eval_time)`, which can be used to create a
`AnimationEvalContext` with the same depsgraph, but at a different
time. This makes it possible to later add fields without changing any
of the code that just want to change the eval time.
This also provides a fix for T75553, although it does require a change
to the custom driver function. The driver should call
`custom_function(depsgraph)`, and the function should use that depsgraph
instead of information from `bpy.context`.
Reviewed By: brecht, sergey
Differential Revision: https://developer.blender.org/D8047
2020-07-17 17:38:09 +02:00
|
|
|
const AnimationEvalContext *anim_eval_context)
|
2009-12-08 22:35:03 +00:00
|
|
|
{
|
2021-12-02 17:24:04 +11:00
|
|
|
/* (old) NOTE: PyGILState_Ensure() isn't always called because python can call
|
|
|
|
|
* the bake operator which intern starts a thread which calls scene update
|
|
|
|
|
* which does a driver update. to avoid a deadlock check #PyC_IsInterpreterActive()
|
2023-02-12 14:37:16 +11:00
|
|
|
* if #PyGILState_Ensure() is needed, see #27683.
|
2021-12-02 17:24:04 +11:00
|
|
|
*
|
2023-02-12 14:37:16 +11:00
|
|
|
* (new) NOTE: checking if python is running is not thread-safe #28114
|
2021-12-02 17:24:04 +11:00
|
|
|
* now release the GIL on python operator execution instead, using
|
|
|
|
|
* #PyEval_SaveThread() / #PyEval_RestoreThread() so we don't lock up blender.
|
|
|
|
|
*
|
|
|
|
|
* For copy-on-write we always cache expressions and write errors in the
|
|
|
|
|
* original driver, otherwise these would get freed while editing.
|
|
|
|
|
* Due to the GIL this is thread-safe. */
|
|
|
|
|
|
2011-12-26 12:26:11 +00:00
|
|
|
PyObject *driver_vars = NULL;
|
|
|
|
|
PyObject *retval = NULL;
|
2019-04-29 19:59:13 +10:00
|
|
|
|
|
|
|
|
/* Speed up by pre-hashing string & avoids re-converting unicode strings for every execution. */
|
|
|
|
|
PyObject *expr_vars;
|
|
|
|
|
|
2010-01-05 10:54:54 +00:00
|
|
|
PyObject *expr_code;
|
2009-12-08 22:35:03 +00:00
|
|
|
PyGILState_STATE gilstate;
|
2013-01-07 05:26:12 +00:00
|
|
|
bool use_gil;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Durian Request: Drivers Recode
Highlights:
* Support for Multi-Target Variables
This was the main reason for this recode. Previously, variables could only be used to give some RNA property used as an input source to the driver a name. However, this meant that effects such as Rotational Difference couldn't be used in conjunction with other effects and/or settings to achieve the powerful results. Now, a variable can take several input targets, perform some interesting operations on them, and spit out a representative value based on that.
* New Variable Types
With the introduction of multi-target variables, there are now 3 types of variable that can be used: single property (i.e. the only type previously), Rotational Difference (angle between two bones), and Distance (distance between two objects or bones).
* New Driver Types
In addition to the existing 'Average', 'Sum', and 'Expression' types, there is now the additional options of 'Minimum' and 'Maximum'. These take the smallest/largest value that one of the variables evaluates to.
* Fix for Driver F-Curve colouring bug
Newly added drivers did not get automatically coloured in the Graph Editor properly. Was caused by inappropriate notifiers being used.
Notes:
* This commit breaks existing 2.5 files with drivers (in other words, they are lost forever).
* Rigify has been corrected to work with the new system. The PyAPI for accessing targets used for the variables could still be made nicer (using subclassing to directly access?), but that is left for later.
* Version patching for 2.49 files still needs to be put back in place.
2010-01-04 21:15:45 +00:00
|
|
|
DriverVar *dvar;
|
2022-03-15 15:17:55 +11:00
|
|
|
double result = 0.0; /* Default return. */
|
2013-06-12 00:10:56 +00:00
|
|
|
const char *expr;
|
2022-07-07 12:30:44 +10:00
|
|
|
bool targets_ok = true;
|
2010-01-05 10:54:54 +00:00
|
|
|
int i;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-15 15:17:55 +11:00
|
|
|
/* Get the python expression to be evaluated. */
|
2018-06-11 20:00:03 +02:00
|
|
|
expr = driver_orig->expression;
|
2019-03-30 06:12:48 +11:00
|
|
|
if (expr[0] == '\0') {
|
2010-03-14 21:04:02 +00:00
|
|
|
return 0.0f;
|
2019-03-30 06:12:48 +11:00
|
|
|
}
|
2009-12-08 22:35:03 +00:00
|
|
|
|
2018-06-17 19:51:05 +02:00
|
|
|
#ifndef USE_BYTECODE_WHITELIST
|
2019-02-02 13:39:51 +11:00
|
|
|
if (!(G.f & G_FLAG_SCRIPT_AUTOEXEC)) {
|
|
|
|
|
if (!(G.f & G_FLAG_SCRIPT_AUTOEXEC_FAIL_QUIET)) {
|
|
|
|
|
G.f |= G_FLAG_SCRIPT_AUTOEXEC_FAIL;
|
2023-05-09 12:50:37 +10:00
|
|
|
SNPRINTF(G.autoexec_fail, "Driver '%s'", expr);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-06-12 00:10:56 +00:00
|
|
|
printf("skipping driver '%s', automatic scripts are disabled\n", expr);
|
2013-06-10 00:42:16 +00:00
|
|
|
}
|
2010-03-14 21:04:02 +00:00
|
|
|
return 0.0f;
|
2010-02-27 01:27:22 +00:00
|
|
|
}
|
2018-06-17 19:51:05 +02:00
|
|
|
#else
|
|
|
|
|
bool is_recompile = false;
|
|
|
|
|
#endif
|
2010-02-27 01:27:22 +00:00
|
|
|
|
2013-09-18 23:21:24 +00:00
|
|
|
use_gil = true; /* !PyC_IsInterpreterActive(); */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-30 06:12:48 +11:00
|
|
|
if (use_gil) {
|
2011-12-26 12:26:11 +00:00
|
|
|
gilstate = PyGILState_Ensure();
|
2019-03-30 06:12:48 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-02-12 14:37:16 +11:00
|
|
|
/* Needed since drivers are updated directly after undo where `main` is re-allocated #28807. */
|
2011-10-05 07:28:59 +00:00
|
|
|
BPY_update_rna_module();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-15 15:17:55 +11:00
|
|
|
/* Initialize global dictionary for Python driver evaluation settings. */
|
2009-12-08 22:35:03 +00:00
|
|
|
if (!bpy_pydriver_Dict) {
|
|
|
|
|
if (bpy_pydriver_create_dict() != 0) {
|
2022-07-07 12:30:44 +10:00
|
|
|
fprintf(stderr, "%s: couldn't create Python dictionary\n", __func__);
|
2019-03-30 06:12:48 +11:00
|
|
|
if (use_gil) {
|
2010-05-18 14:38:25 +00:00
|
|
|
PyGILState_Release(gilstate);
|
2019-03-30 06:12:48 +11:00
|
|
|
}
|
2010-03-14 21:04:02 +00:00
|
|
|
return 0.0f;
|
2009-12-08 22:35:03 +00:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-15 15:17:55 +11:00
|
|
|
/* Update global name-space. */
|
T77086 Animation: Passing Dependency Graph to Drivers
Custom driver functions need access to the dependency graph that is
triggering the evaluation of the driver. This patch passes the
dependency graph pointer through all the animation-related calls.
Instead of passing the evaluation time to functions, the code now passes
an `AnimationEvalContext` pointer:
```
typedef struct AnimationEvalContext {
struct Depsgraph *const depsgraph;
const float eval_time;
} AnimationEvalContext;
```
These structs are read-only, meaning that the code cannot change the
evaluation time. Note that the `depsgraph` pointer itself is const, but
it points to a non-const depsgraph.
FCurves and Drivers can be evaluated at a different time than the
current scene time, for example when evaluating NLA strips. This means
that, even though the current time is stored in the dependency graph, we
need an explicit evaluation time.
There are two functions that allow creation of `AnimationEvalContext`
objects:
- `BKE_animsys_eval_context_construct(Depsgraph *depsgraph, float
eval_time)`, which creates a new context object from scratch, and
- `BKE_animsys_eval_context_construct_at(AnimationEvalContext
*anim_eval_context, float eval_time)`, which can be used to create a
`AnimationEvalContext` with the same depsgraph, but at a different
time. This makes it possible to later add fields without changing any
of the code that just want to change the eval time.
This also provides a fix for T75553, although it does require a change
to the custom driver function. The driver should call
`custom_function(depsgraph)`, and the function should use that depsgraph
instead of information from `bpy.context`.
Reviewed By: brecht, sergey
Differential Revision: https://developer.blender.org/D8047
2020-07-17 17:38:09 +02:00
|
|
|
bpy_pydriver_namespace_update_frame(anim_eval_context->eval_time);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-11 20:00:03 +02:00
|
|
|
if (driver_orig->flag & DRIVER_FLAG_USE_SELF) {
|
2016-07-31 11:22:02 +10:00
|
|
|
bpy_pydriver_namespace_update_self(anim_rna);
|
2016-07-30 16:34:01 +10:00
|
|
|
}
|
2016-07-31 11:43:24 +10:00
|
|
|
else {
|
|
|
|
|
bpy_pydriver_namespace_clear_self();
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-08 22:07:59 +11:00
|
|
|
bpy_pydriver_namespace_update_depsgraph(anim_eval_context->depsgraph);
|
|
|
|
|
|
2019-03-30 06:12:48 +11:00
|
|
|
if (driver_orig->expr_comp == NULL) {
|
2018-06-11 20:00:03 +02:00
|
|
|
driver_orig->flag |= DRIVER_FLAG_RECOMPILE;
|
2019-03-30 06:12:48 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-15 15:17:55 +11:00
|
|
|
/* Compile the expression first if it hasn't been compiled or needs to be rebuilt. */
|
2018-06-11 20:00:03 +02:00
|
|
|
if (driver_orig->flag & DRIVER_FLAG_RECOMPILE) {
|
|
|
|
|
Py_XDECREF(driver_orig->expr_comp);
|
|
|
|
|
driver_orig->expr_comp = PyTuple_New(2);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-12-26 12:26:11 +00:00
|
|
|
expr_code = Py_CompileString(expr, "<bpy driver>", Py_eval_input);
|
2018-06-11 20:00:03 +02:00
|
|
|
PyTuple_SET_ITEM(((PyObject *)driver_orig->expr_comp), 0, expr_code);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-11 20:00:03 +02:00
|
|
|
driver_orig->flag &= ~DRIVER_FLAG_RECOMPILE;
|
2019-04-29 19:59:13 +10:00
|
|
|
|
|
|
|
|
/* Maybe this can be removed but for now best keep until were sure. */
|
|
|
|
|
driver_orig->flag |= DRIVER_FLAG_RENAMEVAR;
|
2018-06-17 19:51:05 +02:00
|
|
|
#ifdef USE_BYTECODE_WHITELIST
|
|
|
|
|
is_recompile = true;
|
|
|
|
|
#endif
|
2010-01-06 22:42:13 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2018-06-11 20:00:03 +02:00
|
|
|
expr_code = PyTuple_GET_ITEM(((PyObject *)driver_orig->expr_comp), 0);
|
2010-01-06 22:42:13 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-11 20:00:03 +02:00
|
|
|
if (driver_orig->flag & DRIVER_FLAG_RENAMEVAR) {
|
2022-03-15 15:17:55 +11:00
|
|
|
/* May not be set. */
|
2018-06-11 20:00:03 +02:00
|
|
|
expr_vars = PyTuple_GET_ITEM(((PyObject *)driver_orig->expr_comp), 1);
|
2010-01-06 22:42:13 +00:00
|
|
|
Py_XDECREF(expr_vars);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-11 20:00:03 +02:00
|
|
|
expr_vars = PyTuple_New(BLI_listbase_count(&driver_orig->variables));
|
|
|
|
|
PyTuple_SET_ITEM(((PyObject *)driver_orig->expr_comp), 1, expr_vars);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-11 20:00:03 +02:00
|
|
|
for (dvar = driver_orig->variables.first, i = 0; dvar; dvar = dvar->next) {
|
2011-06-05 08:18:37 +00:00
|
|
|
PyTuple_SET_ITEM(expr_vars, i++, PyUnicode_FromString(dvar->name));
|
2010-01-05 10:54:54 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-11 20:00:03 +02:00
|
|
|
driver_orig->flag &= ~DRIVER_FLAG_RENAMEVAR;
|
2010-01-05 10:54:54 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2018-06-11 20:00:03 +02:00
|
|
|
expr_vars = PyTuple_GET_ITEM(((PyObject *)driver_orig->expr_comp), 1);
|
2010-01-05 10:54:54 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-15 15:17:55 +11:00
|
|
|
/* Add target values to a dict that will be used as `__locals__` dict. */
|
2016-07-31 17:22:04 +10:00
|
|
|
driver_vars = _PyDict_NewPresized(PyTuple_GET_SIZE(expr_vars));
|
2011-12-26 12:26:11 +00:00
|
|
|
for (dvar = driver->variables.first, i = 0; dvar; dvar = dvar->next) {
|
|
|
|
|
PyObject *driver_arg = NULL;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-15 15:17:55 +11:00
|
|
|
/* Support for any RNA data. */
|
2016-04-05 07:02:43 +10:00
|
|
|
#ifdef USE_RNA_AS_PYOBJECT
|
|
|
|
|
if (dvar->type == DVAR_TYPE_SINGLE_PROP) {
|
Drivers: Introduce the Context Properties
Drivers: Introduce the Context Properties
The goal: allow accessing context dependent data, such as active scene camera
without linking to a specific scene data-block. This is useful in cases when,
for example, geometry node setup needs to be aware of the camera position.
A possible work-around without changes like this is to have some scene
evaluation hook which will update driver variables for the currently evaluating
scene. But this raises an issue of linking: it is undesirable that the asset
scene is linked to the shot file.
Surely, it is possible to have post-evaluation handler to clear the variables,
but it all starts to be quite messy. Not to mention possible threading
conflicts.
Another possibility of introducing a way to achieve the goal is to make it so
the dependency graph somehow parses the python expression where artists can
(and already are trying to) type something like:
depsgraph.scene.camera.matrix_world.col[3][0]
But this is not only tricky to implement properly and reliably, it hits two
limitations:
- Currently dependency graph can only easily resolve dependencies to a RNA
property.
- Some properties access which are valid in Python are not considered valid
RNA properties by the existing property resolution functions:
`camera.matrix_world[3][0]` is a valid RNA property, but
`camera.matrix_world.col[3][0]` is not.
Using driver variables allows to have visual feedback when the path resolution
fails, and there is no way to visualize errors in the python expression itself.
This change introduces the new variable type: Context Property. Using this
variable type makes allows to choose between Active Scene and Active View
Layer. These scene and view layer are resolved during the driver evaluation
time, based on the current dependency graph.
This allows to create a driver variable in the following configuration:
- Type: Context Property
- Context Property: Active Scene
- Path: camera.matrix_world[3][0]
The naming is a bit confusing. Tried my best to keep it clear keeping two
aspects in mind: using UI naming when possible, and follow the existing
naming.
A lot of the changes are related on making it so the required data is available
from the variable evaluation functions. It wasn't really clear what the data
would be, and the scope of the changes, so it is done together with the
functional changes.
It seems that there is some variable evaluation logic duplicated in the
`bpy_rna_driver.c`. This change does not change it. It is not really clear why
this separate code path with much more limited scope of supported target types
is even needed.
There is also a possible change in the behavior of the dependency graph: it
is now using ID of the resolved path when building driver variables. It used
to use the variable ID. In common cases they match, but when going into nested
data-blocks it is actually correct to use relation to the resolved ID. Not sure
if there was some code to ensure that, which now can be resolved. Also not sure
whether it is still needed to ensure the ID specified in the driver target is
build as well. Intuitively it is not needed.
Pull Request #105132
2023-03-06 16:01:47 +01:00
|
|
|
driver_arg = pyrna_driver_get_variable_value(
|
|
|
|
|
anim_eval_context, driver, dvar, &dvar->targets[0]);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-04-05 07:02:43 +10:00
|
|
|
if (driver_arg == NULL) {
|
|
|
|
|
driver_arg = PyFloat_FromDouble(0.0);
|
2016-04-25 15:25:32 +10:00
|
|
|
dvar->curval = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2022-03-15 15:17:55 +11:00
|
|
|
/* No need to worry about overflow here, values from RNA are within limits. */
|
2016-04-25 15:25:32 +10:00
|
|
|
if (PyFloat_CheckExact(driver_arg)) {
|
|
|
|
|
dvar->curval = (float)PyFloat_AsDouble(driver_arg);
|
|
|
|
|
}
|
|
|
|
|
else if (PyLong_CheckExact(driver_arg)) {
|
|
|
|
|
dvar->curval = (float)PyLong_AsLong(driver_arg);
|
|
|
|
|
}
|
|
|
|
|
else if (PyBool_Check(driver_arg)) {
|
|
|
|
|
dvar->curval = (driver_arg == Py_True);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
dvar->curval = 0.0f;
|
|
|
|
|
}
|
2016-04-05 07:02:43 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
{
|
2022-03-15 15:17:55 +11:00
|
|
|
/* Try to get variable value. */
|
Drivers: Introduce the Context Properties
Drivers: Introduce the Context Properties
The goal: allow accessing context dependent data, such as active scene camera
without linking to a specific scene data-block. This is useful in cases when,
for example, geometry node setup needs to be aware of the camera position.
A possible work-around without changes like this is to have some scene
evaluation hook which will update driver variables for the currently evaluating
scene. But this raises an issue of linking: it is undesirable that the asset
scene is linked to the shot file.
Surely, it is possible to have post-evaluation handler to clear the variables,
but it all starts to be quite messy. Not to mention possible threading
conflicts.
Another possibility of introducing a way to achieve the goal is to make it so
the dependency graph somehow parses the python expression where artists can
(and already are trying to) type something like:
depsgraph.scene.camera.matrix_world.col[3][0]
But this is not only tricky to implement properly and reliably, it hits two
limitations:
- Currently dependency graph can only easily resolve dependencies to a RNA
property.
- Some properties access which are valid in Python are not considered valid
RNA properties by the existing property resolution functions:
`camera.matrix_world[3][0]` is a valid RNA property, but
`camera.matrix_world.col[3][0]` is not.
Using driver variables allows to have visual feedback when the path resolution
fails, and there is no way to visualize errors in the python expression itself.
This change introduces the new variable type: Context Property. Using this
variable type makes allows to choose between Active Scene and Active View
Layer. These scene and view layer are resolved during the driver evaluation
time, based on the current dependency graph.
This allows to create a driver variable in the following configuration:
- Type: Context Property
- Context Property: Active Scene
- Path: camera.matrix_world[3][0]
The naming is a bit confusing. Tried my best to keep it clear keeping two
aspects in mind: using UI naming when possible, and follow the existing
naming.
A lot of the changes are related on making it so the required data is available
from the variable evaluation functions. It wasn't really clear what the data
would be, and the scope of the changes, so it is done together with the
functional changes.
It seems that there is some variable evaluation logic duplicated in the
`bpy_rna_driver.c`. This change does not change it. It is not really clear why
this separate code path with much more limited scope of supported target types
is even needed.
There is also a possible change in the behavior of the dependency graph: it
is now using ID of the resolved path when building driver variables. It used
to use the variable ID. In common cases they match, but when going into nested
data-blocks it is actually correct to use relation to the resolved ID. Not sure
if there was some code to ensure that, which now can be resolved. Also not sure
whether it is still needed to ensure the ID specified in the driver target is
build as well. Intuitively it is not needed.
Pull Request #105132
2023-03-06 16:01:47 +01:00
|
|
|
const float tval = driver_get_variable_value(anim_eval_context, driver, dvar);
|
2016-04-05 07:02:43 +10:00
|
|
|
driver_arg = PyFloat_FromDouble((double)tval);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-15 15:17:55 +11:00
|
|
|
/* Try to add to dictionary. */
|
|
|
|
|
/* `if (PyDict_SetItemString(driver_vars, dvar->name, driver_arg)) {` */
|
2016-07-14 17:28:28 +10:00
|
|
|
if (PyDict_SetItem(driver_vars, PyTuple_GET_ITEM(expr_vars, i++), driver_arg) != -1) {
|
2022-03-15 15:03:27 +11:00
|
|
|
/* Pass. */
|
2016-07-14 17:28:28 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2022-03-15 15:17:55 +11:00
|
|
|
/* This target failed - bad name. */
|
2009-12-08 22:35:03 +00:00
|
|
|
if (targets_ok) {
|
2022-03-15 15:17:55 +11:00
|
|
|
/* First one, print some extra info for easier identification. */
|
2022-07-07 12:30:44 +10:00
|
|
|
fprintf(stderr, "\n%s: Error while evaluating PyDriver:\n", __func__);
|
|
|
|
|
targets_ok = false;
|
2009-12-08 22:35:03 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-07-07 12:30:44 +10:00
|
|
|
fprintf(stderr, "\t%s: couldn't add variable '%s' to namespace\n", __func__, dvar->name);
|
2021-07-03 23:08:40 +10:00
|
|
|
// BPy_errors_to_report(NULL); /* TODO: reports. */
|
2009-12-09 14:25:56 +00:00
|
|
|
PyErr_Print();
|
|
|
|
|
PyErr_Clear();
|
2009-12-08 22:35:03 +00:00
|
|
|
}
|
2022-03-15 15:03:27 +11:00
|
|
|
Py_DECREF(driver_arg);
|
2009-12-08 22:35:03 +00:00
|
|
|
}
|
|
|
|
|
|
2018-06-17 19:51:05 +02:00
|
|
|
#ifdef USE_BYTECODE_WHITELIST
|
2018-09-16 10:46:28 +03:00
|
|
|
if (is_recompile && expr_code) {
|
2019-02-02 13:39:51 +11:00
|
|
|
if (!(G.f & G_FLAG_SCRIPT_AUTOEXEC)) {
|
2022-07-12 16:05:13 +10:00
|
|
|
if (!BPY_driver_secure_bytecode_test_ex(
|
|
|
|
|
expr_code,
|
|
|
|
|
(PyObject *[]){
|
|
|
|
|
bpy_pydriver_Dict,
|
|
|
|
|
bpy_pydriver_Dict__whitelist,
|
|
|
|
|
driver_vars,
|
|
|
|
|
NULL,
|
|
|
|
|
},
|
|
|
|
|
/* Always be verbose since this can give hints to why evaluation fails. */
|
|
|
|
|
true,
|
|
|
|
|
__func__))
|
|
|
|
|
{
|
2019-03-26 03:57:39 +01:00
|
|
|
if (!(G.f & G_FLAG_SCRIPT_AUTOEXEC_FAIL_QUIET)) {
|
|
|
|
|
G.f |= G_FLAG_SCRIPT_AUTOEXEC_FAIL;
|
2023-05-09 12:50:37 +10:00
|
|
|
SNPRINTF(G.autoexec_fail, "Driver '%s'", expr);
|
2019-03-26 03:57:39 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-17 19:51:05 +02:00
|
|
|
Py_DECREF(expr_code);
|
|
|
|
|
expr_code = NULL;
|
2018-06-18 15:09:55 +02:00
|
|
|
PyTuple_SET_ITEM(((PyObject *)driver_orig->expr_comp), 0, NULL);
|
2018-06-17 19:51:05 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif /* USE_BYTECODE_WHITELIST */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-15 09:11:17 +00:00
|
|
|
#if 0 /* slow, with this can avoid all Py_CompileString above. */
|
2009-12-08 22:35:03 +00:00
|
|
|
/* execute expression to get a value */
|
2011-12-26 12:26:11 +00:00
|
|
|
retval = PyRun_String(expr, Py_eval_input, bpy_pydriver_Dict, driver_vars);
|
2009-12-08 22:35:03 +00:00
|
|
|
#else
|
2022-03-15 15:17:55 +11:00
|
|
|
/* Evaluate the compiled expression. */
|
2019-03-30 06:12:48 +11:00
|
|
|
if (expr_code) {
|
2011-12-26 12:26:11 +00:00
|
|
|
retval = PyEval_EvalCode((void *)expr_code, bpy_pydriver_Dict, driver_vars);
|
2019-03-30 06:12:48 +11:00
|
|
|
}
|
2009-12-08 22:35:03 +00:00
|
|
|
#endif
|
|
|
|
|
|
2022-03-15 15:17:55 +11:00
|
|
|
/* Decref the driver variables first. */
|
2009-12-08 22:35:03 +00:00
|
|
|
Py_DECREF(driver_vars);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-15 15:17:55 +11:00
|
|
|
/* Process the result. */
|
2009-12-08 22:35:03 +00:00
|
|
|
if (retval == NULL) {
|
2022-07-07 12:30:47 +10:00
|
|
|
pydriver_error(driver, anim_rna);
|
2011-03-19 11:12:48 +00:00
|
|
|
}
|
2010-02-23 17:56:45 +00:00
|
|
|
else {
|
2022-07-07 12:30:44 +10:00
|
|
|
if (UNLIKELY((result = PyFloat_AsDouble(retval)) == -1.0 && PyErr_Occurred())) {
|
2022-07-07 12:30:47 +10:00
|
|
|
pydriver_error(driver, anim_rna);
|
2022-03-15 15:06:25 +11:00
|
|
|
result = 0.0;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2022-03-15 15:17:55 +11:00
|
|
|
/* All fine, make sure the "invalid expression" flag is cleared. */
|
2022-03-15 15:06:25 +11:00
|
|
|
driver->flag &= ~DRIVER_FLAG_INVALID;
|
|
|
|
|
}
|
2010-02-23 17:56:45 +00:00
|
|
|
Py_DECREF(retval);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-03-30 06:12:48 +11:00
|
|
|
if (use_gil) {
|
2010-05-18 14:38:25 +00:00
|
|
|
PyGILState_Release(gilstate);
|
2019-03-30 06:12:48 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-07-07 12:30:44 +10:00
|
|
|
if (UNLIKELY(!isfinite(result))) {
|
|
|
|
|
fprintf(stderr, "\t%s: driver '%s' evaluates to '%f'\n", __func__, driver->expression, result);
|
|
|
|
|
return 0.0f;
|
2010-03-22 09:30:00 +00:00
|
|
|
}
|
2020-08-07 12:41:06 +02:00
|
|
|
|
2022-07-07 12:30:44 +10:00
|
|
|
return (float)result;
|
2009-12-08 22:35:03 +00:00
|
|
|
}
|