Renamed MainLoop to ScreenManager
[supertux.git] / src / video / texture_manager.cpp
1 //  SuperTux
2 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3 //
4 //  This program is free software: you can redistribute it and/or modify
5 //  it under the terms of the GNU General Public License as published by
6 //  the Free Software Foundation, either version 3 of the License, or
7 //  (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17 #include "video/texture_manager.hpp"
18
19 #include <SDL_image.h>
20 #include <iostream>
21
22 #include "physfs/physfs_sdl.hpp"
23 #include "util/file_system.hpp"
24 #include "util/log.hpp"
25 #include "video/gl/gl_texture.hpp"
26 #include "video/video_systems.hpp"
27
28 TextureManager::TextureManager() :
29   image_textures()
30 #ifdef HAVE_OPENGL
31   ,textures(),
32   saved_textures()
33 #endif
34 {
35 }
36
37 TextureManager::~TextureManager()
38 {
39   for(ImageTextures::iterator i = image_textures.begin();
40       i != image_textures.end(); ++i) {
41     if(i->second == NULL)
42       continue;
43     log_warning << "Texture '" << i->first << "' not freed" << std::endl;
44     delete i->second;
45   }
46 }
47
48 Texture*
49 TextureManager::get(const std::string& _filename)
50 {
51   std::string filename = FileSystem::normalize(_filename);
52   ImageTextures::iterator i = image_textures.find(filename);
53
54   Texture* texture = NULL;
55   if(i != image_textures.end())
56     texture = i->second;
57
58   if(texture == NULL) {
59     texture = create_image_texture(filename);
60     image_textures[filename] = texture;
61   }
62
63   return texture;
64 }
65
66 void
67 TextureManager::release(Texture* texture)
68 {
69   image_textures.erase(texture->get_filename());
70   delete texture;
71 }
72
73 #ifdef HAVE_OPENGL
74 void
75 TextureManager::register_texture(GLTexture* texture)
76 {
77   textures.insert(texture);
78 }
79
80 void
81 TextureManager::remove_texture(GLTexture* texture)
82 {
83   textures.erase(texture);
84 }
85 #endif
86
87 Texture*
88 TextureManager::create_image_texture(const std::string& filename)
89 {
90   try {
91
92     SDL_Surface* image = IMG_Load_RW(get_physfs_SDLRWops(filename), 1);
93     if(image == 0) {
94       std::ostringstream msg;
95       msg << "Couldn't load image '" << filename << "' :" << SDL_GetError();
96       throw std::runtime_error(msg.str());
97     }
98
99     Texture* result = 0;
100     try {
101       result = new_texture(image);
102       result->set_filename(filename);
103     } catch(...) {
104       delete result;
105       SDL_FreeSurface(image);
106       throw;
107     }
108
109     SDL_FreeSurface(image);
110     return result;
111
112   } catch (const std::runtime_error& err) {
113     const std::string dummy_texture_fname = "images/engine/missing.png";
114     if (filename == dummy_texture_fname) throw err;
115
116     // on error, try loading placeholder file
117     try {
118
119       Texture* tex = create_image_texture(dummy_texture_fname);
120       log_warning << "Couldn't load texture '" << filename << "' (now using dummy texture): " << err.what() << std::endl;
121       return tex;
122
123     } catch (...) {
124
125       // on error (when loading placeholder), try using empty surface
126       try {
127
128         SDL_Surface* image = SDL_CreateRGBSurface(0, 1024, 1024, 8, 0, 0, 0, 0);
129         if(image == 0) {
130           throw err;
131         }
132
133         Texture* result = 0;
134         try {
135           result = new_texture(image);
136           result->set_filename("-dummy-texture-.png");
137         } catch(...) {
138           delete result;
139           SDL_FreeSurface(image);
140           throw err;
141         }
142
143         SDL_FreeSurface(image);
144         log_warning << "Couldn't load texture '" << filename << "' (now using empty one): " << err.what() << std::endl;
145         return result;
146
147         // on error (when trying to use empty surface), give up
148       } catch (const std::runtime_error& err) {
149         throw err;
150       }
151     }
152   }
153 }
154
155 #ifdef HAVE_OPENGL
156 void
157 TextureManager::save_textures()
158 {
159 #ifdef GL_PACK_ROW_LENGTH
160   /* all this stuff is not support by OpenGL ES */
161   glPixelStorei(GL_PACK_ROW_LENGTH, 0);
162   glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0);
163   glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
164   glPixelStorei(GL_PACK_SKIP_ROWS, 0);
165   glPixelStorei(GL_PACK_SKIP_IMAGES, 0);
166 #endif
167
168   glPixelStorei(GL_PACK_ALIGNMENT, 1);
169   for(Textures::iterator i = textures.begin(); i != textures.end(); ++i) {
170     save_texture(*i);
171   }
172   for(ImageTextures::iterator i = image_textures.begin();
173       i != image_textures.end(); ++i) {
174     save_texture(dynamic_cast<GLTexture *>(i->second));
175   }
176 }
177
178 void
179 TextureManager::save_texture(GLTexture* texture)
180 {
181   SavedTexture saved_texture;
182   saved_texture.texture = texture;
183   glBindTexture(GL_TEXTURE_2D, texture->get_handle());
184
185   //this doesn't work with OpenGL ES (but we don't need it on the GP2X anyway)
186 #ifndef GL_VERSION_ES_CM_1_0
187   glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH,
188                            &saved_texture.width);
189   glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT,
190                            &saved_texture.height);
191   glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BORDER,
192                            &saved_texture.border);
193   glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
194                       &saved_texture.min_filter);
195   glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
196                       &saved_texture.mag_filter);
197   glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
198                       &saved_texture.wrap_s);
199   glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
200                       &saved_texture.wrap_t);
201
202   size_t pixelssize = saved_texture.width * saved_texture.height * 4;
203   saved_texture.pixels = new char[pixelssize];
204
205   glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE,
206                 saved_texture.pixels);
207 #endif
208
209   saved_textures.push_back(saved_texture);
210
211   glDeleteTextures(1, &(texture->get_handle()));
212   texture->set_handle(0);
213
214   assert_gl("retrieving texture for save");
215 }
216
217 void
218 TextureManager::reload_textures()
219 {
220 #ifdef GL_UNPACK_ROW_LENGTH
221   /* OpenGL ES doesn't support these */
222   glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
223   glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
224   glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
225   glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
226   glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0);
227 #endif
228   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
229
230   for(std::vector<SavedTexture>::iterator i = saved_textures.begin();
231       i != saved_textures.end(); ++i) {
232     SavedTexture& saved_texture = *i;
233
234     GLuint handle;
235     glGenTextures(1, &handle);
236     assert_gl("creating texture handle");
237
238     glBindTexture(GL_TEXTURE_2D, handle);
239     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
240                  saved_texture.width, saved_texture.height,
241                  saved_texture.border, GL_RGBA,
242                  GL_UNSIGNED_BYTE, saved_texture.pixels);
243     delete[] saved_texture.pixels;
244     assert_gl("uploading texture pixel data");
245
246     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
247                     saved_texture.min_filter);
248     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
249                     saved_texture.mag_filter);
250     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
251                     saved_texture.wrap_s);
252     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
253                     saved_texture.wrap_t);
254
255     assert_gl("setting texture_params");
256     saved_texture.texture->set_handle(handle);
257   }
258
259   saved_textures.clear();
260 }
261 #endif
262
263 /* EOF */