/* 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 "backends/events/sdl/sdl-events.h" #include "common/textconsole.h" #include "common/config-manager.h" #ifdef USE_OSD #include "common/translation.h" #endif OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(uint desktopWidth, uint desktopHeight, SdlEventSource *eventSource, SdlWindow *window) : SdlGraphicsManager(eventSource, window), _lastRequestedHeight(0), #if SDL_VERSION_ATLEAST(2, 0, 0) _glContext(), #else _lastVideoModeLoad(0), _hwScreen(nullptr), #endif _graphicsScale(2), _ignoreLoadVideoMode(false), _gotResize(false), _wantsFullScreen(false), _ignoreResizeEvents(0), _desiredFullscreenWidth(0), _desiredFullscreenHeight(0) { // 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); // Setup proper SDL OpenGL context creation. #if SDL_VERSION_ATLEAST(2, 0, 0) OpenGL::ContextType glContextType; // Context version 1.4 is choosen arbitrarily based on what most shader // extensions were written against. #define DEFAULT_GL_MAJOR 1 #define DEFAULT_GL_MINOR 4 #define DEFAULT_GLES_MAJOR 1 #define DEFAULT_GLES_MINOR 1 #define DEFAULT_GLES2_MAJOR 2 #define DEFAULT_GLES2_MINOR 0 #if USE_FORCED_GL glContextType = OpenGL::kContextGL; _glContextProfileMask = 0; _glContextMajor = DEFAULT_GL_MAJOR; _glContextMinor = DEFAULT_GL_MINOR; #elif USE_FORCED_GLES glContextType = OpenGL::kContextGLES; _glContextProfileMask = SDL_GL_CONTEXT_PROFILE_ES; _glContextMajor = DEFAULT_GLES_MAJOR; _glContextMinor = DEFAULT_GLES_MINOR; #elif USE_FORCED_GLES2 glContextType = OpenGL::kContextGLES2; _glContextProfileMask = SDL_GL_CONTEXT_PROFILE_ES; _glContextMajor = DEFAULT_GLES2_MAJOR; _glContextMinor = DEFAULT_GLES2_MINOR; #else bool noDefaults = false; // Obtain the default GL(ES) context SDL2 tries to setup. // // Please note this might not actually be SDL2's defaults when multiple // instances of this object have been created. But that is no issue // because then we already set up what we want to use. // // In case no defaults are given we prefer OpenGL over OpenGL ES. if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &_glContextProfileMask) != 0) { _glContextProfileMask = 0; noDefaults = true; } if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &_glContextMajor) != 0) { noDefaults = true; } if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &_glContextMinor) != 0) { noDefaults = true; } if (noDefaults) { if (_glContextProfileMask == SDL_GL_CONTEXT_PROFILE_ES) { _glContextMajor = DEFAULT_GLES_MAJOR; _glContextMinor = DEFAULT_GLES_MINOR; } else { _glContextProfileMask = 0; _glContextMajor = DEFAULT_GL_MAJOR; _glContextMinor = DEFAULT_GL_MINOR; } } if (_glContextProfileMask == SDL_GL_CONTEXT_PROFILE_ES) { if (_glContextMajor >= 2) { glContextType = OpenGL::kContextGLES2; } else { glContextType = OpenGL::kContextGLES; } } else if (_glContextProfileMask == SDL_GL_CONTEXT_PROFILE_CORE) { glContextType = OpenGL::kContextGL; // Core profile does not allow legacy functionality, which we use. // Thus we request a standard OpenGL context. _glContextProfileMask = 0; _glContextMajor = DEFAULT_GL_MAJOR; _glContextMinor = DEFAULT_GL_MINOR; } else { glContextType = OpenGL::kContextGL; } #undef DEFAULT_GL_MAJOR #undef DEFAULT_GL_MINOR #undef DEFAULT_GLES_MAJOR #undef DEFAULT_GLES_MINOR #undef DEFAULT_GLES2_MAJOR #undef DEFAULT_GLES2_MINOR #endif setContextType(glContextType); #else setContextType(OpenGL::kContextGL); #endif // Retrieve a list of working fullscreen modes #if SDL_VERSION_ATLEAST(2, 0, 0) const int numModes = SDL_GetNumDisplayModes(0); for (int i = 0; i < numModes; ++i) { SDL_DisplayMode mode; if (SDL_GetDisplayMode(0, i, &mode)) { continue; } _fullscreenVideoModes.push_back(VideoMode(mode.w, mode.h)); } #else const SDL_Rect *const *availableModes = SDL_ListModes(NULL, SDL_OPENGL | SDL_FULLSCREEN); // TODO: NULL means that there are no fullscreen modes supported. We // should probably use this information and disable any fullscreen support // in this case. if (availableModes != NULL && availableModes != (void *)-1) { for (;*availableModes; ++availableModes) { const SDL_Rect *mode = *availableModes; _fullscreenVideoModes.push_back(VideoMode(mode->w, mode->h)); } } #endif // Sort the modes in ascending order. Common::sort(_fullscreenVideoModes.begin(), _fullscreenVideoModes.end()); // Strip duplicates in video modes. for (uint i = 0; i + 1 < _fullscreenVideoModes.size();) { if (_fullscreenVideoModes[i] == _fullscreenVideoModes[i + 1]) { _fullscreenVideoModes.remove_at(i); } else { ++i; } } // 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() { #if SDL_VERSION_ATLEAST(2, 0, 0) notifyContextDestroy(); SDL_GL_DeleteContext(_glContext); #endif } void OpenGLSdlGraphicsManager::activateManager() { SdlGraphicsManager::activateManager(); // Register the graphics manager as a event observer g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false); } void OpenGLSdlGraphicsManager::deactivateManager() { // Unregister the event observer if (g_system->getEventManager()->getEventDispatcher()) { g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this); } SdlGraphicsManager::deactivateManager(); } 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; break; case OSystem::kFeatureIconifyWindow: if (enable) { _window->iconifyWindow(); } break; default: OpenGLGraphicsManager::setFeatureState(f, enable); } } bool OpenGLSdlGraphicsManager::getFeatureState(OSystem::Feature f) { switch (f) { case OSystem::kFeatureFullscreenMode: #if SDL_VERSION_ATLEAST(2, 0, 0) if (_window) { return (SDL_GetWindowFlags(_window->getSDLWindow()) & SDL_WINDOW_FULLSCREEN) != 0; } else { return _wantsFullScreen; } #else if (_hwScreen) { return (_hwScreen->flags & SDL_FULLSCREEN) != 0; } else { return _wantsFullScreen; } #endif 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 OpenGLSdlGraphicsManager::getSupportedFormats() const { Common::List formats; // Our default mode is (memory layout wise) RGBA8888 which is a different // logical layout depending on the endianness. We chose this mode because // it is the only 32bit color mode we can safely assume to be present in // OpenGL and OpenGL ES implementations. Thus, we need to supply different // logical formats based on endianness. #ifdef SCUMM_LITTLE_ENDIAN // ABGR8888 formats.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24)); #else // RGBA8888 formats.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)); #endif // 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 !USE_FORCED_GLES && !USE_FORCED_GLES2 #if !USE_FORCED_GL if (!isGLESContext()) { #endif #ifdef SCUMM_LITTLE_ENDIAN // RGBA8888 formats.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)); #else // ABGR8888 formats.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24)); #endif #if !USE_FORCED_GL } #endif #endif // RGB555, this is used by SCUMM HE 16 bit games. // This is not natively supported by OpenGL ES implementations, we convert // the pixel format internally. formats.push_back(Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)); formats.push_back(Graphics::PixelFormat::createFormatCLUT8()); return formats; } #endif void OpenGLSdlGraphicsManager::updateScreen() { if (_ignoreResizeEvents) { --_ignoreResizeEvents; } OpenGLGraphicsManager::updateScreen(); } void OpenGLSdlGraphicsManager::notifyVideoExpose() { } void OpenGLSdlGraphicsManager::notifyResize(const uint width, const uint height) { #if SDL_VERSION_ATLEAST(2, 0, 0) // We sometime get outdated resize events from SDL2. So check that the size we get // is the actual current window size. If not ignore the resize. // The issue for example occurs when switching from fullscreen to windowed mode or // when switching between different fullscreen resolutions because SDL_DestroyWindow // for a fullscreen window that doesn't have the SDL_WINDOW_FULLSCREEN_DESKTOP flag // causes a SDL_WINDOWEVENT_RESIZED event with the old resolution to be sent, and this // event is processed after recreating the window at the new resolution. int currentWidth, currentHeight; getWindowDimensions(¤tWidth, ¤tHeight); if (width != currentWidth || height != currentHeight) return; setActualScreenSize(width, height); _eventSource->resetKeyboadEmulation(width - 1, height - 1); #else 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(); } } #endif } 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) { _window->warpMouseInWindow(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); } void OpenGLSdlGraphicsManager::refreshScreen() { // Swap OpenGL buffers #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_GL_SwapWindow(_window->getSDLWindow()); #else SDL_GL_SwapBuffers(); #endif } void *OpenGLSdlGraphicsManager::getProcAddress(const char *name) const { return SDL_GL_GetProcAddress(name); } 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; } // This is pretty confusing since RGBA8888 talks about the memory // layout here. This is a different logical layout depending on // whether we run on little endian or big endian. However, we can // only safely assume that RGBA8888 in memory layout is supported. // Thus, we chose this one. const Graphics::PixelFormat rgba8888 = #ifdef SCUMM_LITTLE_ENDIAN Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24); #else Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0); #endif #if SDL_VERSION_ATLEAST(2, 0, 0) if (_glContext) { notifyContextDestroy(); SDL_GL_DeleteContext(_glContext); _glContext = nullptr; } _window->destroyWindow(); uint32 flags = SDL_WINDOW_OPENGL; if (_wantsFullScreen) { flags |= SDL_WINDOW_FULLSCREEN; } else { flags |= SDL_WINDOW_RESIZABLE; } // Request a OpenGL (ES) context we can use. SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, _glContextProfileMask); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, _glContextMajor); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, _glContextMinor); if (!_window->createWindow(width, height, flags)) { // We treat fullscreen requests as a "hint" for now. This means in // case it is not available we simply ignore it. if (_wantsFullScreen) { _window->createWindow(width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); } if (!_window->getSDLWindow()) { return false; } } _glContext = SDL_GL_CreateContext(_window->getSDLWindow()); if (!_glContext) { return false; } notifyContextCreate(rgba8888, rgba8888); int actualWidth, actualHeight; getWindowDimensions(&actualWidth, &actualHeight); setActualScreenSize(actualWidth, actualHeight); _eventSource->resetKeyboadEmulation(actualWidth - 1, actualHeight - 1); return true; #else // 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); } } uint32 flags = SDL_OPENGL; if (_wantsFullScreen) { flags |= SDL_FULLSCREEN; } else { flags |= SDL_RESIZABLE; } if (_hwScreen) { // When a video mode has been setup already we notify the manager that // the context is about to be destroyed. // We do this because on Windows SDL_SetVideoMode can destroy and // recreate the OpenGL context. notifyContextDestroy(); } _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); } } // Part of the WORKAROUND mentioned above. _lastVideoModeLoad = SDL_GetTicks(); if (_hwScreen) { notifyContextCreate(rgba8888, rgba8888); setActualScreenSize(_hwScreen->w, _hwScreen->h); _eventSource->resetKeyboadEmulation(_hwScreen->w - 1, _hwScreen->h - 1); } // Ignore resize events (from SDL) for a few frames, if this isn't // caused by a notification from SDL. This avoids bad resizes to a // (former) resolution for which we haven't processed an event yet. if (!_gotResize) _ignoreResizeEvents = 10; return _hwScreen != nullptr; #endif } void OpenGLSdlGraphicsManager::getWindowDimensions(int *width, int *height) { #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_GetWindowSize(_window->getSDLWindow(), width, height); #else if (width) { *width = _hwScreen->w; } if (height) { *height = _hwScreen->h; } #endif } 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(); #ifdef USE_OSD if (getFeatureState(OSystem::kFeatureFullscreenMode)) { displayMessageOnOSD(_("Fullscreen mode")); } else { displayMessageOnOSD(_("Windowed mode")); } #endif return true; } if (event.kbd.keycode == Common::KEYCODE_s) { // Alt-s creates a screenshot Common::String filename; for (int n = 0;; n++) { SDL_RWops *file; filename = Common::String::format("scummvm%05d.bmp", n); file = SDL_RWFromFile(filename.c_str(), "r"); if (!file) break; SDL_RWclose(file); } 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. int windowWidth = 0, windowHeight = 0; getWindowDimensions(&windowWidth, &windowHeight); _graphicsScale = MAX(windowWidth / _lastRequestedWidth, windowHeight / _lastRequestedHeight); _graphicsScale = MAX(_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(); } } #ifdef USE_OSD int windowWidth = 0, windowHeight = 0; getWindowDimensions(&windowWidth, &windowHeight); const Common::String osdMsg = Common::String::format(_("Resolution: %dx%d"), windowWidth, windowHeight); displayMessageOnOSD(osdMsg.c_str()); #endif 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); #ifdef USE_OSD if (getFeatureState(OSystem::kFeatureAspectRatioCorrection)) displayMessageOnOSD(_("Enabled aspect ratio correction")); else displayMessageOnOSD(_("Disabled aspect ratio correction")); #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); // 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); #ifdef USE_OSD const Common::String osdMsg = Common::String::format(_("Graphics mode: %s"), _(modeDesc->description)); displayMessageOnOSD(osdMsg.c_str()); #endif 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 || 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; } return false; }