2010-07-10 22:47:29 +00:00
|
|
|
/* 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$
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2010-11-29 16:18:43 +00:00
|
|
|
#include "common/scummsys.h"
|
|
|
|
|
2010-07-31 19:57:54 +00:00
|
|
|
#if defined(USE_OPENGL)
|
2010-07-13 05:38:10 +00:00
|
|
|
|
2010-07-10 22:47:29 +00:00
|
|
|
#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;
|
2010-11-28 18:10:40 +00:00
|
|
|
static bool glext_inited = false;
|
2010-07-10 22:47:29 +00:00
|
|
|
|
2010-07-18 05:32:44 +00:00
|
|
|
/*static inline GLint xdiv(int numerator, int denominator) {
|
2010-07-10 22:47:29 +00:00
|
|
|
assert(numerator < (1 << 16));
|
|
|
|
return (numerator << 16) / denominator;
|
2010-07-18 05:32:44 +00:00
|
|
|
}*/
|
2010-07-10 22:47:29 +00:00
|
|
|
|
2010-07-15 04:20:21 +00:00
|
|
|
static GLuint nextHigher2(GLuint v) {
|
|
|
|
if (v == 0)
|
2010-07-10 22:47:29 +00:00
|
|
|
return 1;
|
2010-07-15 04:20:21 +00:00
|
|
|
v--;
|
|
|
|
v |= v >> 1;
|
|
|
|
v |= v >> 2;
|
|
|
|
v |= v >> 4;
|
|
|
|
v |= v >> 8;
|
|
|
|
v |= v >> 16;
|
2010-07-16 22:20:21 +00:00
|
|
|
return ++v;
|
2010-07-10 22:47:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GLTexture::initGLExtensions() {
|
2010-07-15 04:20:21 +00:00
|
|
|
|
2010-07-31 22:54:10 +00:00
|
|
|
// Return if extensions were already checked
|
2010-11-28 18:10:40 +00:00
|
|
|
if (glext_inited)
|
2010-07-15 04:20:21 +00:00
|
|
|
return;
|
|
|
|
|
2010-07-24 05:54:51 +00:00
|
|
|
// Get a string with all extensions
|
2010-07-10 22:47:29 +00:00
|
|
|
const char* ext_string =
|
|
|
|
reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
|
2010-07-20 07:10:25 +00:00
|
|
|
CHECK_GL_ERROR();
|
2010-07-10 22:47:29 +00:00
|
|
|
Common::StringTokenizer tokenizer(ext_string, " ");
|
2010-07-24 05:54:51 +00:00
|
|
|
// Iterate all string tokens
|
2010-07-10 22:47:29 +00:00
|
|
|
while (!tokenizer.empty()) {
|
|
|
|
Common::String token = tokenizer.nextToken();
|
|
|
|
if (token == "GL_ARB_texture_non_power_of_two")
|
|
|
|
npot_supported = true;
|
|
|
|
}
|
2010-07-24 05:54:51 +00:00
|
|
|
|
2010-11-28 18:10:40 +00:00
|
|
|
glext_inited = true;
|
2010-07-10 22:47:29 +00:00
|
|
|
}
|
|
|
|
|
2010-07-31 22:54:10 +00:00
|
|
|
GLTexture::GLTexture(byte bpp, GLenum internalFormat, GLenum format, GLenum type)
|
2010-07-12 06:00:19 +00:00
|
|
|
:
|
|
|
|
_bytesPerPixel(bpp),
|
2010-07-31 22:54:10 +00:00
|
|
|
_internalFormat(internalFormat),
|
2010-07-12 06:00:19 +00:00
|
|
|
_glFormat(format),
|
|
|
|
_glType(type),
|
2010-07-10 22:47:29 +00:00
|
|
|
_textureWidth(0),
|
2010-07-20 04:32:31 +00:00
|
|
|
_textureHeight(0),
|
|
|
|
_realWidth(0),
|
|
|
|
_realHeight(0),
|
2010-07-22 15:36:50 +00:00
|
|
|
_refresh(false),
|
|
|
|
_filter(GL_NEAREST) {
|
2010-07-10 22:47:29 +00:00
|
|
|
|
2010-07-24 05:54:51 +00:00
|
|
|
// Generate the texture ID
|
2010-07-20 07:10:25 +00:00
|
|
|
glGenTextures(1, &_textureName); CHECK_GL_ERROR();
|
2010-07-10 22:47:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GLTexture::~GLTexture() {
|
2010-07-24 05:54:51 +00:00
|
|
|
// Delete the texture
|
2010-07-20 07:10:25 +00:00
|
|
|
glDeleteTextures(1, &_textureName); CHECK_GL_ERROR();
|
2010-07-10 22:47:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GLTexture::refresh() {
|
2010-07-27 00:30:37 +00:00
|
|
|
// Delete previous texture
|
|
|
|
glDeleteTextures(1, &_textureName); CHECK_GL_ERROR();
|
|
|
|
|
2010-07-24 05:54:51 +00:00
|
|
|
// Generate the texture ID
|
2010-07-20 07:10:25 +00:00
|
|
|
glGenTextures(1, &_textureName); CHECK_GL_ERROR();
|
2010-07-20 04:32:31 +00:00
|
|
|
_refresh = true;
|
2010-07-10 22:47:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GLTexture::allocBuffer(GLuint w, GLuint h) {
|
2010-07-20 04:32:31 +00:00
|
|
|
_realWidth = w;
|
|
|
|
_realHeight = h;
|
|
|
|
|
|
|
|
if (w <= _textureWidth && h <= _textureHeight && !_refresh)
|
2010-07-10 22:47:29 +00:00
|
|
|
// Already allocated a sufficiently large buffer
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (npot_supported) {
|
2010-07-12 06:00:19 +00:00
|
|
|
_textureWidth = w;
|
|
|
|
_textureHeight = h;
|
2010-07-10 22:47:29 +00:00
|
|
|
} else {
|
2010-07-12 06:00:19 +00:00
|
|
|
_textureWidth = nextHigher2(w);
|
|
|
|
_textureHeight = nextHigher2(h);
|
2010-07-10 22:47:29 +00:00
|
|
|
}
|
|
|
|
|
2010-07-24 05:54:51 +00:00
|
|
|
// Select this OpenGL texture
|
2010-07-20 07:10:25 +00:00
|
|
|
glBindTexture(GL_TEXTURE_2D, _textureName); CHECK_GL_ERROR();
|
2010-07-24 05:54:51 +00:00
|
|
|
|
|
|
|
// Set the texture parameters
|
2010-07-22 15:36:50 +00:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _filter); CHECK_GL_ERROR();
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _filter); CHECK_GL_ERROR();
|
2010-07-20 07:10:25 +00:00
|
|
|
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();
|
2010-07-24 05:54:51 +00:00
|
|
|
|
|
|
|
// Allocate room for the texture
|
2010-07-31 22:54:10 +00:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, _internalFormat,
|
2010-07-26 06:58:33 +00:00
|
|
|
_textureWidth, _textureHeight, 0, _glFormat, _glType, NULL); CHECK_GL_ERROR();
|
2010-07-20 04:32:31 +00:00
|
|
|
|
|
|
|
_refresh = false;
|
2010-07-10 22:47:29 +00:00
|
|
|
}
|
|
|
|
|
2010-07-12 06:00:19 +00:00
|
|
|
void GLTexture::updateBuffer(const void *buf, int pitch, GLuint x, GLuint y, GLuint w, GLuint h) {
|
2011-01-08 16:05:27 +00:00
|
|
|
// Skip empty updates.
|
|
|
|
if (w * h == 0)
|
|
|
|
return;
|
|
|
|
|
2010-07-24 05:54:51 +00:00
|
|
|
// Select this OpenGL texture
|
2010-07-20 07:10:25 +00:00
|
|
|
glBindTexture(GL_TEXTURE_2D, _textureName); CHECK_GL_ERROR();
|
2010-07-10 22:47:29 +00:00
|
|
|
|
2010-07-24 05:54:51 +00:00
|
|
|
// Check if the buffer has its data contiguously
|
2011-02-24 16:08:51 +00:00
|
|
|
if (static_cast<int>(w) * _bytesPerPixel == pitch) {
|
2010-07-20 07:10:25 +00:00
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h,
|
|
|
|
_glFormat, _glType, buf); CHECK_GL_ERROR();
|
2010-07-31 19:20:33 +00:00
|
|
|
} else {
|
2010-07-24 05:54:51 +00:00
|
|
|
// Update the texture row by row
|
2010-07-23 06:57:23 +00:00
|
|
|
const byte *src = static_cast<const byte *>(buf);
|
2010-07-10 22:47:29 +00:00
|
|
|
do {
|
2010-07-20 07:10:25 +00:00
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y,
|
|
|
|
w, 1, _glFormat, _glType, src); CHECK_GL_ERROR();
|
2010-07-10 22:47:29 +00:00
|
|
|
++y;
|
|
|
|
src += pitch;
|
|
|
|
} while (--h);
|
2010-07-31 19:20:33 +00:00
|
|
|
}
|
2010-07-10 22:47:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GLTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) {
|
2010-07-24 05:54:51 +00:00
|
|
|
// Select this OpenGL texture
|
2010-07-20 07:10:25 +00:00
|
|
|
glBindTexture(GL_TEXTURE_2D, _textureName); CHECK_GL_ERROR();
|
2010-07-10 22:47:29 +00:00
|
|
|
|
2010-07-24 05:54:51 +00:00
|
|
|
// Calculate the texture rect that will be drawn
|
2010-07-20 04:32:31 +00:00
|
|
|
const GLfloat texWidth = (GLfloat)_realWidth / _textureWidth;//xdiv(_surface.w, _textureWidth);
|
|
|
|
const GLfloat texHeight = (GLfloat)_realHeight / _textureHeight;//xdiv(_surface.h, _textureHeight);
|
2010-07-18 05:32:44 +00:00
|
|
|
const GLfloat texcoords[] = {
|
2010-07-10 22:47:29 +00:00
|
|
|
0, 0,
|
2010-07-16 04:45:47 +00:00
|
|
|
texWidth, 0,
|
|
|
|
0, texHeight,
|
|
|
|
texWidth, texHeight,
|
2010-07-10 22:47:29 +00:00
|
|
|
};
|
2010-07-20 07:10:25 +00:00
|
|
|
glTexCoordPointer(2, GL_FLOAT, 0, texcoords); CHECK_GL_ERROR();
|
2010-07-10 22:47:29 +00:00
|
|
|
|
2010-07-24 05:54:51 +00:00
|
|
|
// Calculate the screen rect where the texture will be drawn
|
2010-07-10 22:47:29 +00:00
|
|
|
const GLshort vertices[] = {
|
2010-12-03 19:16:23 +00:00
|
|
|
x, y,
|
|
|
|
x + w, y,
|
|
|
|
x, y + h,
|
|
|
|
x + w, y + h,
|
2010-07-10 22:47:29 +00:00
|
|
|
};
|
2010-07-20 07:10:25 +00:00
|
|
|
glVertexPointer(2, GL_SHORT, 0, vertices); CHECK_GL_ERROR();
|
2010-07-10 22:47:29 +00:00
|
|
|
|
2010-07-24 05:54:51 +00:00
|
|
|
// Draw the texture to the screen buffer
|
2010-07-20 07:10:25 +00:00
|
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); CHECK_GL_ERROR();
|
2010-07-10 22:47:29 +00:00
|
|
|
}
|
2010-07-13 05:38:10 +00:00
|
|
|
|
|
|
|
#endif
|