diff options
-rw-r--r-- | src/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/graphicsmanager.cpp | 20 | ||||
-rw-r--r-- | src/render/graphics.cpp | 19 | ||||
-rw-r--r-- | src/render/safeopenglgraphics.cpp | 24 | ||||
-rw-r--r-- | src/resources/image.cpp | 9 | ||||
-rw-r--r-- | src/resources/image.h | 7 | ||||
-rw-r--r-- | src/resources/safeopenglimagehelper.cpp | 475 | ||||
-rw-r--r-- | src/resources/safeopenglimagehelper.h | 159 |
9 files changed, 693 insertions, 24 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index aad4324d5..27ed1dbef 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -703,6 +703,8 @@ SET(SRCS resources/resource.h resources/resourcemanager.cpp resources/resourcemanager.h + resources/safeopenglimagehelper.cpp + resources/safeopenglimagehelper.h resources/sdl2imagehelper.cpp resources/sdl2imagehelper.h resources/sdl2softwareimagehelper.cpp diff --git a/src/Makefile.am b/src/Makefile.am index fc2d12975..67269db97 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -357,6 +357,8 @@ SRC += events/actionevent.h \ resources/resource.h \ resources/resourcemanager.cpp \ resources/resourcemanager.h \ + resources/safeopenglimagehelper.cpp \ + resources/safeopenglimagehelper.h \ resources/sdl2imagehelper.cpp \ resources/sdl2imagehelper.h \ resources/sdl2softwareimagehelper.cpp \ diff --git a/src/graphicsmanager.cpp b/src/graphicsmanager.cpp index 90b1c5a69..129ad966d 100644 --- a/src/graphicsmanager.cpp +++ b/src/graphicsmanager.cpp @@ -61,9 +61,11 @@ #ifdef USE_OPENGL #include "resources/fboinfo.h" #include "resources/openglimagehelper.h" - +#ifndef ANDROID +#include "resources/safeopenglimagehelper.h" +#endif // ANDROID #include "render/mglfunctions.h" -#endif +#endif // USE_OPENGL #include "resources/sdlimagehelper.h" @@ -289,7 +291,7 @@ int GraphicsManager::detectGraphics() #define RENDER_GLES2_OPENGL_INIT #else // defined(ANDROID) #define RENDER_SAFE_OPENGL_INIT \ - imageHelper = new OpenGLImageHelper; \ + imageHelper = new SafeOpenGLImageHelper; \ surfaceImageHelper = new SurfaceImageHelper; \ mainGraphics = new SafeOpenGLGraphics; \ mUseTextureSampler = false; @@ -494,6 +496,9 @@ void GraphicsManager::initGraphics() openGLMode = intToRenderType(config.getIntValue("opengl")); #ifdef USE_OPENGL OpenGLImageHelper::setBlur(config.getBoolValue("blur")); +#ifndef ANDROID + SafeOpenGLImageHelper::setBlur(config.getBoolValue("blur")); +#endif // ANDROID SurfaceImageHelper::SDLSetEnableAlphaCache( config.getBoolValue("alphaCache") && !openGLMode); ImageHelper::setEnableAlpha((config.getFloatValue("guialpha") != 1.0F || @@ -786,11 +791,17 @@ void GraphicsManager::updateTextureFormat() const config.getBoolValue("newtextures")) { OpenGLImageHelper::setInternalTextureType(GL_RGBA); +#ifndef ANDROID + SafeOpenGLImageHelper::setInternalTextureType(GL_RGBA); +#endif logger->log1("using RGBA texture format"); } else { OpenGLImageHelper::setInternalTextureType(4); +#ifndef ANDROID + SafeOpenGLImageHelper::setInternalTextureType(4); +#endif logger->log1("using 4 texture format"); } } @@ -1365,6 +1376,9 @@ void GraphicsManager::createTextureSampler() } } OpenGLImageHelper::setUseTextureSampler(mUseTextureSampler); +#ifndef ANDROID + SafeOpenGLImageHelper::setUseTextureSampler(false); +#endif } GLenum GraphicsManager::getLastError() diff --git a/src/render/graphics.cpp b/src/render/graphics.cpp index a8dde9626..f038fdfff 100644 --- a/src/render/graphics.cpp +++ b/src/render/graphics.cpp @@ -77,11 +77,14 @@ #include "resources/imagehelper.h" #ifdef USE_OPENGL #include "resources/openglimagehelper.h" -#if defined(__native_client__) +#ifndef ANDROID +#include "resources/safeopenglimagehelper.h" +#endif // ANDROID +#ifdef __native_client__ #include "render/naclfunctions.h" #include "render/naclgles.h" -#endif -#endif +#endif // __native_client__ +#endif // USE_OPENGL #ifdef USE_OPENGL #ifdef __APPLE__ @@ -332,12 +335,20 @@ bool Graphics::setOpenGLMode() OpenGLImageHelper::mTextureSize = texSize; logger->log("OpenGL texture size: %d pixels (rectangle textures)", OpenGLImageHelper::mTextureSize); +#ifndef ANDROID + SafeOpenGLImageHelper::mTextureType = GL_TEXTURE_RECTANGLE_ARB; + SafeOpenGLImageHelper::mTextureSize = texSize; +#endif } else { - OpenGLImageHelper::mTextureType = GL_TEXTURE_2D; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texSize); + OpenGLImageHelper::mTextureType = GL_TEXTURE_2D; OpenGLImageHelper::mTextureSize = texSize; +#ifndef ANDROID + SafeOpenGLImageHelper::mTextureType = GL_TEXTURE_2D; + SafeOpenGLImageHelper::mTextureSize = texSize; +#endif logger->log("OpenGL texture size: %d pixels", OpenGLImageHelper::mTextureSize); } diff --git a/src/render/safeopenglgraphics.cpp b/src/render/safeopenglgraphics.cpp index f7638c5a1..f2609c299 100644 --- a/src/render/safeopenglgraphics.cpp +++ b/src/render/safeopenglgraphics.cpp @@ -30,7 +30,7 @@ #include "resources/image.h" #include "resources/imagerect.h" -#include "resources/openglimagehelper.h" +#include "resources/safeopenglimagehelper.h" #include "utils/sdlcheckutils.h" @@ -81,7 +81,7 @@ static inline void drawQuad(const Image *image, const int dstX, const int dstY, const int width, const int height) { - if (OpenGLImageHelper::mTextureType == GL_TEXTURE_2D) + if (SafeOpenGLImageHelper::mTextureType == GL_TEXTURE_2D) { const float tw = static_cast<float>(image->mTexWidth); const float th = static_cast<float>(image->mTexHeight); @@ -127,7 +127,7 @@ static inline void drawRescaledQuad(const Image *const image, const int desiredWidth, const int desiredHeight) { - if (OpenGLImageHelper::mTextureType == GL_TEXTURE_2D) + if (SafeOpenGLImageHelper::mTextureType == GL_TEXTURE_2D) { const float tw = static_cast<float>(image->mTexWidth); const float th = static_cast<float>(image->mTexHeight); @@ -173,7 +173,7 @@ void SafeOpenGLGraphics::drawImageInline(const Image *const image, return; setColorAlpha(image->mAlpha); - bindTexture(OpenGLImageHelper::mTextureType, image->mGLImage); + bindTexture(SafeOpenGLImageHelper::mTextureType, image->mGLImage); setTexturingAndBlending(true); const SDL_Rect &bounds = image->mBounds; @@ -192,7 +192,7 @@ void SafeOpenGLGraphics::copyImage(const Image *const image, void SafeOpenGLGraphics::testDraw() { - if (OpenGLImageHelper::mTextureType == GL_TEXTURE_2D) + if (SafeOpenGLImageHelper::mTextureType == GL_TEXTURE_2D) { glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.781250f); @@ -228,7 +228,7 @@ void SafeOpenGLGraphics::drawImageCached(const Image *const image, return; setColorAlpha(image->mAlpha); - bindTexture(OpenGLImageHelper::mTextureType, image->mGLImage); + bindTexture(SafeOpenGLImageHelper::mTextureType, image->mGLImage); setTexturingAndBlending(true); const SDL_Rect &bounds = image->mBounds; @@ -256,7 +256,7 @@ void SafeOpenGLGraphics::drawPatternCached(const Image *const image, const int srcY = imageRect.y; setColorAlpha(image->mAlpha); - bindTexture(OpenGLImageHelper::mTextureType, image->mGLImage); + bindTexture(SafeOpenGLImageHelper::mTextureType, image->mGLImage); setTexturingAndBlending(true); // Draw a set of textured rectangles @@ -300,7 +300,7 @@ void SafeOpenGLGraphics::drawRescaledImage(const Image *const image, } setColorAlpha(image->mAlpha); - bindTexture(OpenGLImageHelper::mTextureType, image->mGLImage); + bindTexture(SafeOpenGLImageHelper::mTextureType, image->mGLImage); setTexturingAndBlending(true); // Draw a textured quad. @@ -335,7 +335,7 @@ void SafeOpenGLGraphics::drawPatternInline(const Image *const image, const int srcY = imageRect.y; setColorAlpha(image->mAlpha); - bindTexture(OpenGLImageHelper::mTextureType, image->mGLImage); + bindTexture(SafeOpenGLImageHelper::mTextureType, image->mGLImage); setTexturingAndBlending(true); // Draw a set of textured rectangles @@ -375,7 +375,7 @@ void SafeOpenGLGraphics::drawRescaledPattern(const Image *const image, const int srcY = imageRect.y; setColorAlpha(image->mAlpha); - bindTexture(OpenGLImageHelper::mTextureType, image->mGLImage); + bindTexture(SafeOpenGLImageHelper::mTextureType, image->mGLImage); setTexturingAndBlending(true); // Draw a set of textured rectangles @@ -676,7 +676,7 @@ void SafeOpenGLGraphics::setTexturingAndBlending(const bool enable) { if (!mTexture) { - glEnable(OpenGLImageHelper::mTextureType); + glEnable(SafeOpenGLImageHelper::mTextureType); mTexture = true; } @@ -702,7 +702,7 @@ void SafeOpenGLGraphics::setTexturingAndBlending(const bool enable) if (mTexture) { - glDisable(OpenGLImageHelper::mTextureType); + glDisable(SafeOpenGLImageHelper::mTextureType); mTexture = false; } } diff --git a/src/resources/image.cpp b/src/resources/image.cpp index 8b952779c..c196b217c 100644 --- a/src/resources/image.cpp +++ b/src/resources/image.cpp @@ -28,7 +28,10 @@ #ifdef USE_OPENGL #include "resources/openglimagehelper.h" -#endif +#ifndef ANDROID +#include "resources/safeopenglimagehelper.h" +#endif // ANDROID +#endif // USE_OPENGL #include "resources/sdlimagehelper.h" #include "resources/subimage.h" @@ -36,9 +39,9 @@ #ifdef USE_SDL2 #include <SDL2_rotozoom.h> -#else +#else // USE_SDL2 #include <SDL_rotozoom.h> -#endif +#endif // USE_SDL2 #include "debug.h" diff --git a/src/resources/image.h b/src/resources/image.h index 804df4c2e..0740864b7 100644 --- a/src/resources/image.h +++ b/src/resources/image.h @@ -55,7 +55,6 @@ class Image notfinal : public Resource friend class CompoundSprite; friend class Graphics; friend class ImageHelper; - friend class OpenGLImageHelper; friend class SDLGraphics; friend class SDLImageHelper; friend class SurfaceGraphics; @@ -73,7 +72,11 @@ class Image notfinal : public Resource friend class NormalOpenGLGraphics; friend class NullOpenGLGraphics; friend class SafeOpenGLGraphics; -#endif + friend class OpenGLImageHelper; +#ifndef ANDROID + friend class SafeOpenGLImageHelper; +#endif // ANDROID +#endif // USE_OPENGL public: A_DELETE_COPY(Image) diff --git a/src/resources/safeopenglimagehelper.cpp b/src/resources/safeopenglimagehelper.cpp new file mode 100644 index 000000000..1271b7e1b --- /dev/null +++ b/src/resources/safeopenglimagehelper.cpp @@ -0,0 +1,475 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2015 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 <http://www.gnu.org/licenses/>. + */ + +#include "resources/safeopenglimagehelper.h" + +#ifdef USE_OPENGL + +#include "graphicsmanager.h" +#include "logger.h" + +#include "render/mgl.h" +#include "render/mglcheck.h" +#include "render/mobileopengl2graphics.h" +#include "render/mobileopenglgraphics.h" +#include "render/modernopenglgraphics.h" +#include "render/normalopenglgraphics.h" +#include "render/safeopenglgraphics.h" + +#include "resources/dye.h" +#include "resources/dyepalette.h" +#include "resources/image.h" + +#include "utils/sdlcheckutils.h" + +#include <SDL_image.h> + +#include "debug.h" + +int SafeOpenGLImageHelper::mTextureType = 0; +int SafeOpenGLImageHelper::mInternalTextureType = GL_RGBA8; +int SafeOpenGLImageHelper::mTextureSize = 0; +bool SafeOpenGLImageHelper::mBlur = true; +bool SafeOpenGLImageHelper::mUseTextureSampler = false; + +SafeOpenGLImageHelper::~SafeOpenGLImageHelper() +{ + glDeleteTextures(static_cast<GLsizei>(texturesSize - mFreeTextureIndex), + &mTextures[mFreeTextureIndex]); +} + +Image *SafeOpenGLImageHelper::load(SDL_RWops *const rw, + Dye const &dye) +{ + SDL_Surface *const tmpImage = loadPng(rw); + if (!tmpImage) + { + logger->log("Error, image load failed: %s", IMG_GetError()); + return nullptr; + } + + SDL_Surface *const surf = convertTo32Bit(tmpImage); + MSDL_FreeSurface(tmpImage); + if (!surf) + return nullptr; + + uint32_t *pixels = static_cast<uint32_t *>(surf->pixels); + const int type = dye.getType(); + + switch (type) + { + case 1: + { + const DyePalette *const pal = dye.getSPalete(); + if (pal) + pal->replaceSOGLColor(pixels, surf->w * surf->h); + break; + } + case 2: + { + const DyePalette *const pal = dye.getAPalete(); + if (pal) + pal->replaceAOGLColor(pixels, surf->w * surf->h); + break; + } + case 0: + default: + { + dye.normalOGLDye(pixels, surf->w * surf->h); + break; + } + } + + Image *const image = load(surf); + MSDL_FreeSurface(surf); + return image; +} + +Image *SafeOpenGLImageHelper::load(SDL_Surface *const tmpImage) +{ + return glLoad(tmpImage); +} + +Image *SafeOpenGLImageHelper::createTextSurface(SDL_Surface *const tmpImage, + const int width, + const int height, + const float alpha) +{ + if (!tmpImage) + return nullptr; + + Image *const img = glLoad(tmpImage, width, height); + if (img) + img->setAlpha(alpha); + return img; +} + +int SafeOpenGLImageHelper::powerOfTwo(const 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; +} + +SDL_Surface *SafeOpenGLImageHelper::convertSurfaceNormalize(SDL_Surface + *tmpImage, + int width, + int height) +{ + if (!tmpImage) + return nullptr; + + 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); + } + +#ifdef USE_SDL2 + SDL_SetSurfaceAlphaMod(tmpImage, SDL_ALPHA_OPAQUE); +#else + // Make sure the alpha channel is not used, but copied to destination + SDL_SetAlpha(tmpImage, 0, SDL_ALPHA_OPAQUE); +#endif + + // Determine 32-bit masks based on byte order + uint32_t 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 + + if (tmpImage->format->BitsPerPixel != 32 + || realWidth != width || realHeight != height + || rmask != tmpImage->format->Rmask + || gmask != tmpImage->format->Gmask + || amask != tmpImage->format->Amask) + { + SDL_Surface *oldImage = tmpImage; +#ifdef USE_SDL2 + SDL_SetSurfaceBlendMode(oldImage, SDL_BLENDMODE_NONE); +#endif + tmpImage = MSDL_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); + } + return tmpImage; +} + +SDL_Surface *SafeOpenGLImageHelper::convertSurface(SDL_Surface *tmpImage, + int width, + int height) +{ + if (!tmpImage) + return nullptr; + +#ifdef USE_SDL2 + SDL_SetSurfaceAlphaMod(tmpImage, SDL_ALPHA_OPAQUE); +#else + // Make sure the alpha channel is not used, but copied to destination + SDL_SetAlpha(tmpImage, 0, SDL_ALPHA_OPAQUE); +#endif + + // Determine 32-bit masks based on byte order + uint32_t 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 + + if (tmpImage->format->BitsPerPixel != 32 + || rmask != tmpImage->format->Rmask + || gmask != tmpImage->format->Gmask + || amask != tmpImage->format->Amask) + { + SDL_Surface *oldImage = tmpImage; +#ifdef USE_SDL2 + SDL_SetSurfaceBlendMode(oldImage, SDL_BLENDMODE_NONE); +#endif + tmpImage = MSDL_CreateRGBSurface(SDL_SWSURFACE, width, height, + 32, rmask, gmask, bmask, amask); + + if (!tmpImage) + { + logger->log("Error, image convert failed: out of memory"); + return nullptr; + } + SDL_BlitSurface(oldImage, nullptr, tmpImage, nullptr); + } + return tmpImage; +} + +void SafeOpenGLImageHelper::bindTexture(const GLuint texture) +{ + switch (mUseOpenGL) + { +#ifdef __native_client__ + case RENDER_NORMAL_OPENGL: + case RENDER_MODERN_OPENGL: + case RENDER_GLES_OPENGL: + break; + case RENDER_SAFE_OPENGL: + SafeOpenGLGraphics::bindTexture(mTextureType, texture); + break; + case RENDER_GLES2_OPENGL: + MobileOpenGL2Graphics::bindTexture(mTextureType, texture); + break; +#else // __native_client__ + case RENDER_NORMAL_OPENGL: + NormalOpenGLGraphics::bindTexture(mTextureType, texture); + break; + case RENDER_MODERN_OPENGL: + ModernOpenGLGraphics::bindTexture(mTextureType, texture); + break; + case RENDER_SAFE_OPENGL: + SafeOpenGLGraphics::bindTexture(mTextureType, texture); + break; + case RENDER_GLES_OPENGL: + MobileOpenGLGraphics::bindTexture(mTextureType, texture); + break; + case RENDER_GLES2_OPENGL: + MobileOpenGL2Graphics::bindTexture(mTextureType, texture); + break; +#endif // __native_client__ + case RENDER_SOFTWARE: + case RENDER_SDL2_DEFAULT: + case RENDER_NULL: + case RENDER_LAST: + default: + logger->log("Unknown OpenGL backend: %d", mUseOpenGL); + break; + } +} + +Image *SafeOpenGLImageHelper::glLoad(SDL_Surface *tmpImage, + int width, + int height) +{ + if (!tmpImage) + return nullptr; + + BLOCK_START("SafeOpenGLImageHelper::glLoad") + // Flush current error flag. + graphicsManager.getLastError(); + + if (!width) + width = tmpImage->w; + if (!height) + height = tmpImage->h; + + SDL_Surface *oldImage = tmpImage; + tmpImage = convertSurfaceNormalize(tmpImage, width, height); + if (!tmpImage) + return nullptr; + + const int realWidth = tmpImage->w; + const int realHeight = tmpImage->h; + + const GLuint texture = getNewTexture(); + bindTexture(texture); + + if (SDL_MUSTLOCK(tmpImage)) + SDL_LockSurface(tmpImage); + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + if (!mUseTextureSampler) + { + 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); + } + } +#ifndef ANDROID + glTexParameteri(mTextureType, GL_TEXTURE_MAX_LEVEL, 0); +#endif + + glTexImage2D(mTextureType, 0, mInternalTextureType, + tmpImage->w, tmpImage->h, + 0, GL_RGBA, GL_UNSIGNED_BYTE, tmpImage->pixels); + +#ifdef DEBUG_OPENGL +// disabled for now, because debugger can't show it +// if (isGLNotNull(mglLabelObject)) +// { +// const char *const text = "image text"; +// mglLabelObject(GL_TEXTURE, texture, strlen(text), text); +// } +#endif + +/* + 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 != tmpImage) + MSDL_FreeSurface(tmpImage); + + GLenum error = graphicsManager.getLastError(); + if (error) + { + std::string errmsg = GraphicsManager::errorToString(error); + logger->log("Error: Image GL import failed: %s (%u)", + errmsg.c_str(), error); +// return nullptr; + } + + BLOCK_END("SafeOpenGLImageHelper::glLoad") + return new Image(texture, width, height, realWidth, realHeight); +} + +void SafeOpenGLImageHelper::initTextureSampler(const GLint id) +{ + if (mBlur) + { + mglSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + mglSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + else + { + mglSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + mglSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } +} + +SDL_Surface *SafeOpenGLImageHelper::create32BitSurface(int width, + int height) const +{ +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + const int rmask = 0xff000000; + const int gmask = 0x00ff0000; + const int bmask = 0x0000ff00; + const int amask = 0x000000ff; +#else + const int rmask = 0x000000ff; + const int gmask = 0x0000ff00; + const int bmask = 0x00ff0000; + const int amask = 0xff000000; +#endif + + width = powerOfTwo(width); + height = powerOfTwo(height); + + return MSDL_CreateRGBSurface(SDL_SWSURFACE, + width, height, 32, rmask, gmask, bmask, amask); +} + +GLuint SafeOpenGLImageHelper::getNewTexture() +{ + GLuint texture = mTextures[mFreeTextureIndex]; + mFreeTextureIndex ++; + if (mFreeTextureIndex == texturesSize) + { + mFreeTextureIndex = 0; + postInit(); + } + return texture; +} + +void SafeOpenGLImageHelper::postInit() +{ + glGenTextures(texturesSize, &mTextures[mFreeTextureIndex]); +} + +void SafeOpenGLImageHelper::invalidate(const GLuint textureId) +{ + if (isGLNotNull(mglInvalidateTexImage)) + { + logger->log("invalidate: %u", textureId); + mglInvalidateTexImage(textureId, 0); + } +} + +void SafeOpenGLImageHelper::copySurfaceToImage(const Image *const image, + const int x, + const int y, + SDL_Surface *surface) const +{ + if (!surface || !image) + return; + + SDL_Surface *const oldSurface = surface; + surface = convertSurface(surface, surface->w, surface->h); + if (!surface) + return; + + mglTextureSubImage2D(image->mGLImage, + mTextureType, 0, + x, y, + surface->w, surface->h, + GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels); + + if (surface != oldSurface) + MSDL_FreeSurface(surface); +} + +#endif diff --git a/src/resources/safeopenglimagehelper.h b/src/resources/safeopenglimagehelper.h new file mode 100644 index 000000000..14de03913 --- /dev/null +++ b/src/resources/safeopenglimagehelper.h @@ -0,0 +1,159 @@ +/* + * The ManaPlus Client + * Copyright (C) 2004-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011-2015 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef RESOURCES_SAFEOPENGLIMAGEHELPER_H +#define RESOURCES_SAFEOPENGLIMAGEHELPER_H + +#include "localconsts.h" +#include "main.h" + +#ifdef USE_OPENGL + +#ifndef GL_TEXTURE_RECTANGLE_ARB +#define GL_TEXTURE_RECTANGLE_ARB 0x84F5 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8 +#endif + +#include "resources/imagehelper.h" + +#ifdef ANDROID +#include <GLES/gl.h> +#define GL_RGBA8 GL_RGBA8_OES +#else +#ifndef USE_SDL2 +#define GL_GLEXT_PROTOTYPES 1 +#endif +#include <SDL_opengl.h> +#endif + +class Dye; +class Image; + +/** + * Defines a class for loading and storing images. + */ +class SafeOpenGLImageHelper final : public ImageHelper +{ + friend class CompoundSprite; + friend class Graphics; + friend class Image; + + public: + SafeOpenGLImageHelper() : + mFreeTextureIndex(0) + { + } + + A_DELETE_COPY(SafeOpenGLImageHelper) + + ~SafeOpenGLImageHelper(); + + /** + * 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 <code>NULL</code> if an error occurred, a valid pointer + * otherwise. + */ + Image *load(SDL_RWops *const rw, + Dye const &dye) override final A_WARN_UNUSED; + + /** + * Loads an image from an SDL surface. + */ + Image *load(SDL_Surface *const tmpImage) + override final A_WARN_UNUSED; + + Image *createTextSurface(SDL_Surface *const tmpImage, + const int width, const int height, + const float alpha) + override final A_WARN_UNUSED; + + // OpenGL only public functions + + static int getTextureType() A_WARN_UNUSED + { return mTextureType; } + + static int getInternalTextureType() A_WARN_UNUSED + { return mInternalTextureType; } + + static void setInternalTextureType(const int n) + { mInternalTextureType = n; } + + static void setBlur(const bool n) + { mBlur = n; } + + static int mTextureType; + + static int mInternalTextureType; + + static int getTextureSize() A_WARN_UNUSED + { return mTextureSize; } + + static void initTextureSampler(const GLint id); + + static void setUseTextureSampler(const bool b) + { mUseTextureSampler = b; } + + static void invalidate(const GLuint textureId); + + static void bindTexture(const GLuint texture); + + SDL_Surface *create32BitSurface(int width, + int height) const override final; + + void postInit() override final; + + void copySurfaceToImage(const Image *const image, + const int x, const int y, + SDL_Surface *surface) const override final; + + protected: + /** + * Returns the first power of two equal or bigger than the input. + */ + static int powerOfTwo(const int input) A_WARN_UNUSED; + + static SDL_Surface *convertSurfaceNormalize(SDL_Surface *tmpImage, + int width, int height); + + static SDL_Surface *convertSurface(SDL_Surface *tmpImage, + int width, int height); + + Image *glLoad(SDL_Surface *tmpImage, + int width = 0, int height = 0) A_WARN_UNUSED; + + GLuint getNewTexture(); + + static const size_t texturesSize = 10; + size_t mFreeTextureIndex; + GLuint mTextures[texturesSize]; + + static int mTextureSize; + static bool mBlur; + static bool mUseTextureSampler; +}; + +#endif +#endif // RESOURCES_SAFEOPENGLIMAGEHELPER_H |