Fix test for bug #32625
[gnash.git] / libbase / GnashTexture.cpp
blob7b9f0a1cfeed5b60413365379d31bfda289410db
1 // GnashTexture.cpp: GnashImage class used for OpenGL rendering
2 //
3 // Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 #include "GnashTexture.h"
21 #include <GL/gl.h>
23 #define GL_DEBUG 0
25 #if GL_DEBUG
26 # define D(x) x
27 #else
28 # define D(x)
29 #endif
30 #define bug printf
32 namespace gnash {
34 // Returns a string representation of an OpenGL error
35 static const char *gl_get_error_string(GLenum error)
37 static const struct {
38 GLenum val;
39 const char *str;
41 gl_errors[] = {
42 { GL_NO_ERROR, "no error" },
43 { GL_INVALID_ENUM, "invalid enumerant" },
44 { GL_INVALID_VALUE, "invalid value" },
45 { GL_INVALID_OPERATION, "invalid operation" },
46 { GL_STACK_OVERFLOW, "stack overflow" },
47 { GL_STACK_UNDERFLOW, "stack underflow" },
48 { GL_OUT_OF_MEMORY, "out of memory" },
49 #ifdef GL_INVALID_FRAMEBUFFER_OPERATION_EXT
50 { GL_INVALID_FRAMEBUFFER_OPERATION_EXT, "invalid framebuffer operation" },
51 #endif
52 { ~0, NULL }
55 int i;
56 for (i = 0; gl_errors[i].str; i++) {
57 if (gl_errors[i].val == error)
58 return gl_errors[i].str;
60 return "unknown";
63 static inline bool gl_do_check_error(int report)
65 GLenum error;
66 bool is_error = false;
67 while ((error = glGetError()) != GL_NO_ERROR) {
68 if (report)
69 log_error("glError: %s caught\n", gl_get_error_string(error));
70 is_error = true;
72 return is_error;
75 static inline void gl_purge_errors(void)
77 gl_do_check_error(0);
80 static inline bool gl_check_error(void)
82 return gl_do_check_error(1);
85 // glGetIntegerv() wrapper
86 static bool gl_get_param(GLenum param, unsigned int *pval)
88 GLint val;
90 gl_purge_errors();
91 glGetIntegerv(param, &val);
92 if (gl_check_error())
93 return false;
94 if (pval)
95 *pval = val;
96 return true;
99 // Check for GLX extensions (TFP, FBO)
100 static bool check_extension(const char *name, const char *ext)
102 const char *end;
103 int name_len, n;
105 if (name == NULL || ext == NULL)
106 return false;
108 end = ext + strlen(ext);
109 name_len = strlen(name);
110 while (ext < end) {
111 n = strcspn(ext, " ");
112 if (n == name_len && strncmp(name, ext, n) == 0)
113 return true;
114 ext += (n + 1);
116 return false;
119 GnashTextureFormat::GnashTextureFormat(image::ImageType type)
121 switch (type) {
122 case image::TYPE_RGB:
123 _internal_format = GL_RGB;
124 _format = GL_RGB;
125 break;
126 case image::TYPE_RGBA:
127 _internal_format = GL_RGBA;
128 _format = GL_BGRA;
129 break;
130 default:
131 assert(0);
132 break;
136 GnashTexture::GnashTexture(unsigned int width, unsigned int height,
137 image::ImageType type)
139 _width(width),
140 _height(height),
141 _texture(0),
142 _format(type),
143 _flags(0)
145 D(bug("GnashTexture::GnashTexture()\n"));
147 init();
150 GnashTexture::~GnashTexture()
152 D(bug("GnashTexture::~GnashTexture()\n"));
154 if (_texture) {
155 glDeleteTextures(1, &_texture);
156 _texture = 0;
160 bool GnashTexture::init()
162 // XXX: we only support NPOT textures
163 const char *gl_extensions = (const char *)glGetString(GL_EXTENSIONS);
164 if (!check_extension("GL_ARB_texture_non_power_of_two", gl_extensions))
165 return false;
167 assert(_width > 0);
168 assert(_height > 0);
169 if (_width == 0 || _height == 0)
170 return false;
172 glGenTextures(1, &_texture);
173 if (!_texture)
174 return false;
176 if (!bind()) {
177 glDeleteTextures(1, &_texture);
178 return false;
181 glPixelStorei(GL_UNPACK_ALIGNMENT, internal_format() == GL_RGBA ? 4 : 1);
182 glTexImage2D(GL_TEXTURE_2D, 0, internal_format(), _width, _height, 0,
183 format(), GL_UNSIGNED_BYTE, NULL);
184 release();
185 return true;
188 // Bind texture, preserve previous texture state
189 bool GnashTexture::bind()
191 TextureState * const ts = &_texture_state;
192 ts->old_texture = 0;
193 ts->was_bound = 0;
194 ts->was_enabled = glIsEnabled(GL_TEXTURE_2D);
196 if (!ts->was_enabled)
197 glEnable(GL_TEXTURE_2D);
198 else if (gl_get_param(GL_TEXTURE_BINDING_2D, &ts->old_texture))
199 ts->was_bound = _texture == ts->old_texture;
200 else
201 return false;
203 if (!ts->was_bound) {
204 gl_purge_errors();
205 glBindTexture(GL_TEXTURE_2D, _texture);
206 if (gl_check_error())
207 return false;
210 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
211 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
212 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
213 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
214 return true;
217 // Release texture, restore previous texture state
218 void GnashTexture::release()
220 TextureState * const ts = &_texture_state;
221 if (!ts->was_bound && ts->old_texture)
222 glBindTexture(GL_TEXTURE_2D, ts->old_texture);
223 if (!ts->was_enabled)
224 glDisable(GL_TEXTURE_2D);
225 gl_check_error();
228 // Update texture with data
229 void GnashTexture::update(const boost::uint8_t *data)
231 D(bug("GnashTexture::update(): data %p, size %dx%d\n", data, _width, _height));
233 bind();
234 glTexSubImage2D(GL_TEXTURE_2D, 0,
235 0, 0, _width, _height,
236 format(), GL_UNSIGNED_BYTE, data);
237 release();
240 } // gnash namespace