diff options
author | Alejandro Marzini | 2010-07-10 22:47:29 +0000 |
---|---|---|
committer | Alejandro Marzini | 2010-07-10 22:47:29 +0000 |
commit | 85034dc730148dab3eb85b47be3f3984337e9484 (patch) | |
tree | b2877f92e3738fcf79956a91d17f1beabca6dcad /backends/graphics/opengl/gltexture.cpp | |
parent | 386785e2b85b066398122d747117f97dbbb4896a (diff) | |
download | scummvm-rg350-85034dc730148dab3eb85b47be3f3984337e9484.tar.gz scummvm-rg350-85034dc730148dab3eb85b47be3f3984337e9484.tar.bz2 scummvm-rg350-85034dc730148dab3eb85b47be3f3984337e9484.zip |
Added BaseSdlGraphicsManager. Added GLTexture.
svn-id: r50795
Diffstat (limited to 'backends/graphics/opengl/gltexture.cpp')
-rw-r--r-- | backends/graphics/opengl/gltexture.cpp | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/backends/graphics/opengl/gltexture.cpp b/backends/graphics/opengl/gltexture.cpp new file mode 100644 index 0000000000..de9bd13eaf --- /dev/null +++ b/backends/graphics/opengl/gltexture.cpp @@ -0,0 +1,173 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "backends/graphics/opengl/gltexture.h" +#include "backends/graphics/opengl/glerrorcheck.h" + +#include "common/rect.h" +#include "common/array.h" +#include "common/util.h" +#include "common/tokenizer.h" + +// Supported GL extensions +static bool npot_supported = false; + +static inline GLint xdiv(int numerator, int denominator) { + assert(numerator < (1 << 16)); + return (numerator << 16) / denominator; +} + +template <class T> +static T nextHigher2(T k) { + if (k == 0) + return 1; + --k; + for (uint i = 1; i < sizeof(T) * CHAR_BIT; i <<= 1) + k = k | k >> i; + return k + 1; +} + +void GLTexture::initGLExtensions() { + const char* ext_string = + reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)); + Common::StringTokenizer tokenizer(ext_string, " "); + while (!tokenizer.empty()) { + Common::String token = tokenizer.nextToken(); + if (token == "GL_ARB_texture_non_power_of_two") + npot_supported = true; + } +} + +GLTexture::GLTexture() : + _textureWidth(0), + _textureHeight(0) { + + refresh(); + + // This all gets reset later in allocBuffer: + _surface.w = 0; + _surface.h = 0; + _surface.pitch = 0; + _surface.pixels = NULL; + _surface.bytesPerPixel = 0; +} + +GLTexture::~GLTexture() { + debug("Destroying texture %u", _textureName); + CHECK_GL_ERROR( glDeleteTextures(1, &_textureName) ); +} + +void GLTexture::refresh() { + // Generates the texture ID for GL + CHECK_GL_ERROR( glGenTextures(1, &_textureName) ); +} + +void GLTexture::allocBuffer(GLuint w, GLuint h) { + int bpp = bytesPerPixel(); + _surface.w = w; + _surface.h = h; + _surface.bytesPerPixel = bpp; + + if (w <= _textureWidth && h <= _textureHeight) + // Already allocated a sufficiently large buffer + return; + + if (npot_supported) { + _textureWidth = _surface.w; + _textureHeight = _surface.h; + } else { + _textureWidth = nextHigher2(_surface.w); + _textureHeight = nextHigher2(_surface.h); + } + _surface.pitch = _textureWidth * bpp; + + _surface.create(w, h, bytesPerPixel()); + + // Allocate room for the texture now, but pixel data gets uploaded + // later (perhaps with multiple TexSubImage2D operations). + CHECK_GL_ERROR( glBindTexture(GL_TEXTURE_2D, _textureName) ); + CHECK_GL_ERROR( glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) ); + CHECK_GL_ERROR( glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) ); + CHECK_GL_ERROR( glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) ); + CHECK_GL_ERROR( glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) ); + CHECK_GL_ERROR( glTexImage2D(GL_TEXTURE_2D, 0, glFormat(), + _textureWidth, _textureHeight, + 0, glFormat(), glType(), NULL) ); +} + +void GLTexture::updateBuffer(GLuint x, GLuint y, GLuint w, GLuint h, const void* buf, int pitch) { + CHECK_GL_ERROR( glBindTexture(GL_TEXTURE_2D, _textureName) ); + + if (static_cast<int>(w) * bytesPerPixel() == pitch) { + CHECK_GL_ERROR( glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, + glFormat(), glType(), buf) ); + memcpy(_surface.pixels, buf, w * pitch); + } else { + // GLES removed the ability to specify pitch, so we + // have to do this row by row. + const byte* src = static_cast<const byte*>(buf); + do { + CHECK_GL_ERROR( glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, + w, 1, glFormat(), glType(), src) ); + memcpy(_surface.pixels, src, pitch); + ++y; + src += pitch; + } while (--h); + } +} + +void GLTexture::fillBuffer(byte x) { + byte* tmpbuf = new byte[_surface.h * _surface.w * bytesPerPixel()]; + memset(tmpbuf, 0, _surface.h * _surface.w * bytesPerPixel()); + CHECK_GL_ERROR( glBindTexture(GL_TEXTURE_2D, _textureName) ); + CHECK_GL_ERROR( glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _surface.w, _surface.h, + glFormat(), glType(), tmpbuf) ); + delete[] tmpbuf; +} + +void GLTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { + CHECK_GL_ERROR( glBindTexture(GL_TEXTURE_2D, _textureName) ); + + const GLint tex_width = xdiv(_surface.w, _textureWidth); + const GLint tex_height = xdiv(_surface.h, _textureHeight); + const GLint texcoords[] = { + 0, 0, + tex_width, 0, + 0, tex_height, + tex_width, tex_height, + }; + CHECK_GL_ERROR( glTexCoordPointer(2, GL_INT, 0, texcoords) ); + + const GLshort vertices[] = { + x, y, + x + w, y, + x, y + h, + x + w, y + h, + }; + CHECK_GL_ERROR( glVertexPointer(2, GL_SHORT, 0, vertices) ); + + assert(ARRAYSIZE(vertices) == ARRAYSIZE(texcoords)); + CHECK_GL_ERROR( glDrawArrays(GL_TRIANGLE_STRIP, 0, ARRAYSIZE(vertices) / 2) ); +} |