[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [19752] branches/blender2.5/blender/source /blender: Animato - Drivers with Multiple Targets:

Joshua Leung aligorith at gmail.com
Thu Apr 16 09:37:07 CEST 2009


Revision: 19752
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=19752
Author:   aligorith
Date:     2009-04-16 09:37:06 +0200 (Thu, 16 Apr 2009)

Log Message:
-----------
Animato - Drivers with Multiple Targets:

Drivers now support multiple targets which act as 'variables'. The targets have a short 'name' (see later), and reference some property (in much the same way as F-Curves do, using RNA-Paths) which acts as the 'value'. 

These named variables can then be used in a Python Expression which relates them to each other for more fine-grained control over the result of the driver. By using only the names of these variables in the expressions, we are able to define expressions/relationships in a much more readable way, as data access is separated from data use. This makes the underlying relationships easier to understand.

By default, if no Python Expression is given, the variables are simply averaged together, so old files won't break. :)

For example, check the following diagram (thanks Cessen/Nathan V from Peach team):
http://download.blender.org/ftp/incoming/250_drivers_mockup_cessen.png


TODO List:
* Depsgraph building for new driver relationships doesn't work yet. This needs to be recoded again, but this new system makes this much easier, since the targets are clearly defined (i.e. no need to parse py expressions to get list of objects)
* Graph Editor interface for editing these needs to be rewritten
* Python function for evaluating these expressions is needed (Campbell?)

Modified Paths:
--------------
    branches/blender2.5/blender/source/blender/blenkernel/BKE_fcurve.h
    branches/blender2.5/blender/source/blender/blenkernel/intern/depsgraph.c
    branches/blender2.5/blender/source/blender/blenkernel/intern/fcurve.c
    branches/blender2.5/blender/source/blender/blenkernel/intern/ipo.c
    branches/blender2.5/blender/source/blender/blenloader/intern/readfile.c
    branches/blender2.5/blender/source/blender/blenloader/intern/writefile.c
    branches/blender2.5/blender/source/blender/editors/space_graph/graph_buttons.c
    branches/blender2.5/blender/source/blender/editors/space_outliner/outliner.c
    branches/blender2.5/blender/source/blender/makesdna/DNA_anim_types.h
    branches/blender2.5/blender/source/blender/makesrna/RNA_access.h
    branches/blender2.5/blender/source/blender/makesrna/intern/rna_action.c

Modified: branches/blender2.5/blender/source/blender/blenkernel/BKE_fcurve.h
===================================================================
--- branches/blender2.5/blender/source/blender/blenkernel/BKE_fcurve.h	2009-04-16 06:24:47 UTC (rev 19751)
+++ branches/blender2.5/blender/source/blender/blenkernel/BKE_fcurve.h	2009-04-16 07:37:06 UTC (rev 19752)
@@ -6,9 +6,12 @@
 #define BKE_FCURVE_H
 
 //struct ListBase;
+
 struct FCurve;
 struct FModifier;
 struct ChannelDriver;
+struct DriverTarget;
+
 struct BezTriple;
 
 /* ************** Keyframe Tools ***************** */
@@ -27,6 +30,9 @@
 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);
+
 /* ************** F-Curve Modifiers *************** */
 
 /* F-Curve Modifier Type-Info (fmi):

Modified: branches/blender2.5/blender/source/blender/blenkernel/intern/depsgraph.c
===================================================================
--- branches/blender2.5/blender/source/blender/blenkernel/intern/depsgraph.c	2009-04-16 06:24:47 UTC (rev 19751)
+++ branches/blender2.5/blender/source/blender/blenkernel/intern/depsgraph.c	2009-04-16 07:37:06 UTC (rev 19752)
@@ -346,6 +346,7 @@
 		else if (driver->type == DRIVER_TYPE_ROTDIFF) {
 			// XXX rotational difference 
 		}
+#if 0 // XXX old animato 
 		else if (driver->id) {
 			if(GS(driver->id->name)==ID_OB) {
 				/* normal channel-drives-channel */
@@ -358,6 +359,7 @@
 					dag_add_relation(dag, node1, node, isdata?DAG_RL_OB_DATA:DAG_RL_OB_OB, "Ipo Driver");
 			}
 		}
+#endif // XXX old animato
 #if 0 // XXX old 'normal' type
 
 		else if (icu->driver->ob) {

Modified: branches/blender2.5/blender/source/blender/blenkernel/intern/fcurve.c
===================================================================
--- branches/blender2.5/blender/source/blender/blenkernel/intern/fcurve.c	2009-04-16 06:24:47 UTC (rev 19751)
+++ branches/blender2.5/blender/source/blender/blenkernel/intern/fcurve.c	2009-04-16 07:37:06 UTC (rev 19752)
@@ -558,19 +558,60 @@
 
 /* Driver API --------------------------------- */
 
+/* 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);
+	
+	/* remove the target from the driver */
+	if (driver)
+		BLI_freelinkN(&driver->targets, dtar);
+	else
+		MEM_freeN(dtar);
+}
+
+/* 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);
+	
+	/* give the target a name */
+	strcpy(dtar->name, "a"); // XXX fimxe... this needs more work to get unique names without dots...
+	
+	/* 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 RNA-paths, as these were allocated when getting the path string */
-	if (driver->rna_path) MEM_freeN(driver->rna_path);
-	if (driver->rna_path2) MEM_freeN(driver->rna_path2);
+	/* free driver targets */
+	for (dtar= driver->targets.first; dtar; dtar= dtarn) {
+		dtarn= dtar->next;
+		driver_free_target(driver, dtar);
+	}
 	
 	/* free driver itself, then set F-Curve's point to this to NULL (as the curve may still be used) */
 	MEM_freeN(driver);
@@ -581,6 +622,7 @@
 ChannelDriver *fcurve_copy_driver (ChannelDriver *driver)
 {
 	ChannelDriver *ndriver;
+	DriverTarget *dtar;
 	
 	/* sanity checks */
 	if (driver == NULL)
@@ -588,19 +630,25 @@
 		
 	/* copy all data */
 	ndriver= MEM_dupallocN(driver);
-	ndriver->rna_path= MEM_dupallocN(ndriver->rna_path);
-	ndriver->rna_path2= MEM_dupallocN(ndriver->rna_path2);
 	
+	/* copy targets */
+	ndriver->targets.first= ndriver->targets.last= NULL;
+	BLI_duplicatelist(&ndriver->targets, &driver->targets);
+	
+	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);
+	}
+	
 	/* return the new driver */
 	return ndriver;
 }
 
 /* Driver Evaluation -------------------------- */
 
-/* Helper function to obtain a value using RNA from the specified source (for evaluating drivers) 
- * 	- target: used to specify which of the two driver-targets to use
- */
-static float driver_get_driver_value (ChannelDriver *driver, short target)
+/* Helper function to obtain a value using RNA from the specified source (for evaluating drivers) */
+static float driver_get_target_value (ChannelDriver *driver, DriverTarget *dtar)
 {
 	PointerRNA id_ptr, ptr;
 	PropertyRNA *prop;
@@ -609,22 +657,16 @@
 	int index;
 	float value= 0.0f;
 	
-	/* get RNA-pointer for the ID-block given in driver */
-	if (target == 1) {
-		/* second target */
-		RNA_id_pointer_create(driver->id2, &id_ptr);
-		id= driver->id2;
-		path= driver->rna_path2;
-		index= driver->array_index2;
-	}
-	else {
-		/* first/main target */
-		RNA_id_pointer_create(driver->id, &id_ptr);
-		id= driver->id;
-		path= driver->rna_path;
-		index= driver->array_index;
-	}
+	/* sanity check */
+	if ELEM(NULL, driver, dtar)
+		return 0.0f;
 	
+	/* get RNA-pointer for the ID-block given in target */
+	RNA_id_pointer_create(dtar->id, &id_ptr);
+	id= dtar->id;
+	path= dtar->rna_path;
+	index= dtar->array_index;
+	
 	/* error check for missing pointer... */
 	if (id == NULL) {
 		printf("Error: driver doesn't have any valid target to use \n");
@@ -671,14 +713,37 @@
  */
 static float evaluate_driver (ChannelDriver *driver, float evaltime)
 {
+	DriverTarget *dtar;
+	
 	/* check if driver can be evaluated */
-	if (driver->flag & DRIVER_FLAG_DISABLED)
+	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_CHANNEL: /* channel/setting drivers channel/setting */
-			return driver_get_driver_value(driver, 0);
-			
+		case DRIVER_TYPE_AVERAGE: /* average values of driver targets */
+		{
+			/* check how many targets there are first (i.e. just one?) */
+			if (driver->targets.first == driver->targets.last) {
+				/* just one target, so just use that */
+				dtar= driver->targets.first;
+				return driver_get_target_value(driver, dtar);
+			}
+			else {
+				/* more than one target, so average the values of the targets */
+				int tot = 0;
+				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); 
+					tot++;
+				}
+				
+				/* return the average of these */
+				return (value / (float)tot);
+			}
+		}
 
 		case DRIVER_TYPE_PYTHON: /* expression */
 		{

Modified: branches/blender2.5/blender/source/blender/blenkernel/intern/ipo.c
===================================================================
--- branches/blender2.5/blender/source/blender/blenkernel/intern/ipo.c	2009-04-16 06:24:47 UTC (rev 19751)
+++ branches/blender2.5/blender/source/blender/blenkernel/intern/ipo.c	2009-04-16 07:37:06 UTC (rev 19752)
@@ -950,6 +950,7 @@
 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");
@@ -957,6 +958,7 @@
 	/* if 'pydriver', just copy data across */
 	if (idriver->type == IPO_DRIVER_TYPE_PYTHON) {
 		/* PyDriver only requires the expression to be copied */
+		// TODO: but the expression will be useless...
 		cdriver->type = DRIVER_TYPE_PYTHON;
 		strcpy(cdriver->expression, idriver->name); // XXX is this safe? 
 	}
@@ -965,12 +967,15 @@
 		if (idriver->blocktype == ID_AR) {
 			/* ID_PO */
 			if (idriver->adrcode == OB_ROT_DIFF) {
-				if (G.f & G_DEBUG) printf("idriver_to_cdriver - rotdiff %p \n", idriver->ob);
 				/* Rotational Difference is a special type of driver now... */
 				cdriver->type= DRIVER_TYPE_ROTDIFF;
 				
+				/* make 2 driver targets */
+				dtar= driver_add_new_target(cdriver);
+				dtar2= driver_add_new_target(cdriver);
+				
 				/* driver must use bones from same armature... */
-				cdriver->id= cdriver->id2= (ID *)idriver->ob;
+				dtar->id= dtar2->id= (ID *)idriver->ob;
 				
 				/* paths for the two targets get the pointers to the relevant Pose-Channels 
 				 *	- return pointers to Pose-Channels not rotation channels, as calculation code is picky
@@ -979,34 +984,36 @@
 				 *	- we use several hacks here - blocktype == -1 specifies that no property needs to be found, and
 				 *	  providing a name for 'actname' will automatically imply Pose-Channel with name 'actname'
 				 */
-				cdriver->rna_path= get_rna_access(-1, -1, idriver->name, NULL, NULL);
-				cdriver->rna_path2= get_rna_access(-1, -1, idriver->name+DRIVER_NAME_OFFS, NULL, NULL);
+				dtar->rna_path= get_rna_access(-1, -1, idriver->name, NULL, NULL);
+				dtar2->rna_path= get_rna_access(-1, -1, idriver->name+DRIVER_NAME_OFFS, NULL, NULL);
 			}
 			else {
-				if (G.f & G_DEBUG) printf("idriver_to_cdriver - arm  %p \n", idriver->ob);
 				/* 'standard' driver */
-				cdriver->type= DRIVER_TYPE_CHANNEL;
-				cdriver->id= (ID *)idriver->ob;
+				cdriver->type= DRIVER_TYPE_AVERAGE;
 				
+				/* make 1 driver target */
+				dtar= driver_add_new_target(cdriver);
+				dtar->id= (ID *)idriver->ob;
+				
 				switch (idriver->adrcode) {
 					case OB_LOC_X:	/* x,y,z location are quite straightforward */
-						cdriver->rna_path= get_rna_access(ID_PO, AC_LOC_X, idriver->name, NULL, &cdriver->array_index);
+						dtar->rna_path= get_rna_access(ID_PO, AC_LOC_X, idriver->name, NULL, &dtar->array_index);
 						break;
 					case OB_LOC_Y:
-						cdriver->rna_path= get_rna_access(ID_PO, AC_LOC_Y, idriver->name, NULL, &cdriver->array_index);
+						dtar->rna_path= get_rna_access(ID_PO, AC_LOC_Y, idriver->name, NULL, &dtar->array_index);
 						break;
 					case OB_LOC_Z:

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list