simply change the type to GLint instead of casting around
[supertux.git] / src / video / texture_manager.cpp
1 #include <config.h>
2
3 #include "texture_manager.hpp"
4
5 #include <assert.h>
6 #include <SDL.h>
7 #include <SDL_image.h>
8 #include <GL/gl.h>
9 #include <GL/glext.h>
10 #include <iostream>
11 #include <sstream>
12 #include <stdexcept>
13 #include "physfs/physfs_sdl.hpp"
14 #include "image_texture.hpp"
15 #include "glutil.hpp"
16 #include "file_system.hpp"
17 #include "msg.hpp"
18
19 TextureManager* texture_manager = NULL;
20
21 TextureManager::TextureManager()
22 {
23 }
24
25 TextureManager::~TextureManager()
26 {
27   for(ImageTextures::iterator i = image_textures.begin();
28       i != image_textures.end(); ++i) {
29     if(i->second == NULL)
30       continue;
31     msg_warning << "Texture '" << i->first << "' not freed" << std::endl;
32     delete i->second;
33   }
34 }
35
36 ImageTexture*
37 TextureManager::get(const std::string& _filename)
38 {
39   std::string filename = FileSystem::normalize(_filename);
40   ImageTextures::iterator i = image_textures.find(filename);
41
42   ImageTexture* texture = NULL;
43   if(i != image_textures.end())
44     texture = i->second;
45
46   if(texture == NULL) {
47     texture = create_image_texture(filename);
48     image_textures[filename] = texture;
49   }
50
51   return texture;
52 }
53
54 void
55 TextureManager::release(ImageTexture* texture)
56 {
57   image_textures.erase(texture->filename);
58   delete texture;
59 }
60
61 void
62 TextureManager::register_texture(Texture* texture)
63 {
64   textures.insert(texture);
65 }
66
67 void
68 TextureManager::remove_texture(Texture* texture)
69 {
70   textures.erase(texture);
71 }
72
73 static inline int next_power_of_two(int val)
74 {
75   int result = 1;
76   while(result < val)
77     result *= 2;
78   return result;
79 }
80
81 ImageTexture*
82 TextureManager::create_image_texture(const std::string& filename)
83 {
84   SDL_Surface* image = IMG_Load_RW(get_physfs_SDLRWops(filename), 1);
85   if(image == NULL) {
86     std::ostringstream msg;
87     msg << "Couldn't load image '" << filename << "' :" << SDL_GetError();
88     throw std::runtime_error(msg.str());
89   }
90
91   int texture_w = next_power_of_two(image->w);
92   int texture_h = next_power_of_two(image->h);
93
94 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
95   SDL_Surface* convert = SDL_CreateRGBSurface(SDL_SWSURFACE,
96       texture_w, texture_h, 32,
97       0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
98 #else
99   SDL_Surface* convert = SDL_CreateRGBSurface(SDL_SWSURFACE,
100       texture_w, texture_h, 32,
101       0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
102 #endif
103
104   if(convert == 0)
105     throw std::runtime_error("Couldn't create texture: out of memory");
106
107   SDL_SetAlpha(image, 0, 0);
108   SDL_BlitSurface(image, 0, convert, 0);
109
110   ImageTexture* result = NULL;
111   try {
112     result = new ImageTexture(convert);
113     result->filename = filename;
114     result->image_width = image->w;
115     result->image_height = image->h;
116   } catch(...) {
117     delete result;
118     SDL_FreeSurface(convert);
119     throw;
120   }
121   
122   SDL_FreeSurface(convert);
123   return result;
124 }
125
126 void
127 TextureManager::save_textures()
128 {
129   glPixelStorei(GL_PACK_ROW_LENGTH, 0);
130   glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0);
131   glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
132   glPixelStorei(GL_PACK_SKIP_ROWS, 0);
133   glPixelStorei(GL_PACK_SKIP_IMAGES, 0);
134   glPixelStorei(GL_PACK_ALIGNMENT, 1);
135   for(Textures::iterator i = textures.begin(); i != textures.end(); ++i) {
136     save_texture(*i);
137   }
138   for(ImageTextures::iterator i = image_textures.begin();
139       i != image_textures.end(); ++i) {
140     save_texture(i->second);
141   }
142 }
143
144 void
145 TextureManager::save_texture(Texture* texture)
146 {
147   SavedTexture saved_texture;
148   saved_texture.texture = texture;
149   glBindTexture(GL_TEXTURE_2D, texture->get_handle());
150   glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH,
151                            &saved_texture.width);
152   glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT,
153                            &saved_texture.height);
154   glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BORDER,
155                            &saved_texture.border);
156   glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
157                       &saved_texture.min_filter);
158   glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
159                       &saved_texture.mag_filter);
160   glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
161                       &saved_texture.wrap_s);
162   glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
163                       &saved_texture.wrap_t);
164
165   size_t pixelssize = saved_texture.width * saved_texture.height * 4;
166   saved_texture.pixels = new char[pixelssize];
167   
168   glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE,
169                 saved_texture.pixels);
170
171   saved_textures.push_back(saved_texture);
172
173   glDeleteTextures(1, &(texture->handle));
174   texture->handle = 0;
175
176   assert_gl("retrieving texture for save");
177 }
178
179 void
180 TextureManager::reload_textures()
181 {
182   glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
183   glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
184   glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
185   glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
186   glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0);
187   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
188   
189   for(std::vector<SavedTexture>::iterator i = saved_textures.begin();
190       i != saved_textures.end(); ++i) {
191     SavedTexture& saved_texture = *i;
192     
193     GLuint handle;
194     glGenTextures(1, &handle);
195     assert_gl("creating texture handle");
196
197     glBindTexture(GL_TEXTURE_2D, handle);
198     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
199                  saved_texture.width, saved_texture.height,
200                  saved_texture.border, GL_RGBA,
201                  GL_UNSIGNED_BYTE, saved_texture.pixels);
202     delete[] saved_texture.pixels;
203     assert_gl("uploading texture pixel data");
204
205     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
206                     saved_texture.min_filter);
207     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
208                     saved_texture.mag_filter);
209     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
210                     saved_texture.wrap_s);
211     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
212                     saved_texture.wrap_t);
213
214     assert_gl("setting texture_params");
215     saved_texture.texture->handle = handle;
216   }
217
218   saved_textures.clear();
219 }
220