9e2b70ddaddfd704eec859c84907a5d9c95b6352
[supertux.git] / src / video / gl / gl_texture.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 "supertux/gameconfig.hpp"
18 #include "video/gl/gl_texture.hpp"
19
20 namespace {
21
22 inline bool is_power_of_2(int v)
23 {
24   return (v & (v-1)) == 0;
25 }
26
27 inline int next_power_of_two(int val)
28 {
29   int result = 1;
30   while(result < val)
31     result *= 2;
32   return result;
33 }
34
35 } // namespace
36
37 GLTexture::GLTexture(unsigned int width, unsigned int height) :
38   handle(),
39   texture_width(),
40   texture_height(),
41   image_width(),
42   image_height()
43 {
44 #ifdef GL_VERSION_ES_CM_1_0
45   assert(is_power_of_2(width));
46   assert(is_power_of_2(height));
47 #endif
48   texture_width  = width;
49   texture_height = height;
50   image_width  = width;
51   image_height = height;
52
53   assert_gl("before creating texture");
54   glGenTextures(1, &handle);
55
56   try {
57     glBindTexture(GL_TEXTURE_2D, handle);
58
59     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_width,
60                  texture_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
61
62     set_texture_params();
63   } catch(...) {
64     glDeleteTextures(1, &handle);
65     throw;
66   }
67 }
68
69 GLTexture::GLTexture(SDL_Surface* image) :
70   handle(),
71   texture_width(),
72   texture_height(),
73   image_width(),
74   image_height()
75 {
76 #ifdef GL_VERSION_ES_CM_1_0
77   texture_width = next_power_of_two(image->w);
78   texture_height = next_power_of_two(image->h);
79 #else
80   if (GLEW_ARB_texture_non_power_of_two)
81   {
82     texture_width  = image->w;
83     texture_height = image->h;
84   }
85   else
86   {
87     texture_width = next_power_of_two(image->w);
88     texture_height = next_power_of_two(image->h);
89   }
90 #endif
91
92   image_width  = image->w;
93   image_height = image->h;
94
95 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
96   SDL_Surface* convert = SDL_CreateRGBSurface(SDL_SWSURFACE,
97                                               texture_width, texture_height, 32,
98                                               0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
99 #else
100   SDL_Surface* convert = SDL_CreateRGBSurface(SDL_SWSURFACE,
101                                               texture_width, texture_height, 32,
102                                               0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
103 #endif
104
105   if(convert == 0) {
106     throw std::runtime_error("Couldn't create texture: out of memory");
107   }
108
109   SDL_SetAlpha(image, 0, 0);
110   SDL_BlitSurface(image, 0, convert, 0);
111
112   assert_gl("before creating texture");
113   glGenTextures(1, &handle);
114
115   try {
116     GLenum sdl_format;
117     if(convert->format->BytesPerPixel == 3)
118       sdl_format = GL_RGB;
119     else if(convert->format->BytesPerPixel == 4)
120       sdl_format = GL_RGBA;
121     else {
122       sdl_format = GL_RGBA;
123       assert(false);
124     }
125
126     glBindTexture(GL_TEXTURE_2D, handle);
127     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
128 #ifdef GL_UNPACK_ROW_LENGTH
129     glPixelStorei(GL_UNPACK_ROW_LENGTH, convert->pitch/convert->format->BytesPerPixel);
130 #else
131     /* OpenGL ES doesn't support UNPACK_ROW_LENGTH, let's hope SDL didn't add
132      * padding bytes, otherwise we need some extra code here... */
133     assert(convert->pitch == texture_width * convert->format->BytesPerPixel);
134 #endif
135
136     if(SDL_MUSTLOCK(convert))
137     {
138       SDL_LockSurface(convert);
139     }
140
141     if (true)
142     { // no not use mipmaps
143       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_width,
144                  texture_height, 0, sdl_format,
145                  GL_UNSIGNED_BYTE, convert->pixels);
146     }
147     else
148     { // build mipmaps
149       gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, texture_width,
150                         texture_height, sdl_format,
151                         GL_UNSIGNED_BYTE, convert->pixels);
152     }
153
154     if(SDL_MUSTLOCK(convert))
155     {
156       SDL_UnlockSurface(convert);
157     }
158
159     assert_gl("creating texture");
160
161     set_texture_params();
162   } catch(...) {
163     glDeleteTextures(1, &handle);
164     SDL_FreeSurface(convert);
165     throw;
166   }
167   SDL_FreeSurface(convert);
168 }
169
170 GLTexture::~GLTexture()
171 {
172   glDeleteTextures(1, &handle);
173 }
174
175 void
176 GLTexture::set_texture_params()
177 {
178   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
179   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
180
181   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
182   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
183
184   assert_gl("set texture params");
185 }
186
187 /* EOF */