aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Schickel2013-08-16 05:29:56 +0200
committerJohannes Schickel2013-10-19 22:12:01 +0200
commit46323074e77622e7d08fe20bfdcc459b8eba08a3 (patch)
tree4bdb5ccf144faec961ee348199e6068097873441
parent8a6e57cba1c89f922e27bb72201cfda55681f6dc (diff)
downloadscummvm-rg350-46323074e77622e7d08fe20bfdcc459b8eba08a3.tar.gz
scummvm-rg350-46323074e77622e7d08fe20bfdcc459b8eba08a3.tar.bz2
scummvm-rg350-46323074e77622e7d08fe20bfdcc459b8eba08a3.zip
OPENGL: Add new generic OpenGL (ES) backend.
This backend is based on ideas of the old OpenGL backend, of the Android GL backend and of the iPhone GL backend.
-rw-r--r--backends/graphics/opengl/debug.cpp65
-rw-r--r--backends/graphics/opengl/debug.h39
-rw-r--r--backends/graphics/opengl/extensions.cpp48
-rw-r--r--backends/graphics/opengl/extensions.h41
-rw-r--r--backends/graphics/opengl/opengl-graphics.cpp922
-rw-r--r--backends/graphics/opengl/opengl-graphics.h418
-rw-r--r--backends/graphics/opengl/opengl-sys.h57
-rw-r--r--backends/graphics/opengl/texture.cpp305
-rw-r--r--backends/graphics/opengl/texture.h159
-rw-r--r--backends/module.mk9
-rw-r--r--engines/engine.cpp2
11 files changed, 2064 insertions, 1 deletions
diff --git a/backends/graphics/opengl/debug.cpp b/backends/graphics/opengl/debug.cpp
new file mode 100644
index 0000000000..69006bb975
--- /dev/null
+++ b/backends/graphics/opengl/debug.cpp
@@ -0,0 +1,65 @@
+/* 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.
+ *
+ */
+
+#include "backends/graphics/opengl/debug.h"
+#include "backends/graphics/opengl/opengl-sys.h"
+
+#include "common/str.h"
+#include "common/textconsole.h"
+
+#ifdef OPENGL_DEBUG
+
+namespace OpenGL {
+
+namespace {
+Common::String getGLErrStr(GLenum error) {
+ switch (error) {
+ case GL_INVALID_ENUM:
+ return "GL_INVALID_ENUM";
+ case GL_INVALID_VALUE:
+ return "GL_INVALID_VALUE";
+ case GL_INVALID_OPERATION:
+ return "GL_INVALID_OPERATION";
+ case GL_STACK_OVERFLOW:
+ return "GL_STACK_OVERFLOW";
+ case GL_STACK_UNDERFLOW:
+ return "GL_STACK_UNDERFLOW";
+ case GL_OUT_OF_MEMORY:
+ return "GL_OUT_OF_MEMORY";
+ }
+
+ return Common::String::format("(Unknown GL error code 0x%X)", error);
+}
+} // End of anonymous namespace
+
+void checkGLError(const char *expr, const char *file, int line) {
+ GLenum error = glGetError();
+
+ if (error != GL_NO_ERROR) {
+ // We cannot use error here because we do not know whether we have a
+ // working screen or not.
+ warning("GL ERROR: %s on %s (%s:%d)", getGLErrStr(error).c_str(), expr, file, line);
+ }
+}
+} // End of namespace OpenGL
+
+#endif
diff --git a/backends/graphics/opengl/debug.h b/backends/graphics/opengl/debug.h
new file mode 100644
index 0000000000..ff6b678870
--- /dev/null
+++ b/backends/graphics/opengl/debug.h
@@ -0,0 +1,39 @@
+/* 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.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_OPENGL_DEBUG_H
+#define BACKENDS_GRAPHICS_OPENGL_DEBUG_H
+
+#define OPENGL_DEBUG
+
+#ifdef OPENGL_DEBUG
+
+namespace OpenGL {
+void checkGLError(const char *expr, const char *file, int line);
+} // End of namespace OpenGL
+
+#define GLCALL(x) do { (x); OpenGL::checkGLError(#x, __FILE__, __LINE__); } while (false)
+#else
+#define GLCALL(x) do { (x); } while (false)
+#endif
+
+#endif
diff --git a/backends/graphics/opengl/extensions.cpp b/backends/graphics/opengl/extensions.cpp
new file mode 100644
index 0000000000..4482ef82b5
--- /dev/null
+++ b/backends/graphics/opengl/extensions.cpp
@@ -0,0 +1,48 @@
+/* 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.
+ *
+ */
+
+#include "backends/graphics/opengl/extensions.h"
+#include "backends/graphics/opengl/opengl-sys.h"
+
+#include "common/tokenizer.h"
+
+namespace OpenGL {
+
+bool g_extNPOTSupported = false;
+
+void initializeGLExtensions() {
+ const char *extString = (const char *)glGetString(GL_EXTENSIONS);
+
+ // Initialize default state.
+ g_extNPOTSupported = false;
+
+ Common::StringTokenizer tokenizer(extString, " ");
+ while (!tokenizer.empty()) {
+ Common::String token = tokenizer.nextToken();
+
+ if (token == "GL_ARB_texture_non_power_of_two") {
+ g_extNPOTSupported = true;
+ }
+ }
+}
+
+} // End of namespace OpenGL
diff --git a/backends/graphics/opengl/extensions.h b/backends/graphics/opengl/extensions.h
new file mode 100644
index 0000000000..87452429e2
--- /dev/null
+++ b/backends/graphics/opengl/extensions.h
@@ -0,0 +1,41 @@
+/* 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.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_OPENGL_EXTENSIONS_H
+#define BACKENDS_GRAPHICS_OPENGL_EXTENSIONS_H
+
+namespace OpenGL {
+
+/**
+ * Checks for availability of extensions we want to use and initializes them
+ * when available.
+ */
+void initializeGLExtensions();
+
+/**
+ * Whether non power of two textures are supported
+ */
+extern bool g_extNPOTSupported;
+
+} // End of namespace OpenGL
+
+#endif
diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
new file mode 100644
index 0000000000..7ea880c92e
--- /dev/null
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -0,0 +1,922 @@
+/* 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.
+ *
+ */
+
+
+#include "backends/graphics/opengl/opengl-graphics.h"
+#include "backends/graphics/opengl/texture.h"
+#include "backends/graphics/opengl/debug.h"
+#include "backends/graphics/opengl/extensions.h"
+
+#include "common/textconsole.h"
+#include "common/translation.h"
+#include "common/algorithm.h"
+
+#include "graphics/conversion.h"
+
+namespace OpenGL {
+
+OpenGLGraphicsManager::OpenGLGraphicsManager()
+ : _currentState(), _oldState(), _transactionMode(kTransactionNone), _screenChangeID(1 << (sizeof(int) * 8 - 2)),
+ _outputScreenWidth(0), _outputScreenHeight(0), _displayX(0), _displayY(0),
+ _displayWidth(0), _displayHeight(0), _defaultFormat(), _defaultFormatAlpha(),
+ _gameScreen(nullptr), _gameScreenShakeOffset(0), _overlay(nullptr),
+ _overlayVisible(false), _cursor(nullptr),
+ _cursorX(0), _cursorY(0), _cursorHotspotX(0), _cursorHotspotY(0), _cursorHotspotXScaled(0),
+ _cursorHotspotYScaled(0), _cursorWidthScaled(0), _cursorHeightScaled(0), _cursorKeyColor(0),
+ _cursorVisible(false), _cursorDontScale(false), _cursorPaletteEnabled(false) {
+ memset(_gamePalette, 0, sizeof(_gamePalette));
+}
+
+OpenGLGraphicsManager::~OpenGLGraphicsManager() {
+ delete _gameScreen;
+ delete _overlay;
+ delete _cursor;
+}
+
+bool OpenGLGraphicsManager::hasFeature(OSystem::Feature f) {
+ switch (f) {
+ case OSystem::kFeatureAspectRatioCorrection:
+ case OSystem::kFeatureCursorPalette:
+ return true;
+
+ case OSystem::kFeatureOverlaySupportsAlpha:
+ return _defaultFormatAlpha.aBits() > 3;
+
+ default:
+ return false;
+ }
+}
+
+void OpenGLGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
+ switch (f) {
+ case OSystem::kFeatureAspectRatioCorrection:
+ assert(_transactionMode != kTransactionNone);
+ _currentState.aspectRatioCorrection = enable;
+ break;
+
+ case OSystem::kFeatureCursorPalette:
+ _cursorPaletteEnabled = enable;
+ updateCursorPalette();
+ break;
+
+ default:
+ break;
+ }
+}
+
+bool OpenGLGraphicsManager::getFeatureState(OSystem::Feature f) {
+ switch (f) {
+ case OSystem::kFeatureAspectRatioCorrection:
+ return _currentState.aspectRatioCorrection;
+
+ case OSystem::kFeatureCursorPalette:
+ return _cursorPaletteEnabled;
+
+ default:
+ return false;
+ }
+}
+
+namespace {
+
+const OSystem::GraphicsMode glGraphicsModes[] = {
+ { "opengl_linear", _s("OpenGL"), GFX_LINEAR },
+ { "opengl_nearest", _s("OpenGL (No filtering)"), GFX_NEAREST },
+ { nullptr, nullptr, 0 }
+};
+
+} // End of anonymous namespace
+
+const OSystem::GraphicsMode *OpenGLGraphicsManager::getSupportedGraphicsModes() const {
+ return glGraphicsModes;
+}
+
+int OpenGLGraphicsManager::getDefaultGraphicsMode() const {
+ return GFX_LINEAR;
+}
+
+bool OpenGLGraphicsManager::setGraphicsMode(int mode) {
+ assert(_transactionMode != kTransactionNone);
+
+ switch (mode) {
+ case GFX_LINEAR:
+ case GFX_NEAREST:
+ _currentState.graphicsMode = mode;
+
+ if (_gameScreen) {
+ _gameScreen->enableLinearFiltering(mode == GFX_LINEAR);
+ }
+
+ if (_overlay) {
+ _overlay->enableLinearFiltering(mode == GFX_LINEAR);
+ }
+
+ if (_cursor) {
+ _cursor->enableLinearFiltering(mode == GFX_LINEAR);
+ }
+ return true;
+
+ default:
+ warning("OpenGLGraphicsManager::setGraphicsMode(%d): Unknown graphics mode", mode);
+ return false;
+ }
+}
+
+int OpenGLGraphicsManager::getGraphicsMode() const {
+ return _currentState.graphicsMode;
+}
+
+#ifdef USE_RGB_COLOR
+Graphics::PixelFormat OpenGLGraphicsManager::getScreenFormat() const {
+ return _currentState.gameFormat;
+}
+#endif
+
+void OpenGLGraphicsManager::beginGFXTransaction() {
+ assert(_transactionMode == kTransactionNone);
+
+ // Start a transaction.
+ _oldState = _currentState;
+ _transactionMode = kTransactionActive;
+}
+
+OSystem::TransactionError OpenGLGraphicsManager::endGFXTransaction() {
+ assert(_transactionMode == kTransactionActive);
+
+ uint transactionError = OSystem::kTransactionSuccess;
+
+ bool setupNewGameScreen = false;
+ if ( _oldState.gameWidth != _currentState.gameWidth
+ || _oldState.gameHeight != _currentState.gameHeight) {
+ setupNewGameScreen = true;
+ }
+
+#ifdef USE_RGB_COLOR
+ if (_oldState.gameFormat != _currentState.gameFormat) {
+ setupNewGameScreen = true;
+ }
+
+ // Check whether the requested format can actually be used.
+ Common::List<Graphics::PixelFormat> supportedFormats = getSupportedFormats();
+ // In case the requested format is not usable we will fall back to CLUT8.
+ if (Common::find(supportedFormats.begin(), supportedFormats.end(), _currentState.gameFormat) == supportedFormats.end()) {
+ _currentState.gameFormat = Graphics::PixelFormat::createFormatCLUT8();
+ transactionError |= OSystem::kTransactionFormatNotSupported;
+ }
+#endif
+
+ do {
+ uint requestedWidth = _currentState.gameWidth;
+ uint requestedHeight = _currentState.gameHeight;
+ const uint desiredAspect = getDesiredGameScreenAspect();
+ requestedHeight = intToFrac(requestedWidth) / desiredAspect;
+
+ if (!loadVideoMode(requestedWidth, requestedHeight,
+#ifdef USE_RGB_COLOR
+ _currentState.gameFormat
+#else
+ Graphics::PixelFormat::createFormatCLUT8()
+#endif
+ )) {
+ if (_transactionMode == kTransactionActive) {
+ // Try to setup the old state in case its valid and is
+ // actually different from the new one.
+ if (_oldState.valid && _oldState != _currentState) {
+ // Give some hints on what failed to set up.
+ if ( _oldState.gameWidth != _currentState.gameWidth
+ || _oldState.gameHeight != _currentState.gameHeight) {
+ transactionError |= OSystem::kTransactionSizeChangeFailed;
+ }
+
+#ifdef USE_RGB_COLOR
+ if (_oldState.gameFormat != _currentState.gameFormat) {
+ transactionError |= OSystem::kTransactionFormatNotSupported;
+ }
+#endif
+
+ if (_oldState.aspectRatioCorrection != _currentState.aspectRatioCorrection) {
+ transactionError |= OSystem::kTransactionAspectRatioFailed;
+ }
+
+ if (_oldState.graphicsMode != _currentState.graphicsMode) {
+ transactionError |= OSystem::kTransactionModeSwitchFailed;
+ }
+
+ // Roll back to the old state.
+ _currentState = _oldState;
+ _transactionMode = kTransactionRollback;
+
+ // Try to set up the old state.
+ continue;
+ }
+ }
+
+ // DON'T use error(), as this tries to bring up the debug
+ // console, which WON'T WORK now that we might no have a
+ // proper screen.
+ warning("OpenGLGraphicsManager::endGFXTransaction: Could not load any graphics mode!");
+ g_system->quit();
+ }
+
+ // In case we reach this we have a valid state, yay.
+ _transactionMode = kTransactionNone;
+ _currentState.valid = true;
+ } while (_transactionMode == kTransactionRollback);
+
+ if (setupNewGameScreen) {
+ delete _gameScreen;
+ _gameScreen = nullptr;
+
+ GLenum glIntFormat, glFormat, glType;
+#ifdef USE_RGB_COLOR
+ if (_currentState.gameFormat.bytesPerPixel == 1) {
+#endif
+ const bool supported = getGLPixelFormat(_defaultFormat, glIntFormat, glFormat, glType);
+ assert(supported);
+ _gameScreen = new TextureCLUT8(glIntFormat, glFormat, glType, _defaultFormat);
+ _gameScreen->setPalette(0, 255, _gamePalette);
+#ifdef USE_RGB_COLOR
+ } else {
+ const bool supported = getGLPixelFormat(_currentState.gameFormat, glIntFormat, glFormat, glType);
+ assert(supported);
+ _gameScreen = new Texture(glIntFormat, glFormat, glType, _currentState.gameFormat);
+ }
+#endif
+
+ _gameScreen->allocate(_currentState.gameWidth, _currentState.gameHeight);
+ _gameScreen->enableLinearFiltering(_currentState.graphicsMode == GFX_LINEAR);
+ // We fill the screen to all black or index 0 for CLUT8.
+ if (_currentState.gameFormat.bytesPerPixel == 1) {
+ _gameScreen->fill(0);
+ } else {
+ _gameScreen->fill(_gameScreen->getSurface()->format.RGBToColor(0, 0, 0));
+ }
+ }
+
+ // Update our display area and cursor scaling. This makes sure we pick up
+ // aspect ratio correction and game screen changes correctly.
+ recalculateDisplayArea();
+ recalculateCursorScaling();
+
+ // Something changed, so update the screen change ID.
+ ++_screenChangeID;
+
+ // Since transactionError is a ORd list of TransactionErrors this is
+ // clearly wrong. But our API is simply broken.
+ return (OSystem::TransactionError)transactionError;
+}
+
+int OpenGLGraphicsManager::getScreenChangeID() const {
+ return _screenChangeID;
+}
+
+void OpenGLGraphicsManager::initSize(uint width, uint height, const Graphics::PixelFormat *format) {
+ Graphics::PixelFormat requestedFormat;
+#ifdef USE_RGB_COLOR
+ if (!format) {
+ requestedFormat = Graphics::PixelFormat::createFormatCLUT8();
+ } else {
+ requestedFormat = *format;
+ }
+ _currentState.gameFormat = requestedFormat;
+#endif
+
+ _currentState.gameWidth = width;
+ _currentState.gameHeight = height;
+}
+
+int16 OpenGLGraphicsManager::getWidth() {
+ return _currentState.gameWidth;
+}
+
+int16 OpenGLGraphicsManager::getHeight() {
+ return _currentState.gameHeight;
+}
+
+void OpenGLGraphicsManager::copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) {
+ _gameScreen->copyRectToTexture(x, y, w, h, buf, pitch);
+}
+
+void OpenGLGraphicsManager::fillScreen(uint32 col) {
+ // FIXME: This does not conform to the OSystem specs because fillScreen
+ // is always taking CLUT8 color values and use color indexed mode. This is,
+ // however, plain odd and probably was a forgotten when we introduced
+ // RGB support. Thus, we simply do the "sane" thing here and hope OSystem
+ // gets fixed one day.
+ _gameScreen->fill(col);
+}
+
+void OpenGLGraphicsManager::setShakePos(int shakeOffset) {
+ _gameScreenShakeOffset = shakeOffset;
+}
+
+void OpenGLGraphicsManager::updateScreen() {
+ if (!_gameScreen) {
+ return;
+ }
+
+ // Clear the screen buffer
+ GLCALL(glClear(GL_COLOR_BUFFER_BIT));
+
+ const GLfloat shakeOffset = _gameScreenShakeOffset * (GLfloat)_displayHeight / _gameScreen->getHeight();
+
+ // First step: Draw the (virtual) game screen.
+ glPushMatrix();
+
+ // Adjust game screen shake position
+ GLCALL(glTranslatef(0, shakeOffset, 0));
+
+ // Draw the game screen
+ _gameScreen->draw(_displayX, _displayY, _displayWidth, _displayHeight);
+
+ glPopMatrix();
+
+ // Second step: Draw the overlay if visible.
+ if (_overlayVisible) {
+ _overlay->draw(0, 0, _outputScreenWidth, _outputScreenHeight);
+ }
+
+ // Third step: Draw the cursor if visible.
+ if (_cursorVisible && _cursor) {
+ glPushMatrix();
+
+ // Adjust game screen shake position, but only when the overlay is not
+ // visible.
+ if (!_overlayVisible) {
+ GLCALL(glTranslatef(0, shakeOffset, 0));
+ }
+
+ _cursor->draw(_cursorX - _cursorHotspotXScaled, _cursorY - _cursorHotspotYScaled,
+ _cursorWidthScaled, _cursorHeightScaled);
+
+ glPopMatrix();
+ }
+}
+
+Graphics::Surface *OpenGLGraphicsManager::lockScreen() {
+ return _gameScreen->getSurface();
+}
+
+void OpenGLGraphicsManager::unlockScreen() {
+ _gameScreen->flagDirty();
+}
+
+void OpenGLGraphicsManager::setFocusRectangle(const Common::Rect& rect) {
+}
+
+void OpenGLGraphicsManager::clearFocusRectangle() {
+}
+
+int16 OpenGLGraphicsManager::getOverlayWidth() {
+ if (_overlay) {
+ return _overlay->getWidth();
+ } else {
+ return 0;
+ }
+}
+
+int16 OpenGLGraphicsManager::getOverlayHeight() {
+ if (_overlay) {
+ return _overlay->getHeight();
+ } else {
+ return 0;
+ }
+}
+
+void OpenGLGraphicsManager::showOverlay() {
+ _overlayVisible = true;
+}
+
+void OpenGLGraphicsManager::hideOverlay() {
+ _overlayVisible = false;
+}
+
+Graphics::PixelFormat OpenGLGraphicsManager::getOverlayFormat() const {
+ return _overlay->getFormat();
+}
+
+void OpenGLGraphicsManager::copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) {
+ _overlay->copyRectToTexture(x, y, w, h, buf, pitch);
+}
+
+void OpenGLGraphicsManager::clearOverlay() {
+ _overlay->fill(0);
+}
+
+void OpenGLGraphicsManager::grabOverlay(void *buf, int pitch) {
+ const Graphics::Surface *overlayData = _overlay->getSurface();
+
+ const byte *src = (const byte *)overlayData->getPixels();
+ byte *dst = (byte *)buf;
+
+ for (uint h = overlayData->h; h > 0; --h) {
+ memcpy(dst, src, overlayData->w * overlayData->format.bytesPerPixel);
+ dst += pitch;
+ src += overlayData->pitch;
+ }
+}
+
+bool OpenGLGraphicsManager::showMouse(bool visible) {
+ bool last = _cursorVisible;
+ _cursorVisible = visible;
+ return last;
+}
+
+void OpenGLGraphicsManager::warpMouse(int x, int y) {
+ int16 currentX = _cursorX;
+ int16 currentY = _cursorY;
+ adjustMousePosition(currentX, currentY);
+
+ // Check whether the (virtual) coordinate actually changed. If not, then
+ // simply do nothing. This avoids ugly "jittering" due to the actual
+ // output screen having a bigger resolution than the virtual coordinates.
+ if (currentX == x && currentY == y) {
+ return;
+ }
+
+ // Scale the virtual coordinates into actual physical coordinates.
+ if (_overlayVisible) {
+ if (!_overlay) {
+ return;
+ }
+
+ // It might be confusing that we actually have to handle something
+ // here when the overlay is visible. This is because for very small
+ // resolutions we have a minimal overlay size and have to adjust
+ // for that.
+ x = (x * _outputScreenWidth) / _overlay->getWidth();
+ y = (y * _outputScreenHeight) / _overlay->getHeight();
+ } else {
+ if (!_gameScreen) {
+ return;
+ }
+
+ x = (x * _displayWidth) / _gameScreen->getWidth();
+ y = (y * _displayHeight) / _gameScreen->getHeight();
+
+ x += _displayX;
+ y += _displayY;
+ }
+
+ setMousePosition(x, y);
+ setInternalMousePosition(x, y);
+}
+
+namespace {
+template<typename DstPixel, typename SrcPixel>
+void applyColorKey(DstPixel *dst, const SrcPixel *src, uint w, uint h, uint dstPitch, uint srcPitch, SrcPixel keyColor, DstPixel alphaMask) {
+ const uint srcAdd = srcPitch - w * sizeof(SrcPixel);
+ const uint dstAdd = dstPitch - w * sizeof(DstPixel);
+
+ while (h-- > 0) {
+ for (uint x = w; x > 0; --x, ++dst, ++src) {
+ if (*src == keyColor) {
+ *dst &= ~alphaMask;
+ }
+ }
+
+ dst = (DstPixel *)((byte *)dst + dstAdd);
+ src = (const SrcPixel *)((const byte *)src + srcAdd);
+ }
+}
+} // End of anonymous namespace
+
+void OpenGLGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
+ Graphics::PixelFormat inputFormat;
+#ifdef USE_RGB_COLOR
+ if (format) {
+ inputFormat = *format;
+ } else {
+ inputFormat = Graphics::PixelFormat::createFormatCLUT8();
+ }
+#else
+ inputFormat = Graphics::PixelFormat::createFormatCLUT8();
+#endif
+
+ // In case the color format has changed we will need to create the texture.
+ if (!_cursor || _cursor->getFormat() != inputFormat) {
+ delete _cursor;
+ _cursor = nullptr;
+
+ GLenum glIntFormat, glFormat, glType;
+
+ if (inputFormat.bytesPerPixel == 1) {
+ // In case this is not supported this is a serious programming
+ // error and the assert a bit below will trigger!
+ const bool supported = getGLPixelFormat(_defaultFormatAlpha, glIntFormat, glFormat, glType);
+ assert(supported);
+ _cursor = new TextureCLUT8(glIntFormat, glFormat, glType, _defaultFormatAlpha);
+ } else {
+ // Try to use the format specified as input directly. We can only
+ // do so when it actually has alpha bits.
+ if (inputFormat.aBits() != 0 && getGLPixelFormat(inputFormat, glIntFormat, glFormat, glType)) {
+ _cursor = new Texture(glIntFormat, glFormat, glType, inputFormat);
+ }
+
+ // Otherwise fall back to the default alpha format.
+ if (!_cursor) {
+ const bool supported = getGLPixelFormat(_defaultFormatAlpha, glIntFormat, glFormat, glType);
+ assert(supported);
+ _cursor = new Texture(glIntFormat, glFormat, glType, _defaultFormatAlpha);
+ }
+ }
+
+ assert(_cursor);
+ _cursor->enableLinearFiltering(_currentState.graphicsMode == GFX_LINEAR);
+ }
+
+ _cursorKeyColor = keycolor;
+ _cursorHotspotX = hotspotX;
+ _cursorHotspotY = hotspotY;
+ _cursorDontScale = dontScale;
+
+ _cursor->allocate(w, h);
+ if (inputFormat.bytesPerPixel == 1) {
+ // For CLUT8 cursors we can simply copy the input data into the
+ // texture.
+ _cursor->copyRectToTexture(0, 0, w, h, buf, w * inputFormat.bytesPerPixel);
+ } else {
+ // Otherwise it is a bit more ugly because we have to handle a key
+ // color properly.
+
+ Graphics::Surface *dst = _cursor->getSurface();
+ const uint srcPitch = w * inputFormat.bytesPerPixel;
+
+ // In case the actual cursor format differs from the requested format
+ // we will need to convert the format. This might be the case because
+ // the cursor format does not have any alpha bits.
+ if (dst->format != inputFormat) {
+ Graphics::crossBlit((byte *)dst->getPixels(), (const byte *)buf, dst->pitch, srcPitch,
+ w, h, dst->format, inputFormat);
+ }
+
+ // We apply the color key by setting the alpha bits of the pixels to
+ // fully transparent.
+ const uint32 aMask = (0xFF >> dst->format.aLoss) << dst->format.aShift;
+ if (dst->format.bytesPerPixel == 2) {
+ if (inputFormat.bytesPerPixel == 2) {
+ applyColorKey<uint16, uint16>((uint16 *)dst->getPixels(), (const uint16 *)buf, w, h,
+ dst->pitch, srcPitch, keycolor, aMask);
+ } else if (inputFormat.bytesPerPixel == 4) {
+ applyColorKey<uint16, uint32>((uint16 *)dst->getPixels(), (const uint32 *)buf, w, h,
+ dst->pitch, srcPitch, keycolor, aMask);
+ }
+ } else {
+ if (inputFormat.bytesPerPixel == 2) {
+ applyColorKey<uint32, uint16>((uint32 *)dst->getPixels(), (const uint16 *)buf, w, h,
+ dst->pitch, srcPitch, keycolor, aMask);
+ } else if (inputFormat.bytesPerPixel == 4) {
+ applyColorKey<uint32, uint32>((uint32 *)dst->getPixels(), (const uint32 *)buf, w, h,
+ dst->pitch, srcPitch, keycolor, aMask);
+ }
+ }
+
+ // Flag the texture as dirty.
+ _cursor->flagDirty();
+ }
+
+ // In case we actually use a palette set that up properly.
+ if (inputFormat.bytesPerPixel == 1) {
+ updateCursorPalette();
+ }
+
+ // Update the scaling.
+ recalculateCursorScaling();
+}
+
+void OpenGLGraphicsManager::setCursorPalette(const byte *colors, uint start, uint num) {
+ // FIXME: For some reason client code assumes that usage of this function
+ // automatically enables the cursor palette.
+ _cursorPaletteEnabled = true;
+
+ memcpy(_cursorPalette + start * 3, colors, num * 3);
+ updateCursorPalette();
+}
+
+void OpenGLGraphicsManager::displayMessageOnOSD(const char *msg) {
+}
+
+void OpenGLGraphicsManager::setPalette(const byte *colors, uint start, uint num) {
+ assert(_gameScreen->hasPalette());
+
+ memcpy(_gamePalette + start * 3, colors, num * 3);
+ _gameScreen->setPalette(start, num, colors);
+
+ // We might need to update the cursor palette here.
+ updateCursorPalette();
+}
+
+void OpenGLGraphicsManager::grabPalette(byte *colors, uint start, uint num) {
+ assert(_gameScreen->hasPalette());
+
+ memcpy(colors, _gamePalette + start * 3, num * 3);
+}
+
+void OpenGLGraphicsManager::setActualScreenSize(uint width, uint height) {
+ _outputScreenWidth = width;
+ _outputScreenHeight = height;
+
+ // Setup coordinates system.
+ GLCALL(glViewport(0, 0, _outputScreenWidth, _outputScreenHeight));
+
+ GLCALL(glMatrixMode(GL_PROJECTION));
+ GLCALL(glLoadIdentity());
+#ifdef USE_GLES
+ GLCALL(glOrthof(0, _outputScreenWidth, _outputScreenHeight, 0, -1, 1));
+#else
+ GLCALL(glOrtho(0, _outputScreenWidth, _outputScreenHeight, 0, -1, 1));
+#endif
+ GLCALL(glMatrixMode(GL_MODELVIEW));
+ GLCALL(glLoadIdentity());
+
+ // HACK: We limit the minimal overlay size to 256x200, which is the
+ // minimum of the dimensions of the two resolutions 256x240 (NES) and
+ // 320x200 (many DOS games use this). This hopefully assure that our
+ // GUI has working layouts.
+ const uint overlayWidth = MAX<uint>(width, 256);
+ const uint overlayHeight = MAX<uint>(height, 200);
+
+ if (!_overlay || _overlay->getFormat() != _defaultFormatAlpha) {
+ delete _overlay;
+ _overlay = nullptr;
+
+ GLenum glIntFormat, glFormat, glType;
+ const bool supported = getGLPixelFormat(_defaultFormatAlpha, glIntFormat, glFormat, glType);
+ assert(supported);
+ _overlay = new Texture(glIntFormat, glFormat, glType, _defaultFormatAlpha);
+ _overlay->enableLinearFiltering(_currentState.graphicsMode == GFX_LINEAR);
+ }
+ _overlay->allocate(overlayWidth, overlayHeight);
+ _overlay->fill(0);
+
+ // Re-setup the scaling for the screen and cursor
+ recalculateDisplayArea();
+ recalculateCursorScaling();
+
+ // Something changed, so update the screen change ID.
+ ++_screenChangeID;
+}
+
+void OpenGLGraphicsManager::notifyContextChange(const Graphics::PixelFormat &defaultFormat, const Graphics::PixelFormat &defaultFormatAlpha) {
+ // Initialize all extensions.
+ initializeGLExtensions();
+
+ // Disable 3D properties.
+ GLCALL(glDisable(GL_CULL_FACE));
+ GLCALL(glDisable(GL_DEPTH_TEST));
+ GLCALL(glDisable(GL_LIGHTING));
+ GLCALL(glDisable(GL_FOG));
+ GLCALL(glDisable(GL_DITHER));
+ GLCALL(glShadeModel(GL_FLAT));
+ GLCALL(glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST));
+
+ // Default to black as clear color.
+ GLCALL(glClearColor(0.0f, 0.0f, 0.0f, 0.0f));
+ GLCALL(glColor4f(1.0f, 1.0f, 1.0f, 1.0f));
+
+ // Setup alpha blend (for overlay and cursor).
+ GLCALL(glEnable(GL_BLEND));
+ GLCALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
+
+ // Enable rendering with vertex and coord arrays.
+ GLCALL(glEnableClientState(GL_VERTEX_ARRAY));
+ GLCALL(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
+
+ GLCALL(glEnable(GL_TEXTURE_2D));
+
+ // Refresh the output screen dimensions if some are set up.
+ if (_outputScreenWidth != 0 && _outputScreenHeight != 0) {
+ setActualScreenSize(_outputScreenWidth, _outputScreenHeight);
+ }
+
+ // TODO: Should we try to convert textures into one of those formats if
+ // possible? For example, when _gameScreen is CLUT8 we might want to use
+ // defaultFormat now.
+ _defaultFormat = defaultFormat;
+ _defaultFormatAlpha = defaultFormatAlpha;
+
+ if (_gameScreen) {
+ _gameScreen->recreateInternalTexture();
+ }
+
+ if (_overlay) {
+ _overlay->recreateInternalTexture();
+ }
+
+ if (_cursor) {
+ _cursor->recreateInternalTexture();
+ }
+}
+
+void OpenGLGraphicsManager::adjustMousePosition(int16 &x, int16 &y) {
+ if (_overlayVisible) {
+ // It might be confusing that we actually have to handle something
+ // here when the overlay is visible. This is because for very small
+ // resolutions we have a minimal overlay size and have to adjust
+ // for that.
+ if (_overlay) {
+ x = (x * _overlay->getWidth()) / _outputScreenWidth;
+ y = (y * _overlay->getHeight()) / _outputScreenHeight;
+ }
+ } else if (_gameScreen) {
+ x -= _displayX;
+ y -= _displayY;
+
+ const int16 width = _gameScreen->getWidth();
+ const int16 height = _gameScreen->getHeight();
+
+ x = (x * width) / _displayWidth;
+ y = (y * height) / _displayHeight;
+
+ // Make sure we only supply valid coordinates.
+ x = CLIP<int16>(x, 0, width - 1);
+ y = CLIP<int16>(y, 0, height - 1);
+ }
+}
+
+bool OpenGLGraphicsManager::getGLPixelFormat(const Graphics::PixelFormat &pixelFormat, GLenum &glIntFormat, GLenum &glFormat, GLenum &glType) const {
+ if (pixelFormat == Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)) { // RGBA8888
+ glIntFormat = GL_RGBA;
+ glFormat = GL_RGBA;
+ glType = GL_UNSIGNED_INT_8_8_8_8;
+ return true;
+ } else if (pixelFormat == Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)) { // RGB565
+ glIntFormat = GL_RGB;
+ glFormat = GL_RGB;
+ glType = GL_UNSIGNED_SHORT_5_6_5;
+ return true;
+ } else if (pixelFormat == Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0)) { // RGBA5551
+ glIntFormat = GL_RGBA;
+ glFormat = GL_RGBA;
+ glType = GL_UNSIGNED_SHORT_5_5_5_1;
+ return true;
+ } else if (pixelFormat == Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0)) { // RGBA4444
+ glIntFormat = GL_RGBA;
+ glFormat = GL_RGBA;
+ glType = GL_UNSIGNED_SHORT_4_4_4_4;
+ return true;
+#ifndef USE_GLES
+ } else if (pixelFormat == Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)) { // RGB555
+ // GL_BGRA does not exist in every GLES implementation so should not be configured if
+ // USE_GLES is set.
+ glIntFormat = GL_RGB;
+ glFormat = GL_BGRA;
+ glType = GL_UNSIGNED_SHORT_1_5_5_5_REV;
+ return true;
+ } else if (pixelFormat == Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24)) { // ARGB8888
+ glIntFormat = GL_RGBA;
+ glFormat = GL_BGRA;
+ glType = GL_UNSIGNED_INT_8_8_8_8_REV;
+ return true;
+ } else if (pixelFormat == Graphics::PixelFormat(2, 4, 4, 4, 4, 8, 4, 0, 12)) { // ARGB4444
+ glIntFormat = GL_RGBA;
+ glFormat = GL_BGRA;
+ glType = GL_UNSIGNED_SHORT_4_4_4_4_REV;
+ return true;
+ } else if (pixelFormat == Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24)) { // ABGR8888
+ glIntFormat = GL_RGBA;
+ glFormat = GL_RGBA;
+ glType = GL_UNSIGNED_INT_8_8_8_8_REV;
+ return true;
+ } else if (pixelFormat == Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0)) { // BGRA8888
+ glIntFormat = GL_RGBA;
+ glFormat = GL_BGRA;
+ glType = GL_UNSIGNED_INT_8_8_8_8;
+ return true;
+ } else if (pixelFormat == Graphics::PixelFormat(2, 5, 6, 5, 0, 0, 5, 11, 0)) { // BGR565
+ glIntFormat = GL_RGB;
+ glFormat = GL_BGR;
+ glType = GL_UNSIGNED_SHORT_5_6_5;
+ return true;
+ } else if (pixelFormat == Graphics::PixelFormat(2, 5, 5, 5, 1, 1, 6, 11, 0)) { // BGRA5551
+ glIntFormat = GL_RGBA;
+ glFormat = GL_BGRA;
+ glType = GL_UNSIGNED_SHORT_5_5_5_1;
+ return true;
+ } else if (pixelFormat == Graphics::PixelFormat(2, 4, 4, 4, 4, 0, 4, 8, 12)) { // ABGR4444
+ glIntFormat = GL_RGBA;
+ glFormat = GL_RGBA;
+ glType = GL_UNSIGNED_SHORT_4_4_4_4_REV;
+ return true;
+ } else if (pixelFormat == Graphics::PixelFormat(2, 4, 4, 4, 4, 4, 8, 12, 0)) { // BGRA4444
+ glIntFormat = GL_RGBA;
+ glFormat = GL_BGRA;
+ glType = GL_UNSIGNED_SHORT_4_4_4_4;
+ return true;
+#endif
+ } else {
+ return false;
+ }
+}
+
+frac_t OpenGLGraphicsManager::getDesiredGameScreenAspect() const {
+ const uint width = _currentState.gameWidth;
+ const uint height = _currentState.gameHeight;
+
+ if (_currentState.aspectRatioCorrection) {
+ // In case we enable aspect ratio correction we force a 4/3 ratio.
+ // But just for 320x200 and 640x400 games, since other games do not need
+ // this.
+ if ((width == 320 && height == 200) || (width == 640 && height == 400)) {
+ return intToFrac(4) / 3;
+ }
+ }
+
+ return intToFrac(width) / height;
+}
+
+void OpenGLGraphicsManager::recalculateDisplayArea() {
+ if (!_gameScreen || _outputScreenHeight == 0) {
+ return;
+ }
+
+ const frac_t outputAspect = intToFrac(_outputScreenWidth) / _outputScreenHeight;
+ const frac_t desiredAspect = getDesiredGameScreenAspect();
+
+ _displayWidth = _outputScreenWidth;
+ _displayHeight = _outputScreenHeight;
+
+ // Adjust one dimension for mantaining the aspect ratio.
+ if (outputAspect < desiredAspect) {
+ _displayHeight = intToFrac(_displayWidth) / desiredAspect;
+ } else if (outputAspect > desiredAspect) {
+ _displayWidth = fracToInt(_displayHeight * desiredAspect);
+ }
+
+ // We center the screen in the middle for now.
+ _displayX = (_outputScreenWidth - _displayWidth ) / 2;
+ _displayY = (_outputScreenHeight - _displayHeight) / 2;
+}
+
+void OpenGLGraphicsManager::updateCursorPalette() {
+ if (!_cursor || !_cursor->hasPalette()) {
+ return;
+ }
+
+ if (_cursorPaletteEnabled) {
+ _cursor->setPalette(0, 256, _cursorPalette);
+ } else {
+ _cursor->setPalette(0, 256, _gamePalette);
+ }
+
+ // We remove all alpha bits from the palette entry of the color key.
+ // This makes sure its properly handled as color key.
+ const Graphics::PixelFormat &hardwareFormat = _cursor->getHardwareFormat();
+ const uint32 aMask = (0xFF >> hardwareFormat.aLoss) << hardwareFormat.aShift;
+
+ if (hardwareFormat.bytesPerPixel == 2) {
+ uint16 *palette = (uint16 *)_cursor->getPalette() + _cursorKeyColor;
+ *palette &= ~aMask;
+ } else if (hardwareFormat.bytesPerPixel == 4) {
+ uint32 *palette = (uint32 *)_cursor->getPalette() + _cursorKeyColor;
+ *palette &= ~aMask;
+ } else {
+ warning("OpenGLGraphicsManager::updateCursorPalette: Unsupported pixel depth %d", hardwareFormat.bytesPerPixel);
+ }
+}
+
+void OpenGLGraphicsManager::recalculateCursorScaling() {
+ if (!_cursor || !_gameScreen) {
+ return;
+ }
+
+ // By default we use the unscaled versions.
+ _cursorHotspotXScaled = _cursorHotspotX;
+ _cursorHotspotYScaled = _cursorHotspotY;
+ _cursorWidthScaled = _cursor->getWidth();
+ _cursorHeightScaled = _cursor->getHeight();
+
+ // In case scaling is actually enabled we will scale the cursor according
+ // to the game screen.
+ if (!_cursorDontScale) {
+ const uint screenScaleFactorX = _displayWidth * 10000 / _gameScreen->getWidth();
+ const uint screenScaleFactorY = _displayHeight * 10000 / _gameScreen->getHeight();
+
+ _cursorHotspotXScaled = (_cursorHotspotXScaled * screenScaleFactorX) / 10000;
+ _cursorWidthScaled = (_cursorWidthScaled * screenScaleFactorX) / 10000;
+
+ _cursorHotspotYScaled = (_cursorHotspotYScaled * screenScaleFactorY) / 10000;
+ _cursorHeightScaled = (_cursorHeightScaled * screenScaleFactorY) / 10000;
+ }
+}
+
+} // End of namespace OpenGL
diff --git a/backends/graphics/opengl/opengl-graphics.h b/backends/graphics/opengl/opengl-graphics.h
new file mode 100644
index 0000000000..e21bda4b8a
--- /dev/null
+++ b/backends/graphics/opengl/opengl-graphics.h
@@ -0,0 +1,418 @@
+/* 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.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_OPENGL_OPENGL_GRAPHICS_H
+#define BACKENDS_GRAPHICS_OPENGL_OPENGL_GRAPHICS_H
+
+#include "backends/graphics/opengl/opengl-sys.h"
+#include "backends/graphics/graphics.h"
+
+#include "common/frac.h"
+
+namespace OpenGL {
+
+class Texture;
+
+enum {
+ GFX_LINEAR = 0,
+ GFX_NEAREST = 1
+};
+
+class OpenGLGraphicsManager : public GraphicsManager {
+public:
+ OpenGLGraphicsManager();
+ virtual ~OpenGLGraphicsManager();
+
+ // GraphicsManager API
+ virtual bool hasFeature(OSystem::Feature f);
+ virtual void setFeatureState(OSystem::Feature f, bool enable);
+ virtual bool getFeatureState(OSystem::Feature f);
+
+ virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const;
+ virtual int getDefaultGraphicsMode() const;
+ virtual bool setGraphicsMode(int mode);
+ virtual int getGraphicsMode() const;
+
+ virtual void resetGraphicsScale() {}
+
+#ifdef USE_RGB_COLOR
+ virtual Graphics::PixelFormat getScreenFormat() const;
+ virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const = 0;
+#endif
+
+ virtual void beginGFXTransaction();
+ virtual OSystem::TransactionError endGFXTransaction();
+
+ virtual int getScreenChangeID() const;
+
+ virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format);
+
+ virtual int16 getWidth();
+ virtual int16 getHeight();
+
+ virtual void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h);
+ virtual void fillScreen(uint32 col);
+
+ virtual void setShakePos(int shakeOffset);
+
+ virtual void updateScreen();
+
+ virtual Graphics::Surface *lockScreen();
+ virtual void unlockScreen();
+
+ virtual void setFocusRectangle(const Common::Rect& rect);
+ virtual void clearFocusRectangle();
+
+ virtual int16 getOverlayWidth();
+ virtual int16 getOverlayHeight();
+
+ virtual void showOverlay();
+ virtual void hideOverlay();
+
+ virtual Graphics::PixelFormat getOverlayFormat() const;
+
+ virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h);
+ virtual void clearOverlay();
+ virtual void grabOverlay(void *buf, int pitch);
+
+ virtual bool showMouse(bool visible);
+ virtual void warpMouse(int x, int y);
+ virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format);
+ virtual void setCursorPalette(const byte *colors, uint start, uint num);
+
+ virtual void displayMessageOnOSD(const char *msg);
+
+ // PaletteManager interface
+ virtual void setPalette(const byte *colors, uint start, uint num);
+ virtual void grabPalette(byte *colors, uint start, uint num);
+
+protected:
+ /**
+ * Set up the actual screen size available for the OpenGL code to do any
+ * drawing.
+ *
+ * @param width The width of the screen.
+ * @param height The height of the screen.
+ */
+ void setActualScreenSize(uint width, uint height);
+
+ /**
+ * Notify the manager of a OpenGL context change. This should be the first
+ * thing to call when you create an OpenGL (ES) context!
+ *
+ * @param defaultFormat The new default format for the game screen
+ * (this is used for the CLUT8 game screens).
+ * @param defaultFromatAlpha The new default format with an alpha channel
+ * (this is used for the overlay and cursor).
+ */
+ void notifyContextChange(const Graphics::PixelFormat &defaultFormat, const Graphics::PixelFormat &defaultFormatAlpha);
+
+ /**
+ * Adjust the physical mouse coordinates according to the currently visible screen.
+ */
+ void adjustMousePosition(int16 &x, int16 &y);
+
+ /**
+ * Set up the mouse position for graphics output.
+ *
+ * @param x X coordinate in physical coordinates.
+ * @param y Y coordinate in physical coordinates.
+ */
+ void setMousePosition(int x, int y) { _cursorX = x; _cursorY = y; }
+
+ /**
+ * Set up the mouse position for the (event) system.
+ *
+ * @param x X coordinate in physical coordinates.
+ * @param y Y coordinate in physical coordinates.
+ */
+ virtual void setInternalMousePosition(int x, int y) = 0;
+
+private:
+ //
+ // Transaction support
+ //
+ struct VideoState {
+ VideoState() : valid(false), gameWidth(0), gameHeight(0),
+#ifdef USE_RGB_COLOR
+ gameFormat(),
+#endif
+ aspectRatioCorrection(false), graphicsMode(GFX_LINEAR) {
+ }
+
+ bool valid;
+
+ uint gameWidth, gameHeight;
+#ifdef USE_RGB_COLOR
+ Graphics::PixelFormat gameFormat;
+#endif
+ bool aspectRatioCorrection;
+ int graphicsMode;
+
+ bool operator==(const VideoState &right) {
+ return gameWidth == right.gameWidth && gameHeight == right.gameHeight
+#ifdef USE_RGB_COLOR
+ && gameFormat == right.gameFormat
+#endif
+ && aspectRatioCorrection == right.aspectRatioCorrection
+ && graphicsMode == right.graphicsMode;
+ }
+
+ bool operator!=(const VideoState &right) {
+ return !(*this == right);
+ }
+ };
+
+ /**
+ * The currently setup video state.
+ */
+ VideoState _currentState;
+
+ /**
+ * The old video state used when doing a transaction rollback.
+ */
+ VideoState _oldState;
+
+protected:
+ enum TransactionMode {
+ kTransactionNone = 0,
+ kTransactionActive = 1,
+ kTransactionRollback = 2
+ };
+
+ TransactionMode getTransactionMode() const { return _transactionMode; }
+
+private:
+ /**
+ * The current transaction mode.
+ */
+ TransactionMode _transactionMode;
+
+ /**
+ * The current screen change ID.
+ */
+ int _screenChangeID;
+
+protected:
+ /**
+ * Set up the requested video mode. This takes parameters which describe
+ * what resolution the game screen requests (this is possibly aspect ratio
+ * corrected!).
+ *
+ * A sub-class should take these parameters as hints. It might very well
+ * set up a mode which it thinks suites the situation best.
+ *
+ * @parma requestedWidth This is the requested actual game screen width.
+ * @param requestedHeight This is the requested actual game screen height.
+ * @param format This is the requested pixel format of the virtual game screen.
+ * @return true on success, false otherwise
+ */
+ virtual bool loadVideoMode(uint requestedWidth, uint requestedHeight, const Graphics::PixelFormat &format) = 0;
+
+private:
+ //
+ // OpenGL utilities
+ //
+
+ /**
+ * Try to determine the internal parameters for a given pixel format.
+ *
+ * @return true when the format can be used, false otherwise.
+ */
+ bool getGLPixelFormat(const Graphics::PixelFormat &pixelFormat, GLenum &glIntFormat, GLenum &glFormat, GLenum &glType) const;
+
+ //
+ // Actual hardware screen
+ //
+
+ /**
+ * The width of the physical output.
+ */
+ uint _outputScreenWidth;
+
+ /**
+ * The height of the physical output.
+ */
+ uint _outputScreenHeight;
+
+ /**
+ * @return The desired aspect of the game screen.
+ */
+ frac_t getDesiredGameScreenAspect() const;
+
+ /**
+ * Recalculates the area used to display the game screen.
+ */
+ void recalculateDisplayArea();
+
+ /**
+ * The X coordinate of the game screen.
+ */
+ uint _displayX;
+
+ /**
+ * The Y coordinate of the game screen.
+ */
+ uint _displayY;
+
+ /**
+ * The width of the game screen in physical coordinates.
+ */
+ uint _displayWidth;
+
+ /**
+ * The height of the game screen in physical coordinates.
+ */
+ uint _displayHeight;
+
+ /**
+ * The default pixel format of the backend.
+ */
+ Graphics::PixelFormat _defaultFormat;
+
+ /**
+ * The default pixel format with an alpha channel.
+ */
+ Graphics::PixelFormat _defaultFormatAlpha;
+
+ //
+ // Game screen
+ //
+
+ /**
+ * The virtual game screen.
+ */
+ Texture *_gameScreen;
+
+ /**
+ * The game palette if in CLUT8 mode.
+ */
+ byte _gamePalette[3 * 256];
+
+ /**
+ * The offset by which the screen is moved vertically.
+ */
+ int _gameScreenShakeOffset;
+
+ //
+ // Overlay
+ //
+
+ /**
+ * The overlay screen.
+ */
+ Texture *_overlay;
+
+ /**
+ * Whether the overlay is visible or not.
+ */
+ bool _overlayVisible;
+
+ //
+ // Cursor
+ //
+
+ /**
+ * Set up the correct cursor palette.
+ */
+ void updateCursorPalette();
+
+ /**
+ * The cursor image.
+ */
+ Texture *_cursor;
+
+ /**
+ * X coordinate of the cursor in phyiscal coordinates.
+ */
+ uint _cursorX;
+
+ /**
+ * Y coordinate of the cursor in physical coordinates.
+ */
+ uint _cursorY;
+
+ /**
+ * The X offset for the cursor hotspot in unscaled coordinates.
+ */
+ uint _cursorHotspotX;
+
+ /**
+ * The Y offset for the cursor hotspot in unscaled coordinates.
+ */
+ uint _cursorHotspotY;
+
+ /**
+ * Recalculate the cursor scaling. Scaling is always done according to
+ * the game screen.
+ */
+ void recalculateCursorScaling();
+
+ /**
+ * The X offset for the cursor hotspot in scaled coordinates.
+ */
+ uint _cursorHotspotXScaled;
+
+ /**
+ * The Y offset for the cursor hotspot in scaled coordinates.
+ */
+ uint _cursorHotspotYScaled;
+
+ /**
+ * The width of the cursor scaled coordinates.
+ */
+ uint _cursorWidthScaled;
+
+ /**
+ * The height of the cursor scaled coordinates.
+ */
+ uint _cursorHeightScaled;
+
+ /**
+ * The key color.
+ */
+ uint32 _cursorKeyColor;
+
+ /**
+ * Whether the cursor is actually visible.
+ */
+ bool _cursorVisible;
+
+ /**
+ * Whether no cursor scaling should be applied.
+ */
+ bool _cursorDontScale;
+
+ /**
+ * Whether the special cursor palette is enabled.
+ */
+ bool _cursorPaletteEnabled;
+
+ /**
+ * The special cursor palette in case enabled.
+ */
+ byte _cursorPalette[3 * 256];
+};
+
+} // End of namespace OpenGL
+
+#endif
diff --git a/backends/graphics/opengl/opengl-sys.h b/backends/graphics/opengl/opengl-sys.h
new file mode 100644
index 0000000000..a3524b28d2
--- /dev/null
+++ b/backends/graphics/opengl/opengl-sys.h
@@ -0,0 +1,57 @@
+/* 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.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_OPENGL_OPENGL_H
+#define BACKENDS_GRAPHICS_OPENGL_OPENGL_H
+
+// The purpose of this header is to include the OpenGL headers in an uniform
+// fashion. A notable example for a non standard port is the Tizen port.
+
+#include "common/scummsys.h"
+
+#ifdef WIN32
+#if defined(ARRAYSIZE) && !defined(_WINDOWS_)
+#undef ARRAYSIZE
+#endif
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef ARRAYSIZE
+#endif
+
+// HACK: In case common/util.h has been included already we need to make sure
+// to define ARRAYSIZE again in case of Windows.
+#if !defined(ARRAYSIZE) && defined(COMMON_UTIL_H)
+#define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(x[0])))
+#endif
+
+#if defined(TIZEN)
+#include <FGraphicsOpengl.h>
+using namespace Tizen::Graphics::Opengl;
+#elif defined(USE_GLES)
+#include <GLES/gl.h>
+#elif defined(SDL_BACKEND)
+#include <SDL_opengl.h>
+#else
+#include <GL/gl.h>
+#endif
+
+#endif
diff --git a/backends/graphics/opengl/texture.cpp b/backends/graphics/opengl/texture.cpp
new file mode 100644
index 0000000000..3067aa7d1c
--- /dev/null
+++ b/backends/graphics/opengl/texture.cpp
@@ -0,0 +1,305 @@
+/* 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.
+ *
+ */
+
+#include "backends/graphics/opengl/texture.h"
+#include "backends/graphics/opengl/extensions.h"
+#include "backends/graphics/opengl/debug.h"
+
+#include "common/rect.h"
+#include "common/textconsole.h"
+
+namespace OpenGL {
+
+static GLuint nextHigher2(GLuint v) {
+ if (v == 0)
+ return 1;
+ v--;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ return ++v;
+}
+
+Texture::Texture(GLenum glIntFormat, GLenum glFormat, GLenum glType, const Graphics::PixelFormat &format)
+ : _glIntFormat(glIntFormat), _glFormat(glFormat), _glType(glType), _format(format), _glFilter(GL_NEAREST),
+ _glTexture(0), _textureData(), _userPixelData(), _allDirty(false) {
+ recreateInternalTexture();
+}
+
+Texture::~Texture() {
+ releaseInternalTexture();
+ _textureData.free();
+}
+
+void Texture::releaseInternalTexture() {
+ GLCALL(glDeleteTextures(1, &_glTexture));
+ _glTexture = 0;
+}
+
+void Texture::recreateInternalTexture() {
+ // Get a new texture name.
+ GLCALL(glGenTextures(1, &_glTexture));
+
+ // Set up all texture parameters.
+ GLCALL(glBindTexture(GL_TEXTURE_2D, _glTexture));
+ GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
+ GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _glFilter));
+ GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _glFilter));
+ GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
+ GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
+
+ // In case there is an actual texture setup we reinitialize it.
+ if (_textureData.getPixels()) {
+ // Mark dirts such that it will be completely refreshed the next time.
+ flagDirty();
+ }
+}
+
+void Texture::enableLinearFiltering(bool enable) {
+ if (enable) {
+ _glFilter = GL_LINEAR;
+ } else {
+ _glFilter = GL_NEAREST;
+ }
+
+ GLCALL(glBindTexture(GL_TEXTURE_2D, _glTexture));
+
+ GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _glFilter));
+ GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _glFilter));
+}
+
+void Texture::allocate(uint width, uint height) {
+ uint texWidth = width, texHeight = height;
+ if (!g_extNPOTSupported) {
+ texWidth = nextHigher2(texWidth);
+ texHeight = nextHigher2(texHeight);
+ }
+
+ // In case the needed texture dimension changed we will reinitialize the
+ // texture.
+ if (texWidth != _textureData.w || texHeight != _textureData.h) {
+ // Create a buffer for the texture data.
+ _textureData.create(texWidth, texHeight, _format);
+ }
+
+ // Create a sub-buffer for raw access.
+ _userPixelData = _textureData.getSubArea(Common::Rect(width, height));
+}
+
+void Texture::copyRectToTexture(uint x, uint y, uint w, uint h, const void *srcPtr, uint srcPitch) {
+ Graphics::Surface *dstSurf = getSurface();
+ assert(x + w <= dstSurf->w);
+ assert(y + h <= dstSurf->h);
+
+ const byte *src = (const byte *)srcPtr;
+ byte *dst = (byte *)dstSurf->getBasePtr(x, y);
+ const uint pitch = dstSurf->pitch;
+ const uint bytesPerPixel = dstSurf->format.bytesPerPixel;
+
+ if (srcPitch == pitch && x == 0 && w == dstSurf->w) {
+ memcpy(dst, src, h * pitch);
+ } else {
+ while (h-- > 0) {
+ memcpy(dst, src, w * bytesPerPixel);
+ dst += pitch;
+ src += srcPitch;
+ }
+ }
+
+ flagDirty();
+}
+
+void Texture::fill(uint32 color) {
+ Graphics::Surface *dst = getSurface();
+ dst->fillRect(Common::Rect(dst->w, dst->h), color);
+
+ flagDirty();
+}
+
+void Texture::draw(GLuint x, GLuint y, GLuint w, GLuint h) {
+ // Only do any processing when the Texture is initialized.
+ if (!_textureData.getPixels()) {
+ return;
+ }
+
+ // First update any potentional changes.
+ updateTexture();
+
+ // Set the texture.
+ GLCALL(glBindTexture(GL_TEXTURE_2D, _glTexture));
+
+ // Calculate the texture rect that will be drawn.
+ const GLfloat texWidth = (GLfloat)_userPixelData.w / _textureData.w;
+ const GLfloat texHeight = (GLfloat)_userPixelData.h / _textureData.h;
+ const GLfloat texcoords[4*2] = {
+ 0, 0,
+ texWidth, 0,
+ 0, texHeight,
+ texWidth, texHeight
+ };
+ GLCALL(glTexCoordPointer(2, GL_FLOAT, 0, texcoords));
+
+ // Calculate the screen rect where the texture will be drawn.
+ const GLshort vertices[4*2] = {
+ (GLshort)x, (GLshort)y,
+ (GLshort)(x + w), (GLshort)y,
+ (GLshort)x, (GLshort)(y + h),
+ (GLshort)(x + w), (GLshort)(y + h)
+ };
+ GLCALL(glVertexPointer(2, GL_SHORT, 0, vertices));
+
+ // Draw the texture to the screen buffer.
+ GLCALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
+}
+
+void Texture::updateTexture() {
+ if (!isDirty()) {
+ return;
+ }
+
+ // In case we use linear filtering we might need to duplicate the last
+ // pixel row/column to avoid glitches with filtering.
+ if (_glFilter == GL_LINEAR) {
+ if (_textureData.w != _userPixelData.w) {
+ uint height = _userPixelData.h;
+
+ const byte *src = (const byte *)_textureData.getBasePtr(_userPixelData.w - 1, 0);
+ byte *dst = (byte *)_textureData.getBasePtr(_userPixelData.w, 0);
+
+ while (height-- > 0) {
+ memcpy(dst, src, _textureData.format.bytesPerPixel);
+ dst += _textureData.pitch;
+ src += _textureData.pitch;
+ }
+ }
+
+ if (_textureData.h != _userPixelData.h) {
+ const byte *src = (const byte *)_textureData.getBasePtr(0, _userPixelData.h - 1);
+ byte *dst = (byte *)_textureData.getBasePtr(0, _userPixelData.h);
+ memcpy(dst, src, _userPixelData.w * _textureData.format.bytesPerPixel);
+ }
+ }
+
+ // Set the texture.
+ GLCALL(glBindTexture(GL_TEXTURE_2D, _glTexture));
+
+ // Update the actual texture.
+ GLCALL(glTexImage2D(GL_TEXTURE_2D, 0, _glIntFormat, _textureData.w, _textureData.h, 0, _glFormat, _glType, _textureData.getPixels()));
+
+ // We should have handled everything, thus not dirty anymore.
+ clearDirty();
+}
+
+TextureCLUT8::TextureCLUT8(GLenum glIntFormat, GLenum glFormat, GLenum glType, const Graphics::PixelFormat &format)
+ : Texture(glIntFormat, glFormat, glType, format), _clut8Data(), _palette(new byte[256 * format.bytesPerPixel]) {
+ memset(_palette, 0, sizeof(byte) * format.bytesPerPixel);
+}
+
+TextureCLUT8::~TextureCLUT8() {
+ delete[] _palette;
+ _palette = nullptr;
+ _clut8Data.free();
+}
+
+void TextureCLUT8::allocate(uint width, uint height) {
+ Texture::allocate(width, height);
+
+ // We only need to reinitialize our CLUT8 surface when the output size
+ // changed.
+ if (width == _clut8Data.w && width == _clut8Data.h) {
+ return;
+ }
+
+ _clut8Data.create(width, height, Graphics::PixelFormat::createFormatCLUT8());
+}
+
+Graphics::PixelFormat TextureCLUT8::getFormat() const {
+ return Graphics::PixelFormat::createFormatCLUT8();
+}
+
+namespace {
+template<typename ColorType>
+inline void convertPalette(ColorType *dst, const byte *src, uint colors, const Graphics::PixelFormat &format) {
+ while (colors-- > 0) {
+ *dst++ = format.RGBToColor(src[0], src[1], src[2]);
+ src += 3;
+ }
+}
+} // End of anonymous namespace
+
+void TextureCLUT8::setPalette(uint start, uint colors, const byte *palData) {
+ const Graphics::PixelFormat &hardwareFormat = getHardwareFormat();
+
+ if (hardwareFormat.bytesPerPixel == 2) {
+ convertPalette<uint16>((uint16 *)_palette + start, palData, colors, hardwareFormat);
+ } else if (hardwareFormat.bytesPerPixel == 4) {
+ convertPalette<uint32>((uint32 *)_palette + start, palData, colors, hardwareFormat);
+ } else {
+ warning("TextureCLUT8::setPalette: Unsupported pixel depth: %d", hardwareFormat.bytesPerPixel);
+ }
+
+ // A palette changes means we need to refresh the whole surface.
+ flagDirty();
+}
+
+namespace {
+template<typename PixelType>
+inline void doPaletteLookUp(PixelType *dst, const byte *src, uint width, uint height, uint dstPitch, uint srcPitch, const PixelType *palette) {
+ uint srcAdd = srcPitch - width;
+ uint dstAdd = dstPitch - width * sizeof(PixelType);
+
+ while (height-- > 0) {
+ for (uint x = width; x > 0; --x) {
+ *dst++ = palette[*src++];
+ }
+
+ dst = (PixelType *)((byte *)dst + dstAdd);
+ src += srcAdd;
+ }
+}
+} // End of anonymous namespace
+
+void TextureCLUT8::updateTexture() {
+ if (!isDirty()) {
+ return;
+ }
+
+ // Do the palette look up
+ Graphics::Surface *outSurf = Texture::getSurface();
+
+ if (outSurf->format.bytesPerPixel == 2) {
+ doPaletteLookUp<uint16>((uint16 *)outSurf->getPixels(), (const byte *)_clut8Data.getPixels(), _clut8Data.w, _clut8Data.h,
+ outSurf->pitch, _clut8Data.pitch, (const uint16 *)_palette);
+ } else if (outSurf->format.bytesPerPixel == 4) {
+ doPaletteLookUp<uint32>((uint32 *)outSurf->getPixels(), (const byte *)_clut8Data.getPixels(), _clut8Data.w, _clut8Data.h,
+ outSurf->pitch, _clut8Data.pitch, (const uint32 *)_palette);
+ } else {
+ warning("TextureCLUT8::updateTexture: Unsupported pixel depth: %d", outSurf->format.bytesPerPixel);
+ }
+
+ // Do generic handling of updating the texture.
+ Texture::updateTexture();
+}
+
+} // End of namespace OpenGL
diff --git a/backends/graphics/opengl/texture.h b/backends/graphics/opengl/texture.h
new file mode 100644
index 0000000000..1127aed350
--- /dev/null
+++ b/backends/graphics/opengl/texture.h
@@ -0,0 +1,159 @@
+/* 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.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_OPENGL_TEXTURE_H
+#define BACKENDS_GRAPHICS_OPENGL_TEXTURE_H
+
+#include "backends/graphics/opengl/opengl-sys.h"
+
+#include "graphics/pixelformat.h"
+#include "graphics/surface.h"
+
+namespace OpenGL {
+
+/**
+ * An OpenGL texture wrapper. It automatically takes care of all OpenGL
+ * texture handling issues and also provides access to the texture data.
+ */
+class Texture {
+public:
+ /**
+ * Create a new texture with the specific internal format.
+ *
+ * @param glIntFormat The internal format to use.
+ * @param glFormat The input format.
+ * @param glType The input type.
+ * @param format The format used for the texture input.
+ */
+ Texture(GLenum glIntFormat, GLenum glFormat, GLenum glType, const Graphics::PixelFormat &format);
+ virtual ~Texture();
+
+ /**
+ * Destroy the OpenGL texture name.
+ */
+ void releaseInternalTexture();
+
+ /**
+ * Create the OpenGL texture name and flag the whole texture as dirty.
+ */
+ void recreateInternalTexture();
+
+ /**
+ * Enable or disable linear texture filtering.
+ *
+ * @param enable true to enable and false to disable.
+ */
+ void enableLinearFiltering(bool enable);
+
+ /**
+ * Allocate texture space for the desired dimensions. This wraps any
+ * handling of requirements for POT textures.
+ *
+ * @param width The desired logical width.
+ * @param height The desired logical height.
+ */
+ virtual void allocate(uint width, uint height);
+
+ void copyRectToTexture(uint x, uint y, uint w, uint h, const void *src, uint srcPitch);
+
+ void fill(uint32 color);
+
+ void draw(GLuint x, GLuint y, GLuint w, GLuint h);
+
+ void flagDirty() { _allDirty = true; }
+ bool isDirty() const { return _allDirty; }
+
+ uint getWidth() const { return _userPixelData.w; }
+ uint getHeight() const { return _userPixelData.h; }
+
+ /**
+ * @return The hardware format of the texture data.
+ */
+ const Graphics::PixelFormat &getHardwareFormat() const { return _format; }
+
+ /**
+ * @return The logical format of the texture data.
+ */
+ virtual Graphics::PixelFormat getFormat() const { return _format; }
+
+ virtual Graphics::Surface *getSurface() { return &_userPixelData; }
+ virtual const Graphics::Surface *getSurface() const { return &_userPixelData; }
+
+ /**
+ * @return Whether the texture data is using a palette.
+ */
+ virtual bool hasPalette() const { return false; }
+
+ virtual void setPalette(uint start, uint colors, const byte *palData) {}
+
+ virtual void *getPalette() { return 0; }
+ virtual const void *getPalette() const { return 0; }
+
+protected:
+ virtual void updateTexture();
+
+private:
+ const GLenum _glIntFormat;
+ const GLenum _glFormat;
+ const GLenum _glType;
+ const Graphics::PixelFormat _format;
+
+ GLint _glFilter;
+ GLuint _glTexture;
+
+ Graphics::Surface _textureData;
+ Graphics::Surface _userPixelData;
+
+ bool _allDirty;
+ void clearDirty() { _allDirty = false; }
+};
+
+class TextureCLUT8 : public Texture {
+public:
+ TextureCLUT8(GLenum glIntFormat, GLenum glFormat, GLenum glType, const Graphics::PixelFormat &format);
+ virtual ~TextureCLUT8();
+
+ virtual void allocate(uint width, uint height);
+
+ virtual Graphics::PixelFormat getFormat() const;
+
+ virtual bool hasPalette() const { return true; }
+
+ virtual void setPalette(uint start, uint colors, const byte *palData);
+
+ virtual void *getPalette() { return _palette; }
+ virtual const void *getPalette() const { return _palette; }
+
+ virtual Graphics::Surface *getSurface() { return &_clut8Data; }
+ virtual const Graphics::Surface *getSurface() const { return &_clut8Data; }
+
+protected:
+ virtual void updateTexture();
+
+private:
+ Graphics::Surface _clut8Data;
+ byte *_palette;
+};
+
+} // End of namespace OpenGL
+
+#endif
diff --git a/backends/module.mk b/backends/module.mk
index 682ca78e22..b66b0b04ec 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -49,6 +49,15 @@ MODULE_OBJS += \
vkeybd/virtual-keyboard-parser.o
endif
+# OpenGL specific source files.
+ifdef USE_OPENGL
+MODULE_OBJS += \
+ graphics/opengl/debug.o \
+ graphics/opengl/extensions.o \
+ graphics/opengl/opengl-graphics.o \
+ graphics/opengl/texture.o
+endif
+
# SDL specific source files.
# We cannot just check $BACKEND = sdl, as various other backends
# derive from the SDL backend, and they all need the following files.
diff --git a/engines/engine.cpp b/engines/engine.cpp
index c84404cc68..52020c772e 100644
--- a/engines/engine.cpp
+++ b/engines/engine.cpp
@@ -183,7 +183,7 @@ void initCommonGFX(bool defaultTo1XScaler) {
g_system->setGraphicsMode(gfxMode.c_str());
// HACK: For OpenGL modes, we will still honor the graphics scale override
- if (defaultTo1XScaler && (gfxMode.equalsIgnoreCase("gl1") || gfxMode.equalsIgnoreCase("gl2") || gfxMode.equalsIgnoreCase("gl4")))
+ if (defaultTo1XScaler && (gfxMode.equalsIgnoreCase("opengl_linear") || gfxMode.equalsIgnoreCase("opengl_nearest")))
g_system->resetGraphicsScale();
}
}