Anim: add layered Action support to BKE_animdata_transfer_by_basepath

Add explicit handling of slots to `BKE_animdata_transfer_by_basepath()`,
and modernise the code to use the new API.

No functional changes for legacy Actions.

Ref: #123424

Pull Request: https://projects.blender.org/blender/blender/pulls/128088
This commit is contained in:
Sybren A. Stüvel
2024-09-24 18:02:49 +02:00
parent 4159f60e46
commit 02ebab57da

View File

@@ -49,6 +49,7 @@
#include "RNA_access.hh"
#include "RNA_path.hh"
#include "ANIM_action_iterators.hh"
#include "ANIM_action_legacy.hh"
#include "CLG_log.h"
@@ -625,12 +626,12 @@ static void animpath_update_basepath(FCurve *fcu,
* F-Curves to need to be moved over too
*/
static void action_move_fcurves_by_basepath(bAction *srcAct,
const animrig::slot_handle_t src_slot_handle,
bAction *dstAct,
const animrig::slot_handle_t dst_slot_handle,
const char *src_basepath,
const char *dst_basepath)
{
FCurve *fcu, *fcn = nullptr;
/* sanity checks */
if (ELEM(nullptr, srcAct, dstAct, src_basepath, dst_basepath)) {
if (G.debug & G_DEBUG) {
@@ -645,72 +646,22 @@ static void action_move_fcurves_by_basepath(bAction *srcAct,
return;
}
/* clear 'temp' flags on all groups in src, as we'll be needing them later
* to identify groups that we've managed to empty out here
*/
action_groups_clear_tempflags(srcAct);
animrig::Action &source_action = srcAct->wrap();
animrig::Action &dest_action = dstAct->wrap();
/* iterate over all src F-Curves, moving over the ones that need to be moved */
for (fcu = static_cast<FCurve *>(srcAct->curves.first); fcu; fcu = fcn) {
/* store next pointer in case we move stuff */
fcn = fcu->next;
/* should F-Curve be moved over?
* - we only need the start of the path to match basepath
*/
if (animpath_matches_basepath(fcu->rna_path, src_basepath)) {
bActionGroup *agrp = nullptr;
/* if grouped... */
if (fcu->grp) {
/* make sure there will be a matching group on the other side for the migrants */
agrp = BKE_action_group_find_name(dstAct, fcu->grp->name);
if (agrp == nullptr) {
/* add a new one with a similar name (usually will be the same though) */
agrp = action_groups_add_new(dstAct, fcu->grp->name);
}
/* old groups should be tagged with 'temp' flags so they can be removed later
* if we remove everything from them
*/
fcu->grp->flag |= AGRP_TEMP;
}
/* perform the migration now */
action_groups_remove_channel(srcAct, fcu);
animpath_update_basepath(fcu, src_basepath, dst_basepath);
if (agrp) {
action_groups_add_channel(dstAct, agrp, fcu);
}
else {
BLI_addtail(&dstAct->curves, fcu);
}
/* Get a list of all F-Curves to move. This is done in a separate step so we
* don't move the curves while iterating over them at the same time. */
Vector<FCurve *> fcurves_to_move;
animrig::foreach_fcurve_in_action_slot(source_action, src_slot_handle, [&](FCurve &fcurve) {
if (animpath_matches_basepath(fcurve.rna_path, src_basepath)) {
fcurves_to_move.append(&fcurve);
}
}
});
/* cleanup groups (if present) */
if (srcAct->groups.first) {
bActionGroup *agrp, *grp = nullptr;
for (agrp = static_cast<bActionGroup *>(srcAct->groups.first); agrp; agrp = grp) {
grp = agrp->next;
/* only tagged groups need to be considered - clearing these tags or removing them */
if (agrp->flag & AGRP_TEMP) {
/* if group is empty and tagged, then we can remove as this operation
* moved out all the channels that were formerly here
*/
if (BLI_listbase_is_empty(&agrp->channels)) {
BLI_freelinkN(&srcAct->groups, agrp);
}
else {
agrp->flag &= ~AGRP_TEMP;
}
}
}
/* Move the curves from one Action to the other, and change its path to match the destination. */
for (FCurve *fcurve_to_move : fcurves_to_move) {
animpath_update_basepath(fcurve_to_move, src_basepath, dst_basepath);
animrig::action_fcurve_move(dest_action, dst_slot_handle, source_action, *fcurve_to_move);
}
}
@@ -771,16 +722,22 @@ void BKE_animdata_transfer_by_basepath(Main *bmain, ID *srcID, ID *dstID, ListBa
/* Set up an action if necessary, and name it in a similar way so that it
* can be easily found again. */
if (!dstAdt->action) {
bAction *new_action = BKE_action_add(bmain, srcAdt->action->id.name + 2);
/* Reduce user count to 0 as the Action is unused before it's assigned. */
id_us_min(&new_action->id);
animrig::assign_action(new_action, dst_owned_adt);
animrig::Action &new_action = animrig::action_add(*bmain, srcAdt->action->id.name + 2);
if (USER_EXPERIMENTAL_TEST(&U, use_animation_baklava)) {
new_action.slot_add_for_id(*dstID);
}
animrig::assign_action(&new_action, dst_owned_adt);
if (USER_EXPERIMENTAL_TEST(&U, use_animation_baklava)) {
BLI_assert(dstAdt->slot_handle != animrig::Slot::unassigned);
}
}
/* loop over base paths, trying to fix for each one... */
LISTBASE_FOREACH (const AnimationBasePathChange *, basepath_change, basepaths) {
action_move_fcurves_by_basepath(srcAdt->action,
srcAdt->slot_handle,
dstAdt->action,
dstAdt->slot_handle,
basepath_change->src_basepath,
basepath_change->dst_basepath);
}