~ubuntu-branches/ubuntu/trusty/manaplus/trusty-proposed

« back to all changes in this revision

Viewing changes to src/being/compoundsprite.cpp

  • Committer: Package Import Robot
  • Author(s): Patrick Matthäi
  • Date: 2013-09-17 10:35:51 UTC
  • mfrom: (1.1.10)
  • Revision ID: package-import@ubuntu.com-20130917103551-az7p3nz9jgxwqjfn
Tags: 1.3.9.15-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  The ManaPlus Client
 
3
 *  Copyright (C) 2010  The Mana Developers
 
4
 *  Copyright (C) 2011-2013  The ManaPlus Developers
 
5
 *
 
6
 *  This file is part of The ManaPlus Client.
 
7
 *
 
8
 *  This program is free software; you can redistribute it and/or modify
 
9
 *  it under the terms of the GNU General Public License as published by
 
10
 *  the Free Software Foundation; either version 2 of the License, or
 
11
 *  any later version.
 
12
 *
 
13
 *  This program is distributed in the hope that it will be useful,
 
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
 *  GNU General Public License for more details.
 
17
 *
 
18
 *  You should have received a copy of the GNU General Public License
 
19
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
20
 */
 
21
 
 
22
#include "being/compoundsprite.h"
 
23
 
 
24
#include "client.h"
 
25
#include "configuration.h"
 
26
#include "game.h"
 
27
 
 
28
#ifdef USE_OPENGL
 
29
#include "main.h"
 
30
#endif
 
31
 
 
32
#include "map.h"
 
33
#include "sdlshared.h"
 
34
 
 
35
#include "render/surfacegraphics.h"
 
36
 
 
37
#include "resources/image.h"
 
38
#include "resources/imagehelper.h"
 
39
 
 
40
#include "utils/dtor.h"
 
41
#include "utils/sdlcheckutils.h"
 
42
 
 
43
#include "debug.h"
 
44
 
 
45
static const int BUFFER_WIDTH = 100;
 
46
static const int BUFFER_HEIGHT = 100;
 
47
 
 
48
static const unsigned cache_max_size = 10;
 
49
static const unsigned cache_clean_part = 3;
 
50
bool CompoundSprite::mEnableDelay = true;
 
51
 
 
52
CompoundSprite::CompoundSprite() :
 
53
    imagesCache(),
 
54
    mCacheItem(nullptr),
 
55
    mImage(nullptr),
 
56
    mAlphaImage(nullptr),
 
57
    mOffsetX(0),
 
58
    mOffsetY(0),
 
59
    mSprites(),
 
60
    mNextRedrawTime(0),
 
61
    mNeedsRedraw(false),
 
62
    mEnableAlphaFix(config.getBoolValue("enableAlphaFix")),
 
63
    mDisableAdvBeingCaching(config.getBoolValue("disableAdvBeingCaching")),
 
64
    mDisableBeingCaching(config.getBoolValue("disableBeingCaching"))
 
65
{
 
66
    mAlpha = 1.0f;
 
67
}
 
68
 
 
69
CompoundSprite::~CompoundSprite()
 
70
{
 
71
    clear();
 
72
    mImage = nullptr;
 
73
    mAlphaImage = nullptr;
 
74
}
 
75
 
 
76
bool CompoundSprite::reset()
 
77
{
 
78
    bool ret = false;
 
79
    FOR_EACH (SpriteIterator, it, mSprites)
 
80
    {
 
81
        if (*it)
 
82
            ret |= (*it)->reset();
 
83
    }
 
84
    mNeedsRedraw |= ret;
 
85
    return ret;
 
86
}
 
87
 
 
88
bool CompoundSprite::play(const std::string &action)
 
89
{
 
90
    bool ret = false;
 
91
    FOR_EACH (SpriteIterator, it, mSprites)
 
92
    {
 
93
        if (*it)
 
94
            ret |= (*it)->play(action);
 
95
    }
 
96
    mNeedsRedraw |= ret;
 
97
    return ret;
 
98
}
 
99
 
 
100
bool CompoundSprite::update(const int time)
 
101
{
 
102
    bool ret = false;
 
103
    FOR_EACH (SpriteIterator, it, mSprites)
 
104
    {
 
105
        if (*it)
 
106
            ret |= (*it)->update(time);
 
107
    }
 
108
    mNeedsRedraw |= ret;
 
109
    return ret;
 
110
}
 
111
 
 
112
bool CompoundSprite::draw(Graphics *const graphics,
 
113
                          const int posX, const int posY) const
 
114
{
 
115
    FUNC_BLOCK("CompoundSprite::draw", 1)
 
116
    if (mNeedsRedraw)
 
117
        updateImages();
 
118
 
 
119
    if (mSprites.empty())  // Nothing to draw
 
120
        return false;
 
121
 
 
122
    if (mAlpha == 1.0f && mImage)
 
123
    {
 
124
        return graphics->drawImage(mImage, posX + mOffsetX, posY + mOffsetY);
 
125
    }
 
126
    else if (mAlpha && mAlphaImage)
 
127
    {
 
128
        mAlphaImage->setAlpha(mAlpha);
 
129
        return graphics->drawImage(mAlphaImage,
 
130
            posX + mOffsetX, posY + mOffsetY);
 
131
    }
 
132
    else
 
133
    {
 
134
        drawSprites(graphics, posX, posY);
 
135
    }
 
136
    return false;
 
137
}
 
138
 
 
139
void CompoundSprite::drawSprites(Graphics *const graphics,
 
140
                                 const int posX, const int posY) const
 
141
{
 
142
    FOR_EACH (SpriteConstIterator, it, mSprites)
 
143
    {
 
144
        if (*it)
 
145
        {
 
146
            (*it)->setAlpha(mAlpha);
 
147
            (*it)->draw(graphics, posX, posY);
 
148
        }
 
149
    }
 
150
}
 
151
 
 
152
void CompoundSprite::drawSpritesSDL(Graphics *const graphics,
 
153
                                    const int posX, const int posY) const
 
154
{
 
155
    FOR_EACH (SpriteConstIterator, it, mSprites)
 
156
    {
 
157
        if (*it)
 
158
            (*it)->draw(graphics, posX, posY);
 
159
    }
 
160
}
 
161
 
 
162
int CompoundSprite::getWidth() const
 
163
{
 
164
    FOR_EACH (SpriteConstIterator, it, mSprites)
 
165
    {
 
166
        const Sprite *const base = *it;
 
167
        if (base)
 
168
            return base->getWidth();
 
169
    }
 
170
 
 
171
    return 0;
 
172
}
 
173
 
 
174
int CompoundSprite::getHeight() const
 
175
{
 
176
    FOR_EACH (SpriteConstIterator, it, mSprites)
 
177
    {
 
178
        const Sprite *const base = *it;
 
179
        if (base)
 
180
            return base->getHeight();
 
181
    }
 
182
 
 
183
    return 0;
 
184
}
 
185
 
 
186
const Image *CompoundSprite::getImage() const
 
187
{
 
188
    return mImage;
 
189
}
 
190
 
 
191
bool CompoundSprite::setSpriteDirection(const SpriteDirection direction)
 
192
{
 
193
    bool ret = false;
 
194
    FOR_EACH (SpriteIterator, it, mSprites)
 
195
    {
 
196
        if (*it)
 
197
            ret |= (*it)->setSpriteDirection(direction);
 
198
    }
 
199
    mNeedsRedraw |= ret;
 
200
    return ret;
 
201
}
 
202
 
 
203
int CompoundSprite::getNumberOfLayers() const
 
204
{
 
205
    if (mImage || mAlphaImage)
 
206
        return 1;
 
207
    else
 
208
        return static_cast<int>(size());
 
209
}
 
210
 
 
211
unsigned int CompoundSprite::getCurrentFrame() const
 
212
{
 
213
    FOR_EACH (SpriteConstIterator, it, mSprites)
 
214
    {
 
215
        if (*it)
 
216
            return (*it)->getCurrentFrame();
 
217
    }
 
218
    return 0;
 
219
}
 
220
 
 
221
unsigned int CompoundSprite::getFrameCount() const
 
222
{
 
223
    FOR_EACH (SpriteConstIterator, it, mSprites)
 
224
    {
 
225
        if (*it)
 
226
            return (*it)->getFrameCount();
 
227
    }
 
228
    return 0;
 
229
}
 
230
 
 
231
void CompoundSprite::addSprite(Sprite *const sprite)
 
232
{
 
233
    mSprites.push_back(sprite);
 
234
    mNeedsRedraw = true;
 
235
}
 
236
 
 
237
void CompoundSprite::setSprite(const int layer, Sprite *const sprite)
 
238
{
 
239
    // Skip if it won't change anything
 
240
    if (mSprites.at(layer) == sprite)
 
241
        return;
 
242
 
 
243
    delete mSprites.at(layer);
 
244
    mSprites[layer] = sprite;
 
245
    mNeedsRedraw = true;
 
246
}
 
247
 
 
248
void CompoundSprite::removeSprite(const int layer)
 
249
{
 
250
    // Skip if it won't change anything
 
251
    if (!mSprites.at(layer))
 
252
        return;
 
253
 
 
254
    delete mSprites.at(layer);
 
255
    mSprites.at(layer) = nullptr;
 
256
    mNeedsRedraw = true;
 
257
}
 
258
 
 
259
void CompoundSprite::clear()
 
260
{
 
261
    // Skip if it won't change anything
 
262
    if (!mSprites.empty())
 
263
    {
 
264
        delete_all(mSprites);
 
265
        mSprites.clear();
 
266
    }
 
267
    mNeedsRedraw = true;
 
268
    delete_all(imagesCache);
 
269
    imagesCache.clear();
 
270
    delete mCacheItem;
 
271
    mCacheItem = nullptr;
 
272
}
 
273
 
 
274
void CompoundSprite::ensureSize(size_t layerCount)
 
275
{
 
276
    // Skip if it won't change anything
 
277
    if (mSprites.size() >= layerCount)
 
278
        return;
 
279
 
 
280
//    resize(layerCount, nullptr);
 
281
    mSprites.resize(layerCount);
 
282
}
 
283
 
 
284
/**
 
285
 * Returns the curent frame in the current animation of the given layer.
 
286
 */
 
287
unsigned int CompoundSprite::getCurrentFrame(unsigned int layer) const
 
288
{
 
289
    if (layer >= mSprites.size())
 
290
        return 0;
 
291
 
 
292
    const Sprite *const s = getSprite(layer);
 
293
    if (s)
 
294
        return s->getCurrentFrame();
 
295
 
 
296
    return 0;
 
297
}
 
298
 
 
299
/**
 
300
 * Returns the frame count in the current animation of the given layer.
 
301
 */
 
302
unsigned int CompoundSprite::getFrameCount(unsigned int layer)
 
303
{
 
304
    if (layer >= mSprites.size())
 
305
        return 0;
 
306
 
 
307
    const Sprite *const s = getSprite(layer);
 
308
    if (s)
 
309
        return s->getFrameCount();
 
310
 
 
311
    return 0;
 
312
}
 
313
 
 
314
void CompoundSprite::redraw() const
 
315
{
 
316
#ifndef USE_SDL2
 
317
 
 
318
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
 
319
    const int rmask = 0xff000000;
 
320
    const int gmask = 0x00ff0000;
 
321
    const int bmask = 0x0000ff00;
 
322
    const int amask = 0x000000ff;
 
323
#else
 
324
    const int rmask = 0x000000ff;
 
325
    const int gmask = 0x0000ff00;
 
326
    const int bmask = 0x00ff0000;
 
327
    const int amask = 0xff000000;
 
328
#endif
 
329
 
 
330
    SDL_Surface *const surface = MSDL_CreateRGBSurface(SDL_HWSURFACE,
 
331
        BUFFER_WIDTH, BUFFER_HEIGHT, 32, rmask, gmask, bmask, amask);
 
332
 
 
333
    if (!surface)
 
334
        return;
 
335
 
 
336
    SurfaceGraphics *graphics = new SurfaceGraphics();
 
337
    graphics->setBlitMode(SurfaceGraphics::BLIT_GFX);
 
338
    graphics->setTarget(surface);
 
339
    graphics->_beginDraw();
 
340
 
 
341
    int tileX = 32 / 2;
 
342
    int tileY = 32;
 
343
 
 
344
    const Game *const game = Game::instance();
 
345
    if (game)
 
346
    {
 
347
        const Map *const map = game->getCurrentMap();
 
348
        if (map)
 
349
        {
 
350
            tileX = map->getTileWidth() / 2;
 
351
            tileY = map->getTileWidth();
 
352
        }
 
353
    }
 
354
 
 
355
    const int posX = BUFFER_WIDTH / 2 - tileX;
 
356
    const int posY = BUFFER_HEIGHT - tileY;
 
357
 
 
358
    mOffsetX = tileX - BUFFER_WIDTH / 2;
 
359
    mOffsetY = tileY - BUFFER_HEIGHT;
 
360
 
 
361
    drawSpritesSDL(graphics, posX, posY);
 
362
 
 
363
    delete graphics;
 
364
    graphics = nullptr;
 
365
 
 
366
    SDL_Surface *const surfaceA = MSDL_CreateRGBSurface(SDL_HWSURFACE,
 
367
        BUFFER_WIDTH, BUFFER_HEIGHT, 32, rmask, gmask, bmask, amask);
 
368
 
 
369
#ifdef USE_SDL2
 
370
    SDL_SetSurfaceAlphaMod(surface, 255);
 
371
#else
 
372
    SDL_SetAlpha(surface, 0, SDL_ALPHA_OPAQUE);
 
373
#endif
 
374
    SDL_BlitSurface(surface, nullptr, surfaceA, nullptr);
 
375
 
 
376
    delete mImage;
 
377
    delete mAlphaImage;
 
378
 
 
379
    mImage = imageHelper->load(surface);
 
380
    MSDL_FreeSurface(surface);
 
381
 
 
382
    if (ImageHelper::mEnableAlpha)
 
383
    {
 
384
        mAlphaImage = imageHelper->load(surfaceA);
 
385
        MSDL_FreeSurface(surfaceA);
 
386
    }
 
387
    else
 
388
    {
 
389
        mAlphaImage = nullptr;
 
390
    }
 
391
#endif
 
392
}
 
393
 
 
394
void CompoundSprite::setAlpha(float alpha)
 
395
{
 
396
    if (alpha != mAlpha)
 
397
    {
 
398
#ifdef USE_OPENGL
 
399
        if (mEnableAlphaFix && imageHelper->useOpenGL() == RENDER_SOFTWARE
 
400
            && size() > 3)
 
401
#else
 
402
        if (mEnableAlphaFix && size() > 3)
 
403
#endif
 
404
        {
 
405
            FOR_EACH (SpriteConstIterator, it, mSprites)
 
406
            {
 
407
                if (*it)
 
408
                    (*it)->setAlpha(alpha);
 
409
            }
 
410
        }
 
411
        mAlpha = alpha;
 
412
    }
 
413
}
 
414
 
 
415
void CompoundSprite::updateImages() const
 
416
{
 
417
#ifndef USE_SDL2
 
418
#ifdef USE_OPENGL
 
419
    if (imageHelper->useOpenGL() != RENDER_SOFTWARE)
 
420
        return;
 
421
#endif
 
422
 
 
423
    if (mEnableDelay)
 
424
    {
 
425
        if (get_elapsed_time1(mNextRedrawTime) < 10)
 
426
            return;
 
427
        mNextRedrawTime = tick_time;
 
428
    }
 
429
    mNeedsRedraw = false;
 
430
 
 
431
    if (!mDisableBeingCaching)
 
432
    {
 
433
        if (size() <= 3)
 
434
            return;
 
435
 
 
436
        if (!mDisableAdvBeingCaching)
 
437
        {
 
438
            if (updateFromCache())
 
439
                return;
 
440
 
 
441
            redraw();
 
442
 
 
443
            if (mImage)
 
444
                initCurrentCacheItem();
 
445
        }
 
446
        else
 
447
        {
 
448
            redraw();
 
449
        }
 
450
    }
 
451
#endif
 
452
}
 
453
 
 
454
bool CompoundSprite::updateFromCache() const
 
455
{
 
456
#ifndef USE_SDL2
 
457
//    static int hits = 0;
 
458
//    static int miss = 0;
 
459
 
 
460
    if (mCacheItem && mCacheItem->image)
 
461
    {
 
462
        imagesCache.push_front(mCacheItem);
 
463
        mCacheItem = nullptr;
 
464
        if (imagesCache.size() > cache_max_size)
 
465
        {
 
466
            for (unsigned f = 0; f < cache_clean_part; f ++)
 
467
            {
 
468
                CompoundItem *item = imagesCache.back();
 
469
                imagesCache.pop_back();
 
470
                delete item;
 
471
            }
 
472
        }
 
473
    }
 
474
 
 
475
//    logger->log("cache size: %d, hit %d, miss %d",
 
476
//        (int)imagesCache.size(), hits, miss);
 
477
 
 
478
    const size_t sz = size();
 
479
    FOR_EACH (ImagesCache::iterator, it, imagesCache)
 
480
    {
 
481
        CompoundItem *const ic = *it;
 
482
        if (ic && ic->data.size() == sz)
 
483
        {
 
484
            bool fail(false);
 
485
            VectorPointers::const_iterator it2 = ic->data.begin();
 
486
            const VectorPointers::const_iterator it2_end = ic->data.end();
 
487
 
 
488
            for (SpriteConstIterator it1 = mSprites.begin(),
 
489
                 it1_end = mSprites.end();
 
490
                 it1 != it1_end && it2 != it2_end;
 
491
                 ++ it1, ++ it2)
 
492
            {
 
493
                const void *ptr1 = nullptr;
 
494
                const void *ptr2 = nullptr;
 
495
                if (*it1)
 
496
                    ptr1 = (*it1)->getHash();
 
497
                if (*it2)
 
498
                    ptr2 = *it2;
 
499
                if (ptr1 != ptr2)
 
500
                {
 
501
                    fail = true;
 
502
                    break;
 
503
                }
 
504
            }
 
505
            if (!fail)
 
506
            {
 
507
//                hits ++;
 
508
                mImage = (*it)->image;
 
509
                mAlphaImage = (*it)->alphaImage;
 
510
                imagesCache.erase(it);
 
511
                mCacheItem = ic;
 
512
                return true;
 
513
            }
 
514
        }
 
515
    }
 
516
    mImage = nullptr;
 
517
    mAlphaImage = nullptr;
 
518
//    miss++;
 
519
#endif
 
520
    return false;
 
521
}
 
522
 
 
523
void CompoundSprite::initCurrentCacheItem() const
 
524
{
 
525
    delete mCacheItem;
 
526
    mCacheItem = new CompoundItem();
 
527
    mCacheItem->image = mImage;
 
528
    mCacheItem->alphaImage = mAlphaImage;
 
529
//    mCacheItem->alpha = mAlpha;
 
530
 
 
531
    FOR_EACH (SpriteConstIterator, it, mSprites)
 
532
    {
 
533
        if (*it)
 
534
            mCacheItem->data.push_back((*it)->getHash());
 
535
        else
 
536
            mCacheItem->data.push_back(nullptr);
 
537
    }
 
538
}
 
539
 
 
540
bool CompoundSprite::updateNumber(unsigned num)
 
541
{
 
542
    bool res(false);
 
543
    FOR_EACH (SpriteConstIterator, it, mSprites)
 
544
    {
 
545
        if (*it)
 
546
        {
 
547
            if ((*it)->updateNumber(num))
 
548
                res = true;
 
549
        }
 
550
    }
 
551
    return res;
 
552
}
 
553
 
 
554
CompoundItem::CompoundItem() :
 
555
    data(),
 
556
    image(nullptr),
 
557
    alphaImage(nullptr)
 
558
{
 
559
}
 
560
 
 
561
CompoundItem::~CompoundItem()
 
562
{
 
563
    delete image;
 
564
    delete alphaImage;
 
565
}