Update with current status
[gnash.git] / librender / GnashTexture.cpp
blob72c7403798a2212ccbb99413f7de9ecf5d0615db
1 // GnashTexture.cpp: GnashImage class used for OpenGL rendering
2 //
3 // Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012
4 // Free Software Foundation, Inc.
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "GnashTexture.h"
22 #include <GL/gl.h>
23 #include <GL/glu.h>
25 #define GL_DEBUG 0
27 #if GL_DEBUG
28 # define D(x) x
29 #else
30 # define D(x)
31 #endif
32 #define bug printf
34 namespace gnash {
36 struct gl_errors_t {
37 GLenum val;
38 const char *str;
41 static inline bool gl_do_check_error(int report)
43 GLenum error;
44 bool is_error = false;
45 while ((error = glGetError()) != GL_NO_ERROR) {
46 if (report)
47 log_error(_("glError: %s caught\n"), gluErrorString(error));
48 is_error = true;
50 return is_error;
53 static inline void gl_purge_errors(void)
55 gl_do_check_error(0);
58 static inline bool gl_check_error(void)
60 return gl_do_check_error(1);
63 // glGetIntegerv() wrapper
64 static bool gl_get_param(GLenum param, unsigned int *pval)
66 GLint val;
68 gl_purge_errors();
69 glGetIntegerv(param, &val);
70 if (gl_check_error())
71 return false;
72 if (pval)
73 *pval = val;
74 return true;
77 // Check for GLX extensions (TFP, FBO)
78 static bool check_extension(const char *name, const char *ext)
80 const char *end;
81 int name_len, n;
83 if (name == nullptr || ext == nullptr)
84 return false;
86 end = ext + strlen(ext);
87 name_len = strlen(name);
88 while (ext < end) {
89 n = strcspn(ext, " ");
90 if (n == name_len && strncmp(name, ext, n) == 0)
91 return true;
92 ext += (n + 1);
94 return false;
97 GnashTextureFormat::GnashTextureFormat(image::ImageType type)
99 switch (type) {
100 case image::TYPE_RGB:
101 _internal_format = GL_RGB;
102 _format = GL_RGB;
103 break;
104 case image::TYPE_RGBA:
105 _internal_format = GL_RGBA;
106 _format = GL_BGRA;
107 break;
108 default:
109 assert(0);
110 break;
114 GnashTexture::GnashTexture(unsigned int width, unsigned int height,
115 image::ImageType type)
117 _width(width),
118 _height(height),
119 _texture(0),
120 _format(type),
121 _flags(0)
123 D(bug("GnashTexture::GnashTexture()\n"));
125 init();
128 GnashTexture::~GnashTexture()
130 D(bug("GnashTexture::~GnashTexture()\n"));
132 if (_texture) {
133 glDeleteTextures(1, &_texture);
134 _texture = 0;
138 bool GnashTexture::init()
140 // XXX: we only support NPOT textures
141 const char *gl_extensions = (const char *)glGetString(GL_EXTENSIONS);
142 if (!check_extension("GL_ARB_texture_non_power_of_two", gl_extensions))
143 return false;
145 assert(_width > 0);
146 assert(_height > 0);
147 if (_width == 0 || _height == 0)
148 return false;
150 glGenTextures(1, &_texture);
151 if (!_texture)
152 return false;
154 if (!bind()) {
155 glDeleteTextures(1, &_texture);
156 return false;
159 glPixelStorei(GL_UNPACK_ALIGNMENT, internal_format() == GL_RGBA ? 4 : 1);
160 glTexImage2D(GL_TEXTURE_2D, 0, internal_format(), _width, _height, 0,
161 format(), GL_UNSIGNED_BYTE, nullptr);
162 release();
163 return true;
166 // Bind texture, preserve previous texture state
167 bool GnashTexture::bind()
169 TextureState * const ts = &_texture_state;
170 ts->old_texture = 0;
171 ts->was_bound = 0;
172 ts->was_enabled = glIsEnabled(GL_TEXTURE_2D);
174 if (!ts->was_enabled)
175 glEnable(GL_TEXTURE_2D);
176 else if (gl_get_param(GL_TEXTURE_BINDING_2D, &ts->old_texture))
177 ts->was_bound = _texture == ts->old_texture;
178 else
179 return false;
181 if (!ts->was_bound) {
182 gl_purge_errors();
183 glBindTexture(GL_TEXTURE_2D, _texture);
184 if (gl_check_error())
185 return false;
188 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
189 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
190 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
191 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
192 return true;
195 // Release texture, restore previous texture state
196 void GnashTexture::release()
198 TextureState * const ts = &_texture_state;
199 if (!ts->was_bound && ts->old_texture)
200 glBindTexture(GL_TEXTURE_2D, ts->old_texture);
201 if (!ts->was_enabled)
202 glDisable(GL_TEXTURE_2D);
203 gl_check_error();
206 // Update texture with data
207 void GnashTexture::update(const std::uint8_t *data)
209 D(bug("GnashTexture::update(): data %p, size %dx%d\n", data, _width, _height));
211 bind();
212 glTexSubImage2D(GL_TEXTURE_2D, 0,
213 0, 0, _width, _height,
214 format(), GL_UNSIGNED_BYTE, data);
215 release();
218 } // gnash namespace