aboutsummaryrefslogtreecommitdiff
path: root/backends
diff options
context:
space:
mode:
Diffstat (limited to 'backends')
-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