diff options
Diffstat (limited to 'backends/graphics/openglsdl/openglsdl-graphics.cpp')
-rw-r--r-- | backends/graphics/openglsdl/openglsdl-graphics.cpp | 886 |
1 files changed, 372 insertions, 514 deletions
diff --git a/backends/graphics/openglsdl/openglsdl-graphics.cpp b/backends/graphics/openglsdl/openglsdl-graphics.cpp index c5605cae87..925237b75e 100644 --- a/backends/graphics/openglsdl/openglsdl-graphics.cpp +++ b/backends/graphics/openglsdl/openglsdl-graphics.cpp @@ -8,45 +8,42 @@ * 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 "common/scummsys.h" - -#if defined(SDL_BACKEND) && defined(USE_OPENGL) - #include "backends/graphics/openglsdl/openglsdl-graphics.h" -#include "backends/platform/sdl/sdl.h" -#include "common/config-manager.h" + #include "common/textconsole.h" +#include "common/config-manager.h" +#ifdef USE_OSD #include "common/translation.h" +#endif -OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(SdlEventSource *eventSource) - : - SdlGraphicsManager(eventSource), - _hwscreen(0), - _screenResized(false), - _activeFullscreenMode(-2), - _lastFullscreenModeWidth(0), - _lastFullscreenModeHeight(0), - _desktopWidth(0), - _desktopHeight(0), - _ignoreResizeFrames(0) { - +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); @@ -54,27 +51,41 @@ OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(SdlEventSource *eventSource) // Disable OS cursor SDL_ShowCursor(SDL_DISABLE); - // Get desktop resolution - // TODO: In case the OpenGL manager is created *after* a plain SDL manager - // has been used, this will return the last setup graphics mode rather - // than the desktop resolution. We should really look into a way to - // properly retrieve the desktop resolution. - const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo(); - if (videoInfo->current_w > 0 && videoInfo->current_h > 0) { - _desktopWidth = videoInfo->current_w; - _desktopHeight = videoInfo->current_h; + // 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)); } - if (ConfMan.hasKey("last_fullscreen_mode_width") && ConfMan.hasKey("last_fullscreen_mode_height")) { - _lastFullscreenModeWidth = ConfMan.getInt("last_fullscreen_mode_width"); - _lastFullscreenModeHeight = ConfMan.getInt("last_fullscreen_mode_height"); + // 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() != NULL) + if (g_system->getEventManager()->getEventDispatcher()) { g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this); + } } void OpenGLSdlGraphicsManager::initEventObserver() { @@ -83,421 +94,270 @@ void OpenGLSdlGraphicsManager::initEventObserver() { } bool OpenGLSdlGraphicsManager::hasFeature(OSystem::Feature f) { - return - (f == OSystem::kFeatureFullscreenMode) || - (f == OSystem::kFeatureIconifyWindow) || - OpenGLGraphicsManager::hasFeature(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) + if (enable) { SDL_WM_IconifyWindow(); + } break; + default: OpenGLGraphicsManager::setFeatureState(f, enable); } } -#ifdef USE_RGB_COLOR - -Common::List<Graphics::PixelFormat> OpenGLSdlGraphicsManager::getSupportedFormats() const { - assert(!_supportedFormats.empty()); - return _supportedFormats; -} - -void OpenGLSdlGraphicsManager::detectSupportedFormats() { - - // Clear old list - _supportedFormats.clear(); - - // Some tables with standard formats that we always list - // as "supported". If frontend code tries to use one of - // these, we will perform the necessary format - // conversion in the background. Of course this incurs a - // performance hit, but on desktop ports this should not - // matter. We still push the currently active format to - // the front, so if frontend code just uses the first - // available format, it will get one that is "cheap" to - // use. - const Graphics::PixelFormat RGBList[] = { -#if defined(ENABLE_32BIT) - Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0), // RGBA8888 -#ifndef USE_GLES - Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24), // ARGB8888 -#endif - Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0), // RGB888 -#endif - Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0), // RGB565 - Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0), // RGB5551 - Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0), // RGB555 - Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0), // RGBA4444 -#ifndef USE_GLES - Graphics::PixelFormat(2, 4, 4, 4, 4, 8, 4, 0, 12) // ARGB4444 -#endif - }; -#ifndef USE_GLES - const Graphics::PixelFormat BGRList[] = { -#ifdef ENABLE_32BIT - Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24), // ABGR8888 - Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0), // BGRA8888 - Graphics::PixelFormat(3, 8, 8, 8, 0, 0, 8, 16, 0), // BGR888 -#endif - Graphics::PixelFormat(2, 5, 6, 5, 0, 0, 5, 11, 0), // BGR565 - Graphics::PixelFormat(2, 5, 5, 5, 1, 1, 6, 11, 0), // BGRA5551 - Graphics::PixelFormat(2, 4, 4, 4, 4, 0, 4, 8, 12), // ABGR4444 - Graphics::PixelFormat(2, 4, 4, 4, 4, 4, 8, 12, 0) // BGRA4444 - }; -#endif - - Graphics::PixelFormat format = Graphics::PixelFormat::createFormatCLUT8(); - if (_hwscreen) { - // Get our currently set hardware format - format = Graphics::PixelFormat(_hwscreen->format->BytesPerPixel, - 8 - _hwscreen->format->Rloss, 8 - _hwscreen->format->Gloss, - 8 - _hwscreen->format->Bloss, 8 - _hwscreen->format->Aloss, - _hwscreen->format->Rshift, _hwscreen->format->Gshift, - _hwscreen->format->Bshift, _hwscreen->format->Ashift); - - // Workaround to SDL not providing an accurate Aloss value on Mac OS X. - if (_hwscreen->format->Amask == 0) - format.aLoss = 8; - - // Push it first, as the prefered format if available - for (int i = 0; i < ARRAYSIZE(RGBList); i++) { - if (RGBList[i] == format) { - _supportedFormats.push_back(format); - break; - } - } -#ifndef USE_GLES - for (int i = 0; i < ARRAYSIZE(BGRList); i++) { - if (BGRList[i] == format) { - _supportedFormats.push_back(format); - break; - } +bool OpenGLSdlGraphicsManager::getFeatureState(OSystem::Feature f) { + switch (f) { + case OSystem::kFeatureFullscreenMode: + if (_hwScreen) { + return (_hwScreen->flags & SDL_FULLSCREEN) != 0; + } else { + return _wantsFullScreen; } -#endif - } - // Push some RGB formats - for (int i = 0; i < ARRAYSIZE(RGBList); i++) { - if (_hwscreen && (RGBList[i].bytesPerPixel > format.bytesPerPixel)) - continue; - if (RGBList[i] != format) - _supportedFormats.push_back(RGBList[i]); - } -#ifndef USE_GLES - // Push some BGR formats - for (int i = 0; i < ARRAYSIZE(BGRList); i++) { - if (_hwscreen && (BGRList[i].bytesPerPixel > format.bytesPerPixel)) - continue; - if (BGRList[i] != format) - _supportedFormats.push_back(BGRList[i]); + default: + return OpenGLGraphicsManager::getFeatureState(f); } -#endif - _supportedFormats.push_back(Graphics::PixelFormat::createFormatCLUT8()); } -#endif +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; -void OpenGLSdlGraphicsManager::setInternalMousePosition(int x, int y) { - SDL_WarpMouse(x, y); + return OpenGLGraphicsManager::setGraphicsMode(mode); } -void OpenGLSdlGraphicsManager::updateScreen() { - if (_ignoreResizeFrames) - _ignoreResizeFrames -= 1; +void OpenGLSdlGraphicsManager::resetGraphicsScale() { + OpenGLGraphicsManager::resetGraphicsScale(); - OpenGLGraphicsManager::updateScreen(); + // HACK: See OpenGLSdlGraphicsManager::setGraphicsMode. + _graphicsScale = 1; } -// -// Intern -// - -bool OpenGLSdlGraphicsManager::setupFullscreenMode() { - SDL_Rect const* const*availableModes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_OPENGL); - - // SDL_ListModes() returns -1 in case any dimension is okay. In that - // case we'll reuse the current desktop resolution for fullscreen. - if (availableModes == (void *)-1) { - _videoMode.hardwareWidth = _desktopWidth; - _videoMode.hardwareHeight = _desktopHeight; - _activeFullscreenMode = -2; - return true; - } - - // If -2, autodetect the fullscreen mode - // The last used fullscreen mode will be prioritized, if there is no last fullscreen - // mode, the desktop resolution will be used, and in case the desktop resolution - // is not available as a fullscreen mode, the one with smallest metric will be selected. - if (_activeFullscreenMode == -2) { - // Desktop resolution - int desktopModeIndex = -1; - - // Best metric mode - const SDL_Rect *bestMode = availableModes[0]; - int bestModeIndex = 0; - uint bestMetric = (uint)-1; - - // Iterate over all available fullscreen modes - for (int i = 0; const SDL_Rect *mode = availableModes[i]; i++) { - // Try to setup the last used fullscreen mode - if (mode->w == _lastFullscreenModeWidth && mode->h == _lastFullscreenModeHeight) { - _videoMode.hardwareWidth = _lastFullscreenModeWidth; - _videoMode.hardwareHeight = _lastFullscreenModeHeight; - _activeFullscreenMode = i; - return true; - } +#ifdef USE_RGB_COLOR +Common::List<Graphics::PixelFormat> OpenGLSdlGraphicsManager::getSupportedFormats() const { + Common::List<Graphics::PixelFormat> formats; - if (mode->w == _desktopWidth && mode->h == _desktopHeight) - desktopModeIndex = i; + // 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)); - if (mode->w < _videoMode.overlayWidth) - continue; - if (mode->h < _videoMode.overlayHeight) - continue; +#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)); - uint metric = mode->w * mode->h - _videoMode.overlayWidth * _videoMode.overlayHeight; - if (metric < bestMetric) { - bestMode = mode; - bestMetric = metric; - bestModeIndex = i; - } - } + // 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 - if (desktopModeIndex >= 0) { - _videoMode.hardwareWidth = _desktopWidth; - _videoMode.hardwareHeight = _desktopHeight; + formats.push_back(Graphics::PixelFormat::createFormatCLUT8()); - _activeFullscreenMode = desktopModeIndex; - return true; - } else if (bestMode) { - _videoMode.hardwareWidth = bestMode->w; - _videoMode.hardwareHeight = bestMode->h; + return formats; +} +#endif - _activeFullscreenMode = bestModeIndex; - return true; - } - } else { - // Use last fullscreen mode if looping backwards from the first mode - if (_activeFullscreenMode == -1) { - do { - _activeFullscreenMode++; - } while(availableModes[_activeFullscreenMode]); - _activeFullscreenMode--; - } +void OpenGLSdlGraphicsManager::updateScreen() { + if (_ignoreResizeEvents) { + --_ignoreResizeEvents; + } - // Use first fullscreen mode if looping from last mode - if (!availableModes[_activeFullscreenMode]) - _activeFullscreenMode = 0; + OpenGLGraphicsManager::updateScreen(); - // Check if the fullscreen mode is valid - if (availableModes[_activeFullscreenMode]) { - _videoMode.hardwareWidth = availableModes[_activeFullscreenMode]->w; - _videoMode.hardwareHeight = availableModes[_activeFullscreenMode]->h; - return true; - } - } + // Swap OpenGL buffers + SDL_GL_SwapBuffers(); +} - // Could not find any suiting fullscreen mode, return false. - return false; +void OpenGLSdlGraphicsManager::notifyVideoExpose() { } -bool OpenGLSdlGraphicsManager::loadGFXMode() { - // If the screen was resized, do not change its size - if (!_screenResized) { - const int scaleFactor = getScale(); - _videoMode.overlayWidth = _videoMode.hardwareWidth = _videoMode.screenWidth * scaleFactor; - _videoMode.overlayHeight = _videoMode.hardwareHeight = _videoMode.screenHeight * scaleFactor; - - // The only modes where we need to adapt the aspect ratio are 320x200 - // and 640x400. That is since our aspect ratio correction in fact is - // only used to ensure that the original pixel size aspect for these - // modes is used. - // (Non-square pixels on old monitors vs square pixel on new ones). - if (_videoMode.aspectRatioCorrection) { - if (_videoMode.screenWidth == 320 && _videoMode.screenHeight == 200) - _videoMode.overlayHeight = _videoMode.hardwareHeight = 240 * scaleFactor; - else if (_videoMode.screenWidth == 640 && _videoMode.screenHeight == 400) - _videoMode.overlayHeight = _videoMode.hardwareHeight = 480 * scaleFactor; +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(); } } +} - _screenResized = false; +void OpenGLSdlGraphicsManager::transformMouseCoordinates(Common::Point &point) { + adjustMousePosition(point.x, point.y); +} - // 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); +void OpenGLSdlGraphicsManager::notifyMousePos(Common::Point mouse) { + setMousePosition(mouse.x, mouse.y); +} - const bool isFullscreen = getFullscreenMode(); +void OpenGLSdlGraphicsManager::setInternalMousePosition(int x, int y) { + SDL_WarpMouse(x, y); +} - // In case we have an fullscreen mode and we are not in a rollback, detect - // a proper mode to use. In case we are in a rollback, we already detected - // a proper mode when setting up that mode, thus there is no need to run - // the detection again. - if (isFullscreen && _transactionMode != kTransactionRollback) { - if (!setupFullscreenMode()) - // Failed setuping a fullscreen mode - return false; +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; } - _videoMode.overlayWidth = _videoMode.hardwareWidth; - _videoMode.overlayHeight = _videoMode.hardwareHeight; - - uint32 flags = SDL_OPENGL; - - if (isFullscreen) - flags |= SDL_FULLSCREEN; - else - flags |= SDL_RESIZABLE; + // This function should never be called from notifyResize thus we know + // that the requested size came from somewhere else. + _gotResize = false; - // Create our window - _hwscreen = SDL_SetVideoMode(_videoMode.hardwareWidth, _videoMode.hardwareHeight, 32, flags); -#ifdef USE_RGB_COLOR - detectSupportedFormats(); -#endif + // Save the requested dimensions. + _lastRequestedWidth = requestedWidth; + _lastRequestedHeight = requestedHeight; - if (_hwscreen == NULL) { - // DON'T use error(), as this tries to bring up the debug - // console, which WON'T WORK now that _hwscreen is hosed. + // Apply the currently saved scale setting. + requestedWidth *= _graphicsScale; + requestedHeight *= _graphicsScale; - if (!_oldVideoMode.setup) { - warning("SDL_SetVideoMode says we can't switch to that mode (%s)", SDL_GetError()); - g_system->quit(); - } else - // Cancel GFX load, and go back to last mode - return false; - } + // Set up the mode. + return setupMode(requestedWidth, requestedHeight); +} - // Check if the screen is BGR format - setFormatIsBGR(_hwscreen->format->Rshift != 0); +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; + } + } + } - if (isFullscreen) { - _lastFullscreenModeWidth = _videoMode.hardwareWidth; - _lastFullscreenModeHeight = _videoMode.hardwareHeight; - ConfMan.setInt("last_fullscreen_mode_width", _lastFullscreenModeWidth); - ConfMan.setInt("last_fullscreen_mode_height", _lastFullscreenModeHeight); - } + // 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; + } + } - // Call and return parent implementation of this method - return OpenGLGraphicsManager::loadGFXMode(); -} + // Remember our choice. + ConfMan.setInt("last_fullscreen_mode_width", _desiredFullscreenWidth, Common::ConfigManager::kApplicationDomain); + ConfMan.setInt("last_fullscreen_mode_height", _desiredFullscreenHeight, Common::ConfigManager::kApplicationDomain); -void OpenGLSdlGraphicsManager::unloadGFXMode() { - if (_hwscreen) { - SDL_FreeSurface(_hwscreen); - _hwscreen = NULL; + // Use our choice. + width = _desiredFullscreenWidth; + height = _desiredFullscreenHeight; } -} -void OpenGLSdlGraphicsManager::internUpdateScreen() { - // Call to parent implementation of this method - OpenGLGraphicsManager::internUpdateScreen(); - - // Swap OpenGL buffers - SDL_GL_SwapBuffers(); -} - -#ifdef USE_OSD -void OpenGLSdlGraphicsManager::displayModeChangedMsg() { - const char *newModeName = getCurrentModeName(); - if (newModeName) { - const int scaleFactor = getScale(); - - Common::String osdMessage = Common::String::format( - "%s: %s\n%d x %d -> %d x %d", - _("Current display mode"), - newModeName, - _videoMode.screenWidth * scaleFactor, - _videoMode.screenHeight * scaleFactor, - _hwscreen->w, _hwscreen->h - ); - displayMessageOnOSD(osdMessage.c_str()); + // 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); + } } -} -void OpenGLSdlGraphicsManager::displayScaleChangedMsg() { - const int scaleFactor = getScale(); - Common::String osdMessage = Common::String::format( - "%s: x%d\n%d x %d -> %d x %d", - _("Current scale"), - scaleFactor, - _videoMode.screenWidth, _videoMode.screenHeight, - _videoMode.overlayWidth, _videoMode.overlayHeight - ); - displayMessageOnOSD(osdMessage.c_str()); -} -#endif + _lastVideoModeLoad = curTime; -bool OpenGLSdlGraphicsManager::isHotkey(const Common::Event &event) { - if ((event.kbd.flags & (Common::KBD_CTRL|Common::KBD_ALT)) == (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 || - event.kbd.keycode == 'a' || event.kbd.keycode == 'f') - return true; - } else if ((event.kbd.flags & (Common::KBD_CTRL|Common::KBD_SHIFT)) == (Common::KBD_CTRL|Common::KBD_SHIFT)) { - if (event.kbd.keycode == 'a' || event.kbd.keycode == 'f') - return true; - } else if ((event.kbd.flags & (Common::KBD_ALT)) == (Common::KBD_ALT) && event.kbd.keycode == 's') { - return true; + uint32 flags = SDL_OPENGL; + if (_wantsFullScreen) { + flags |= SDL_FULLSCREEN; + } else { + flags |= SDL_RESIZABLE; } - return false; -} -void OpenGLSdlGraphicsManager::toggleFullScreen(int loop) { - beginGFXTransaction(); - const bool isFullscreen = getFullscreenMode(); + _hwScreen = SDL_SetVideoMode(width, height, 32, flags); - if (isFullscreen && loop) { - _activeFullscreenMode += loop; - setFullscreenMode(true); - } else { - _activeFullscreenMode = -2; - setFullscreenMode(!isFullscreen); + 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); } + } - // HACK: We need to force a refresh here, since we change the - // fullscreen mode. - _transactionDetails.needRefresh = true; - endGFXTransaction(); - - // Ignore resize events for the next 10 frames - _ignoreResizeFrames = 10; + 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); + } -#ifdef USE_OSD - Common::String osdMessage; - if (getFullscreenMode()) - osdMessage = Common::String::format("%s\n%d x %d", - _("Fullscreen mode"), - _hwscreen->w, _hwscreen->h - ); - else - osdMessage = Common::String::format("%s\n%d x %d", - _("Windowed mode"), - _hwscreen->w, _hwscreen->h - ); - displayMessageOnOSD(osdMessage.c_str()); -#endif + 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)) { - // Alt-Return and Alt-Enter toggle full screen mode - if (event.kbd.keycode == Common::KEYCODE_RETURN || - event.kbd.keycode == (Common::KeyCode)SDLK_KP_ENTER) { - toggleFullScreen(0); + 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(); + +#ifdef USE_OSD + if (getFeatureState(OSystem::kFeatureFullscreenMode)) { + displayMessageOnOSD("Fullscreen mode"); + } else { + displayMessageOnOSD("Windowed mode"); + } +#endif return true; } - // Alt-S create a screenshot - if (event.kbd.keycode == 's') { + if (event.kbd.keycode == Common::KEYCODE_s) { + // Alt-s creates a screenshot Common::String filename; for (int n = 0;; n++) { @@ -509,169 +369,167 @@ bool OpenGLSdlGraphicsManager::notifyEvent(const Common::Event &event) { break; SDL_RWclose(file); } - if (saveScreenshot(filename.c_str())) - debug("Saved screenshot '%s'", filename.c_str()); - else - warning("Could not save screenshot"); - return true; - } - } - if (event.kbd.hasFlags(Common::KBD_CTRL|Common::KBD_ALT)) { - // Ctrl-Alt-Return and Ctrl-Alt-Enter switch between full screen modes - if (event.kbd.keycode == Common::KEYCODE_RETURN || - event.kbd.keycode == (Common::KeyCode)SDLK_KP_ENTER) { - toggleFullScreen(1); + saveScreenshot(filename.c_str()); + debug("Saved screenshot '%s'", filename.c_str()); + 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(); + } + } - // Ctrl-Alt-a switch between display modes - if (event.kbd.keycode == 'a') { - beginGFXTransaction(); - setFeatureState(OSystem::kFeatureAspectRatioCorrection, !getFeatureState(OSystem::kFeatureAspectRatioCorrection)); - endGFXTransaction(); #ifdef USE_OSD - Common::String osdMessage; - if (getFeatureState(OSystem::kFeatureAspectRatioCorrection)) - osdMessage = Common::String::format("%s\n%d x %d -> %d x %d", - _("Enabled aspect ratio correction"), - _videoMode.screenWidth, _videoMode.screenHeight, - _hwscreen->w, _hwscreen->h); - else - osdMessage = Common::String::format("%s\n%d x %d -> %d x %d", - _("Disabled aspect ratio correction"), - _videoMode.screenWidth, _videoMode.screenHeight, - _hwscreen->w, _hwscreen->h); - displayMessageOnOSD(osdMessage.c_str()); + const Common::String osdMsg = Common::String::format("Resolution: %dx%d", _hwScreen->w, _hwScreen->h); + displayMessageOnOSD(osdMsg.c_str()); #endif - internUpdateScreen(); + 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-f toggles antialiasing - if (event.kbd.keycode == 'f') { + // Ctrl+Alt+a toggles the aspect ratio correction state. beginGFXTransaction(); - toggleAntialiasing(); + 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); + #ifdef USE_OSD - // TODO: This makes guesses about what internal antialiasing - // modes we use, we might want to consider a better way of - // displaying information to the user. - if (getAntialiasingState()) - displayMessageOnOSD(_("Active filter mode: Linear")); - else - displayMessageOnOSD(_("Active filter mode: Nearest")); + Common::String osdMsg = "Aspect ratio correction: "; + osdMsg += getFeatureState(OSystem::kFeatureAspectRatioCorrection) ? "enabled" : "disabled"; + displayMessageOnOSD(osdMsg.c_str()); #endif + 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); - SDLKey sdlKey = (SDLKey)event.kbd.keycode; - - // Ctrl+Alt+Plus/Minus Increase/decrease the scale factor - if ((sdlKey == SDLK_EQUALS || sdlKey == SDLK_PLUS || sdlKey == SDLK_MINUS || - sdlKey == SDLK_KP_PLUS || sdlKey == SDLK_KP_MINUS)) { - int factor = getScale(); - factor += (sdlKey == SDLK_MINUS || sdlKey == SDLK_KP_MINUS) ? -1 : +1; - if (0 < factor && factor < 4) { - // Check if the desktop resolution has been detected - if (_desktopWidth > 0 && _desktopHeight > 0) - // If the new scale factor is too big, do not scale - if (_videoMode.screenWidth * factor > _desktopWidth || - _videoMode.screenHeight * factor > _desktopHeight) - return false; - - beginGFXTransaction(); - setScale(factor); - endGFXTransaction(); -#ifdef USE_OSD - displayScaleChangedMsg(); -#endif - return true; + // Try to use the next mode in the list. + ++modeDesc; + if (!modeDesc->name) { + modeDesc = getSupportedGraphicsModes(); } - } - const bool isNormalNumber = (SDLK_1 <= sdlKey && sdlKey <= SDLK_3); - const bool isKeypadNumber = (SDLK_KP1 <= sdlKey && sdlKey <= SDLK_KP3); + // 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); - // Ctrl-Alt-<number key> will change the GFX mode - if (isNormalNumber || isKeypadNumber) { - if (sdlKey - (isNormalNumber ? SDLK_1 : SDLK_KP1) <= 3) { -#ifdef USE_OSD - int lastMode = _videoMode.mode; -#endif - // We need to query the scale and set it up, because - // setGraphicsMode sets the default scale to 2 - int oldScale = getScale(); - beginGFXTransaction(); - setGraphicsMode(sdlKey - (isNormalNumber ? SDLK_1 : SDLK_KP1)); - setScale(oldScale); - endGFXTransaction(); #ifdef USE_OSD - if (lastMode != _videoMode.mode) - displayModeChangedMsg(); + const Common::String osdMsg = Common::String::format("Graphics mode: %s", _(modeDesc->description)); + displayMessageOnOSD(osdMsg.c_str()); #endif - internUpdateScreen(); - } - } - } - if (event.kbd.hasFlags(Common::KBD_CTRL|Common::KBD_SHIFT)) { - // Ctrl-Shift-Return and Ctrl-Shift-Enter switch backwards between full screen modes - if (event.kbd.keycode == Common::KEYCODE_RETURN || - event.kbd.keycode == (Common::KeyCode)SDLK_KP_ENTER) { - toggleFullScreen(-1); return true; } } - break; - - case Common::EVENT_KEYUP: - return isHotkey(event); + // Fall through default: - break; + return false; } - - return false; -} - -void OpenGLSdlGraphicsManager::notifyVideoExpose() { } -void OpenGLSdlGraphicsManager::notifyResize(const uint width, const uint height) { - // Do not resize if ignoring resize events. - if (!_ignoreResizeFrames && !getFullscreenMode()) { - bool scaleChanged = false; - beginGFXTransaction(); - _videoMode.hardwareWidth = width; - _videoMode.hardwareHeight = height; - - _screenResized = true; - - int scale = MIN(_videoMode.hardwareWidth / _videoMode.screenWidth, - _videoMode.hardwareHeight / _videoMode.screenHeight); - - if (getScale() != scale) { - scaleChanged = true; - setScale(MAX(MIN(scale, 3), 1)); - } - - _transactionDetails.sizeChanged = true; - endGFXTransaction(); -#ifdef USE_OSD - if (scaleChanged) - displayScaleChangedMsg(); -#endif +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 + || event.kbd.keycode == Common::KEYCODE_s; + } 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; } -} -void OpenGLSdlGraphicsManager::transformMouseCoordinates(Common::Point &point) { - adjustMousePosition(point.x, point.y); -} - -void OpenGLSdlGraphicsManager::notifyMousePos(Common::Point mouse) { - setMousePosition(mouse.x, mouse.y); + return false; } - -#endif |