Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/armature_pose.cc
| Show All 17 Lines | |||||
| * | * | ||||
| * Defines and code for core node types | * Defines and code for core node types | ||||
| */ | */ | ||||
| /** \file | /** \file | ||||
| * \ingroup bke | * \ingroup bke | ||||
| */ | */ | ||||
| #include "BKE_action.hh" | |||||
| #include "BKE_animsys.h" | #include "BKE_animsys.h" | ||||
| #include "BKE_armature.h" | #include "BKE_armature.hh" | ||||
| #include "BLI_function_ref.hh" | |||||
| #include "BLI_set.hh" | #include "BLI_set.hh" | ||||
| #include "DNA_action_types.h" | #include "DNA_action_types.h" | ||||
| #include "DNA_anim_types.h" | #include "DNA_anim_types.h" | ||||
| #include "DNA_armature_types.h" | #include "DNA_armature_types.h" | ||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| #include "RNA_access.h" | #include "RNA_access.h" | ||||
| using namespace blender::bke; | |||||
| namespace { | namespace { | ||||
| using BoneNameSet = blender::Set<std::string>; | |||||
| // Forward declarations. | using ActionApplier = | ||||
| BoneNameSet pose_apply_find_selected_bones(const bArmature *armature, const bPose *pose); | blender::FunctionRef<void(PointerRNA *, bAction *, const AnimationEvalContext *)>; | ||||
| /* Forward declarations. */ | |||||
| void pose_apply_disable_fcurves_for_unselected_bones(bAction *action, | void pose_apply_disable_fcurves_for_unselected_bones(bAction *action, | ||||
| const BoneNameSet &selected_bone_names); | const BoneNameSet &selected_bone_names); | ||||
| void pose_apply_restore_fcurves(bAction *action); | void pose_apply_restore_fcurves(bAction *action); | ||||
| void pose_apply(struct Object *ob, | |||||
| struct bAction *action, | |||||
| struct AnimationEvalContext *anim_eval_context, | |||||
| ActionApplier applier); | |||||
| } // namespace | } // namespace | ||||
| void BKE_pose_apply_action(struct Object *ob, | void BKE_pose_apply_action_selected_bones(struct Object *ob, | ||||
| struct bAction *action, | |||||
| struct AnimationEvalContext *anim_eval_context) | |||||
| { | |||||
| auto evaluate_and_apply = | |||||
| [](PointerRNA *ptr, bAction *act, const AnimationEvalContext *anim_eval_context) { | |||||
| animsys_evaluate_action(ptr, act, anim_eval_context, false); | |||||
| }; | |||||
| pose_apply(ob, action, anim_eval_context, evaluate_and_apply); | |||||
| } | |||||
| void BKE_pose_apply_action_all_bones(struct Object *ob, | |||||
| struct bAction *action, | struct bAction *action, | ||||
| struct AnimationEvalContext *anim_eval_context) | struct AnimationEvalContext *anim_eval_context) | ||||
| { | { | ||||
| PointerRNA pose_owner_ptr; | |||||
| RNA_id_pointer_create(&ob->id, &pose_owner_ptr); | |||||
| animsys_evaluate_action(&pose_owner_ptr, action, anim_eval_context, false); | |||||
| } | |||||
| void BKE_pose_apply_action_blend(struct Object *ob, | |||||
| struct bAction *action, | |||||
| struct AnimationEvalContext *anim_eval_context, | |||||
| const float blend_factor) | |||||
| { | |||||
| auto evaluate_and_blend = [blend_factor](PointerRNA *ptr, | |||||
| bAction *act, | |||||
| const AnimationEvalContext *anim_eval_context) { | |||||
| animsys_blend_in_action(ptr, act, anim_eval_context, blend_factor); | |||||
| }; | |||||
| pose_apply(ob, action, anim_eval_context, evaluate_and_blend); | |||||
| } | |||||
| namespace { | |||||
| void pose_apply(struct Object *ob, | |||||
| struct bAction *action, | |||||
| struct AnimationEvalContext *anim_eval_context, | |||||
| ActionApplier applier) | |||||
| { | |||||
| bPose *pose = ob->pose; | bPose *pose = ob->pose; | ||||
| if (pose == nullptr) { | if (pose == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| const bArmature *armature = (bArmature *)ob->data; | const bArmature *armature = (bArmature *)ob->data; | ||||
| const BoneNameSet selected_bone_names = pose_apply_find_selected_bones(armature, pose); | const BoneNameSet selected_bone_names = BKE_armature_find_selected_bone_names(armature); | ||||
| const bool limit_to_selected_bones = !selected_bone_names.is_empty(); | const bool limit_to_selected_bones = !selected_bone_names.is_empty(); | ||||
| if (limit_to_selected_bones) { | if (limit_to_selected_bones) { | ||||
| /* Mute all FCurves that are not associated with selected bones. This separates the concept of | /* Mute all FCurves that are not associated with selected bones. This separates the concept of | ||||
| * bone selection from the FCurve evaluation code. */ | * bone selection from the FCurve evaluation code. */ | ||||
| pose_apply_disable_fcurves_for_unselected_bones(action, selected_bone_names); | pose_apply_disable_fcurves_for_unselected_bones(action, selected_bone_names); | ||||
| } | } | ||||
| /* Apply the Action. */ | /* Apply the Action. */ | ||||
| PointerRNA pose_owner_ptr; | PointerRNA pose_owner_ptr; | ||||
| RNA_id_pointer_create(&ob->id, &pose_owner_ptr); | RNA_id_pointer_create(&ob->id, &pose_owner_ptr); | ||||
| animsys_evaluate_action(&pose_owner_ptr, action, anim_eval_context, false); | |||||
| applier(&pose_owner_ptr, action, anim_eval_context); | |||||
| if (limit_to_selected_bones) { | if (limit_to_selected_bones) { | ||||
| pose_apply_restore_fcurves(action); | pose_apply_restore_fcurves(action); | ||||
| } | } | ||||
| } | } | ||||
| namespace { | |||||
| BoneNameSet pose_apply_find_selected_bones(const bArmature *armature, const bPose *pose) | |||||
| { | |||||
| BoneNameSet selected_bone_names; | |||||
| bool all_bones_selected = true; | |||||
| bool no_bones_selected = true; | |||||
| LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) { | |||||
| const bool is_selected = PBONE_SELECTED(armature, pchan->bone); | |||||
| all_bones_selected &= is_selected; | |||||
| no_bones_selected &= !is_selected; | |||||
| if (is_selected) { | |||||
| /* Bone names are unique, so no need to check for duplicates. */ | |||||
| selected_bone_names.add_new(pchan->name); | |||||
| } | |||||
| } | |||||
| /* If no bones are selected, act as if all are. */ | |||||
| if (all_bones_selected || no_bones_selected) { | |||||
| return BoneNameSet(); /* An empty set means "ignore bone selection". */ | |||||
| } | |||||
| return selected_bone_names; | |||||
| } | |||||
| void pose_apply_restore_fcurves(bAction *action) | void pose_apply_restore_fcurves(bAction *action) | ||||
| { | { | ||||
| /* TODO(Sybren): Restore the FCurve flags, instead of just erasing the 'disabled' flag. */ | /* TODO(Sybren): Restore the FCurve flags, instead of just erasing the 'disabled' flag. */ | ||||
| LISTBASE_FOREACH (FCurve *, fcu, &action->curves) { | LISTBASE_FOREACH (FCurve *, fcu, &action->curves) { | ||||
| fcu->flag &= ~FCURVE_DISABLED; | fcu->flag &= ~FCURVE_DISABLED; | ||||
| } | } | ||||
| } | } | ||||
| void pose_apply_disable_fcurves_for_unselected_bones(bAction *action, | void pose_apply_disable_fcurves_for_unselected_bones(bAction *action, | ||||
| const BoneNameSet &selected_bone_names) | const BoneNameSet &selected_bone_names) | ||||
| { | { | ||||
| LISTBASE_FOREACH (FCurve *, fcu, &action->curves) { | auto disable_unselected_fcurve = [&](FCurve *fcu, const char *bone_name) { | ||||
| if (!fcu->rna_path || !strstr(fcu->rna_path, "pose.bones[")) { | const bool is_bone_selected = selected_bone_names.contains(bone_name); | ||||
| continue; | if (!is_bone_selected) { | ||||
| } | |||||
| /* Get bone name, and check if this bone is selected. */ | |||||
| char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); | |||||
| if (!bone_name) { | |||||
| continue; | |||||
| } | |||||
| const bool is_selected = selected_bone_names.contains(bone_name); | |||||
| MEM_freeN(bone_name); | |||||
| if (is_selected) { | |||||
| continue; | |||||
| } | |||||
| fcu->flag |= FCURVE_DISABLED; | fcu->flag |= FCURVE_DISABLED; | ||||
| } | } | ||||
| }; | |||||
| BKE_action_find_fcurves_with_bones(action, disable_unselected_fcurve); | |||||
| } | } | ||||
| } // namespace | } // namespace | ||||