Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Leung <aligorith@gmail.com>2010-01-05 00:15:45 +0300
committerJoshua Leung <aligorith@gmail.com>2010-01-05 00:15:45 +0300
commita9861e3381f4c2ac44fcc880aa1bd030a3ba8dae (patch)
tree72f8f0d8e7f4abb1833456bbaa8b27ac82a2e829 /source/blender
parentc79cf56b69ecf3f49c220ce6dea626caa48e089b (diff)
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.
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h34
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c26
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c49
-rw-r--r--source/blender/blenkernel/intern/fcurve.c549
-rw-r--r--source/blender/blenkernel/intern/ipo.c10
-rw-r--r--source/blender/blenkernel/intern/object.c17
-rw-r--r--source/blender/blenloader/intern/readfile.c46
-rw-r--r--source/blender/blenloader/intern/writefile.c21
-rw-r--r--source/blender/editors/animation/drivers.c6
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c192
-rw-r--r--source/blender/editors/space_outliner/outliner.c22
-rw-r--r--source/blender/makesdna/DNA_anim_types.h80
-rw-r--r--source/blender/makesrna/RNA_access.h1
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c129
-rw-r--r--source/blender/python/intern/bpy_driver.c22
-rw-r--r--source/blender/windowmanager/WM_types.h5
16 files changed, 853 insertions, 356 deletions
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index fa6b8969edb..d3457a5f5ae 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -31,6 +31,7 @@
struct FCurve;
struct FModifier;
struct ChannelDriver;
+struct DriverVar;
struct DriverTarget;
struct BezTriple;
@@ -40,7 +41,6 @@ struct StructRNA;
/* ************** Keyframe Tools ***************** */
-// XXX this stuff is defined in BKE_ipo.h too, so maybe skip for now?
typedef struct CfraElem {
struct CfraElem *next, *prev;
float cfra;
@@ -51,13 +51,39 @@ void bezt_add_to_cfra_elem(ListBase *lb, struct BezTriple *bezt);
/* ************** F-Curve Drivers ***************** */
+/* With these iterators for convenience, the variables "tarIndex" and "dtar" can be
+ * accessed directly from the code using them, but it is not recommended that their
+ * values be changed to point at other slots...
+ */
+
+/* convenience looper over ALL driver targets for a given variable (even the unused ones) */
+#define DRIVER_TARGETS_LOOPER(dvar) \
+ { \
+ DriverTarget *dtar= &dvar->targets[0]; \
+ int tarIndex= 0; \
+ for (; tarIndex < MAX_DRIVER_TARGETS; tarIndex++, dtar++)
+
+/* convenience looper over USED driver targets only */
+#define DRIVER_TARGETS_USED_LOOPER(dvar) \
+ { \
+ DriverTarget *dtar= &dvar->targets[0]; \
+ int tarIndex= 0; \
+ for (; tarIndex < dvar->num_targets; tarIndex++, dtar++)
+
+/* tidy up for driver targets loopers */
+#define DRIVER_TARGETS_LOOPER_END \
+ }
+
+/* ---------------------- */
+
void fcurve_free_driver(struct FCurve *fcu);
struct ChannelDriver *fcurve_copy_driver(struct ChannelDriver *driver);
-void driver_free_target(struct ChannelDriver *driver, struct DriverTarget *dtar);
-struct DriverTarget *driver_add_new_target(struct ChannelDriver *driver);
+void driver_free_variable(struct ChannelDriver *driver, struct DriverVar *dvar);
+void driver_change_variable_type(struct DriverVar *dvar, int type);
+struct DriverVar *driver_add_new_variable(struct ChannelDriver *driver);
-float driver_get_target_value(struct ChannelDriver *driver, struct DriverTarget *dtar);
+float driver_get_variable_value (struct ChannelDriver *driver, struct DriverVar *dvar);
/* ************** F-Curve Modifiers *************** */
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 4f96b031daa..4c63c64ccb9 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -319,16 +319,32 @@ static void fcurves_path_rename_fix (ID *owner_id, char *prefix, char *oldName,
/* we need to check every curve... */
for (fcu= curves->first; fcu; fcu= fcu->next) {
/* firstly, handle the F-Curve's own path */
- fcu->rna_path= rna_path_rename_fix(owner_id, prefix, oldName, newName, fcu->rna_path);
+ if (fcu->rna_path)
+ fcu->rna_path= rna_path_rename_fix(owner_id, prefix, oldName, newName, fcu->rna_path);
/* driver? */
if (fcu->driver) {
ChannelDriver *driver= fcu->driver;
- DriverTarget *dtar;
+ DriverVar *dvar;
- /* driver targets */
- for (dtar= driver->targets.first; dtar; dtar=dtar->next) {
- dtar->rna_path= rna_path_rename_fix(dtar->id, prefix, oldName, newName, dtar->rna_path);
+ /* driver variables */
+ for (dvar= driver->variables.first; dvar; dvar=dvar->next) {
+ /* all targets (even unused ones) */
+ // XXX maybe we only need to modify the used ones, since the others can be manually fixed anyways
+ DRIVER_TARGETS_LOOPER(dvar)
+ {
+ /* rename RNA path */
+ if (dtar->rna_path)
+ dtar->rna_path= rna_path_rename_fix(dtar->id, prefix, oldName, newName, dtar->rna_path);
+
+ /* also fix the bone-name (if applicable) */
+ if ( ((dtar->id) && (GS(dtar->id->name) == ID_OB)) &&
+ (dtar->pchan_name[0]) && (strcmp(oldName, dtar->pchan_name)==0) )
+ {
+ BLI_strncpy(dtar->pchan_name, newName, sizeof(dtar->pchan_name));
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END
}
}
}
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 2f08abd82b3..e664dd01f4d 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -68,6 +68,7 @@
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_effect.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_group.h"
#include "BKE_key.h"
@@ -316,28 +317,38 @@ static void dag_add_driver_relation(AnimData *adt, DagForest *dag, DagNode *node
for (fcu= adt->drivers.first; fcu; fcu= fcu->next) {
ChannelDriver *driver= fcu->driver;
- DriverTarget *dtar;
+ DriverVar *dvar;
- /* loop over targets, adding relationships as appropriate */
- for (dtar= driver->targets.first; dtar; dtar= dtar->next) {
- if (dtar->id) {
- if (GS(dtar->id->name)==ID_OB) {
- Object *ob= (Object *)dtar->id;
-
- /* normal channel-drives-channel */
- node1 = dag_get_node(dag, dtar->id);
-
- /* check if bone... */
- if ((ob->type==OB_ARMATURE) && dtar->rna_path && strstr(dtar->rna_path, "pose.bones["))
- dag_add_relation(dag, node1, node, isdata?DAG_RL_DATA_DATA:DAG_RL_DATA_OB, "Driver");
- /* check if ob data */
- else if (dtar->rna_path && strstr(dtar->rna_path, "data."))
- dag_add_relation(dag, node1, node, isdata?DAG_RL_DATA_DATA:DAG_RL_DATA_OB, "Driver");
- /* normal */
- else
- dag_add_relation(dag, node1, node, isdata?DAG_RL_OB_DATA:DAG_RL_OB_OB, "Driver");
+ /* loop over variables to get the target relationships */
+ for (dvar= driver->variables.first; dvar; dvar= dvar->next) {
+ /* only used targets */
+ DRIVER_TARGETS_USED_LOOPER(dvar)
+ {
+ if (dtar->id) {
+ // FIXME: other data types need to be added here so that they can work!
+ if (GS(dtar->id->name)==ID_OB) {
+ Object *ob= (Object *)dtar->id;
+
+ /* normal channel-drives-channel */
+ node1 = dag_get_node(dag, dtar->id);
+
+ /* check if bone... */
+ if ((ob->type==OB_ARMATURE) &&
+ ( ((dtar->rna_path) && strstr(dtar->rna_path, "pose.bones[")) ||
+ ((dtar->flag & DTAR_FLAG_STRUCT_REF) && (dtar->pchan_name[0])) ))
+ {
+ dag_add_relation(dag, node1, node, isdata?DAG_RL_DATA_DATA:DAG_RL_DATA_OB, "Driver");
+ }
+ /* check if ob data */
+ else if (dtar->rna_path && strstr(dtar->rna_path, "data."))
+ dag_add_relation(dag, node1, node, isdata?DAG_RL_DATA_DATA:DAG_RL_DATA_OB, "Driver");
+ /* normal */
+ else
+ dag_add_relation(dag, node1, node, isdata?DAG_RL_OB_DATA:DAG_RL_OB_OB, "Driver");
+ }
}
}
+ DRIVER_TARGETS_LOOPER_END
}
}
}
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index d5e033652a8..9e84727fbf1 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -41,6 +41,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
+#include "DNA_object_types.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
@@ -48,6 +49,7 @@
#include "BKE_fcurve.h"
#include "BKE_animsys.h"
+#include "BKE_action.h"
#include "BKE_curve.h"
#include "BKE_global.h"
@@ -735,108 +737,31 @@ short test_time_fcurve (FCurve *fcu)
/* ***************************** Drivers ********************************* */
-/* Driver API --------------------------------- */
+/* Driver Variables --------------------------- */
-/* This frees the driver target itself */
-void driver_free_target (ChannelDriver *driver, DriverTarget *dtar)
-{
- /* sanity checks */
- if (dtar == NULL)
- return;
-
- /* free target vars */
- if (dtar->rna_path)
- MEM_freeN(dtar->rna_path);
+/* TypeInfo for Driver Variables (dvti) */
+typedef struct DriverVarTypeInfo {
+ /* evaluation callback */
+ float (*get_value)(ChannelDriver *driver, DriverVar *dvar);
- /* remove the target from the driver */
- if (driver)
- BLI_freelinkN(&driver->targets, dtar);
- else
- MEM_freeN(dtar);
-}
+ /* allocation of target slots */
+ int num_targets; /* number of target slots required */
+ char *target_names[MAX_DRIVER_TARGETS]; /* UI names that should be given to the slots */
+ int target_flags[MAX_DRIVER_TARGETS]; /* flags defining the requirements for each slot */
+} DriverVarTypeInfo;
-/* Add a new driver target variable */
-DriverTarget *driver_add_new_target (ChannelDriver *driver)
-{
- DriverTarget *dtar;
-
- /* sanity checks */
- if (driver == NULL)
- return NULL;
-
- /* make a new target */
- dtar= MEM_callocN(sizeof(DriverTarget), "DriverTarget");
- BLI_addtail(&driver->targets, dtar);
-
- /* make the default ID-type ID_OB, since most driver targets refer to objects */
- dtar->idtype= ID_OB;
-
- /* give the target a 'unique' name */
- strcpy(dtar->name, "var");
- BLI_uniquename(&driver->targets, dtar, "var", '_', offsetof(DriverTarget, name), 64);
-
- /* return the target */
- return dtar;
-}
-
-/* This frees the driver itself */
-void fcurve_free_driver(FCurve *fcu)
-{
- ChannelDriver *driver;
- DriverTarget *dtar, *dtarn;
-
- /* sanity checks */
- if ELEM(NULL, fcu, fcu->driver)
- return;
- driver= fcu->driver;
-
- /* free driver targets */
- for (dtar= driver->targets.first; dtar; dtar= dtarn) {
- dtarn= dtar->next;
- driver_free_target(driver, dtar);
- }
-
-#ifndef DISABLE_PYTHON
- if(driver->expr_comp)
- BPY_DECREF(driver->expr_comp);
-#endif
-
- /* free driver itself, then set F-Curve's point to this to NULL (as the curve may still be used) */
- MEM_freeN(driver);
- fcu->driver= NULL;
-}
-
-/* This makes a copy of the given driver */
-ChannelDriver *fcurve_copy_driver (ChannelDriver *driver)
-{
- ChannelDriver *ndriver;
- DriverTarget *dtar;
-
- /* sanity checks */
- if (driver == NULL)
- return NULL;
-
- /* copy all data */
- ndriver= MEM_dupallocN(driver);
-
- /* copy targets */
- ndriver->targets.first= ndriver->targets.last= NULL;
- BLI_duplicatelist(&ndriver->targets, &driver->targets);
+/* Macro to begin definitions */
+#define BEGIN_DVAR_TYPEDEF(type) \
+ {
- for (dtar= ndriver->targets.first; dtar; dtar= dtar->next) {
- /* make a copy of target's rna path if available */
- if (dtar->rna_path)
- dtar->rna_path = MEM_dupallocN(dtar->rna_path);
+/* Macro to end definitions */
+#define END_DVAR_TYPEDEF \
}
-
- /* return the new driver */
- return ndriver;
-}
-/* Driver Evaluation -------------------------- */
+/* ......... */
/* Helper function to obtain a value using RNA from the specified source (for evaluating drivers) */
-float driver_get_target_value (ChannelDriver *driver, DriverTarget *dtar)
+static float dtar_get_prop_val (ChannelDriver *driver, DriverTarget *dtar)
{
PointerRNA id_ptr, ptr;
PropertyRNA *prop;
@@ -853,22 +778,18 @@ float driver_get_target_value (ChannelDriver *driver, DriverTarget *dtar)
RNA_id_pointer_create(dtar->id, &id_ptr);
id= dtar->id;
path= dtar->rna_path;
- index= dtar->array_index;
/* error check for missing pointer... */
+ // TODO: tag the specific target too as having issues
if (id == NULL) {
- printf("Error: driver doesn't have any valid target to use \n");
- if (G.f & G_DEBUG) printf("\tpath = %s [%d] \n", path, index);
+ printf("Error: driver has an invalid target to use \n");
+ if (G.f & G_DEBUG) printf("\tpath = %s\n", path);
driver->flag |= DRIVER_FLAG_INVALID;
return 0.0f;
}
/* get property to read from, and get value as appropriate */
if (RNA_path_resolve_full(&id_ptr, path, &ptr, &prop, &index)) {
- /* for now, if there is no valid index, fall back to the array-index specified separately */
- if (index == -1)
- index= dtar->array_index;
-
switch (RNA_property_type(prop)) {
case PROP_BOOLEAN:
if (RNA_property_array_length(&ptr, prop))
@@ -906,39 +827,326 @@ float driver_get_target_value (ChannelDriver *driver, DriverTarget *dtar)
return value;
}
-/* Get two PoseChannels from the targets of the given Driver */
-static void driver_get_target_pchans2 (ChannelDriver *driver, bPoseChannel **pchan1, bPoseChannel **pchan2)
+/* Helper function to obtain a pointer to a Pose Channel (for evaluating drivers) */
+static bPoseChannel *dtar_get_pchan_ptr (ChannelDriver *driver, DriverTarget *dtar)
{
- DriverTarget *dtar;
- short i = 0;
+ /* sanity check */
+ if ELEM(NULL, driver, dtar)
+ return NULL;
+
+ /* check if the ID here is a valid object */
+ if ((dtar->id) && GS(dtar->id->name)) {
+ Object *ob= (Object *)dtar->id;
+
+ /* get pose, and subsequently, posechannel */
+ return get_pose_channel(ob->pose, dtar->pchan_name);
+ }
+ else {
+ /* cannot find a posechannel this way */
+ return NULL;
+ }
+}
+
+/* ......... */
+
+/* evaluate 'single prop' driver variable */
+static float dvar_eval_singleProp (ChannelDriver *driver, DriverVar *dvar)
+{
+ /* just evaluate the first target slot */
+ return dtar_get_prop_val(driver, &dvar->targets[0]);
+}
+
+/* evaluate 'rotation difference' driver variable */
+static float dvar_eval_rotDiff (ChannelDriver *driver, DriverVar *dvar)
+{
+ bPoseChannel *pchan, *pchan2;
+ float q1[4], q2[4], quat[4], angle;
- /* before doing anything */
- *pchan1= NULL;
- *pchan2= NULL;
+ /* get pose channels, and check if we've got two */
+ pchan= dtar_get_pchan_ptr(driver, &dvar->targets[0]);
+ pchan2= dtar_get_pchan_ptr(driver, &dvar->targets[1]);
- /* only take the first two targets */
- for (dtar= driver->targets.first; (dtar) && (i < 2); dtar=dtar->next, i++) {
- PointerRNA id_ptr, ptr;
- PropertyRNA *prop;
+ if (ELEM(NULL, pchan, pchan2)) {
+ /* disable this driver, since it doesn't work correctly... */
+ driver->flag |= DRIVER_FLAG_INVALID;
- /* get RNA-pointer for the ID-block given in target */
- if (dtar->id)
- RNA_id_pointer_create(dtar->id, &id_ptr);
- else
- continue;
+ /* check what the error was */
+ if ((pchan == NULL) && (pchan2 == NULL))
+ printf("Driver Evaluation Error: Rotational difference failed - first 2 targets invalid \n");
+ else if (pchan == NULL)
+ printf("Driver Evaluation Error: Rotational difference failed - first target not valid PoseChannel \n");
+ else if (pchan2 == NULL)
+ printf("Driver Evaluation Error: Rotational difference failed - second target not valid PoseChannel \n");
+
+ /* stop here... */
+ return 0.0f;
+ }
+
+ /* use the final posed locations */
+ mat4_to_quat(q1, pchan->pose_mat);
+ mat4_to_quat(q2, pchan2->pose_mat);
+
+ invert_qt(q1);
+ mul_qt_qtqt(quat, q1, q2);
+ angle = 2.0f * (saacos(quat[0]));
+ angle= ABS(angle);
+
+ return (angle > M_PI) ? (float)((2.0f * M_PI) - angle) : (float)(angle);
+}
+
+/* evaluate 'location difference' driver variable */
+// TODO: this needs to take into account space conversions...
+static float dvar_eval_locDiff (ChannelDriver *driver, DriverVar *dvar)
+{
+ float loc1[3] = {0.0f,0.0f,0.0f};
+ float loc2[3] = {0.0f,0.0f,0.0f};
+
+ /* get two location values */
+ // NOTE: for now, these are all just worldspace
+ DRIVER_TARGETS_USED_LOOPER(dvar)
+ {
+ /* get pointer to loc values to store in */
+ Object *ob= (Object *)dtar->id;
+ bPoseChannel *pchan;
+ float tmp_loc[3];
- /* resolve path so that we have pointer to the right posechannel */
- if (RNA_path_resolve(&id_ptr, dtar->rna_path, &ptr, &prop)) {
- /* is pointer valid (i.e. pointing to an actual posechannel */
- if ((ptr.type == &RNA_PoseBone) && (ptr.data)) {
- /* first or second target? */
- if (i)
- *pchan1= ptr.data;
- else
- *pchan2= ptr.data;
- }
+ /* check if this target has valid data */
+ if ((ob == NULL) || (GS(dtar->id->name) != ID_OB)) {
+ /* invalid target, so will not have enough targets */
+ driver->flag |= DRIVER_FLAG_INVALID;
+ return 0.0f;
+ }
+
+ /* try to get posechannel */
+ pchan= get_pose_channel(ob->pose, dtar->pchan_name);
+
+ /* check if object or bone */
+ if (pchan) {
+ /* bone - need to convert to worldspace */
+ VECCOPY(tmp_loc, pchan->pose_head);
+ mul_m4_v3(ob->obmat, tmp_loc);
+ }
+ else {
+ /* object, already in worldspace */
+ VECCOPY(tmp_loc, ob->obmat[3]);
+ }
+
+ /* copy the location to the right place */
+ if (tarIndex) {
+ VECCOPY(loc2, tmp_loc);
+ }
+ else {
+ VECCOPY(loc1, tmp_loc);
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END
+
+
+ /* if we're still here, there should now be two targets to use,
+ * so just take the length of the vector between these points
+ */
+ return len_v3v3(loc1, loc2);
+}
+
+/* ......... */
+
+/* Table of Driver Varaiable Type Info Data */
+DriverVarTypeInfo dvar_types[MAX_DVAR_TYPES] = {
+ BEGIN_DVAR_TYPEDEF(DVAR_TYPE_SINGLE_PROP)
+ dvar_eval_singleProp, /* eval callback */
+ 1, /* number of targets used */
+ {"Property"}, /* UI names for targets */
+ {0} /* flags */
+ END_DVAR_TYPEDEF,
+
+ BEGIN_DVAR_TYPEDEF(DVAR_TYPE_ROT_DIFF)
+ dvar_eval_rotDiff, /* eval callback */
+ 2, /* number of targets used */
+ {"Bone 1", "Bone 2"}, /* UI names for targets */
+ {DTAR_FLAG_STRUCT_REF|DTAR_FLAG_ID_OB_ONLY, DTAR_FLAG_STRUCT_REF|DTAR_FLAG_ID_OB_ONLY} /* flags */
+ END_DVAR_TYPEDEF,
+
+ BEGIN_DVAR_TYPEDEF(DVAR_TYPE_LOC_DIFF)
+ dvar_eval_locDiff, /* eval callback */
+ 2, /* number of targets used */
+ {"Object/Bone 1", "Object/Bone 2"}, /* UI names for targets */
+ {DTAR_FLAG_STRUCT_REF|DTAR_FLAG_ID_OB_ONLY, DTAR_FLAG_STRUCT_REF|DTAR_FLAG_ID_OB_ONLY} /* flags */
+ END_DVAR_TYPEDEF
+};
+
+/* Get driver variable typeinfo */
+DriverVarTypeInfo *get_dvar_typeinfo (int type)
+{
+ /* check if valid type */
+ if ((type >= 0) && (type < MAX_DVAR_TYPES))
+ return &dvar_types[type];
+ else
+ return NULL;
+}
+
+/* Driver API --------------------------------- */
+
+/* This frees the driver variable itself */
+void driver_free_variable (ChannelDriver *driver, DriverVar *dvar)
+{
+ /* sanity checks */
+ if (dvar == NULL)
+ return;
+
+ /* free target vars
+ * - need to go over all of them, not just up to the ones that are used
+ * currently, since there may be some lingering RNA paths from
+ * previous users needing freeing
+ */
+ DRIVER_TARGETS_LOOPER(dvar)
+ {
+ /* free RNA path if applicable */
+ if (dtar->rna_path)
+ MEM_freeN(dtar->rna_path);
+ }
+ DRIVER_TARGETS_LOOPER_END
+
+ /* remove the variable from the driver */
+ if (driver)
+ BLI_freelinkN(&driver->variables, dvar);
+ else
+ MEM_freeN(dvar);
+}
+
+/* Change the type of driver variable */
+void driver_change_variable_type (DriverVar *dvar, int type)
+{
+ DriverVarTypeInfo *dvti= get_dvar_typeinfo(type);
+
+ /* sanity check */
+ if (ELEM(NULL, dvar, dvti))
+ return;
+
+ /* set the new settings */
+ dvar->type= type;
+ dvar->num_targets= dvti->num_targets;
+
+ /* make changes to the targets based on the defines for these types
+ * NOTE: only need to make sure the ones we're using here are valid...
+ */
+ DRIVER_TARGETS_USED_LOOPER(dvar)
+ {
+ int flags = dvti->target_flags[tarIndex];
+
+ /* store the flags */
+ dtar->flag = flags;
+
+ /* object ID types only, or idtype not yet initialised*/
+ if ((flags & DTAR_FLAG_ID_OB_ONLY) || (dtar->idtype == 0))
+ dtar->idtype= ID_OB;
+ }
+ DRIVER_TARGETS_LOOPER_END
+}
+
+/* Add a new driver variable */
+DriverVar *driver_add_new_variable (ChannelDriver *driver)
+{
+ DriverVar *dvar;
+
+ /* sanity checks */
+ if (driver == NULL)
+ return NULL;
+
+ /* make a new variable */
+ dvar= MEM_callocN(sizeof(DriverVar), "DriverVar");
+ BLI_addtail(&driver->variables, dvar);
+
+ /* give the variable a 'unique' name */
+ strcpy(dvar->name, "var");
+ BLI_uniquename(&driver->variables, dvar, "var", '_', offsetof(DriverVar, name), 64);
+
+ /* set the default type to 'single prop' */
+ driver_change_variable_type(dvar, DVAR_TYPE_SINGLE_PROP);
+
+ /* return the target */
+ return dvar;
+}
+
+/* This frees the driver itself */
+void fcurve_free_driver(FCurve *fcu)
+{
+ ChannelDriver *driver;
+ DriverVar *dvar, *dvarn;
+
+ /* sanity checks */
+ if ELEM(NULL, fcu, fcu->driver)
+ return;
+ driver= fcu->driver;
+
+ /* free driver targets */
+ for (dvar= driver->variables.first; dvar; dvar= dvarn) {
+ dvarn= dvar->next;
+ driver_free_variable(driver, dvar);
+ }
+
+#ifndef DISABLE_PYTHON
+ /* free compiled driver expression */
+ if (driver->expr_comp)
+ BPY_DECREF(driver->expr_comp);
+#endif
+
+ /* free driver itself, then set F-Curve's point to this to NULL (as the curve may still be used) */
+ MEM_freeN(driver);
+ fcu->driver= NULL;
+}
+
+/* This makes a copy of the given driver */
+ChannelDriver *fcurve_copy_driver (ChannelDriver *driver)
+{
+ ChannelDriver *ndriver;
+ DriverVar *dvar;
+
+ /* sanity checks */
+ if (driver == NULL)
+ return NULL;
+
+ /* copy all data */
+ ndriver= MEM_dupallocN(driver);
+
+ /* copy variables */
+ ndriver->variables.first= ndriver->variables.last= NULL;
+ BLI_duplicatelist(&ndriver->variables, &driver->variables);
+
+ for (dvar= ndriver->variables.first; dvar; dvar= dvar->next) {
+ /* need to go over all targets so that we don't leave any dangling paths */
+ DRIVER_TARGETS_LOOPER(dvar)
+ {
+ /* make a copy of target's rna path if available */
+ if (dtar->rna_path)
+ dtar->rna_path = MEM_dupallocN(dtar->rna_path);
}
+ DRIVER_TARGETS_LOOPER_END
}
+
+ /* return the new driver */
+ return ndriver;
+}
+
+/* Driver Evaluation -------------------------- */
+
+/* Evaluate a Driver Variable to get a value that contributes to the final */
+float driver_get_variable_value (ChannelDriver *driver, DriverVar *dvar)
+{
+ DriverVarTypeInfo *dvti;
+
+ /* sanity check */
+ if (ELEM(NULL, driver, dvar))
+ return 0.0f;
+
+ /* call the relevant callbacks to get the variable value
+ * using the variable type info
+ */
+ dvti= get_dvar_typeinfo(dvar->type);
+
+ if (dvti && dvti->get_value)
+ return dvti->get_value(driver, dvar);
+ else
+ return 0.0f;
}
/* Evaluate an Channel-Driver to get a 'time' value to use instead of "evaltime"
@@ -947,22 +1155,21 @@ static void driver_get_target_pchans2 (ChannelDriver *driver, bPoseChannel **pch
*/
static float evaluate_driver (ChannelDriver *driver, float evaltime)
{
- DriverTarget *dtar;
+ DriverVar *dvar;
/* check if driver can be evaluated */
if (driver->flag & DRIVER_FLAG_INVALID)
return 0.0f;
- // TODO: the flags for individual targets need to be used too for more fine-grained support...
switch (driver->type) {
case DRIVER_TYPE_AVERAGE: /* average values of driver targets */
case DRIVER_TYPE_SUM: /* sum values of driver targets */
{
- /* check how many targets there are first (i.e. just one?) */
- if (driver->targets.first == driver->targets.last) {
+ /* check how many variables there are first (i.e. just one?) */
+ if (driver->variables.first == driver->variables.last) {
/* just one target, so just use that */
- dtar= driver->targets.first;
- return driver_get_target_value(driver, dtar);
+ dvar= driver->variables.first;
+ return driver_get_variable_value(driver, dvar);
}
else {
/* more than one target, so average the values of the targets */
@@ -970,12 +1177,12 @@ static float evaluate_driver (ChannelDriver *driver, float evaltime)
float value = 0.0f;
/* loop through targets, adding (hopefully we don't get any overflow!) */
- for (dtar= driver->targets.first; dtar; dtar=dtar->next) {
- value += driver_get_target_value(driver, dtar);
+ for (dvar= driver->variables.first; dvar; dvar=dvar->next) {
+ value += driver_get_variable_value(driver, dvar);
tot++;
}
- /* return the average of these */
+ /* perform operations on the total if appropriate */
if (driver->type == DRIVER_TYPE_AVERAGE)
return (value / (float)tot);
else
@@ -984,6 +1191,39 @@ static float evaluate_driver (ChannelDriver *driver, float evaltime)
}
}
break;
+
+ case DRIVER_TYPE_MIN: /* smallest value */
+ case DRIVER_TYPE_MAX: /* largest value */
+ {
+ float value = 0.0f;
+
+ /* loop through the variables, getting the values and comparing them to existing ones */
+ for (dvar= driver->variables.first; dvar; dvar= dvar->next) {
+ /* get value */
+ float tmp_val= driver_get_variable_value(driver, dvar);
+
+ /* store this value if appropriate */
+ if (dvar->prev) {
+ /* check if greater/smaller than the baseline */
+ if (driver->type == DRIVER_TYPE_MAX) {
+ /* max? */
+ if (tmp_val > value)
+ value= tmp_val;
+ }
+ else {
+ /* min? */
+ if (tmp_val < value)
+ value= tmp_val;
+ }
+ }
+ else {
+ /* first item - make this the baseline for comparisons */
+ value= tmp_val;
+ }
+ }
+ }
+ break;
+
case DRIVER_TYPE_PYTHON: /* expression */
{
#ifndef DISABLE_PYTHON
@@ -1001,43 +1241,6 @@ static float evaluate_driver (ChannelDriver *driver, float evaltime)
#endif /* DISABLE_PYTHON*/
}
break;
-
-
- case DRIVER_TYPE_ROTDIFF: /* difference of rotations of 2 bones (should ideally be in same armature) */
- {
- bPoseChannel *pchan, *pchan2;
- float q1[4], q2[4], quat[4], angle;
-
- /* get pose channels, and check if we've got two */
- driver_get_target_pchans2(driver, &pchan, &pchan2);
- if (ELEM(NULL, pchan, pchan2)) {
- /* disable this driver, since it doesn't work correctly... */
- driver->flag |= DRIVER_FLAG_INVALID;
-
- /* check what the error was */
- if ((pchan == NULL) && (pchan2 == NULL))
- printf("Driver Evaluation Error: Rotational difference failed - first 2 targets invalid \n");
- else if (pchan == NULL)
- printf("Driver Evaluation Error: Rotational difference failed - first target not valid PoseChannel \n");
- else if (pchan2 == NULL)
- printf("Driver Evaluation Error: Rotational difference failed - second target not valid PoseChannel \n");
-
- /* stop here... */
- return 0.0f;
- }
-
- /* use the final posed locations */
- mat4_to_quat(q1, pchan->pose_mat);
- mat4_to_quat(q2, pchan2->pose_mat);
-
- invert_qt(q1);
- mul_qt_qtqt(quat, q1, q2);
- angle = 2.0f * (saacos(quat[0]));
- angle= ABS(angle);
-
- return (angle > M_PI) ? (float)((2.0f * M_PI) - angle) : (float)(angle);
- }
- break;
default:
{
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 6fc3fc547df..988bd429185 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -969,7 +969,6 @@ static char *get_rna_access (int blocktype, int adrcode, char actname[], char co
static ChannelDriver *idriver_to_cdriver (IpoDriver *idriver)
{
ChannelDriver *cdriver;
- DriverTarget *dtar=NULL, *dtar2=NULL;
/* allocate memory for new driver */
cdriver= MEM_callocN(sizeof(ChannelDriver), "ChannelDriver");
@@ -981,7 +980,10 @@ static ChannelDriver *idriver_to_cdriver (IpoDriver *idriver)
cdriver->type = DRIVER_TYPE_PYTHON;
strcpy(cdriver->expression, idriver->name); // XXX is this safe?
}
+#if 0 // XXX needs changes for the new system
else {
+ DriverTarget *dtar=NULL, *dtar2=NULL;
+
/* what to store depends on the 'blocktype' (ID_OB or ID_PO - object or posechannel) */
if (idriver->blocktype == ID_AR) {
/* ID_PO */
@@ -1058,6 +1060,7 @@ static ChannelDriver *idriver_to_cdriver (IpoDriver *idriver)
dtar->rna_path= get_rna_access(ID_OB, idriver->adrcode, NULL, NULL, &dtar->array_index);
}
}
+#endif // XXX fixme
/* return the new one */
return cdriver;
@@ -1288,8 +1291,9 @@ static void icu_to_fcurves (ListBase *groups, ListBase *list, IpoCurve *icu, cha
* - need to go from degrees to radians...
* - there's only really 1 target to worry about
*/
- if (fcu->driver && fcu->driver->targets.first) {
- DriverTarget *dtar= fcu->driver->targets.first;
+ if (fcu->driver && fcu->driver->variables.first) {
+ DriverVar *dvar= fcu->driver->variables.first;
+ DriverTarget *dtar= &dvar->targets[0];
/* since drivers could only be for objects, we should just check for 'rotation' being
* in the name of the path given
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 0f9198df263..762ad2432b0 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -1500,13 +1500,18 @@ void object_make_proxy(Object *ob, Object *target, Object *gob)
for (fcu= ob->adt->drivers.first; fcu; fcu= fcu->next) {
ChannelDriver *driver= fcu->driver;
- DriverTarget *dtar;
+ DriverVar *dvar;
- for (dtar= driver->targets.first; dtar; dtar= dtar->next) {
- if ((Object *)dtar->id == target)
- dtar->id= (ID *)ob;
- else
- id_lib_extern((ID *)dtar->id);
+ for (dvar= driver->variables.first; dvar; dvar= dvar->next) {
+ /* all drivers */
+ DRIVER_TARGETS_LOOPER(dvar)
+ {
+ if ((Object *)dtar->id == target)
+ dtar->id= (ID *)ob;
+ else
+ id_lib_extern((ID *)dtar->id);
+ }
+ DRIVER_TARGETS_LOOPER_END
}
}
}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 3e35250bd74..1eff6c8f8e3 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -1699,10 +1699,19 @@ static void lib_link_fcurves(FileData *fd, ID *id, ListBase *list)
/* driver data */
if (fcu->driver) {
ChannelDriver *driver= fcu->driver;
- DriverTarget *dtar;
+ DriverVar *dvar;
- for (dtar= driver->targets.first; dtar; dtar= dtar->next)
- dtar->id= newlibadr(fd, id->lib, dtar->id);
+ for (dvar= driver->variables.first; dvar; dvar= dvar->next) {
+ DRIVER_TARGETS_LOOPER(dvar)
+ {
+ /* only relink if still used */
+ if (tarIndex < dvar->num_targets)
+ dtar->id= newlibadr(fd, id->lib, dtar->id);
+ else
+ dtar->id= NULL;
+ }
+ DRIVER_TARGETS_LOOPER_END
+ }
}
/* modifiers */
@@ -1770,12 +1779,21 @@ static void direct_link_fcurves(FileData *fd, ListBase *list)
fcu->driver= newdataadr(fd, fcu->driver);
if (fcu->driver) {
ChannelDriver *driver= fcu->driver;
- DriverTarget *dtar;
+ DriverVar *dvar;
- /* relink targets and their paths */
- link_list(fd, &driver->targets);
- for (dtar= driver->targets.first; dtar; dtar= dtar->next)
- dtar->rna_path= newdataadr(fd, dtar->rna_path);
+ /* relink variables, targets and their paths */
+ link_list(fd, &driver->variables);
+ for (dvar= driver->variables.first; dvar; dvar= dvar->next) {
+ DRIVER_TARGETS_LOOPER(dvar)
+ {
+ /* only relink the targets being used */
+ if (tarIndex < dvar->num_targets)
+ dtar->rna_path= newdataadr(fd, dtar->rna_path);
+ else
+ dtar->rna_path= NULL;
+ }
+ DRIVER_TARGETS_LOOPER_END
+ }
}
/* modifiers */
@@ -10764,10 +10782,16 @@ static void expand_fcurves(FileData *fd, Main *mainvar, ListBase *list)
/* Driver targets if there is a driver */
if (fcu->driver) {
ChannelDriver *driver= fcu->driver;
- DriverTarget *dtar;
+ DriverVar *dvar;
- for (dtar= driver->targets.first; dtar; dtar= dtar->next)
- expand_doit(fd, mainvar, dtar->id);
+ for (dvar= driver->variables.first; dvar; dvar= dvar->next) {
+ DRIVER_TARGETS_LOOPER(dvar)
+ {
+ // TODO: only expand those that are going to get used?
+ expand_doit(fd, mainvar, dtar->id);
+ }
+ DRIVER_TARGETS_LOOPER_END
+ }
}
/* F-Curve Modifiers */
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 98d3dc5188a..061ed71d77e 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -932,22 +932,27 @@ static void write_fcurves(WriteData *wd, ListBase *fcurves)
/* driver data */
if (fcu->driver) {
ChannelDriver *driver= fcu->driver;
- DriverTarget *dtar;
+ DriverVar *dvar;
/* don't save compiled python bytecode */
void *expr_comp= driver->expr_comp;
driver->expr_comp= NULL;
-
+
writestruct(wd, DATA, "ChannelDriver", 1, driver);
driver->expr_comp= expr_comp; /* restore */
-
- /* targets */
- for (dtar= driver->targets.first; dtar; dtar= dtar->next) {
- writestruct(wd, DATA, "DriverTarget", 1, dtar);
+
+
+ /* variables */
+ for (dvar= driver->variables.first; dvar; dvar= dvar->next) {
+ writestruct(wd, DATA, "DriverVar", 1, dvar);
- if (dtar->rna_path)
- writedata(wd, DATA, strlen(dtar->rna_path)+1, dtar->rna_path);
+ DRIVER_TARGETS_USED_LOOPER(dvar)
+ {
+ if (dtar->rna_path)
+ writedata(wd, DATA, strlen(dtar->rna_path)+1, dtar->rna_path);
+ }
+ DRIVER_TARGETS_LOOPER_END
}
}
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index 59e52c0d489..b816ffbe905 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -404,8 +404,7 @@ static int add_driver_button_exec (bContext *C, wmOperator *op)
/* send updates */
DAG_ids_flush_update(0);
- /* for now, only send ND_KEYS for KeyingSets */
- WM_event_add_notifier(C, ND_KEYS, NULL); // XXX
+ WM_event_add_notifier(C, NC_ANIMATION|ND_FCURVES_ORDER, NULL); // XXX
}
return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
@@ -468,8 +467,7 @@ static int remove_driver_button_exec (bContext *C, wmOperator *op)
/* send updates */
DAG_ids_flush_update(0);
- /* for now, only send ND_KEYS for KeyingSets */
- WM_event_add_notifier(C, ND_KEYS, NULL); // XXX
+ WM_event_add_notifier(C, NC_ANIMATION|ND_FCURVES_ORDER, NULL); // XXX
}
return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index 3faba9bbba7..c42dfd0015d 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -264,18 +264,18 @@ static void driver_add_var_cb (bContext *C, void *driver_v, void *dummy_v)
{
ChannelDriver *driver= (ChannelDriver *)driver_v;
- /* add a new var */
- driver_add_new_target(driver);
+ /* add a new variable */
+ driver_add_new_variable(driver);
}
/* callback to remove target variable from active driver */
-static void driver_delete_var_cb (bContext *C, void *driver_v, void *dtar_v)
+static void driver_delete_var_cb (bContext *C, void *driver_v, void *dvar_v)
{
ChannelDriver *driver= (ChannelDriver *)driver_v;
- DriverTarget *dtar= (DriverTarget *)dtar_v;
+ DriverVar *dvar= (DriverVar *)dvar_v;
- /* remove the active target */
- driver_free_target(driver, dtar);
+ /* remove the active variable */
+ driver_free_variable(driver, dvar);
}
/* callback to reset the driver's flags */
@@ -301,13 +301,115 @@ static int graph_panel_drivers_poll(const bContext *C, PanelType *pt)
}
+/* settings for 'single property' driver variable type */
+static void graph_panel_driverVar__singleProp(const bContext *C, uiLayout *layout, ID *id, DriverVar *dvar)
+{
+ DriverTarget *dtar= &dvar->targets[0];
+ PointerRNA dtar_ptr;
+ uiLayout *row, *col;
+ uiBlock *block;
+
+ /* initialise RNA pointer to the target */
+ RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
+
+ /* Target ID */
+ row= uiLayoutRow(layout, 0);
+ uiTemplateAnyID(row, (bContext *)C, &dtar_ptr, "id", "id_type", "Value:");
+
+ /* Target Property */
+ // TODO: make this less technical...
+ if (dtar->id) {
+ PointerRNA root_ptr;
+
+ /* get pointer for resolving the property selected */
+ RNA_id_pointer_create(dtar->id, &root_ptr);
+
+ col= uiLayoutColumn(layout, 1);
+ block= uiLayoutGetBlock(col);
+ /* rna path */
+ uiTemplatePathBuilder(col, (bContext *)C, &dtar_ptr, "data_path", &root_ptr, "Path");
+ }
+}
+
+/* settings for 'rotation difference' driver variable type */
+static void graph_panel_driverVar__rotDiff(const bContext *C, uiLayout *layout, ID *id, DriverVar *dvar)
+{
+ DriverTarget *dtar= &dvar->targets[0];
+ DriverTarget *dtar2= &dvar->targets[1];
+ Object *ob1 = (Object *)dtar->id;
+ Object *ob2 = (Object *)dtar2->id;
+ PointerRNA dtar_ptr, dtar2_ptr;
+ uiLayout *col;
+
+ /* initialise RNA pointer to the target */
+ RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
+ RNA_pointer_create(id, &RNA_DriverTarget, dtar2, &dtar2_ptr);
+
+ /* Bone 1 */
+ col= uiLayoutColumn(layout, 1);
+ uiTemplateAnyID(col, (bContext *)C, &dtar_ptr, "id", "id_type", "Bone 1:");
+
+ if (dtar->id && ob1->pose) {
+ PointerRNA tar_ptr;
+
+ RNA_pointer_create(dtar2->id, &RNA_Pose, ob1->pose, &tar_ptr);
+ uiItemPointerR(col, "", ICON_BONE_DATA, &dtar_ptr, "bone_target", &tar_ptr, "bones");
+ }
+
+ col= uiLayoutColumn(layout, 1);
+ uiTemplateAnyID(col, (bContext *)C, &dtar2_ptr, "id", "id_type", "Bone 2:");
+
+ if (dtar2->id && ob2->pose) {
+ PointerRNA tar_ptr;
+
+ RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr);
+ uiItemPointerR(col, "", ICON_BONE_DATA, &dtar2_ptr, "bone_target", &tar_ptr, "bones");
+ }
+}
+
+/* settings for 'rotation difference' driver variable type */
+static void graph_panel_driverVar__locDiff(const bContext *C, uiLayout *layout, ID *id, DriverVar *dvar)
+{
+ DriverTarget *dtar= &dvar->targets[0];
+ DriverTarget *dtar2= &dvar->targets[1];
+ Object *ob1 = (Object *)dtar->id;
+ Object *ob2 = (Object *)dtar2->id;
+ PointerRNA dtar_ptr, dtar2_ptr;
+ uiLayout *col;
+
+ /* initialise RNA pointer to the target */
+ RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
+ RNA_pointer_create(id, &RNA_DriverTarget, dtar2, &dtar2_ptr);
+
+ /* Bone 1 */
+ col= uiLayoutColumn(layout, 1);
+ uiTemplateAnyID(col, (bContext *)C, &dtar_ptr, "id", "id_type", "Ob/Bone 1:");
+
+ if (dtar->id && ob1->pose) {
+ PointerRNA tar_ptr;
+
+ RNA_pointer_create(dtar2->id, &RNA_Pose, ob1->pose, &tar_ptr);
+ uiItemPointerR(col, "", ICON_BONE_DATA, &dtar_ptr, "bone_target", &tar_ptr, "bones");
+ }
+
+ col= uiLayoutColumn(layout, 1);
+ uiTemplateAnyID(col, (bContext *)C, &dtar2_ptr, "id", "id_type", "Ob/Bone 2:");
+
+ if (dtar2->id && ob2->pose) {
+ PointerRNA tar_ptr;
+
+ RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr);
+ uiItemPointerR(col, "", ICON_BONE_DATA, &dtar2_ptr, "bone_target", &tar_ptr, "bones");
+ }
+}
+
/* driver settings for active F-Curve (only for 'Drivers' mode) */
static void graph_panel_drivers(const bContext *C, Panel *pa)
{
bAnimListElem *ale;
FCurve *fcu;
ChannelDriver *driver;
- DriverTarget *dtar;
+ DriverVar *dvar;
PointerRNA driver_ptr;
uiLayout *col;
@@ -354,56 +456,54 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
uiItemL(col, "ERROR: invalid target channel(s)", ICON_ERROR);
}
- /* add driver target variables */
+ /* add driver variables */
col= uiLayoutColumn(pa->layout, 0);
block= uiLayoutGetBlock(col);
- but= uiDefBut(block, BUT, B_IPO_DEPCHANGE, "Add Target", 0, 0, 10*UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "Add a new target variable for this Driver");
+ but= uiDefBut(block, BUT, B_IPO_DEPCHANGE, "Add Variable", 0, 0, 10*UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "Add a new target variable for this Driver");
uiButSetFunc(but, driver_add_var_cb, driver, NULL);
/* loop over targets, drawing them */
- for (dtar= driver->targets.first; dtar; dtar= dtar->next) {
- PointerRNA dtar_ptr;
+ for (dvar= driver->variables.first; dvar; dvar= dvar->next) {
+ PointerRNA dvar_ptr;
uiLayout *box, *row;
- /* panel holding the buttons */
- box= uiLayoutBox(pa->layout);
-
- /* first row context info for driver */
- RNA_pointer_create(ale->id, &RNA_DriverTarget, dtar, &dtar_ptr);
-
- row= uiLayoutRow(box, 0);
- block= uiLayoutGetBlock(row);
- /* variable name */
- uiItemR(row, "", 0, &dtar_ptr, "name", 0);
-
- /* remove button */
- but= uiDefIconBut(block, BUT, B_IPO_DEPCHANGE, ICON_X, 290, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, "Delete target variable.");
- uiButSetFunc(but, driver_delete_var_cb, driver, dtar);
-
-
- /* Target ID */
- row= uiLayoutRow(box, 0);
- uiTemplateAnyID(row, (bContext *)C, &dtar_ptr, "id", "id_type", "Value:");
+ /* sub-layout column for this variable's settings */
+ col= uiLayoutColumn(pa->layout, 1);
- /* Target Property */
- // TODO: make this less technical...
- if (dtar->id) {
- PointerRNA root_ptr;
+ /* header panel */
+ box= uiLayoutBox(col);
+ /* first row context info for driver */
+ RNA_pointer_create(ale->id, &RNA_DriverVariable, dvar, &dvar_ptr);
- /* get pointer for resolving the property selected */
- RNA_id_pointer_create(dtar->id, &root_ptr);
+ row= uiLayoutRow(box, 0);
+ block= uiLayoutGetBlock(row);
+ /* variable name */
+ uiItemR(row, "", 0, &dvar_ptr, "name", 0);
+
+ /* remove button */
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+ but= uiDefIconBut(block, BUT, B_IPO_DEPCHANGE, ICON_X, 290, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, "Delete target variable.");
+ uiButSetFunc(but, driver_delete_var_cb, driver, dvar);
+ uiBlockSetEmboss(block, UI_EMBOSS);
- col= uiLayoutColumn(box, 1);
- block= uiLayoutGetBlock(col);
- /* rna path */
- uiTemplatePathBuilder(col, (bContext *)C, &dtar_ptr, "data_path", &root_ptr, "Path");
+ /* variable type */
+ row= uiLayoutRow(box, 0);
+ uiItemR(row, "", 0, &dvar_ptr, "type", 0);
- /* array index */
- // TODO: this needs selector which limits it to ok values
- // NOTE: for for now, the array index box still gets shown when non-zero (i.e. for tweaking rigs as necessary)
- if (dtar->array_index)
- uiItemR(col, "Index", 0, &dtar_ptr, "array_index", 0);
- }
+ /* variable type settings */
+ box= uiLayoutBox(col);
+ /* controls to draw depends on the type of variable */
+ switch (dvar->type) {
+ case DVAR_TYPE_SINGLE_PROP: /* single property */
+ graph_panel_driverVar__singleProp(C, box, ale->id, dvar);
+ break;
+ case DVAR_TYPE_ROT_DIFF: /* rotational difference */
+ graph_panel_driverVar__rotDiff(C, box, ale->id, dvar);
+ break;
+ case DVAR_TYPE_LOC_DIFF: /* location difference */
+ graph_panel_driverVar__locDiff(C, box, ale->id, dvar);
+ break;
+ }
}
/* cleanup */
diff --git a/source/blender/editors/space_outliner/outliner.c b/source/blender/editors/space_outliner/outliner.c
index 1303168e78d..93b32086614 100644
--- a/source/blender/editors/space_outliner/outliner.c
+++ b/source/blender/editors/space_outliner/outliner.c
@@ -69,6 +69,7 @@
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_depsgraph.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_group.h"
#include "BKE_library.h"
@@ -913,18 +914,25 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
TreeElement *ted= outliner_add_element(soops, &te->subtree, adt, te, TSE_DRIVER_BASE, 0);
ID *lastadded= NULL;
FCurve *fcu;
- DriverTarget *dtar;
ted->name= "Drivers";
for (fcu= adt->drivers.first; fcu; fcu= fcu->next) {
- if (fcu->driver && fcu->driver->targets.first) {
- for (dtar= fcu->driver->targets.first; dtar; dtar= dtar->next) {
- if (lastadded != dtar->id) {
- // XXX this lastadded check is rather lame, and also fails quite badly...
- outliner_add_element(soops, &ted->subtree, dtar->id, ted, TSE_LINKED_OB, 0);
- lastadded= dtar->id;
+ if (fcu->driver && fcu->driver->variables.first) {
+ ChannelDriver *driver= fcu->driver;
+ DriverVar *dvar;
+
+ for (dvar= driver->variables.first; dvar; dvar= dvar->next) {
+ /* loop over all targets used here */
+ DRIVER_TARGETS_USED_LOOPER(dvar)
+ {
+ if (lastadded != dtar->id) {
+ // XXX this lastadded check is rather lame, and also fails quite badly...
+ outliner_add_element(soops, &ted->subtree, dtar->id, ted, TSE_LINKED_OB, 0);
+ lastadded= dtar->id;
+ }
}
+ DRIVER_TARGETS_LOOPER_END
}
}
}
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index dcb10d0f2cf..f2d4471607f 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -232,26 +232,72 @@ typedef enum eFMod_Noise_Modifications {
/* Drivers -------------------------------------- */
-/* Driver Target
+/* Driver Target (dtar)
*
- * A 'variable' for use as a target of the driver/expression.
+ * Defines how to access a dependency needed for a driver variable.
+ */
+typedef struct DriverTarget {
+ ID *id; /* ID-block which owns the target */
+
+ char *rna_path; /* target channel to use as driver value */
+ char pchan_name[32]; /* name of the posebone to use (for certain types of variable only) */
+
+ int idtype; /* type of ID-block that this target can use */
+ int flag; /* flags for the validity of the target (NOTE: these get reset everytime the types change) */
+} DriverTarget;
+
+/* Driver Target flags */
+typedef enum eDriverTarget_Flag {
+ /* used for targets that use the pchan_name instead of RNA path
+ * (i.e. rotation difference)
+ */
+ DTAR_FLAG_STRUCT_REF = (1<<0),
+ /* idtype can only be 'Object' */
+ DTAR_FLAG_ID_OB_ONLY = (1<<1),
+} eDriverTarget_Flag;
+
+/* --- */
+
+/* maximum number of driver targets per variable */
+// FIXME: make this get used below (for DriverVariable defines) if DNA supports preprocessor stuff..
+#define MAX_DRIVER_TARGETS 8
+
+
+/* Driver Variable (dvar)
+ *
+ * A 'variable' for use as an input for the driver evaluation.
* Defines a way of accessing some channel to use, that can be
* referred to in the expression as a variable, thus simplifying
* expressions and also Depsgraph building.
*/
-typedef struct DriverTarget {
- struct DriverTarget *next, *prev;
+typedef struct DriverVar {
+ struct DriverVar *next, *prev;
- ID *id; /* ID-block which owns the target */
- char *rna_path; /* target channel to use as driver value */
- int array_index; /* if applicable, the index of the RNA-array item to use as driver */
+ char name[64]; /* name of the variable to use in py-expression (must be valid python identifier) */
- int idtype; /* type of ID-block that this target can use */
- int flags; /* flags for the validity of the target */
- int pad;
+ DriverTarget targets[8]; /* MAX_DRIVER_TARGETS - targets available for use for this type of variable */
+ int num_targets; /* number of targets used by this variable */
- char name[64]; /* name of the variable */
-} DriverTarget;
+ int type; /* type of driver target (eDriverTarget_Types) */
+} DriverVar;
+
+/* Driver Variable Types */
+typedef enum eDriverVar_Types {
+ /* single RNA property */
+ DVAR_TYPE_SINGLE_PROP = 0,
+ /* rotation difference (between 2 bones) */
+ DVAR_TYPE_ROT_DIFF,
+ /* distance between objects/bones */
+ DVAR_TYPE_LOC_DIFF,
+
+ /* maximum number of variable types
+ * NOTE: this must always be th last item in this list,
+ * so add new types above this line
+ */
+ MAX_DVAR_TYPES
+} eDriverVar_Types;
+
+/* --- */
/* Channel Driver (i.e. Drivers / Expressions) (driver)
*
@@ -265,7 +311,7 @@ typedef struct DriverTarget {
* evaluated in. This order is set by the Depsgraph's sorting stuff.
*/
typedef struct ChannelDriver {
- ListBase targets; /* targets for this driver (i.e. list of DriverTarget) */
+ ListBase variables; /* targets for this driver (i.e. list of DriverVar) */
/* python expression to execute (may call functions defined in an accessory file)
* which relates the target 'variables' in some way to yield a single usable value
@@ -287,10 +333,12 @@ typedef enum eDriver_Types {
DRIVER_TYPE_AVERAGE = 0,
/* python expression/function relates targets */
DRIVER_TYPE_PYTHON,
- /* rotational difference (must use rotation channels only) */
- DRIVER_TYPE_ROTDIFF,
/* sum of all values */
DRIVER_TYPE_SUM,
+ /* smallest value */
+ DRIVER_TYPE_MIN,
+ /* largest value */
+ DRIVER_TYPE_MAX,
} eDriver_Types;
/* driver flags */
@@ -301,7 +349,7 @@ typedef enum eDriver_Flags {
DRIVER_FLAG_RECALC = (1<<1),
/* driver does replace value, but overrides (for layering of animation over driver) */
// TODO: this needs to be implemented at some stage or left out...
- DRIVER_FLAG_LAYERING = (1<<2),
+ //DRIVER_FLAG_LAYERING = (1<<2),
/* use when the expression needs to be recompiled */
DRIVER_FLAG_RECOMPILE = (1<<3),
} eDriver_Flags;
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index e631e037e74..5697747fcab 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -182,6 +182,7 @@ extern StructRNA RNA_DistortedNoiseTexture;
extern StructRNA RNA_DomainFluidSettings;
extern StructRNA RNA_Driver;
extern StructRNA RNA_DriverTarget;
+extern StructRNA RNA_DriverVariable;
extern StructRNA RNA_DupliObject;
extern StructRNA RNA_EdgeSplitModifier;
extern StructRNA RNA_EditBone;
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index 62ee19df352..10fece3391f 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -116,10 +116,12 @@ static void rna_DriverTarget_update_data(Main *bmain, Scene *scene, PointerRNA *
AnimData *adt= BKE_animdata_from_id(ptr->id.data);
/* find the driver this belongs to and update it */
- for(fcu=adt->drivers.first; fcu; fcu=fcu->next) {
+ for (fcu=adt->drivers.first; fcu; fcu=fcu->next) {
driver= fcu->driver;
-
- if(driver && BLI_findindex(&driver->targets, ptr->data) != -1) {
+
+ if (driver) {
+ // FIXME: need to be able to search targets for required one...
+ //BLI_findindex(&driver->targets, ptr->data) != -1)
RNA_pointer_create(ptr->id.data, &RNA_Driver, driver, &driverptr);
rna_ChannelDriver_update_data(bmain, scene, &driverptr);
return;
@@ -185,6 +187,14 @@ static void rna_DriverTarget_RnaPath_set(PointerRNA *ptr, const char *value)
dtar->rna_path= NULL;
}
+static void rna_DriverVariable_type_set(PointerRNA *ptr, int value)
+{
+ DriverVar *dvar= (DriverVar *)ptr->data;
+
+ /* call the API function for this */
+ driver_change_variable_type(dvar, value);
+}
+
/* ****************************** */
static void rna_FCurve_RnaPath_get(PointerRNA *ptr, char *value)
@@ -220,15 +230,16 @@ static void rna_FCurve_RnaPath_set(PointerRNA *ptr, const char *value)
fcu->rna_path= NULL;
}
-DriverTarget *rna_Driver_new_target(ChannelDriver *driver)
+DriverVar *rna_Driver_new_variable(ChannelDriver *driver)
{
- return driver_add_new_target(driver);
+ /* call the API function for this */
+ return driver_add_new_variable(driver);
}
-void rna_Driver_remove_target(ChannelDriver *driver, DriverTarget *dtar)
+void rna_Driver_remove_variable(ChannelDriver *driver, DriverVar *dvar)
{
/* call the API function for this */
- driver_free_target(driver, dtar);
+ driver_free_variable(driver, dvar);
}
@@ -677,13 +688,7 @@ static void rna_def_drivertarget(BlenderRNA *brna)
PropertyRNA *prop;
srna= RNA_def_struct(brna, "DriverTarget", NULL);
- RNA_def_struct_ui_text(srna, "Driver Target", "Variable from some source/target for driver relationship.");
-
- /* Variable Name */
- prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
- RNA_def_struct_name_property(srna, prop);
- RNA_def_property_ui_text(prop, "Name", "Name to use in scripted expressions/functions. (No spaces or dots are allowed. Also, must not start with a symbol or digit)");
- RNA_def_property_update(prop, 0, "rna_DriverTarget_update_data");
+ RNA_def_struct_ui_text(srna, "Driver Target", "Source of input values for driver variables.");
/* Target Properties - ID-block to Drive */
prop= RNA_def_property(srna, "id", PROP_POINTER, PROP_NONE);
@@ -698,6 +703,7 @@ static void rna_def_drivertarget(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "idtype");
RNA_def_property_enum_items(prop, id_type_items);
RNA_def_property_enum_default(prop, ID_OB);
+ // XXX need to add an 'editable func' for this, in the case where certain flags are set already...
RNA_def_property_enum_funcs(prop, NULL, "rna_DriverTarget_id_type_set", NULL);
RNA_def_property_ui_text(prop, "ID Type", "Type of ID-block that can be used.");
RNA_def_property_update(prop, 0, "rna_DriverTarget_update_data");
@@ -708,41 +714,78 @@ static void rna_def_drivertarget(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Data Path", "RNA Path (from Object) to property used");
RNA_def_property_update(prop, 0, "rna_DriverTarget_update_data");
- prop= RNA_def_property(srna, "array_index", PROP_INT, PROP_NONE);
- RNA_def_property_ui_text(prop, "RNA Array Index", "Index to the specific property used (if applicable)");
+ prop= RNA_def_property(srna, "bone_target", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "pchan_name");
+ RNA_def_property_ui_text(prop, "Bone Name", "Name of PoseBone to use as target.");
RNA_def_property_update(prop, 0, "rna_DriverTarget_update_data");
}
+static void rna_def_drivervar(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem prop_type_items[] = {
+ {DVAR_TYPE_SINGLE_PROP, "SINGLE_PROP", 0, "Single Property", "Use the value from some RNA property (Default)"},
+ {DVAR_TYPE_ROT_DIFF, "ROTATION_DIFF", 0, "Rotational Difference", "Use the angle between two bones"},
+ {DVAR_TYPE_LOC_DIFF, "LOC_DIFF", 0, "Distance", "Distance between two bones or "},
+ {0, NULL, 0, NULL, NULL}};
+
+
+ srna= RNA_def_struct(brna, "DriverVariable", NULL);
+ RNA_def_struct_sdna(srna, "DriverVar");
+ RNA_def_struct_ui_text(srna, "Driver Variable", "Variable from some source/target for driver relationship.");
+
+ /* Variable Name */
+ prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_ui_text(prop, "Name", "Name to use in scripted expressions/functions. (No spaces or dots are allowed. Also, must not start with a symbol or digit)");
+ RNA_def_property_update(prop, 0, "rna_DriverTarget_update_data"); // XXX
+
+ /* Enums */
+ prop= RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_type_items);
+ RNA_def_property_enum_funcs(prop, NULL, "rna_DriverVariable_type_set", NULL);
+ RNA_def_property_ui_text(prop, "Type", "Driver variable type.");
+ RNA_def_property_update(prop, 0, "rna_ChannelDriver_update_data"); // XXX
+
+ /* Targets */
+ // TODO: for nicer api, only expose the relevant props via subclassing, instead of exposing the collection of targets
+ prop= RNA_def_property(srna, "targets", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "targets", "num_targets");
+ RNA_def_property_struct_type(prop, "DriverTarget");
+ RNA_def_property_ui_text(prop, "Targets", "Sources of input data for evaluating this variable.");
+}
+
-/* channeldriver.targets.* */
-static void rna_def_channeldriver_targets(BlenderRNA *brna, PropertyRNA *cprop)
+/* channeldriver.variables.* */
+static void rna_def_channeldriver_variables(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
// PropertyRNA *prop;
-
+
FunctionRNA *func;
PropertyRNA *parm;
-
- RNA_def_property_srna(cprop, "ChannelDriverTargets");
- srna= RNA_def_struct(brna, "ChannelDriverTargets", NULL);
+
+ RNA_def_property_srna(cprop, "ChannelDriverVariables");
+ srna= RNA_def_struct(brna, "ChannelDriverVariables", NULL);
RNA_def_struct_sdna(srna, "ChannelDriver");
- RNA_def_struct_ui_text(srna, "ChannelDriver Targets", "Collection of channel driver Targets.");
-
-
- /* add target */
- func= RNA_def_function(srna, "new", "rna_Driver_new_target");
- RNA_def_function_ui_description(func, "Add a new target for the driver.");
+ RNA_def_struct_ui_text(srna, "ChannelDriver Variables", "Collection of channel driver Variables.");
+
+
+ /* add variable */
+ func= RNA_def_function(srna, "new", "rna_Driver_new_variable");
+ RNA_def_function_ui_description(func, "Add a new variable for the driver.");
/* return type */
- parm= RNA_def_pointer(func, "target", "DriverTarget", "", "Newly created Driver Target.");
+ parm= RNA_def_pointer(func, "var", "DriverVariable", "", "Newly created Driver Variable.");
RNA_def_function_return(func, parm);
- /* remove target */
- func= RNA_def_function(srna, "remove", "rna_Driver_remove_target");
- RNA_def_function_ui_description(func, "Remove an existing target from the driver.");
- /* target to remove*/
- parm= RNA_def_pointer(func, "target", "DriverTarget", "", "Target to remove from the driver.");
+ /* remove variable */
+ func= RNA_def_function(srna, "remove", "rna_Driver_remove_variable");
+ RNA_def_function_ui_description(func, "Remove an existing variable from the driver.");
+ /* target to remove */
+ parm= RNA_def_pointer(func, "var", "DriverVariable", "", "Variable to remove from the driver.");
RNA_def_property_flag(parm, PROP_REQUIRED);
-
}
static void rna_def_channeldriver(BlenderRNA *brna)
@@ -754,7 +797,8 @@ static void rna_def_channeldriver(BlenderRNA *brna)
{DRIVER_TYPE_AVERAGE, "AVERAGE", 0, "Averaged Value", ""},
{DRIVER_TYPE_SUM, "SUM", 0, "Sum Values", ""},
{DRIVER_TYPE_PYTHON, "SCRIPTED", 0, "Scripted Expression", ""},
- {DRIVER_TYPE_ROTDIFF, "ROTDIFF", 0, "Rotational Difference", ""},
+ {DRIVER_TYPE_MIN, "MIN", 0, "Minimum Value", ""},
+ {DRIVER_TYPE_MAX, "MAX", 0, "Maximum Value", ""},
{0, NULL, 0, NULL, NULL}};
srna= RNA_def_struct(brna, "Driver", NULL);
@@ -764,7 +808,7 @@ static void rna_def_channeldriver(BlenderRNA *brna)
/* Enums */
prop= RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, prop_type_items);
- RNA_def_property_ui_text(prop, "Type", "Driver types.");
+ RNA_def_property_ui_text(prop, "Type", "Driver type.");
RNA_def_property_update(prop, 0, "rna_ChannelDriver_update_data");
/* String values */
@@ -773,11 +817,11 @@ static void rna_def_channeldriver(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_ChannelDriver_update_expr");
/* Collections */
- prop= RNA_def_property(srna, "targets", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "targets", NULL);
- RNA_def_property_struct_type(prop, "DriverTarget");
- RNA_def_property_ui_text(prop, "Target Variables", "Properties acting as targets for this driver.");
- rna_def_channeldriver_targets(brna, prop);
+ prop= RNA_def_property(srna, "variables", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "variables", NULL);
+ RNA_def_property_struct_type(prop, "DriverVariable");
+ RNA_def_property_ui_text(prop, "Variables", "Properties acting as inputs for this driver.");
+ rna_def_channeldriver_variables(brna, prop);
/* Functions */
RNA_api_drivers(srna);
@@ -933,6 +977,7 @@ void RNA_def_fcurve(BlenderRNA *brna)
rna_def_fpoint(brna);
rna_def_drivertarget(brna);
+ rna_def_drivervar(brna);
rna_def_channeldriver(brna);
rna_def_fmodifier(brna);
diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c
index 76df28494ac..016aed70c31 100644
--- a/source/blender/python/intern/bpy_driver.c
+++ b/source/blender/python/intern/bpy_driver.c
@@ -147,7 +147,7 @@ float BPY_pydriver_eval (ChannelDriver *driver)
PyObject *retval= NULL;
PyGILState_STATE gilstate;
- DriverTarget *dtar;
+ DriverVar *dvar;
float result = 0.0f; /* default return */
char *expr = NULL;
short targets_ok= 1;
@@ -174,24 +174,24 @@ float BPY_pydriver_eval (ChannelDriver *driver)
/* 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) {
+ for (dvar= driver->variables.first; dvar; dvar= dvar->next) {
PyObject *driver_arg = NULL;
float tval = 0.0f;
-
+
/* try to get variable value */
- tval= driver_get_target_value(driver, dtar);
+ tval= driver_get_variable_value(driver, dvar);
driver_arg= PyFloat_FromDouble((double)tval);
-
+
/* try to add to dictionary */
- if (PyDict_SetItemString(driver_vars, dtar->name, driver_arg)) {
+ if (PyDict_SetItemString(driver_vars, dvar->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);
+
+ fprintf(stderr, "\tBPY_pydriver_eval() - couldn't add variable '%s' to namespace \n", dvar->name);
// BPy_errors_to_report(NULL); // TODO - reports
PyErr_Print();
PyErr_Clear();
@@ -202,12 +202,14 @@ float BPY_pydriver_eval (ChannelDriver *driver)
/* 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) {
+ /* compile the expression first if it hasn't been compiled or needs to be rebuilt */
+ 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)
+ /* evaluate the compiled expression */
+ if (driver->expr_comp)
retval= PyEval_EvalCode(driver->expr_comp, bpy_pydriver_Dict, driver_vars);
#endif
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 78125954816..9f52cde27e1 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -213,11 +213,12 @@ typedef struct wmNotifier {
#define ND_NLA_SELECT (75<<16)
#define ND_NLA_EDIT (76<<16)
#define ND_NLA_ACTCHANGE (77<<16)
+#define ND_FCURVES_ORDER (78<<16)
/* NC_GEOM Geometry */
/* Mesh, Curve, MetaBall, Armature, .. */
-#define ND_SELECT (80<<16)
-#define ND_DATA (81<<16)
+#define ND_SELECT (90<<16)
+#define ND_DATA (91<<16)
/* NC_NODE Nodes */
#define ND_NODE_SELECT (1<<16)