Merged changes from branches/supertux-milestone2-grumbel/ to trunk/supertux/
[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 {
39   assert(is_power_of_2(width));
40   assert(is_power_of_2(height));
41   texture_width = width;
42   texture_height = height;
43   image_width = width;
44   image_height = height;
45
46   assert_gl("before creating texture");
47   glGenTextures(1, &handle);
48
49   try {
50     glBindTexture(GL_TEXTURE_2D, handle);
51
52     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_width,
53                  texture_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
54
55     set_texture_params();
56   } catch(...) {
57     glDeleteTextures(1, &handle);
58     throw;
59   }
60 }
61
62 GLTexture::GLTexture(SDL_Surface* image)
63 {
64   texture_width = next_power_of_two(image->w);
65   texture_height = next_power_of_two(image->h);
66   image_width = image->w;
67   image_height = image->h;
68
69 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
70   SDL_Surface* convert = SDL_CreateRGBSurface(SDL_SWSURFACE,
71                                               texture_width, texture_height, 32,
72                                               0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
73 #else
74   SDL_Surface* convert = SDL_CreateRGBSurface(SDL_SWSURFACE,
75                                               texture_width, texture_height, 32,
76                                               0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
77 #endif
78
79   if(convert == 0) {
80     throw std::runtime_error("Couldn't create texture: out of memory");
81   }
82
83   SDL_SetAlpha(image, 0, 0);
84   SDL_BlitSurface(image, 0, convert, 0);
85
86   assert_gl("before creating texture");
87   glGenTextures(1, &handle);
88
89   try {
90     GLenum sdl_format;
91     if(convert->format->BytesPerPixel == 3)
92       sdl_format = GL_RGB;
93     else if(convert->format->BytesPerPixel == 4)
94       sdl_format = GL_RGBA;
95     else
96       assert(false);
97
98     glBindTexture(GL_TEXTURE_2D, handle);
99     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
100 #ifdef GL_UNPACK_ROW_LENGTH
101     glPixelStorei(GL_UNPACK_ROW_LENGTH, convert->pitch/convert->format->BytesPerPixel);
102 #else
103     /* OpenGL ES doesn't support UNPACK_ROW_LENGTH, let's hope SDL didn't add
104      * padding bytes, otherwise we need some extra code here... */
105     assert(convert->pitch == texture_width * convert->format->BytesPerPixel);
106 #endif
107
108     if(SDL_MUSTLOCK(convert))
109     {
110       SDL_LockSurface(convert);
111     }
112     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_width,
113                  texture_height, 0, sdl_format,
114                  GL_UNSIGNED_BYTE, convert->pixels);
115     if(SDL_MUSTLOCK(convert))
116     {
117       SDL_UnlockSurface(convert);
118     }
119
120     assert_gl("creating texture");
121
122     set_texture_params();
123   } catch(...) {
124     glDeleteTextures(1, &handle);
125     SDL_FreeSurface(convert);
126     throw;
127   }
128   SDL_FreeSurface(convert);
129 }
130
131 GLTexture::~GLTexture()
132 {
133   glDeleteTextures(1, &handle);
134 }
135
136 void
137 GLTexture::set_texture_params()
138 {
139   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
140   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
141 #ifdef GL_CLAMP
142   /* OpenGL ES doesn't support it */
143   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
144   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
145 #endif
146
147   assert_gl("set texture params");
148 }
149
150 /* EOF */