GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/resources/sprite/animatedsprite.cpp Lines: 82 198 41.4 %
Date: 2017-11-29 Branches: 53 182 29.1 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2004-2009  The Mana World Development Team
4
 *  Copyright (C) 2009-2010  The Mana Developers
5
 *  Copyright (C) 2011-2017  The ManaPlus Developers
6
 *
7
 *  This file is part of The ManaPlus Client.
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or
12
 *  any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
#include "resources/sprite/animatedsprite.h"
24
25
#include "const/resources/spriteaction.h"
26
27
#include "render/graphics.h"
28
29
#include "resources/action.h"
30
#include "resources/delayedmanager.h"
31
32
#include "resources/animation/animation.h"
33
34
#include "resources/image/image.h"
35
36
#include "resources/loaders/spritedefloader.h"
37
38
#include "resources/resourcemanager/resourcemanager.h"
39
40
#include "resources/sprite/animationdelayload.h"
41
42
#include "utils/delete2.h"
43
#include "utils/likely.h"
44
#include "utils/mrand.h"
45
46
#include "debug.h"
47
48
bool AnimatedSprite::mEnableCache = false;
49
50
2310
AnimatedSprite::AnimatedSprite(SpriteDef *restrict const sprite) :
51
    mDirection(SpriteDirection::DOWN),
52
    mLastTime(0),
53
    mFrameIndex(0),
54
    mFrameTime(0),
55
    mSprite(sprite),
56
    mAction(nullptr),
57
    mAnimation(nullptr),
58
    mFrame(nullptr),
59
    mNumber(100),
60
    mNumber1(100),
61
    mDelayLoad(nullptr),
62
4620
    mTerminated(false)
63
{
64
2310
    mAlpha = 1.0F;
65
66
    // Take possession of the sprite
67
    if (mSprite != nullptr)
68

2310
        mSprite->incRef();
69
}
70
71
2310
AnimatedSprite *AnimatedSprite::load(const std::string &restrict filename,
72
                                     const int variant)
73
{
74
    SpriteDef *restrict const s = Loader::getSprite(
75
2310
        filename, variant);
76
2310
    if (s == nullptr)
77
        return nullptr;
78
4620
    AnimatedSprite *restrict const as = new AnimatedSprite(s);
79
#ifdef DEBUG_ANIMATIONS
80
    as->setSpriteName(filename);
81
#endif  // DEBUG_ANIMATIONS
82
83
2310
    as->play(SpriteAction::STAND);
84
2310
    s->decRef();
85
2310
    return as;
86
}
87
88
AnimatedSprite *AnimatedSprite::delayedLoad(const std::string &restrict
89
                                            filename,
90
                                            const int variant)
91
{
92
    if (!mEnableCache)
93
        return load(filename, variant);
94
    Resource *restrict const res = ResourceManager::getFromCache(
95
        filename, variant);
96
    if (res != nullptr)
97
    {
98
        res->decRef();
99
        return load(filename, variant);
100
    }
101
102
    AnimatedSprite *restrict const as = new AnimatedSprite(nullptr);
103
#ifdef DEBUG_ANIMATIONS
104
    as->setSpriteName(filename);
105
#endif  // DEBUG_ANIMATIONS
106
107
    as->play(SpriteAction::STAND);
108
    as->setDelayLoad(filename, variant);
109
    return as;
110
}
111
112
AnimatedSprite *AnimatedSprite::clone(const AnimatedSprite *restrict const
113
                                      anim)
114
{
115
    if (anim == nullptr)
116
        return nullptr;
117
    AnimatedSprite *restrict const sprite = new AnimatedSprite(anim->mSprite);
118
#ifdef DEBUG_ANIMATIONS
119
    sprite->setSpriteName(anim->getSpriteName());
120
#endif  // DEBUG_ANIMATIONS
121
122
    sprite->play(SpriteAction::STAND);
123
    return sprite;
124
}
125
126
6930
AnimatedSprite::~AnimatedSprite()
127
{
128
2310
    if (mSprite != nullptr)
129
    {
130
2310
        mSprite->decRef();
131
2310
        mSprite = nullptr;
132
    }
133
2310
    if (mDelayLoad != nullptr)
134
    {
135
        mDelayLoad->clearSprite();
136
        DelayedManager::removeDelayLoad(mDelayLoad);
137
        delete2(mDelayLoad);
138
    }
139
4620
}
140
141
bool AnimatedSprite::reset() restrict2
142
{
143
2312
    const bool ret = mFrameIndex !=0 ||
144
        mFrameTime != 0 ||
145
        mLastTime != 0;
146
147
2312
    mFrameIndex = 0;
148
2312
    mFrameTime = 0;
149
2312
    mLastTime = 0;
150
151
    if (mAnimation != nullptr)
152
2312
        mFrame = &mAnimation->mFrames[0];
153
    else
154
        mFrame = nullptr;
155
    return ret;
156
}
157
158
2316
bool AnimatedSprite::play(const std::string &restrict spriteAction) restrict2
159
{
160
2316
    if (mSprite == nullptr)
161
    {
162
        if (mDelayLoad == nullptr)
163
            return false;
164
        mDelayLoad->setAction(spriteAction);
165
        return true;
166
    }
167
168
2316
    const Action *const action = mSprite->getAction(spriteAction, mNumber);
169
2316
    if (action == nullptr)
170
        return false;
171
172
2316
    mAction = action;
173
2316
    const Animation *const animation = mAction->getAnimation(mDirection);
174
175
2316
    if ((animation != nullptr) &&
176

4628
        animation != mAnimation &&
177
2312
        animation->getLength() > 0)
178
    {
179
2312
        mAnimation = animation;
180
2312
        reset();
181
182
2312
        return true;
183
    }
184
185
    return false;
186
}
187
188
32
bool AnimatedSprite::update(const int time) restrict2
189
{
190
    // Avoid freaking out at first frame or when tick_time overflows
191

32
    if (A_UNLIKELY(time < mLastTime || mLastTime == 0))
192
6
        mLastTime = time;
193
194
    // If not enough time has passed yet, do nothing
195

32
    if (time <= mLastTime || (mAnimation == nullptr))
196
        return false;
197
198
24
    const unsigned int dt = time - mLastTime;
199
24
    mLastTime = time;
200
201
24
    const Animation *restrict const animation = mAnimation;
202
24
    const Frame *restrict const frame = mFrame;
203
204
24
    if (A_UNLIKELY(!updateCurrentAnimation(dt)))
205
    {
206
        // Animation finished, reset to default
207
        play(SpriteAction::STAND);
208
        mTerminated = true;
209
    }
210
211
    // Make sure something actually changed
212

24
    return animation != mAnimation || frame != mFrame;
213
}
214
215
24
bool AnimatedSprite::updateCurrentAnimation(const unsigned int time) restrict2
216
{
217
    // move code from Animation::isTerminator(*mFrame)
218

48
    if (mFrame == nullptr ||
219
48
        mAnimation == nullptr ||
220
24
        (mFrame->image == nullptr && mFrame->type == FrameType::ANIMATION))
221
    {
222
        return false;
223
    }
224
225
24
    mFrameTime += time;
226
227
70
    while ((mFrameTime > CAST_U32(mFrame->delay) &&
228

76
           mFrame->delay > 0) ||
229
30
           (mFrame->type != FrameType::ANIMATION &&
230
           mFrame->type != FrameType::PAUSE))
231
    {
232
22
        bool fail(true);
233
22
        mFrameTime -= CAST_U32(mFrame->delay);
234
22
        mFrameIndex++;
235
236
44
        if (mFrameIndex >= CAST_U32(mAnimation->getLength()))
237
            mFrameIndex = 0;
238
239
44
        mFrame = &mAnimation->mFrames[mFrameIndex];
240

24
        if (mFrame->type == FrameType::LABEL &&
241
4
            !mFrame->nextAction.empty())
242
        {
243
            fail = false;
244
        }
245

24
        else if (mFrame->type == FrameType::GOTO &&
246
8
                 !mFrame->nextAction.empty())
247
        {
248
4
            const int rand = mFrame->rand;
249

4
            if (rand == 100 ||
250
                ((rand != 0) && rand >= mrand() % 100))
251
            {
252
22
                for (size_t i = 0; i < mAnimation->getLength(); i ++)
253
                {
254
                    const Frame *restrict const frame =
255
16
                        &mAnimation->mFrames[i];
256
8
                    if (frame->type == FrameType::LABEL &&
257
4
                        mFrame->nextAction == frame->nextAction)
258
                    {
259
2
                        mFrameIndex = CAST_U32(i);
260
2
                        if (mFrameIndex >= CAST_U32(
261
4
                            mAnimation->getLength()))
262
                        {
263
                            mFrameIndex = 0;
264
                        }
265
266
4
                        mFrame = &mAnimation->mFrames[mFrameIndex];
267
268
2
                        fail = false;
269
                        break;
270
                    }
271
                }
272
            }
273
            else
274
            {
275
                fail = false;
276
            }
277
        }
278

16
        else if (mFrame->type == FrameType::JUMP &&
279
                 !mFrame->nextAction.empty())
280
        {
281
            const int rand = mFrame->rand;
282
            if (rand == 100 ||
283
                ((rand != 0) && rand >= mrand() % 100))
284
            {
285
                play(mFrame->nextAction);
286
                return true;
287
            }
288
        }
289
        // copy code from Animation::isTerminator(*mFrame)
290

16
        else if ((mFrame->image == nullptr) &&
291
                 mFrame->type == FrameType::ANIMATION)
292
        {
293
            const int rand = mFrame->rand;
294
            if (rand == 100 ||
295
                ((rand != 0) && rand >= mrand() % 100))
296
            {
297
                mAnimation = nullptr;
298
                mFrame = nullptr;
299
                return false;
300
            }
301
        }
302
        else
303
        {
304
16
            const int rand = mFrame->rand;
305

18
            if (rand == 100 ||
306
4
                mFrameIndex >= CAST_U32(mAnimation->getLength()))
307
            {
308
                fail = false;
309
            }
310
            else
311
            {
312

2
                if ((rand != 0) && mrand() % 100 <= rand)
313
                    fail = false;
314
            }
315
        }
316
2
        if (fail)
317
        {
318
2
            if (mFrame != nullptr)
319
2
                mFrameTime = mFrame->delay + 1;
320
            else
321
                mFrameTime ++;
322
        }
323
    }
324
    return true;
325
}
326
327
void AnimatedSprite::draw(Graphics *restrict const graphics,
328
                          const int posX,
329
                          const int posY) const restrict2
330
{
331
    FUNC_BLOCK("AnimatedSprite::draw", 1)
332
    if ((mFrame == nullptr) || (mFrame->image == nullptr))
333
        return;
334
335
    Image *restrict const image = mFrame->image;
336
    image->setAlpha(mAlpha);
337
    graphics->drawImage(image,
338
        posX + mFrame->offsetX, posY + mFrame->offsetY);
339
}
340
341
void AnimatedSprite::drawRescaled(Graphics *restrict const graphics,
342
                                  const int posX,
343
                                  const int posY,
344
                                  const int dx,
345
                                  const int dy) const restrict2
346
{
347
    if (mFrame == nullptr ||
348
        mFrame->image == nullptr)
349
    {
350
        return;
351
    }
352
353
    Image *restrict const image = mFrame->image;
354
    image->setAlpha(mAlpha);
355
    graphics->drawRescaledImage(image,
356
        posX + mFrame->offsetX,
357
        posY + mFrame->offsetY,
358
        dx,
359
        dy);
360
}
361
362
void AnimatedSprite::drawRaw(Graphics *restrict const graphics,
363
                             const int posX,
364
                             const int posY) const restrict2
365
{
366
    if ((mFrame == nullptr) || (mFrame->image == nullptr))
367
        return;
368
369
    Image *restrict const image = mFrame->image;
370
    image->setAlpha(mAlpha);
371
    graphics->drawImage(image,
372
        posX,
373
        posY);
374
}
375
376
bool AnimatedSprite::setSpriteDirection(const SpriteDirection::Type direction)
377
                                        restrict2
378
{
379
    if (mDirection != direction)
380
    {
381
        mDirection = direction;
382
383
        if (mAction == nullptr)
384
            return false;
385
386
        const Animation *restrict const animation =
387
            mAction->getAnimation(mDirection);
388
389
        if ((animation != nullptr) &&
390
            animation != mAnimation &&
391
            animation->getLength() > 0)
392
        {
393
            mAnimation = animation;
394
            reset();
395
        }
396
397
        return true;
398
    }
399
400
    return false;
401
}
402
403
unsigned int AnimatedSprite::getFrameCount() const restrict2
404
{
405
    if (mAnimation != nullptr)
406
        return CAST_U32(mAnimation->getLength());
407
    return 0;
408
}
409
410
int AnimatedSprite::getWidth() const restrict2
411
{
412
    if ((mFrame != nullptr) && (mFrame->image != nullptr))
413
        return mFrame->image->mBounds.w;
414
    return 0;
415
}
416
417
int AnimatedSprite::getHeight() const restrict2
418
{
419
    if ((mFrame != nullptr) && (mFrame->image != nullptr))
420
        return mFrame->image->mBounds.h;
421
    return 0;
422
}
423
424
std::string AnimatedSprite::getIdPath() const restrict2
425
{
426
    if (mSprite == nullptr)
427
        return "";
428
    return mSprite->mIdPath;
429
}
430
431
const Image* AnimatedSprite::getImage() const restrict2 noexcept2
432
{
433
    return mFrame != nullptr ? mFrame->image : nullptr;
434
}
435
436
void AnimatedSprite::setAlpha(float alpha) restrict2
437
{
438
    mAlpha = alpha;
439
440
    if (mFrame != nullptr)
441
    {
442
        Image *restrict const image = mFrame->image;
443
        if (image != nullptr)
444
            image->setAlpha(mAlpha);
445
    }
446
}
447
448
const void *AnimatedSprite::getHash() const restrict2
449
{
450
    if (mFrame != nullptr)
451
        return mFrame;
452
    return this;
453
}
454
455
bool AnimatedSprite::updateNumber(const unsigned num) restrict2
456
{
457
    if (mSprite == nullptr)
458
        return false;
459
460
    if (mNumber1 != num)
461
    {
462
        mNumber1 = num;
463
        mNumber = mSprite->findNumber(num);
464
        if (mNumber == 0u)
465
        {
466
            mNumber = 100;
467
            return false;
468
        }
469
        return true;
470
    }
471
    return false;
472
}
473
474
void AnimatedSprite::setDelayLoad(const std::string &restrict filename,
475
                                  const int variant) restrict2
476
{
477
    if (mDelayLoad != nullptr)
478
    {
479
        mDelayLoad->clearSprite();
480
        DelayedManager::removeDelayLoad(mDelayLoad);
481
        delete mDelayLoad;
482
    }
483
    mDelayLoad = new AnimationDelayLoad(filename, variant, this);
484
    DelayedManager::addDelayedAnimation(mDelayLoad);
485

6
}