summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJared Adams <jaxad0127@gmail.com>2010-05-20 01:35:17 -0600
committerJared Adams <jaxad0127@gmail.com>2010-05-20 12:25:37 -0600
commit487a86fe7dc9904f445d91667095f641f72f7c81 (patch)
tree57191d175f7b2fe771f6b2da225bc2d9cb5ff1d9
parent36832f3a5378f739da7040f0711b7101dbc2af02 (diff)
downloadmana-487a86fe7dc9904f445d91667095f641f72f7c81.tar.gz
mana-487a86fe7dc9904f445d91667095f641f72f7c81.tar.bz2
mana-487a86fe7dc9904f445d91667095f641f72f7c81.tar.xz
mana-487a86fe7dc9904f445d91667095f641f72f7c81.zip
Buffer layered sprites under SDL
This improves framerate and allows transparent overlay for complex sprites. Two copies of the buffer are kept, one at full opacity, one with variable opactiy, to reduce calls to setAlpha. Reviewed-by: Bertram
-rw-r--r--src/actorsprite.cpp6
-rw-r--r--src/animatedsprite.cpp34
-rw-r--r--src/animatedsprite.h10
-rw-r--r--src/being.cpp12
-rw-r--r--src/compoundsprite.cpp221
-rw-r--r--src/compoundsprite.h50
-rw-r--r--src/graphics.cpp10
-rw-r--r--src/graphics.h12
-rw-r--r--src/imagesprite.h14
-rw-r--r--src/sprite.h20
10 files changed, 320 insertions, 69 deletions
diff --git a/src/actorsprite.cpp b/src/actorsprite.cpp
index da81873f..92894b04 100644
--- a/src/actorsprite.cpp
+++ b/src/actorsprite.cpp
@@ -304,14 +304,14 @@ void ActorSprite::setupSpriteDisplay(const SpriteDisplay &display,
{
std::string file = "graphics/sprites/" + (*it)->sprite;
int variant = (*it)->variant;
- push_back(AnimatedSprite::load(file, variant));
+ addSprite(AnimatedSprite::load(file, variant));
}
// Ensure that something is shown, if desired
if (size() == 0 && forceDisplay)
{
if (display.image.empty())
- push_back(AnimatedSprite::load("graphics/sprites/error.xml"));
+ addSprite(AnimatedSprite::load("graphics/sprites/error.xml"));
else
{
ResourceManager *resman = ResourceManager::getInstance();
@@ -321,7 +321,7 @@ void ActorSprite::setupSpriteDisplay(const SpriteDisplay &display,
if (!img)
img = Theme::getImageFromTheme("unknown-item.png");
- push_back(new ImageSprite(img));
+ addSprite(new ImageSprite(img));
}
}
diff --git a/src/animatedsprite.cpp b/src/animatedsprite.cpp
index bc595f79..3e4104a9 100644
--- a/src/animatedsprite.cpp
+++ b/src/animatedsprite.cpp
@@ -70,18 +70,22 @@ AnimatedSprite::~AnimatedSprite()
mSprite->decRef();
}
-void AnimatedSprite::reset()
+bool AnimatedSprite::reset()
{
+ bool ret = mFrameIndex !=0 || mFrameTime != 0 || mLastTime != 0;
+
mFrameIndex = 0;
mFrameTime = 0;
mLastTime = 0;
+
+ return ret;
}
-void AnimatedSprite::play(SpriteAction spriteAction)
+bool AnimatedSprite::play(SpriteAction spriteAction)
{
Action *action = mSprite->getAction(spriteAction);
if (!action)
- return;
+ return false;
mAction = action;
Animation *animation = mAction->getAnimation(mDirection);
@@ -92,10 +96,14 @@ void AnimatedSprite::play(SpriteAction spriteAction)
mFrame = mAnimation->getFrame(0);
reset();
+
+ return true;
}
+
+ return false;
}
-void AnimatedSprite::update(int time)
+bool AnimatedSprite::update(int time)
{
// Avoid freaking out at first frame or when tick_time overflows
if (time < mLastTime || mLastTime == 0)
@@ -103,16 +111,22 @@ void AnimatedSprite::update(int time)
// If not enough time has passed yet, do nothing
if (time <= mLastTime || !mAnimation)
- return;
+ return false;
unsigned int dt = time - mLastTime;
mLastTime = time;
+ Animation *animation = mAnimation;
+ Frame *frame = mFrame;
+
if (!updateCurrentAnimation(dt))
{
// Animation finished, reset to default
play(ACTION_STAND);
}
+
+ // Make sure something actually changed
+ return animation != mAnimation || frame != mFrame;
}
bool AnimatedSprite::updateCurrentAnimation(unsigned int time)
@@ -159,14 +173,14 @@ bool AnimatedSprite::draw(Graphics *graphics, int posX, int posY) const
posY + mFrame->offsetY);
}
-void AnimatedSprite::setDirection(SpriteDirection direction)
+bool AnimatedSprite::setDirection(SpriteDirection direction)
{
if (mDirection != direction)
{
mDirection = direction;
if (!mAction)
- return;
+ return false;
Animation *animation = mAction->getAnimation(mDirection);
@@ -176,7 +190,11 @@ void AnimatedSprite::setDirection(SpriteDirection direction)
mFrame = mAnimation->getFrame(0);
reset();
}
+
+ return true;
}
+
+ return false;
}
int AnimatedSprite::getWidth() const
@@ -195,7 +213,7 @@ int AnimatedSprite::getHeight() const
return 0;
}
-Image* AnimatedSprite::getImage() const
+const Image* AnimatedSprite::getImage() const
{
return mFrame ? mFrame->image : 0;
}
diff --git a/src/animatedsprite.h b/src/animatedsprite.h
index 833a07a3..aae116be 100644
--- a/src/animatedsprite.h
+++ b/src/animatedsprite.h
@@ -54,11 +54,11 @@ class AnimatedSprite : public Sprite
virtual ~AnimatedSprite();
- void reset();
+ bool reset();
- void play(SpriteAction action);
+ bool play(SpriteAction action);
- void update(int time);
+ bool update(int time);
bool draw(Graphics* graphics, int posX, int posY) const;
@@ -66,9 +66,9 @@ class AnimatedSprite : public Sprite
int getHeight() const;
- Image* getImage() const;
+ const Image* getImage() const;
- void setDirection(SpriteDirection direction);
+ bool setDirection(SpriteDirection direction);
int getNumberOfLayers()
{ return 1; }
diff --git a/src/being.cpp b/src/being.cpp
index a2180c84..24f2e2e1 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -1063,7 +1063,7 @@ void Being::setSprite(unsigned int slot, int id, const std::string &color,
assert(slot < Net::getCharHandler()->maxSprite());
if (slot >= size())
- resize(slot + 1, NULL);
+ ensureSize(slot + 1);
if (slot >= mSpriteIDs.size())
mSpriteIDs.resize(slot + 1, 0);
@@ -1074,8 +1074,7 @@ void Being::setSprite(unsigned int slot, int id, const std::string &color,
// id = 0 means unequip
if (id == 0)
{
- delete at(slot);
- at(slot) = NULL;
+ removeSprite(slot);
if (isWeapon)
mEquippedWeapon = NULL;
@@ -1097,10 +1096,7 @@ void Being::setSprite(unsigned int slot, int id, const std::string &color,
if (equipmentSprite)
equipmentSprite->setDirection(getSpriteDirection());
- if (at(slot))
- delete at(slot);
-
- at(slot) = equipmentSprite;
+ CompoundSprite::setSprite(slot, equipmentSprite);
if (isWeapon)
mEquippedWeapon = &ItemDB::get(id);
@@ -1124,7 +1120,7 @@ void Being::setSpriteColor(unsigned int slot, const std::string &color)
int Being::getNumberOfLayers() const
{
- return size();
+ return CompoundSprite::getNumberOfLayers();
}
void Being::load()
diff --git a/src/compoundsprite.cpp b/src/compoundsprite.cpp
index a9a521ef..53fdd7c2 100644
--- a/src/compoundsprite.cpp
+++ b/src/compoundsprite.cpp
@@ -20,9 +20,24 @@
#include "compoundsprite.h"
+#include "game.h"
+#include "graphics.h"
+#include "openglgraphics.h"
+#include "map.h"
+
+#include "resources/image.h"
+
#include "utils/dtor.h"
-CompoundSprite::CompoundSprite()
+#include <SDL.h>
+
+#define BUFFER_WIDTH 100
+#define BUFFER_HEIGHT 100
+
+CompoundSprite::CompoundSprite():
+ mImage(NULL),
+ mAlphaImage(NULL),
+ mNeedsRedraw(false)
{
mAlpha = 1.0f;
}
@@ -36,44 +51,73 @@ CompoundSprite::~CompoundSprite()
clear();
}
-void CompoundSprite::reset()
+bool CompoundSprite::reset()
{
+ bool ret = false;
+
SpriteIterator it, it_end;
for (it = begin(), it_end = end(); it != it_end; it++)
if (*it)
- (*it)->reset();
+ ret |= (*it)->reset();
+
+ mNeedsRedraw |= ret;
+ return ret;
}
-void CompoundSprite::play(SpriteAction action)
+bool CompoundSprite::play(SpriteAction action)
{
+ bool ret = false;
+
SpriteIterator it, it_end;
for (it = begin(), it_end = end(); it != it_end; it++)
if (*it)
- (*it)->play(action);
+ ret |= (*it)->play(action);
+
+ mNeedsRedraw |= ret;
+ return ret;
}
-void CompoundSprite::update(int time)
+bool CompoundSprite::update(int time)
{
+ bool ret = false;
+
SpriteIterator it, it_end;
for (it = begin(), it_end = end(); it != it_end; it++)
if (*it)
- (*it)->update(time);
+ ret |= (*it)->update(time);
+
+ mNeedsRedraw |= ret;
+ return ret;
}
bool CompoundSprite::draw(Graphics* graphics, int posX, int posY) const
{
- SpriteConstIterator it, it_end;
- for (it = begin(), it_end = end(); it != it_end; it++)
+ if (mNeedsRedraw)
+ redraw();
+
+ if (mAlpha == 1.0f && mImage)
+ return graphics->drawImage(mImage, posX + mOffsetX, posY + mOffsetY);
+ else if (mAlpha && mAlphaImage)
{
- if (*it)
+ if (mAlphaImage->getAlpha() != mAlpha)
+ mAlphaImage->setAlpha(mAlpha);
+
+ return graphics->drawImage(mAlphaImage,
+ posX + mOffsetX, posY + mOffsetY);
+ }
+ else
+ {
+ SpriteConstIterator it, it_end;
+ for (it = begin(), it_end = end(); it != it_end; it++)
{
- if ((*it)->getAlpha() != mAlpha)
- (*it)->setAlpha(mAlpha);
- (*it)->draw(graphics, posX, posY);
+ if (*it)
+ {
+ (*it)->draw(graphics, posX, posY);
+ }
}
}
- return true;
+ return false;
}
int CompoundSprite::getWidth() const
@@ -106,16 +150,155 @@ int CompoundSprite::getHeight() const
return 0;
}
-Image* CompoundSprite::getImage() const
+const Image* CompoundSprite::getImage() const
{
- // TODO http://bugs.manasource.org/view.php?id=24
- return NULL;
+ return mImage;
}
-void CompoundSprite::setDirection(SpriteDirection direction)
+bool CompoundSprite::setDirection(SpriteDirection direction)
{
+ bool ret = false;
+
SpriteIterator it, it_end;
for (it = begin(), it_end = end(); it != it_end; it++)
if (*it)
- (*it)->setDirection(direction);
+ ret |= (*it)->setDirection(direction);
+
+ mNeedsRedraw |= ret;
+ return ret;
+}
+
+int CompoundSprite::getNumberOfLayers() const
+{
+ if (mImage || mAlphaImage)
+ {
+ return 1;
+ }
+ else
+ {
+ return size();
+ }
+}
+
+void CompoundSprite::addSprite(Sprite* sprite)
+{
+ push_back(sprite);
+ mNeedsRedraw = true;
+}
+
+void CompoundSprite::setSprite(int layer, Sprite* sprite)
+{
+ // Skip if it won't change anything
+ if (at(layer) == sprite)
+ return;
+
+ if (at(layer))
+ delete at(layer);
+ at(layer) = sprite;
+ mNeedsRedraw = true;
+}
+
+void CompoundSprite::removeSprite(int layer)
+{
+ // Skip if it won't change anything
+ if (at(layer) == NULL)
+ return;
+
+ delete at(layer);
+ at(layer) = NULL;
+ mNeedsRedraw = true;
+}
+
+void CompoundSprite::clear()
+{
+ // Skip if it won't change anything
+ if (empty())
+ return;
+
+ std::vector<Sprite*>::clear();
+ mNeedsRedraw = true;
+}
+
+void CompoundSprite::ensureSize(size_t layerCount)
+{
+ // Skip if it won't change anything
+ if (size() >= layerCount)
+ return;
+
+ resize(layerCount, NULL);
+ mNeedsRedraw = true;
+}
+
+void CompoundSprite::redraw() const
+{
+ // TODO OpenGL support
+ if (Image::getLoadAsOpenGL())
+ {
+ mNeedsRedraw = false;
+ return;
+ }
+
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+ int rmask = 0xff000000;
+ int gmask = 0x00ff0000;
+ int bmask = 0x0000ff00;
+ int amask = 0x000000ff;
+#else
+ int rmask = 0x000000ff;
+ int gmask = 0x0000ff00;
+ int bmask = 0x00ff0000;
+ int amask = 0xff000000;
+#endif
+
+ SDL_Surface *surface = SDL_CreateRGBSurface(SDL_HWSURFACE,
+ BUFFER_WIDTH, BUFFER_HEIGHT,
+ 32, rmask, gmask, bmask, amask);
+
+ if (!surface)
+ return;
+
+ Graphics *graphics = new Graphics();
+ graphics->setBlitMode(Graphics::BLIT_GFX);
+ graphics->setTarget(surface);
+ graphics->_beginDraw();
+
+ int tileX = 32 / 2;
+ int tileY = 32;
+
+ Game *game = Game::instance();
+ if (game)
+ {
+ Map *map = game->getCurrentMap();
+ tileX = map->getTileWidth() / 2;
+ tileY = map->getTileWidth();
+ }
+
+ int posX = BUFFER_WIDTH / 2 - tileX;
+ int posY = BUFFER_HEIGHT - tileY;
+
+ mOffsetX = tileX - BUFFER_WIDTH / 2;
+ mOffsetY = tileY - BUFFER_HEIGHT;
+
+ SpriteConstIterator it, it_end;
+ for (it = begin(), it_end = end(); it != it_end; it++)
+ {
+ if (*it)
+ {
+ (*it)->draw(graphics, posX, posY);
+ }
+ }
+
+ delete graphics;
+
+ SDL_Surface *surfaceA = SDL_CreateRGBSurface(SDL_HWSURFACE,
+ BUFFER_WIDTH, BUFFER_HEIGHT,
+ 32, rmask, gmask, bmask, amask);
+
+ SDL_SetAlpha(surface, 0, SDL_ALPHA_OPAQUE);
+ SDL_BlitSurface(surface, NULL, surfaceA, NULL);
+
+ mImage = Image::load(surface);
+ mAlphaImage = Image::load(surfaceA);
+
+ mNeedsRedraw = false;
}
diff --git a/src/compoundsprite.h b/src/compoundsprite.h
index b3925216..c714c34b 100644
--- a/src/compoundsprite.h
+++ b/src/compoundsprite.h
@@ -25,18 +25,20 @@
#include <vector>
-class CompoundSprite : public Sprite, public std::vector<Sprite*>
+class Image;
+
+class CompoundSprite : public Sprite, private std::vector<Sprite*>
{
public:
CompoundSprite();
~CompoundSprite();
- virtual void reset();
+ virtual bool reset();
- virtual void play(SpriteAction action);
+ virtual bool play(SpriteAction action);
- virtual void update(int time);
+ virtual bool update(int time);
virtual bool draw(Graphics* graphics, int posX, int posY) const;
@@ -50,18 +52,40 @@ public:
*/
virtual int getHeight() const;
- virtual Image* getImage() const;
+ virtual const Image* getImage() const;
- virtual void setDirection(SpriteDirection direction);
+ virtual bool setDirection(SpriteDirection direction);
- virtual Sprite *getSprite(int index) const
- { return at(index); }
+ int getNumberOfLayers() const;
- int getNumberOfLayers()
- { return size(); }
-};
+ size_t size() const
+ { return std::vector<Sprite*>::size(); }
+
+ void addSprite(Sprite* sprite);
+
+ void setSprite(int layer, Sprite* sprite);
+
+ Sprite *getSprite(int layer) const
+ { return at(layer); }
+
+ void removeSprite(int layer);
+
+ void clear();
-typedef CompoundSprite::iterator SpriteIterator;
-typedef CompoundSprite::const_iterator SpriteConstIterator;
+ void ensureSize(size_t layerCount);
+
+private:
+ typedef CompoundSprite::iterator SpriteIterator;
+ typedef CompoundSprite::const_iterator SpriteConstIterator;
+
+ void redraw() const;
+
+ mutable Image *mImage;
+ mutable Image *mAlphaImage;
+
+ mutable int mOffsetX, mOffsetY;
+
+ mutable bool mNeedsRedraw;
+};
#endif // COMPOUNDSPRITE_H
diff --git a/src/graphics.cpp b/src/graphics.cpp
index 9815e1ad..24f92544 100644
--- a/src/graphics.cpp
+++ b/src/graphics.cpp
@@ -27,12 +27,15 @@
#include "resources/image.h"
#include "resources/imageloader.h"
+#include <SDL_gfxBlitFunc.h>
+
Graphics::Graphics():
mWidth(0),
mHeight(0),
mBpp(0),
mFullscreen(false),
- mHWAccel(false)
+ mHWAccel(false),
+ mBlitMode(BLIT_NORMAL)
{
}
@@ -183,7 +186,10 @@ bool Graphics::drawImage(Image *image, int srcX, int srcY, int dstX, int dstY,
srcRect.w = width;
srcRect.h = height;
- return !(SDL_BlitSurface(image->mSDLSurface, &srcRect, mTarget, &dstRect) < 0);
+ if (mBlitMode == BLIT_NORMAL)
+ return !(SDL_BlitSurface(image->mSDLSurface, &srcRect, mTarget, &dstRect) < 0);
+ else
+ return !(SDL_gfxBlitRGBA(image->mSDLSurface, &srcRect, mTarget, &dstRect) < 0);
}
void Graphics::drawImage(gcn::Image const *image, int srcX, int srcY,
diff --git a/src/graphics.h b/src/graphics.h
index 211fb901..344c31c3 100644
--- a/src/graphics.h
+++ b/src/graphics.h
@@ -73,6 +73,11 @@ struct ImageRect
class Graphics : public gcn::SDLGraphics
{
public:
+ enum BlitMode {
+ BLIT_NORMAL = 0,
+ BLIT_GFX
+ };
+
/**
* Constructor.
*/
@@ -182,6 +187,12 @@ class Graphics : public gcn::SDLGraphics
drawImageRect(area.x, area.y, area.width, area.height, imgRect);
}
+ void setBlitMode(BlitMode mode)
+ { mBlitMode = mode; }
+
+ BlitMode getBlitMode()
+ { return mBlitMode; }
+
/**
* Updates the screen. This is done by either copying the buffer to the
* screen or swapping pages.
@@ -211,6 +222,7 @@ class Graphics : public gcn::SDLGraphics
int mBpp;
bool mFullscreen;
bool mHWAccel;
+ BlitMode mBlitMode;
};
extern Graphics *graphics;
diff --git a/src/imagesprite.h b/src/imagesprite.h
index 83fcfa12..20f9fbef 100644
--- a/src/imagesprite.h
+++ b/src/imagesprite.h
@@ -34,11 +34,14 @@ public:
~ImageSprite();
- virtual void reset() {}
+ virtual bool reset()
+ { return false; }
- virtual void play(SpriteAction action) {}
+ virtual bool play(SpriteAction action)
+ { return false; }
- virtual void update(int time) {}
+ virtual bool update(int time)
+ { return false; }
virtual bool draw(Graphics* graphics, int posX, int posY) const;
@@ -48,10 +51,11 @@ public:
virtual int getHeight() const
{ return mImage->getHeight(); }
- virtual Image* getImage() const
+ virtual const Image* getImage() const
{ return mImage; }
- virtual void setDirection(SpriteDirection direction) {}
+ virtual bool setDirection(SpriteDirection direction)
+ { return false; }
int getNumberOfLayers()
{ return 1; }
diff --git a/src/sprite.h b/src/sprite.h
index d8345ab8..2bcd754a 100644
--- a/src/sprite.h
+++ b/src/sprite.h
@@ -33,19 +33,25 @@ class Sprite
/**
* Resets the sprite.
+ *
+ * @returns true if the sprite changed, false otherwise
*/
- virtual void reset() = 0;
+ virtual bool reset() = 0;
/**
- * Plays an action using the current direction
+ * Plays an action using the current direction.
+ *
+ * @returns true if the sprite changed, false otherwise
*/
- virtual void play(SpriteAction action) = 0;
+ virtual bool play(SpriteAction action) = 0;
/**
* Inform the animation of the passed time so that it can output the
* correct animation frame.
+ *
+ * @returns true if the sprite changed, false otherwise
*/
- virtual void update(int time) = 0;
+ virtual bool update(int time) = 0;
/**
* Draw the current animation frame at the coordinates given in screen
@@ -66,12 +72,14 @@ class Sprite
/**
* Returns a reference to the current image being drawn.
*/
- virtual Image* getImage() const = 0;
+ virtual const Image* getImage() const = 0;
/**
* Sets the direction.
+ *
+ * @returns true if the sprite changed, false otherwise
*/
- virtual void setDirection(SpriteDirection direction) = 0;
+ virtual bool setDirection(SpriteDirection direction) = 0;
/**
* Sets the alpha value of the animated sprite