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 "being/compoundsprite.h"
25
#include "configuration.h"
33
#include "sdlshared.h"
35
#include "render/surfacegraphics.h"
37
#include "resources/image.h"
38
#include "resources/imagehelper.h"
40
#include "utils/dtor.h"
41
#include "utils/sdlcheckutils.h"
45
static const int BUFFER_WIDTH = 100;
46
static const int BUFFER_HEIGHT = 100;
48
static const unsigned cache_max_size = 10;
49
static const unsigned cache_clean_part = 3;
50
bool CompoundSprite::mEnableDelay = true;
52
CompoundSprite::CompoundSprite() :
62
mEnableAlphaFix(config.getBoolValue("enableAlphaFix")),
63
mDisableAdvBeingCaching(config.getBoolValue("disableAdvBeingCaching")),
64
mDisableBeingCaching(config.getBoolValue("disableBeingCaching"))
69
CompoundSprite::~CompoundSprite()
73
mAlphaImage = nullptr;
76
bool CompoundSprite::reset()
79
FOR_EACH (SpriteIterator, it, mSprites)
82
ret |= (*it)->reset();
88
bool CompoundSprite::play(const std::string &action)
91
FOR_EACH (SpriteIterator, it, mSprites)
94
ret |= (*it)->play(action);
100
bool CompoundSprite::update(const int time)
103
FOR_EACH (SpriteIterator, it, mSprites)
106
ret |= (*it)->update(time);
112
bool CompoundSprite::draw(Graphics *const graphics,
113
const int posX, const int posY) const
115
FUNC_BLOCK("CompoundSprite::draw", 1)
119
if (mSprites.empty()) // Nothing to draw
122
if (mAlpha == 1.0f && mImage)
124
return graphics->drawImage(mImage, posX + mOffsetX, posY + mOffsetY);
126
else if (mAlpha && mAlphaImage)
128
mAlphaImage->setAlpha(mAlpha);
129
return graphics->drawImage(mAlphaImage,
130
posX + mOffsetX, posY + mOffsetY);
134
drawSprites(graphics, posX, posY);
139
void CompoundSprite::drawSprites(Graphics *const graphics,
140
const int posX, const int posY) const
142
FOR_EACH (SpriteConstIterator, it, mSprites)
146
(*it)->setAlpha(mAlpha);
147
(*it)->draw(graphics, posX, posY);
152
void CompoundSprite::drawSpritesSDL(Graphics *const graphics,
153
const int posX, const int posY) const
155
FOR_EACH (SpriteConstIterator, it, mSprites)
158
(*it)->draw(graphics, posX, posY);
162
int CompoundSprite::getWidth() const
164
FOR_EACH (SpriteConstIterator, it, mSprites)
166
const Sprite *const base = *it;
168
return base->getWidth();
174
int CompoundSprite::getHeight() const
176
FOR_EACH (SpriteConstIterator, it, mSprites)
178
const Sprite *const base = *it;
180
return base->getHeight();
186
const Image *CompoundSprite::getImage() const
191
bool CompoundSprite::setSpriteDirection(const SpriteDirection direction)
194
FOR_EACH (SpriteIterator, it, mSprites)
197
ret |= (*it)->setSpriteDirection(direction);
203
int CompoundSprite::getNumberOfLayers() const
205
if (mImage || mAlphaImage)
208
return static_cast<int>(size());
211
unsigned int CompoundSprite::getCurrentFrame() const
213
FOR_EACH (SpriteConstIterator, it, mSprites)
216
return (*it)->getCurrentFrame();
221
unsigned int CompoundSprite::getFrameCount() const
223
FOR_EACH (SpriteConstIterator, it, mSprites)
226
return (*it)->getFrameCount();
231
void CompoundSprite::addSprite(Sprite *const sprite)
233
mSprites.push_back(sprite);
237
void CompoundSprite::setSprite(const int layer, Sprite *const sprite)
239
// Skip if it won't change anything
240
if (mSprites.at(layer) == sprite)
243
delete mSprites.at(layer);
244
mSprites[layer] = sprite;
248
void CompoundSprite::removeSprite(const int layer)
250
// Skip if it won't change anything
251
if (!mSprites.at(layer))
254
delete mSprites.at(layer);
255
mSprites.at(layer) = nullptr;
259
void CompoundSprite::clear()
261
// Skip if it won't change anything
262
if (!mSprites.empty())
264
delete_all(mSprites);
268
delete_all(imagesCache);
271
mCacheItem = nullptr;
274
void CompoundSprite::ensureSize(size_t layerCount)
276
// Skip if it won't change anything
277
if (mSprites.size() >= layerCount)
280
// resize(layerCount, nullptr);
281
mSprites.resize(layerCount);
285
* Returns the curent frame in the current animation of the given layer.
287
unsigned int CompoundSprite::getCurrentFrame(unsigned int layer) const
289
if (layer >= mSprites.size())
292
const Sprite *const s = getSprite(layer);
294
return s->getCurrentFrame();
300
* Returns the frame count in the current animation of the given layer.
302
unsigned int CompoundSprite::getFrameCount(unsigned int layer)
304
if (layer >= mSprites.size())
307
const Sprite *const s = getSprite(layer);
309
return s->getFrameCount();
314
void CompoundSprite::redraw() const
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;
324
const int rmask = 0x000000ff;
325
const int gmask = 0x0000ff00;
326
const int bmask = 0x00ff0000;
327
const int amask = 0xff000000;
330
SDL_Surface *const surface = MSDL_CreateRGBSurface(SDL_HWSURFACE,
331
BUFFER_WIDTH, BUFFER_HEIGHT, 32, rmask, gmask, bmask, amask);
336
SurfaceGraphics *graphics = new SurfaceGraphics();
337
graphics->setBlitMode(SurfaceGraphics::BLIT_GFX);
338
graphics->setTarget(surface);
339
graphics->_beginDraw();
344
const Game *const game = Game::instance();
347
const Map *const map = game->getCurrentMap();
350
tileX = map->getTileWidth() / 2;
351
tileY = map->getTileWidth();
355
const int posX = BUFFER_WIDTH / 2 - tileX;
356
const int posY = BUFFER_HEIGHT - tileY;
358
mOffsetX = tileX - BUFFER_WIDTH / 2;
359
mOffsetY = tileY - BUFFER_HEIGHT;
361
drawSpritesSDL(graphics, posX, posY);
366
SDL_Surface *const surfaceA = MSDL_CreateRGBSurface(SDL_HWSURFACE,
367
BUFFER_WIDTH, BUFFER_HEIGHT, 32, rmask, gmask, bmask, amask);
370
SDL_SetSurfaceAlphaMod(surface, 255);
372
SDL_SetAlpha(surface, 0, SDL_ALPHA_OPAQUE);
374
SDL_BlitSurface(surface, nullptr, surfaceA, nullptr);
379
mImage = imageHelper->load(surface);
380
MSDL_FreeSurface(surface);
382
if (ImageHelper::mEnableAlpha)
384
mAlphaImage = imageHelper->load(surfaceA);
385
MSDL_FreeSurface(surfaceA);
389
mAlphaImage = nullptr;
394
void CompoundSprite::setAlpha(float alpha)
399
if (mEnableAlphaFix && imageHelper->useOpenGL() == RENDER_SOFTWARE
402
if (mEnableAlphaFix && size() > 3)
405
FOR_EACH (SpriteConstIterator, it, mSprites)
408
(*it)->setAlpha(alpha);
415
void CompoundSprite::updateImages() const
419
if (imageHelper->useOpenGL() != RENDER_SOFTWARE)
425
if (get_elapsed_time1(mNextRedrawTime) < 10)
427
mNextRedrawTime = tick_time;
429
mNeedsRedraw = false;
431
if (!mDisableBeingCaching)
436
if (!mDisableAdvBeingCaching)
438
if (updateFromCache())
444
initCurrentCacheItem();
454
bool CompoundSprite::updateFromCache() const
457
// static int hits = 0;
458
// static int miss = 0;
460
if (mCacheItem && mCacheItem->image)
462
imagesCache.push_front(mCacheItem);
463
mCacheItem = nullptr;
464
if (imagesCache.size() > cache_max_size)
466
for (unsigned f = 0; f < cache_clean_part; f ++)
468
CompoundItem *item = imagesCache.back();
469
imagesCache.pop_back();
475
// logger->log("cache size: %d, hit %d, miss %d",
476
// (int)imagesCache.size(), hits, miss);
478
const size_t sz = size();
479
FOR_EACH (ImagesCache::iterator, it, imagesCache)
481
CompoundItem *const ic = *it;
482
if (ic && ic->data.size() == sz)
485
VectorPointers::const_iterator it2 = ic->data.begin();
486
const VectorPointers::const_iterator it2_end = ic->data.end();
488
for (SpriteConstIterator it1 = mSprites.begin(),
489
it1_end = mSprites.end();
490
it1 != it1_end && it2 != it2_end;
493
const void *ptr1 = nullptr;
494
const void *ptr2 = nullptr;
496
ptr1 = (*it1)->getHash();
508
mImage = (*it)->image;
509
mAlphaImage = (*it)->alphaImage;
510
imagesCache.erase(it);
517
mAlphaImage = nullptr;
523
void CompoundSprite::initCurrentCacheItem() const
526
mCacheItem = new CompoundItem();
527
mCacheItem->image = mImage;
528
mCacheItem->alphaImage = mAlphaImage;
529
// mCacheItem->alpha = mAlpha;
531
FOR_EACH (SpriteConstIterator, it, mSprites)
534
mCacheItem->data.push_back((*it)->getHash());
536
mCacheItem->data.push_back(nullptr);
540
bool CompoundSprite::updateNumber(unsigned num)
543
FOR_EACH (SpriteConstIterator, it, mSprites)
547
if ((*it)->updateNumber(num))
554
CompoundItem::CompoundItem() :
561
CompoundItem::~CompoundItem()