Merged changes in the trunk up to revision 25508.
This commit is contained in:
@@ -32,8 +32,6 @@
|
||||
|
||||
#include "BKE_global.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#define MAX_ARRAY_DIMENSION 10
|
||||
|
||||
typedef void (*ItemConvertFunc)(PyObject *, char *);
|
||||
@@ -258,7 +256,7 @@ static int py_to_array(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, char *p
|
||||
|
||||
if (totitem) {
|
||||
if (!param_data || RNA_property_flag(prop) & PROP_DYNAMIC)
|
||||
data= MEM_callocN(item_size * totitem, "pyrna primitive type array");
|
||||
data= PyMem_MALLOC(item_size * totitem);
|
||||
else
|
||||
data= param_data;
|
||||
|
||||
@@ -273,7 +271,7 @@ static int py_to_array(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, char *p
|
||||
else {
|
||||
/* NULL can only pass through in case RNA property arraylength is 0 (impossible?) */
|
||||
rna_set_array(ptr, prop, data);
|
||||
MEM_freeN(data);
|
||||
PyMem_FREE(data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -513,3 +511,94 @@ PyObject *pyrna_py_from_array(PointerRNA *ptr, PropertyRNA *prop)
|
||||
|
||||
return pyrna_prop_CreatePyObject(ptr, prop);
|
||||
}
|
||||
|
||||
/* TODO, multi-dimensional arrays */
|
||||
int pyrna_array_contains_py(PointerRNA *ptr, PropertyRNA *prop, PyObject *value)
|
||||
{
|
||||
int len= RNA_property_array_length(ptr, prop);
|
||||
int type;
|
||||
int i;
|
||||
|
||||
if(len==0) /* possible with dynamic arrays */
|
||||
return 0;
|
||||
|
||||
if (RNA_property_array_dimension(ptr, prop, NULL) > 1) {
|
||||
PyErr_SetString(PyExc_TypeError, "PropertyRNA - multi dimensional arrays not supported yet");
|
||||
return -1;
|
||||
}
|
||||
|
||||
type= RNA_property_type(prop);
|
||||
|
||||
switch (type) {
|
||||
case PROP_FLOAT:
|
||||
{
|
||||
float value_f= PyFloat_AsDouble(value);
|
||||
if(value_f==-1 && PyErr_Occurred()) {
|
||||
PyErr_Clear();
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
float tmp[32];
|
||||
float *tmp_arr;
|
||||
|
||||
if(len * sizeof(float) > sizeof(tmp)) {
|
||||
tmp_arr= PyMem_MALLOC(len * sizeof(float));
|
||||
}
|
||||
else {
|
||||
tmp_arr= tmp;
|
||||
}
|
||||
|
||||
RNA_property_float_get_array(ptr, prop, tmp_arr);
|
||||
|
||||
for(i=0; i<len; i++)
|
||||
if(tmp_arr[i] == value_f)
|
||||
break;
|
||||
|
||||
if(tmp_arr != tmp)
|
||||
PyMem_FREE(tmp_arr);
|
||||
|
||||
return i<len ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PROP_BOOLEAN:
|
||||
case PROP_INT:
|
||||
{
|
||||
int value_i= PyLong_AsSsize_t(value);
|
||||
if(value_i==-1 && PyErr_Occurred()) {
|
||||
PyErr_Clear();
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
int tmp[32];
|
||||
int *tmp_arr;
|
||||
|
||||
if(len * sizeof(int) > sizeof(tmp)) {
|
||||
tmp_arr= PyMem_MALLOC(len * sizeof(int));
|
||||
}
|
||||
else {
|
||||
tmp_arr= tmp;
|
||||
}
|
||||
|
||||
if(type==PROP_BOOLEAN)
|
||||
RNA_property_boolean_get_array(ptr, prop, tmp_arr);
|
||||
else
|
||||
RNA_property_int_get_array(ptr, prop, tmp_arr);
|
||||
|
||||
for(i=0; i<len; i++)
|
||||
if(tmp_arr[i] == value_i)
|
||||
break;
|
||||
|
||||
if(tmp_arr != tmp)
|
||||
PyMem_FREE(tmp_arr);
|
||||
|
||||
return i<len ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* should never reach this */
|
||||
PyErr_SetString(PyExc_TypeError, "PropertyRNA - type not in float/bool/int");
|
||||
return -1;
|
||||
}
|
||||
|
||||
239
source/blender/python/intern/bpy_driver.c
Normal file
239
source/blender/python/intern/bpy_driver.c
Normal file
@@ -0,0 +1,239 @@
|
||||
/**
|
||||
* $Id:
|
||||
*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Contributor(s): Willian P. Germano, Campbell Barton
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
/* ****************************************** */
|
||||
/* Drivers - PyExpression Evaluation */
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
|
||||
#include "BPY_extern.h"
|
||||
#include "BKE_fcurve.h"
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
/* for pydrivers (drivers using one-line Python expressions to express relationships between targets) */
|
||||
PyObject *bpy_pydriver_Dict = NULL;
|
||||
|
||||
/* For faster execution we keep a special dictionary for pydrivers, with
|
||||
* the needed modules and aliases.
|
||||
*/
|
||||
static int bpy_pydriver_create_dict(void)
|
||||
{
|
||||
PyObject *d, *mod;
|
||||
|
||||
/* validate namespace for driver evaluation */
|
||||
if (bpy_pydriver_Dict) return -1;
|
||||
|
||||
d = PyDict_New();
|
||||
if (d == NULL)
|
||||
return -1;
|
||||
else
|
||||
bpy_pydriver_Dict = d;
|
||||
|
||||
/* import some modules: builtins, bpy, math, (Blender.noise )*/
|
||||
PyDict_SetItemString(d, "__builtins__", PyEval_GetBuiltins());
|
||||
|
||||
mod = PyImport_ImportModule("math");
|
||||
if (mod) {
|
||||
PyDict_Merge(d, PyModule_GetDict(mod), 0); /* 0 - dont overwrite existing values */
|
||||
|
||||
/* Only keep for backwards compat! - just import all math into root, they are standard */
|
||||
PyDict_SetItemString(d, "math", mod);
|
||||
PyDict_SetItemString(d, "m", mod);
|
||||
Py_DECREF(mod);
|
||||
}
|
||||
|
||||
/* add bpy to global namespace */
|
||||
mod= PyImport_ImportModuleLevel("bpy", NULL, NULL, NULL, 0);
|
||||
if (mod) {
|
||||
PyDict_SetItemString(bpy_pydriver_Dict, "bpy", mod);
|
||||
Py_DECREF(mod);
|
||||
}
|
||||
|
||||
|
||||
#if 0 // non existant yet
|
||||
mod = PyImport_ImportModule("Blender.Noise");
|
||||
if (mod) {
|
||||
PyDict_SetItemString(d, "noise", mod);
|
||||
PyDict_SetItemString(d, "n", mod);
|
||||
Py_DECREF(mod);
|
||||
} else {
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
/* If there's a Blender text called pydrivers.py, import it.
|
||||
* Users can add their own functions to this module.
|
||||
*/
|
||||
if (G.f & G_DOSCRIPTLINKS) {
|
||||
mod = importText("pydrivers"); /* can also use PyImport_Import() */
|
||||
if (mod) {
|
||||
PyDict_SetItemString(d, "pydrivers", mod);
|
||||
PyDict_SetItemString(d, "p", mod);
|
||||
Py_DECREF(mod);
|
||||
} else {
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
#endif // non existant yet
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Update function, it gets rid of pydrivers global dictionary, forcing
|
||||
* BPY_pydriver_eval to recreate it. This function is used to force
|
||||
* reloading the Blender text module "pydrivers.py", if available, so
|
||||
* updates in it reach pydriver evaluation.
|
||||
*/
|
||||
void BPY_pydriver_update(void)
|
||||
{
|
||||
PyGILState_STATE gilstate = PyGILState_Ensure();
|
||||
|
||||
if (bpy_pydriver_Dict) { /* free the global dict used by pydrivers */
|
||||
PyDict_Clear(bpy_pydriver_Dict);
|
||||
Py_DECREF(bpy_pydriver_Dict);
|
||||
bpy_pydriver_Dict = NULL;
|
||||
}
|
||||
|
||||
PyGILState_Release(gilstate);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* error return function for BPY_eval_pydriver */
|
||||
static float pydriver_error(ChannelDriver *driver)
|
||||
{
|
||||
if (bpy_pydriver_Dict) { /* free the global dict used by pydrivers */
|
||||
PyDict_Clear(bpy_pydriver_Dict);
|
||||
Py_DECREF(bpy_pydriver_Dict);
|
||||
bpy_pydriver_Dict = NULL;
|
||||
}
|
||||
|
||||
driver->flag |= DRIVER_FLAG_INVALID; /* py expression failed */
|
||||
fprintf(stderr, "\nError in Driver: The following Python expression failed:\n\t'%s'\n\n", driver->expression);
|
||||
|
||||
// BPy_errors_to_report(NULL); // TODO - reports
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/* This evals py driver expressions, 'expr' is a Python expression that
|
||||
* should evaluate to a float number, which is returned.
|
||||
*/
|
||||
float BPY_pydriver_eval (ChannelDriver *driver)
|
||||
{
|
||||
PyObject *driver_vars=NULL;
|
||||
PyObject *retval= NULL;
|
||||
PyGILState_STATE gilstate;
|
||||
|
||||
DriverTarget *dtar;
|
||||
float result = 0.0f; /* default return */
|
||||
char *expr = NULL;
|
||||
short targets_ok= 1;
|
||||
|
||||
/* sanity checks - should driver be executed? */
|
||||
if ((driver == NULL) /*|| (G.f & G_DOSCRIPTLINKS)==0*/)
|
||||
return result;
|
||||
|
||||
/* get the py expression to be evaluated */
|
||||
expr = driver->expression;
|
||||
if ((expr == NULL) || (expr[0]=='\0'))
|
||||
return result;
|
||||
|
||||
gilstate = PyGILState_Ensure();
|
||||
|
||||
/* init global dictionary for py-driver evaluation settings */
|
||||
if (!bpy_pydriver_Dict) {
|
||||
if (bpy_pydriver_create_dict() != 0) {
|
||||
fprintf(stderr, "Pydriver error: couldn't create Python dictionary");
|
||||
PyGILState_Release(gilstate);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/* add target values to a dict that will be used as '__locals__' dict */
|
||||
driver_vars = PyDict_New(); // XXX do we need to decref this?
|
||||
for (dtar= driver->targets.first; dtar; dtar= dtar->next) {
|
||||
PyObject *driver_arg = NULL;
|
||||
float tval = 0.0f;
|
||||
|
||||
/* try to get variable value */
|
||||
tval= driver_get_target_value(driver, dtar);
|
||||
driver_arg= PyFloat_FromDouble((double)tval);
|
||||
|
||||
/* try to add to dictionary */
|
||||
if (PyDict_SetItemString(driver_vars, dtar->name, driver_arg)) {
|
||||
/* this target failed - bad name */
|
||||
if (targets_ok) {
|
||||
/* first one - print some extra info for easier identification */
|
||||
fprintf(stderr, "\nBPY_pydriver_eval() - Error while evaluating PyDriver:\n");
|
||||
targets_ok= 0;
|
||||
}
|
||||
|
||||
fprintf(stderr, "\tBPY_pydriver_eval() - couldn't add variable '%s' to namespace \n", dtar->name);
|
||||
// BPy_errors_to_report(NULL); // TODO - reports
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 // slow
|
||||
/* execute expression to get a value */
|
||||
retval = PyRun_String(expr, Py_eval_input, bpy_pydriver_Dict, driver_vars);
|
||||
#else
|
||||
if(driver->flag & DRIVER_FLAG_RECOMPILE || driver->expr_comp==NULL) {
|
||||
Py_XDECREF(driver->expr_comp);
|
||||
driver->expr_comp= Py_CompileString(expr, "<bpy driver>", Py_eval_input);
|
||||
driver->flag &= ~DRIVER_FLAG_RECOMPILE;
|
||||
}
|
||||
if(driver->expr_comp)
|
||||
retval= PyEval_EvalCode(driver->expr_comp, bpy_pydriver_Dict, driver_vars);
|
||||
#endif
|
||||
|
||||
/* decref the driver vars first... */
|
||||
Py_DECREF(driver_vars);
|
||||
|
||||
/* process the result */
|
||||
if (retval == NULL) {
|
||||
result = pydriver_error(driver);
|
||||
PyGILState_Release(gilstate);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = (float)PyFloat_AsDouble(retval);
|
||||
Py_DECREF(retval);
|
||||
|
||||
if ((result == -1) && PyErr_Occurred()) {
|
||||
result = pydriver_error(driver);
|
||||
PyGILState_Release(gilstate);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* all fine, make sure the "invalid expression" flag is cleared */
|
||||
driver->flag &= ~DRIVER_FLAG_INVALID;
|
||||
|
||||
PyGILState_Release(gilstate);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -49,19 +49,17 @@
|
||||
#include "BLI_winstuff.h"
|
||||
#endif
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_space_types.h"
|
||||
#include "DNA_text_types.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_util.h"
|
||||
#include "BLI_path_util.h"
|
||||
#include "BLI_storage.h"
|
||||
#include "BLI_fileops.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_fcurve.h"
|
||||
#include "BKE_text.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_global.h"
|
||||
@@ -79,7 +77,6 @@
|
||||
#include "../generic/BGL.h"
|
||||
#include "../generic/IDProp.h"
|
||||
|
||||
|
||||
/* for internal use, when starting and ending python scripts */
|
||||
|
||||
/* incase a python script triggers another python call, stop bpy_context_clear from invalidating */
|
||||
@@ -283,6 +280,14 @@ void BPY_start_python_path(void)
|
||||
/* set the environment path */
|
||||
printf("found bundled python: %s\n", py_path_bundle);
|
||||
|
||||
#ifdef __APPLE__
|
||||
/* OSX allow file/directory names to contain : character (represented as / in the Finder)
|
||||
but current Python lib (release 3.1.1) doesn't handle these correctly */
|
||||
if(strchr(py_path_bundle, ':'))
|
||||
printf("Warning : Blender application is located in a path containing : or / chars\
|
||||
\nThis may make python import function fail\n");
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
BLI_setenv("PYTHONHOME", py_path_bundle);
|
||||
BLI_setenv("PYTHONPATH", py_path_bundle);
|
||||
@@ -316,11 +321,25 @@ void BPY_start_python( int argc, char **argv )
|
||||
/* sigh, why do python guys not have a char** version anymore? :( */
|
||||
{
|
||||
int i;
|
||||
#if 0
|
||||
PyObject *py_argv= PyList_New(argc);
|
||||
|
||||
for (i=0; i<argc; i++)
|
||||
PyList_SET_ITEM(py_argv, i, PyUnicode_FromString(argv[i]));
|
||||
|
||||
#else // should fix bug #20021 - utf path name problems
|
||||
PyObject *py_argv= PyList_New(0);
|
||||
for (i=0; i<argc; i++) {
|
||||
PyObject *item= PyUnicode_Decode(argv[i], strlen(argv[i]), Py_FileSystemDefaultEncoding, NULL);
|
||||
if(item==NULL) { // should never happen
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
else {
|
||||
PyList_Append(py_argv, item);
|
||||
Py_DECREF(item);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
PySys_SetObject("argv", py_argv);
|
||||
Py_DECREF(py_argv);
|
||||
}
|
||||
@@ -538,7 +557,9 @@ int BPY_run_script_space_listener(bContext *C, SpaceScript * sc)
|
||||
|
||||
void BPY_DECREF(void *pyob_ptr)
|
||||
{
|
||||
PyGILState_STATE gilstate = PyGILState_Ensure();
|
||||
Py_DECREF((PyObject *)pyob_ptr);
|
||||
PyGILState_Release(gilstate);
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -596,201 +617,6 @@ int BPY_run_python_script_space(const char *modulename, const char *func)
|
||||
#include "PIL_time.h"
|
||||
#endif
|
||||
|
||||
/* ****************************************** */
|
||||
/* Drivers - PyExpression Evaluation */
|
||||
|
||||
/* for pydrivers (drivers using one-line Python expressions to express relationships between targets) */
|
||||
PyObject *bpy_pydriver_Dict = NULL;
|
||||
|
||||
/* For faster execution we keep a special dictionary for pydrivers, with
|
||||
* the needed modules and aliases.
|
||||
*/
|
||||
static int bpy_pydriver_create_dict(void)
|
||||
{
|
||||
PyObject *d, *mod;
|
||||
|
||||
/* validate namespace for driver evaluation */
|
||||
if (bpy_pydriver_Dict) return -1;
|
||||
|
||||
d = PyDict_New();
|
||||
if (d == NULL)
|
||||
return -1;
|
||||
else
|
||||
bpy_pydriver_Dict = d;
|
||||
|
||||
/* import some modules: builtins, bpy, math, (Blender.noise )*/
|
||||
PyDict_SetItemString(d, "__builtins__", PyEval_GetBuiltins());
|
||||
|
||||
mod = PyImport_ImportModule("math");
|
||||
if (mod) {
|
||||
PyDict_Merge(d, PyModule_GetDict(mod), 0); /* 0 - dont overwrite existing values */
|
||||
|
||||
/* Only keep for backwards compat! - just import all math into root, they are standard */
|
||||
PyDict_SetItemString(d, "math", mod);
|
||||
PyDict_SetItemString(d, "m", mod);
|
||||
Py_DECREF(mod);
|
||||
}
|
||||
|
||||
/* add bpy to global namespace */
|
||||
mod= PyImport_ImportModuleLevel("bpy", NULL, NULL, NULL, 0);
|
||||
if (mod) {
|
||||
PyDict_SetItemString(bpy_pydriver_Dict, "bpy", mod);
|
||||
Py_DECREF(mod);
|
||||
}
|
||||
|
||||
|
||||
#if 0 // non existant yet
|
||||
mod = PyImport_ImportModule("Blender.Noise");
|
||||
if (mod) {
|
||||
PyDict_SetItemString(d, "noise", mod);
|
||||
PyDict_SetItemString(d, "n", mod);
|
||||
Py_DECREF(mod);
|
||||
} else {
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
/* If there's a Blender text called pydrivers.py, import it.
|
||||
* Users can add their own functions to this module.
|
||||
*/
|
||||
if (G.f & G_DOSCRIPTLINKS) {
|
||||
mod = importText("pydrivers"); /* can also use PyImport_Import() */
|
||||
if (mod) {
|
||||
PyDict_SetItemString(d, "pydrivers", mod);
|
||||
PyDict_SetItemString(d, "p", mod);
|
||||
Py_DECREF(mod);
|
||||
} else {
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
#endif // non existant yet
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Update function, it gets rid of pydrivers global dictionary, forcing
|
||||
* BPY_pydriver_eval to recreate it. This function is used to force
|
||||
* reloading the Blender text module "pydrivers.py", if available, so
|
||||
* updates in it reach pydriver evaluation.
|
||||
*/
|
||||
void BPY_pydriver_update(void)
|
||||
{
|
||||
PyGILState_STATE gilstate = PyGILState_Ensure();
|
||||
|
||||
if (bpy_pydriver_Dict) { /* free the global dict used by pydrivers */
|
||||
PyDict_Clear(bpy_pydriver_Dict);
|
||||
Py_DECREF(bpy_pydriver_Dict);
|
||||
bpy_pydriver_Dict = NULL;
|
||||
}
|
||||
|
||||
PyGILState_Release(gilstate);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* error return function for BPY_eval_pydriver */
|
||||
static float pydriver_error(ChannelDriver *driver)
|
||||
{
|
||||
if (bpy_pydriver_Dict) { /* free the global dict used by pydrivers */
|
||||
PyDict_Clear(bpy_pydriver_Dict);
|
||||
Py_DECREF(bpy_pydriver_Dict);
|
||||
bpy_pydriver_Dict = NULL;
|
||||
}
|
||||
|
||||
driver->flag |= DRIVER_FLAG_INVALID; /* py expression failed */
|
||||
fprintf(stderr, "\nError in Driver: The following Python expression failed:\n\t'%s'\n\n", driver->expression);
|
||||
|
||||
BPy_errors_to_report(NULL); // TODO - reports
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/* This evals py driver expressions, 'expr' is a Python expression that
|
||||
* should evaluate to a float number, which is returned.
|
||||
*/
|
||||
float BPY_pydriver_eval (ChannelDriver *driver)
|
||||
{
|
||||
PyObject *driver_vars=NULL;
|
||||
PyObject *retval;
|
||||
PyGILState_STATE gilstate;
|
||||
|
||||
DriverTarget *dtar;
|
||||
float result = 0.0f; /* default return */
|
||||
char *expr = NULL;
|
||||
short targets_ok= 1;
|
||||
|
||||
/* sanity checks - should driver be executed? */
|
||||
if ((driver == NULL) /*|| (G.f & G_DOSCRIPTLINKS)==0*/)
|
||||
return result;
|
||||
|
||||
/* get the py expression to be evaluated */
|
||||
expr = driver->expression;
|
||||
if ((expr == NULL) || (expr[0]=='\0'))
|
||||
return result;
|
||||
|
||||
gilstate = PyGILState_Ensure();
|
||||
|
||||
/* init global dictionary for py-driver evaluation settings */
|
||||
if (!bpy_pydriver_Dict) {
|
||||
if (bpy_pydriver_create_dict() != 0) {
|
||||
fprintf(stderr, "Pydriver error: couldn't create Python dictionary");
|
||||
PyGILState_Release(gilstate);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/* add target values to a dict that will be used as '__locals__' dict */
|
||||
driver_vars = PyDict_New(); // XXX do we need to decref this?
|
||||
for (dtar= driver->targets.first; dtar; dtar= dtar->next) {
|
||||
PyObject *driver_arg = NULL;
|
||||
float tval = 0.0f;
|
||||
|
||||
/* try to get variable value */
|
||||
tval= driver_get_target_value(driver, dtar);
|
||||
driver_arg= PyFloat_FromDouble((double)tval);
|
||||
|
||||
/* try to add to dictionary */
|
||||
if (PyDict_SetItemString(driver_vars, dtar->name, driver_arg)) {
|
||||
/* this target failed - bad name */
|
||||
if (targets_ok) {
|
||||
/* first one - print some extra info for easier identification */
|
||||
fprintf(stderr, "\nBPY_pydriver_eval() - Error while evaluating PyDriver:\n");
|
||||
targets_ok= 0;
|
||||
}
|
||||
|
||||
fprintf(stderr, "\tBPY_pydriver_eval() - couldn't add variable '%s' to namespace \n", dtar->name);
|
||||
BPy_errors_to_report(NULL); // TODO - reports
|
||||
}
|
||||
}
|
||||
|
||||
/* execute expression to get a value */
|
||||
retval = PyRun_String(expr, Py_eval_input, bpy_pydriver_Dict, driver_vars);
|
||||
|
||||
/* decref the driver vars first... */
|
||||
Py_DECREF(driver_vars);
|
||||
|
||||
/* process the result */
|
||||
if (retval == NULL) {
|
||||
result = pydriver_error(driver);
|
||||
PyGILState_Release(gilstate);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = (float)PyFloat_AsDouble(retval);
|
||||
Py_DECREF(retval);
|
||||
|
||||
if ((result == -1) && PyErr_Occurred()) {
|
||||
result = pydriver_error(driver);
|
||||
PyGILState_Release(gilstate);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* all fine, make sure the "invalid expression" flag is cleared */
|
||||
driver->flag &= ~DRIVER_FLAG_INVALID;
|
||||
|
||||
PyGILState_Release(gilstate);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int BPY_button_eval(bContext *C, char *expr, double *value)
|
||||
{
|
||||
|
||||
@@ -164,6 +164,7 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
|
||||
case PROP_VELOCITY:
|
||||
case PROP_ACCELERATION:
|
||||
case PROP_XYZ:
|
||||
case PROP_XYZ|PROP_UNIT_LENGTH:
|
||||
if(len>=2 && len <= 4) {
|
||||
PyObject *vec_cb= newVectorObject_cb(ret, len, mathutils_rna_array_cb_index, FALSE);
|
||||
Py_DECREF(ret); /* the vector owns now */
|
||||
@@ -379,6 +380,69 @@ static int pyrna_string_to_enum(PyObject *item, PointerRNA *ptr, PropertyRNA *pr
|
||||
return 1;
|
||||
}
|
||||
|
||||
static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val)
|
||||
{
|
||||
PyObject *item, *ret= NULL;
|
||||
|
||||
if(RNA_property_flag(prop) & PROP_ENUM_FLAG) {
|
||||
const char *identifier[RNA_ENUM_BITFLAG_SIZE + 1];
|
||||
|
||||
ret= PySet_New(NULL);
|
||||
|
||||
if (RNA_property_enum_bitflag_identifiers(BPy_GetContext(), ptr, prop, val, identifier)) {
|
||||
int index;
|
||||
|
||||
for(index=0; identifier[index]; index++) {
|
||||
item= PyUnicode_FromString(identifier[index]);
|
||||
PySet_Add(ret, item);
|
||||
Py_DECREF(item);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
const char *identifier;
|
||||
if (RNA_property_enum_identifier(BPy_GetContext(), ptr, prop, val, &identifier)) {
|
||||
ret = PyUnicode_FromString(identifier);
|
||||
} else {
|
||||
EnumPropertyItem *item;
|
||||
int free= FALSE;
|
||||
|
||||
/* don't throw error here, can't trust blender 100% to give the
|
||||
* right values, python code should not generate error for that */
|
||||
RNA_property_enum_items(BPy_GetContext(), ptr, prop, &item, NULL, &free);
|
||||
if(item && item->identifier) {
|
||||
ret= PyUnicode_FromString(item->identifier);
|
||||
}
|
||||
else {
|
||||
char *ptr_name= RNA_struct_name_get_alloc(ptr, NULL, FALSE);
|
||||
|
||||
/* prefer not fail silently incase of api errors, maybe disable it later */
|
||||
printf("RNA Warning: Current value \"%d\" matches no enum in '%s', '%s', '%s'\n", val, RNA_struct_identifier(ptr->type), ptr_name, RNA_property_identifier(prop));
|
||||
|
||||
#if 0 // gives python decoding errors while generating docs :(
|
||||
char error_str[256];
|
||||
snprintf(error_str, sizeof(error_str), "RNA Warning: Current value \"%d\" matches no enum in '%s', '%s', '%s'", val, RNA_struct_identifier(ptr->type), ptr_name, RNA_property_identifier(prop));
|
||||
PyErr_Warn(PyExc_RuntimeWarning, error_str);
|
||||
#endif
|
||||
|
||||
if(ptr_name)
|
||||
MEM_freeN(ptr_name);
|
||||
|
||||
ret = PyUnicode_FromString( "" );
|
||||
}
|
||||
|
||||
if(free)
|
||||
MEM_freeN(item);
|
||||
|
||||
/*PyErr_Format(PyExc_AttributeError, "RNA Error: Current value \"%d\" matches no enum", val);
|
||||
ret = NULL;*/
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
|
||||
{
|
||||
PyObject *ret;
|
||||
@@ -409,46 +473,7 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
|
||||
}
|
||||
case PROP_ENUM:
|
||||
{
|
||||
const char *identifier;
|
||||
int val = RNA_property_enum_get(ptr, prop);
|
||||
|
||||
if (RNA_property_enum_identifier(BPy_GetContext(), ptr, prop, val, &identifier)) {
|
||||
ret = PyUnicode_FromString( identifier );
|
||||
} else {
|
||||
EnumPropertyItem *item;
|
||||
int free= FALSE;
|
||||
|
||||
/* don't throw error here, can't trust blender 100% to give the
|
||||
* right values, python code should not generate error for that */
|
||||
RNA_property_enum_items(BPy_GetContext(), ptr, prop, &item, NULL, &free);
|
||||
if(item && item->identifier) {
|
||||
ret = PyUnicode_FromString( item->identifier );
|
||||
}
|
||||
else {
|
||||
char *ptr_name= RNA_struct_name_get_alloc(ptr, NULL, FALSE);
|
||||
|
||||
/* prefer not fail silently incase of api errors, maybe disable it later */
|
||||
printf("RNA Warning: Current value \"%d\" matches no enum in '%s', '%s', '%s'\n", val, RNA_struct_identifier(ptr->type), ptr_name, RNA_property_identifier(prop));
|
||||
|
||||
#if 0 // gives python decoding errors while generating docs :(
|
||||
char error_str[256];
|
||||
snprintf(error_str, sizeof(error_str), "RNA Warning: Current value \"%d\" matches no enum in '%s', '%s', '%s'", val, RNA_struct_identifier(ptr->type), ptr_name, RNA_property_identifier(prop));
|
||||
PyErr_Warn(PyExc_RuntimeWarning, error_str);
|
||||
#endif
|
||||
|
||||
if(ptr_name)
|
||||
MEM_freeN(ptr_name);
|
||||
|
||||
ret = PyUnicode_FromString( "" );
|
||||
}
|
||||
|
||||
if(free)
|
||||
MEM_freeN(item);
|
||||
|
||||
/*PyErr_Format(PyExc_AttributeError, "RNA Error: Current value \"%d\" matches no enum", val);
|
||||
ret = NULL;*/
|
||||
}
|
||||
|
||||
ret= pyrna_enum_to_py(ptr, prop, RNA_property_enum_get(ptr, prop));
|
||||
break;
|
||||
}
|
||||
case PROP_POINTER:
|
||||
@@ -534,7 +559,7 @@ int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, int all_args, const cha
|
||||
|
||||
static PyObject * pyrna_func_call(PyObject *self, PyObject *args, PyObject *kw);
|
||||
|
||||
PyObject *pyrna_func_to_py(BPy_DummyPointerRNA *pyrna, FunctionRNA *func)
|
||||
static PyObject *pyrna_func_to_py(BPy_DummyPointerRNA *pyrna, FunctionRNA *func)
|
||||
{
|
||||
static PyMethodDef func_meth = {"<generic rna function>", (PyCFunction)pyrna_func_call, METH_VARARGS|METH_KEYWORDS, "python rna function"};
|
||||
PyObject *self;
|
||||
@@ -559,6 +584,7 @@ PyObject *pyrna_func_to_py(BPy_DummyPointerRNA *pyrna, FunctionRNA *func)
|
||||
}
|
||||
|
||||
|
||||
|
||||
int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *value, const char *error_prefix)
|
||||
{
|
||||
/* XXX hard limits should be checked here */
|
||||
@@ -653,28 +679,36 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v
|
||||
}
|
||||
case PROP_ENUM:
|
||||
{
|
||||
int val, i;
|
||||
int val= 0, tmpval;
|
||||
|
||||
if (PyUnicode_Check(value)) {
|
||||
if (!pyrna_string_to_enum(value, ptr, prop, &val, error_prefix))
|
||||
return -1;
|
||||
}
|
||||
else if (PyTuple_Check(value)) {
|
||||
/* tuple of enum items, concatenate all values with OR */
|
||||
val= 0;
|
||||
for (i= 0; i < PyTuple_Size(value); i++) {
|
||||
int tmpval;
|
||||
else if (PyAnySet_Check(value)) {
|
||||
if(RNA_property_flag(prop) & PROP_ENUM_FLAG) {
|
||||
/* set of enum items, concatenate all values with OR */
|
||||
|
||||
/* PyTuple_GET_ITEM returns a borrowed reference */
|
||||
if (!pyrna_string_to_enum(PyTuple_GET_ITEM(value, i), ptr, prop, &tmpval, error_prefix))
|
||||
return -1;
|
||||
/* set looping */
|
||||
Py_ssize_t pos = 0;
|
||||
PyObject *key;
|
||||
long hash;
|
||||
|
||||
val |= tmpval;
|
||||
while (_PySet_NextEntry(value, &pos, &key, &hash)) {
|
||||
if (!pyrna_string_to_enum(key, ptr, prop, &tmpval, error_prefix))
|
||||
return -1;
|
||||
|
||||
val |= tmpval;
|
||||
}
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_TypeError, "%.200s, %.200s.%.200s is not a bitflag enum type", error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
char *enum_str= pyrna_enum_as_string(ptr, prop);
|
||||
PyErr_Format(PyExc_TypeError, "%.200s expected a string enum or a tuple of strings in (%.200s)", error_prefix, enum_str);
|
||||
PyErr_Format(PyExc_TypeError, "%.200s expected a string enum or a set of strings in (%.200s)", error_prefix, enum_str);
|
||||
MEM_freeN(enum_str);
|
||||
return -1;
|
||||
}
|
||||
@@ -1134,22 +1168,29 @@ static PyMappingMethods pyrna_prop_as_mapping = {
|
||||
static int pyrna_prop_contains(BPy_PropertyRNA *self, PyObject *value)
|
||||
{
|
||||
PointerRNA newptr; /* not used, just so RNA_property_collection_lookup_string runs */
|
||||
char *keyname = _PyUnicode_AsString(value);
|
||||
|
||||
if(keyname==NULL) {
|
||||
PyErr_SetString(PyExc_TypeError, "PropertyRNA - key in prop, key must be a string type");
|
||||
if (RNA_property_type(self->prop) == PROP_COLLECTION) {
|
||||
/* key in dict style check */
|
||||
char *keyname = _PyUnicode_AsString(value);
|
||||
|
||||
if(keyname==NULL) {
|
||||
PyErr_SetString(PyExc_TypeError, "PropertyRNA - key in prop, key must be a string type");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (RNA_property_collection_lookup_string(&self->ptr, self->prop, keyname, &newptr))
|
||||
return 1;
|
||||
}
|
||||
else if (RNA_property_array_check(&self->ptr, self->prop)) {
|
||||
/* value in list style check */
|
||||
return pyrna_array_contains_py(&self->ptr, self->prop, value);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError, "PropertyRNA - type is not an array or a collection");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (RNA_property_type(self->prop) != PROP_COLLECTION) {
|
||||
PyErr_SetString(PyExc_TypeError, "PropertyRNA - key in prop, is only valid for collection types");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (RNA_property_collection_lookup_string(&self->ptr, self->prop, keyname, &newptr))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1617,14 +1658,6 @@ static PyObject *pyrna_struct_dir(BPy_StructRNA *self)
|
||||
|
||||
BLI_freelistN(&lb);
|
||||
}
|
||||
|
||||
/* Hard coded names */
|
||||
if(self->ptr.id.data) {
|
||||
pystring = PyUnicode_FromString("id_data");
|
||||
PyList_Append(ret, pystring);
|
||||
Py_DECREF(pystring);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1691,17 +1724,6 @@ static PyObject *pyrna_struct_getattro( BPy_StructRNA *self, PyObject *pyname )
|
||||
|
||||
BLI_freelistN(&newlb);
|
||||
}
|
||||
else if (strcmp(name, "id_data")==0) { /* XXX - hard coded */
|
||||
if(self->ptr.id.data) {
|
||||
PointerRNA id_ptr;
|
||||
RNA_id_pointer_create((ID *)self->ptr.id.data, &id_ptr);
|
||||
ret = pyrna_struct_CreatePyObject(&id_ptr);
|
||||
}
|
||||
else {
|
||||
ret = Py_None;
|
||||
Py_INCREF(ret);
|
||||
}
|
||||
}
|
||||
else {
|
||||
#if 0
|
||||
PyErr_Format( PyExc_AttributeError, "StructRNA - Attribute \"%.200s\" not found", name);
|
||||
@@ -1873,6 +1895,17 @@ static PyObject *pyrna_prop_remove(BPy_PropertyRNA *self, PyObject *value)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PyObject *pyrna_struct_get_id_data(BPy_StructRNA *self)
|
||||
{
|
||||
if(self->ptr.id.data) {
|
||||
PointerRNA id_ptr;
|
||||
RNA_id_pointer_create((ID *)self->ptr.id.data, &id_ptr);
|
||||
return pyrna_struct_CreatePyObject(&id_ptr);
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Python attributes get/set structure: */
|
||||
/*****************************************************************************/
|
||||
@@ -1883,6 +1916,11 @@ static PyGetSetDef pyrna_prop_getseters[] = {
|
||||
};
|
||||
#endif
|
||||
|
||||
static PyGetSetDef pyrna_struct_getseters[] = {
|
||||
{"id_data", (getter)pyrna_struct_get_id_data, (setter)NULL, "The ID data this datablock is from, (not available for all data)", NULL},
|
||||
{NULL,NULL,NULL,NULL,NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyObject *pyrna_prop_keys(BPy_PropertyRNA *self)
|
||||
{
|
||||
PyObject *ret;
|
||||
@@ -2231,6 +2269,9 @@ static PyObject *foreach_getset(BPy_PropertyRNA *self, PyObject *args, int set)
|
||||
}
|
||||
}
|
||||
|
||||
if(array)
|
||||
PyMem_Free(array);
|
||||
|
||||
if(PyErr_Occurred()) {
|
||||
/* Maybe we could make our own error */
|
||||
PyErr_Print();
|
||||
@@ -2242,9 +2283,6 @@ static PyObject *foreach_getset(BPy_PropertyRNA *self, PyObject *args, int set)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(array)
|
||||
PyMem_Free(array);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
@@ -2422,22 +2460,7 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *data)
|
||||
}
|
||||
case PROP_ENUM:
|
||||
{
|
||||
const char *identifier;
|
||||
int val = *(int*)data;
|
||||
|
||||
if (RNA_property_enum_identifier(BPy_GetContext(), ptr, prop, val, &identifier)) {
|
||||
ret = PyUnicode_FromString( identifier );
|
||||
} else {
|
||||
/* prefer not fail silently incase of api errors, maybe disable it later */
|
||||
char error_str[128];
|
||||
sprintf(error_str, "RNA Warning: Current value \"%d\" matches no enum", val);
|
||||
PyErr_Warn(PyExc_RuntimeWarning, error_str);
|
||||
|
||||
ret = PyUnicode_FromString( "" );
|
||||
/*PyErr_Format(PyExc_AttributeError, "RNA Error: Current value \"%d\" matches no enum", val);
|
||||
ret = NULL;*/
|
||||
}
|
||||
|
||||
ret= pyrna_enum_to_py(ptr, prop, *(int*)data);
|
||||
break;
|
||||
}
|
||||
case PROP_POINTER:
|
||||
@@ -2645,6 +2668,9 @@ static PyObject * pyrna_func_call(PyObject *self, PyObject *args, PyObject *kw)
|
||||
RNA_parameter_list_begin(&parms, &iter);
|
||||
for(; iter.valid; RNA_parameter_list_next(&iter)) {
|
||||
parm= iter.parm;
|
||||
if(RNA_property_flag(parm) & PROP_RETURN)
|
||||
continue;
|
||||
|
||||
BLI_dynstr_appendf(good_args, first ? "%s" : ", %s", RNA_property_identifier(parm));
|
||||
first= FALSE;
|
||||
}
|
||||
@@ -2758,7 +2784,7 @@ PyTypeObject pyrna_struct_Type = {
|
||||
/*** Attribute descriptor and subclassing stuff ***/
|
||||
pyrna_struct_methods, /* struct PyMethodDef *tp_methods; */
|
||||
NULL, /* struct PyMemberDef *tp_members; */
|
||||
NULL, /* struct PyGetSetDef *tp_getset; */
|
||||
pyrna_struct_getseters, /* struct PyGetSetDef *tp_getset; */
|
||||
NULL, /* struct _typeobject *tp_base; */
|
||||
NULL, /* PyObject *tp_dict; */
|
||||
NULL, /* descrgetfunc tp_descr_get; */
|
||||
@@ -3690,11 +3716,15 @@ static int deferred_register_prop(StructRNA *srna, PyObject *item, PyObject *key
|
||||
if(PyTuple_CheckExact(item) && PyTuple_GET_SIZE(item)==2) {
|
||||
|
||||
PyObject *py_func_ptr, *py_kw, *py_srna_cobject, *py_ret;
|
||||
PyObject *(*pyfunc)(PyObject *, PyObject *, PyObject *);
|
||||
|
||||
if(PyArg_ParseTuple(item, "O!O!", &PyCObject_Type, &py_func_ptr, &PyDict_Type, &py_kw)) {
|
||||
|
||||
PyObject *(*pyfunc)(PyObject *, PyObject *, PyObject *);
|
||||
|
||||
if(*_PyUnicode_AsString(key)=='_') {
|
||||
PyErr_Format(PyExc_ValueError, "StructRNA \"%.200s\" registration error: %.200s could not register because the property starts with an '_'\n", RNA_struct_identifier(srna), _PyUnicode_AsString(key));
|
||||
Py_DECREF(dummy_args);
|
||||
return -1;
|
||||
}
|
||||
pyfunc = PyCObject_AsVoidPtr(py_func_ptr);
|
||||
py_srna_cobject = PyCObject_FromVoidPtr(srna, NULL);
|
||||
|
||||
|
||||
@@ -103,5 +103,6 @@ int pyrna_py_to_array_index(PointerRNA *ptr, PropertyRNA *prop, int arraydim, in
|
||||
PyObject *pyrna_py_from_array(PointerRNA *ptr, PropertyRNA *prop);
|
||||
PyObject *pyrna_py_from_array_index(BPy_PropertyRNA *self, int index);
|
||||
PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop);
|
||||
int pyrna_array_contains_py(PointerRNA *ptr, PropertyRNA *prop, PyObject *value);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -92,11 +92,13 @@ int BPY_flag_from_seq(BPY_flag_def *flagdef, PyObject *seq, int *flag)
|
||||
if(cstring) {
|
||||
fd= flagdef;
|
||||
while(fd->name) {
|
||||
if (strcmp(cstring, fd->name) == 0)
|
||||
if (strcmp(cstring, fd->name) == 0) {
|
||||
(*flag) |= fd->flag;
|
||||
break;
|
||||
}
|
||||
fd++;
|
||||
}
|
||||
if (fd==NULL) { /* could not find a match */
|
||||
if (fd->name==NULL) { /* could not find a match */
|
||||
error_val= 1;
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user