X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fvideo%2Ftexture_manager.cpp;h=dc38be94943ea7393eed7933912b9514fdb81ff8;hb=77b5a67fccb8ce3a5ba43280105031a46560a5c8;hp=255efba48d04a10b392105cb77f15621c3334f8e;hpb=5a4ba5e7cfc6b0eaaa5a9f021443bec3a30adca2;p=supertux.git diff --git a/src/video/texture_manager.cpp b/src/video/texture_manager.cpp index 255efba48..dc38be949 100644 --- a/src/video/texture_manager.cpp +++ b/src/video/texture_manager.cpp @@ -1,152 +1,287 @@ -#include +// SuperTux +// Copyright (C) 2006 Matthias Braun +// +// 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 3 of the License, or +// (at your option) 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 "texture_manager.hpp" +#include "video/texture_manager.hpp" -#include -#include #include -#include -#include +#include #include #include #include + +#include "math/rect.hpp" #include "physfs/physfs_sdl.hpp" -#include "image_texture.hpp" -#include "glutil.hpp" -#include "file_system.hpp" -#include "msg.hpp" +#include "util/file_system.hpp" +#include "util/log.hpp" +#include "video/sdl_surface_ptr.hpp" +#include "video/texture.hpp" +#include "video/video_system.hpp" -TextureManager* texture_manager = NULL; +#ifdef HAVE_OPENGL +#include "video/gl/gl_texture.hpp" +#endif -TextureManager::TextureManager() +TextureManager::TextureManager() : + m_image_textures() + ,m_surfaces() +#ifdef HAVE_OPENGL + ,m_textures(), + m_saved_textures() +#endif { } TextureManager::~TextureManager() { - for(ImageTextures::iterator i = image_textures.begin(); - i != image_textures.end(); ++i) { - if(i->second == NULL) - continue; - msg_warning << "Texture '" << i->first << "' not freed" << std::endl; - delete i->second; + for(ImageTextures::iterator i = m_image_textures.begin(); i != m_image_textures.end(); ++i) + { + if(!i->second.expired()) + { + log_warning << "Texture '" << i->first << "' not freed" << std::endl; + } + } + m_image_textures.clear(); + + for(auto& surface : m_surfaces) + { + SDL_FreeSurface(surface.second); } + m_surfaces.clear(); } -ImageTexture* +TexturePtr TextureManager::get(const std::string& _filename) { std::string filename = FileSystem::normalize(_filename); - ImageTextures::iterator i = image_textures.find(filename); + ImageTextures::iterator i = m_image_textures.find(filename); - ImageTexture* texture = NULL; - if(i != image_textures.end()) - texture = i->second; + TexturePtr texture; + if(i != m_image_textures.end()) + texture = i->second.lock(); - if(texture == NULL) { + if(!texture) { texture = create_image_texture(filename); - image_textures[filename] = texture; + texture->cache_filename = filename; + m_image_textures[filename] = texture; } return texture; } +TexturePtr +TextureManager::get(const std::string& _filename, const Rect& rect) +{ + std::string filename = FileSystem::normalize(_filename); + // FIXME: implement caching + return create_image_texture(filename, rect); +} + void -TextureManager::release(ImageTexture* texture) +TextureManager::reap_cache_entry(const std::string& filename) { - image_textures.erase(texture->filename); - delete texture; + ImageTextures::iterator i = m_image_textures.find(filename); + assert(i != m_image_textures.end()); + assert(i->second.expired()); + m_image_textures.erase(i); } +#ifdef HAVE_OPENGL void -TextureManager::register_texture(Texture* texture) +TextureManager::register_texture(GLTexture* texture) { - textures.insert(texture); + m_textures.insert(texture); } void -TextureManager::remove_texture(Texture* texture) +TextureManager::remove_texture(GLTexture* texture) { - textures.erase(texture); + m_textures.erase(texture); } +#endif -static inline int next_power_of_two(int val) +TexturePtr +TextureManager::create_image_texture(const std::string& filename, const Rect& rect) { - int result = 1; - while(result < val) - result *= 2; - return result; + try + { + return create_image_texture_raw(filename, rect); + } + catch(const std::exception& err) + { + log_warning << "Couldn't load texture '" << filename << "' (now using dummy texture): " << err.what() << std::endl; + return create_dummy_texture(); + } } -ImageTexture* +TexturePtr +TextureManager::create_image_texture_raw(const std::string& filename, const Rect& rect) +{ + SDL_Surface *image = nullptr; + + Surfaces::iterator i = m_surfaces.find(filename); + if (i != m_surfaces.end()) + { + image = i->second; + } + else + { + image = IMG_Load_RW(get_physfs_SDLRWops(filename), 1); + if (!image) + { + std::ostringstream msg; + msg << "Couldn't load image '" << filename << "' :" << SDL_GetError(); + throw std::runtime_error(msg.str()); + } + + m_surfaces[filename] = image; + } + + SDL_PixelFormat* format = image->format; + if(format->Rmask == 0 && format->Gmask == 0 && format->Bmask == 0 && format->Amask == 0) { + log_debug << "Wrong surface format for image " << filename << ". Compensating." << std::endl; + image = SDL_ConvertSurfaceFormat(image, SDL_PIXELFORMAT_RGBA8888, 0); + } + + SDLSurfacePtr subimage(SDL_CreateRGBSurfaceFrom(static_cast(image->pixels) + + rect.top * image->pitch + + rect.left * image->format->BytesPerPixel, + rect.get_width(), rect.get_height(), + image->format->BitsPerPixel, + image->pitch, + image->format->Rmask, + image->format->Gmask, + image->format->Bmask, + image->format->Amask)); + if (!subimage) + { + throw std::runtime_error("SDL_CreateRGBSurfaceFrom() call failed"); + } + +#ifdef OLD_SDL + if (image->format->palette) + { // copy the image palette to subimage if present + SDL_SetSurfacePalette(subimage.get(), image->format->palette->colors); + } +#endif + + return VideoSystem::current()->new_texture(subimage.get()); +} + +TexturePtr TextureManager::create_image_texture(const std::string& filename) { - SDL_Surface* image = IMG_Load_RW(get_physfs_SDLRWops(filename), 1); - if(image == NULL) { + try + { + return create_image_texture_raw(filename); + } + catch (const std::exception& err) + { + log_warning << "Couldn't load texture '" << filename << "' (now using dummy texture): " << err.what() << std::endl; + return create_dummy_texture(); + } +} + +TexturePtr +TextureManager::create_image_texture_raw(const std::string& filename) +{ + SDLSurfacePtr image(IMG_Load_RW(get_physfs_SDLRWops(filename), 1)); + if (!image) + { std::ostringstream msg; msg << "Couldn't load image '" << filename << "' :" << SDL_GetError(); throw std::runtime_error(msg.str()); } + else + { + TexturePtr texture = VideoSystem::current()->new_texture(image.get()); + image.reset(NULL); + return texture; + } +} - int texture_w = next_power_of_two(image->w); - int texture_h = next_power_of_two(image->h); - -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - SDL_Surface* convert = SDL_CreateRGBSurface(SDL_SWSURFACE, - texture_w, texture_h, 32, - 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff); -#else - SDL_Surface* convert = SDL_CreateRGBSurface(SDL_SWSURFACE, - texture_w, texture_h, 32, - 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); -#endif +TexturePtr +TextureManager::create_dummy_texture() +{ + const std::string dummy_texture_fname = "images/engine/missing.png"; - if(convert == 0) - throw std::runtime_error("Couldn't create texture: out of memory"); - - SDL_SetAlpha(image, 0, 0); - SDL_BlitSurface(image, 0, convert, 0); - - ImageTexture* result = NULL; - try { - result = new ImageTexture(convert); - result->filename = filename; - result->image_width = image->w; - result->image_height = image->h; - } catch(...) { - delete result; - SDL_FreeSurface(convert); - throw; - } - - SDL_FreeSurface(convert); - return result; + // on error, try loading placeholder file + try + { + TexturePtr tex = create_image_texture_raw(dummy_texture_fname); + return tex; + } + catch (const std::exception& err) + { + // on error (when loading placeholder), try using empty surface, + // when that fails to, just give up + SDLSurfacePtr image(SDL_CreateRGBSurface(0, 1024, 1024, 8, 0, 0, 0, 0)); + if (!image) + { + throw; + } + else + { + log_warning << "Couldn't load texture '" << dummy_texture_fname << "' (now using empty one): " << err.what() << std::endl; + TexturePtr texture = VideoSystem::current()->new_texture(image.get()); + image.reset(NULL); + return texture; + } + } } +#ifdef HAVE_OPENGL void TextureManager::save_textures() { +#if defined(GL_PACK_ROW_LENGTH) || defined(USE_GLBINDING) + /* all this stuff is not support by OpenGL ES */ glPixelStorei(GL_PACK_ROW_LENGTH, 0); glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0); glPixelStorei(GL_PACK_SKIP_PIXELS, 0); glPixelStorei(GL_PACK_SKIP_ROWS, 0); glPixelStorei(GL_PACK_SKIP_IMAGES, 0); +#endif + glPixelStorei(GL_PACK_ALIGNMENT, 1); - for(Textures::iterator i = textures.begin(); i != textures.end(); ++i) { + + for(Textures::iterator i = m_textures.begin(); i != m_textures.end(); ++i) + { save_texture(*i); } - for(ImageTextures::iterator i = image_textures.begin(); - i != image_textures.end(); ++i) { - save_texture(i->second); + + for(ImageTextures::iterator i = m_image_textures.begin(); + i != m_image_textures.end(); ++i) + { + GLTexture* texture = dynamic_cast(i->second.lock().get()); + if(texture == NULL) + continue; + + save_texture(texture); } } void -TextureManager::save_texture(Texture* texture) +TextureManager::save_texture(GLTexture* texture) { SavedTexture saved_texture; saved_texture.texture = texture; glBindTexture(GL_TEXTURE_2D, texture->get_handle()); + + //this doesn't work with OpenGL ES (but we don't need it on the GP2X anyway) +#ifndef GL_VERSION_ES_CM_1_0 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &saved_texture.width); glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, @@ -164,14 +299,15 @@ TextureManager::save_texture(Texture* texture) size_t pixelssize = saved_texture.width * saved_texture.height * 4; saved_texture.pixels = new char[pixelssize]; - + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, saved_texture.pixels); +#endif - saved_textures.push_back(saved_texture); + m_saved_textures.push_back(saved_texture); - glDeleteTextures(1, &(texture->handle)); - texture->handle = 0; + glDeleteTextures(1, &(texture->get_handle())); + texture->set_handle(0); assert_gl("retrieving texture for save"); } @@ -179,23 +315,26 @@ TextureManager::save_texture(Texture* texture) void TextureManager::reload_textures() { +#if defined(GL_UNPACK_ROW_LENGTH) || defined(USE_GLBINDING) + /* OpenGL ES doesn't support these */ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0); +#endif glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - for(std::vector::iterator i = saved_textures.begin(); - i != saved_textures.end(); ++i) { + + for(std::vector::iterator i = m_saved_textures.begin(); + i != m_saved_textures.end(); ++i) { SavedTexture& saved_texture = *i; - + GLuint handle; glGenTextures(1, &handle); assert_gl("creating texture handle"); glBindTexture(GL_TEXTURE_2D, handle); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, + glTexImage2D(GL_TEXTURE_2D, 0, static_cast(GL_RGBA), saved_texture.width, saved_texture.height, saved_texture.border, GL_RGBA, GL_UNSIGNED_BYTE, saved_texture.pixels); @@ -212,9 +351,11 @@ TextureManager::reload_textures() saved_texture.wrap_t); assert_gl("setting texture_params"); - saved_texture.texture->handle = handle; + saved_texture.texture->set_handle(handle); } - saved_textures.clear(); + m_saved_textures.clear(); } +#endif +/* EOF */