[Bf-blender-cvs] [3df93d0] master: Fix: Joining armatures loses drivers

Joshua Leung noreply at git.blender.org
Wed Jan 21 14:10:28 CET 2015


Commit: 3df93d063e2d52a2c2e73cfe31801c15682bf0b4
Author: Joshua Leung
Date:   Thu Jan 22 02:08:29 2015 +1300
Branches: master
https://developer.blender.org/rB3df93d063e2d52a2c2e73cfe31801c15682bf0b4

Fix: Joining armatures loses drivers

Currently, when joining two armatures, the drivers of the armatures being merged
in are lost. This commit introduces a new AnimData API function for merging
animation data into another AnimData block.

NOTE:
* For now, this only copies the drivers over. As a result, manual effort will
  still be needed to go through and fix the drivers.

  I am working on automating that process, but it's more important that the
  drivers don't have to be created from scratch for now (since this is needed
  for the Goosberry rigging work).

===================================================================

M	source/blender/blenkernel/BKE_animsys.h
M	source/blender/blenkernel/intern/anim_sys.c
M	source/blender/editors/armature/armature_naming.c
M	source/blender/editors/armature/armature_relations.c

===================================================================

diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index a5109ac..24abd11 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -73,6 +73,20 @@ bool BKE_copy_animdata_id(struct ID *id_to, struct ID *id_from, const bool do_ac
 /* Copy AnimData Actions */
 void BKE_copy_animdata_id_action(struct ID *id);
 
+/* Merge copies of data from source AnimData block */
+typedef enum eAnimData_MergeCopy_Modes {
+	/* Keep destination action */
+	ADT_MERGECOPY_KEEP_DST = 0,
+	
+	/* Use src action (make a new copy) */
+	ADT_MERGECOPY_SRC_COPY = 1,
+	
+	/* Use src action (but just reference the existing version) */
+	ADT_MERGECOPY_SRC_REF  = 2
+} eAnimData_MergeCopy_Modes;
+
+void BKE_animdata_merge_copy(struct ID *dst_id, struct ID *src_id, eAnimData_MergeCopy_Modes action_mode, bool fix_drivers);
+
 /* Make Local */
 void BKE_animdata_make_local(struct AnimData *adt);
 
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 8e36449..00e5c1b 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -318,6 +318,77 @@ void BKE_copy_animdata_id_action(ID *id)
 	}
 }
 
+/* Merge copies of the data from the src AnimData into the destination AnimData */
+void BKE_animdata_merge_copy(ID *dst_id, ID *src_id, eAnimData_MergeCopy_Modes action_mode, bool fix_drivers)
+{
+	AnimData *src = BKE_animdata_from_id(src_id);
+	AnimData *dst = BKE_animdata_from_id(dst_id);
+	
+	/* sanity checks */
+	if (ELEM(NULL, dst, src))
+		return;
+		
+	// TODO: we must unset all "tweakmode" flags
+	if ((src->flag & ADT_NLA_EDIT_ON) || (dst->flag & ADT_NLA_EDIT_ON)) {
+		printf("ERROR: Merging AnimData blocks while editing NLA is dangerous as it may cause data corruption\n");
+		return;
+	}
+	
+	/* handle actions... */
+	if (action_mode == ADT_MERGECOPY_SRC_COPY) {
+		/* make a copy of the actions */
+		dst->action = BKE_action_copy(src->action);
+		dst->tmpact = BKE_action_copy(src->tmpact);
+	}
+	else if (action_mode == ADT_MERGECOPY_SRC_REF) {
+		/* make a reference to it */
+		dst->action = src->action;
+		id_us_plus((ID *)dst->action);
+		
+		dst->tmpact = src->tmpact;
+		id_us_plus((ID *)dst->tmpact);
+	}
+	
+	/* duplicate NLA data */
+	if (src->nla_tracks.first) {
+		ListBase tracks = {NULL, NULL};
+		
+		copy_nladata(&tracks, &src->nla_tracks);
+		BLI_movelisttolist(&dst->nla_tracks, &tracks);
+	}
+	
+	/* duplicate drivers (F-Curves) */
+	if (src->drivers.first) {
+		ListBase drivers = {NULL, NULL};
+		
+		copy_fcurves(&drivers, &src->drivers);
+		
+		/* Fix up all driver targets using the old target id
+		 * - This assumes that the src ID is being merged into the dst ID
+		 */
+		if (fix_drivers) {
+			FCurve *fcu;
+			
+			for (fcu = drivers.first; fcu; fcu = fcu->next) {
+				ChannelDriver *driver = fcu->driver;
+				DriverVar *dvar;
+				
+				for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+					DRIVER_TARGETS_USED_LOOPER(dvar)
+					{
+						if (dtar->id == src_id) {
+							dtar->id = dst_id;
+						}
+					}
+					DRIVER_TARGETS_LOOPER_END
+				}
+			}
+		}
+		
+		BLI_movelisttolist(&dst->drivers, &drivers);
+	}
+}
+
 /* Make Local -------------------------------------------- */
 
 static void make_local_strips(ListBase *strips)
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index 9afc459..f984bf0 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -267,6 +267,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n
 		/* Fix all animdata that may refer to this bone - we can't just do the ones attached to objects, since
 		 * other ID-blocks may have drivers referring to this bone [#29822]
 		 */
+		// XXX: the ID here is for armatures, but most bone drivers are actually on the object instead...
 		{
 			
 			BKE_all_animdata_fix_paths_rename(&arm->id, "pose.bones", oldname, newname);
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index 3e226c3..2a19d7a 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -40,6 +40,7 @@
 #include "BLF_translation.h"
 
 #include "BKE_action.h"
+#include "BKE_animsys.h"
 #include "BKE_constraint.h"
 #include "BKE_context.h"
 #include "BKE_depsgraph.h"
@@ -200,6 +201,33 @@ int join_armature_exec(bContext *C, wmOperator *op)
 		if ((base->object->type == OB_ARMATURE) && (base->object != ob)) {
 			bArmature *curarm = base->object->data;
 			
+			/* we assume that each armature datablock is only used in a single place */
+			BLI_assert(ob->data != base->object->data);
+			
+			/* copy over animdata first, so that the link fixing can access and fix the links */
+			if (base->object->adt) {
+				if (ob->adt == NULL) {
+					/* no animdata, so just use a copy of the whole thing */
+					ob->adt = BKE_copy_animdata(base->object->adt, false);
+				}
+				else {
+					/* merge in data - we'll fix the drivers manually */
+					BKE_animdata_merge_copy(&ob->id, &base->object->id, ADT_MERGECOPY_KEEP_DST, false);
+				}
+			}
+			
+			if (curarm->adt) {
+				if (arm->adt == NULL) {
+					/* no animdata, so just use a copy of the whole thing */
+					arm->adt = BKE_copy_animdata(curarm->adt, false);
+				}
+				else {
+					/* merge in data - we'll fix the drivers manually */
+					BKE_animdata_merge_copy(&arm->id, &curarm->id, ADT_MERGECOPY_KEEP_DST, false);
+				}
+			}
+			
+			
 			/* Make a list of editbones in current armature */
 			ED_armature_to_edit(base->object->data);




More information about the Bf-blender-cvs mailing list