1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "BsCorePrerequisites.h"
6#include "Reflection/BsIReflectable.h"
7#include "Math/BsMatrix4.h"
8#include "Math/BsVector3.h"
9#include "Math/BsQuaternion.h"
10#include "Animation/BsCurveCache.h"
11#include "Scene/BsTransform.h"
12
13namespace bs
14{
15 class SkeletonMask;
16
17 /** @addtogroup Animation-Internal
18 * @{
19 */
20
21 /**
22 * Contains indices for position/rotation/scale animation curves. Used for quick mapping of bones in a skeleton to
23 * relevant animation curves.
24 */
25 struct AnimationCurveMapping
26 {
27 UINT32 position;
28 UINT32 rotation;
29 UINT32 scale;
30 };
31
32 /** Information about a single bone used for constructing a skeleton. */
33 struct BONE_DESC
34 {
35 String name; /**< Unique name of the bone. */
36 UINT32 parent; /**< Index of the parent bone, if any. -1 if root bone. */
37
38 Transform localTfrm; /**< Local transform of the bone, relative to other bones in the hierarchy. */
39 Matrix4 invBindPose; /**< Inverse bind pose which transforms vertices from their bind pose into local space. */
40 };
41
42 /** Contains information about a single playing animation clip. */
43 struct AnimationState
44 {
45 SPtr<AnimationCurves> curves; /**< All curves in the animation clip. */
46 AnimationCurveMapping* boneToCurveMapping; /**< Mapping of bone indices to curve indices for quick lookup .*/
47 AnimationCurveMapping* soToCurveMapping; /**< Mapping of scene object indices to curve indices for quick lookup. */
48
49 TCurveCache<Vector3>* positionCaches; /**< Cache used for evaluating position curves. */
50 TCurveCache<Quaternion>* rotationCaches; /**< Cache used for evaluating rotation curves. */
51 TCurveCache<Vector3>* scaleCaches; /**< Cache used for evaluating scale curves. */
52 TCurveCache<float>* genericCaches; /**< Cache used for evaluating generic curves. */
53
54 float time; /**< Time to evaluate the curve at. */
55 float weight; /**< Determines how much of an influence will this clip have in regard to others in the same layer. */
56 bool loop; /**< Determines should the animation loop (wrap) once ending or beginning frames are passed. */
57 bool disabled; /**< If true the clip state will not be evaluated. */
58 };
59
60 /** Contains animation states for a single animation layer. */
61 struct AnimationStateLayer
62 {
63 AnimationState* states; /**< Array of animation states in the layer. */
64 UINT32 numStates; /**< Number of states in @p states. */
65
66 UINT8 index; /**< Unique index of the animation layer. */
67
68 /**
69 * If true animations from this layer will be added on top of other layers using the per-state weights. If false
70 * the weights will be normalized, animations will be blended with each other according to the normalized weights
71 * and then added on top of other layers.
72 */
73 bool additive;
74 };
75
76 /**
77 * Contains local translation, rotation and scale values for each bone in a skeleton, after being evaluated at a
78 * specific time of an animation. All values are stored in the same order as the bones in the skeleton they were
79 * created by.
80 */
81 struct LocalSkeletonPose
82 {
83 LocalSkeletonPose() = default;
84 LocalSkeletonPose(UINT32 numBones, bool individualOverride = false);
85 LocalSkeletonPose(UINT32 numPos, UINT32 numRot, UINT32 numScale);
86 LocalSkeletonPose(const LocalSkeletonPose& other) = delete;
87 LocalSkeletonPose(LocalSkeletonPose&& other);
88 ~LocalSkeletonPose();
89
90 LocalSkeletonPose& operator=(const LocalSkeletonPose& other) = delete;
91 LocalSkeletonPose& operator=(LocalSkeletonPose&& other);
92
93 Vector3* positions = nullptr; /**< Local bone positions at specific animation time. */
94 Quaternion* rotations = nullptr; /**< Local bone rotations at specific animation time. */
95 Vector3* scales = nullptr; /**< Local bone scales at specific animation time. */
96 bool* hasOverride = nullptr; /**< True if the bone transform was overriden externally (local pose was ignored). */
97 UINT32 numBones = 0; /**< Number of bones in the pose. */
98 };
99
100 /** Contains internal information about a single bone in a Skeleton. */
101 struct SkeletonBoneInfo
102 {
103 String name; /**< Unique name of the bone. */
104 UINT32 parent; /**< Index of the bone parent, or -1 if root (no parent). */
105 };
106
107 /**
108 * @native
109 * Contains information about bones required for skeletal animation. Allows caller to evaluate a set of animation
110 * clips at a specific time and output the relevant skeleton pose.
111 * @endnative
112 * @script
113 * Contains information about bones required for skeletal animation.
114 * @endscript
115 */
116 class BS_CORE_EXPORT BS_SCRIPT_EXPORT(m:Animation) Skeleton : public IReflectable // Note: Must be immutable in order to be usable on multiple threads
117 {
118 public:
119 ~Skeleton();
120
121 /**
122 * Outputs a skeleton pose containing required transforms for transforming the skeleton to the values specified by
123 * the provided animation clip evaluated at the specified time.
124 *
125 * @param[out] pose Output pose containing the requested transforms. Must be pre-allocated with enough space
126 * to hold all the bone matrices of this skeleton.
127 * @param[in] mask Mask that filters which skeleton bones are enabled or disabled.
128 * @param[out] localPose Output pose containing the local transforms. Must be pre-allocated with enough space
129 * to hold all the bone data of this skeleton.
130 * @param[in] clip Clip to evaluate.
131 * @param[in] time Time to evaluate the clip with.
132 * @param[in] loop Determines should the time be looped (wrapped) if it goes past the clip start/end.
133 *
134 * @note It is more efficient to use the other getPose overload as sequential calls can benefit from animation
135 * evaluator cache.
136 */
137 void getPose(Matrix4* pose, LocalSkeletonPose& localPose, const SkeletonMask& mask, const AnimationClip& clip,
138 float time, bool loop = true);
139
140 /**
141 * Outputs a skeleton pose containing required transforms for transforming the skeleton to the values specified by
142 * the provided set of animation curves.
143 *
144 * @param[out] pose Output pose containing the requested transforms. Must be pre-allocated with enough space
145 * to hold all the bone matrices of this skeleton.
146 * @param[in] mask Mask that filters which skeleton bones are enabled or disabled.
147 * @param[out] localPose Output pose containing the local transforms. Must be pre-allocated with enough space
148 * to hold all the bone data of this skeleton.
149 * @param[in] layers One or multiple layers, containing one or multiple animation states to evaluate.
150 * @param[in] numLayers Number of layers in the @p layers array.
151 */
152 void getPose(Matrix4* pose, LocalSkeletonPose& localPose, const SkeletonMask& mask,
153 const AnimationStateLayer* layers, UINT32 numLayers);
154
155 /** Returns the total number of bones in the skeleton. */
156 BS_SCRIPT_EXPORT(pr:getter,n:NumBones)
157 UINT32 getNumBones() const { return mNumBones; }
158
159 /** Returns information about a bone at the provided index. */
160 const SkeletonBoneInfo& getBoneInfo(UINT32 idx) const { return mBoneInfo[idx]; }
161
162 /** Searches all bones to find a root bone. Returns -1 if no root can be found. */
163 UINT32 getRootBoneIndex() const;
164
165 /** Returns the inverse bind pose for the bone at the provided index. */
166 const Matrix4& getInvBindPose(UINT32 idx) const { return mInvBindPoses[idx]; }
167
168 /** Calculates the bind-pose transform of the bone at the specified index. */
169 Transform calcBoneTransform(UINT32 idx) const;
170
171 /**
172 * Creates a new Skeleton.
173 *
174 * @param[in] bones An array of bones to initialize the skeleton with. Data will be copied.
175 * @param[in] numBones Number of bones in the @p bones array.
176 */
177 static SPtr<Skeleton> create(BONE_DESC* bones, UINT32 numBones);
178
179 private:
180 Skeleton() = default;
181 Skeleton(BONE_DESC* bones, UINT32 numBones);
182
183 UINT32 mNumBones = 0;
184 Transform* mBoneTransforms = nullptr;
185 Matrix4* mInvBindPoses = nullptr;
186 SkeletonBoneInfo* mBoneInfo = nullptr;
187
188 /************************************************************************/
189 /* SERIALIZATION */
190 /************************************************************************/
191 public:
192 friend class SkeletonRTTI;
193 static RTTITypeBase* getRTTIStatic();
194 RTTITypeBase* getRTTI() const override;
195
196 /**
197 * Creates a Skeleton with no data. You must populate its data manually.
198 *
199 * @note For serialization use only.
200 */
201 static SPtr<Skeleton> createEmpty();
202 };
203
204 /** @} */
205}