00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "video/texture_manager.hpp"
00018
00019 #include <SDL_image.h>
00020 #include <assert.h>
00021 #include <iostream>
00022 #include <sstream>
00023 #include <stdexcept>
00024
00025 #include "math/rect.hpp"
00026 #include "physfs/physfs_sdl.hpp"
00027 #include "util/file_system.hpp"
00028 #include "util/log.hpp"
00029 #include "video/sdl_surface_ptr.hpp"
00030 #include "video/texture.hpp"
00031 #include "video/video_systems.hpp"
00032
00033 #ifdef HAVE_OPENGL
00034 #include "video/gl/gl_texture.hpp"
00035 #endif
00036
00037 TextureManager::TextureManager() :
00038 image_textures()
00039 #ifdef HAVE_OPENGL
00040 ,textures(),
00041 saved_textures()
00042 #endif
00043 {
00044 }
00045
00046 TextureManager::~TextureManager()
00047 {
00048 for(ImageTextures::iterator i = image_textures.begin(); i != image_textures.end(); ++i)
00049 {
00050 if(!i->second.expired())
00051 {
00052 log_warning << "Texture '" << i->first << "' not freed" << std::endl;
00053 }
00054 }
00055 image_textures.clear();
00056 }
00057
00058 TexturePtr
00059 TextureManager::get(const std::string& _filename)
00060 {
00061 std::string filename = FileSystem::normalize(_filename);
00062 ImageTextures::iterator i = image_textures.find(filename);
00063
00064 TexturePtr texture;
00065 if(i != image_textures.end())
00066 texture = i->second.lock();
00067
00068 if(!texture) {
00069 texture = create_image_texture(filename);
00070 texture->cache_filename = filename;
00071 image_textures[filename] = texture;
00072 }
00073
00074 return texture;
00075 }
00076
00077 TexturePtr
00078 TextureManager::get(const std::string& filename, const Rect& rect)
00079 {
00080
00081 return create_image_texture(filename, rect);
00082 }
00083
00084 void
00085 TextureManager::reap_cache_entry(const std::string& filename)
00086 {
00087 ImageTextures::iterator i = image_textures.find(filename);
00088 assert(i != image_textures.end());
00089 assert(i->second.expired());
00090 image_textures.erase(i);
00091 }
00092
00093 #ifdef HAVE_OPENGL
00094 void
00095 TextureManager::register_texture(GLTexture* texture)
00096 {
00097 textures.insert(texture);
00098 }
00099
00100 void
00101 TextureManager::remove_texture(GLTexture* texture)
00102 {
00103 textures.erase(texture);
00104 }
00105 #endif
00106
00107 TexturePtr
00108 TextureManager::create_image_texture(const std::string& filename, const Rect& rect)
00109 {
00110 try
00111 {
00112 return create_image_texture_raw(filename, rect);
00113 }
00114 catch(const std::exception& err)
00115 {
00116 log_warning << "Couldn't load texture '" << filename << "' (now using dummy texture): " << err.what() << std::endl;
00117 return create_dummy_texture();
00118 }
00119 }
00120
00121 TexturePtr
00122 TextureManager::create_image_texture_raw(const std::string& filename, const Rect& rect)
00123 {
00124 SDLSurfacePtr image(IMG_Load_RW(get_physfs_SDLRWops(filename), 1));
00125 if (!image)
00126 {
00127 std::ostringstream msg;
00128 msg << "Couldn't load image '" << filename << "' :" << SDL_GetError();
00129 throw std::runtime_error(msg.str());
00130 }
00131 else
00132 {
00133 SDLSurfacePtr subimage(SDL_CreateRGBSurfaceFrom(static_cast<uint8_t*>(image->pixels) +
00134 rect.top * image->pitch +
00135 rect.left * image->format->BytesPerPixel,
00136
00137 rect.get_width(), rect.get_height(),
00138 image->format->BitsPerPixel,
00139 image->pitch,
00140 image->format->Rmask,
00141 image->format->Gmask,
00142 image->format->Bmask,
00143 image->format->Amask));
00144 if (!subimage)
00145 {
00146 throw std::runtime_error("SDL_CreateRGBSurfaceFrom() call failed");
00147 }
00148 else
00149 {
00150 if (image->format->palette)
00151 {
00152 SDL_SetColors(subimage.get(), image->format->palette->colors, 0, image->format->palette->ncolors);
00153 }
00154
00155 return VideoSystem::new_texture(subimage.get());
00156 }
00157 }
00158 }
00159
00160 TexturePtr
00161 TextureManager::create_image_texture(const std::string& filename)
00162 {
00163 try
00164 {
00165 return create_image_texture_raw(filename);
00166 }
00167 catch (const std::exception& err)
00168 {
00169 log_warning << "Couldn't load texture '" << filename << "' (now using dummy texture): " << err.what() << std::endl;
00170 return create_dummy_texture();
00171 }
00172 }
00173
00174 TexturePtr
00175 TextureManager::create_image_texture_raw(const std::string& filename)
00176 {
00177 SDLSurfacePtr image(IMG_Load_RW(get_physfs_SDLRWops(filename), 1));
00178 if (!image)
00179 {
00180 std::ostringstream msg;
00181 msg << "Couldn't load image '" << filename << "' :" << SDL_GetError();
00182 throw std::runtime_error(msg.str());
00183 }
00184 else
00185 {
00186 return VideoSystem::new_texture(image.get());
00187 }
00188 }
00189
00190 TexturePtr
00191 TextureManager::create_dummy_texture()
00192 {
00193 const std::string dummy_texture_fname = "images/engine/missing.png";
00194
00195
00196 try
00197 {
00198 TexturePtr tex = create_image_texture_raw(dummy_texture_fname);
00199 return tex;
00200 }
00201 catch (const std::exception& err)
00202 {
00203
00204
00205 SDLSurfacePtr image(SDL_CreateRGBSurface(0, 1024, 1024, 8, 0, 0, 0, 0));
00206 if (!image)
00207 {
00208 throw err;
00209 }
00210 else
00211 {
00212 log_warning << "Couldn't load texture '" << dummy_texture_fname << "' (now using empty one): " << err.what() << std::endl;
00213 return VideoSystem::new_texture(image.get());
00214 }
00215 }
00216 }
00217
00218 #ifdef HAVE_OPENGL
00219 void
00220 TextureManager::save_textures()
00221 {
00222 #ifdef GL_PACK_ROW_LENGTH
00223
00224 glPixelStorei(GL_PACK_ROW_LENGTH, 0);
00225 glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0);
00226 glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
00227 glPixelStorei(GL_PACK_SKIP_ROWS, 0);
00228 glPixelStorei(GL_PACK_SKIP_IMAGES, 0);
00229 #endif
00230
00231 glPixelStorei(GL_PACK_ALIGNMENT, 1);
00232 for(Textures::iterator i = textures.begin(); i != textures.end(); ++i) {
00233 save_texture(*i);
00234 }
00235 for(ImageTextures::iterator i = image_textures.begin();
00236 i != image_textures.end(); ++i) {
00237 save_texture(dynamic_cast<GLTexture*>(i->second.lock().get()));
00238 }
00239 }
00240
00241 void
00242 TextureManager::save_texture(GLTexture* texture)
00243 {
00244 SavedTexture saved_texture;
00245 saved_texture.texture = texture;
00246 glBindTexture(GL_TEXTURE_2D, texture->get_handle());
00247
00248
00249 #ifndef GL_VERSION_ES_CM_1_0
00250 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH,
00251 &saved_texture.width);
00252 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT,
00253 &saved_texture.height);
00254 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BORDER,
00255 &saved_texture.border);
00256 glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
00257 &saved_texture.min_filter);
00258 glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
00259 &saved_texture.mag_filter);
00260 glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
00261 &saved_texture.wrap_s);
00262 glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
00263 &saved_texture.wrap_t);
00264
00265 size_t pixelssize = saved_texture.width * saved_texture.height * 4;
00266 saved_texture.pixels = new char[pixelssize];
00267
00268 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE,
00269 saved_texture.pixels);
00270 #endif
00271
00272 saved_textures.push_back(saved_texture);
00273
00274 glDeleteTextures(1, &(texture->get_handle()));
00275 texture->set_handle(0);
00276
00277 assert_gl("retrieving texture for save");
00278 }
00279
00280 void
00281 TextureManager::reload_textures()
00282 {
00283 #ifdef GL_UNPACK_ROW_LENGTH
00284
00285 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
00286 glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
00287 glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
00288 glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
00289 glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0);
00290 #endif
00291 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00292
00293 for(std::vector<SavedTexture>::iterator i = saved_textures.begin();
00294 i != saved_textures.end(); ++i) {
00295 SavedTexture& saved_texture = *i;
00296
00297 GLuint handle;
00298 glGenTextures(1, &handle);
00299 assert_gl("creating texture handle");
00300
00301 glBindTexture(GL_TEXTURE_2D, handle);
00302 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
00303 saved_texture.width, saved_texture.height,
00304 saved_texture.border, GL_RGBA,
00305 GL_UNSIGNED_BYTE, saved_texture.pixels);
00306 delete[] saved_texture.pixels;
00307 assert_gl("uploading texture pixel data");
00308
00309 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
00310 saved_texture.min_filter);
00311 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
00312 saved_texture.mag_filter);
00313 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
00314 saved_texture.wrap_s);
00315 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
00316 saved_texture.wrap_t);
00317
00318 assert_gl("setting texture_params");
00319 saved_texture.texture->set_handle(handle);
00320 }
00321
00322 saved_textures.clear();
00323 }
00324 #endif
00325
00326