Durian Request: Drivers Recode
authorJoshua Leung <aligorith@gmail.com>
Mon, 4 Jan 2010 21:15:45 +0000 (21:15 +0000)
committerJoshua Leung <aligorith@gmail.com>
Mon, 4 Jan 2010 21:15:45 +0000 (21:15 +0000)
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.

23 files changed:
release/scripts/modules/rigify/arm_biped_generic.py
release/scripts/modules/rigify/finger_curl.py
release/scripts/modules/rigify/leg_biped_generic.py
release/scripts/modules/rigify/neck_flex.py
release/scripts/modules/rigify/palm_curl.py
release/scripts/modules/rigify/spine_pivot_flex.py
release/scripts/modules/rigify_utils.py
source/blender/blenkernel/BKE_fcurve.h
source/blender/blenkernel/intern/anim_sys.c
source/blender/blenkernel/intern/depsgraph.c
source/blender/blenkernel/intern/fcurve.c
source/blender/blenkernel/intern/ipo.c
source/blender/blenkernel/intern/object.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/animation/drivers.c
source/blender/editors/space_graph/graph_buttons.c
source/blender/editors/space_outliner/outliner.c
source/blender/makesdna/DNA_anim_types.h
source/blender/makesrna/RNA_access.h
source/blender/makesrna/intern/rna_fcurve.c
source/blender/python/intern/bpy_driver.c
source/blender/windowmanager/WM_types.h

index 092a047f0daa14327b45ce568ce17906661fdbea..0974b1b80105160a364d68b4a8ebbe3949aeffb3 100644 (file)
@@ -254,11 +254,11 @@ def fk(obj, definitions, base_names, options):
         driver = driver_fcurve.driver
         driver.type = 'AVERAGE'
 
-        tar = driver.targets.new()
-        tar.name = "hinge"
-        tar.id_type = 'OBJECT'
-        tar.id = obj
-        tar.data_path = controller_path + '["hinge"]'
+        var = driver.variables.new()
+        var.name = "hinge"
+        var.targets[0].id_type = 'OBJECT'
+        var.targets[0].id = obj
+        var.targets[0].data_path = controller_path + '["hinge"]'
 
         mod = driver_fcurve.modifiers[0]
         mod.poly_order = 1
index 7eb1588efd6970113996132e9d5706249ef88775..4c00f134e190e73d1cb278fcec83cc9d5646f03a 100644 (file)
@@ -251,18 +251,18 @@ def main(obj, bone_definition, base_names, options):
         driver = fcurve_driver.driver
 
         # scale target
-        tar = driver.targets.new()
-        tar.name = "scale"
-        tar.id_type = 'OBJECT'
-        tar.id = obj
-        tar.data_path = controller_path + '.scale[1]'
+        var = driver.variables.new()
+        var.name = "scale"
+        var.targets[0].id_type = 'OBJECT'
+        var.targets[0].id = obj
+        var.targets[0].data_path = controller_path + '.scale[1]'
 
         # bend target
-        tar = driver.targets.new()
-        tar.name = "br"
-        tar.id_type = 'OBJECT'
-        tar.id = obj
-        tar.data_path = controller_path + '["bend_ratio"]'
+        var = driver.variables.new()
+        var.name = "br"
+        var.targets[0].id_type = 'OBJECT'
+        var.targets[0].id = obj
+        var.targets[0].data_path = controller_path + '["bend_ratio"]'
 
         # XXX - todo, any number
         if i == 0:
index f2d59a96032e7e1a259d20b7ac87b4f099731f4f..2bf53ddc1ce775da0d6ecc9c014d0a62eea8708b 100644 (file)
@@ -336,12 +336,12 @@ def fk(obj, bone_definition, base_names, options):
 
     fcurve = con.driver_add("influence", 0)
     driver = fcurve.driver
-    tar = driver.targets.new()
+    var = driver.variables.new()
     driver.type = 'AVERAGE'
-    tar.name = "var"
-    tar.id_type = 'OBJECT'
-    tar.id = obj
-    tar.data_path = hinge_driver_path
+    var.name = "var"
+    var.targets[0].id_type = 'OBJECT'
+    var.targets[0].id = obj
+    var.targets[0].data_path = hinge_driver_path
 
     mod = fcurve.modifiers[0]
     mod.poly_order = 1
index 7b5b8c6bacb83f59b2265f86a9352d75a8776bfa..a56c7dcb4e3fcdf1b067e0b1645ef489f275b8fc 100644 (file)
@@ -238,12 +238,12 @@ def main(obj, bone_definition, base_names, options):
 
     fcurve = con.driver_add("influence", 0)
     driver = fcurve.driver
-    tar = driver.targets.new()
+    var = driver.variables.new()
     driver.type = 'AVERAGE'
-    tar.name = "var"
-    tar.id_type = 'OBJECT'
-    tar.id = obj
-    tar.data_path = hinge_driver_path
+    var.name = "var"
+    var.targets[0].id_type = 'OBJECT'
+    var.targets[0].id = obj
+    var.targets[0].data_path = hinge_driver_path
 
     #mod = fcurve_driver.modifiers.new('GENERATOR')
     mod = fcurve.modifiers[0]
@@ -262,11 +262,11 @@ def main(obj, bone_definition, base_names, options):
     fcurve.modifiers.remove(0) # grr dont need a modifier
 
     for i in range(len(neck_chain)):
-        tar = driver.targets.new()
-        tar.name = target_names[i]
-        tar.id_type = 'OBJECT'
-        tar.id = obj
-        tar.data_path = head_driver_path + ('["bend_%.2d"]' % (i + 1))
+        var = driver.variables.new()
+        var.name = target_names[i]
+        var.targets[0].id_type = 'OBJECT'
+        var.targets[0].id = obj
+        var.targets[0].data_path = head_driver_path + ('["bend_%.2d"]' % (i + 1))
 
 
     for i, attr in enumerate(ex_chain.attr_names):
@@ -302,17 +302,17 @@ def main(obj, bone_definition, base_names, options):
 
 
         # add target
-        tar = driver.targets.new()
-        tar.name = "bend_tot"
-        tar.id_type = 'OBJECT'
-        tar.id = obj
-        tar.data_path = head_driver_path + ('["bend_tot"]')
-
-        tar = driver.targets.new()
-        tar.name = "bend"
-        tar.id_type = 'OBJECT'
-        tar.id = obj
-        tar.data_path = head_driver_path + ('["%s"]' % prop_name)
+        var = driver.variables.new()
+        var.name = "bend_tot"
+        var.targets[0].id_type = 'OBJECT'
+        var.targets[0].id = obj
+        var.targets[0].data_path = head_driver_path + ('["bend_tot"]')
+
+        var = driver.variables.new()
+        var.name = "bend"
+        var.targets[0].id_type = 'OBJECT'
+        var.targets[0].id = obj
+        var.targets[0].data_path = head_driver_path + ('["%s"]' % prop_name)
 
 
         # finally constrain the original bone to this one
index 489310798167e20e72b02d6ceb3490f501250bd6..548c311f823b01bb5827d1b23eb2d10e265095b7 100644 (file)
@@ -169,22 +169,22 @@ def main(obj, bone_definition, base_names, options):
     driver = driver_fcurves[0].driver
     driver.type = 'AVERAGE'
 
-    tar = driver.targets.new()
-    tar.name = "x"
-    tar.id_type = 'OBJECT'
-    tar.id = obj
-    tar.data_path = controller_path + ".rotation_euler[0]"
+    var = driver.variables.new()
+    var.name = "x"
+    var.targets[0].id_type = 'OBJECT'
+    var.targets[0].id = obj
+    var.targets[0].data_path = controller_path + ".rotation_euler[0]"
 
 
     # *****
     driver = driver_fcurves[1].driver
     driver.expression = "-x/4.0"
 
-    tar = driver.targets.new()
-    tar.name = "x"
-    tar.id_type = 'OBJECT'
-    tar.id = obj
-    tar.data_path = controller_path + ".rotation_euler[0]"
+    var = driver.variables.new()
+    var.name = "x"
+    var.targets[0].id_type = 'OBJECT'
+    var.targets[0].id = obj
+    var.targets[0].data_path = controller_path + ".rotation_euler[0]"
 
 
     # *****
@@ -194,17 +194,17 @@ def main(obj, bone_definition, base_names, options):
     for fcurve in driver_fcurves:
         fcurve.modifiers.remove(0) # grr dont need a modifier
 
-    tar = driver.targets.new()
-    tar.name = "x"
-    tar.id_type = 'OBJECT'
-    tar.id = obj
-    tar.data_path = controller_path + ".rotation_euler[0]"
-
-    tar = driver.targets.new()
-    tar.name = "s"
-    tar.id_type = 'OBJECT'
-    tar.id = obj
-    tar.data_path = controller_path + '["spread"]'
+    var = driver.variables.new()
+    var.name = "x"
+    var.targets[0].id_type = 'OBJECT'
+    var.targets[0].id = obj
+    var.targets[0].data_path = controller_path + ".rotation_euler[0]"
+
+    var = driver.variables.new()
+    var.name = "s"
+    var.targets[0].id_type = 'OBJECT'
+    var.targets[0].id = obj
+    var.targets[0].data_path = controller_path + '["spread"]'
 
 
     for i, child_name in enumerate(children):
index a8ba71d1fe63378692007ffdcb114181f7fa0b27..c6a5fa673903f1ab1fee35cd701961e3cedc7321 100644 (file)
@@ -341,12 +341,12 @@ def main(obj, bone_definition, base_names, options):
     # add driver
     fcurve = con.driver_add("influence", 0)
     driver = fcurve.driver
-    tar = driver.targets.new()
+    var = driver.variables.new()
     driver.type = 'AVERAGE'
-    tar.name = "var"
-    tar.id_type = 'OBJECT'
-    tar.id = obj
-    tar.data_path = ex.ribcage_copy_p.path_to_id() + '["hinge"]'
+    var.name = "var"
+    var.targets[0].id_type = 'OBJECT'
+    var.targets[0].id = obj
+    var.targets[0].data_path = ex.ribcage_copy_p.path_to_id() + '["hinge"]'
 
     mod = fcurve.modifiers[0]
     mod.poly_order = 1
@@ -426,11 +426,11 @@ def main(obj, bone_definition, base_names, options):
     fcurve.modifiers.remove(0) # grr dont need a modifier
 
     for i in range(spine_chain_len - 1):
-        tar = driver.targets.new()
-        tar.name = target_names[i]
-        tar.id_type = 'OBJECT'
-        tar.id = obj
-        tar.data_path = rib_driver_path + ('["bend_%.2d"]' % (i + 1))
+        var = driver.variables.new()
+        var.name = target_names[i]
+        var.targets[0].id_type = 'OBJECT'
+        var.targets[0].id = obj
+        var.targets[0].data_path = rib_driver_path + ('["bend_%.2d"]' % (i + 1))
 
     for i in range(1, spine_chain_len):
 
@@ -461,17 +461,17 @@ def main(obj, bone_definition, base_names, options):
 
 
         # add target
-        tar = driver.targets.new()
-        tar.name = "bend_tot"
-        tar.id_type = 'OBJECT'
-        tar.id = obj
-        tar.data_path = rib_driver_path + ('["bend_tot"]')
+        var = driver.variables.new()
+        var.name = "bend_tot"
+        var.targets[0].id_type = 'OBJECT'
+        var.targets[0].id = obj
+        var.targets[0].data_path = rib_driver_path + ('["bend_tot"]')
 
-        tar = driver.targets.new()
-        tar.name = "bend"
-        tar.id_type = 'OBJECT'
-        tar.id = obj
-        tar.data_path = rib_driver_path + ('["%s"]' % prop_name)
+        var = driver.variables.new()
+        var.name = "bend"
+        var.targets[0].id_type = 'OBJECT'
+        var.targets[0].id = obj
+        var.targets[0].data_path = rib_driver_path + ('["%s"]' % prop_name)
 
 
 
@@ -509,12 +509,12 @@ def main(obj, bone_definition, base_names, options):
 
         fcurve = con.driver_add("influence", 0)
         driver = fcurve.driver
-        tar = driver.targets.new()
+        var = driver.variables.new()
         driver.type = 'AVERAGE'
-        tar.name = "var"
-        tar.id_type = 'OBJECT'
-        tar.id = obj
-        tar.data_path = rib_driver_path + '["pivot_slide"]'
+        var.name = "var"
+        var.targets[0].id_type = 'OBJECT'
+        var.targets[0].id = obj
+        var.targets[0].data_path = rib_driver_path + '["pivot_slide"]'
 
         mod = fcurve.modifiers[0]
         mod.poly_order = 1
index 83b23b288699e62027a286dc2fa80f127744bab7..b453ef77d4f6d9dbaf320425742c5b16fac85c8f 100644 (file)
@@ -138,11 +138,11 @@ def blend_bone_list(obj, apply_bones, from_bones, to_bones, target_bone=None, ta
     driver_path = prop_pbone.path_to_id() + ('["%s"]' % target_prop)
 
     def blend_target(driver):
-        tar = driver.targets.new()
-        tar.name = target_bone
-        tar.id_type = 'OBJECT'
-        tar.id = obj
-        tar.data_path = driver_path
+        var = driver.variables.new()
+        var.name = target_bone
+        var.targets[0].id_type = 'OBJECT'
+        var.targets[0].id = obj
+        var.targets[0].data_path = driver_path
 
     def blend_location(new_pbone, from_bone_name, to_bone_name):
         con = new_pbone.constraints.new('COPY_LOCATION')
index fa6b8969edb5ee7c23bd9dc00b1b7304f4f22606..d3457a5f5aea15ad24df958bd16c0aaaeb9d2500 100644 (file)
@@ -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 *************** */
 
index 4f96b031daa00f2e9d114fdae3ab148499bef66d..4c63c64ccb973b3630a1fd41e3af6fed6123ad4e 100644 (file)
@@ -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
                        }
                }
        }
index 2f08abd82b37fa18b39403285b74fba5b2113f32..e664dd01f4d20b3bb7834f81be6667b20b8f447a 100644 (file)
@@ -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
                }
        }
 }
index d5e033652a8f1021098ff936762e4b10e674ac5b..9e84727fbf1d93eb39648f649b9e5319b6a14978 100644 (file)
@@ -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:
                {
index 6fc3fc547dfd97262dfbcd48b10fa03763f32938..988bd42918506ea3c388688e0c1990a275c2722e 100644 (file)
@@ -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
index 0f9198df26335ece9244ec5a0b9641e6154dc6b8..762ad2432b09704a7f687f80adbbb1c2c5d0d8fe 100644 (file)
@@ -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
                        }
                }
        }
index 3e35250bd748a977274f7fe17b6eea3e21e17074..1eff6c8f8e3349d1a42a3c2f88e5a518bb49db06 100644 (file)
@@ -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 */
index 98d3dc5188aab9b383cbf06b4f532d086a341d09..061ed71d77ea772587e81bb76fe6cb8c150333d1 100644 (file)
@@ -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
                        }
                }
                
index 59e52c0d489d47c02024674fa9b3feba8af60f3b..b816ffbe905abec89ccf8a0fdb9dfb8960917cb6 100644 (file)
@@ -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;
index 3faba9bbba7f32bd2d4840896c7feaf07bc42dcf..c42dfd0015d427f0084aa80df08464bbea1a9e85 100644 (file)
@@ -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 */
index 1303168e78d3b1454cfe30c46b384280a09f8492..93b3208661481a06bd045ce468d82e101d8d1d7c 100644 (file)
@@ -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
                                        }
                                }
                        }
index dcb10d0f2cf4cfca26afa02e1a72cb3bf483e3ea..f2d4471607f059058fcd581e570e099e15da7379 100644 (file)
@@ -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;
index e631e037e744ac2846d9a08038a0219788bb9cc9..5697747fcabe993b391abc87f9dd1cfffd27eb0b 100644 (file)
@@ -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;
index 62ee19df35269a902bdc506dcfd76278e1712346..10fece3391f511611107c5f8965aa957630ad61c 100644 (file)
@@ -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);
index 76df28494ac90f905608bba69227be82fc41b800..016aed70c31b6486dd9277309c77a718a3659d48 100644 (file)
@@ -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
 
index 781259548165bd5027806fd677b31d6b6cb104f9..9f52cde27e1a71e791a0e32392b28ccba25082ee 100644 (file)
@@ -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)