PyDriver support for all RNA property types

Support for driver variables that don't resolve to numbers, eg:
objects, bones, curves... etc.

Without this, Python expressions to access this data needed to use an absolute path from `bpy.data`,
however this is inconvenient, breaks easily (based on naming) and wouldn't set the dependencies correctly.
This commit is contained in:
Campbell Barton 2016-04-05 07:02:43 +10:00
parent 65f279b770
commit 82b0a9e369
Notes: blender-bot 2023-02-14 08:07:50 +01:00
Referenced by commit 3f90c11621, Fix T85318: Driver variable don't resolve collection indices
Referenced by issue #52213, Driver doesn't work with value from rollout
6 changed files with 204 additions and 6 deletions

View File

@ -99,6 +99,10 @@ void driver_variable_name_validate(struct DriverVar *dvar);
struct DriverVar *driver_add_new_variable(struct ChannelDriver *driver);
float driver_get_variable_value(struct ChannelDriver *driver, struct DriverVar *dvar);
bool driver_get_variable_property(
struct ChannelDriver *driver, struct DriverTarget *dtar,
struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index);
float evaluate_driver(struct ChannelDriver *driver, const float evaltime);
/* ************** F-Curve Modifiers *************** */

View File

@ -1151,6 +1151,71 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
return value;
}
/**
* Same as 'dtar_get_prop_val'. but get the RNA property.
*/
bool driver_get_variable_property(
ChannelDriver *driver, DriverTarget *dtar,
PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
{
PointerRNA id_ptr;
PointerRNA ptr;
PropertyRNA *prop;
ID *id;
int index = -1;
/* sanity check */
if (ELEM(NULL, driver, dtar))
return false;
id = dtar_id_ensure_proxy_from(dtar->id);
/* error check for missing pointer... */
if (id == NULL) {
if (G.debug & G_DEBUG) {
printf("Error: driver has an invalid target to use (path = %s)\n", dtar->rna_path);
}
driver->flag |= DRIVER_FLAG_INVALID;
dtar->flag |= DTAR_FLAG_INVALID;
return false;
}
/* get RNA-pointer for the ID-block given in target */
RNA_id_pointer_create(id, &id_ptr);
/* get property to read from, and get value as appropriate */
if (dtar->rna_path == NULL || dtar->rna_path[0] == '\0') {
ptr = PointerRNA_NULL;
prop = NULL; /* ok */
}
else if (RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
/* ok */
}
else {
/* path couldn't be resolved */
if (G.debug & G_DEBUG) {
printf("Driver Evaluation Error: cannot resolve target for %s -> %s\n", id->name, dtar->rna_path);
}
ptr = PointerRNA_NULL;
*r_prop = NULL;
*r_index = -1;
driver->flag |= DRIVER_FLAG_INVALID;
dtar->flag |= DTAR_FLAG_INVALID;
return false;
}
*r_ptr = ptr;
*r_prop = prop;
*r_index = index;
/* if we're still here, we should be ok... */
dtar->flag &= ~DTAR_FLAG_INVALID;
return true;
}
/* Helper function to obtain a pointer to a Pose Channel (for evaluating drivers) */
static bPoseChannel *dtar_get_pchan_ptr(ChannelDriver *driver, DriverTarget *dtar)
{

View File

@ -71,6 +71,7 @@ set(SRC
bpy_rna_anim.c
bpy_rna_array.c
bpy_rna_callback.c
bpy_rna_driver.c
bpy_rna_id_collection.c
bpy_traceback.c
bpy_util.c
@ -99,6 +100,7 @@ set(SRC
bpy_rna.h
bpy_rna_anim.h
bpy_rna_callback.h
bpy_rna_driver.h
bpy_rna_id_collection.h
bpy_traceback.h
bpy_util.h

View File

@ -42,10 +42,13 @@
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "bpy_rna_driver.h" /* for pyrna_driver_get_variable_value */
#include "bpy_driver.h"
extern void BPY_update_rna_module(void);
#define USE_RNA_AS_PYOBJECT
/* for pydrivers (drivers using one-line Python expressions to express relationships between targets) */
PyObject *bpy_pydriver_Dict = NULL;
@ -262,12 +265,24 @@ float BPY_driver_exec(ChannelDriver *driver, const float evaltime)
driver_vars = PyDict_New();
for (dvar = driver->variables.first, i = 0; dvar; dvar = dvar->next) {
PyObject *driver_arg = NULL;
float tval = 0.0f;
/* try to get variable value */
tval = driver_get_variable_value(driver, dvar);
driver_arg = PyFloat_FromDouble((double)tval);
/* support for any RNA data */
#ifdef USE_RNA_AS_PYOBJECT
if (dvar->type == DVAR_TYPE_SINGLE_PROP) {
driver_arg = pyrna_driver_get_variable_value(driver, &dvar->targets[0]);
if (driver_arg == NULL) {
driver_arg = PyFloat_FromDouble(0.0);
}
}
else
#endif
{
/* try to get variable value */
float tval = driver_get_variable_value(driver, dvar);
driver_arg = PyFloat_FromDouble((double)tval);
}
/* try to add to dictionary */
/* if (PyDict_SetItemString(driver_vars, dvar->name, driver_arg)) { */
if (PyDict_SetItem(driver_vars, PyTuple_GET_ITEM(expr_vars, i++), driver_arg) < 0) {

View File

@ -0,0 +1,79 @@
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/python/intern/bpy_rna_driver.c
* \ingroup pythonintern
*
* This file defines utility functions that use the RNA API, from PyDrivers.
*/
#include <Python.h>
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
#include "BKE_fcurve.h"
#include "RNA_access.h"
#include "bpy_rna.h"
#include "bpy_rna_driver.h" /* own include */
/**
* A version of #driver_get_variable_value which returns a PyObject.
*/
PyObject *pyrna_driver_get_variable_value(
struct ChannelDriver *driver, struct DriverTarget *dtar)
{
PyObject *driver_arg = NULL;
PointerRNA ptr;
PropertyRNA *prop = NULL;
int index;
if (driver_get_variable_property(driver, dtar, &ptr, &prop, &index)) {
if (prop) {
if (index != -1) {
if (index < RNA_property_array_length(&ptr, prop) && index >= 0) {
/* object, property & index */
driver_arg = pyrna_array_index(&ptr, prop, index);
}
else {
/* out of range, pass */
}
}
else {
/* object & property */
driver_arg = pyrna_prop_to_py(&ptr, prop);
}
}
else {
/* object only */
driver_arg = pyrna_struct_CreatePyObject(&ptr);
}
}
else {
/* can't resolve path, pass */
}
return driver_arg;
}

View File

@ -0,0 +1,33 @@
/*
* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __BPY_RNA_DRIVER_H__
#define __BPY_RNA_DRIVER_H__
/** \file blender/python/intern/bpy_rna_driver.h
* \ingroup pythonintern
*/
struct ChannelDriver;
struct DriverTarget;
PyObject *pyrna_driver_get_variable_value(struct ChannelDriver *driver, struct DriverTarget *dtar);
#endif /* __BPY_RNA_DRIVER_H__ */