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 | |
8 | namespace 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 | } |