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