Refactored video/ subsystem to make adding other methods of rendering (in particular...
[supertux.git] / src / video / gl_texture.cpp
1 //  $Id: gl_texture.cpp 4063 2006-07-21 21:05:23Z anmaster $
2 //
3 //  SuperTux
4 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 2
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19
20 #include <config.h>
21
22 #ifdef HAVE_OPENGL
23
24 #include "gl_texture.hpp"
25 #include "gameconfig.hpp"
26 #include "glutil.hpp"
27 #include "log.hpp"
28
29 #include <assert.h>
30 #include <stdexcept>
31
32 namespace
33 {
34   inline bool is_power_of_2(int v)
35   {
36     return (v & (v-1)) == 0;
37   }
38
39   inline int next_power_of_two(int val)
40   {
41     int result = 1;
42     while(result < val)
43       result *= 2;
44     return result;
45   }
46 }
47
48 namespace GL
49 {
50   Texture::Texture(unsigned int width, unsigned int height)
51   {
52     assert(is_power_of_2(width));
53     assert(is_power_of_2(height));
54     texture_width = width;
55     texture_height = height;
56     image_width = width;
57     image_height = height;
58
59     assert_gl("before creating texture");
60     glGenTextures(1, &handle);
61
62     try {
63       glBindTexture(GL_TEXTURE_2D, handle);
64
65       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_width,
66                    texture_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
67
68       set_texture_params();
69     } catch(...) {
70       glDeleteTextures(1, &handle);
71       throw;
72     }
73   }
74
75   Texture::Texture(SDL_Surface* image)
76   {
77     texture_width = next_power_of_two(image->w);
78     texture_height = next_power_of_two(image->h);
79     image_width = image->w;
80     image_height = image->h;
81
82 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
83     SDL_Surface* convert = SDL_CreateRGBSurface(SDL_SWSURFACE,
84         texture_width, texture_height, 32,
85         0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
86 #else
87     SDL_Surface* convert = SDL_CreateRGBSurface(SDL_SWSURFACE,
88         texture_width, texture_height, 32,
89         0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
90 #endif
91
92     if(convert == 0) {
93       throw std::runtime_error("Couldn't create texture: out of memory");
94     }
95
96     SDL_SetAlpha(image, 0, 0);
97     SDL_BlitSurface(image, 0, convert, 0);
98
99     assert_gl("before creating texture");
100     glGenTextures(1, &handle);
101
102     try {
103       GLenum sdl_format;
104       if(convert->format->BytesPerPixel == 3)
105         sdl_format = GL_RGB;
106       else if(convert->format->BytesPerPixel == 4)
107         sdl_format = GL_RGBA;
108       else
109         assert(false);
110
111       glBindTexture(GL_TEXTURE_2D, handle);
112       glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
113       glPixelStorei(GL_UNPACK_ROW_LENGTH, convert->pitch/convert->format->BytesPerPixel);
114       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_width,
115               texture_height, 0, sdl_format,
116               GL_UNSIGNED_BYTE, convert->pixels);
117
118       assert_gl("creating texture");
119
120       set_texture_params();
121     } catch(...) {
122       glDeleteTextures(1, &handle);
123       SDL_FreeSurface(convert);
124       throw;
125     }
126     SDL_FreeSurface(convert);
127   }
128
129   Texture::~Texture()
130   {
131     glDeleteTextures(1, &handle);
132   }
133
134   void
135   Texture::set_texture_params()
136   {
137     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
138     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
139     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
140     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
141
142     assert_gl("set texture params");
143   }
144 }
145
146 #endif