3
* Copyright (C) 2010 The Mana Developers
4
* Copyright (C) 2011-2013 The ManaPlus Developers
6
* This file is part of The ManaPlus Client.
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
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.
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/>.
22
#include "compoundsprite.h"
25
#include "configuration.h"
33
#include "sdlshared.h"
34
#include "surfacegraphics.h"
36
#include "resources/image.h"
37
#include "resources/imagehelper.h"
39
#include "utils/dtor.h"
40
#include "utils/sdlcheckutils.h"
46
static const int BUFFER_WIDTH = 100;
47
static const int BUFFER_HEIGHT = 100;
49
static const unsigned cache_max_size = 10;
50
static const unsigned cache_clean_part = 3;
51
bool CompoundSprite::mEnableDelay = true;
53
CompoundSprite::CompoundSprite() :
63
mEnableAlphaFix(config.getBoolValue("enableAlphaFix")),
64
mDisableAdvBeingCaching(config.getBoolValue("disableAdvBeingCaching")),
65
mDisableBeingCaching(config.getBoolValue("disableBeingCaching"))
70
CompoundSprite::~CompoundSprite()
74
mAlphaImage = nullptr;
77
bool CompoundSprite::reset()
80
FOR_EACH (SpriteIterator, it, mSprites)
83
ret |= (*it)->reset();
89
bool CompoundSprite::play(const std::string &action)
92
FOR_EACH (SpriteIterator, it, mSprites)
95
ret |= (*it)->play(action);
101
bool CompoundSprite::update(const int time)
104
FOR_EACH (SpriteIterator, it, mSprites)
107
ret |= (*it)->update(time);
113
bool CompoundSprite::draw(Graphics *const graphics,
114
const int posX, const int posY) const
116
FUNC_BLOCK("CompoundSprite::draw", 1)
120
if (mSprites.empty()) // Nothing to draw
123
if (mAlpha == 1.0f && mImage)
125
return graphics->drawImage(mImage, posX + mOffsetX, posY + mOffsetY);
127
else if (mAlpha && mAlphaImage)
129
mAlphaImage->setAlpha(mAlpha);
130
return graphics->drawImage(mAlphaImage,
131
posX + mOffsetX, posY + mOffsetY);
135
drawSprites(graphics, posX, posY);
140
void CompoundSprite::drawSprites(Graphics *const graphics,
141
const int posX, const int posY) const
143
FOR_EACH (SpriteConstIterator, it, mSprites)
147
(*it)->setAlpha(mAlpha);
148
(*it)->draw(graphics, posX, posY);
153
void CompoundSprite::drawSpritesSDL(Graphics *const graphics,
154
const int posX, const int posY) const
156
FOR_EACH (SpriteConstIterator, it, mSprites)
159
(*it)->draw(graphics, posX, posY);
163
int CompoundSprite::getWidth() const
165
FOR_EACH (SpriteConstIterator, it, mSprites)
167
const Sprite *const base = *it;
169
return base->getWidth();
175
int CompoundSprite::getHeight() const
177
FOR_EACH (SpriteConstIterator, it, mSprites)
179
const Sprite *const base = *it;
181
return base->getHeight();
187
const Image *CompoundSprite::getImage() const
192
bool CompoundSprite::setSpriteDirection(const SpriteDirection direction)
195
FOR_EACH (SpriteIterator, it, mSprites)
198
ret |= (*it)->setSpriteDirection(direction);
204
int CompoundSprite::getNumberOfLayers() const
206
if (mImage || mAlphaImage)
209
return static_cast<int>(size());
212
unsigned int CompoundSprite::getCurrentFrame() const
214
FOR_EACH (SpriteConstIterator, it, mSprites)
217
return (*it)->getCurrentFrame();
222
unsigned int CompoundSprite::getFrameCount() const
224
FOR_EACH (SpriteConstIterator, it, mSprites)
227
return (*it)->getFrameCount();
232
void CompoundSprite::addSprite(Sprite *const sprite)
234
mSprites.push_back(sprite);
238
void CompoundSprite::setSprite(const int layer, Sprite *const sprite)
240
// Skip if it won't change anything
241
if (mSprites.at(layer) == sprite)
244
delete mSprites.at(layer);
245
mSprites[layer] = sprite;
249
void CompoundSprite::removeSprite(const int layer)
251
// Skip if it won't change anything
252
if (!mSprites.at(layer))
255
delete mSprites.at(layer);
256
mSprites.at(layer) = nullptr;
260
void CompoundSprite::clear()
262
// Skip if it won't change anything
263
if (!mSprites.empty())
265
delete_all(mSprites);
269
delete_all(imagesCache);
272
mCacheItem = nullptr;
275
void CompoundSprite::ensureSize(size_t layerCount)
277
// Skip if it won't change anything
278
if (mSprites.size() >= layerCount)
281
// resize(layerCount, nullptr);
282
mSprites.resize(layerCount);
286
* Returns the curent frame in the current animation of the given layer.
288
unsigned int CompoundSprite::getCurrentFrame(unsigned int layer) const
290
if (layer >= mSprites.size())
293
const Sprite *const s = getSprite(layer);
295
return s->getCurrentFrame();
301
* Returns the frame count in the current animation of the given layer.
303
unsigned int CompoundSprite::getFrameCount(unsigned int layer)
305
if (layer >= mSprites.size())
308
const Sprite *const s = getSprite(layer);
310
return s->getFrameCount();
315
void CompoundSprite::redraw() const
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;
325
const int rmask = 0x000000ff;
326
const int gmask = 0x0000ff00;
327
const int bmask = 0x00ff0000;
328
const int amask = 0xff000000;
331
SDL_Surface *const surface = MSDL_CreateRGBSurface(SDL_HWSURFACE,
332
BUFFER_WIDTH, BUFFER_HEIGHT, 32, rmask, gmask, bmask, amask);
337
SurfaceGraphics *graphics = new SurfaceGraphics();
338
graphics->setBlitMode(SurfaceGraphics::BLIT_GFX);
339
graphics->setTarget(surface);
340
graphics->_beginDraw();
345
const Game *const game = Game::instance();
348
const Map *const map = game->getCurrentMap();
351
tileX = map->getTileWidth() / 2;
352
tileY = map->getTileWidth();
356
const int posX = BUFFER_WIDTH / 2 - tileX;
357
const int posY = BUFFER_HEIGHT - tileY;
359
mOffsetX = tileX - BUFFER_WIDTH / 2;
360
mOffsetY = tileY - BUFFER_HEIGHT;
362
drawSpritesSDL(graphics, posX, posY);
367
SDL_Surface *const surfaceA = MSDL_CreateRGBSurface(SDL_HWSURFACE,
368
BUFFER_WIDTH, BUFFER_HEIGHT, 32, rmask, gmask, bmask, amask);
371
SDL_SetSurfaceAlphaMod(surface, 255);
373
SDL_SetAlpha(surface, 0, SDL_ALPHA_OPAQUE);
375
SDL_BlitSurface(surface, nullptr, surfaceA, nullptr);
380
mImage = imageHelper->load(surface);
381
MSDL_FreeSurface(surface);
383
if (ImageHelper::mEnableAlpha)
385
mAlphaImage = imageHelper->load(surfaceA);
386
MSDL_FreeSurface(surfaceA);
390
mAlphaImage = nullptr;
395
void CompoundSprite::setAlpha(float alpha)
400
if (mEnableAlphaFix && imageHelper->useOpenGL() == 0
403
if (mEnableAlphaFix && size() > 3)
406
FOR_EACH (SpriteConstIterator, it, mSprites)
409
(*it)->setAlpha(alpha);
416
void CompoundSprite::updateImages() const
420
if (imageHelper->useOpenGL())
426
if (get_elapsed_time1(mNextRedrawTime) < 10)
428
mNextRedrawTime = tick_time;
430
mNeedsRedraw = false;
432
if (!mDisableBeingCaching)
437
if (!mDisableAdvBeingCaching)
439
if (updateFromCache())
445
initCurrentCacheItem();
455
bool CompoundSprite::updateFromCache() const
458
// static int hits = 0;
459
// static int miss = 0;
461
if (mCacheItem && mCacheItem->image)
463
imagesCache.push_front(mCacheItem);
464
mCacheItem = nullptr;
465
if (imagesCache.size() > cache_max_size)
467
for (unsigned f = 0; f < cache_clean_part; f ++)
469
CompoundItem *item = imagesCache.back();
470
imagesCache.pop_back();
476
// logger->log("cache size: %d, hit %d, miss %d",
477
// (int)imagesCache.size(), hits, miss);
479
const size_t sz = size();
480
FOR_EACH (ImagesCache::iterator, it, imagesCache)
482
CompoundItem *const ic = *it;
483
if (ic && ic->data.size() == sz)
486
VectorPointers::const_iterator it2 = ic->data.begin();
487
const VectorPointers::const_iterator it2_end = ic->data.end();
489
for (SpriteConstIterator it1 = mSprites.begin(),
490
it1_end = mSprites.end();
491
it1 != it1_end && it2 != it2_end;
494
const void *ptr1 = nullptr;
495
const void *ptr2 = nullptr;
497
ptr1 = (*it1)->getHash();
509
mImage = (*it)->image;
510
mAlphaImage = (*it)->alphaImage;
511
imagesCache.erase(it);
518
mAlphaImage = nullptr;
524
void CompoundSprite::initCurrentCacheItem() const
527
mCacheItem = new CompoundItem();
528
mCacheItem->image = mImage;
529
mCacheItem->alphaImage = mAlphaImage;
530
// mCacheItem->alpha = mAlpha;
532
FOR_EACH (SpriteConstIterator, it, mSprites)
535
mCacheItem->data.push_back((*it)->getHash());
537
mCacheItem->data.push_back(nullptr);
541
bool CompoundSprite::updateNumber(unsigned num)
544
FOR_EACH (SpriteConstIterator, it, mSprites)
548
if ((*it)->updateNumber(num))
555
CompoundItem::CompoundItem() :
562
CompoundItem::~CompoundItem()