aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Schickel2013-08-18 16:56:34 +0200
committerJohannes Schickel2013-10-19 22:14:24 +0200
commit5ce830b97643fc76bdcafdbbe09e226519a9d2e6 (patch)
tree2081a1d9eff756823e3141aa019e141bb1e5f18c
parent46323074e77622e7d08fe20bfdcc459b8eba08a3 (diff)
downloadscummvm-rg350-5ce830b97643fc76bdcafdbbe09e226519a9d2e6.tar.gz
scummvm-rg350-5ce830b97643fc76bdcafdbbe09e226519a9d2e6.tar.bz2
scummvm-rg350-5ce830b97643fc76bdcafdbbe09e226519a9d2e6.zip
SDL: Add a OpenGL SDL backend and hook it into the SDL backend.
The hooking code is nearly exactly the old hooking code. Only the OpenGL SDL creation has been adapted since it uses a different constructor now.
-rw-r--r--backends/graphics/opengl/opengl-graphics.cpp4
-rw-r--r--backends/graphics/opengl/opengl-graphics.h4
-rw-r--r--backends/graphics/openglsdl/openglsdl-graphics.cpp487
-rw-r--r--backends/graphics/openglsdl/openglsdl-graphics.h115
-rw-r--r--backends/module.mk5
-rw-r--r--backends/platform/sdl/sdl.cpp231
-rw-r--r--backends/platform/sdl/sdl.h19
7 files changed, 861 insertions, 4 deletions
diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index 7ea880c92e..87d6d3c2e5 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -106,6 +106,10 @@ const OSystem::GraphicsMode glGraphicsModes[] = {
} // End of anonymous namespace
+const OSystem::GraphicsMode *OpenGLGraphicsManager::supportedGraphicsModes() {
+ return glGraphicsModes;
+}
+
const OSystem::GraphicsMode *OpenGLGraphicsManager::getSupportedGraphicsModes() const {
return glGraphicsModes;
}
diff --git a/backends/graphics/opengl/opengl-graphics.h b/backends/graphics/opengl/opengl-graphics.h
index e21bda4b8a..5aa521cb7a 100644
--- a/backends/graphics/opengl/opengl-graphics.h
+++ b/backends/graphics/opengl/opengl-graphics.h
@@ -47,6 +47,10 @@ public:
virtual void setFeatureState(OSystem::Feature f, bool enable);
virtual bool getFeatureState(OSystem::Feature f);
+ // HACK: This is required for the SDL backend to switch between OpenGL SDL
+ // and Surface SDL.
+ static const OSystem::GraphicsMode *supportedGraphicsModes();
+
virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const;
virtual int getDefaultGraphicsMode() const;
virtual bool setGraphicsMode(int mode);
diff --git a/backends/graphics/openglsdl/openglsdl-graphics.cpp b/backends/graphics/openglsdl/openglsdl-graphics.cpp
new file mode 100644
index 0000000000..ce6d7ec7f0
--- /dev/null
+++ b/backends/graphics/openglsdl/openglsdl-graphics.cpp
@@ -0,0 +1,487 @@
+/* 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/openglsdl/openglsdl-graphics.h"
+
+#include "common/textconsole.h"
+#include "common/config-manager.h"
+
+OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(uint desktopWidth, uint desktopHeight, SdlEventSource *eventSource)
+ : SdlGraphicsManager(eventSource), _lastVideoModeLoad(0), _hwScreen(nullptr), _lastRequestedWidth(0), _lastRequestedHeight(0),
+ _graphicsScale(2), _ignoreLoadVideoMode(false), _gotResize(false), _wantsFullScreen(false), _ignoreResizeEvents(0),
+ _desiredFullscreenWidth(0), _desiredFullscreenHeight(0) {
+ // Initialize SDL video subsystem
+ if (SDL_InitSubSystem(SDL_INIT_VIDEO) == -1) {
+ error("Could not initialize SDL: %s", SDL_GetError());
+ }
+
+ // Setup OpenGL attributes for SDL
+ SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+ // This is also called in initSDL(), but initializing graphics
+ // may reset it.
+ SDL_EnableUNICODE(1);
+
+ // Disable OS cursor
+ SDL_ShowCursor(SDL_DISABLE);
+
+ // Retrieve a list of working fullscreen modes
+ const SDL_Rect *const *availableModes = SDL_ListModes(NULL, SDL_OPENGL | SDL_FULLSCREEN);
+ if (availableModes != (void *)-1) {
+ for (;*availableModes; ++availableModes) {
+ const SDL_Rect *mode = *availableModes;
+
+ _fullscreenVideoModes.push_back(VideoMode(mode->w, mode->h));
+ }
+
+ // Sort the modes in ascending order.
+ Common::sort(_fullscreenVideoModes.begin(), _fullscreenVideoModes.end());
+ }
+
+ // In case SDL is fine with every mode we will force the desktop mode.
+ // TODO? We could also try to add some default resolutions here.
+ if (_fullscreenVideoModes.empty() && desktopWidth && desktopHeight) {
+ _fullscreenVideoModes.push_back(VideoMode(desktopWidth, desktopHeight));
+ }
+
+ // Get information about display sizes from the previous runs.
+ if (ConfMan.hasKey("last_fullscreen_mode_width", Common::ConfigManager::kApplicationDomain) && ConfMan.hasKey("last_fullscreen_mode_height", Common::ConfigManager::kApplicationDomain)) {
+ _desiredFullscreenWidth = ConfMan.getInt("last_fullscreen_mode_width", Common::ConfigManager::kApplicationDomain);
+ _desiredFullscreenHeight = ConfMan.getInt("last_fullscreen_mode_height", Common::ConfigManager::kApplicationDomain);
+ } else {
+ // Use the desktop resolutions when no previous default has been setup.
+ _desiredFullscreenWidth = desktopWidth;
+ _desiredFullscreenHeight = desktopHeight;
+ }
+}
+
+OpenGLSdlGraphicsManager::~OpenGLSdlGraphicsManager() {
+ // Unregister the event observer
+ if (g_system->getEventManager()->getEventDispatcher()) {
+ g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this);
+ }
+}
+
+void OpenGLSdlGraphicsManager::initEventObserver() {
+ // Register the graphics manager as a event observer
+ g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false);
+}
+
+bool OpenGLSdlGraphicsManager::hasFeature(OSystem::Feature f) {
+ switch (f) {
+ case OSystem::kFeatureFullscreenMode:
+ case OSystem::kFeatureIconifyWindow:
+ return true;
+
+ default:
+ return OpenGLGraphicsManager::hasFeature(f);
+ }
+}
+
+void OpenGLSdlGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
+ switch (f) {
+ case OSystem::kFeatureFullscreenMode:
+ assert(getTransactionMode() != kTransactionNone);
+ _wantsFullScreen = enable;
+ // When we switch to windowed mode we will ignore resize events. This
+ // avoids bad resizes to the (former) fullscreen resolution.
+ if (!enable) {
+ _ignoreResizeEvents = 10;
+ }
+ break;
+
+ case OSystem::kFeatureIconifyWindow:
+ if (enable) {
+ SDL_WM_IconifyWindow();
+ }
+ break;
+
+ default:
+ OpenGLGraphicsManager::setFeatureState(f, enable);
+ }
+}
+
+bool OpenGLSdlGraphicsManager::getFeatureState(OSystem::Feature f) {
+ switch (f) {
+ case OSystem::kFeatureFullscreenMode:
+ if (_hwScreen) {
+ return (_hwScreen->flags & SDL_FULLSCREEN) != 0;
+ } else {
+ return _wantsFullScreen;
+ }
+
+ default:
+ return OpenGLGraphicsManager::getFeatureState(f);
+ }
+}
+
+bool OpenGLSdlGraphicsManager::setGraphicsMode(int mode) {
+ // HACK: This is stupid but the SurfaceSDL backend defaults to 2x. This
+ // assures that the launcher (which requests 320x200) has a reasonable
+ // size. It also makes small games have a reasonable size (i.e. at least
+ // 640x400). We follow the same logic here until we have a better way to
+ // give hints to our backend for that.
+ _graphicsScale = 2;
+
+ return OpenGLGraphicsManager::setGraphicsMode(mode);
+}
+
+void OpenGLSdlGraphicsManager::resetGraphicsScale() {
+ OpenGLGraphicsManager::resetGraphicsScale();
+
+ // HACK: See OpenGLSdlGraphicsManager::setGraphicsMode.
+ _graphicsScale = 1;
+}
+
+#ifdef USE_RGB_COLOR
+Common::List<Graphics::PixelFormat> OpenGLSdlGraphicsManager::getSupportedFormats() const {
+ Common::List<Graphics::PixelFormat> formats;
+
+ // RGBA8888
+ formats.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
+ // RGB565
+ formats.push_back(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
+ // RGBA5551
+ formats.push_back(Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0));
+ // RGBA4444
+ formats.push_back(Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0));
+
+#ifndef USE_GLES
+ // ARGB8888, this should not be here, but Sword25 requires it. :-/
+ formats.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24));
+
+ // RGB555, this is used by SCUMM HE 16 bit games.
+ formats.push_back(Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0));
+#endif
+
+ formats.push_back(Graphics::PixelFormat::createFormatCLUT8());
+
+ return formats;
+}
+#endif
+
+void OpenGLSdlGraphicsManager::updateScreen() {
+ if (_ignoreResizeEvents) {
+ --_ignoreResizeEvents;
+ }
+
+ OpenGLGraphicsManager::updateScreen();
+
+ // Swap OpenGL buffers
+ SDL_GL_SwapBuffers();
+}
+
+void OpenGLSdlGraphicsManager::notifyVideoExpose() {
+}
+
+void OpenGLSdlGraphicsManager::notifyResize(const uint width, const uint height) {
+ if (!_ignoreResizeEvents && _hwScreen && !(_hwScreen->flags & SDL_FULLSCREEN)) {
+ // We save that we handled a resize event here. We need to know this
+ // so we do not overwrite the users requested window size whenever we
+ // switch aspect ratio or similar.
+ _gotResize = true;
+ if (!setupMode(width, height)) {
+ warning("OpenGLSdlGraphicsManager::notifyResize: Resize failed ('%s')", SDL_GetError());
+ g_system->quit();
+ }
+ }
+}
+
+void OpenGLSdlGraphicsManager::transformMouseCoordinates(Common::Point &point) {
+ adjustMousePosition(point.x, point.y);
+}
+
+void OpenGLSdlGraphicsManager::notifyMousePos(Common::Point mouse) {
+ setMousePosition(mouse.x, mouse.y);
+}
+
+void OpenGLSdlGraphicsManager::setInternalMousePosition(int x, int y) {
+ SDL_WarpMouse(x, y);
+}
+
+bool OpenGLSdlGraphicsManager::loadVideoMode(uint requestedWidth, uint requestedHeight, const Graphics::PixelFormat &format) {
+ // In some cases we might not want to load the requested video mode. This
+ // will assure that the window size is not altered.
+ if (_ignoreLoadVideoMode) {
+ _ignoreLoadVideoMode = false;
+ return true;
+ }
+
+ // This function should never be called from notifyResize thus we know
+ // that the requested size came from somewhere else.
+ _gotResize = false;
+
+ // Save the requested dimensions.
+ _lastRequestedWidth = requestedWidth;
+ _lastRequestedHeight = requestedHeight;
+
+ // Apply the currently saved scale setting.
+ requestedWidth *= _graphicsScale;
+ requestedHeight *= _graphicsScale;
+
+ // Set up the mode.
+ return setupMode(requestedWidth, requestedHeight);
+}
+
+bool OpenGLSdlGraphicsManager::setupMode(uint width, uint height) {
+ // In case we request a fullscreen mode we will use the mode the user
+ // has chosen last time or the biggest mode available.
+ if (_wantsFullScreen) {
+ if (_desiredFullscreenWidth && _desiredFullscreenHeight) {
+ // In case only a distinct set of modes is available we check
+ // whether the requested mode is actually available.
+ if (!_fullscreenVideoModes.empty()) {
+ VideoModeArray::const_iterator i = Common::find(_fullscreenVideoModes.begin(),
+ _fullscreenVideoModes.end(),
+ VideoMode(_desiredFullscreenWidth, _desiredFullscreenHeight));
+ // It's not available fall back to default.
+ if (i == _fullscreenVideoModes.end()) {
+ _desiredFullscreenWidth = 0;
+ _desiredFullscreenHeight = 0;
+ }
+ }
+ }
+
+ // In case no desired mode has been set we default to the biggest mode
+ // available or the requested mode in case we don't know any
+ // any fullscreen modes.
+ if (!_desiredFullscreenWidth || !_desiredFullscreenHeight) {
+ if (!_fullscreenVideoModes.empty()) {
+ VideoModeArray::const_iterator i = _fullscreenVideoModes.end();
+ --i;
+
+ _desiredFullscreenWidth = i->width;
+ _desiredFullscreenHeight = i->height;
+ } else {
+ _desiredFullscreenWidth = width;
+ _desiredFullscreenHeight = height;
+ }
+ }
+
+ // Remember our choice.
+ ConfMan.setInt("last_fullscreen_mode_width", _desiredFullscreenWidth, Common::ConfigManager::kApplicationDomain);
+ ConfMan.setInt("last_fullscreen_mode_height", _desiredFullscreenHeight, Common::ConfigManager::kApplicationDomain);
+
+ // Use our choice.
+ width = _desiredFullscreenWidth;
+ height = _desiredFullscreenHeight;
+ }
+
+ // WORKAROUND: Working around infamous SDL bugs when switching
+ // resolutions too fast. This might cause the event system to supply
+ // incorrect mouse position events otherwise.
+ // Reference: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=665779
+ const uint32 curTime = SDL_GetTicks();
+ if (_hwScreen && (curTime < _lastVideoModeLoad || curTime - _lastVideoModeLoad < 100)) {
+ for (int i = 10; i > 0; --i) {
+ SDL_PumpEvents();
+ SDL_Delay(10);
+ }
+ }
+ _lastVideoModeLoad = curTime;
+
+ uint32 flags = SDL_OPENGL;
+ if (_wantsFullScreen) {
+ flags |= SDL_FULLSCREEN;
+ } else {
+ flags |= SDL_RESIZABLE;
+ }
+
+ _hwScreen = SDL_SetVideoMode(width, height, 32, flags);
+
+ if (!_hwScreen) {
+ // We treat fullscreen requests as a "hint" for now. This means in
+ // case it is not available we simply ignore it.
+ if (_wantsFullScreen) {
+ _hwScreen = SDL_SetVideoMode(width, height, 32, SDL_OPENGL | SDL_RESIZABLE);
+ }
+ }
+
+ if (_hwScreen) {
+ const Graphics::PixelFormat rgba8888 = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
+ notifyContextChange(rgba8888, rgba8888);
+ setActualScreenSize(_hwScreen->w, _hwScreen->h);
+ }
+
+ return _hwScreen != nullptr;
+}
+
+bool OpenGLSdlGraphicsManager::notifyEvent(const Common::Event &event) {
+ switch (event.type) {
+ case Common::EVENT_KEYUP:
+ return isHotkey(event);
+
+ case Common::EVENT_KEYDOWN:
+ if (event.kbd.hasFlags(Common::KBD_ALT)) {
+ if ( event.kbd.keycode == Common::KEYCODE_RETURN
+ || event.kbd.keycode == (Common::KeyCode)SDLK_KP_ENTER) {
+ // Alt-Return and Alt-Enter toggle full screen mode
+ beginGFXTransaction();
+ setFeatureState(OSystem::kFeatureFullscreenMode, !getFeatureState(OSystem::kFeatureFullscreenMode));
+ endGFXTransaction();
+ return true;
+ }
+ } else if (event.kbd.hasFlags(Common::KBD_CTRL | Common::KBD_ALT)) {
+ if ( event.kbd.keycode == Common::KEYCODE_PLUS || event.kbd.keycode == Common::KEYCODE_MINUS
+ || event.kbd.keycode == Common::KEYCODE_KP_PLUS || event.kbd.keycode == Common::KEYCODE_KP_MINUS) {
+ // Ctrl+Alt+Plus/Minus Increase/decrease the size
+ const int direction = (event.kbd.keycode == Common::KEYCODE_PLUS || event.kbd.keycode == Common::KEYCODE_KP_PLUS) ? +1 : -1;
+
+ if (getFeatureState(OSystem::kFeatureFullscreenMode)) {
+ // In case we are in fullscreen we will choose the previous
+ // or next mode.
+
+ // In case no modes are available we do nothing.
+ if (_fullscreenVideoModes.empty()) {
+ return true;
+ }
+
+ // Look for the current mode.
+ VideoModeArray::const_iterator i = Common::find(_fullscreenVideoModes.begin(),
+ _fullscreenVideoModes.end(),
+ VideoMode(_desiredFullscreenWidth, _desiredFullscreenHeight));
+ if (i == _fullscreenVideoModes.end()) {
+ return true;
+ }
+
+ // Cycle through the modes in the specified direction.
+ if (direction > 0) {
+ ++i;
+ if (i == _fullscreenVideoModes.end()) {
+ i = _fullscreenVideoModes.begin();
+ }
+ } else {
+ if (i == _fullscreenVideoModes.begin()) {
+ i = _fullscreenVideoModes.end();
+ }
+ --i;
+ }
+
+ _desiredFullscreenWidth = i->width;
+ _desiredFullscreenHeight = i->height;
+
+ // Try to setup the mode.
+ if (!setupMode(_lastRequestedWidth, _lastRequestedHeight)) {
+ warning("OpenGLSdlGraphicsManager::notifyEvent: Fullscreen resize failed ('%s')", SDL_GetError());
+ g_system->quit();
+ }
+ } else {
+ // Calculate the next scaling setting. We approximate the
+ // current scale setting in case the user resized the
+ // window. Then we apply the direction change.
+ _graphicsScale = MAX<int>(_hwScreen->w / _lastRequestedWidth, _hwScreen->h / _lastRequestedHeight);
+ _graphicsScale = MAX<int>(_graphicsScale + direction, 1);
+
+ // Since we overwrite a user resize here we reset its
+ // flag here. This makes enabling AR smoother because it
+ // will change the window size like in surface SDL.
+ _gotResize = false;
+
+ // Try to setup the mode.
+ if (!setupMode(_lastRequestedWidth * _graphicsScale, _lastRequestedHeight * _graphicsScale)) {
+ warning("OpenGLSdlGraphicsManager::notifyEvent: Window resize failed ('%s')", SDL_GetError());
+ g_system->quit();
+ }
+ }
+
+ return true;
+ } else if (event.kbd.keycode == Common::KEYCODE_a) {
+ // In case the user changed the window size manually we will
+ // not change the window size again here.
+ _ignoreLoadVideoMode = _gotResize;
+
+ // Ctrl+Alt+a toggles the aspect ratio correction state.
+ beginGFXTransaction();
+ setFeatureState(OSystem::kFeatureAspectRatioCorrection, !getFeatureState(OSystem::kFeatureAspectRatioCorrection));
+ endGFXTransaction();
+
+ // Make sure we do not ignore the next resize. This
+ // effectively checks whether loadVideoMode has been called.
+ assert(!_ignoreLoadVideoMode);
+
+ return true;
+ } else if (event.kbd.keycode == Common::KEYCODE_f) {
+ // Ctrl+Alt+f toggles the graphics modes.
+
+ // We are crazy we will allow the OpenGL base class to
+ // introduce new graphics modes like shaders for special
+ // filtering. If some other OpenGL subclass needs this,
+ // we can think of refactoring this.
+ int mode = getGraphicsMode();
+ const OSystem::GraphicsMode *supportedModes = getSupportedGraphicsModes();
+ const OSystem::GraphicsMode *modeDesc = nullptr;
+
+ // Search the current mode.
+ for (; supportedModes->name; ++supportedModes) {
+ if (supportedModes->id == mode) {
+ modeDesc = supportedModes;
+ break;
+ }
+ }
+ assert(modeDesc);
+
+ // Try to use the next mode in the list.
+ ++modeDesc;
+ if (!modeDesc->name) {
+ modeDesc = getSupportedGraphicsModes();
+ }
+
+ // Never ever try to resize the window when we simply want to
+ // switch the graphics mode. This assures that the window size
+ // does not change.
+ _ignoreLoadVideoMode = true;
+
+ beginGFXTransaction();
+ setGraphicsMode(modeDesc->id);
+ endGFXTransaction();
+
+ // Make sure we do not ignore the next resize. This
+ // effectively checks whether loadVideoMode has been called.
+ assert(!_ignoreLoadVideoMode);
+
+ return true;
+ }
+ }
+ // Fall through
+
+ default:
+ return false;
+ }
+}
+
+bool OpenGLSdlGraphicsManager::isHotkey(const Common::Event &event) {
+ if (event.kbd.hasFlags(Common::KBD_ALT)) {
+ return event.kbd.keycode == Common::KEYCODE_RETURN
+ || event.kbd.keycode == (Common::KeyCode)SDLK_KP_ENTER;
+ } else if (event.kbd.hasFlags(Common::KBD_CTRL | Common::KBD_ALT)) {
+ return event.kbd.keycode == Common::KEYCODE_PLUS || event.kbd.keycode == Common::KEYCODE_MINUS
+ || event.kbd.keycode == Common::KEYCODE_KP_PLUS || event.kbd.keycode == Common::KEYCODE_KP_MINUS
+ || event.kbd.keycode == Common::KEYCODE_a
+ || event.kbd.keycode == Common::KEYCODE_f;
+ }
+
+ return false;
+}
diff --git a/backends/graphics/openglsdl/openglsdl-graphics.h b/backends/graphics/openglsdl/openglsdl-graphics.h
new file mode 100644
index 0000000000..0644f27602
--- /dev/null
+++ b/backends/graphics/openglsdl/openglsdl-graphics.h
@@ -0,0 +1,115 @@
+/* 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_OPENGLSDL_OPENGLSDL_GRAPHICS_H
+#define BACKENDS_GRAPHICS_OPENGLSDL_OPENGLSDL_GRAPHICS_H
+
+#include "backends/graphics/opengl/opengl-graphics.h"
+#include "backends/graphics/sdl/sdl-graphics.h"
+#include "backends/platform/sdl/sdl-sys.h"
+
+#include "common/array.h"
+#include "common/events.h"
+
+class OpenGLSdlGraphicsManager : public OpenGL::OpenGLGraphicsManager, public SdlGraphicsManager, public Common::EventObserver {
+public:
+ OpenGLSdlGraphicsManager(uint desktopWidth, uint desktopHeight, SdlEventSource *eventSource);
+ virtual ~OpenGLSdlGraphicsManager();
+
+ void initEventObserver();
+
+ // GraphicsManager API
+ virtual bool hasFeature(OSystem::Feature f);
+ virtual void setFeatureState(OSystem::Feature f, bool enable);
+ virtual bool getFeatureState(OSystem::Feature f);
+
+ virtual bool setGraphicsMode(int mode);
+ virtual void resetGraphicsScale();
+
+#ifdef USE_RGB_COLOR
+ virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const;
+#endif
+
+ virtual void updateScreen();
+
+ // EventObserver API
+ virtual bool notifyEvent(const Common::Event &event);
+
+ // SdlGraphicsManager API
+ virtual void notifyVideoExpose();
+ virtual void notifyResize(const uint width, const uint height);
+ virtual void transformMouseCoordinates(Common::Point &point);
+ virtual void notifyMousePos(Common::Point mouse);
+
+protected:
+ virtual void setInternalMousePosition(int x, int y);
+
+ virtual bool loadVideoMode(uint requestedWidth, uint requestedHeight, const Graphics::PixelFormat &format);
+private:
+ bool setupMode(uint width, uint height);
+
+ uint32 _lastVideoModeLoad;
+ SDL_Surface *_hwScreen;
+
+ uint _lastRequestedWidth;
+ uint _lastRequestedHeight;
+ uint _graphicsScale;
+ bool _ignoreLoadVideoMode;
+ bool _gotResize;
+
+ bool _wantsFullScreen;
+ uint _ignoreResizeEvents;
+
+ struct VideoMode {
+ VideoMode() : width(0), height(0) {}
+ VideoMode(uint w, uint h) : width(w), height(h) {}
+
+ bool operator<(const VideoMode &right) const {
+ if (width < right.width) {
+ return true;
+ } else if (width == right.width && height < right.height) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ bool operator==(const VideoMode &right) const {
+ return width == right.width && height == right.height;
+ }
+
+ bool operator!=(const VideoMode &right) const {
+ return !(*this == right);
+ }
+
+ uint width, height;
+ };
+ typedef Common::Array<VideoMode> VideoModeArray;
+ VideoModeArray _fullscreenVideoModes;
+
+ uint _desiredFullscreenWidth;
+ uint _desiredFullscreenHeight;
+
+ virtual bool isHotkey(const Common::Event &event);
+};
+
+#endif
diff --git a/backends/module.mk b/backends/module.mk
index b66b0b04ec..1222d9a363 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -77,6 +77,11 @@ ifndef USE_SDL13
MODULE_OBJS += \
audiocd/sdl/sdl-audiocd.o
endif
+
+ifdef USE_OPENGL
+MODULE_OBJS += \
+ graphics/openglsdl/openglsdl-graphics.o
+endif
endif
ifdef POSIX
diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp
index 16fe88e990..1431e1fc5e 100644
--- a/backends/platform/sdl/sdl.cpp
+++ b/backends/platform/sdl/sdl.cpp
@@ -47,6 +47,10 @@
#include "backends/mutex/sdl/sdl-mutex.h"
#include "backends/timer/sdl/sdl-timer.h"
#include "backends/graphics/surfacesdl/surfacesdl-graphics.h"
+#ifdef USE_OPENGL
+#include "backends/graphics/openglsdl/openglsdl-graphics.h"
+#include "graphics/cursorman.h"
+#endif
#include "icons/scummvm.xpm"
@@ -60,6 +64,14 @@
OSystem_SDL::OSystem_SDL()
:
+#ifdef USE_OPENGL
+ _desktopWidth(0),
+ _desktopHeight(0),
+ _graphicsModes(0),
+ _graphicsMode(0),
+ _sdlModesCount(0),
+ _glModesCount(0),
+#endif
_inited(false),
_initedSDL(false),
_logger(0),
@@ -100,6 +112,10 @@ OSystem_SDL::~OSystem_SDL() {
delete _mutexManager;
_mutexManager = 0;
+#ifdef USE_OPENGL
+ delete[] _graphicsModes;
+#endif
+
delete _logger;
_logger = 0;
@@ -129,6 +145,11 @@ void OSystem_SDL::init() {
if (_taskbarManager == 0)
_taskbarManager = new Common::TaskbarManager();
#endif
+
+#ifdef USE_OPENGL
+ // Setup a list with both SDL and OpenGL graphics modes
+ setupGraphicsModes();
+#endif
}
void OSystem_SDL::initBackend() {
@@ -140,8 +161,46 @@ void OSystem_SDL::initBackend() {
if (_eventSource == 0)
_eventSource = new SdlEventSource();
+ int graphicsManagerType = 0;
+
+#ifdef USE_OPENGL
+ // Query the desktop resolution. We simply hope nothing tried to change
+ // the resolution so far.
+ const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
+ if (videoInfo && videoInfo->current_w > 0 && videoInfo->current_h > 0) {
+ _desktopWidth = videoInfo->current_w;
+ _desktopHeight = videoInfo->current_h;
+ }
+#endif
+
if (_graphicsManager == 0) {
- _graphicsManager = new SurfaceSdlGraphicsManager(_eventSource);
+#ifdef USE_OPENGL
+ if (ConfMan.hasKey("gfx_mode")) {
+ Common::String gfxMode(ConfMan.get("gfx_mode"));
+ bool use_opengl = false;
+ const OSystem::GraphicsMode *mode = OpenGLSdlGraphicsManager::supportedGraphicsModes();
+ int i = 0;
+ while (mode->name) {
+ if (scumm_stricmp(mode->name, gfxMode.c_str()) == 0) {
+ _graphicsMode = i + _sdlModesCount;
+ use_opengl = true;
+ }
+
+ mode++;
+ ++i;
+ }
+
+ // If the gfx_mode is from OpenGL, create the OpenGL graphics manager
+ if (use_opengl) {
+ _graphicsManager = new OpenGLSdlGraphicsManager(_desktopWidth, _desktopHeight, _eventSource);
+ graphicsManagerType = 1;
+ }
+ }
+#endif
+ if (_graphicsManager == 0) {
+ _graphicsManager = new SurfaceSdlGraphicsManager(_eventSource);
+ graphicsManagerType = 0;
+ }
}
if (_savefileManager == 0)
@@ -183,7 +242,13 @@ void OSystem_SDL::initBackend() {
// so the virtual keyboard can be initialized, but we have to add the
// graphics manager as an event observer after initializing the event
// manager.
- ((SurfaceSdlGraphicsManager *)_graphicsManager)->initEventObserver();
+ if (graphicsManagerType == 0)
+ ((SurfaceSdlGraphicsManager *)_graphicsManager)->initEventObserver();
+#ifdef USE_OPENGL
+ else if (graphicsManagerType == 1)
+ ((OpenGLSdlGraphicsManager *)_graphicsManager)->initEventObserver();
+#endif
+
}
#if defined(USE_TASKBAR)
@@ -208,8 +273,9 @@ void OSystem_SDL::initSDL() {
if (ConfMan.hasKey("disable_sdl_parachute"))
sdlFlags |= SDL_INIT_NOPARACHUTE;
-#ifdef WEBOS
- // WebOS needs this flag or otherwise the application won't start
+#if defined(WEBOS) || defined(USE_OPENGL)
+ // WebOS needs this flag or otherwise the application won't start.
+ // OpenGL SDL needs this to query the desktop resolution on startup.
sdlFlags |= SDL_INIT_VIDEO;
#endif
@@ -478,3 +544,160 @@ Common::TimerManager *OSystem_SDL::getTimerManager() {
return _timerManager;
#endif
}
+
+#ifdef USE_OPENGL
+
+const OSystem::GraphicsMode *OSystem_SDL::getSupportedGraphicsModes() const {
+ return _graphicsModes;
+}
+
+int OSystem_SDL::getDefaultGraphicsMode() const {
+ // Return the default graphics mode from the current graphics manager
+ if (_graphicsMode < _sdlModesCount)
+ return _graphicsManager->getDefaultGraphicsMode();
+ else
+ return _graphicsManager->getDefaultGraphicsMode() + _sdlModesCount;
+}
+
+bool OSystem_SDL::setGraphicsMode(int mode) {
+ const OSystem::GraphicsMode *srcMode;
+ int i;
+
+ // Check if mode is from SDL or OpenGL
+ if (mode < _sdlModesCount) {
+ srcMode = SurfaceSdlGraphicsManager::supportedGraphicsModes();
+ i = 0;
+ } else {
+ srcMode = OpenGLSdlGraphicsManager::supportedGraphicsModes();
+ i = _sdlModesCount;
+ }
+
+ // Very hacky way to set up the old graphics manager state, in case we
+ // switch from SDL->OpenGL or OpenGL->SDL.
+ //
+ // This is a probably temporary workaround to fix bugs like #3368143
+ // "SDL/OpenGL: Crash when switching renderer backend".
+ const int screenWidth = _graphicsManager->getWidth();
+ const int screenHeight = _graphicsManager->getHeight();
+ const bool arState = _graphicsManager->getFeatureState(kFeatureAspectRatioCorrection);
+ const bool fullscreen = _graphicsManager->getFeatureState(kFeatureFullscreenMode);
+ const bool cursorPalette = _graphicsManager->getFeatureState(kFeatureCursorPalette);
+#ifdef USE_RGB_COLOR
+ const Graphics::PixelFormat pixelFormat = _graphicsManager->getScreenFormat();
+#endif
+
+ bool switchedManager = false;
+
+ // Loop through modes
+ while (srcMode->name) {
+ if (i == mode) {
+ // If the new mode and the current mode are not from the same graphics
+ // manager, delete and create the new mode graphics manager
+ if (_graphicsMode >= _sdlModesCount && mode < _sdlModesCount) {
+ debug(1, "switching to plain SDL graphics");
+ delete _graphicsManager;
+ _graphicsManager = new SurfaceSdlGraphicsManager(_eventSource);
+ ((SurfaceSdlGraphicsManager *)_graphicsManager)->initEventObserver();
+ _graphicsManager->beginGFXTransaction();
+
+ switchedManager = true;
+ } else if (_graphicsMode < _sdlModesCount && mode >= _sdlModesCount) {
+ debug(1, "switching to OpenGL graphics");
+ delete _graphicsManager;
+ _graphicsManager = new OpenGLSdlGraphicsManager(_desktopWidth, _desktopHeight, _eventSource);
+ ((OpenGLSdlGraphicsManager *)_graphicsManager)->initEventObserver();
+ _graphicsManager->beginGFXTransaction();
+
+ switchedManager = true;
+ }
+
+ _graphicsMode = mode;
+
+ if (switchedManager) {
+#ifdef USE_RGB_COLOR
+ _graphicsManager->initSize(screenWidth, screenHeight, &pixelFormat);
+#else
+ _graphicsManager->initSize(screenWidth, screenHeight, 0);
+#endif
+ _graphicsManager->setFeatureState(kFeatureAspectRatioCorrection, arState);
+ _graphicsManager->setFeatureState(kFeatureFullscreenMode, fullscreen);
+ _graphicsManager->setFeatureState(kFeatureCursorPalette, cursorPalette);
+
+ // Worst part about this right now, tell the cursor manager to
+ // resetup the cursor + cursor palette if necessarily
+
+ // First we need to try to setup the old state on the new manager...
+ if (_graphicsManager->endGFXTransaction() != kTransactionSuccess) {
+ // Oh my god if this failed the client code might just explode.
+ return false;
+ }
+
+ // Next setup the cursor again
+ CursorMan.pushCursor(0, 0, 0, 0, 0, 0);
+ CursorMan.popCursor();
+
+ // Next setup cursor palette if needed
+ if (cursorPalette) {
+ CursorMan.pushCursorPalette(0, 0, 0);
+ CursorMan.popCursorPalette();
+ }
+
+ _graphicsManager->beginGFXTransaction();
+ // Oh my god if this failed the client code might just explode.
+ return _graphicsManager->setGraphicsMode(srcMode->id);
+ } else {
+ return _graphicsManager->setGraphicsMode(srcMode->id);
+ }
+ }
+
+ i++;
+ srcMode++;
+ }
+
+ return false;
+}
+
+int OSystem_SDL::getGraphicsMode() const {
+ return _graphicsMode;
+}
+
+void OSystem_SDL::setupGraphicsModes() {
+ const OSystem::GraphicsMode *sdlGraphicsModes = SurfaceSdlGraphicsManager::supportedGraphicsModes();
+ const OSystem::GraphicsMode *openglGraphicsModes = OpenGLSdlGraphicsManager::supportedGraphicsModes();
+ _sdlModesCount = 0;
+ _glModesCount = 0;
+
+ // Count the number of graphics modes
+ const OSystem::GraphicsMode *srcMode = sdlGraphicsModes;
+ while (srcMode->name) {
+ _sdlModesCount++;
+ srcMode++;
+ }
+ srcMode = openglGraphicsModes;
+ while (srcMode->name) {
+ _glModesCount++;
+ srcMode++;
+ }
+
+ // Allocate enough space for merged array of modes
+ _graphicsModes = new OSystem::GraphicsMode[_glModesCount + _sdlModesCount + 1];
+
+ // Copy SDL graphics modes
+ memcpy((void *)_graphicsModes, sdlGraphicsModes, _sdlModesCount * sizeof(OSystem::GraphicsMode));
+
+ // Copy OpenGL graphics modes
+ memcpy((void *)(_graphicsModes + _sdlModesCount), openglGraphicsModes, _glModesCount * sizeof(OSystem::GraphicsMode));
+
+ // Set a null mode at the end
+ memset((void *)(_graphicsModes + _sdlModesCount + _glModesCount), 0, sizeof(OSystem::GraphicsMode));
+
+ // Set new internal ids for all modes
+ int i = 0;
+ OSystem::GraphicsMode *mode = _graphicsModes;
+ while (mode->name) {
+ mode->id = i++;
+ mode++;
+ }
+}
+
+#endif
diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h
index 0012e88c51..590354b699 100644
--- a/backends/platform/sdl/sdl.h
+++ b/backends/platform/sdl/sdl.h
@@ -104,6 +104,25 @@ protected:
// Logging
virtual Common::WriteStream *createLogFile() { return 0; }
Backends::Log::Log *_logger;
+
+#ifdef USE_OPENGL
+ int _desktopWidth, _desktopHeight;
+
+ OSystem::GraphicsMode *_graphicsModes;
+ int _graphicsMode;
+ int _sdlModesCount;
+ int _glModesCount;
+
+ /**
+ * Creates the merged graphics modes list
+ */
+ virtual void setupGraphicsModes();
+
+ virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const;
+ virtual int getDefaultGraphicsMode() const;
+ virtual bool setGraphicsMode(int mode);
+ virtual int getGraphicsMode() const;
+#endif
};
#endif