aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThierry Crozat2018-05-12 19:57:21 +0100
committerThierry Crozat2018-07-08 16:54:51 +0100
commit812ce59ee44d669d2b17a1c1602f9364900b9479 (patch)
treed1a7b66bc186a5c892c67e281a502a997246f369
parent8526c2c31a07e57f7166047a87474bffd82e8a03 (diff)
downloadscummvm-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--README1
-rw-r--r--backends/graphics/openglsdl/openglsdl-graphics.cpp83
-rw-r--r--backends/graphics/openglsdl/openglsdl-graphics.h6
-rw-r--r--backends/graphics/surfacesdl/surfacesdl-graphics.cpp101
-rw-r--r--backends/graphics/surfacesdl/surfacesdl-graphics.h11
-rw-r--r--backends/graphics/windowed.h60
6 files changed, 246 insertions, 16 deletions
diff --git a/README b/README
index 700811828d..9c0b25bdb2 100644
--- a/README
+++ b/README
@@ -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;