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#include "Animation/BsAnimationClip.h"
4#include "Resources/BsResources.h"
5#include "Animation/BsSkeleton.h"
6#include "Private/RTTI/BsAnimationClipRTTI.h"
7
8namespace bs
9{
10 void AnimationCurves::addPositionCurve(const String& name, const TAnimationCurve<Vector3>& curve)
11 {
12 auto iterFind = std::find_if(position.begin(), position.end(), [&](auto x) { return x.name == name; });
13
14 if (iterFind != position.end())
15 iterFind->curve = curve;
16 else
17 position.push_back({ name, AnimationCurveFlags(), curve });
18 }
19
20 void AnimationCurves::addRotationCurve(const String& name, const TAnimationCurve<Quaternion>& curve)
21 {
22 auto iterFind = std::find_if(rotation.begin(), rotation.end(), [&](auto x) { return x.name == name; });
23
24 if (iterFind != rotation.end())
25 iterFind->curve = curve;
26 else
27 rotation.push_back({ name, AnimationCurveFlags(), curve });
28 }
29
30 void AnimationCurves::addScaleCurve(const String& name, const TAnimationCurve<Vector3>& curve)
31 {
32 auto iterFind = std::find_if(scale.begin(), scale.end(), [&](auto x) { return x.name == name; });
33
34 if (iterFind != scale.end())
35 iterFind->curve = curve;
36 else
37 scale.push_back({ name, AnimationCurveFlags(), curve });
38 }
39
40 void AnimationCurves::addGenericCurve(const String& name, const TAnimationCurve<float>& curve)
41 {
42 auto iterFind = std::find_if(generic.begin(), generic.end(), [&](auto x) { return x.name == name; });
43
44 if (iterFind != generic.end())
45 iterFind->curve = curve;
46 else
47 generic.push_back({ name, AnimationCurveFlags(), curve });
48 }
49
50 void AnimationCurves::removePositionCurve(const String& name)
51 {
52 auto iterFind = std::find_if(position.begin(), position.end(), [&](auto x) { return x.name == name; });
53
54 if (iterFind != position.end())
55 position.erase(iterFind);
56 }
57
58 void AnimationCurves::removeRotationCurve(const String& name)
59 {
60 auto iterFind = std::find_if(rotation.begin(), rotation.end(), [&](auto x) { return x.name == name; });
61
62 if (iterFind != rotation.end())
63 rotation.erase(iterFind);
64 }
65
66 void AnimationCurves::removeScaleCurve(const String& name)
67 {
68 auto iterFind = std::find_if(scale.begin(), scale.end(), [&](auto x) { return x.name == name; });
69
70 if (iterFind != scale.end())
71 scale.erase(iterFind);
72 }
73
74 void AnimationCurves::removeGenericCurve(const String& name)
75 {
76 auto iterFind = std::find_if(generic.begin(), generic.end(), [&](auto x) { return x.name == name; });
77
78 if (iterFind != generic.end())
79 generic.erase(iterFind);
80 }
81
82 AnimationClip::AnimationClip()
83 : Resource(false), mVersion(0), mCurves(bs_shared_ptr_new<AnimationCurves>())
84 , mRootMotion(bs_shared_ptr_new<RootMotion>()), mIsAdditive(false), mLength(0.0f), mSampleRate(1)
85 {
86
87 }
88
89 AnimationClip::AnimationClip(const SPtr<AnimationCurves>& curves, bool isAdditive, UINT32 sampleRate,
90 const SPtr<RootMotion>& rootMotion)
91 : Resource(false), mVersion(0), mCurves(curves), mRootMotion(rootMotion), mIsAdditive(isAdditive), mLength(0.0f)
92 , mSampleRate(sampleRate)
93 {
94 if (mCurves == nullptr)
95 mCurves = bs_shared_ptr_new<AnimationCurves>();
96
97 if (mRootMotion == nullptr)
98 mRootMotion = bs_shared_ptr_new<RootMotion>();
99
100 buildNameMapping();
101 calculateLength();
102 }
103
104 HAnimationClip AnimationClip::create(bool isAdditive)
105 {
106 return static_resource_cast<AnimationClip>(gResources()._createResourceHandle(
107 _createPtr(bs_shared_ptr_new<AnimationCurves>(), isAdditive)));
108 }
109
110 HAnimationClip AnimationClip::create(const SPtr<AnimationCurves>& curves, bool isAdditive, UINT32 sampleRate,
111 const SPtr<RootMotion>& rootMotion)
112 {
113 return static_resource_cast<AnimationClip>(gResources()._createResourceHandle(
114 _createPtr(curves, isAdditive, sampleRate, rootMotion)));
115 }
116
117 SPtr<AnimationClip> AnimationClip::createEmpty()
118 {
119 AnimationClip* rawPtr = new (bs_alloc<AnimationClip>()) AnimationClip();
120
121 SPtr<AnimationClip> newClip = bs_core_ptr<AnimationClip>(rawPtr);
122 newClip->_setThisPtr(newClip);
123
124 return newClip;
125 }
126
127 SPtr<AnimationClip> AnimationClip::_createPtr(const SPtr<AnimationCurves>& curves, bool isAdditive, UINT32 sampleRate,
128 const SPtr<RootMotion>& rootMotion)
129 {
130 AnimationClip* rawPtr = new (bs_alloc<AnimationClip>()) AnimationClip(curves, isAdditive, sampleRate, rootMotion);
131
132 SPtr<AnimationClip> newClip = bs_core_ptr<AnimationClip>(rawPtr);
133 newClip->_setThisPtr(newClip);
134 newClip->initialize();
135
136 return newClip;
137 }
138
139 void AnimationClip::setCurves(const AnimationCurves& curves)
140 {
141 *mCurves = curves;
142
143 buildNameMapping();
144 calculateLength();
145 mVersion++;
146 }
147
148 bool AnimationClip::hasRootMotion() const
149 {
150 return mRootMotion != nullptr &&
151 (mRootMotion->position.getNumKeyFrames() > 0 || mRootMotion->rotation.getNumKeyFrames() > 0);
152 }
153
154 void AnimationClip::calculateLength()
155 {
156 mLength = 0.0f;
157
158 for (auto& entry : mCurves->position)
159 mLength = std::max(mLength, entry.curve.getLength());
160
161 for (auto& entry : mCurves->rotation)
162 mLength = std::max(mLength, entry.curve.getLength());
163
164 for (auto& entry : mCurves->scale)
165 mLength = std::max(mLength, entry.curve.getLength());
166
167 for (auto& entry : mCurves->generic)
168 mLength = std::max(mLength, entry.curve.getLength());
169 }
170
171 void AnimationClip::buildNameMapping()
172 {
173 mNameMapping.clear();
174
175 auto registerEntries = [&](auto& curve, CurveType type)
176 {
177 UINT32 typeIdx = (UINT32)type;
178
179 for (UINT32 i = 0; i < (UINT32)curve.size(); i++)
180 {
181 auto& entry = curve[i];
182
183 auto iterFind = mNameMapping.find(entry.name);
184 if (iterFind == mNameMapping.end())
185 {
186 UINT32* indices = mNameMapping[entry.name].data();
187 memset(indices, -1, sizeof(UINT32) * (int)CurveType::Count);
188
189 indices[typeIdx] = i;
190 }
191 else
192 mNameMapping[entry.name][typeIdx] = i;
193 }
194 };
195
196 registerEntries(mCurves->position, CurveType::Position);
197 registerEntries(mCurves->rotation, CurveType::Rotation);
198 registerEntries(mCurves->scale, CurveType::Scale);
199
200 // Generic and morph curves
201 {
202 Vector<TNamedAnimationCurve<float>>& curve = mCurves->generic;
203 for (UINT32 i = 0; i < (UINT32)curve.size(); i++)
204 {
205 auto& entry = curve[i];
206
207 UINT32 typeIdx;
208 if (entry.flags.isSet(AnimationCurveFlag::MorphFrame))
209 typeIdx = (UINT32)CurveType::MorphFrame;
210 else if (entry.flags.isSet(AnimationCurveFlag::MorphWeight))
211 typeIdx = (UINT32)CurveType::MorphWeight;
212 else
213 typeIdx = (UINT32)CurveType::Generic;
214
215 auto iterFind = mNameMapping.find(entry.name);
216 if (iterFind == mNameMapping.end())
217 {
218 UINT32* indices = mNameMapping[entry.name].data();
219 memset(indices, -1, sizeof(UINT32) * (int)CurveType::Count);
220
221 indices[typeIdx] = i;
222 }
223 else
224 mNameMapping[entry.name][typeIdx] = i;
225 }
226 }
227 }
228
229 void AnimationClip::initialize()
230 {
231 buildNameMapping();
232
233 Resource::initialize();
234 }
235
236 void AnimationClip::getBoneMapping(const Skeleton& skeleton, AnimationCurveMapping* mapping) const
237 {
238 UINT32 numBones = skeleton.getNumBones();
239 for(UINT32 i = 0; i < numBones; i++)
240 {
241 const SkeletonBoneInfo& boneInfo = skeleton.getBoneInfo(i);
242
243 getCurveMapping(boneInfo.name, mapping[i]);
244 }
245 }
246
247 void AnimationClip::getCurveMapping(const String& name, AnimationCurveMapping& mapping) const
248 {
249 auto iterFind = mNameMapping.find(name);
250 if (iterFind != mNameMapping.end())
251 {
252 const UINT32* indices = iterFind->second.data();
253
254 mapping.position = indices[(UINT32)CurveType::Position];
255 mapping.rotation = indices[(UINT32)CurveType::Rotation];
256 mapping.scale = indices[(UINT32)CurveType::Scale];
257 }
258 else
259 mapping = { (UINT32)-1, (UINT32)-1, (UINT32)-1 };
260 }
261
262 void AnimationClip::getMorphMapping(const String& name, UINT32& frameIdx, UINT32& weightIdx) const
263 {
264 auto iterFind = mNameMapping.find(name);
265 if (iterFind != mNameMapping.end())
266 {
267 const UINT32* indices = iterFind->second.data();
268
269 frameIdx = indices[(UINT32)CurveType::MorphFrame];
270 weightIdx = indices[(UINT32)CurveType::MorphWeight];
271 }
272 else
273 {
274 frameIdx = (UINT32)-1;
275 weightIdx = (UINT32)-1;
276 }
277 }
278
279 RTTITypeBase* AnimationClip::getRTTIStatic()
280 {
281 return AnimationClipRTTI::instance();
282 }
283
284 RTTITypeBase* AnimationClip::getRTTI() const
285 {
286 return getRTTIStatic();
287 }
288}