mirror of
https://github.com/scummvm/scummvm.git
synced 2025-04-02 10:52:32 -04:00
228 lines
6.6 KiB
C++
228 lines
6.6 KiB
C++
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "graphics/opengl/system_headers.h"
|
|
|
|
#ifdef USE_OPENGL
|
|
|
|
#include "graphics/opengl/texture.h"
|
|
#include "graphics/opengl/debug.h"
|
|
|
|
#include "common/algorithm.h"
|
|
#include "common/endian.h"
|
|
#include "common/rect.h"
|
|
#include "common/textconsole.h"
|
|
|
|
namespace OpenGL {
|
|
|
|
Texture::Texture(GLenum glIntFormat, GLenum glFormat, GLenum glType, bool autoCreate)
|
|
: _glIntFormat(glIntFormat), _glFormat(glFormat), _glType(glType),
|
|
_width(0), _height(0), _logicalWidth(0), _logicalHeight(0),
|
|
_texCoords(), _glFilter(GL_NEAREST),
|
|
_glTexture(0) {
|
|
if (autoCreate)
|
|
create();
|
|
}
|
|
|
|
Texture::~Texture() {
|
|
GL_CALL_SAFE(glDeleteTextures, (1, &_glTexture));
|
|
}
|
|
|
|
void Texture::enableLinearFiltering(bool enable) {
|
|
if (enable) {
|
|
_glFilter = GL_LINEAR;
|
|
} else {
|
|
_glFilter = GL_NEAREST;
|
|
}
|
|
|
|
bind();
|
|
|
|
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _glFilter));
|
|
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _glFilter));
|
|
}
|
|
|
|
void Texture::setWrapMode(WrapMode wrapMode) {
|
|
GLuint glwrapMode;
|
|
|
|
switch(wrapMode) {
|
|
case kWrapModeBorder:
|
|
if (OpenGLContext.textureBorderClampSupported) {
|
|
glwrapMode = GL_CLAMP_TO_BORDER;
|
|
break;
|
|
}
|
|
// fall through
|
|
case kWrapModeEdge:
|
|
if (OpenGLContext.textureEdgeClampSupported) {
|
|
glwrapMode = GL_CLAMP_TO_EDGE;
|
|
break;
|
|
} else {
|
|
#if !USE_FORCED_GLES && !USE_FORCED_GLES2
|
|
// Fallback on clamp
|
|
glwrapMode = GL_CLAMP;
|
|
#else
|
|
// This fallback should never happen in real life (GLES/GLES2 have border/edge clamp)
|
|
glwrapMode = GL_REPEAT;
|
|
#endif
|
|
break;
|
|
}
|
|
case kWrapModeMirroredRepeat:
|
|
#if !USE_FORCED_GLES
|
|
if (OpenGLContext.textureMirrorRepeatSupported) {
|
|
glwrapMode = GL_MIRRORED_REPEAT;
|
|
break;
|
|
}
|
|
#endif
|
|
// fall through
|
|
case kWrapModeRepeat:
|
|
default:
|
|
glwrapMode = GL_REPEAT;
|
|
}
|
|
|
|
|
|
bind();
|
|
|
|
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glwrapMode));
|
|
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glwrapMode));
|
|
}
|
|
|
|
void Texture::destroy() {
|
|
GL_CALL(glDeleteTextures(1, &_glTexture));
|
|
_glTexture = 0;
|
|
}
|
|
|
|
void Texture::create() {
|
|
// Release old texture name in case it exists.
|
|
destroy();
|
|
|
|
// Get a new texture name.
|
|
GL_CALL(glGenTextures(1, &_glTexture));
|
|
|
|
// Set up all texture parameters.
|
|
bind();
|
|
GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
|
|
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _glFilter));
|
|
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _glFilter));
|
|
if (OpenGLContext.textureEdgeClampSupported) {
|
|
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
|
|
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
|
|
} else {
|
|
#if !USE_FORCED_GLES && !USE_FORCED_GLES2
|
|
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP));
|
|
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP));
|
|
#endif
|
|
}
|
|
|
|
// If a size is specified, allocate memory for it.
|
|
if (_width != 0 && _height != 0) {
|
|
// Allocate storage for OpenGL texture.
|
|
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, _glIntFormat, _width, _height,
|
|
0, _glFormat, _glType, nullptr));
|
|
}
|
|
}
|
|
|
|
void Texture::bind() const {
|
|
GL_CALL(glBindTexture(GL_TEXTURE_2D, _glTexture));
|
|
}
|
|
|
|
bool Texture::setSize(uint width, uint height) {
|
|
const uint oldWidth = _width;
|
|
const uint oldHeight = _height;
|
|
|
|
_logicalWidth = width;
|
|
_logicalHeight = height;
|
|
|
|
if (!OpenGLContext.NPOTSupported) {
|
|
_width = Common::nextHigher2(width);
|
|
_height = Common::nextHigher2(height);
|
|
} else {
|
|
_width = width;
|
|
_height = height;
|
|
}
|
|
|
|
// If a size is specified, allocate memory for it.
|
|
if (width != 0 && height != 0) {
|
|
const GLfloat texWidth = (GLfloat)width / _width;
|
|
const GLfloat texHeight = (GLfloat)height / _height;
|
|
|
|
_texCoords[0] = 0;
|
|
_texCoords[1] = 0;
|
|
|
|
_texCoords[2] = texWidth;
|
|
_texCoords[3] = 0;
|
|
|
|
_texCoords[4] = 0;
|
|
_texCoords[5] = texHeight;
|
|
|
|
_texCoords[6] = texWidth;
|
|
_texCoords[7] = texHeight;
|
|
|
|
// Allocate storage for OpenGL texture if necessary.
|
|
if (oldWidth != _width || oldHeight != _height) {
|
|
bind();
|
|
bool error;
|
|
GL_CALL_CHECK(error, glTexImage2D(GL_TEXTURE_2D, 0, _glIntFormat, _width, _height,
|
|
0, _glFormat, _glType, nullptr));
|
|
if (error) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void Texture::updateArea(const Common::Rect &area, const Graphics::Surface &src) {
|
|
// Set the texture on the active texture unit.
|
|
bind();
|
|
|
|
// Update the actual texture.
|
|
// Although we have the area of the texture buffer we want to update we
|
|
// cannot take advantage of the left/right boundaries here because it is
|
|
// not possible to specify a pitch to glTexSubImage2D. To be precise, with
|
|
// plain OpenGL we could set GL_UNPACK_ROW_LENGTH to achieve this. However,
|
|
// OpenGL ES 1.0 does not support GL_UNPACK_ROW_LENGTH. Thus, we are left
|
|
// with the following options:
|
|
//
|
|
// 1) (As we do right now) Simply always update the whole texture lines of
|
|
// rect changed. This is simplest to implement. In case performance is
|
|
// really an issue we can think of switching to another method.
|
|
//
|
|
// 2) Copy the dirty rect to a temporary buffer and upload that by using
|
|
// glTexSubImage2D. This is what the Android backend does. It is more
|
|
// complicated though.
|
|
//
|
|
// 3) Use glTexSubImage2D per line changed. This is what the old OpenGL
|
|
// graphics manager did but it is much slower! Thus, we do not use it.
|
|
GL_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, area.top, src.w, area.height(),
|
|
_glFormat, _glType, src.getBasePtr(0, area.top)));
|
|
}
|
|
|
|
const Graphics::PixelFormat Texture::getRGBAPixelFormat() {
|
|
#ifdef SCUMM_BIG_ENDIAN
|
|
return Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
|
|
#else
|
|
return Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24);
|
|
#endif
|
|
}
|
|
|
|
} // End of namespace OpenGL
|
|
|
|
#endif
|
|
|