Files
test2/source/blender/animrig/intern/pose.cc
Sybren A. Stüvel 7cb77d925a Anim: add NLA evaluation of slotted Actions
Add support for slotted Actions to the NLA evaluation code.

This also affects the pose library code and the Action Constraint. These
both share some Action evaluation logic with the NLA. They now
explicitly looks at only the first Action slot. The Action Constraint will
have to be updated to have an explicit slot selector, but that's for another
commit.

Pull Request: https://projects.blender.org/blender/blender/pulls/127425
2024-09-13 12:34:50 +02:00

122 lines
4.0 KiB
C++

/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup animrig
*/
#include "ANIM_pose.hh"
#include "BKE_action.hh"
#include "BKE_animsys.h"
#include "BKE_armature.hh"
#include "BLI_listbase.h"
#include "DNA_anim_types.h"
#include "DNA_object_types.h"
#include "RNA_access.hh"
#include "ANIM_action.hh"
namespace blender::animrig {
namespace {
using ActionApplier = blender::FunctionRef<void(
PointerRNA *, bAction *, slot_handle_t, const AnimationEvalContext *)>;
void pose_apply_restore_fcurves(bAction *action)
{
/* TODO(Sybren): Restore the FCurve flags, instead of just erasing the 'disabled' flag. */
LISTBASE_FOREACH (FCurve *, fcu, &action->curves) {
fcu->flag &= ~FCURVE_DISABLED;
}
}
void pose_apply_disable_fcurves_for_unselected_bones(
bAction *action, const blender::bke::BoneNameSet &selected_bone_names)
{
auto disable_unselected_fcurve = [&](FCurve *fcu, const char *bone_name) {
const bool is_bone_selected = selected_bone_names.contains(bone_name);
if (!is_bone_selected) {
fcu->flag |= FCURVE_DISABLED;
}
};
blender::bke::BKE_action_find_fcurves_with_bones(action, disable_unselected_fcurve);
}
void pose_apply(Object *ob,
bAction *action,
const slot_handle_t slot_handle,
const AnimationEvalContext *anim_eval_context,
ActionApplier applier)
{
bPose *pose = ob->pose;
if (pose == nullptr) {
return;
}
const bArmature *armature = (bArmature *)ob->data;
const blender::bke::BoneNameSet selected_bone_names =
blender::bke::BKE_armature_find_selected_bone_names(armature);
const bool limit_to_selected_bones = !selected_bone_names.is_empty();
if (limit_to_selected_bones) {
/* Mute all FCurves that are not associated with selected bones. This separates the concept of
* bone selection from the FCurve evaluation code. */
pose_apply_disable_fcurves_for_unselected_bones(action, selected_bone_names);
}
/* Apply the Action. */
PointerRNA pose_owner_ptr = RNA_id_pointer_create(&ob->id);
applier(&pose_owner_ptr, action, slot_handle, anim_eval_context);
if (limit_to_selected_bones) {
pose_apply_restore_fcurves(action);
}
}
} // namespace
void pose_apply_action_selected_bones(Object *ob,
bAction *action,
const int32_t slot_handle,
const AnimationEvalContext *anim_eval_context)
{
auto evaluate_and_apply = [](PointerRNA *ptr,
bAction *act,
const int32_t slot_handle,
const AnimationEvalContext *anim_eval_context) {
animsys_evaluate_action(ptr, act, slot_handle, anim_eval_context, false);
};
pose_apply(ob, action, slot_handle, anim_eval_context, evaluate_and_apply);
}
void pose_apply_action_all_bones(Object *ob,
bAction *action,
const int32_t slot_handle,
const AnimationEvalContext *anim_eval_context)
{
PointerRNA pose_owner_ptr = RNA_id_pointer_create(&ob->id);
animsys_evaluate_action(&pose_owner_ptr, action, slot_handle, anim_eval_context, false);
}
void pose_apply_action_blend(Object *ob,
bAction *action,
const int32_t slot_handle,
const AnimationEvalContext *anim_eval_context,
const float blend_factor)
{
auto evaluate_and_blend = [blend_factor](PointerRNA *ptr,
bAction *act,
const int32_t slot_handle,
const AnimationEvalContext *anim_eval_context) {
animsys_blend_in_action(ptr, act, slot_handle, anim_eval_context, blend_factor);
};
pose_apply(ob, action, slot_handle, anim_eval_context, evaluate_and_blend);
}
} // namespace blender::animrig