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
10namespace 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 layersSize = 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