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) ); +} | 
