From 3a28edfb7ac991ad70a7baf76f48218d9db89bcb Mon Sep 17 00:00:00 2001 From: Andrei Karas Date: Sun, 10 Jun 2012 16:54:18 +0300 Subject: Split ImageHelper to ImageHelper, SDLImageHelper, OpenGLImageHelper. --- src/resources/ambientlayer.cpp | 4 +- src/resources/image.cpp | 12 +- src/resources/image.h | 2 + src/resources/imagehelper.cpp | 471 +----------------------------------- src/resources/imagehelper.h | 107 +------- src/resources/openglimagehelper.cpp | 278 +++++++++++++++++++++ src/resources/openglimagehelper.h | 122 ++++++++++ src/resources/resourcemanager.cpp | 4 +- src/resources/sdlimagehelper.cpp | 280 +++++++++++++++++++++ src/resources/sdlimagehelper.h | 85 +++++++ 10 files changed, 793 insertions(+), 572 deletions(-) create mode 100644 src/resources/openglimagehelper.cpp create mode 100644 src/resources/openglimagehelper.h create mode 100644 src/resources/sdlimagehelper.cpp create mode 100644 src/resources/sdlimagehelper.h (limited to 'src/resources') diff --git a/src/resources/ambientlayer.cpp b/src/resources/ambientlayer.cpp index f2eaeab81..e51160efe 100644 --- a/src/resources/ambientlayer.cpp +++ b/src/resources/ambientlayer.cpp @@ -39,7 +39,7 @@ AmbientLayer::AmbientLayer(Image *img, float parallax, if (!mImage) return; - if (keepRatio && !ImageHelper::useOpenGL() + if (keepRatio && !imageHelper->useOpenGL() /*&& defaultScreenWidth != 0 && defaultScreenHeight != 0*/ && mainGraphics->mWidth != defaultScreenWidth @@ -106,7 +106,7 @@ void AmbientLayer::draw(Graphics *graphics, int x, int y) if (!mImage) return; - if (!ImageHelper::useOpenGL() || !mKeepRatio) + if (!imageHelper->useOpenGL() || !mKeepRatio) { graphics->drawImagePattern(mImage, static_cast(-mPosX), static_cast(-mPosY), x + static_cast(mPosX), diff --git a/src/resources/image.cpp b/src/resources/image.cpp index 5496a10d8..b060be6f4 100644 --- a/src/resources/image.cpp +++ b/src/resources/image.cpp @@ -37,6 +37,8 @@ #include "utils/stringutils.h" #include "resources/imagehelper.h" +#include "resources/openglimagehelper.h" +#include "resources/sdlimagehelper.h" #include "resources/subimage.h" #include @@ -56,7 +58,7 @@ Image::Image(SDL_Surface *image, bool hasAlphaChannel0, Uint8 *alphaChannel): mGLImage = 0; #endif - mUseAlphaCache = ImageHelper::mEnableAlphaCache; + mUseAlphaCache = SDLImageHelper::mEnableAlphaCache; mBounds.x = 0; mBounds.y = 0; @@ -165,7 +167,7 @@ bool Image::hasAlphaChannel() return mHasAlphaChannel; #ifdef USE_OPENGL - if (ImageHelper::mUseOpenGL) + if (OpenGLImageHelper::mUseOpenGL) return true; #endif @@ -232,7 +234,7 @@ void Image::setAlpha(float alpha) } else { - mSDLSurface = ImageHelper::SDLDuplicateSurface(mSDLSurface); + mSDLSurface = SDLImageHelper::SDLDuplicateSurface(mSDLSurface); } // logger->log("miss"); } @@ -310,7 +312,7 @@ Image* Image::SDLgetScaledImage(int width, int height) // and about freeing the given SDL_surface*. if (scaledSurface) { - scaledImage = ImageHelper::load(scaledSurface); + scaledImage = imageHelper->load(scaledSurface); SDL_FreeSurface(scaledSurface); } } @@ -321,7 +323,7 @@ Image *Image::getSubImage(int x, int y, int width, int height) { // Create a new clipped sub-image #ifdef USE_OPENGL - if (ImageHelper::mUseOpenGL) + if (OpenGLImageHelper::mUseOpenGL) { return new SubImage(this, mGLImage, x, y, width, height, mTexWidth, mTexHeight); diff --git a/src/resources/image.h b/src/resources/image.h index 4bee1f0ed..c7d2657bd 100644 --- a/src/resources/image.h +++ b/src/resources/image.h @@ -56,6 +56,8 @@ class Image : public Resource friend class CompoundSprite; friend class Graphics; friend class ImageHelper; + friend class OpenGLImageHelper; + friend class SDLImageHelper; #ifdef USE_OPENGL friend class OpenGLGraphics; friend class OpenGL1Graphics; diff --git a/src/resources/imagehelper.cpp b/src/resources/imagehelper.cpp index 9ee52267e..a70889acd 100644 --- a/src/resources/imagehelper.cpp +++ b/src/resources/imagehelper.cpp @@ -25,11 +25,6 @@ #include "resources/dye.h" #include "resources/resourcemanager.h" -#ifdef USE_OPENGL -#include "openglgraphics.h" -#include "opengl1graphics.h" -#endif - #include "client.h" #include "logger.h" #include "main.h" @@ -43,14 +38,8 @@ #include "debug.h" -#ifdef USE_OPENGL -int ImageHelper::mUseOpenGL = 0; -int ImageHelper::mTextureType = 0; -int ImageHelper::mInternalTextureType = GL_RGBA8; -int ImageHelper::mTextureSize = 0; -bool ImageHelper::mBlur = true; -#endif -bool ImageHelper::mEnableAlphaCache = false; +ImageHelper *imageHelper = nullptr; + bool ImageHelper::mEnableAlpha = true; Resource *ImageHelper::load(SDL_RWops *rw) @@ -69,198 +58,6 @@ Resource *ImageHelper::load(SDL_RWops *rw) return image; } -Resource *ImageHelper::load(SDL_RWops *rw, Dye const &dye) -{ - SDL_Surface *tmpImage = IMG_Load_RW(rw, 1); - - if (!tmpImage) - { - logger->log("Error, image load failed: %s", IMG_GetError()); - return nullptr; - } - - SDL_Surface *surf = nullptr; - SDL_PixelFormat rgba; - rgba.palette = nullptr; - rgba.BitsPerPixel = 32; - rgba.BytesPerPixel = 4; - rgba.colorkey = 0; - rgba.alpha = 255; - if (mUseOpenGL) - { - surf = convertTo32Bit(tmpImage); - SDL_FreeSurface(tmpImage); - - Uint32 *pixels = static_cast(surf->pixels); - DyePalette *pal = dye.getSPalete(); - - if (pal) - { - for (Uint32 *p_end = pixels + surf->w * surf->h; - pixels != p_end; ++pixels) - { - Uint8 *p = (Uint8 *)pixels; - const int alpha = *p & 255; - if (!alpha) - continue; - pal->replaceOGLColor(p); - } - } - else - { - for (Uint32 *p_end = pixels + surf->w * surf->h; - pixels != p_end; ++pixels) - { - const Uint32 p = *pixels; - const int alpha = (p >> 24) & 255; - if (!alpha) - continue; - int v[3]; - v[0] = (p) & 255; - v[1] = (p >> 8) & 255; - v[2] = (p >> 16 ) & 255; - dye.update(v); - *pixels = (v[0]) | (v[1] << 8) | (v[2] << 16) | (alpha << 24); - } - } - } - else - { - rgba.Rmask = 0xFF000000; rgba.Rloss = 0; rgba.Rshift = 24; - rgba.Gmask = 0x00FF0000; rgba.Gloss = 0; rgba.Gshift = 16; - rgba.Bmask = 0x0000FF00; rgba.Bloss = 0; rgba.Bshift = 8; - rgba.Amask = 0x000000FF; rgba.Aloss = 0; rgba.Ashift = 0; - - surf = SDL_ConvertSurface(tmpImage, &rgba, SDL_SWSURFACE); - SDL_FreeSurface(tmpImage); - - Uint32 *pixels = static_cast(surf->pixels); - DyePalette *pal = dye.getSPalete(); - - if (pal) - { - for (Uint32 *p_end = pixels + surf->w * surf->h; - pixels != p_end; ++pixels) - { - Uint8 *p = (Uint8 *)pixels; - const int alpha = *p & 255; - if (!alpha) - continue; - pal->replaceColor(p + 1); - } - } - else - { - for (Uint32 *p_end = pixels + surf->w * surf->h; - pixels != p_end; ++pixels) - { - const Uint32 p = *pixels; - const int alpha = p & 255; - if (!alpha) - continue; - int v[3]; - v[0] = (p >> 24) & 255; - v[1] = (p >> 16) & 255; - v[2] = (p >> 8 ) & 255; - dye.update(v); - *pixels = (v[0] << 24) | (v[1] << 16) | (v[2] << 8) | alpha; - } - } - } - - Image *image = load(surf); - SDL_FreeSurface(surf); - return image; -} - -Image *ImageHelper::load(SDL_Surface *tmpImage) -{ -#ifdef USE_OPENGL - if (mUseOpenGL) - return _GLload(tmpImage); -#endif - return _SDLload(tmpImage); -} - -Image *ImageHelper::createTextSurface(SDL_Surface *tmpImage, float alpha) -{ - if (!tmpImage) - return nullptr; - - Image *img; -#ifdef USE_OPENGL - if (mUseOpenGL) - { - img = _GLload(tmpImage); - if (img) - img->setAlpha(alpha); - return img; - } -#endif - - bool hasAlpha = false; - bool converted = false; - - const int sz = tmpImage->w * tmpImage->h; - - // The alpha channel to be filled with alpha values - Uint8 *alphaChannel = new Uint8[sz]; - - const SDL_PixelFormat * const fmt = tmpImage->format; - if (fmt->Amask) - { - for (int i = 0; i < sz; ++ i) - { - Uint32 c = (static_cast(tmpImage->pixels))[i]; - - unsigned v = (c & fmt->Amask) >> fmt->Ashift; - Uint8 a = (v << fmt->Aloss) + (v >> (8 - (fmt->Aloss << 1))); - - Uint8 a2 = static_cast(static_cast(a) * alpha); - - c &= ~fmt->Amask; - c |= ((a2 >> fmt->Aloss) << fmt->Ashift & fmt->Amask); - (static_cast(tmpImage->pixels))[i] = c; - - if (a != 255) - hasAlpha = true; - - alphaChannel[i] = a; - } - } - - SDL_Surface *image; - - // Convert the surface to the current display format - if (hasAlpha) - { - image = SDL_DisplayFormatAlpha(tmpImage); - } - else - { - image = SDL_DisplayFormat(tmpImage); - - // We also delete the alpha channel since - // it's not used. - delete [] alphaChannel; - alphaChannel = nullptr; - } - - if (!image) - { - logger->log1("Error: Image convert failed."); - delete [] alphaChannel; - return nullptr; - } - - if (converted) - SDL_FreeSurface(tmpImage); - - img = new Image(image, hasAlpha, alphaChannel); - img->mAlpha = alpha; - return img; -} - SDL_Surface* ImageHelper::convertTo32Bit(SDL_Surface* tmpImage) { if (!tmpImage) @@ -301,261 +98,6 @@ SDL_Surface* ImageHelper::convertTo32Bit(SDL_Surface* tmpImage) return SDL_ConvertSurface(tmpImage, &RGBAFormat, SDL_SWSURFACE); } -SDL_Surface* ImageHelper::SDLDuplicateSurface(SDL_Surface* tmpImage) -{ - if (!tmpImage || !tmpImage->format) - return nullptr; - - return SDL_ConvertSurface(tmpImage, tmpImage->format, SDL_SWSURFACE); -} - -Image *ImageHelper::_SDLload(SDL_Surface *tmpImage) -{ - if (!tmpImage) - return nullptr; - - bool hasAlpha = false; - bool converted = false; - - if (tmpImage->format->BitsPerPixel != 32) - { - tmpImage = convertTo32Bit(tmpImage); - - if (!tmpImage) - return nullptr; - converted = true; - } - - const int sz = tmpImage->w * tmpImage->h; - - // The alpha channel to be filled with alpha values - Uint8 *alphaChannel = new Uint8[sz]; - - // Figure out whether the image uses its alpha layer - if (!tmpImage->format->palette) - { - const SDL_PixelFormat * const fmt = tmpImage->format; - if (fmt->Amask) - { - for (int i = 0; i < sz; ++ i) - { - unsigned v = ((static_cast(tmpImage->pixels))[i] - & fmt->Amask) >> fmt->Ashift; - Uint8 a = (v << fmt->Aloss) + (v >> (8 - (fmt->Aloss << 1))); - - if (a != 255) - hasAlpha = true; - - alphaChannel[i] = a; - } - } - else - { - if (SDL_ALPHA_OPAQUE != 255) - { - hasAlpha = true; - memset(alphaChannel, SDL_ALPHA_OPAQUE, sz); - } - } - } - else - { - if (SDL_ALPHA_OPAQUE != 255) - { - hasAlpha = true; - memset(alphaChannel, SDL_ALPHA_OPAQUE, sz); - } - } - - SDL_Surface *image; - - // Convert the surface to the current display format - if (hasAlpha) - { - image = SDL_DisplayFormatAlpha(tmpImage); - } - else - { - image = SDL_DisplayFormat(tmpImage); - - // We also delete the alpha channel since - // it's not used. - delete [] alphaChannel; - alphaChannel = nullptr; - } - - if (!image) - { - logger->log1("Error: Image convert failed."); - delete [] alphaChannel; - return nullptr; - } - - if (converted) - SDL_FreeSurface(tmpImage); - - return new Image(image, hasAlpha, alphaChannel); -} - -#ifdef USE_OPENGL -int ImageHelper::powerOfTwo(int input) -{ - int value; - if (mTextureType == GL_TEXTURE_2D) - { - value = 1; - while (value < input && value < mTextureSize) - value <<= 1; - } - else - { - value = input; - } - return value >= mTextureSize ? mTextureSize : value; -} - -Image *ImageHelper::_GLload(SDL_Surface *tmpImage) -{ - if (!tmpImage) - return nullptr; - - // Flush current error flag. - glGetError(); - - int width = tmpImage->w; - int height = tmpImage->h; - int realWidth = powerOfTwo(width); - int realHeight = powerOfTwo(height); - - if (realWidth < width || realHeight < height) - { - logger->log("Warning: image too large, cropping to %dx%d texture!", - tmpImage->w, tmpImage->h); - } - - // Make sure the alpha channel is not used, but copied to destination - SDL_SetAlpha(tmpImage, 0, SDL_ALPHA_OPAQUE); - - // Determine 32-bit masks based on byte order - Uint32 rmask, gmask, bmask, amask; -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - rmask = 0xff000000; - gmask = 0x00ff0000; - bmask = 0x0000ff00; - amask = 0x000000ff; -#else - rmask = 0x000000ff; - gmask = 0x0000ff00; - bmask = 0x00ff0000; - amask = 0xff000000; -#endif - - SDL_Surface *oldImage = nullptr; - if (tmpImage->format->BitsPerPixel != 32 - || realWidth != width || realHeight != height - || rmask != tmpImage->format->Rmask - || gmask != tmpImage->format->Gmask - || amask != tmpImage->format->Amask) - { - oldImage = tmpImage; - tmpImage = SDL_CreateRGBSurface(SDL_SWSURFACE, realWidth, realHeight, - 32, rmask, gmask, bmask, amask); - - if (!tmpImage) - { - logger->log("Error, image convert failed: out of memory"); - return nullptr; - } - SDL_BlitSurface(oldImage, nullptr, tmpImage, nullptr); - } - - GLuint texture; - glGenTextures(1, &texture); - if (mUseOpenGL == 1) - OpenGLGraphics::bindTexture(mTextureType, texture); - else if (mUseOpenGL == 2) - OpenGL1Graphics::bindTexture(mTextureType, texture); - - if (SDL_MUSTLOCK(tmpImage)) - SDL_LockSurface(tmpImage); - - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - if (mBlur) - { - glTexParameteri(mTextureType, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(mTextureType, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } - else - { - glTexParameteri(mTextureType, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(mTextureType, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - } - - glTexImage2D(mTextureType, 0, mInternalTextureType, - tmpImage->w, tmpImage->h, - 0, GL_RGBA, GL_UNSIGNED_BYTE, tmpImage->pixels); - -/* - GLint compressed; - glGetTexLevelParameteriv(mTextureType, 0, - GL_TEXTURE_COMPRESSED_ARB, &compressed); - if (compressed) - logger->log("image compressed"); - else - logger->log("image not compressed"); -*/ - -#ifdef DEBUG_OPENGL_LEAKS - textures_count ++; -#endif - - if (SDL_MUSTLOCK(tmpImage)) - SDL_UnlockSurface(tmpImage); - - if (oldImage) - SDL_FreeSurface(tmpImage); - - GLenum error = glGetError(); - if (error) - { - std::string errmsg = "Unknown error"; - switch (error) - { - case GL_INVALID_ENUM: - errmsg = "GL_INVALID_ENUM"; - break; - case GL_INVALID_VALUE: - errmsg = "GL_INVALID_VALUE"; - break; - case GL_INVALID_OPERATION: - errmsg = "GL_INVALID_OPERATION"; - break; - case GL_STACK_OVERFLOW: - errmsg = "GL_STACK_OVERFLOW"; - break; - case GL_STACK_UNDERFLOW: - errmsg = "GL_STACK_UNDERFLOW"; - break; - case GL_OUT_OF_MEMORY: - errmsg = "GL_OUT_OF_MEMORY"; - break; - default: - break; - } - logger->log("Error: Image GL import failed: %s", errmsg.c_str()); - return nullptr; - } - - return new Image(texture, width, height, realWidth, realHeight); -} - -void ImageHelper::setLoadAsOpenGL(int useOpenGL) -{ - ImageHelper::mUseOpenGL = useOpenGL; -} - -#endif - void ImageHelper::dumpSurfaceFormat(SDL_Surface *image) { if (image->format) @@ -571,12 +113,3 @@ void ImageHelper::dumpSurfaceFormat(SDL_Surface *image) format->Gmask, format->Bmask, format->Amask); } } - -int ImageHelper::useOpenGL() -{ -#ifdef USE_OPENGL - return mUseOpenGL; -#else - return 0; -#endif -} diff --git a/src/resources/imagehelper.h b/src/resources/imagehelper.h index 680794625..b0cbca7e6 100644 --- a/src/resources/imagehelper.h +++ b/src/resources/imagehelper.h @@ -24,26 +24,11 @@ #define IMAGEHELPER_H #include "localconsts.h" -#include "main.h" #include "resources/resource.h" #include -#ifdef USE_OPENGL - -/* The definition of OpenGL extensions by SDL is giving problems with recent - * gl.h headers, since they also include these definitions. As we're not using - * extensions anyway it's safe to just disable the SDL version. - */ -//#define NO_SDL_GLEXT -#define GL_GLEXT_PROTOTYPES 1 - -#include -#endif - -#include - class Dye; class Image; @@ -52,17 +37,12 @@ struct Position; /** * Defines a class for loading and storing images. */ -class ImageHelper : public Resource +class ImageHelper { - friend class CompoundSprite; - friend class Graphics; - friend class Image; -#ifdef USE_OPENGL - friend class OpenGLGraphics; - friend class OpenGL1Graphics; -#endif - public: + virtual ~ImageHelper() + { } + /** * Loads an image from an SDL_RWops structure. * @@ -71,7 +51,7 @@ class ImageHelper : public Resource * @return NULL if an error occurred, a valid pointer * otherwise. */ - static Resource *load(SDL_RWops *rw); + Resource *load(SDL_RWops *rw); /** * Loads an image from an SDL_RWops structure and recolors it. @@ -82,89 +62,28 @@ class ImageHelper : public Resource * @return NULL if an error occurred, a valid pointer * otherwise. */ - static Resource *load(SDL_RWops *rw, Dye const &dye); + virtual Resource *load(SDL_RWops *rw, Dye const &dye) = 0; /** * Loads an image from an SDL surface. */ - static Image *load(SDL_Surface *); + virtual Image *load(SDL_Surface *) = 0; - static SDL_Surface *convertTo32Bit(SDL_Surface* tmpImage); + virtual Image *createTextSurface(SDL_Surface *tmpImage, + float alpha) = 0; - static Image *createTextSurface(SDL_Surface *tmpImage, float alpha); + virtual int useOpenGL() = 0; - static void SDLSetEnableAlphaCache(bool n) - { mEnableAlphaCache = n; } + SDL_Surface *convertTo32Bit(SDL_Surface* tmpImage); - static bool SDLGetEnableAlphaCache() - { return mEnableAlphaCache; } + void dumpSurfaceFormat(SDL_Surface *image); static void setEnableAlpha(bool n) { mEnableAlpha = n; } -#ifdef USE_OPENGL - - // OpenGL only public functions - - /** - * Sets the target image format. Use false for SDL and - * true for OpenGL. - */ - static void setLoadAsOpenGL(int useOpenGL); - - static int getLoadAsOpenGL() - { return mUseOpenGL; } - - static int getTextureType() - { return mTextureType; } - - static int getInternalTextureType() - { return mInternalTextureType; } - - static void setInternalTextureType(int n) - { mInternalTextureType = n; } - - static void setBlur(bool n) - { mBlur = n; } - - static int mTextureType; - - static int mInternalTextureType; - - static void dumpSurfaceFormat(SDL_Surface *image); - - static SDL_Surface* SDLDuplicateSurface(SDL_Surface* tmpImage); - -#endif - - /** - * Tells if the image was loaded using OpenGL or SDL - * @return true if OpenGL, false if SDL. - */ - static int useOpenGL(); - protected: - /** SDL_Surface to SDL_Surface Image loader */ - static Image *_SDLload(SDL_Surface *tmpImage); - - static bool mEnableAlphaCache; static bool mEnableAlpha; - - // ----------------------- - // OpenGL protected members - // ----------------------- -#ifdef USE_OPENGL - /** - * Returns the first power of two equal or bigger than the input. - */ - static int powerOfTwo(int input); - - static Image *_GLload(SDL_Surface *tmpImage); - - static int mUseOpenGL; - static int mTextureSize; - static bool mBlur; -#endif }; +extern ImageHelper *imageHelper; #endif diff --git a/src/resources/openglimagehelper.cpp b/src/resources/openglimagehelper.cpp new file mode 100644 index 000000000..1de5305c4 --- /dev/null +++ b/src/resources/openglimagehelper.cpp @@ -0,0 +1,278 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2012 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "resources/openglimagehelper.h" + +#ifdef USE_OPENGL + +#include "resources/dye.h" +#include "resources/resourcemanager.h" + +#include "openglgraphics.h" +#include "opengl1graphics.h" + +#include "client.h" +#include "logger.h" + +#include "utils/stringutils.h" + +#include "resources/image.h" + +#include +#include + +#include "debug.h" + +int OpenGLImageHelper::mTextureType = 0; +int OpenGLImageHelper::mInternalTextureType = GL_RGBA8; +int OpenGLImageHelper::mTextureSize = 0; +bool OpenGLImageHelper::mBlur = true; +int OpenGLImageHelper::mUseOpenGL = 0; + +Resource *OpenGLImageHelper::load(SDL_RWops *rw, Dye const &dye) +{ + SDL_Surface *tmpImage = IMG_Load_RW(rw, 1); + + if (!tmpImage) + { + logger->log("Error, image load failed: %s", IMG_GetError()); + return nullptr; + } + + SDL_Surface *surf = convertTo32Bit(tmpImage); + SDL_FreeSurface(tmpImage); + + Uint32 *pixels = static_cast(surf->pixels); + DyePalette *pal = dye.getSPalete(); + + if (pal) + { + for (Uint32 *p_end = pixels + surf->w * surf->h; + pixels != p_end; ++pixels) + { + Uint8 *p = (Uint8 *)pixels; + const int alpha = *p & 255; + if (!alpha) + continue; + pal->replaceOGLColor(p); + } + } + else + { + for (Uint32 *p_end = pixels + surf->w * surf->h; + pixels != p_end; ++pixels) + { + const Uint32 p = *pixels; + const int alpha = (p >> 24) & 255; + if (!alpha) + continue; + int v[3]; + v[0] = (p) & 255; + v[1] = (p >> 8) & 255; + v[2] = (p >> 16 ) & 255; + dye.update(v); + *pixels = (v[0]) | (v[1] << 8) | (v[2] << 16) | (alpha << 24); + } + } + + Image *image = load(surf); + SDL_FreeSurface(surf); + return image; +} + +Image *OpenGLImageHelper::load(SDL_Surface *tmpImage) +{ + return _GLload(tmpImage); +} + +Image *OpenGLImageHelper::createTextSurface(SDL_Surface *tmpImage, float alpha) +{ + if (!tmpImage) + return nullptr; + + Image *img = _GLload(tmpImage); + if (img) + img->setAlpha(alpha); + return img; +} + +int OpenGLImageHelper::powerOfTwo(int input) +{ + int value; + if (mTextureType == GL_TEXTURE_2D) + { + value = 1; + while (value < input && value < mTextureSize) + value <<= 1; + } + else + { + value = input; + } + return value >= mTextureSize ? mTextureSize : value; +} + +Image *OpenGLImageHelper::_GLload(SDL_Surface *tmpImage) +{ + if (!tmpImage) + return nullptr; + + // Flush current error flag. + glGetError(); + + int width = tmpImage->w; + int height = tmpImage->h; + int realWidth = powerOfTwo(width); + int realHeight = powerOfTwo(height); + + if (realWidth < width || realHeight < height) + { + logger->log("Warning: image too large, cropping to %dx%d texture!", + tmpImage->w, tmpImage->h); + } + + // Make sure the alpha channel is not used, but copied to destination + SDL_SetAlpha(tmpImage, 0, SDL_ALPHA_OPAQUE); + + // Determine 32-bit masks based on byte order + Uint32 rmask, gmask, bmask, amask; +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + rmask = 0xff000000; + gmask = 0x00ff0000; + bmask = 0x0000ff00; + amask = 0x000000ff; +#else + rmask = 0x000000ff; + gmask = 0x0000ff00; + bmask = 0x00ff0000; + amask = 0xff000000; +#endif + + SDL_Surface *oldImage = nullptr; + if (tmpImage->format->BitsPerPixel != 32 + || realWidth != width || realHeight != height + || rmask != tmpImage->format->Rmask + || gmask != tmpImage->format->Gmask + || amask != tmpImage->format->Amask) + { + oldImage = tmpImage; + tmpImage = SDL_CreateRGBSurface(SDL_SWSURFACE, realWidth, realHeight, + 32, rmask, gmask, bmask, amask); + + if (!tmpImage) + { + logger->log("Error, image convert failed: out of memory"); + return nullptr; + } + SDL_BlitSurface(oldImage, nullptr, tmpImage, nullptr); + } + + GLuint texture; + glGenTextures(1, &texture); + if (mUseOpenGL == 1) + OpenGLGraphics::bindTexture(mTextureType, texture); + else if (mUseOpenGL == 2) + OpenGL1Graphics::bindTexture(mTextureType, texture); + + if (SDL_MUSTLOCK(tmpImage)) + SDL_LockSurface(tmpImage); + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + if (mBlur) + { + glTexParameteri(mTextureType, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(mTextureType, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + else + { + glTexParameteri(mTextureType, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(mTextureType, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + + glTexImage2D(mTextureType, 0, mInternalTextureType, + tmpImage->w, tmpImage->h, + 0, GL_RGBA, GL_UNSIGNED_BYTE, tmpImage->pixels); + +/* + GLint compressed; + glGetTexLevelParameteriv(mTextureType, 0, + GL_TEXTURE_COMPRESSED_ARB, &compressed); + if (compressed) + logger->log("image compressed"); + else + logger->log("image not compressed"); +*/ + +#ifdef DEBUG_OPENGL_LEAKS + textures_count ++; +#endif + + if (SDL_MUSTLOCK(tmpImage)) + SDL_UnlockSurface(tmpImage); + + if (oldImage) + SDL_FreeSurface(tmpImage); + + GLenum error = glGetError(); + if (error) + { + std::string errmsg = "Unknown error"; + switch (error) + { + case GL_INVALID_ENUM: + errmsg = "GL_INVALID_ENUM"; + break; + case GL_INVALID_VALUE: + errmsg = "GL_INVALID_VALUE"; + break; + case GL_INVALID_OPERATION: + errmsg = "GL_INVALID_OPERATION"; + break; + case GL_STACK_OVERFLOW: + errmsg = "GL_STACK_OVERFLOW"; + break; + case GL_STACK_UNDERFLOW: + errmsg = "GL_STACK_UNDERFLOW"; + break; + case GL_OUT_OF_MEMORY: + errmsg = "GL_OUT_OF_MEMORY"; + break; + default: + break; + } + logger->log("Error: Image GL import failed: %s", errmsg.c_str()); + return nullptr; + } + + return new Image(texture, width, height, realWidth, realHeight); +} + +void OpenGLImageHelper::setLoadAsOpenGL(int useOpenGL) +{ + OpenGLImageHelper::mUseOpenGL = useOpenGL; +} + +int OpenGLImageHelper::useOpenGL() +{ + return mUseOpenGL; +} +#endif diff --git a/src/resources/openglimagehelper.h b/src/resources/openglimagehelper.h new file mode 100644 index 000000000..b27409040 --- /dev/null +++ b/src/resources/openglimagehelper.h @@ -0,0 +1,122 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2012 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef OPENGLIMAGEHELPER_H +#define OPENGLIMAGEHELPER_H + +#include "localconsts.h" +#include "main.h" + +#include "resources/imagehelper.h" + +#include + +#ifdef USE_OPENGL + +/* The definition of OpenGL extensions by SDL is giving problems with recent + * gl.h headers, since they also include these definitions. As we're not using + * extensions anyway it's safe to just disable the SDL version. + */ +//#define NO_SDL_GLEXT +#define GL_GLEXT_PROTOTYPES 1 + +#include +#endif + +class Dye; +class Image; + +/** + * Defines a class for loading and storing images. + */ +class OpenGLImageHelper : public ImageHelper +{ + friend class CompoundSprite; + friend class Graphics; + friend class Image; + + public: + virtual ~OpenGLImageHelper() + { } + + /** + * Loads an image from an SDL_RWops structure and recolors it. + * + * @param rw The SDL_RWops to load the image from. + * @param dye The dye used to recolor the image. + * + * @return NULL if an error occurred, a valid pointer + * otherwise. + */ + Resource *load(SDL_RWops *rw, Dye const &dye); + + /** + * Loads an image from an SDL surface. + */ + Image *load(SDL_Surface *); + + Image *createTextSurface(SDL_Surface *tmpImage, float alpha); + + // OpenGL only public functions + + /** + * Sets the target image format. Use false for SDL and + * true for OpenGL. + */ + static void setLoadAsOpenGL(int useOpenGL); + + static int getTextureType() + { return mTextureType; } + + static int getInternalTextureType() + { return mInternalTextureType; } + + static void setInternalTextureType(int n) + { mInternalTextureType = n; } + + static void setBlur(bool n) + { mBlur = n; } + + static int mTextureType; + + static int mInternalTextureType; + + /** + * Tells if the image was loaded using OpenGL or SDL + * @return true if OpenGL, false if SDL. + */ + int useOpenGL(); + + protected: + /** + * Returns the first power of two equal or bigger than the input. + */ + int powerOfTwo(int input); + + Image *_GLload(SDL_Surface *tmpImage); + + static int mUseOpenGL; + static int mTextureSize; + static bool mBlur; +}; + +#endif diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp index 62a604ebe..37975cf16 100644 --- a/src/resources/resourcemanager.cpp +++ b/src/resources/resourcemanager.cpp @@ -457,8 +457,8 @@ struct DyedImageLoader delete d; return nullptr; } - Resource *res = d ? ImageHelper::load(rw, *d) - : ImageHelper::load(rw); + Resource *res = d ? imageHelper->load(rw, *d) + : imageHelper->load(rw); delete d; return res; } diff --git a/src/resources/sdlimagehelper.cpp b/src/resources/sdlimagehelper.cpp new file mode 100644 index 000000000..66e1bc823 --- /dev/null +++ b/src/resources/sdlimagehelper.cpp @@ -0,0 +1,280 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2012 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "resources/sdlimagehelper.h" + +#include "resources/dye.h" +#include "resources/resourcemanager.h" + +#include "client.h" +#include "logger.h" +#include "main.h" + +#include "utils/stringutils.h" + +#include "resources/image.h" + +#include +#include + +#include "debug.h" + +bool SDLImageHelper::mEnableAlphaCache = false; + +Resource *SDLImageHelper::load(SDL_RWops *rw, Dye const &dye) +{ + SDL_Surface *tmpImage = IMG_Load_RW(rw, 1); + + if (!tmpImage) + { + logger->log("Error, image load failed: %s", IMG_GetError()); + return nullptr; + } + + SDL_Surface *surf = nullptr; + SDL_PixelFormat rgba; + rgba.palette = nullptr; + rgba.BitsPerPixel = 32; + rgba.BytesPerPixel = 4; + rgba.colorkey = 0; + rgba.alpha = 255; + rgba.Rmask = 0xFF000000; rgba.Rloss = 0; rgba.Rshift = 24; + rgba.Gmask = 0x00FF0000; rgba.Gloss = 0; rgba.Gshift = 16; + rgba.Bmask = 0x0000FF00; rgba.Bloss = 0; rgba.Bshift = 8; + rgba.Amask = 0x000000FF; rgba.Aloss = 0; rgba.Ashift = 0; + + surf = SDL_ConvertSurface(tmpImage, &rgba, SDL_SWSURFACE); + SDL_FreeSurface(tmpImage); + + Uint32 *pixels = static_cast(surf->pixels); + DyePalette *pal = dye.getSPalete(); + + if (pal) + { + for (Uint32 *p_end = pixels + surf->w * surf->h; + pixels != p_end; ++pixels) + { + Uint8 *p = (Uint8 *)pixels; + const int alpha = *p & 255; + if (!alpha) + continue; + pal->replaceColor(p + 1); + } + } + else + { + for (Uint32 *p_end = pixels + surf->w * surf->h; + pixels != p_end; ++pixels) + { + const Uint32 p = *pixels; + const int alpha = p & 255; + if (!alpha) + continue; + int v[3]; + v[0] = (p >> 24) & 255; + v[1] = (p >> 16) & 255; + v[2] = (p >> 8 ) & 255; + dye.update(v); + *pixels = (v[0] << 24) | (v[1] << 16) | (v[2] << 8) | alpha; + } + } + + Image *image = load(surf); + SDL_FreeSurface(surf); + return image; +} + +Image *SDLImageHelper::load(SDL_Surface *tmpImage) +{ + return _SDLload(tmpImage); +} + +Image *SDLImageHelper::createTextSurface(SDL_Surface *tmpImage, float alpha) +{ + if (!tmpImage) + return nullptr; + + Image *img; + + bool hasAlpha = false; + bool converted = false; + + const int sz = tmpImage->w * tmpImage->h; + + // The alpha channel to be filled with alpha values + Uint8 *alphaChannel = new Uint8[sz]; + + const SDL_PixelFormat * const fmt = tmpImage->format; + if (fmt->Amask) + { + for (int i = 0; i < sz; ++ i) + { + Uint32 c = (static_cast(tmpImage->pixels))[i]; + + unsigned v = (c & fmt->Amask) >> fmt->Ashift; + Uint8 a = (v << fmt->Aloss) + (v >> (8 - (fmt->Aloss << 1))); + + Uint8 a2 = static_cast(static_cast(a) * alpha); + + c &= ~fmt->Amask; + c |= ((a2 >> fmt->Aloss) << fmt->Ashift & fmt->Amask); + (static_cast(tmpImage->pixels))[i] = c; + + if (a != 255) + hasAlpha = true; + + alphaChannel[i] = a; + } + } + + SDL_Surface *image; + + // Convert the surface to the current display format + if (hasAlpha) + { + image = SDL_DisplayFormatAlpha(tmpImage); + } + else + { + image = SDL_DisplayFormat(tmpImage); + + // We also delete the alpha channel since + // it's not used. + delete [] alphaChannel; + alphaChannel = nullptr; + } + + if (!image) + { + logger->log1("Error: Image convert failed."); + delete [] alphaChannel; + return nullptr; + } + + if (converted) + SDL_FreeSurface(tmpImage); + + img = new Image(image, hasAlpha, alphaChannel); + img->mAlpha = alpha; + return img; +} + +SDL_Surface* SDLImageHelper::SDLDuplicateSurface(SDL_Surface* tmpImage) +{ + if (!tmpImage || !tmpImage->format) + return nullptr; + + return SDL_ConvertSurface(tmpImage, tmpImage->format, SDL_SWSURFACE); +} + +Image *SDLImageHelper::_SDLload(SDL_Surface *tmpImage) +{ + if (!tmpImage) + return nullptr; + + bool hasAlpha = false; + bool converted = false; + + if (tmpImage->format->BitsPerPixel != 32) + { + tmpImage = convertTo32Bit(tmpImage); + + if (!tmpImage) + return nullptr; + converted = true; + } + + const int sz = tmpImage->w * tmpImage->h; + + // The alpha channel to be filled with alpha values + Uint8 *alphaChannel = new Uint8[sz]; + + // Figure out whether the image uses its alpha layer + if (!tmpImage->format->palette) + { + const SDL_PixelFormat * const fmt = tmpImage->format; + if (fmt->Amask) + { + for (int i = 0; i < sz; ++ i) + { + unsigned v = ((static_cast(tmpImage->pixels))[i] + & fmt->Amask) >> fmt->Ashift; + Uint8 a = (v << fmt->Aloss) + (v >> (8 - (fmt->Aloss << 1))); + + if (a != 255) + hasAlpha = true; + + alphaChannel[i] = a; + } + } + else + { + if (SDL_ALPHA_OPAQUE != 255) + { + hasAlpha = true; + memset(alphaChannel, SDL_ALPHA_OPAQUE, sz); + } + } + } + else + { + if (SDL_ALPHA_OPAQUE != 255) + { + hasAlpha = true; + memset(alphaChannel, SDL_ALPHA_OPAQUE, sz); + } + } + + SDL_Surface *image; + + // Convert the surface to the current display format + if (hasAlpha) + { + image = SDL_DisplayFormatAlpha(tmpImage); + } + else + { + image = SDL_DisplayFormat(tmpImage); + + // We also delete the alpha channel since + // it's not used. + delete [] alphaChannel; + alphaChannel = nullptr; + } + + if (!image) + { + logger->log1("Error: Image convert failed."); + delete [] alphaChannel; + return nullptr; + } + + if (converted) + SDL_FreeSurface(tmpImage); + + return new Image(image, hasAlpha, alphaChannel); +} + +int SDLImageHelper::useOpenGL() +{ + return 0; +} diff --git a/src/resources/sdlimagehelper.h b/src/resources/sdlimagehelper.h new file mode 100644 index 000000000..cecbf6c93 --- /dev/null +++ b/src/resources/sdlimagehelper.h @@ -0,0 +1,85 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2012 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SDLIMAGEHELPER_H +#define SDLIMAGEHELPER_H + +#include "localconsts.h" + +#include "resources/imagehelper.h" + +#include + +class Dye; +class Image; + +/** + * Defines a class for loading and storing images. + */ +class SDLImageHelper : public ImageHelper +{ + friend class Image; + + public: + virtual ~SDLImageHelper() + { } + + /** + * Loads an image from an SDL_RWops structure and recolors it. + * + * @param rw The SDL_RWops to load the image from. + * @param dye The dye used to recolor the image. + * + * @return NULL if an error occurred, a valid pointer + * otherwise. + */ + Resource *load(SDL_RWops *rw, Dye const &dye); + + /** + * Loads an image from an SDL surface. + */ + Image *load(SDL_Surface *); + + Image *createTextSurface(SDL_Surface *tmpImage, float alpha); + + static void SDLSetEnableAlphaCache(bool n) + { mEnableAlphaCache = n; } + + static bool SDLGetEnableAlphaCache() + { return mEnableAlphaCache; } + + /** + * Tells if the image was loaded using OpenGL or SDL + * @return true if OpenGL, false if SDL. + */ + int useOpenGL(); + + static SDL_Surface* SDLDuplicateSurface(SDL_Surface* tmpImage); + + protected: + /** SDL_Surface to SDL_Surface Image loader */ + Image *_SDLload(SDL_Surface *tmpImage); + + static bool mEnableAlphaCache; +}; + +#endif -- cgit v1.2.3-70-g09d2