Coverage Report

Created: 2025-12-25 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ogre/OgreMain/src/OgreAnimationTrack.cpp
Line
Count
Source
1
/*
2
-----------------------------------------------------------------------------
3
This source file is part of OGRE
4
    (Object-oriented Graphics Rendering Engine)
5
For the latest info, see http://www.ogre3d.org/
6
7
Copyright (c) 2000-2014 Torus Knot Software Ltd
8
9
Permission is hereby granted, free of charge, to any person obtaining a copy
10
of this software and associated documentation files (the "Software"), to deal
11
in the Software without restriction, including without limitation the rights
12
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
copies of the Software, and to permit persons to whom the Software is
14
furnished to do so, subject to the following conditions:
15
16
The above copyright notice and this permission notice shall be included in
17
all copies or substantial portions of the Software.
18
19
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
THE SOFTWARE.
26
-----------------------------------------------------------------------------
27
*/
28
#include "OgreStableHeaders.h"
29
#include "OgreAnimationTrack.h"
30
#include "OgreAnimation.h"
31
#include "OgreKeyFrame.h"
32
33
namespace Ogre {
34
35
    namespace {
36
        // Locally key frame search helper
37
        struct KeyFrameTimeLess
38
        {
39
            bool operator() (const KeyFrame* kf, const KeyFrame* kf2) const
40
0
            {
41
0
                return kf->getTime() < kf2->getTime();
42
0
            }
43
        };
44
    }
45
    //---------------------------------------------------------------------
46
    //---------------------------------------------------------------------
47
    AnimationTrack::AnimationTrack(Animation* parent, unsigned short handle) :
48
0
        mParent(parent), mListener(0), mHandle(handle)
49
0
    {
50
0
    }
51
    //---------------------------------------------------------------------
52
    AnimationTrack::~AnimationTrack()
53
0
    {
54
0
        removeAllKeyFrames();
55
0
    }
56
    //---------------------------------------------------------------------
57
    float AnimationTrack::getKeyFramesAtTime(const TimeIndex& timeIndex, KeyFrame** keyFrame1, KeyFrame** keyFrame2,
58
        unsigned short* firstKeyIndex) const
59
0
    {
60
        // Parametric time
61
        // t1 = time of previous keyframe
62
        // t2 = time of next keyframe
63
0
        Real t1, t2;
64
65
0
        Real timePos = timeIndex.getTimePos();
66
67
        // Find first keyframe after or on current time
68
0
        KeyFrameList::const_iterator i;
69
0
        if (timeIndex.hasKeyIndex())
70
0
        {
71
            // Global keyframe index available, map to local keyframe index directly.
72
0
            assert(timeIndex.getKeyIndex() < mKeyFrameIndexMap.size());
73
0
            i = mKeyFrames.begin() + mKeyFrameIndexMap[timeIndex.getKeyIndex()];
74
#if OGRE_DEBUG_MODE
75
            KeyFrame timeKey(NULL, timePos);
76
            if (i != std::lower_bound(mKeyFrames.begin(), mKeyFrames.end() - 1, &timeKey, KeyFrameTimeLess()))
77
            {
78
                OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Optimised key frame search failed");
79
            }
80
#endif
81
0
        }
82
0
        else
83
0
        {
84
            // Wrap time
85
0
            Real totalAnimationLength = mParent->getLength();
86
0
            OgreAssertDbg(totalAnimationLength > 0.0f, "Invalid animation length!");
87
88
0
            if( timePos > totalAnimationLength && totalAnimationLength > 0.0f )
89
0
                timePos = std::fmod( timePos, totalAnimationLength );
90
91
            // No global keyframe index, need to search with local keyframes.
92
0
            KeyFrame timeKey(NULL, timePos);
93
0
            i = std::lower_bound(mKeyFrames.begin(), mKeyFrames.end() - 1, &timeKey, KeyFrameTimeLess());
94
0
        }
95
96
0
        OgreAssertDbg(i != mKeyFrames.end(), "time should have been wrapped before this");
97
98
0
        *keyFrame2 = *i;
99
0
        t2 = (*keyFrame2)->getTime();
100
101
        // Find last keyframe before or on current time
102
0
        if (i != mKeyFrames.begin() && timePos < (*i)->getTime())
103
0
        {
104
0
            --i;
105
0
        }
106
107
        // Fill index of the first key
108
0
        if (firstKeyIndex)
109
0
        {
110
0
            *firstKeyIndex = static_cast<unsigned short>(std::distance(mKeyFrames.begin(), i));
111
0
        }
112
113
0
        *keyFrame1 = *i;
114
115
0
        t1 = (*keyFrame1)->getTime();
116
117
0
        if (t1 == t2)
118
0
        {
119
            // Same KeyFrame (only one)
120
0
            return 0.0f;
121
0
        }
122
0
        else
123
0
        {
124
0
            return (timePos - t1) / (t2 - t1);
125
0
        }
126
0
    }
127
    //---------------------------------------------------------------------
128
    KeyFrame* AnimationTrack::createKeyFrame(Real timePos)
129
0
    {
130
0
        KeyFrame* kf = createKeyFrameImpl(timePos);
131
132
        // Insert just before upper bound
133
0
        KeyFrameList::iterator i =
134
0
            std::upper_bound(mKeyFrames.begin(), mKeyFrames.end(), kf, KeyFrameTimeLess());
135
0
        mKeyFrames.insert(i, kf);
136
137
0
        _keyFrameDataChanged();
138
0
        mParent->_keyFrameListChanged();
139
140
0
        return kf;
141
142
0
    }
143
    //---------------------------------------------------------------------
144
    void AnimationTrack::removeKeyFrame(unsigned short index)
145
0
    {
146
        // If you hit this assert, then the keyframe index is out of bounds
147
0
        assert( index < (ushort)mKeyFrames.size() );
148
149
0
        KeyFrameList::iterator i = mKeyFrames.begin();
150
151
0
        i += index;
152
153
0
        OGRE_DELETE *i;
154
155
0
        mKeyFrames.erase(i);
156
157
0
        _keyFrameDataChanged();
158
0
        mParent->_keyFrameListChanged();
159
160
161
0
    }
162
    //---------------------------------------------------------------------
163
    void AnimationTrack::removeAllKeyFrames(void)
164
0
    {
165
0
        for (auto *f : mKeyFrames)
166
0
            OGRE_DELETE f;
167
168
0
        _keyFrameDataChanged();
169
0
        mParent->_keyFrameListChanged();
170
171
0
        mKeyFrames.clear();
172
173
0
    }
174
    //---------------------------------------------------------------------
175
    void AnimationTrack::_collectKeyFrameTimes(std::vector<Real>& keyFrameTimes)
176
0
    {
177
0
        for (auto k : mKeyFrames)
178
0
        {
179
0
            Real timePos = k->getTime();
180
181
0
            std::vector<Real>::iterator it =
182
0
                std::lower_bound(keyFrameTimes.begin(), keyFrameTimes.end(), timePos);
183
0
            if (it == keyFrameTimes.end() || *it != timePos)
184
0
            {
185
0
                keyFrameTimes.insert(it, timePos);
186
0
            }
187
0
        }
188
0
    }
189
    //---------------------------------------------------------------------
190
    void AnimationTrack::_buildKeyFrameIndexMap(const std::vector<Real>& keyFrameTimes)
191
0
    {
192
        // Pre-allocate memory
193
0
        mKeyFrameIndexMap.resize(keyFrameTimes.size());
194
195
0
        int i = 0, j = 0;
196
197
0
        while (j < int(keyFrameTimes.size()))
198
0
        {
199
0
            mKeyFrameIndexMap[j] = static_cast<ushort>(i);
200
0
            while (i < (int(mKeyFrames.size()) - 1) && mKeyFrames[i]->getTime() <= keyFrameTimes[j])
201
0
            {
202
0
                ++i;
203
0
            }
204
0
            ++j;
205
0
        }
206
0
    }
207
    //--------------------------------------------------------------------------
208
    void AnimationTrack::_applyBaseKeyFrame(const KeyFrame*)
209
0
    {
210
211
0
    }
212
    //---------------------------------------------------------------------
213
    void AnimationTrack::populateClone(AnimationTrack* clone) const
214
0
    {
215
0
        for (auto k : mKeyFrames)
216
0
        {
217
0
            KeyFrame* clonekf = k->_clone(clone);
218
0
            clone->mKeyFrames.push_back(clonekf);
219
0
        }
220
0
    }
221
    //---------------------------------------------------------------------
222
    //---------------------------------------------------------------------
223
    // Numeric specialisations
224
    //---------------------------------------------------------------------
225
    NumericAnimationTrack::NumericAnimationTrack(Animation* parent,
226
        unsigned short handle, const AnimableValuePtr& target)
227
0
        :AnimationTrack(parent, handle), mTargetAnim(target)
228
0
    {
229
0
    }
230
    //---------------------------------------------------------------------
231
    KeyFrame* NumericAnimationTrack::createKeyFrameImpl(Real time)
232
0
    {
233
0
        return OGRE_NEW NumericKeyFrame(this, time);
234
0
    }
235
236
    static Any lerpAny(const Any& v0, const Any& v1, Real t, AnimableValue::ValueType type)
237
0
    {
238
0
        switch(type)
239
0
        {
240
0
        default:
241
0
        case AnimableValue::INT:
242
0
            return Math::lerp(any_cast<int>(v0), any_cast<int>(v1), t);
243
0
        case AnimableValue::REAL:
244
0
            return Math::lerp(any_cast<Real>(v0), any_cast<Real>(v1), t);
245
0
        case AnimableValue::VECTOR2:
246
0
            return Math::lerp(any_cast<Vector2>(v0), any_cast<Vector2>(v1), t);
247
0
        case AnimableValue::VECTOR3:
248
0
            return Math::lerp(any_cast<Vector3>(v0), any_cast<Vector3>(v1), t);
249
0
        case AnimableValue::VECTOR4:
250
0
            return Math::lerp(any_cast<Vector4>(v0), any_cast<Vector4>(v1), t);
251
0
        case AnimableValue::QUATERNION:
252
0
            return Math::lerp(any_cast<Quaternion>(v0), any_cast<Quaternion>(v1), t);
253
0
        case AnimableValue::COLOUR:
254
0
            return Math::lerp(any_cast<ColourValue>(v0), any_cast<ColourValue>(v1), t);
255
0
        case AnimableValue::RADIAN:
256
0
            return Math::lerp(any_cast<Radian>(v0), any_cast<Radian>(v1), t);
257
0
        }
258
0
    }
259
260
    //---------------------------------------------------------------------
261
    void NumericAnimationTrack::getInterpolatedKeyFrame(const TimeIndex& timeIndex,
262
        KeyFrame* kf) const
263
0
    {
264
0
        if (mListener)
265
0
        {
266
0
            if (mListener->getInterpolatedKeyFrame(this, timeIndex, kf))
267
0
                return;
268
0
        }
269
270
0
        NumericKeyFrame* kret = static_cast<NumericKeyFrame*>(kf);
271
272
        // Keyframe pointers
273
0
        KeyFrame *kBase1, *kBase2;
274
0
        NumericKeyFrame *k1, *k2;
275
0
        unsigned short firstKeyIndex;
276
277
0
        Real t = this->getKeyFramesAtTime(timeIndex, &kBase1, &kBase2, &firstKeyIndex);
278
0
        k1 = static_cast<NumericKeyFrame*>(kBase1);
279
0
        k2 = static_cast<NumericKeyFrame*>(kBase2);
280
281
0
        if (t == 0.0)
282
0
        {
283
            // Just use k1
284
0
            kret->setValue(k1->getValue());
285
0
        }
286
0
        else
287
0
        {
288
            // Interpolate by t
289
0
            kret->setValue(lerpAny(k1->getValue(), k2->getValue(), t, mTargetAnim->getType()));
290
0
        }
291
0
    }
292
    //---------------------------------------------------------------------
293
    void NumericAnimationTrack::apply(const TimeIndex& timeIndex, Real weight, Real scale)
294
0
    {
295
0
        applyToAnimable(mTargetAnim, timeIndex, weight, scale);
296
0
    }
297
    //---------------------------------------------------------------------
298
    static Any scaleAny(const Any& v, Real s, AnimableValue::ValueType type)
299
0
    {
300
0
        switch(type)
301
0
        {
302
0
        default:
303
0
        case AnimableValue::INT:
304
0
            return any_cast<int>(v) * s;
305
0
        case AnimableValue::REAL:
306
0
            return any_cast<Real>(v) * s;
307
0
        case AnimableValue::VECTOR2:
308
0
            return any_cast<Vector2>(v) * s;
309
0
        case AnimableValue::VECTOR3:
310
0
            return any_cast<Vector3>(v) * s;
311
0
        case AnimableValue::VECTOR4:
312
0
            return any_cast<Vector4>(v) * s;
313
0
        case AnimableValue::QUATERNION:
314
0
            return any_cast<Quaternion>(v) * s;
315
0
        case AnimableValue::COLOUR:
316
0
            return any_cast<ColourValue>(v) * s;
317
0
        case AnimableValue::RADIAN:
318
0
            return any_cast<Radian>(v) * s;
319
0
        }
320
0
    }
321
    void NumericAnimationTrack::applyToAnimable(const AnimableValuePtr& anim, const TimeIndex& timeIndex,
322
        Real weight, Real scale)
323
0
    {
324
        // Nothing to do if no keyframes or zero weight, scale
325
0
        if (mKeyFrames.empty() || !weight || !scale)
326
0
            return;
327
328
0
        NumericKeyFrame kf(0, timeIndex.getTimePos());
329
0
        getInterpolatedKeyFrame(timeIndex, &kf);
330
        // add to existing. Weights are not relative, but treated as
331
        // absolute multipliers for the animation
332
0
        anim->applyDeltaValue(scaleAny(kf.getValue(), weight * scale, mTargetAnim->getType()));
333
334
0
    }
335
    //--------------------------------------------------------------------------
336
    NumericKeyFrame* NumericAnimationTrack::createNumericKeyFrame(Real timePos)
337
0
    {
338
0
        return static_cast<NumericKeyFrame*>(createKeyFrame(timePos));
339
0
    }
340
    //--------------------------------------------------------------------------
341
    NumericKeyFrame* NumericAnimationTrack::getNumericKeyFrame(unsigned short index) const
342
0
    {
343
0
        return static_cast<NumericKeyFrame*>(getKeyFrame(index));
344
0
    }
345
    //---------------------------------------------------------------------
346
    NumericAnimationTrack* NumericAnimationTrack::_clone(Animation* newParent) const
347
0
    {
348
0
        NumericAnimationTrack* newTrack = newParent->createNumericTrack(mHandle, mTargetAnim);
349
0
        populateClone(newTrack);
350
0
        return newTrack;
351
0
    }
352
    //---------------------------------------------------------------------
353
    //---------------------------------------------------------------------
354
    // Node specialisations
355
    //---------------------------------------------------------------------
356
    NodeAnimationTrack::NodeAnimationTrack(Animation* parent, unsigned short handle)
357
0
        : NodeAnimationTrack(parent, handle, 0)
358
0
    {
359
0
    }
360
    //---------------------------------------------------------------------
361
    NodeAnimationTrack::NodeAnimationTrack(Animation* parent, unsigned short handle, Node* targetNode)
362
0
        : AnimationTrack(parent, handle), mSplineBuildNeeded(false), mUseShortestRotationPath(true),
363
0
          mTargetNode(targetNode), mSplines(0)
364
365
0
    {
366
0
    }
367
    //---------------------------------------------------------------------
368
    NodeAnimationTrack::~NodeAnimationTrack()
369
0
    {
370
0
        OGRE_DELETE_T(mSplines, Splines, MEMCATEGORY_ANIMATION);
371
0
    }
372
    //---------------------------------------------------------------------
373
    void NodeAnimationTrack::getInterpolatedKeyFrame(const TimeIndex& timeIndex, KeyFrame* kf) const
374
0
    {
375
0
        if (mListener)
376
0
        {
377
0
            if (mListener->getInterpolatedKeyFrame(this, timeIndex, kf))
378
0
                return;
379
0
        }
380
381
0
        TransformKeyFrame* kret = static_cast<TransformKeyFrame*>(kf);
382
383
        // Keyframe pointers
384
0
        KeyFrame *kBase1, *kBase2;
385
0
        TransformKeyFrame *k1, *k2;
386
0
        unsigned short firstKeyIndex;
387
388
0
        Real t = this->getKeyFramesAtTime(timeIndex, &kBase1, &kBase2, &firstKeyIndex);
389
0
        k1 = static_cast<TransformKeyFrame*>(kBase1);
390
0
        k2 = static_cast<TransformKeyFrame*>(kBase2);
391
392
0
        if (t == 0.0)
393
0
        {
394
            // Just use k1
395
0
            kret->setRotation(k1->getRotation());
396
0
            kret->setTranslate(k1->getTranslate());
397
0
            kret->setScale(k1->getScale());
398
0
        }
399
0
        else
400
0
        {
401
            // Interpolate by t
402
0
            Animation::InterpolationMode im = mParent->getInterpolationMode();
403
0
            Animation::RotationInterpolationMode rim =
404
0
                mParent->getRotationInterpolationMode();
405
0
            Vector3 base;
406
0
            switch(im)
407
0
            {
408
0
            case Animation::IM_LINEAR:
409
                // Interpolate linearly
410
                // Rotation
411
                // Interpolate to nearest rotation if mUseShortestRotationPath set
412
0
                if (rim == Animation::RIM_LINEAR)
413
0
                {
414
0
                    kret->setRotation( Quaternion::nlerp(t, k1->getRotation(),
415
0
                        k2->getRotation(), mUseShortestRotationPath) );
416
0
                }
417
0
                else //if (rim == Animation::RIM_SPHERICAL)
418
0
                {
419
0
                    kret->setRotation( Quaternion::Slerp(t, k1->getRotation(),
420
0
                        k2->getRotation(), mUseShortestRotationPath) );
421
0
                }
422
423
                // Translation
424
0
                base = k1->getTranslate();
425
0
                kret->setTranslate( base + ((k2->getTranslate() - base) * t) );
426
427
                // Scale
428
0
                base = k1->getScale();
429
0
                kret->setScale( base + ((k2->getScale() - base) * t) );
430
0
                break;
431
432
0
            case Animation::IM_SPLINE:
433
                // Spline interpolation
434
435
                // Build splines if required
436
0
                if (mSplineBuildNeeded)
437
0
                {
438
0
                    buildInterpolationSplines();
439
0
                }
440
441
                // Rotation, take mUseShortestRotationPath into account
442
0
                kret->setRotation( mSplines->rotationSpline.interpolate(firstKeyIndex, t,
443
0
                    mUseShortestRotationPath) );
444
445
                // Translation
446
0
                kret->setTranslate( mSplines->positionSpline.interpolate(firstKeyIndex, t) );
447
448
                // Scale
449
0
                kret->setScale( mSplines->scaleSpline.interpolate(firstKeyIndex, t) );
450
451
0
                break;
452
0
            }
453
454
0
        }
455
0
    }
456
    //---------------------------------------------------------------------
457
    void NodeAnimationTrack::apply(const TimeIndex& timeIndex, Real weight, Real scale)
458
0
    {
459
0
        applyToNode(mTargetNode, timeIndex, weight, scale);
460
461
0
    }
462
    //---------------------------------------------------------------------
463
    Node* NodeAnimationTrack::getAssociatedNode(void) const
464
0
    {
465
0
        return mTargetNode;
466
0
    }
467
    //---------------------------------------------------------------------
468
    void NodeAnimationTrack::setAssociatedNode(Node* node)
469
0
    {
470
0
        mTargetNode = node;
471
0
    }
472
    //---------------------------------------------------------------------
473
    void NodeAnimationTrack::applyToNode(Node* node, const TimeIndex& timeIndex, Real weight,
474
        Real scl)
475
0
    {
476
        // Nothing to do if no keyframes or zero weight or no node
477
0
        if (mKeyFrames.empty() || !weight || !node)
478
0
            return;
479
480
0
        TransformKeyFrame kf(0, timeIndex.getTimePos());
481
0
        getInterpolatedKeyFrame(timeIndex, &kf);
482
483
        // add to existing. Weights are not relative, but treated as absolute multipliers for the animation
484
0
        Vector3 translate = kf.getTranslate() * weight * scl;
485
0
        node->translate(translate);
486
487
        // interpolate between no-rotation and full rotation, to point 'weight', so 0 = no rotate, 1 = full
488
0
        Quaternion rotate;
489
0
        Animation::RotationInterpolationMode rim =
490
0
            mParent->getRotationInterpolationMode();
491
0
        if (rim == Animation::RIM_LINEAR)
492
0
        {
493
0
            rotate = Quaternion::nlerp(weight, Quaternion::IDENTITY, kf.getRotation(), mUseShortestRotationPath);
494
0
        }
495
0
        else //if (rim == Animation::RIM_SPHERICAL)
496
0
        {
497
0
            rotate = Quaternion::Slerp(weight, Quaternion::IDENTITY, kf.getRotation(), mUseShortestRotationPath);
498
0
        }
499
0
        node->rotate(rotate);
500
501
0
        Vector3 scale = kf.getScale();
502
        // Not sure how to modify scale for cumulative anims... leave it alone
503
        //scale = ((Vector3::UNIT_SCALE - kf.getScale()) * weight) + Vector3::UNIT_SCALE;
504
0
        if (scale != Vector3::UNIT_SCALE)
505
0
        {
506
0
            if (scl != 1.0f)
507
0
                scale = Vector3::UNIT_SCALE + (scale - Vector3::UNIT_SCALE) * scl;
508
0
            else if (weight != 1.0f)
509
0
                scale = Vector3::UNIT_SCALE + (scale - Vector3::UNIT_SCALE) * weight;
510
0
        }
511
0
        node->scale(scale);
512
513
0
    }
514
    //---------------------------------------------------------------------
515
    void NodeAnimationTrack::buildInterpolationSplines(void) const
516
0
    {
517
        // Allocate splines if not exists
518
0
        if (!mSplines)
519
0
        {
520
0
            mSplines = OGRE_NEW_T(Splines, MEMCATEGORY_ANIMATION);
521
0
        }
522
523
        // Cache to register for optimisation
524
0
        Splines* splines = mSplines;
525
526
        // Don't calc automatically, do it on request at the end
527
0
        splines->positionSpline.setAutoCalculate(false);
528
0
        splines->rotationSpline.setAutoCalculate(false);
529
0
        splines->scaleSpline.setAutoCalculate(false);
530
531
0
        splines->positionSpline.clear();
532
0
        splines->rotationSpline.clear();
533
0
        splines->scaleSpline.clear();
534
535
0
        for (auto *f : mKeyFrames)
536
0
        {
537
0
            TransformKeyFrame* kf = static_cast<TransformKeyFrame*>(f);
538
0
            splines->positionSpline.addPoint(kf->getTranslate());
539
0
            splines->rotationSpline.addPoint(kf->getRotation());
540
0
            splines->scaleSpline.addPoint(kf->getScale());
541
0
        }
542
543
0
        splines->positionSpline.recalcTangents();
544
0
        splines->rotationSpline.recalcTangents();
545
0
        splines->scaleSpline.recalcTangents();
546
547
548
0
        mSplineBuildNeeded = false;
549
0
    }
550
551
    //---------------------------------------------------------------------
552
    void NodeAnimationTrack::setUseShortestRotationPath(bool useShortestPath)
553
0
    {
554
0
        mUseShortestRotationPath = useShortestPath ;
555
0
    }
556
557
    //---------------------------------------------------------------------
558
    bool NodeAnimationTrack::getUseShortestRotationPath() const
559
0
    {
560
0
        return mUseShortestRotationPath ;
561
0
    }
562
    //---------------------------------------------------------------------
563
    void NodeAnimationTrack::_keyFrameDataChanged(void) const
564
0
    {
565
0
        mSplineBuildNeeded = true;
566
0
    }
567
    //---------------------------------------------------------------------
568
    bool NodeAnimationTrack::hasNonZeroKeyFrames(void) const
569
0
    {
570
0
        for (auto *k : mKeyFrames)
571
0
        {
572
            // look for keyframes which have any component which is non-zero
573
            // Since exporters can be a little inaccurate sometimes we use a
574
            // tolerance value rather than looking for nothing
575
0
            TransformKeyFrame* kf = static_cast<TransformKeyFrame*>(k);
576
0
            Vector3 trans = kf->getTranslate();
577
0
            Vector3 scale = kf->getScale();
578
0
            Vector3 axis;
579
0
            Radian angle;
580
0
            kf->getRotation().ToAngleAxis(angle, axis);
581
0
            Real tolerance = 1e-3f;
582
0
            if (!trans.positionEquals(Vector3::ZERO, tolerance) ||
583
0
                !scale.positionEquals(Vector3::UNIT_SCALE, tolerance) ||
584
0
                !Math::RealEqual(angle.valueRadians(), 0.0f, tolerance))
585
0
            {
586
0
                return true;
587
0
            }
588
0
        }
589
590
0
        return false;
591
0
    }
592
    //---------------------------------------------------------------------
593
    void NodeAnimationTrack::optimise(void)
594
0
    {
595
        // Eliminate duplicate keyframes from 2nd to penultimate keyframe
596
        // NB only eliminate middle keys from sequences of 5+ identical keyframes
597
        // since we need to preserve the boundary keys in place, and we need
598
        // 2 at each end to preserve tangents for spline interpolation
599
0
        Vector3 lasttrans = Vector3::ZERO;
600
0
        Vector3 lastscale = Vector3::ZERO;
601
0
        Quaternion lastorientation;
602
0
        Radian quatTolerance(1e-3f);
603
0
        std::list<unsigned short> removeList;
604
0
        unsigned short k = 0;
605
0
        ushort dupKfCount = 0;
606
0
        for (auto *f : mKeyFrames)
607
0
        {
608
0
            auto kf = static_cast<TransformKeyFrame*>(f);
609
0
            Vector3 newtrans = kf->getTranslate();
610
0
            Vector3 newscale = kf->getScale();
611
0
            Quaternion neworientation = kf->getRotation();
612
            // Ignore first keyframe; now include the last keyframe as we eliminate
613
            // only k-2 in a group of 5 to ensure we only eliminate middle keys
614
0
            if (k && newtrans.positionEquals(lasttrans) &&
615
0
                newscale.positionEquals(lastscale) &&
616
0
                neworientation.equals(lastorientation, quatTolerance))
617
0
            {
618
0
                ++dupKfCount;
619
620
                // 4 indicates this is the 5th duplicate keyframe
621
0
                if (dupKfCount == 4)
622
0
                {
623
                    // remove the 'middle' keyframe
624
0
                    removeList.push_back(k-2);
625
0
                    --dupKfCount;
626
0
                }
627
0
            }
628
0
            else
629
0
            {
630
                // reset
631
0
                dupKfCount = 0;
632
0
                lasttrans = newtrans;
633
0
                lastscale = newscale;
634
0
                lastorientation = neworientation;
635
0
            }
636
0
            ++k;
637
0
        }
638
639
        // Now remove keyframes, in reverse order to avoid index revocation
640
0
        std::list<unsigned short>::reverse_iterator r = removeList.rbegin();
641
0
        for (; r!= removeList.rend(); ++r)
642
0
        {
643
0
            removeKeyFrame(*r);
644
0
        }
645
0
    }
646
    //--------------------------------------------------------------------------
647
    KeyFrame* NodeAnimationTrack::createKeyFrameImpl(Real time)
648
0
    {
649
0
        return OGRE_NEW TransformKeyFrame(this, time);
650
0
    }
651
    //--------------------------------------------------------------------------
652
    TransformKeyFrame* NodeAnimationTrack::createNodeKeyFrame(Real timePos)
653
0
    {
654
0
        return static_cast<TransformKeyFrame*>(createKeyFrame(timePos));
655
0
    }
656
    //--------------------------------------------------------------------------
657
    TransformKeyFrame* NodeAnimationTrack::getNodeKeyFrame(unsigned short index) const
658
0
    {
659
0
        return static_cast<TransformKeyFrame*>(getKeyFrame(index));
660
0
    }
661
    //---------------------------------------------------------------------
662
    NodeAnimationTrack* NodeAnimationTrack::_clone(Animation* newParent) const
663
0
    {
664
0
        NodeAnimationTrack* newTrack = 
665
0
            newParent->createNodeTrack(mHandle, mTargetNode);
666
0
        newTrack->mUseShortestRotationPath = mUseShortestRotationPath;
667
0
        populateClone(newTrack);
668
0
        return newTrack;
669
0
    }
670
    //--------------------------------------------------------------------------
671
    void NodeAnimationTrack::_applyBaseKeyFrame(const KeyFrame* b)
672
0
    {
673
0
        const TransformKeyFrame* base = static_cast<const TransformKeyFrame*>(b);
674
        
675
0
        for (auto& k : mKeyFrames)
676
0
        {
677
0
            TransformKeyFrame* kf = static_cast<TransformKeyFrame*>(k);
678
0
            kf->setTranslate(kf->getTranslate() - base->getTranslate());
679
0
            kf->setRotation(base->getRotation().Inverse() * kf->getRotation());
680
0
            kf->setScale(kf->getScale() * (Vector3::UNIT_SCALE / base->getScale()));
681
0
        }
682
            
683
0
    }
684
    //--------------------------------------------------------------------------
685
    VertexAnimationTrack::VertexAnimationTrack(Animation* parent,
686
        unsigned short handle, VertexAnimationType animType)
687
0
        : AnimationTrack(parent, handle)
688
0
        , mAnimationType(animType)
689
0
    {
690
0
    }
691
    //--------------------------------------------------------------------------
692
    VertexAnimationTrack::VertexAnimationTrack(Animation* parent, unsigned short handle,
693
        VertexAnimationType animType, VertexData* targetData, TargetMode target)
694
0
        : AnimationTrack(parent, handle)
695
0
        , mAnimationType(animType)
696
0
        , mTargetMode(target)
697
0
        , mTargetVertexData(targetData)
698
0
    {
699
0
    }
700
    //--------------------------------------------------------------------------
701
    VertexMorphKeyFrame* VertexAnimationTrack::createVertexMorphKeyFrame(Real timePos)
702
0
    {
703
0
        OgreAssert(mAnimationType == VAT_MORPH, "Type mismatch");
704
0
        return static_cast<VertexMorphKeyFrame*>(createKeyFrame(timePos));
705
0
    }
706
    //--------------------------------------------------------------------------
707
    VertexPoseKeyFrame* VertexAnimationTrack::createVertexPoseKeyFrame(Real timePos)
708
0
    {
709
0
        OgreAssert(mAnimationType == VAT_POSE, "Type mismatch");
710
0
        return static_cast<VertexPoseKeyFrame*>(createKeyFrame(timePos));
711
0
    }
712
    //--------------------------------------------------------------------------
713
    void VertexAnimationTrack::getInterpolatedKeyFrame(const TimeIndex& timeIndex, KeyFrame* kf) const
714
0
    {
715
        // Only relevant for pose animation
716
0
        if (mAnimationType == VAT_POSE)
717
0
        {
718
            // Get keyframes
719
0
            KeyFrame *kf1, *kf2;
720
0
            Real t = getKeyFramesAtTime(timeIndex, &kf1, &kf2);
721
            
722
0
            VertexPoseKeyFrame* vkfOut = static_cast<VertexPoseKeyFrame*>(kf);
723
0
            VertexPoseKeyFrame* vkf1 = static_cast<VertexPoseKeyFrame*>(kf1);
724
0
            VertexPoseKeyFrame* vkf2 = static_cast<VertexPoseKeyFrame*>(kf2);
725
            
726
            // For each pose reference in key 1, we need to locate the entry in
727
            // key 2 and interpolate the influence
728
0
            const VertexPoseKeyFrame::PoseRefList& poseList1 = vkf1->getPoseReferences();
729
0
            const VertexPoseKeyFrame::PoseRefList& poseList2 = vkf2->getPoseReferences();
730
0
            for (auto& p1 : poseList1)
731
0
            {
732
0
                Real startInfluence = p1.influence;
733
0
                Real endInfluence = 0;
734
                // Search for entry in keyframe 2 list (if not there, will be 0)
735
0
                for (auto& p2 : poseList2)
736
0
                {
737
0
                    if (p1.poseIndex == p2.poseIndex)
738
0
                    {
739
0
                        endInfluence = p2.influence;
740
0
                        break;
741
0
                    }
742
0
                }
743
                // Interpolate influence
744
0
                Real influence = startInfluence + t*(endInfluence - startInfluence);
745
                
746
0
                vkfOut->addPoseReference(p1.poseIndex, influence);
747
                
748
                
749
0
            }
750
            // Now deal with any poses in key 2 which are not in key 1
751
0
            for (auto& p2 : poseList2)
752
0
            {
753
0
                bool found = false;
754
0
                for (auto& p1 : poseList1)
755
0
                {
756
0
                    if (p1.poseIndex == p2.poseIndex)
757
0
                    {
758
0
                        found = true;
759
0
                        break;
760
0
                    }
761
0
                }
762
0
                if (!found)
763
0
                {
764
                    // Need to apply this pose too, scaled from 0 start
765
0
                    Real influence = t * p2.influence;
766
                    
767
0
                    vkfOut->addPoseReference(p2.poseIndex, influence);
768
769
0
                }
770
0
            } // key 2 iteration
771
            
772
0
        }           
773
0
    }
774
    //--------------------------------------------------------------------------
775
    bool VertexAnimationTrack::getVertexAnimationIncludesNormals() const
776
0
    {
777
0
        if (mAnimationType == VAT_NONE)
778
0
            return false;
779
        
780
0
        if (mAnimationType == VAT_MORPH)
781
0
        {
782
0
            bool normals = false;
783
0
            for (KeyFrameList::const_iterator i = mKeyFrames.begin(); i != mKeyFrames.end(); ++i)
784
0
            {
785
0
                VertexMorphKeyFrame* kf = static_cast<VertexMorphKeyFrame*>(*i);
786
0
                bool thisnorm = kf->getVertexBuffer()->getVertexSize() > 12;
787
0
                if (i == mKeyFrames.begin())
788
0
                    normals = thisnorm;
789
0
                else
790
                    // Only support normals if ALL keyframes include them
791
0
                    normals = normals && thisnorm;
792
793
0
            }
794
0
            return normals;
795
0
        }
796
0
        else 
797
0
        {
798
            // needs to derive from Mesh::PoseList, can't tell here
799
0
            return false;
800
0
        }
801
0
    }
802
    //--------------------------------------------------------------------------
803
    void VertexAnimationTrack::apply(const TimeIndex& timeIndex, Real weight, Real scale)
804
0
    {
805
0
        applyToVertexData(mTargetVertexData, timeIndex, weight);
806
0
    }
807
    //--------------------------------------------------------------------------
808
    void VertexAnimationTrack::applyToVertexData(VertexData* data,
809
        const TimeIndex& timeIndex, float weight, const PoseList* poseList)
810
0
    {
811
        // Nothing to do if no keyframes or no vertex data
812
0
        if (mKeyFrames.empty() || !data)
813
0
            return;
814
815
        // Get keyframes
816
0
        KeyFrame *kf1, *kf2;
817
0
        float t = getKeyFramesAtTime(timeIndex, &kf1, &kf2);
818
819
0
        if (mAnimationType == VAT_MORPH)
820
0
        {
821
0
            VertexMorphKeyFrame* vkf1 = static_cast<VertexMorphKeyFrame*>(kf1);
822
0
            VertexMorphKeyFrame* vkf2 = static_cast<VertexMorphKeyFrame*>(kf2);
823
824
0
            if (mTargetMode == TM_HARDWARE)
825
0
            {
826
                // If target mode is hardware, need to bind our 2 keyframe buffers,
827
                // one to main pos, one to morph target texcoord
828
0
                assert(!data->hwAnimationDataList.empty() &&
829
0
                    "Haven't set up hardware vertex animation elements!");
830
831
                // no use for TempBlendedBufferInfo here btw
832
                // NB we assume that position buffer is unshared, except for normals
833
                // VertexDeclaration::getAutoOrganisedDeclaration should see to that
834
0
                const VertexElement* posElem =
835
0
                    data->vertexDeclaration->findElementBySemantic(VES_POSITION);
836
                // Set keyframe1 data as original position
837
0
                data->vertexBufferBinding->setBinding(
838
0
                    posElem->getSource(), vkf1->getVertexBuffer());
839
                // Set keyframe2 data as derived
840
0
                data->vertexBufferBinding->setBinding(
841
0
                    data->hwAnimationDataList[0].targetBufferIndex,
842
0
                    vkf2->getVertexBuffer());
843
                // save T for use later
844
0
                data->hwAnimationDataList[0].parametric = t;
845
846
0
            }
847
0
            else
848
0
            {
849
                // If target mode is software, need to software interpolate each vertex
850
0
                Mesh::softwareVertexMorph(
851
0
                    t, vkf1->getVertexBuffer(), vkf2->getVertexBuffer(), data);
852
0
            }
853
0
        }
854
0
        else
855
0
        {
856
            // Pose
857
0
            OgreAssert(poseList, "Pose list required for pose animation");
858
0
            VertexPoseKeyFrame* vkf1 = static_cast<VertexPoseKeyFrame*>(kf1);
859
0
            VertexPoseKeyFrame* vkf2 = static_cast<VertexPoseKeyFrame*>(kf2);
860
            // For each pose reference in key 1, we need to locate the entry in
861
            // key 2 and interpolate the influence
862
0
            const VertexPoseKeyFrame::PoseRefList& poseList1 = vkf1->getPoseReferences();
863
0
            const VertexPoseKeyFrame::PoseRefList& poseList2 = vkf2->getPoseReferences();
864
0
            for (auto& p1 : poseList1)
865
0
            {
866
0
                float startInfluence = p1.influence;
867
0
                float endInfluence = 0;
868
                // Search for entry in keyframe 2 list (if not there, will be 0)
869
0
                for (auto& p2 : poseList2)
870
0
                {
871
0
                    if (p1.poseIndex == p2.poseIndex)
872
0
                    {
873
0
                        endInfluence = p2.influence;
874
0
                        break;
875
0
                    }
876
0
                }
877
                // Interpolate influence
878
0
                float influence = startInfluence + t*(endInfluence - startInfluence);
879
                // Scale by animation weight
880
0
                influence = weight * influence;
881
                // Get pose
882
0
                assert (p1.poseIndex < poseList->size());
883
0
                Pose* pose = (*poseList)[p1.poseIndex];
884
                // apply
885
0
                applyPoseToVertexData(pose, data, influence);
886
0
            }
887
            // Now deal with any poses in key 2 which are not in key 1
888
0
            for (auto& p2 : poseList2)
889
0
            {
890
0
                bool found = false;
891
0
                for (auto& p1 : poseList1)
892
0
                {
893
0
                    if (p1.poseIndex == p2.poseIndex)
894
0
                    {
895
0
                        found = true;
896
0
                        break;
897
0
                    }
898
0
                }
899
0
                if (!found)
900
0
                {
901
                    // Need to apply this pose too, scaled from 0 start
902
0
                    float influence = t * p2.influence;
903
                    // Scale by animation weight
904
0
                    influence = weight * influence;
905
                    // Get pose
906
0
                    assert (p2.poseIndex < poseList->size());
907
0
                    const Pose* pose = (*poseList)[p2.poseIndex];
908
                    // apply
909
0
                    applyPoseToVertexData(pose, data, influence);
910
0
                }
911
0
            } // key 2 iteration
912
0
        } // morph or pose animation
913
0
    }
914
    //-----------------------------------------------------------------------------
915
    void VertexAnimationTrack::applyPoseToVertexData(const Pose* pose,
916
        VertexData* data, float influence)
917
0
    {
918
0
        if (mTargetMode == TM_HARDWARE)
919
0
        {
920
            // Hardware
921
            // If target mode is hardware, need to bind our pose buffer
922
            // to a target texcoord
923
0
            assert(!data->hwAnimationDataList.empty() &&
924
0
                "Haven't set up hardware vertex animation elements!");
925
            // no use for TempBlendedBufferInfo here btw
926
            // Set pose target as required
927
0
            size_t hwIndex = data->hwAnimDataItemsUsed++;
928
            // If we try to use too many poses, ignore extras
929
0
            if (hwIndex < data->hwAnimationDataList.size())
930
0
            {
931
0
                VertexData::HardwareAnimationData& animData = data->hwAnimationDataList[hwIndex];
932
0
                data->vertexBufferBinding->setBinding(
933
0
                    animData.targetBufferIndex,
934
0
                    pose->_getHardwareVertexBuffer(data));
935
                // save final influence in parametric
936
0
                animData.parametric = influence;
937
938
0
            }
939
0
        }
940
0
        else
941
0
        {
942
            // Software
943
0
            Mesh::softwareVertexPoseBlend(influence, pose->getVertexOffsets(), pose->getNormals(), data);
944
0
        }
945
946
0
    }
947
    //--------------------------------------------------------------------------
948
    VertexMorphKeyFrame* VertexAnimationTrack::getVertexMorphKeyFrame(unsigned short index) const
949
0
    {
950
0
        OgreAssert(mAnimationType == VAT_MORPH, "Type mismatch");
951
0
        return static_cast<VertexMorphKeyFrame*>(getKeyFrame(index));
952
0
    }
953
    //--------------------------------------------------------------------------
954
    VertexPoseKeyFrame* VertexAnimationTrack::getVertexPoseKeyFrame(unsigned short index) const
955
0
    {
956
0
        OgreAssert(mAnimationType == VAT_POSE, "Type mismatch");
957
0
        return static_cast<VertexPoseKeyFrame*>(getKeyFrame(index));
958
0
    }
959
    //--------------------------------------------------------------------------
960
    KeyFrame* VertexAnimationTrack::createKeyFrameImpl(Real time)
961
0
    {
962
0
        switch(mAnimationType)
963
0
        {
964
0
        default:
965
0
        case VAT_MORPH:
966
0
            return OGRE_NEW VertexMorphKeyFrame(this, time);
967
0
        case VAT_POSE:
968
0
            return OGRE_NEW VertexPoseKeyFrame(this, time);
969
0
        };
970
971
0
    }
972
    //---------------------------------------------------------------------
973
    bool VertexAnimationTrack::hasNonZeroKeyFrames(void) const
974
0
    {
975
0
        if (mAnimationType == VAT_MORPH)
976
0
        {
977
0
            return !mKeyFrames.empty();
978
0
        }
979
0
        else
980
0
        {
981
0
            for (auto kf : mKeyFrames)
982
0
            {
983
                // look for keyframes which have a pose influence which is non-zero
984
0
                auto& poses = static_cast<const VertexPoseKeyFrame *>(kf)->getPoseReferences();
985
0
                for (auto& poseIt : poses)
986
0
                {
987
0
                    if (poseIt.influence > 0.0f)
988
0
                        return true;
989
0
                }
990
0
            }
991
992
0
            return false;
993
0
        }
994
0
    }
995
    //---------------------------------------------------------------------
996
    void VertexAnimationTrack::optimise(void)
997
0
    {
998
        // TODO - remove sequences of duplicate pose references?
999
1000
0
    }
1001
    //---------------------------------------------------------------------
1002
    VertexAnimationTrack* VertexAnimationTrack::_clone(Animation* newParent) const
1003
0
    {
1004
0
        VertexAnimationTrack* newTrack = 
1005
0
            newParent->createVertexTrack(mHandle, mAnimationType);
1006
0
        newTrack->mTargetMode = mTargetMode;
1007
0
        populateClone(newTrack);
1008
0
        return newTrack;
1009
0
    }   
1010
    //--------------------------------------------------------------------------
1011
    void VertexAnimationTrack::_applyBaseKeyFrame(const KeyFrame* b)
1012
0
    {
1013
0
        const VertexPoseKeyFrame* base = static_cast<const VertexPoseKeyFrame*>(b);
1014
        
1015
0
        for (auto& k : mKeyFrames)
1016
0
        {
1017
0
            VertexPoseKeyFrame* kf = static_cast<VertexPoseKeyFrame*>(k);
1018
            
1019
0
            kf->_applyBaseKeyFrame(base);
1020
0
        }
1021
0
    }
1022
}