diff options
-rw-r--r-- | README | 1 | ||||
-rw-r--r-- | backends/graphics/openglsdl/openglsdl-graphics.cpp | 83 | ||||
-rw-r--r-- | backends/graphics/openglsdl/openglsdl-graphics.h | 6 | ||||
-rw-r--r-- | backends/graphics/surfacesdl/surfacesdl-graphics.cpp | 101 | ||||
-rw-r--r-- | backends/graphics/surfacesdl/surfacesdl-graphics.h | 11 | ||||
-rw-r--r-- | backends/graphics/windowed.h | 60 |
6 files changed, 246 insertions, 16 deletions
@@ -1718,6 +1718,7 @@ other games. stretches the image to use 320x240 pixels instead, or a multiple thereof Ctrl-Alt f - Enable/disable graphics filtering + Ctrl-Alt s - Cycle through scaling modes Alt-Enter - Toggles full screen/windowed Alt-s - Make a screenshot (SDL backend only) Ctrl-F7 - Open virtual keyboard (if enabled) diff --git a/backends/graphics/openglsdl/openglsdl-graphics.cpp b/backends/graphics/openglsdl/openglsdl-graphics.cpp index 3209905085..8dcc5582a9 100644 --- a/backends/graphics/openglsdl/openglsdl-graphics.cpp +++ b/backends/graphics/openglsdl/openglsdl-graphics.cpp @@ -39,7 +39,7 @@ OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(uint desktopWidth, uint deskt #else _lastVideoModeLoad(0), #endif - _graphicsScale(2), _ignoreLoadVideoMode(false), _gotResize(false), _wantsFullScreen(false), _ignoreResizeEvents(0), + _graphicsScale(2), _stretchMode(STRETCH_FIT), _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); @@ -266,6 +266,54 @@ bool OpenGLSdlGraphicsManager::getFeatureState(OSystem::Feature f) const { } } +namespace { +const OSystem::GraphicsMode sdlGlStretchModes[] = { + {"center", _s("Center"), STRETCH_CENTER}, + {"pixel-perfect", _s("Pixel-perfect scaling"), STRETCH_INTEGRAL}, + {"fit", _s("Fit to window"), STRETCH_FIT}, + {"stretch", _s("Stretch to window"), STRETCH_STRETCH}, + {nullptr, nullptr, 0} +}; + +} // End of anonymous namespace + +const OSystem::GraphicsMode *OpenGLSdlGraphicsManager::getSupportedStretchModes() const { + return sdlGlStretchModes; +} + +int OpenGLSdlGraphicsManager::getDefaultStretchMode() const { + return STRETCH_FIT; +} + +bool OpenGLSdlGraphicsManager::setStretchMode(int mode) { + assert(getTransactionMode() != kTransactionNone); + + if (mode == _stretchMode) + return true; + + // Check this is a valid mode + const OSystem::GraphicsMode *sm = sdlGlStretchModes; + bool found = false; + while (sm->name) { + if (sm->id == mode) { + found = true; + break; + } + sm++; + } + if (!found) { + warning("unknown stretch mode %d", mode); + return false; + } + + _stretchMode = mode; + return true; +} + +int OpenGLSdlGraphicsManager::getStretchMode() const { + return _stretchMode; +} + void OpenGLSdlGraphicsManager::initSize(uint w, uint h, const Graphics::PixelFormat *format) { // HACK: This is stupid but the SurfaceSDL backend defaults to 2x. This // assures that the launcher (which requests 320x200) has a reasonable @@ -735,7 +783,7 @@ bool OpenGLSdlGraphicsManager::notifyEvent(const Common::Event &event) { // Ctrl+Alt+f toggles filtering on/off beginGFXTransaction(); - setFeatureState(OSystem::kFeatureFilteringMode, !getFeatureState(OSystem::kFeatureFilteringMode)); + setFeatureState(OSystem::kFeatureFilteringMode, !getFeatureState(OSystem::kFeatureFilteringMode)); endGFXTransaction(); // Make sure we do not ignore the next resize. This @@ -751,6 +799,34 @@ bool OpenGLSdlGraphicsManager::notifyEvent(const Common::Event &event) { #endif return true; + } else if (event.kbd.keycode == Common::KEYCODE_s) { + // Never try to resize the window when changing the scaling mode. + _ignoreLoadVideoMode = true; + + // Ctrl+Alt+s cycles through stretch mode + int index = 0; + const OSystem::GraphicsMode *sm = sdlGlStretchModes; + while (sm->name) { + if (sm->id == _stretchMode) + break; + sm++; + index++; + } + index++; + if (!sdlGlStretchModes[index].name) + index = 0; + beginGFXTransaction(); + setStretchMode(sdlGlStretchModes[index].id); + endGFXTransaction(); + +#ifdef USE_OSD + Common::String message = Common::String::format("%s: %s", + _("Stretch mode"), + _(sdlGlStretchModes[index].description) + ); + displayMessageOnOSD(message.c_str()); +#endif + return true; } } // Fall through @@ -769,7 +845,8 @@ bool OpenGLSdlGraphicsManager::isHotkey(const Common::Event &event) const { 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; + || event.kbd.keycode == Common::KEYCODE_f + || event.kbd.keycode == Common::KEYCODE_s; } return false; diff --git a/backends/graphics/openglsdl/openglsdl-graphics.h b/backends/graphics/openglsdl/openglsdl-graphics.h index 954c7215a4..b6ea496575 100644 --- a/backends/graphics/openglsdl/openglsdl-graphics.h +++ b/backends/graphics/openglsdl/openglsdl-graphics.h @@ -43,6 +43,11 @@ public: virtual void setFeatureState(OSystem::Feature f, bool enable) override; virtual bool getFeatureState(OSystem::Feature f) const override; + virtual const OSystem::GraphicsMode *getSupportedStretchModes() const override; + virtual int getDefaultStretchMode() const override; + virtual bool setStretchMode(int mode) override; + virtual int getStretchMode() const override; + virtual void initSize(uint w, uint h, const Graphics::PixelFormat *format) override; #ifdef USE_RGB_COLOR @@ -82,6 +87,7 @@ private: uint _lastRequestedWidth; uint _lastRequestedHeight; uint _graphicsScale; + int _stretchMode; bool _ignoreLoadVideoMode; bool _gotResize; diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp index fd6e2bd400..654dbd7c97 100644 --- a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp +++ b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp @@ -71,6 +71,16 @@ static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { {0, 0, 0} }; +#if SDL_VERSION_ATLEAST(2, 0, 0) +const OSystem::GraphicsMode s_supportedStretchModes[] = { + {"center", _s("Center"), STRETCH_CENTER}, + {"pixel-perfect", _s("Pixel-perfect scaling"), STRETCH_INTEGRAL}, + {"fit", _s("Fit to window"), STRETCH_FIT}, + {"stretch", _s("Stretch to window"), STRETCH_STRETCH}, + {nullptr, nullptr, 0} +}; +#endif + DECLARE_TRANSLATION_ADDITIONAL_CONTEXT("Normal (no scaling)", "lowres") // Table of the cursor scalers [scaleFactor - 1] @@ -196,6 +206,7 @@ SurfaceSdlGraphicsManager::SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSou #if SDL_VERSION_ATLEAST(2, 0, 0) _videoMode.filtering = ConfMan.getBool("filtering"); + _videoMode.stretchMode = STRETCH_FIT; #endif // the default backend has no shaders @@ -323,6 +334,7 @@ void SurfaceSdlGraphicsManager::beginGFXTransaction() { _transactionDetails.needHotswap = false; _transactionDetails.needUpdatescreen = false; + _transactionDetails.needDisplayResize = false; #if SDL_VERSION_ATLEAST(2, 0, 0) _transactionDetails.needTextureUpdate = false; @@ -354,6 +366,10 @@ OSystem::TransactionError SurfaceSdlGraphicsManager::endGFXTransaction() { _videoMode.mode = _oldVideoMode.mode; _videoMode.scaleFactor = _oldVideoMode.scaleFactor; #if SDL_VERSION_ATLEAST(2, 0, 0) + } else if (_videoMode.stretchMode != _oldVideoMode.stretchMode) { + errors |= OSystem::kTransactionStretchModeSwitchFailed; + + _videoMode.stretchMode = _oldVideoMode.stretchMode; } else if (_videoMode.filtering != _oldVideoMode.filtering) { errors |= OSystem::kTransactionFilteringFailed; @@ -431,6 +447,8 @@ OSystem::TransactionError SurfaceSdlGraphicsManager::endGFXTransaction() { // To fix this issue we update the screen change count right here. _screenChangeCount++; + if (_transactionDetails.needDisplayResize) + recalculateDisplayAreas(); if (_transactionDetails.needUpdatescreen) internUpdateScreen(); } @@ -438,10 +456,14 @@ OSystem::TransactionError SurfaceSdlGraphicsManager::endGFXTransaction() { } else if (_transactionDetails.needTextureUpdate) { setGraphicsModeIntern(); recreateScreenTexture(); + if (_transactionDetails.needDisplayResize) + recalculateDisplayAreas(); internUpdateScreen(); #endif } else if (_transactionDetails.needUpdatescreen) { setGraphicsModeIntern(); + if (_transactionDetails.needDisplayResize) + recalculateDisplayAreas(); internUpdateScreen(); } @@ -745,6 +767,51 @@ bool SurfaceSdlGraphicsManager::setShader(int id) { return true; } +#if SDL_VERSION_ATLEAST(2, 0, 0) +const OSystem::GraphicsMode *SurfaceSdlGraphicsManager::getSupportedStretchModes() const { + return s_supportedStretchModes; +} + +int SurfaceSdlGraphicsManager::getDefaultStretchMode() const { + return STRETCH_FIT; +} + +bool SurfaceSdlGraphicsManager::setStretchMode(int mode) { + Common::StackLock lock(_graphicsMutex); + + assert(_transactionMode == kTransactionActive); + + if (_oldVideoMode.setup && _oldVideoMode.stretchMode == mode) + return true; + + // Check this is a valid mode + const OSystem::GraphicsMode *sm = s_supportedStretchModes; + bool found = false; + while (sm->name) { + if (sm->id == mode) { + found = true; + break; + } + sm++; + } + if (!found) { + warning("unknown stretch mode %d", mode); + return false; + } + + _transactionDetails.needUpdatescreen = true; + _transactionDetails.needDisplayResize = true; + + _videoMode.stretchMode = mode; + + return true; +} + +int SurfaceSdlGraphicsManager::getStretchMode() const { + return _videoMode.stretchMode; +} +#endif + void SurfaceSdlGraphicsManager::initSize(uint w, uint h, const Graphics::PixelFormat *format) { assert(_transactionMode == kTransactionActive); @@ -2485,6 +2552,38 @@ bool SurfaceSdlGraphicsManager::handleScalerHotkeys(Common::KeyCode key) { } #endif +#if SDL_VERSION_ATLEAST(2, 0, 0) + // Ctrl+Alt+s cycles through scaling mode (0 to 3) + if (key == 's') { + int index = 0; + const OSystem::GraphicsMode *sm = s_supportedStretchModes; + while (sm->name) { + if (sm->id == _videoMode.stretchMode) + break; + sm++; + index++; + } + index++; + if (!s_supportedStretchModes[index].name) + index = 0; + + beginGFXTransaction(); + setStretchMode(s_supportedStretchModes[index].id); + endGFXTransaction(); + +#ifdef USE_OSD + Common::String message = Common::String::format("%s: %s", + _("Stretch mode"), + _(s_supportedStretchModes[index].description) + ); + displayMessageOnOSD(message.c_str()); +#endif + _forceRedraw = true; + internUpdateScreen(); + return true; + } +#endif + int newMode = -1; int factor = _videoMode.scaleFactor - 1; SDLKey sdlKey = (SDLKey)key; @@ -2575,6 +2674,8 @@ bool SurfaceSdlGraphicsManager::isScalerHotkey(const Common::Event &event) { #if SDL_VERSION_ATLEAST(2, 0, 0) if (event.kbd.keycode == 'f') return true; + if (event.kbd.keycode == 's') + return true; #endif return (isScaleKey || event.kbd.keycode == 'a'); } diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.h b/backends/graphics/surfacesdl/surfacesdl-graphics.h index 9e8e75772d..6e7fec4823 100644 --- a/backends/graphics/surfacesdl/surfacesdl-graphics.h +++ b/backends/graphics/surfacesdl/surfacesdl-graphics.h @@ -98,6 +98,12 @@ public: virtual const OSystem::GraphicsMode *getSupportedShaders() const override; virtual int getShader() const override; virtual bool setShader(int id) override; +#if SDL_VERSION_ATLEAST(2, 0, 0) + virtual const OSystem::GraphicsMode *getSupportedStretchModes() const override; + virtual int getDefaultStretchMode() const override; + virtual bool setStretchMode(int mode) override; + virtual int getStretchMode() const override; +#endif virtual void initSize(uint w, uint h, const Graphics::PixelFormat *format = NULL) override; virtual int getScreenChangeID() const override { return _screenChangeCount; } @@ -174,6 +180,9 @@ protected: virtual bool gameNeedsAspectRatioCorrection() const override { return _videoMode.aspectRatioCorrection; } + virtual int getGameRenderScale() const override { + return _videoMode.scaleFactor; + } virtual void handleResizeImpl(const int width, const int height) override; @@ -225,6 +234,7 @@ protected: bool needUpdatescreen; #if SDL_VERSION_ATLEAST(2, 0, 0) bool needTextureUpdate; + bool needDisplayResize; #endif #ifdef USE_RGB_COLOR bool formatChanged; @@ -241,6 +251,7 @@ protected: #if SDL_VERSION_ATLEAST(2, 0, 0) bool filtering; + int stretchMode; #endif int mode; diff --git a/backends/graphics/windowed.h b/backends/graphics/windowed.h index 8a0bddf5be..4732ea9708 100644 --- a/backends/graphics/windowed.h +++ b/backends/graphics/windowed.h @@ -26,9 +26,17 @@ #include "backends/graphics/graphics.h" #include "common/frac.h" #include "common/rect.h" +#include "common/config-manager.h" #include "common/textconsole.h" #include "graphics/scaler/aspect.h" +enum { + STRETCH_CENTER = 0, + STRETCH_INTEGRAL = 1, + STRETCH_FIT = 2, + STRETCH_STRETCH = 3 +}; + class WindowedGraphicsManager : virtual public GraphicsManager { public: WindowedGraphicsManager() : @@ -136,6 +144,13 @@ protected: } /** + * @returns the scale used between the game size and the surface on which it is rendered. + */ + virtual int getGameRenderScale() const { + return 1; + } + + /** * Called after the window has been updated with new dimensions. * * @param width The new width of the window, excluding window decoration. @@ -156,13 +171,11 @@ protected: return; } - const frac_t outputAspect = intToFrac(_windowWidth) / _windowHeight; - - populateDisplayAreaDrawRect(getDesiredGameAspectRatio(), outputAspect, _gameDrawRect); + populateDisplayAreaDrawRect(getDesiredGameAspectRatio(), getWidth() * getGameRenderScale(), _gameDrawRect); if (getOverlayHeight()) { const frac_t overlayAspect = intToFrac(getOverlayWidth()) / getOverlayHeight(); - populateDisplayAreaDrawRect(overlayAspect, outputAspect, _overlayDrawRect); + populateDisplayAreaDrawRect(overlayAspect, getOverlayWidth(), _overlayDrawRect); } if (_overlayVisible) { @@ -316,15 +329,36 @@ protected: int _cursorX, _cursorY; private: - void populateDisplayAreaDrawRect(const frac_t inputAspect, const frac_t outputAspect, Common::Rect &drawRect) const { - int width = _windowWidth; - int height = _windowHeight; - - // Maintain aspect ratios - if (outputAspect < inputAspect) { - height = intToFrac(width) / inputAspect; - } else if (outputAspect > inputAspect) { - width = fracToInt(height * inputAspect); + void populateDisplayAreaDrawRect(const frac_t displayAspect, int originalWidth, Common::Rect &drawRect) const { + int mode = getStretchMode(); + // Mode Center = use original size, or divide by an integral amount if window is smaller than game surface + // Mode Integral = scale by an integral amount. + // Mode Fit = scale to fit the window while respecting the aspect ratio + // Mode Stretch = scale and stretch to fit the window without respecting the aspect ratio + + int width = 0, height = 0; + if (mode == STRETCH_CENTER || mode == STRETCH_INTEGRAL) { + width = originalWidth; + height = intToFrac(width) / displayAspect; + if (width > _windowWidth || height > _windowHeight) { + int fac = 1 + MAX((width - 1) / _windowWidth, (height - 1) / _windowHeight); + width /= fac; + height /= fac; + } else if (mode == STRETCH_INTEGRAL) { + int fac = MIN(_windowWidth / width, _windowHeight / height); + width *= fac; + height *= fac; + } + } else { + frac_t windowAspect = intToFrac(_windowWidth) / _windowHeight; + width = _windowWidth; + height = _windowHeight; + if (mode != STRETCH_STRETCH) { + if (windowAspect < displayAspect) + height = intToFrac(width) / displayAspect; + else if (windowAspect > displayAspect) + width = fracToInt(height * displayAspect); + } } drawRect.left = (_windowWidth - width) / 2; |