Coverage Report

Created: 2025-08-25 06:48

/src/ogre/OgreMain/src/OgreAnimationState.cpp
Line
Count
Source (jump to first uncovered line)
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 "OgreAnimationState.h"
30
31
32
namespace Ogre 
33
{
34
35
    //---------------------------------------------------------------------
36
    AnimationState::AnimationState(AnimationStateSet* parent, const AnimationState &rhs)
37
0
        : mAnimationName(rhs.mAnimationName)
38
0
        , mParent(parent)
39
0
        , mTimePos(rhs.mTimePos)
40
0
        , mLength(rhs.mLength)
41
0
        , mWeight(rhs.mWeight)
42
0
        , mEnabled(rhs.mEnabled)
43
0
        , mLoop(rhs.mLoop)
44
0
  {
45
0
        mParent->_notifyDirty();
46
0
    }
47
    //---------------------------------------------------------------------
48
    AnimationState::AnimationState(const String& animName, 
49
        AnimationStateSet *parent, Real timePos, Real length, Real weight, 
50
        bool enabled)
51
0
        : mAnimationName(animName)
52
0
        , mParent(parent)
53
0
        , mTimePos(timePos)
54
0
        , mLength(length)
55
0
        , mWeight(weight)
56
0
        , mEnabled(enabled)
57
0
        , mLoop(true)
58
0
    {
59
0
        mParent->_notifyDirty();
60
0
    }
61
    //---------------------------------------------------------------------
62
    const String& AnimationState::getAnimationName() const
63
0
    {
64
0
        return mAnimationName;
65
0
    }
66
    //---------------------------------------------------------------------
67
    Real AnimationState::getTimePosition(void) const
68
0
    {
69
0
        return mTimePos;
70
0
    }
71
    //---------------------------------------------------------------------
72
    void AnimationState::setTimePosition(Real timePos)
73
0
    {
74
0
        if (timePos != mTimePos)
75
0
        {
76
0
            mTimePos = timePos;
77
0
            if (mLoop)
78
0
            {
79
                // Wrap
80
0
                mTimePos = std::fmod(mTimePos, mLength);
81
0
                if(mTimePos < 0) mTimePos += mLength;
82
0
            }
83
0
            else
84
0
            {
85
                // Clamp
86
0
                mTimePos = Math::Clamp(mTimePos, Real(0), mLength);
87
0
            }
88
89
0
            if (mEnabled)
90
0
                mParent->_notifyDirty();
91
0
        }
92
93
0
    }
94
    //---------------------------------------------------------------------
95
    Real AnimationState::getLength() const
96
0
    {
97
0
        return mLength;
98
0
    }
99
    //---------------------------------------------------------------------
100
    void AnimationState::setLength(Real len)
101
0
    {
102
0
        mLength = len;
103
0
    }
104
    //---------------------------------------------------------------------
105
    Real AnimationState::getWeight(void) const
106
0
    {
107
0
        return mWeight;
108
0
    }
109
    //---------------------------------------------------------------------
110
    void AnimationState::setWeight(Real weight)
111
0
    {
112
0
        mWeight = weight;
113
114
0
        if (mEnabled)
115
0
            mParent->_notifyDirty();
116
0
    }
117
    //---------------------------------------------------------------------
118
    void AnimationState::addTime(Real offset)
119
0
    {
120
0
        setTimePosition(mTimePos + offset);
121
0
    }
122
    //---------------------------------------------------------------------
123
    bool AnimationState::hasEnded(void) const
124
0
    {
125
0
        return (mTimePos >= mLength && !mLoop);
126
0
    }
127
    //---------------------------------------------------------------------
128
    bool AnimationState::getEnabled(void) const
129
0
    {
130
0
        return mEnabled;
131
0
    }
132
    //---------------------------------------------------------------------
133
    void AnimationState::setEnabled(bool enabled)
134
0
    {
135
0
        mEnabled = enabled;
136
0
        mParent->_notifyAnimationStateEnabled(this, enabled);
137
0
    }
138
    //---------------------------------------------------------------------
139
    bool AnimationState::operator==(const AnimationState& rhs) const
140
0
    {
141
0
        if (mAnimationName == rhs.mAnimationName &&
142
0
            mEnabled == rhs.mEnabled &&
143
0
            mTimePos == rhs.mTimePos &&
144
0
            mWeight == rhs.mWeight &&
145
0
            mLength == rhs.mLength && 
146
0
            mLoop == rhs.mLoop)
147
0
        {
148
0
            return true;
149
0
        }
150
0
        else
151
0
        {
152
0
            return false;
153
0
        }
154
0
    }
155
    //---------------------------------------------------------------------
156
    bool AnimationState::operator!=(const AnimationState& rhs) const
157
0
    {
158
0
        return !(*this == rhs);
159
0
    }
160
    //---------------------------------------------------------------------
161
    void AnimationState::copyStateFrom(const AnimationState& animState)
162
0
    {
163
0
        mTimePos = animState.mTimePos;
164
0
        mLength = animState.mLength;
165
0
        mWeight = animState.mWeight;
166
0
        mEnabled = animState.mEnabled;
167
0
        mLoop = animState.mLoop;
168
0
        mParent->_notifyDirty();
169
170
0
    }
171
    //---------------------------------------------------------------------
172
    void AnimationState::setBlendMaskEntry(size_t boneHandle, float weight)
173
0
    {
174
0
        assert(mBlendMask.size() > boneHandle);
175
0
        mBlendMask[boneHandle] = weight;
176
0
        if (mEnabled)
177
0
            mParent->_notifyDirty();
178
0
    }
179
    //---------------------------------------------------------------------
180
    void AnimationState::_setBlendMaskData(const float* blendMaskData) 
181
0
    {
182
0
        assert(!mBlendMask.empty() && "No BlendMask set!");
183
        // input 0?
184
0
        if(!blendMaskData)
185
0
        {
186
0
            destroyBlendMask();
187
0
            return;
188
0
        }
189
        // dangerous memcpy
190
0
        memcpy(mBlendMask.data(), blendMaskData, sizeof(float) * mBlendMask.size());
191
0
        if (mEnabled)
192
0
            mParent->_notifyDirty();
193
0
    }
194
    //---------------------------------------------------------------------
195
    void AnimationState::_setBlendMask(const BoneBlendMask* blendMask) 
196
0
    {
197
0
        if(mBlendMask.empty())
198
0
        {
199
0
            createBlendMask(blendMask->size(), false);
200
0
        }
201
0
        _setBlendMaskData(blendMask->data());
202
0
    }
203
    //---------------------------------------------------------------------
204
    void AnimationState::createBlendMask(size_t blendMaskSizeHint, float initialWeight)
205
0
    {
206
0
        if(mBlendMask.empty())
207
0
        {
208
0
            if(initialWeight >= 0)
209
0
            {
210
0
                mBlendMask.resize(blendMaskSizeHint, initialWeight);
211
0
            }
212
0
            else
213
0
            {
214
0
                mBlendMask.resize(blendMaskSizeHint);
215
0
            }
216
0
        }
217
0
    }
218
    //---------------------------------------------------------------------
219
    void AnimationState::destroyBlendMask()
220
0
    {
221
0
        mBlendMask.clear();
222
0
        mBlendMask.shrink_to_fit();
223
0
    }
224
    //---------------------------------------------------------------------
225
226
    //---------------------------------------------------------------------
227
    AnimationStateSet::AnimationStateSet()
228
0
        : mDirtyFrameNumber(std::numeric_limits<unsigned long>::max())
229
0
    {
230
0
    }
231
    //---------------------------------------------------------------------
232
    AnimationStateSet::AnimationStateSet(const AnimationStateSet& rhs)
233
0
        : mDirtyFrameNumber(std::numeric_limits<unsigned long>::max())
234
0
    {
235
        // lock rhs
236
0
            OGRE_LOCK_MUTEX(rhs.OGRE_AUTO_MUTEX_NAME);
237
238
0
        for (const auto & mAnimationState : rhs.mAnimationStates)
239
0
        {
240
0
            AnimationState* src = mAnimationState.second;
241
0
            mAnimationStates[src->getAnimationName()] = OGRE_NEW AnimationState(this, *src);
242
0
        }
243
244
        // Clone enabled animation state list
245
0
        for (auto src : rhs.mEnabledAnimationStates)
246
0
        {
247
0
            mEnabledAnimationStates.push_back(getAnimationState(src->getAnimationName()));
248
0
        }
249
0
    }
250
    //---------------------------------------------------------------------
251
    AnimationStateSet::~AnimationStateSet()
252
0
    {
253
        // Destroy
254
0
        removeAllAnimationStates();
255
0
    }
256
    //---------------------------------------------------------------------
257
    void AnimationStateSet::removeAnimationState(const String& name)
258
0
    {
259
0
            OGRE_LOCK_AUTO_MUTEX;
260
261
0
        AnimationStateMap::iterator i = mAnimationStates.find(name);
262
0
        if (i != mAnimationStates.end())
263
0
        {
264
0
            mEnabledAnimationStates.remove(i->second);
265
266
0
            OGRE_DELETE i->second;
267
0
            mAnimationStates.erase(i);
268
0
        }
269
0
    }
270
    //---------------------------------------------------------------------
271
    void AnimationStateSet::removeAllAnimationStates(void)
272
0
    {
273
0
            OGRE_LOCK_AUTO_MUTEX;
274
275
0
        for (auto & mAnimationState : mAnimationStates)
276
0
        {
277
0
            OGRE_DELETE mAnimationState.second;
278
0
        }
279
0
        mAnimationStates.clear();
280
0
        mEnabledAnimationStates.clear();
281
0
    }
282
    //---------------------------------------------------------------------
283
    AnimationState* AnimationStateSet::createAnimationState(const String& name,  
284
        Real timePos, Real length, Real weight, bool enabled)
285
0
    {
286
0
            OGRE_LOCK_AUTO_MUTEX;
287
288
0
        AnimationStateMap::iterator i = mAnimationStates.find(name);
289
0
        if (i != mAnimationStates.end())
290
0
        {
291
0
            OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM, 
292
0
                "State for animation named '" + name + "' already exists.", 
293
0
                "AnimationStateSet::createAnimationState");
294
0
        }
295
296
0
        AnimationState* newState = OGRE_NEW AnimationState(name, this, timePos, 
297
0
            length, weight, enabled);
298
0
        mAnimationStates[name] = newState;
299
0
        return newState;
300
301
0
    }
302
    //---------------------------------------------------------------------
303
    AnimationState* AnimationStateSet::getAnimationState(const String& name) const
304
0
    {
305
0
            OGRE_LOCK_AUTO_MUTEX;
306
307
0
        AnimationStateMap::const_iterator i = mAnimationStates.find(name);
308
0
        if (i == mAnimationStates.end())
309
0
        {
310
0
            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
311
0
                "No state found for animation named '" + name + "'", 
312
0
                "AnimationStateSet::getAnimationState");
313
0
        }
314
0
        return i->second;
315
0
    }
316
    //---------------------------------------------------------------------
317
    bool AnimationStateSet::hasAnimationState(const String& name) const
318
0
    {
319
0
            OGRE_LOCK_AUTO_MUTEX;
320
321
0
        return mAnimationStates.find(name) != mAnimationStates.end();
322
0
    }
323
    //---------------------------------------------------------------------
324
    AnimationStateIterator AnimationStateSet::getAnimationStateIterator(void)
325
0
    {
326
0
            OGRE_LOCK_AUTO_MUTEX;
327
        // returned iterator not threadsafe, noted in header
328
0
        return AnimationStateIterator(
329
0
            mAnimationStates.begin(), mAnimationStates.end());
330
0
    }
331
    //---------------------------------------------------------------------
332
    ConstAnimationStateIterator AnimationStateSet::getAnimationStateIterator(void) const
333
0
    {
334
0
            OGRE_LOCK_AUTO_MUTEX;
335
        // returned iterator not threadsafe, noted in header
336
0
        return ConstAnimationStateIterator(
337
0
            mAnimationStates.begin(), mAnimationStates.end());
338
0
    }
339
    //---------------------------------------------------------------------
340
    void AnimationStateSet::copyMatchingState(AnimationStateSet* target) const
341
0
    {
342
        // lock target
343
0
        OGRE_LOCK_MUTEX(target->OGRE_AUTO_MUTEX_NAME);
344
        // lock source
345
0
        OGRE_LOCK_AUTO_MUTEX;
346
347
0
        for (auto& t : target->mAnimationStates) {
348
0
            AnimationStateMap::const_iterator iother = mAnimationStates.find(t.first);
349
0
            if (iother == mAnimationStates.end()) {
350
0
                OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "No animation entry found named " + t.first,
351
0
                    "AnimationStateSet::copyMatchingState");
352
0
            } else {
353
0
                t.second->copyStateFrom(*(iother->second));
354
0
            }
355
0
        }
356
357
        // Copy matching enabled animation state list
358
0
        target->mEnabledAnimationStates.clear();
359
360
0
        for (auto *src : mEnabledAnimationStates)
361
0
        {
362
0
            AnimationStateMap::const_iterator itarget = target->mAnimationStates.find(src->getAnimationName());
363
0
            if (itarget != target->mAnimationStates.end())
364
0
            {
365
0
                target->mEnabledAnimationStates.push_back(itarget->second);
366
0
            }
367
0
        }
368
369
0
        target->mDirtyFrameNumber = mDirtyFrameNumber;
370
0
    }
371
    //---------------------------------------------------------------------
372
    void AnimationStateSet::_notifyDirty(void)
373
0
    {
374
0
        OGRE_LOCK_AUTO_MUTEX;
375
0
        ++mDirtyFrameNumber;
376
0
    }
377
    //---------------------------------------------------------------------
378
    void AnimationStateSet::_notifyAnimationStateEnabled(AnimationState* target, bool enabled)
379
0
    {
380
0
        OGRE_LOCK_AUTO_MUTEX;
381
        // Remove from enabled animation state list first
382
0
        mEnabledAnimationStates.remove(target);
383
384
        // Add to enabled animation state list if need
385
0
        if (enabled)
386
0
        {
387
0
            mEnabledAnimationStates.push_back(target);
388
0
        }
389
390
        // Set the dirty frame number
391
0
        _notifyDirty();
392
0
    }
393
    //---------------------------------------------------------------------
394
    ConstEnabledAnimationStateIterator AnimationStateSet::getEnabledAnimationStateIterator(void) const
395
0
    {
396
0
        OGRE_LOCK_AUTO_MUTEX;
397
        // returned iterator not threadsafe, noted in header
398
0
        return ConstEnabledAnimationStateIterator(
399
0
            mEnabledAnimationStates.begin(), mEnabledAnimationStates.end());
400
0
    }
401
402
    ControllerValueRealPtr AnimationStateControllerValue::create(AnimationState* targetAnimationState, bool addTime)
403
0
    {
404
0
        return std::make_shared<AnimationStateControllerValue>(targetAnimationState, addTime);
405
0
    }
406
}
407