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

« back to all changes in this revision

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