diff options
author | Thierry Crozat | 2018-05-12 19:57:21 +0100 |
---|---|---|
committer | Thierry Crozat | 2018-07-08 16:54:51 +0100 |
commit | 812ce59ee44d669d2b17a1c1602f9364900b9479 (patch) | |
tree | d1a7b66bc186a5c892c67e281a502a997246f369 | |
parent | 8526c2c31a07e57f7166047a87474bffd82e8a03 (diff) | |
download | scummvm-rg350-812ce59ee44d669d2b17a1c1602f9364900b9479.tar.gz scummvm-rg350-812ce59ee44d669d2b17a1c1602f9364900b9479.tar.bz2 scummvm-rg350-812ce59ee44d669d2b17a1c1602f9364900b9479.zip |
SDL: Implement stretch mode API
Four modes are supported:
- Use original size with no scaling
- Scale by an integral amount as much as possible but not bigger
than the window.
- Scale to fit the window while respecting the aspect ratio. There
may be black bars on the left and right, or on the top and bottom,
but not both. This is the default, and the old behaviour.
- Scale and stretch to fit the window. In this mode the aspecy ratio
is not respected and there is no black bars.
The mode is controled by the "scaling_mode" value (between 0 and 3) in
the config file.
Also add Crtl-Alt-s hotkey to cycle through scaling modes
-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; |