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