Skip to content
Snippets Groups Projects
  • Campbell Barton's avatar
    c434782e
    File headers: SPDX License migration · c434782e
    Campbell Barton authored
    Use a shorter/simpler license convention, stops the header taking so
    much space.
    
    Follow the SPDX license specification: https://spdx.org/licenses
    
    - C/C++/objc/objc++
    - Python
    - Shell Scripts
    - CMake, GNUmakefile
    
    While most of the source tree has been included
    
    - `./extern/` was left out.
    - `./intern/cycles` & `./intern/atomic` are also excluded because they
      use different header conventions.
    
    doc/license/SPDX-license-identifiers.txt has been added to list SPDX all
    used identifiers.
    
    See P2788 for the script that automated these edits.
    
    Reviewed By: brecht, mont29, sergey
    
    Ref D14069
    c434782e
    History
    File headers: SPDX License migration
    Campbell Barton authored
    Use a shorter/simpler license convention, stops the header taking so
    much space.
    
    Follow the SPDX license specification: https://spdx.org/licenses
    
    - C/C++/objc/objc++
    - Python
    - Shell Scripts
    - CMake, GNUmakefile
    
    While most of the source tree has been included
    
    - `./extern/` was left out.
    - `./intern/cycles` & `./intern/atomic` are also excluded because they
      use different header conventions.
    
    doc/license/SPDX-license-identifiers.txt has been added to list SPDX all
    used identifiers.
    
    See P2788 for the script that automated these edits.
    
    Reviewed By: brecht, mont29, sergey
    
    Ref D14069
armature_pose.cc 4.09 KiB
/* SPDX-License-Identifier: GPL-2.0-or-later
 * Copyright 2015 Blender Foundation. All rights reserved. */

/** \file
 * \ingroup bke
 */

#include "BKE_action.hh"
#include "BKE_animsys.h"
#include "BKE_armature.hh"

#include "BLI_function_ref.hh"
#include "BLI_set.hh"

#include "DNA_action_types.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_object_types.h"

#include "RNA_access.h"

using namespace blender::bke;

namespace {

using ActionApplier =
    blender::FunctionRef<void(PointerRNA *, bAction *, const AnimationEvalContext *)>;

/* Forward declarations. */
void pose_apply_disable_fcurves_for_unselected_bones(bAction *action,
                                                     const BoneNameSet &selected_bone_names);
void pose_apply_restore_fcurves(bAction *action);

void pose_apply(struct Object *ob,
                struct bAction *action,
                struct AnimationEvalContext *anim_eval_context,
                ActionApplier applier);

}  // namespace

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 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;
  if (pose == nullptr) {
    return;
  }

  const bArmature *armature = (bArmature *)ob->data;
  const BoneNameSet selected_bone_names = 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, &pose_owner_ptr);

  applier(&pose_owner_ptr, action, anim_eval_context);

  if (limit_to_selected_bones) {
    pose_apply_restore_fcurves(action);
  }
}

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 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;
    }
  };
  BKE_action_find_fcurves_with_bones(action, disable_unselected_fcurve);
}

}  // namespace