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).
This commit is contained in:
Joshua Leung 2015-01-22 02:08:29 +13:00
parent f087e9930d
commit 3df93d063e
4 changed files with 114 additions and 0 deletions

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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);