Blender  V2.93
armature_pose.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2015 Blender Foundation.
17  * All rights reserved.
18  *
19  * Defines and code for core node types
20  */
21 
26 #include "BKE_animsys.h"
27 #include "BKE_armature.h"
28 
29 #include "BLI_set.hh"
30 
31 #include "DNA_action_types.h"
32 #include "DNA_anim_types.h"
33 #include "DNA_armature_types.h"
34 #include "DNA_object_types.h"
35 
36 #include "RNA_access.h"
37 
38 namespace {
39 using BoneNameSet = blender::Set<std::string>;
40 
41 // Forward declarations.
42 BoneNameSet pose_apply_find_selected_bones(const bArmature *armature, const bPose *pose);
43 void pose_apply_disable_fcurves_for_unselected_bones(bAction *action,
44  const BoneNameSet &selected_bone_names);
45 void pose_apply_restore_fcurves(bAction *action);
46 } // namespace
47 
48 void BKE_pose_apply_action(struct Object *ob,
49  struct bAction *action,
50  struct AnimationEvalContext *anim_eval_context)
51 {
52  bPose *pose = ob->pose;
53  if (pose == nullptr) {
54  return;
55  }
56 
57  const bArmature *armature = (bArmature *)ob->data;
58  const BoneNameSet selected_bone_names = pose_apply_find_selected_bones(armature, pose);
59  const bool limit_to_selected_bones = !selected_bone_names.is_empty();
60 
61  if (limit_to_selected_bones) {
62  /* Mute all FCurves that are not associated with selected bones. This separates the concept of
63  * bone selection from the FCurve evaluation code. */
64  pose_apply_disable_fcurves_for_unselected_bones(action, selected_bone_names);
65  }
66 
67  /* Apply the Action. */
68  PointerRNA pose_owner_ptr;
69  RNA_id_pointer_create(&ob->id, &pose_owner_ptr);
70  animsys_evaluate_action(&pose_owner_ptr, action, anim_eval_context, false);
71 
72  if (limit_to_selected_bones) {
73  pose_apply_restore_fcurves(action);
74  }
75 }
76 
77 namespace {
78 BoneNameSet pose_apply_find_selected_bones(const bArmature *armature, const bPose *pose)
79 {
80  BoneNameSet selected_bone_names;
81  bool all_bones_selected = true;
82  bool no_bones_selected = true;
83 
84  LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) {
85  const bool is_selected = PBONE_SELECTED(armature, pchan->bone);
86  all_bones_selected &= is_selected;
87  no_bones_selected &= !is_selected;
88 
89  if (is_selected) {
90  /* Bone names are unique, so no need to check for duplicates. */
91  selected_bone_names.add_new(pchan->name);
92  }
93  }
94 
95  /* If no bones are selected, act as if all are. */
96  if (all_bones_selected || no_bones_selected) {
97  return BoneNameSet(); /* An empty set means "ignore bone selection". */
98  }
99  return selected_bone_names;
100 }
101 
102 void pose_apply_restore_fcurves(bAction *action)
103 {
104  /* TODO(Sybren): Restore the FCurve flags, instead of just erasing the 'disabled' flag. */
105  LISTBASE_FOREACH (FCurve *, fcu, &action->curves) {
106  fcu->flag &= ~FCURVE_DISABLED;
107  }
108 }
109 
110 void pose_apply_disable_fcurves_for_unselected_bones(bAction *action,
111  const BoneNameSet &selected_bone_names)
112 {
113  LISTBASE_FOREACH (FCurve *, fcu, &action->curves) {
114  if (!fcu->rna_path || !strstr(fcu->rna_path, "pose.bones[")) {
115  continue;
116  }
117 
118  /* Get bone name, and check if this bone is selected. */
119  char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
120  if (!bone_name) {
121  continue;
122  }
123  const bool is_selected = selected_bone_names.contains(bone_name);
124  MEM_freeN(bone_name);
125  if (is_selected) {
126  continue;
127  }
128 
129  fcu->flag |= FCURVE_DISABLED;
130  }
131 }
132 
133 } // namespace
void animsys_evaluate_action(struct PointerRNA *ptr, struct bAction *act, const struct AnimationEvalContext *anim_eval_context, bool flush_to_original)
#define PBONE_SELECTED(arm, bone)
Definition: BKE_armature.h:346
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
char * BLI_str_quoted_substrN(const char *__restrict str, const char *__restrict prefix) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:432
@ FCURVE_DISABLED
Object is a sort of wrapper for general info.
void BKE_pose_apply_action(struct Object *ob, struct bAction *action, struct AnimationEvalContext *anim_eval_context)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void RNA_id_pointer_create(ID *id, PointerRNA *r_ptr)
Definition: rna_access.c:122
struct bPose * pose
void * data
ListBase curves
ListBase chanbase