diff options
Diffstat (limited to 'backends')
-rw-r--r-- | backends/graphics/opengl/opengl-graphics.cpp | 4 | ||||
-rw-r--r-- | backends/graphics/opengl/opengl-graphics.h | 4 | ||||
-rw-r--r-- | backends/graphics/openglsdl/openglsdl-graphics.cpp | 487 | ||||
-rw-r--r-- | backends/graphics/openglsdl/openglsdl-graphics.h | 115 | ||||
-rw-r--r-- | backends/module.mk | 5 | ||||
-rw-r--r-- | backends/platform/sdl/sdl.cpp | 231 | ||||
-rw-r--r-- | backends/platform/sdl/sdl.h | 19 |
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 |