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/BsAnimation.h" |
4 | #include "Animation/BsAnimationManager.h" |
5 | #include "Animation/BsAnimationClip.h" |
6 | #include "Animation/BsAnimationUtility.h" |
7 | #include "Scene/BsSceneObject.h" |
8 | #include "Animation/BsMorphShapes.h" |
9 | |
10 | namespace bs |
11 | { |
12 | AnimationClipInfo::AnimationClipInfo(const HAnimationClip& clip) |
13 | : clip(clip) |
14 | { } |
15 | |
16 | AnimationProxy::AnimationProxy(UINT64 id) |
17 | : id(id) |
18 | { } |
19 | |
20 | AnimationProxy::~AnimationProxy() |
21 | { |
22 | clear(); |
23 | } |
24 | |
25 | void AnimationProxy::clear() |
26 | { |
27 | if (layers == nullptr) |
28 | return; |
29 | |
30 | for(UINT32 i = 0; i < numLayers; i++) |
31 | { |
32 | AnimationStateLayer& layer = layers[i]; |
33 | for(UINT32 j = 0; j < layer.numStates; j++) |
34 | { |
35 | AnimationState& state = layer.states[j]; |
36 | |
37 | if(state.curves != nullptr) |
38 | { |
39 | { |
40 | UINT32 numCurves = (UINT32)state.curves->position.size(); |
41 | for (UINT32 k = 0; k < numCurves; k++) |
42 | state.positionCaches[k].~TCurveCache(); |
43 | } |
44 | |
45 | { |
46 | UINT32 numCurves = (UINT32)state.curves->rotation.size(); |
47 | for (UINT32 k = 0; k < numCurves; k++) |
48 | state.rotationCaches[k].~TCurveCache(); |
49 | } |
50 | |
51 | { |
52 | UINT32 numCurves = (UINT32)state.curves->scale.size(); |
53 | for (UINT32 k = 0; k < numCurves; k++) |
54 | state.scaleCaches[k].~TCurveCache(); |
55 | } |
56 | |
57 | { |
58 | UINT32 numCurves = (UINT32)state.curves->generic.size(); |
59 | for (UINT32 k = 0; k < numCurves; k++) |
60 | state.genericCaches[k].~TCurveCache(); |
61 | } |
62 | } |
63 | |
64 | if(skeleton != nullptr) |
65 | { |
66 | UINT32 numBones = skeleton->getNumBones(); |
67 | for (UINT32 k = 0; k < numBones; k++) |
68 | state.boneToCurveMapping[k].~AnimationCurveMapping(); |
69 | } |
70 | |
71 | if(state.soToCurveMapping != nullptr) |
72 | { |
73 | for(UINT32 k = 0; k < numSceneObjects; k++) |
74 | state.soToCurveMapping[k].~AnimationCurveMapping(); |
75 | } |
76 | |
77 | state.~AnimationState(); |
78 | } |
79 | |
80 | layer.~AnimationStateLayer(); |
81 | } |
82 | |
83 | for(UINT32 i = 0; i < numMorphShapes; i++) |
84 | { |
85 | morphShapeInfos[i].shape.~SPtr<MorphShape>(); |
86 | } |
87 | |
88 | // All of the memory is part of the same buffer, so we only need to free the first element |
89 | bs_free(layers); |
90 | layers = nullptr; |
91 | genericCurveOutputs = nullptr; |
92 | sceneObjectInfos = nullptr; |
93 | sceneObjectTransforms = nullptr; |
94 | |
95 | numLayers = 0; |
96 | numGenericCurves = 0; |
97 | } |
98 | |
99 | void AnimationProxy::rebuild(const SPtr<Skeleton>& skeleton, const SkeletonMask& mask, |
100 | Vector<AnimationClipInfo>& clipInfos, const Vector<AnimatedSceneObject>& sceneObjects, |
101 | const SPtr<MorphShapes>& morphShapes) |
102 | { |
103 | this->skeleton = skeleton; |
104 | this->skeletonMask = mask; |
105 | |
106 | // Note: I could avoid having a separate allocation for LocalSkeletonPoses and use the same buffer as the rest |
107 | // of AnimationProxy |
108 | if (skeleton != nullptr) |
109 | skeletonPose = LocalSkeletonPose(skeleton->getNumBones()); |
110 | |
111 | numSceneObjects = (UINT32)sceneObjects.size(); |
112 | if (numSceneObjects > 0) |
113 | sceneObjectPose = LocalSkeletonPose(numSceneObjects, true); |
114 | else |
115 | sceneObjectPose = LocalSkeletonPose(); |
116 | |
117 | rebuild(clipInfos, sceneObjects, morphShapes); |
118 | } |
119 | |
120 | void AnimationProxy::rebuild(Vector<AnimationClipInfo>& clipInfos, const Vector<AnimatedSceneObject>& sceneObjects, |
121 | const SPtr<MorphShapes>& morphShapes) |
122 | { |
123 | clear(); |
124 | |
125 | bs_frame_mark(); |
126 | { |
127 | FrameVector<bool> clipLoadState(clipInfos.size()); |
128 | FrameVector<AnimationStateLayer> tempLayers; |
129 | UINT32 clipIdx = 0; |
130 | for (auto& clipInfo : clipInfos) |
131 | { |
132 | UINT32 layer = clipInfo.state.layer; |
133 | if (layer == (UINT32)-1) |
134 | layer = 0; |
135 | else |
136 | layer += 1; |
137 | |
138 | auto iterFind = std::find_if(tempLayers.begin(), tempLayers.end(), |
139 | [&](auto& x) |
140 | { |
141 | return x.index == layer; |
142 | }); |
143 | |
144 | bool isLoaded = clipInfo.clip.isLoaded(); |
145 | clipLoadState[clipIdx] = isLoaded; |
146 | |
147 | if (iterFind == tempLayers.end()) |
148 | { |
149 | tempLayers.push_back(AnimationStateLayer()); |
150 | AnimationStateLayer& newLayer = tempLayers.back(); |
151 | |
152 | newLayer.index = layer; |
153 | newLayer.additive = isLoaded && clipInfo.clip->isAdditive(); |
154 | } |
155 | |
156 | clipIdx++; |
157 | } |
158 | |
159 | std::sort(tempLayers.begin(), tempLayers.end(), |
160 | [&](auto& x, auto& y) |
161 | { |
162 | return x.index < y.index; |
163 | }); |
164 | |
165 | numLayers = (UINT32)tempLayers.size(); |
166 | UINT32 numClips = (UINT32)clipInfos.size(); |
167 | UINT32 numBones; |
168 | |
169 | if (skeleton != nullptr) |
170 | numBones = skeleton->getNumBones(); |
171 | else |
172 | numBones = 0; |
173 | |
174 | UINT32 numPosCurves = 0; |
175 | UINT32 numRotCurves = 0; |
176 | UINT32 numScaleCurves = 0; |
177 | |
178 | clipIdx = 0; |
179 | for (auto& clipInfo : clipInfos) |
180 | { |
181 | bool isLoaded = clipLoadState[clipIdx++]; |
182 | if (!isLoaded) |
183 | continue; |
184 | |
185 | SPtr<AnimationCurves> curves = clipInfo.clip->getCurves(); |
186 | numPosCurves += (UINT32)curves->position.size(); |
187 | numRotCurves += (UINT32)curves->rotation.size(); |
188 | numScaleCurves += (UINT32)curves->scale.size(); |
189 | } |
190 | |
191 | numGenericCurves = 0; |
192 | if(clipInfos.size() > 0 && clipLoadState[0]) |
193 | { |
194 | SPtr<AnimationCurves> curves = clipInfos[0].clip->getCurves(); |
195 | numGenericCurves = (UINT32)curves->generic.size(); |
196 | } |
197 | |
198 | UINT32* mappedBoneIndices = (UINT32*)bs_frame_alloc(sizeof(UINT32) * numSceneObjects); |
199 | for (UINT32 i = 0; i < numSceneObjects; i++) |
200 | mappedBoneIndices[i] = -1; |
201 | |
202 | UINT32 numBoneMappedSOs = 0; |
203 | if (skeleton != nullptr) |
204 | { |
205 | for (UINT32 i = 0; i < numSceneObjects; i++) |
206 | { |
207 | if (sceneObjects[i].so.isDestroyed(true)) |
208 | continue; |
209 | |
210 | // Empty string always means root bone |
211 | if (sceneObjects[i].curveName.empty()) |
212 | { |
213 | UINT32 rootBoneIdx = skeleton->getRootBoneIndex(); |
214 | if (rootBoneIdx != (UINT32)-1) |
215 | { |
216 | mappedBoneIndices[i] = rootBoneIdx; |
217 | numBoneMappedSOs++; |
218 | } |
219 | } |
220 | else |
221 | { |
222 | for (UINT32 j = 0; j < numBones; j++) |
223 | { |
224 | if (skeleton->getBoneInfo(j).name == sceneObjects[i].curveName) |
225 | { |
226 | mappedBoneIndices[i] = j; |
227 | |
228 | numBoneMappedSOs++; |
229 | break; |
230 | } |
231 | } |
232 | } |
233 | } |
234 | } |
235 | |
236 | if (morphShapes != nullptr) |
237 | { |
238 | numMorphChannels = morphShapes->getNumChannels(); |
239 | numMorphVertices = morphShapes->getNumVertices(); |
240 | |
241 | numMorphShapes = 0; |
242 | for (UINT32 i = 0; i < numMorphChannels; i++) |
243 | numMorphShapes += morphShapes->getChannel(i)->getNumShapes(); |
244 | } |
245 | else |
246 | { |
247 | numMorphChannels = 0; |
248 | numMorphShapes = 0; |
249 | numMorphVertices = 0; |
250 | } |
251 | |
252 | UINT32 numBoneMappings = numBones * numClips; |
253 | UINT32 = sizeof(AnimationStateLayer) * numLayers; |
254 | UINT32 clipsSize = sizeof(AnimationState) * numClips; |
255 | UINT32 boneMappingSize = numBoneMappings * sizeof(AnimationCurveMapping); |
256 | UINT32 posCacheSize = numPosCurves * sizeof(TCurveCache<Vector3>); |
257 | UINT32 rotCacheSize = numRotCurves * sizeof(TCurveCache<Quaternion>); |
258 | UINT32 scaleCacheSize = numScaleCurves * sizeof(TCurveCache<Vector3>); |
259 | UINT32 genCacheSize = numGenericCurves * sizeof(TCurveCache<float>); |
260 | UINT32 genericCurveOutputSize = numGenericCurves * sizeof(float); |
261 | UINT32 sceneObjectIdsSize = numSceneObjects * sizeof(AnimatedSceneObjectInfo); |
262 | UINT32 sceneObjectTransformsSize = numBoneMappedSOs * sizeof(Matrix4); |
263 | UINT32 morphChannelSize = numMorphChannels * sizeof(MorphChannelInfo); |
264 | UINT32 morphShapeSize = numMorphShapes * sizeof(MorphShapeInfo); |
265 | |
266 | UINT8* data = (UINT8*)bs_alloc(layersSize + clipsSize + boneMappingSize + posCacheSize + rotCacheSize + |
267 | scaleCacheSize + genCacheSize + genericCurveOutputSize + sceneObjectIdsSize + sceneObjectTransformsSize + |
268 | morphChannelSize + morphShapeSize); |
269 | |
270 | layers = (AnimationStateLayer*)data; |
271 | memcpy(layers, tempLayers.data(), layersSize); |
272 | data += layersSize; |
273 | |
274 | AnimationState* states = (AnimationState*)data; |
275 | for(UINT32 i = 0; i < numClips; i++) |
276 | new (&states[i]) AnimationState(); |
277 | |
278 | data += clipsSize; |
279 | |
280 | AnimationCurveMapping* boneMappings = (AnimationCurveMapping*)data; |
281 | for (UINT32 i = 0; i < numBoneMappings; i++) |
282 | new (&boneMappings[i]) AnimationCurveMapping(); |
283 | |
284 | data += boneMappingSize; |
285 | |
286 | TCurveCache<Vector3>* posCache = (TCurveCache<Vector3>*)data; |
287 | for (UINT32 i = 0; i < numPosCurves; i++) |
288 | new (&posCache[i]) TCurveCache<Vector3>(); |
289 | |
290 | data += posCacheSize; |
291 | |
292 | TCurveCache<Quaternion>* rotCache = (TCurveCache<Quaternion>*)data; |
293 | for (UINT32 i = 0; i < numRotCurves; i++) |
294 | new (&rotCache[i]) TCurveCache<Quaternion>(); |
295 | |
296 | data += rotCacheSize; |
297 | |
298 | TCurveCache<Vector3>* scaleCache = (TCurveCache<Vector3>*)data; |
299 | for (UINT32 i = 0; i < numScaleCurves; i++) |
300 | new (&scaleCache[i]) TCurveCache<Vector3>(); |
301 | |
302 | data += scaleCacheSize; |
303 | |
304 | TCurveCache<float>* genCache = (TCurveCache<float>*)data; |
305 | for (UINT32 i = 0; i < numGenericCurves; i++) |
306 | new (&genCache[i]) TCurveCache<float>(); |
307 | |
308 | data += genCacheSize; |
309 | |
310 | genericCurveOutputs = (float*)data; |
311 | data += genericCurveOutputSize; |
312 | |
313 | sceneObjectInfos = (AnimatedSceneObjectInfo*)data; |
314 | data += sceneObjectIdsSize; |
315 | |
316 | sceneObjectTransforms = (Matrix4*)data; |
317 | for (UINT32 i = 0; i < numBoneMappedSOs; i++) |
318 | sceneObjectTransforms[i] = Matrix4::IDENTITY; |
319 | |
320 | data += sceneObjectTransformsSize; |
321 | |
322 | morphChannelInfos = (MorphChannelInfo*)data; |
323 | data += morphChannelSize; |
324 | |
325 | morphShapeInfos = (MorphShapeInfo*)data; |
326 | data += morphShapeSize; |
327 | |
328 | // Generate data required for morph shape animation |
329 | if (morphShapes != nullptr) |
330 | { |
331 | UINT32 currentShapeIdx = 0; |
332 | for (UINT32 i = 0; i < numMorphChannels; i++) |
333 | { |
334 | SPtr<MorphChannel> morphChannel = morphShapes->getChannel(i); |
335 | UINT32 numShapes = morphChannel->getNumShapes(); |
336 | |
337 | MorphChannelInfo& channelInfo = morphChannelInfos[i]; |
338 | channelInfo.weight = 0.0f; |
339 | channelInfo.shapeStart = currentShapeIdx; |
340 | channelInfo.shapeCount = numShapes; |
341 | channelInfo.frameCurveIdx = (UINT32)-1; |
342 | channelInfo.weightCurveIdx = (UINT32)-1; |
343 | |
344 | for (UINT32 j = 0; j < numShapes; j++) |
345 | { |
346 | MorphShapeInfo& shapeInfo = morphShapeInfos[currentShapeIdx]; |
347 | new (&shapeInfo.shape) SPtr<MorphShape>(); |
348 | |
349 | SPtr<MorphShape> shape = morphChannel->getShape(j); |
350 | shapeInfo.shape = shape; |
351 | shapeInfo.frameWeight = shape->getWeight(); |
352 | shapeInfo.finalWeight = 0.0f; |
353 | |
354 | currentShapeIdx++; |
355 | } |
356 | } |
357 | |
358 | // Find any curves affecting morph shape animation |
359 | if (!clipInfos.empty()) |
360 | { |
361 | bool isClipValid = clipLoadState[0]; |
362 | if (isClipValid) |
363 | { |
364 | AnimationClipInfo& clipInfo = clipInfos[0]; |
365 | |
366 | for (UINT32 i = 0; i < numMorphChannels; i++) |
367 | { |
368 | SPtr<MorphChannel> morphChannel = morphShapes->getChannel(i); |
369 | MorphChannelInfo& channelInfo = morphChannelInfos[i]; |
370 | |
371 | clipInfo.clip->getMorphMapping(morphChannel->getName(), channelInfo.frameCurveIdx, |
372 | channelInfo.weightCurveIdx); |
373 | } |
374 | } |
375 | } |
376 | |
377 | morphChannelWeightsDirty = true; |
378 | } |
379 | |
380 | UINT32 curLayerIdx = 0; |
381 | UINT32 curStateIdx = 0; |
382 | |
383 | // Note: Hidden dependency. First clip info must be in layers[0].states[0] (needed for generic curves which only |
384 | // use the primary clip). |
385 | for(UINT32 i = 0; i < numLayers; i++) |
386 | { |
387 | AnimationStateLayer& layer = layers[i]; |
388 | |
389 | layer.states = &states[curStateIdx]; |
390 | layer.numStates = 0; |
391 | |
392 | UINT32 localStateIdx = 0; |
393 | for(UINT32 j = 0; j < (UINT32)clipInfos.size(); j++) |
394 | { |
395 | AnimationClipInfo& clipInfo = clipInfos[j]; |
396 | |
397 | UINT32 clipLayer = clipInfo.state.layer; |
398 | if (clipLayer == (UINT32)-1) |
399 | clipLayer = 0; |
400 | else |
401 | clipLayer += 1; |
402 | |
403 | if (clipLayer != layer.index) |
404 | continue; |
405 | |
406 | AnimationState& state = states[curStateIdx]; |
407 | state.loop = clipInfo.state.wrapMode == AnimWrapMode::Loop; |
408 | state.time = clipInfo.state.time; |
409 | |
410 | // Calculate weight if fading is active |
411 | float weight = clipInfo.state.weight; |
412 | |
413 | //// Assumes time is clamped to [0, fadeLength] and fadeLength != 0 |
414 | if(clipInfo.fadeDirection < 0.0f) |
415 | { |
416 | float t = clipInfo.fadeTime / clipInfo.fadeLength; |
417 | weight *= (1.0f - t); |
418 | } |
419 | else if(clipInfo.fadeDirection > 0.0f) |
420 | { |
421 | float t = clipInfo.fadeTime / clipInfo.fadeLength; |
422 | weight *= t; |
423 | } |
424 | |
425 | state.weight = weight; |
426 | |
427 | // Set up individual curves and their caches |
428 | bool isClipValid = clipLoadState[j]; |
429 | if (isClipValid) |
430 | { |
431 | state.curves = clipInfo.clip->getCurves(); |
432 | state.disabled = clipInfo.playbackType == AnimPlaybackType::None; |
433 | } |
434 | else |
435 | { |
436 | static SPtr<AnimationCurves> zeroCurves = bs_shared_ptr_new<AnimationCurves>(); |
437 | state.curves = zeroCurves; |
438 | state.disabled = true; |
439 | } |
440 | |
441 | state.positionCaches = posCache; |
442 | posCache += state.curves->position.size(); |
443 | |
444 | state.rotationCaches = rotCache; |
445 | rotCache += state.curves->rotation.size(); |
446 | |
447 | state.scaleCaches = scaleCache; |
448 | scaleCache += state.curves->scale.size(); |
449 | |
450 | state.genericCaches = genCache; |
451 | genCache += state.curves->generic.size(); |
452 | |
453 | clipInfo.layerIdx = curLayerIdx; |
454 | clipInfo.stateIdx = localStateIdx; |
455 | |
456 | if(isClipValid) |
457 | clipInfo.curveVersion = clipInfo.clip->getVersion(); |
458 | |
459 | // Set up bone mapping |
460 | if (skeleton != nullptr) |
461 | { |
462 | state.boneToCurveMapping = &boneMappings[curStateIdx * numBones]; |
463 | |
464 | if (isClipValid) |
465 | { |
466 | clipInfo.clip->getBoneMapping(*skeleton, state.boneToCurveMapping); |
467 | } |
468 | else |
469 | { |
470 | AnimationCurveMapping emptyMapping = { (UINT32)-1, (UINT32)-1, (UINT32)-1 }; |
471 | |
472 | for (UINT32 i = 0; i < numBones; i++) |
473 | state.boneToCurveMapping[i] = emptyMapping; |
474 | } |
475 | } |
476 | else |
477 | state.boneToCurveMapping = nullptr; |
478 | |
479 | layer.numStates++; |
480 | curStateIdx++; |
481 | localStateIdx++; |
482 | } |
483 | |
484 | curLayerIdx++; |
485 | |
486 | // Must be larger than zero otherwise the layer.states pointer will point to data held by some other layer |
487 | assert(layer.numStates > 0); |
488 | } |
489 | |
490 | Matrix4 invRootTransform(BsIdentity); |
491 | for (UINT32 i = 0; i < numSceneObjects; i++) |
492 | { |
493 | if(sceneObjects[i].curveName.empty()) |
494 | { |
495 | HSceneObject so = sceneObjects[i].so; |
496 | if (!so.isDestroyed(true)) |
497 | invRootTransform = so->getWorldMatrix().inverseAffine(); |
498 | |
499 | break; |
500 | } |
501 | } |
502 | |
503 | UINT32 boneIdx = 0; |
504 | for(UINT32 i = 0; i < numSceneObjects; i++) |
505 | { |
506 | HSceneObject so = sceneObjects[i].so; |
507 | AnimatedSceneObjectInfo& soInfo = sceneObjectInfos[i]; |
508 | soInfo.id = so.getInstanceId(); |
509 | soInfo.boneIdx = mappedBoneIndices[i]; |
510 | |
511 | bool isSOValid = !so.isDestroyed(true); |
512 | if (isSOValid) |
513 | soInfo.hash = so->getTransformHash(); |
514 | else |
515 | soInfo.hash = 0; |
516 | |
517 | soInfo.layerIdx = (UINT32)-1; |
518 | soInfo.stateIdx = (UINT32)-1; |
519 | |
520 | // If no bone mapping, find curves directly |
521 | if(soInfo.boneIdx == -1) |
522 | { |
523 | soInfo.curveIndices = { (UINT32)-1, (UINT32)-1, (UINT32)-1 }; |
524 | |
525 | if (isSOValid) |
526 | { |
527 | for (UINT32 j = 0; j < (UINT32)clipInfos.size(); j++) |
528 | { |
529 | AnimationClipInfo& clipInfo = clipInfos[j]; |
530 | |
531 | soInfo.layerIdx = clipInfo.layerIdx; |
532 | soInfo.stateIdx = clipInfo.stateIdx; |
533 | |
534 | bool isClipValid = clipLoadState[j]; |
535 | if (isClipValid) |
536 | { |
537 | // Note: If there are multiple clips with the relevant curve name, we only use the first |
538 | |
539 | clipInfo.clip->getCurveMapping(sceneObjects[i].curveName, soInfo.curveIndices); |
540 | break; |
541 | } |
542 | } |
543 | } |
544 | } |
545 | else |
546 | { |
547 | // No need to check if SO is valid, if it has a bone connection it must be |
548 | sceneObjectTransforms[boneIdx] = so->getWorldMatrix() * invRootTransform; |
549 | boneIdx++; |
550 | } |
551 | } |
552 | |
553 | bs_frame_free(mappedBoneIndices); |
554 | } |
555 | bs_frame_clear(); |
556 | } |
557 | |
558 | void AnimationProxy::updateClipInfos(const Vector<AnimationClipInfo>& clipInfos) |
559 | { |
560 | for(auto& clipInfo : clipInfos) |
561 | { |
562 | AnimationState& state = layers[clipInfo.layerIdx].states[clipInfo.stateIdx]; |
563 | |
564 | state.loop = clipInfo.state.wrapMode == AnimWrapMode::Loop; |
565 | state.weight = clipInfo.state.weight; |
566 | state.time = clipInfo.state.time; |
567 | |
568 | bool isLoaded = clipInfo.clip.isLoaded(); |
569 | state.disabled = !isLoaded || clipInfo.playbackType == AnimPlaybackType::None; |
570 | } |
571 | } |
572 | |
573 | void AnimationProxy::updateMorphChannelWeights(const Vector<float>& weights) |
574 | { |
575 | UINT32 numWeights = (UINT32)weights.size(); |
576 | for(UINT32 i = 0; i < numMorphChannels; i++) |
577 | { |
578 | if (i < numWeights) |
579 | morphChannelInfos[i].weight = weights[i]; |
580 | else |
581 | morphChannelInfos[i].weight = 0.0f; |
582 | } |
583 | |
584 | morphChannelWeightsDirty = true; |
585 | } |
586 | |
587 | void AnimationProxy::updateTransforms(const Vector<AnimatedSceneObject>& sceneObjects) |
588 | { |
589 | Matrix4 invRootTransform(BsIdentity); |
590 | for (UINT32 i = 0; i < numSceneObjects; i++) |
591 | { |
592 | if (sceneObjects[i].curveName.empty()) |
593 | { |
594 | HSceneObject so = sceneObjects[i].so; |
595 | if (!so.isDestroyed(true)) |
596 | invRootTransform = so->getWorldMatrix().inverseAffine(); |
597 | |
598 | break; |
599 | } |
600 | } |
601 | |
602 | UINT32 boneIdx = 0; |
603 | for (UINT32 i = 0; i < numSceneObjects; i++) |
604 | { |
605 | HSceneObject so = sceneObjects[i].so; |
606 | if (so.isDestroyed(true)) |
607 | { |
608 | sceneObjectInfos[i].hash = 0; |
609 | continue; |
610 | } |
611 | |
612 | sceneObjectInfos[i].hash = so->getTransformHash(); |
613 | |
614 | if (sceneObjectInfos[i].boneIdx == -1) |
615 | continue; |
616 | |
617 | sceneObjectTransforms[boneIdx] = sceneObjects[i].so->getWorldMatrix() * invRootTransform; |
618 | boneIdx++; |
619 | } |
620 | } |
621 | |
622 | void AnimationProxy::updateTime(const Vector<AnimationClipInfo>& clipInfos) |
623 | { |
624 | for (auto& clipInfo : clipInfos) |
625 | { |
626 | AnimationState& state = layers[clipInfo.layerIdx].states[clipInfo.stateIdx]; |
627 | state.time = clipInfo.state.time; |
628 | |
629 | bool isLoaded = clipInfo.clip.isLoaded(); |
630 | state.disabled = !isLoaded || clipInfo.playbackType == AnimPlaybackType::None; |
631 | } |
632 | } |
633 | |
634 | Animation::Animation() |
635 | { |
636 | mId = AnimationManager::instance().registerAnimation(this); |
637 | mAnimProxy = bs_shared_ptr_new<AnimationProxy>(mId); |
638 | } |
639 | |
640 | Animation::~Animation() |
641 | { |
642 | AnimationManager::instance().unregisterAnimation(mId); |
643 | } |
644 | |
645 | void Animation::setSkeleton(const SPtr<Skeleton>& skeleton) |
646 | { |
647 | mSkeleton = skeleton; |
648 | mDirty |= AnimDirtyStateFlag::All; |
649 | } |
650 | |
651 | void Animation::setMorphShapes(const SPtr<MorphShapes>& morphShapes) |
652 | { |
653 | mMorphShapes = morphShapes; |
654 | |
655 | UINT32 numChannels; |
656 | if (mMorphShapes != nullptr) |
657 | numChannels = mMorphShapes->getNumChannels(); |
658 | else |
659 | numChannels = 0; |
660 | |
661 | mMorphChannelWeights.assign(numChannels, 0.0f); |
662 | if (numChannels > 0) |
663 | mMorphChannelWeights[0] = 1.0f; |
664 | |
665 | mDirty |= AnimDirtyStateFlag::Layout; |
666 | mDirty |= AnimDirtyStateFlag::MorphWeights; |
667 | } |
668 | |
669 | void Animation::setMorphChannelWeight(UINT32 idx, float weight) |
670 | { |
671 | UINT32 numShapes = (UINT32)mMorphChannelWeights.size(); |
672 | if (idx >= numShapes) |
673 | return; |
674 | |
675 | mMorphChannelWeights[idx] = weight; |
676 | mDirty |= AnimDirtyStateFlag::MorphWeights; |
677 | } |
678 | |
679 | void Animation::setMask(const SkeletonMask& mask) |
680 | { |
681 | mSkeletonMask = mask; |
682 | mDirty |= AnimDirtyStateFlag::All; |
683 | } |
684 | |
685 | void Animation::setWrapMode(AnimWrapMode wrapMode) |
686 | { |
687 | mDefaultWrapMode = wrapMode; |
688 | |
689 | for (auto& clipInfo : mClipInfos) |
690 | clipInfo.state.wrapMode = wrapMode; |
691 | |
692 | mDirty |= AnimDirtyStateFlag::Value; |
693 | } |
694 | |
695 | void Animation::setSpeed(float speed) |
696 | { |
697 | mDefaultSpeed = speed; |
698 | |
699 | for (auto& clipInfo : mClipInfos) |
700 | { |
701 | // Special case: Ignore non-moving ones |
702 | if(!clipInfo.state.stopped) |
703 | clipInfo.state.speed = speed; |
704 | } |
705 | |
706 | mDirty |= AnimDirtyStateFlag::Value; |
707 | } |
708 | |
709 | void Animation::setBounds(const AABox& bounds) |
710 | { |
711 | mBounds = bounds; |
712 | |
713 | mDirty |= AnimDirtyStateFlag::Culling; |
714 | } |
715 | |
716 | void Animation::setCulling(bool cull) |
717 | { |
718 | mCull = cull; |
719 | |
720 | mDirty |= AnimDirtyStateFlag::Culling; |
721 | } |
722 | |
723 | void Animation::play(const HAnimationClip& clip) |
724 | { |
725 | AnimationClipInfo* clipInfo = addClip(clip, (UINT32)-1); |
726 | if(clipInfo != nullptr) |
727 | { |
728 | clipInfo->state.time = 0.0f; |
729 | clipInfo->state.speed = mDefaultSpeed; |
730 | clipInfo->state.weight = 1.0f; |
731 | clipInfo->state.wrapMode = mDefaultWrapMode; |
732 | clipInfo->playbackType = AnimPlaybackType::Normal; |
733 | } |
734 | |
735 | mSampleStep = AnimSampleStep::None; |
736 | mDirty |= AnimDirtyStateFlag::Value; |
737 | } |
738 | |
739 | void Animation::blendAdditive(const HAnimationClip& clip, float weight, float fadeLength, UINT32 layer) |
740 | { |
741 | if(clip != nullptr && !clip->isAdditive()) |
742 | { |
743 | LOGWRN("blendAdditive() called with a clip that doesn't contain additive animation. Ignoring." ); |
744 | |
745 | // Stop any clips on this layer, even if invalid |
746 | HAnimationClip nullClip; |
747 | addClip(nullClip, layer); |
748 | |
749 | mSampleStep = AnimSampleStep::None; |
750 | return; |
751 | } |
752 | |
753 | AnimationClipInfo* clipInfo = addClip(clip, layer); |
754 | if (clipInfo != nullptr) |
755 | { |
756 | clipInfo->state.time = 0.0f; |
757 | clipInfo->state.speed = mDefaultSpeed; |
758 | clipInfo->state.weight = weight; |
759 | clipInfo->state.wrapMode = mDefaultWrapMode; |
760 | |
761 | if(fadeLength > 0.0f) |
762 | { |
763 | clipInfo->fadeDirection = 1.0f; |
764 | clipInfo->fadeTime = 0.0f; |
765 | clipInfo->fadeLength = fadeLength; |
766 | } |
767 | |
768 | clipInfo->playbackType = AnimPlaybackType::Normal; |
769 | |
770 | mSampleStep = AnimSampleStep::None; |
771 | mDirty |= AnimDirtyStateFlag::Value; |
772 | } |
773 | } |
774 | |
775 | void Animation::blend1D(const Blend1DInfo& info, float t) |
776 | { |
777 | if (info.clips.size() == 0) |
778 | return; |
779 | |
780 | // Find valid range |
781 | float startPos = 0.0f; |
782 | float endPos = 0.0f; |
783 | |
784 | for (UINT32 i = 0; i < (UINT32)info.clips.size(); i++) |
785 | { |
786 | startPos = std::min(startPos, info.clips[i].position); |
787 | endPos = std::min(endPos, info.clips[i].position); |
788 | } |
789 | |
790 | float length = endPos - startPos; |
791 | if(Math::approxEquals(length, 0.0f) || info.clips.size() < 2) |
792 | { |
793 | play(info.clips[0].clip); |
794 | return; |
795 | } |
796 | |
797 | // Clamp or loop time |
798 | bool loop = mDefaultWrapMode == AnimWrapMode::Loop; |
799 | if (t < startPos) |
800 | { |
801 | if (loop) |
802 | t = t - std::floor(t / length) * length; |
803 | else // Clamping |
804 | t = startPos; |
805 | } |
806 | |
807 | if (t > endPos) |
808 | { |
809 | if (loop) |
810 | t = t - std::floor(t / length) * length; |
811 | else // Clamping |
812 | t = endPos; |
813 | } |
814 | |
815 | // Find keys to blend between |
816 | UINT32 leftKey = 0; |
817 | UINT32 rightKey = 0; |
818 | |
819 | INT32 start = 0; |
820 | INT32 searchLength = (INT32)info.clips.size(); |
821 | |
822 | while (searchLength > 0) |
823 | { |
824 | INT32 half = searchLength >> 1; |
825 | INT32 mid = start + half; |
826 | |
827 | if (t < info.clips[mid].position) |
828 | { |
829 | searchLength = half; |
830 | } |
831 | else |
832 | { |
833 | start = mid + 1; |
834 | searchLength -= (half + 1); |
835 | } |
836 | } |
837 | |
838 | leftKey = std::max(0, start - 1); |
839 | rightKey = std::min(start, (INT32)info.clips.size() - 1); |
840 | |
841 | float interpLength = info.clips[rightKey].position - info.clips[leftKey].position; |
842 | t = (t - info.clips[leftKey].position) / interpLength; |
843 | |
844 | // Add clips and set weights |
845 | for(UINT32 i = 0; i < (UINT32)info.clips.size(); i++) |
846 | { |
847 | AnimationClipInfo* clipInfo = addClip(info.clips[i].clip, (UINT32)-1, i == 0); |
848 | if (clipInfo != nullptr) |
849 | { |
850 | clipInfo->state.time = 0.0f; |
851 | clipInfo->state.stopped = true; |
852 | clipInfo->state.speed = 0.0f; |
853 | clipInfo->state.wrapMode = AnimWrapMode::Clamp; |
854 | |
855 | if (i == leftKey) |
856 | clipInfo->state.weight = 1.0f - t; |
857 | else if (i == rightKey) |
858 | clipInfo->state.weight = t; |
859 | else |
860 | clipInfo->state.weight = 0.0f; |
861 | |
862 | clipInfo->playbackType = AnimPlaybackType::Normal; |
863 | } |
864 | } |
865 | |
866 | mSampleStep = AnimSampleStep::None; |
867 | mDirty |= AnimDirtyStateFlag::Value; |
868 | } |
869 | |
870 | void Animation::blend2D(const Blend2DInfo& info, const Vector2& t) |
871 | { |
872 | AnimationClipInfo* topLeftClipInfo = addClip(info.topLeftClip, (UINT32)-1, true); |
873 | if (topLeftClipInfo != nullptr) |
874 | { |
875 | topLeftClipInfo->state.time = 0.0f; |
876 | topLeftClipInfo->state.stopped = true; |
877 | topLeftClipInfo->state.speed = 0.0f; |
878 | topLeftClipInfo->state.weight = (1.0f - t.x) * (1.0f - t.y); |
879 | topLeftClipInfo->state.wrapMode = AnimWrapMode::Clamp; |
880 | |
881 | topLeftClipInfo->playbackType = AnimPlaybackType::Normal; |
882 | } |
883 | |
884 | AnimationClipInfo* topRightClipInfo = addClip(info.topRightClip, (UINT32)-1, false); |
885 | if (topRightClipInfo != nullptr) |
886 | { |
887 | topRightClipInfo->state.time = 0.0f; |
888 | topRightClipInfo->state.stopped = true; |
889 | topRightClipInfo->state.speed = 0.0f; |
890 | topRightClipInfo->state.weight = t.x * (1.0f - t.y); |
891 | topRightClipInfo->state.wrapMode = AnimWrapMode::Clamp; |
892 | |
893 | topRightClipInfo->playbackType = AnimPlaybackType::Normal; |
894 | } |
895 | |
896 | AnimationClipInfo* botLeftClipInfo = addClip(info.botLeftClip, (UINT32)-1, false); |
897 | if (botLeftClipInfo != nullptr) |
898 | { |
899 | botLeftClipInfo->state.time = 0.0f; |
900 | botLeftClipInfo->state.stopped = true; |
901 | botLeftClipInfo->state.speed = 0.0f; |
902 | botLeftClipInfo->state.weight = (1.0f - t.x) * t.y; |
903 | botLeftClipInfo->state.wrapMode = AnimWrapMode::Clamp; |
904 | |
905 | botLeftClipInfo->playbackType = AnimPlaybackType::Normal; |
906 | } |
907 | |
908 | AnimationClipInfo* botRightClipInfo = addClip(info.botRightClip, (UINT32)-1, false); |
909 | if (botRightClipInfo != nullptr) |
910 | { |
911 | botRightClipInfo->state.time = 0.0f; |
912 | botRightClipInfo->state.stopped = true; |
913 | botRightClipInfo->state.speed = 0.0f; |
914 | botRightClipInfo->state.weight = t.x * t.y; |
915 | botRightClipInfo->state.wrapMode = AnimWrapMode::Clamp; |
916 | |
917 | botRightClipInfo->playbackType = AnimPlaybackType::Normal; |
918 | } |
919 | |
920 | mSampleStep = AnimSampleStep::None; |
921 | mDirty |= AnimDirtyStateFlag::Value; |
922 | } |
923 | |
924 | void Animation::crossFade(const HAnimationClip& clip, float fadeLength) |
925 | { |
926 | bool isFading = fadeLength > 0.0f; |
927 | if(!isFading) |
928 | { |
929 | play(clip); |
930 | return; |
931 | } |
932 | |
933 | AnimationClipInfo* clipInfo = addClip(clip, (UINT32)-1, false); |
934 | if (clipInfo != nullptr) |
935 | { |
936 | clipInfo->state.time = 0.0f; |
937 | clipInfo->state.speed = mDefaultSpeed; |
938 | clipInfo->state.weight = 1.0f; |
939 | clipInfo->state.wrapMode = mDefaultWrapMode; |
940 | clipInfo->playbackType = AnimPlaybackType::Normal; |
941 | |
942 | // Set up fade lengths |
943 | clipInfo->fadeDirection = 1.0f; |
944 | clipInfo->fadeTime = 0.0f; |
945 | clipInfo->fadeLength = fadeLength; |
946 | |
947 | for (auto& entry : mClipInfos) |
948 | { |
949 | if (entry.state.layer == (UINT32)-1 && entry.clip != clip) |
950 | { |
951 | // If other clips are already cross-fading, we need to persist their current weight before starting |
952 | // a new crossfade. We do that by adjusting the fade times. |
953 | if(clipInfo->fadeDirection != 0 && clipInfo->fadeTime < clipInfo->fadeLength) |
954 | { |
955 | float t = clipInfo->fadeTime / clipInfo->fadeLength; |
956 | if (clipInfo->fadeDirection < 0.0f) |
957 | t = (1.0f - t); |
958 | |
959 | clipInfo->state.weight *= t; |
960 | } |
961 | |
962 | clipInfo->fadeDirection = -1.0f; |
963 | clipInfo->fadeTime = 0.0f; |
964 | clipInfo->fadeLength = fadeLength; |
965 | } |
966 | } |
967 | } |
968 | |
969 | mSampleStep = AnimSampleStep::None; |
970 | mDirty |= AnimDirtyStateFlag::Value; |
971 | } |
972 | |
973 | void Animation::sample(const HAnimationClip& clip, float time) |
974 | { |
975 | AnimationClipInfo* clipInfo = addClip(clip, (UINT32)-1); |
976 | if (clipInfo != nullptr) |
977 | { |
978 | clipInfo->state.time = time; |
979 | clipInfo->state.speed = 0.0f; |
980 | clipInfo->state.weight = 1.0f; |
981 | clipInfo->state.wrapMode = mDefaultWrapMode; |
982 | clipInfo->playbackType = AnimPlaybackType::Sampled; |
983 | } |
984 | |
985 | mSampleStep = AnimSampleStep::Frame; |
986 | mDirty |= AnimDirtyStateFlag::Value; |
987 | } |
988 | |
989 | void Animation::stop(UINT32 layer) |
990 | { |
991 | bs_frame_mark(); |
992 | { |
993 | FrameVector<AnimationClipInfo> newClips; |
994 | for (auto& clipInfo : mClipInfos) |
995 | { |
996 | if (clipInfo.state.layer != layer) |
997 | newClips.push_back(clipInfo); |
998 | else |
999 | mDirty |= AnimDirtyStateFlag::Layout; |
1000 | } |
1001 | |
1002 | mClipInfos.resize(newClips.size()); |
1003 | for(UINT32 i = 0; i < (UINT32)newClips.size(); i++) |
1004 | mClipInfos[i] = newClips[i]; |
1005 | } |
1006 | bs_frame_clear(); |
1007 | } |
1008 | |
1009 | void Animation::stopAll() |
1010 | { |
1011 | mClipInfos.clear(); |
1012 | |
1013 | mSampleStep = AnimSampleStep::None; |
1014 | mDirty |= AnimDirtyStateFlag::Layout; |
1015 | } |
1016 | |
1017 | AnimationClipInfo* Animation::addClip(const HAnimationClip& clip, UINT32 layer, bool stopExisting) |
1018 | { |
1019 | AnimationClipInfo* output = nullptr; |
1020 | bool hasExisting = false; |
1021 | |
1022 | // Search for existing |
1023 | for (auto& clipInfo : mClipInfos) |
1024 | { |
1025 | if (clipInfo.state.layer == layer) |
1026 | { |
1027 | if (clipInfo.clip == clip) |
1028 | output = &clipInfo; |
1029 | else if (stopExisting) |
1030 | hasExisting = true; |
1031 | } |
1032 | } |
1033 | |
1034 | // Doesn't exist or found extra animations, rebuild |
1035 | if (output == nullptr || hasExisting) |
1036 | { |
1037 | bs_frame_mark(); |
1038 | { |
1039 | FrameVector<AnimationClipInfo> newClips; |
1040 | for (auto& clipInfo : mClipInfos) |
1041 | { |
1042 | if (!stopExisting || clipInfo.state.layer != layer || clipInfo.clip == clip) |
1043 | newClips.push_back(clipInfo); |
1044 | } |
1045 | |
1046 | if (output == nullptr && clip != nullptr) |
1047 | newClips.push_back(AnimationClipInfo()); |
1048 | |
1049 | mClipInfos.resize(newClips.size()); |
1050 | for(UINT32 i = 0; i < (UINT32)newClips.size(); i++) |
1051 | mClipInfos[i] = newClips[i]; |
1052 | |
1053 | mDirty |= AnimDirtyStateFlag::Layout; |
1054 | } |
1055 | bs_frame_clear(); |
1056 | } |
1057 | |
1058 | // If new clip was added, get its address |
1059 | if (output == nullptr && clip != nullptr) |
1060 | { |
1061 | AnimationClipInfo& newInfo = mClipInfos.back(); |
1062 | newInfo.clip = clip; |
1063 | newInfo.state.layer = layer; |
1064 | |
1065 | output = &newInfo; |
1066 | } |
1067 | |
1068 | return output; |
1069 | } |
1070 | |
1071 | bool Animation::_getAnimatesRoot() const |
1072 | { |
1073 | if (mSkeleton == nullptr) |
1074 | return false; |
1075 | |
1076 | UINT32 rootBoneIdx = mSkeleton->getRootBoneIndex(); |
1077 | if (rootBoneIdx == (UINT32)-1) |
1078 | return false; |
1079 | |
1080 | String rootBoneName = mSkeleton->getBoneInfo(rootBoneIdx).name; |
1081 | for (auto& entry : mClipInfos) |
1082 | { |
1083 | if (entry.clip.isLoaded()) |
1084 | { |
1085 | HAnimationClip clip = entry.clip; |
1086 | if(!clip->hasRootMotion()) |
1087 | { |
1088 | AnimationCurveMapping mapping; |
1089 | clip->getCurveMapping(rootBoneName, mapping); |
1090 | |
1091 | if (mapping.position != (UINT32)-1) |
1092 | return true; |
1093 | |
1094 | if (mapping.rotation != (UINT32)-1) |
1095 | return true; |
1096 | |
1097 | if (mapping.scale != (UINT32)-1) |
1098 | return true; |
1099 | } |
1100 | } |
1101 | } |
1102 | |
1103 | return false; |
1104 | } |
1105 | |
1106 | void Animation::getListenerResources(Vector<HResource>& resources) |
1107 | { |
1108 | for (auto& entry : mClipInfos) |
1109 | { |
1110 | if(entry.clip != nullptr) |
1111 | resources.push_back(entry.clip); |
1112 | } |
1113 | } |
1114 | |
1115 | void Animation::notifyResourceLoaded(const HResource& resource) |
1116 | { |
1117 | mDirty |= AnimDirtyStateFlag::Layout; |
1118 | } |
1119 | |
1120 | void Animation::notifyResourceChanged(const HResource& resource) |
1121 | { |
1122 | mDirty |= AnimDirtyStateFlag::Layout; |
1123 | } |
1124 | |
1125 | bool Animation::isPlaying() const |
1126 | { |
1127 | for(auto& clipInfo : mClipInfos) |
1128 | { |
1129 | if (clipInfo.clip.isLoaded()) |
1130 | return true; |
1131 | } |
1132 | |
1133 | return false; |
1134 | } |
1135 | |
1136 | bool Animation::getState(const HAnimationClip& clip, AnimationClipState& state) |
1137 | { |
1138 | if (clip == nullptr) |
1139 | return false; |
1140 | |
1141 | for (auto& clipInfo : mClipInfos) |
1142 | { |
1143 | if (clipInfo.clip == clip) |
1144 | { |
1145 | state = clipInfo.state; |
1146 | |
1147 | // Internally we store unclamped time, so clamp/loop it |
1148 | float clipLength = 0.0f; |
1149 | if (clip.isLoaded()) |
1150 | clipLength = clip->getLength(); |
1151 | |
1152 | bool loop = clipInfo.state.wrapMode == AnimWrapMode::Loop; |
1153 | AnimationUtility::wrapTime(clipInfo.state.time, 0.0f, clipLength, loop); |
1154 | |
1155 | return true; |
1156 | } |
1157 | } |
1158 | |
1159 | return false; |
1160 | } |
1161 | |
1162 | void Animation::setState(const HAnimationClip& clip, AnimationClipState state) |
1163 | { |
1164 | if (state.layer == 0) |
1165 | state.layer = (UINT32)-1; |
1166 | else |
1167 | state.layer -= 1; |
1168 | |
1169 | AnimationClipInfo* clipInfo = addClip(clip, state.layer, false); |
1170 | |
1171 | if (clipInfo == nullptr) |
1172 | return; |
1173 | |
1174 | clipInfo->state = state; |
1175 | clipInfo->playbackType = AnimPlaybackType::Normal; |
1176 | |
1177 | mSampleStep = AnimSampleStep::None; |
1178 | mDirty |= AnimDirtyStateFlag::Value; |
1179 | } |
1180 | |
1181 | UINT32 Animation::getNumClips() const |
1182 | { |
1183 | return (UINT32)mClipInfos.size(); |
1184 | } |
1185 | |
1186 | HAnimationClip Animation::getClip(UINT32 idx) const |
1187 | { |
1188 | if (idx >= (UINT32)mClipInfos.size()) |
1189 | return HAnimationClip(); |
1190 | |
1191 | return mClipInfos[idx].clip; |
1192 | } |
1193 | |
1194 | void Animation::triggerEvents(float delta) |
1195 | { |
1196 | for (auto& clipInfo : mClipInfos) |
1197 | { |
1198 | if (!clipInfo.clip.isLoaded()) |
1199 | continue; |
1200 | |
1201 | const Vector<AnimationEvent>& events = clipInfo.clip->getEvents(); |
1202 | bool loop = clipInfo.state.wrapMode == AnimWrapMode::Loop; |
1203 | |
1204 | float start = std::max(clipInfo.state.time - delta, 0.0f); |
1205 | float end = clipInfo.state.time; |
1206 | float clipLength = clipInfo.clip->getLength(); |
1207 | |
1208 | float wrappedStart = start; |
1209 | float wrappedEnd = end; |
1210 | AnimationUtility::wrapTime(wrappedStart, 0.0f, clipLength, loop); |
1211 | AnimationUtility::wrapTime(wrappedEnd, 0.0f, clipLength, loop); |
1212 | |
1213 | if(!loop) |
1214 | { |
1215 | for (auto& event : events) |
1216 | { |
1217 | if (event.time >= wrappedStart && (event.time < wrappedEnd || |
1218 | (event.time == clipLength && start < clipLength && end >= clipLength))) |
1219 | onEventTriggered(clipInfo.clip, event.name); |
1220 | } |
1221 | } |
1222 | else |
1223 | { |
1224 | if (wrappedStart < wrappedEnd) |
1225 | { |
1226 | for (auto& event : events) |
1227 | { |
1228 | if (event.time >= wrappedStart && event.time < wrappedEnd) |
1229 | onEventTriggered(clipInfo.clip, event.name); |
1230 | } |
1231 | } |
1232 | else if (wrappedEnd < wrappedStart) // End is looped, but start is not |
1233 | { |
1234 | for (auto& event : events) |
1235 | { |
1236 | if ((event.time >= wrappedStart && event.time <= clipLength) || (event.time >= 0 && event.time < wrappedEnd)) |
1237 | onEventTriggered(clipInfo.clip, event.name); |
1238 | } |
1239 | } |
1240 | } |
1241 | } |
1242 | } |
1243 | |
1244 | void Animation::mapCurveToSceneObject(const String& curve, const HSceneObject& so) |
1245 | { |
1246 | AnimatedSceneObject animSo = { so, curve }; |
1247 | mSceneObjects[so.getInstanceId()] = animSo; |
1248 | |
1249 | mDirty |= AnimDirtyStateFlag::All; |
1250 | } |
1251 | |
1252 | void Animation::unmapSceneObject(const HSceneObject& so) |
1253 | { |
1254 | mSceneObjects.erase(so.getInstanceId()); |
1255 | |
1256 | mDirty |= AnimDirtyStateFlag::All; |
1257 | } |
1258 | |
1259 | bool Animation::getGenericCurveValue(UINT32 curveIdx, float& value) |
1260 | { |
1261 | if (!mGenericCurveValuesValid || curveIdx >= (UINT32)mGenericCurveOutputs.size()) |
1262 | return false; |
1263 | |
1264 | value = mGenericCurveOutputs[curveIdx]; |
1265 | return true; |
1266 | } |
1267 | |
1268 | SPtr<Animation> Animation::create() |
1269 | { |
1270 | Animation* anim = new (bs_alloc<Animation>()) Animation(); |
1271 | |
1272 | SPtr<Animation> animPtr = bs_core_ptr(anim); |
1273 | animPtr->_setThisPtr(animPtr); |
1274 | animPtr->initialize(); |
1275 | |
1276 | return animPtr; |
1277 | } |
1278 | |
1279 | void Animation::updateAnimProxy(float timeDelta) |
1280 | { |
1281 | // Check if any of the clip curves are dirty and advance time, perform fading |
1282 | for (auto& clipInfo : mClipInfos) |
1283 | { |
1284 | float scaledTimeDelta = timeDelta * clipInfo.state.speed; |
1285 | clipInfo.state.time += scaledTimeDelta; |
1286 | |
1287 | HAnimationClip clip = clipInfo.clip; |
1288 | if (clip.isLoaded()) |
1289 | { |
1290 | if (clipInfo.curveVersion != clip->getVersion()) |
1291 | mDirty |= AnimDirtyStateFlag::Layout; |
1292 | } |
1293 | |
1294 | float fadeTime = clipInfo.fadeTime + scaledTimeDelta; |
1295 | clipInfo.fadeTime = Math::clamp(fadeTime, 0.0f, clipInfo.fadeLength); |
1296 | } |
1297 | |
1298 | if(mSampleStep == AnimSampleStep::None) |
1299 | mAnimProxy->sampleStep = AnimSampleStep::None; |
1300 | else if(mSampleStep == AnimSampleStep::Frame) |
1301 | { |
1302 | if(mAnimProxy->sampleStep == AnimSampleStep::None) |
1303 | mAnimProxy->sampleStep = AnimSampleStep::Frame; |
1304 | else |
1305 | mAnimProxy->sampleStep = AnimSampleStep::Done; |
1306 | } |
1307 | |
1308 | if (mDirty.isSet(AnimDirtyStateFlag::Culling)) |
1309 | { |
1310 | mAnimProxy->mCullEnabled = mCull; |
1311 | mAnimProxy->mBounds = mBounds; |
1312 | |
1313 | mDirty.unset(AnimDirtyStateFlag::Culling); |
1314 | } |
1315 | |
1316 | auto getAnimatedSOList = [&]() |
1317 | { |
1318 | Vector<AnimatedSceneObject> animatedSO(mSceneObjects.size()); |
1319 | UINT32 idx = 0; |
1320 | for (auto& entry : mSceneObjects) |
1321 | animatedSO[idx++] = entry.second; |
1322 | |
1323 | return animatedSO; |
1324 | }; |
1325 | |
1326 | bool didFullRebuild = false; |
1327 | if((UINT32)mDirty == 0) // Clean |
1328 | { |
1329 | mAnimProxy->updateTime(mClipInfos); |
1330 | } |
1331 | else |
1332 | { |
1333 | if (mDirty.isSet(AnimDirtyStateFlag::All)) |
1334 | { |
1335 | Vector<AnimatedSceneObject> animatedSOs = getAnimatedSOList(); |
1336 | |
1337 | mAnimProxy->rebuild(mSkeleton, mSkeletonMask, mClipInfos, animatedSOs, mMorphShapes); |
1338 | didFullRebuild = true; |
1339 | } |
1340 | else if (mDirty.isSet(AnimDirtyStateFlag::Layout)) |
1341 | { |
1342 | Vector<AnimatedSceneObject> animatedSOs = getAnimatedSOList(); |
1343 | |
1344 | mAnimProxy->rebuild(mClipInfos, animatedSOs, mMorphShapes); |
1345 | didFullRebuild = true; |
1346 | } |
1347 | else if(mDirty.isSet(AnimDirtyStateFlag::Value)) |
1348 | mAnimProxy->updateClipInfos(mClipInfos); |
1349 | |
1350 | if (mDirty.isSet(AnimDirtyStateFlag::MorphWeights) || didFullRebuild) |
1351 | mAnimProxy->updateMorphChannelWeights(mMorphChannelWeights); |
1352 | } |
1353 | |
1354 | // Check if there are dirty transforms |
1355 | if (!didFullRebuild) |
1356 | { |
1357 | for (UINT32 i = 0; i < mAnimProxy->numSceneObjects; i++) |
1358 | { |
1359 | AnimatedSceneObjectInfo& soInfo = mAnimProxy->sceneObjectInfos[i]; |
1360 | |
1361 | auto iterFind = mSceneObjects.find(soInfo.id); |
1362 | if (iterFind == mSceneObjects.end()) |
1363 | { |
1364 | assert(false); // Should never happen |
1365 | continue; |
1366 | } |
1367 | |
1368 | UINT32 hash; |
1369 | |
1370 | HSceneObject so = iterFind->second.so; |
1371 | if (so.isDestroyed(true)) |
1372 | hash = 0; |
1373 | else |
1374 | hash = so->getTransformHash(); |
1375 | |
1376 | if (hash != mAnimProxy->sceneObjectInfos[i].hash) |
1377 | { |
1378 | Vector<AnimatedSceneObject> animatedSOs = getAnimatedSOList(); |
1379 | mAnimProxy->updateTransforms(animatedSOs); |
1380 | break; |
1381 | } |
1382 | } |
1383 | } |
1384 | |
1385 | mDirty = AnimDirtyState(); |
1386 | } |
1387 | |
1388 | void Animation::updateFromProxy() |
1389 | { |
1390 | // When sampling a single frame we don't want to keep updating the scene objects so they can be moved through other |
1391 | // means (e.g. for the purposes of recording new keyframes if running from the editor). |
1392 | const bool disableSOUpdates = mAnimProxy->sampleStep == AnimSampleStep::Done; |
1393 | if(disableSOUpdates) |
1394 | return; |
1395 | |
1396 | // If the object was culled, then we have no valid data to read back |
1397 | if(mAnimProxy->wasCulled) |
1398 | return; |
1399 | |
1400 | HSceneObject rootSO; |
1401 | |
1402 | // Write TRS animation results to relevant SceneObjects |
1403 | for(UINT32 i = 0; i < mAnimProxy->numSceneObjects; i++) |
1404 | { |
1405 | AnimatedSceneObjectInfo& soInfo = mAnimProxy->sceneObjectInfos[i]; |
1406 | |
1407 | auto iterFind = mSceneObjects.find(soInfo.id); |
1408 | if (iterFind == mSceneObjects.end()) |
1409 | continue; |
1410 | |
1411 | HSceneObject so = iterFind->second.so; |
1412 | if (iterFind->second.curveName.empty()) |
1413 | rootSO = so; |
1414 | |
1415 | if (so.isDestroyed(true)) |
1416 | continue; |
1417 | |
1418 | if(soInfo.boneIdx != -1) |
1419 | { |
1420 | if (mAnimProxy->skeletonPose.hasOverride[soInfo.boneIdx]) |
1421 | continue; |
1422 | |
1423 | Vector3 position = mAnimProxy->skeletonPose.positions[soInfo.boneIdx]; |
1424 | Quaternion rotation = mAnimProxy->skeletonPose.rotations[soInfo.boneIdx]; |
1425 | Vector3 scale = mAnimProxy->skeletonPose.scales[soInfo.boneIdx]; |
1426 | |
1427 | const SPtr<Skeleton>& skeleton = mAnimProxy->skeleton; |
1428 | |
1429 | UINT32 parentBoneIdx = skeleton->getBoneInfo(soInfo.boneIdx).parent; |
1430 | if (parentBoneIdx == (UINT32)-1) |
1431 | { |
1432 | so->setPosition(position); |
1433 | so->setRotation(rotation); |
1434 | so->setScale(scale); |
1435 | } |
1436 | else |
1437 | { |
1438 | while(parentBoneIdx != (UINT32)-1) |
1439 | { |
1440 | // Update rotation |
1441 | const Quaternion& parentOrientation = mAnimProxy->skeletonPose.rotations[parentBoneIdx]; |
1442 | rotation = parentOrientation * rotation; |
1443 | |
1444 | // Update scale |
1445 | const Vector3& parentScale = mAnimProxy->skeletonPose.scales[parentBoneIdx]; |
1446 | scale = parentScale * scale; |
1447 | |
1448 | // Update position |
1449 | position = parentOrientation.rotate(parentScale * position); |
1450 | position += mAnimProxy->skeletonPose.positions[parentBoneIdx]; |
1451 | |
1452 | parentBoneIdx = skeleton->getBoneInfo(parentBoneIdx).parent; |
1453 | } |
1454 | |
1455 | // Search for root if not already found |
1456 | if(rootSO == nullptr) |
1457 | { |
1458 | for(auto& entry : mSceneObjects) |
1459 | { |
1460 | if (entry.second.curveName.empty()) |
1461 | rootSO = entry.second.so; |
1462 | } |
1463 | } |
1464 | |
1465 | while(rootSO && rootSO.isDestroyed(true)) |
1466 | rootSO = rootSO->getParent(); |
1467 | |
1468 | Vector3 parentPos = Vector3::ZERO; |
1469 | Quaternion parentRot = Quaternion::IDENTITY; |
1470 | Vector3 parentScale = Vector3::ONE; |
1471 | |
1472 | if(!rootSO.isDestroyed(true)) |
1473 | { |
1474 | const Transform& tfrm = rootSO->getTransform(); |
1475 | parentPos = tfrm.getPosition(); |
1476 | parentRot = tfrm.getRotation(); |
1477 | parentScale = tfrm.getScale(); |
1478 | } |
1479 | |
1480 | // Transform from space relative to root's parent to world space |
1481 | rotation = parentRot * rotation; |
1482 | |
1483 | scale = parentScale * scale; |
1484 | |
1485 | position = parentRot.rotate(parentScale * position); |
1486 | position += parentPos; |
1487 | |
1488 | so->setWorldPosition(position); |
1489 | so->setWorldRotation(rotation); |
1490 | so->setWorldScale(scale); |
1491 | } |
1492 | } |
1493 | else |
1494 | { |
1495 | if (!mAnimProxy->sceneObjectPose.hasOverride[i * 3 + 0]) |
1496 | so->setPosition(mAnimProxy->sceneObjectPose.positions[i]); |
1497 | |
1498 | if (!mAnimProxy->sceneObjectPose.hasOverride[i * 3 + 1]) |
1499 | so->setRotation(mAnimProxy->sceneObjectPose.rotations[i]); |
1500 | |
1501 | if (!mAnimProxy->sceneObjectPose.hasOverride[i * 3 + 2]) |
1502 | so->setScale(mAnimProxy->sceneObjectPose.scales[i]); |
1503 | } |
1504 | } |
1505 | |
1506 | // Must ensure that clip in the proxy and current primary clip are the same |
1507 | mGenericCurveValuesValid = false; |
1508 | if(mAnimProxy->numLayers > 0 && mAnimProxy->layers[0].numStates > 0) |
1509 | { |
1510 | const AnimationState& state = mAnimProxy->layers[0].states[0]; |
1511 | |
1512 | if(!state.disabled && mClipInfos.size() > 0) |
1513 | { |
1514 | const AnimationClipInfo& clipInfo = mClipInfos[0]; |
1515 | |
1516 | if (clipInfo.stateIdx == 0 && clipInfo.layerIdx == 0) |
1517 | { |
1518 | if (clipInfo.clip.isLoaded() && clipInfo.curveVersion == clipInfo.clip->getVersion()) |
1519 | { |
1520 | UINT32 numGenericCurves = (UINT32)clipInfo.clip->getCurves()->generic.size(); |
1521 | mGenericCurveValuesValid = numGenericCurves == mAnimProxy->numGenericCurves; |
1522 | } |
1523 | } |
1524 | } |
1525 | } |
1526 | |
1527 | if(mGenericCurveValuesValid) |
1528 | { |
1529 | mGenericCurveOutputs.resize(mAnimProxy->numGenericCurves); |
1530 | |
1531 | memcpy(mGenericCurveOutputs.data(), mAnimProxy->genericCurveOutputs, mAnimProxy->numGenericCurves * sizeof(float)); |
1532 | } |
1533 | } |
1534 | } |
1535 | |