From 0d3d7c908ef6d294b14f55f09c9d83767fbc5f32 Mon Sep 17 00:00:00 2001 From: Andrei Karas Date: Tue, 12 Oct 2010 19:59:25 +0300 Subject: Implement opacity cache for SDL surfaces. Enabled by default. Can be disabled in configuration option "alphaCache" if set it to 0. Reviewed-by: Bertram --- src/resources/image.cpp | 94 ++++++++++++++++++++++++++++++++++++--- src/resources/image.h | 25 +++++++++-- src/resources/resourcemanager.cpp | 15 +++++++ src/resources/resourcemanager.h | 6 +++ 4 files changed, 130 insertions(+), 10 deletions(-) (limited to 'src/resources') diff --git a/src/resources/image.cpp b/src/resources/image.cpp index 82799bce..cd6bda15 100644 --- a/src/resources/image.cpp +++ b/src/resources/image.cpp @@ -22,6 +22,7 @@ #include "resources/image.h" #include "resources/dye.h" +#include "resources/resourcemanager.h" #ifdef USE_OPENGL #include "openglgraphics.h" @@ -37,6 +38,7 @@ bool Image::mUseOpenGL = false; int Image::mTextureType = 0; int Image::mTextureSize = 0; #endif +bool Image::mEnableAlphaCache = false; Image::Image(SDL_Surface *image, bool hasAlphaChannel, Uint8 *alphaChannel): mAlpha(1.0f), @@ -48,6 +50,8 @@ Image::Image(SDL_Surface *image, bool hasAlphaChannel, Uint8 *alphaChannel): mGLImage = 0; #endif + mUseAlphaCache = Image::mEnableAlphaCache; + mBounds.x = 0; mBounds.y = 0; @@ -71,6 +75,7 @@ Image::Image(GLuint glimage, int width, int height, int texWidth, int texHeight) mHasAlphaChannel(true), mSDLSurface(0), mAlphaChannel(0), + mUseAlphaCache(false), mGLImage(glimage), mTexWidth(texWidth), mTexHeight(texHeight) @@ -166,12 +171,28 @@ Image *Image::load(SDL_Surface *tmpImage) return _SDLload(tmpImage); } +void Image::cleanCache() +{ + ResourceManager *resman = ResourceManager::getInstance(); + + for (std::map::iterator + i = mAlphaCache.begin(), i_end = mAlphaCache.end(); + i != i_end; ++i) + { + if (mSDLSurface != i->second) + resman->scheduleDelete(i->second); + i->second = 0; + } + mAlphaCache.clear(); +} + void Image::unload() { mLoaded = false; if (mSDLSurface) { + cleanCache(); // Free the image surface. SDL_FreeSurface(mSDLSurface); mSDLSurface = NULL; @@ -211,6 +232,14 @@ bool Image::hasAlphaChannel() return false; } +SDL_Surface *Image::getByAlpha(float alpha) +{ + std::map::iterator it = mAlphaCache.find(alpha); + if (it != mAlphaCache.end()) + return (*it).second; + return 0; +} + void Image::setAlpha(float alpha) { if (mAlpha == alpha) @@ -219,10 +248,34 @@ void Image::setAlpha(float alpha) if (alpha < 0.0f || alpha > 1.0f) return; - mAlpha = alpha; - if (mSDLSurface) { + if (mUseAlphaCache) + { + SDL_Surface *surface = getByAlpha(mAlpha); + if (!surface) + { + if (mAlphaCache.size() > 100) + cleanCache(); + + mAlphaCache[mAlpha] = mSDLSurface; + } + surface = getByAlpha(alpha); + if (surface) + { + mAlphaCache.erase(alpha); + mSDLSurface = surface; + mAlpha = alpha; + return; + } + else + { + mSDLSurface = Image::duplicateSurface(mSDLSurface); + } + } + + mAlpha = alpha; + if (!hasAlphaChannel()) { // Set the alpha value this image is drawn at @@ -263,6 +316,10 @@ void Image::setAlpha(float alpha) SDL_UnlockSurface(mSDLSurface); } } + else + { + mAlpha = alpha; + } } Image* Image::SDLmerge(Image *image, int x, int y) @@ -371,6 +428,14 @@ Image* Image::SDLgetScaledImage(int width, int height) return scaledImage; } +SDL_Surface* Image::duplicateSurface(SDL_Surface* tmpImage) +{ + if (!tmpImage || !tmpImage->format) + return NULL; + + return SDL_ConvertSurface(tmpImage, tmpImage->format, SDL_SWSURFACE); +} + Image *Image::_SDLload(SDL_Surface *tmpImage) { if (!tmpImage) @@ -560,25 +625,40 @@ Image *Image::getSubImage(int x, int y, int width, int height) return new SubImage(this, mSDLSurface, x, y, width, height); } +void Image::terminateAlphaCache() +{ + cleanCache(); + mUseAlphaCache = false; +} + //============================================================================ // SubImage Class //============================================================================ SubImage::SubImage(Image *parent, SDL_Surface *image, - int x, int y, int width, int height): + int x, int y, int width, int height): Image(image), mParent(parent) { - mParent->incRef(); - - mHasAlphaChannel = mParent->hasAlphaChannel(); - mAlphaChannel = mParent->SDLgetAlphaChannel(); + if (mParent) + { + mParent->incRef(); + mParent->terminateAlphaCache(); + mHasAlphaChannel = mParent->hasAlphaChannel(); + mAlphaChannel = mParent->SDLgetAlphaChannel(); + } + else + { + mHasAlphaChannel = false; + mAlphaChannel = 0; + } // Set up the rectangle. mBounds.x = x; mBounds.y = y; mBounds.w = width; mBounds.h = height; + mUseAlphaCache = false; } #ifdef USE_OPENGL diff --git a/src/resources/image.h b/src/resources/image.h index 3e8ad551..815b7764 100644 --- a/src/resources/image.h +++ b/src/resources/image.h @@ -39,6 +39,8 @@ #include #endif +#include + class Dye; class Position; @@ -169,6 +171,15 @@ class Image : public Resource Uint8 *SDLgetAlphaChannel() const { return mAlphaChannel; } + SDL_Surface* duplicateSurface(SDL_Surface* tmpImage); + + void cleanCache(); + + void terminateAlphaCache(); + + static void setEnableAlphaCache(bool n) + { mEnableAlphaCache = n; } + #ifdef USE_OPENGL // OpenGL only public functions @@ -208,14 +219,22 @@ class Image : public Resource /** SDL_Surface to SDL_Surface Image loader */ static Image *_SDLload(SDL_Surface *tmpImage); + SDL_Surface *getByAlpha(float alpha); + SDL_Surface *mSDLSurface; /** Alpha Channel pointer used for 32bit based SDL surfaces */ Uint8 *mAlphaChannel; - // ----------------------- - // OpenGL protected members - // ----------------------- + std::map mAlphaCache; + + bool mUseAlphaCache; + + static bool mEnableAlphaCache; + + // ----------------------- + // OpenGL protected members + // ----------------------- #ifdef USE_OPENGL /** * OpenGL Constructor. diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp index c63b626e..00e4726e 100644 --- a/src/resources/resourcemanager.cpp +++ b/src/resources/resourcemanager.cpp @@ -533,3 +533,18 @@ SDL_Surface *ResourceManager::loadSDLSurface(const std::string &filename) return tmp; } + +void ResourceManager::scheduleDelete(SDL_Surface* surface) +{ + mDeletedSurfaces.insert(surface); +} + +void ResourceManager::clearScheduled() +{ + for (std::set::iterator i = mDeletedSurfaces.begin(), + i_end = mDeletedSurfaces.end(); i != i_end; ++i) + { + SDL_FreeSurface(*i); + } + mDeletedSurfaces.clear(); +} diff --git a/src/resources/resourcemanager.h b/src/resources/resourcemanager.h index 28ab4725..870182e4 100644 --- a/src/resources/resourcemanager.h +++ b/src/resources/resourcemanager.h @@ -26,6 +26,7 @@ #include #include #include +#include class Image; class ImageSet; @@ -205,6 +206,10 @@ class ResourceManager */ SDL_Surface *loadSDLSurface(const std::string &filename); + void scheduleDelete(SDL_Surface* surface); + + void clearScheduled(); + /** * Returns an instance of the class, creating one if it does not * already exist. @@ -227,6 +232,7 @@ class ResourceManager static ResourceManager *instance; typedef std::map Resources; typedef Resources::iterator ResourceIterator; + std::set mDeletedSurfaces; Resources mResources; Resources mOrphanedResources; time_t mOldestOrphan; -- cgit v1.2.3-70-g09d2