Skip to content

Commit

Permalink
BACKENDS: Fix window sizing of games that switch between multiple res…
Browse files Browse the repository at this point in the history
…olutions
  • Loading branch information
csnover committed Oct 1, 2017
1 parent 10c9ac7 commit 69f09e1
Show file tree
Hide file tree
Showing 17 changed files with 287 additions and 57 deletions.
2 changes: 2 additions & 0 deletions backends/graphics/graphics.h
Expand Up @@ -27,6 +27,7 @@
#include "common/noncopyable.h"
#include "common/keyboard.h"

#include "graphics/mode.h"
#include "graphics/palette.h"

/**
Expand Down Expand Up @@ -58,6 +59,7 @@ class GraphicsManager : public PaletteManager {
virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const = 0;
#endif
virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format = NULL) = 0;
virtual void initSizeHint(const Graphics::ModeList &modes) = 0;
virtual int getScreenChangeID() const = 0;

virtual void beginGFXTransaction() = 0;
Expand Down
17 changes: 7 additions & 10 deletions backends/graphics/openglsdl/openglsdl-graphics.cpp
Expand Up @@ -268,22 +268,19 @@ bool OpenGLSdlGraphicsManager::getFeatureState(OSystem::Feature f) {
}
}

bool OpenGLSdlGraphicsManager::setGraphicsMode(int mode) {
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
// 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();
if (w > 320) {
_graphicsScale = 1;
} else {
_graphicsScale = 2;
}

// HACK: See OpenGLSdlGraphicsManager::setGraphicsMode.
_graphicsScale = 1;
return OpenGLGraphicsManager::initSize(w, h, format);
}

#ifdef USE_RGB_COLOR
Expand Down
5 changes: 3 additions & 2 deletions backends/graphics/openglsdl/openglsdl-graphics.h
Expand Up @@ -43,8 +43,7 @@ class OpenGLSdlGraphicsManager : public OpenGL::OpenGLGraphicsManager, public Sd
virtual void setFeatureState(OSystem::Feature f, bool enable);
virtual bool getFeatureState(OSystem::Feature f);

virtual bool setGraphicsMode(int mode);
virtual void resetGraphicsScale();
virtual void initSize(uint w, uint h, const Graphics::PixelFormat *format) override;

#ifdef USE_RGB_COLOR
virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const;
Expand All @@ -69,6 +68,8 @@ class OpenGLSdlGraphicsManager : public OpenGL::OpenGLGraphicsManager, public Sd
virtual void refreshScreen();

virtual void *getProcAddress(const char *name) const;
virtual int getGraphicsModeScale(int mode) const override { return 1; }

private:
bool setupMode(uint width, uint height);

Expand Down
89 changes: 86 additions & 3 deletions backends/graphics/sdl/sdl-graphics.cpp
Expand Up @@ -23,12 +23,14 @@
#include "backends/graphics/sdl/sdl-graphics.h"
#include "backends/platform/sdl/sdl-sys.h"
#include "backends/events/sdl/sdl-events.h"
#include "common/config-manager.h"
#include "common/textconsole.h"
#include "graphics/scaler/aspect.h"

SdlGraphicsManager::SdlGraphicsManager(SdlEventSource *source, SdlWindow *window)
: _eventSource(source), _window(window)
#if SDL_VERSION_ATLEAST(2, 0, 0)
, _allowWindowSizeReset(false), _lastFlags(0)
, _allowWindowSizeReset(false), _hintedWidth(0), _hintedHeight(0), _lastFlags(0)
#endif
{
}
Expand Down Expand Up @@ -63,7 +65,7 @@ bool SdlGraphicsManager::setState(const State &state) {
#ifdef USE_RGB_COLOR
initSize(state.screenWidth, state.screenHeight, &state.pixelFormat);
#else
initSize(state.screenWidth, state.screenHeight, 0);
initSize(state.screenWidth, state.screenHeight, nullptr);
#endif
setFeatureState(OSystem::kFeatureAspectRatioCorrection, state.aspectRatio);
setFeatureState(OSystem::kFeatureFullscreenMode, state.fullscreen);
Expand All @@ -76,8 +78,82 @@ bool SdlGraphicsManager::setState(const State &state) {
}
}

bool SdlGraphicsManager::defaultGraphicsModeConfig() const {
const Common::ConfigManager::Domain *transientDomain = ConfMan.getDomain(Common::ConfigManager::kTransientDomain);
if (transientDomain && transientDomain->contains("gfx_mode")) {
const Common::String &mode = transientDomain->getVal("gfx_mode");
if (!mode.equalsIgnoreCase("normal") && !mode.equalsIgnoreCase("default")) {
return false;
}
}

const Common::ConfigManager::Domain *gameDomain = ConfMan.getActiveDomain();
if (gameDomain && gameDomain->contains("gfx_mode")) {
const Common::String &mode = gameDomain->getVal("gfx_mode");
if (!mode.equalsIgnoreCase("normal") && !mode.equalsIgnoreCase("default")) {
return false;
}
}

return true;
}

int SdlGraphicsManager::getGraphicsModeIdByName(const Common::String &name) const {
const OSystem::GraphicsMode *mode = getSupportedGraphicsModes();
while (mode && mode->name != nullptr) {
if (name.equalsIgnoreCase(mode->name)) {
return mode->id;
}
++mode;
}
return -1;
}

void SdlGraphicsManager::initSizeHint(const Graphics::ModeList &modes) {
#if SDL_VERSION_ATLEAST(2, 0, 0)
bool SdlGraphicsManager::createOrUpdateWindow(const int width, const int height, const Uint32 flags) {
const bool useDefault = defaultGraphicsModeConfig();

int scale = getGraphicsModeScale(getGraphicsModeIdByName(ConfMan.get("gfx_mode")));
if (scale == -1) {
warning("Unknown scaler; defaulting to 1");
scale = 1;
}

int16 bestWidth = 0, bestHeight = 0;
const Graphics::ModeList::const_iterator end = modes.end();
for (Graphics::ModeList::const_iterator it = modes.begin(); it != end; ++it) {
int16 width = it->width, height = it->height;

// TODO: Normalize AR correction by passing a PAR in the mode list
// instead of checking the dimensions here like this, since not all
// 320x200/640x400 uses are with non-square pixels (e.g. DreamWeb).
if (ConfMan.getBool("aspect_ratio")) {
if ((width == 320 && height == 200) || (width == 640 && height == 400)) {
height = real2Aspect(height);
}
}

if (!useDefault || width <= 320) {
width *= scale;
height *= scale;
}

if (bestWidth < width) {
bestWidth = width;
}

if (bestHeight < height) {
bestHeight = height;
}
}

_hintedWidth = bestWidth;
_hintedHeight = bestHeight;
#endif
}

#if SDL_VERSION_ATLEAST(2, 0, 0)
bool SdlGraphicsManager::createOrUpdateWindow(int width, int height, const Uint32 flags) {
if (!_window) {
return false;
}
Expand All @@ -88,6 +164,13 @@ bool SdlGraphicsManager::createOrUpdateWindow(const int width, const int height,
// size or pixel format of the internal game surface (since a user may have
// resized the game window)
if (!_window->getSDLWindow() || _lastFlags != flags || _allowWindowSizeReset) {
if (_hintedWidth) {
width = _hintedWidth;
}
if (_hintedHeight) {
height = _hintedHeight;
}

if (!_window->createOrUpdateWindow(width, height, flags)) {
return false;
}
Expand Down
14 changes: 13 additions & 1 deletion backends/graphics/sdl/sdl-graphics.h
Expand Up @@ -122,14 +122,26 @@ class SdlGraphicsManager : virtual public GraphicsManager {
*/
SdlWindow *getWindow() const { return _window; }

virtual void initSizeHint(const Graphics::ModeList &modes) override;

protected:
virtual int getGraphicsModeScale(int mode) const = 0;

bool defaultGraphicsModeConfig() const;
int getGraphicsModeIdByName(const Common::String &name) const;

#if SDL_VERSION_ATLEAST(2, 0, 0)
public:
void unlockWindowSize() { _allowWindowSizeReset = true; }
void unlockWindowSize() {
_allowWindowSizeReset = true;
_hintedWidth = 0;
_hintedHeight = 0;
}

protected:
Uint32 _lastFlags;
bool _allowWindowSizeReset;
int _hintedWidth, _hintedHeight;

bool createOrUpdateWindow(const int width, const int height, const Uint32 flags);
#endif
Expand Down
45 changes: 31 additions & 14 deletions backends/graphics/surfacesdl/surfacesdl-graphics.cpp
Expand Up @@ -598,19 +598,11 @@ void SurfaceSdlGraphicsManager::detectSupportedFormats() {
}
#endif

bool SurfaceSdlGraphicsManager::setGraphicsMode(int mode) {
Common::StackLock lock(_graphicsMutex);

assert(_transactionMode == kTransactionActive);

if (_oldVideoMode.setup && _oldVideoMode.mode == mode)
return true;

int newScaleFactor = 1;

int SurfaceSdlGraphicsManager::getGraphicsModeScale(int mode) const {
int scale;
switch (mode) {
case GFX_NORMAL:
newScaleFactor = 1;
scale = 1;
break;
#ifdef USE_SCALERS
case GFX_DOUBLESIZE:
Expand All @@ -623,18 +615,34 @@ bool SurfaceSdlGraphicsManager::setGraphicsMode(int mode) {
#ifdef USE_HQ_SCALERS
case GFX_HQ2X:
#endif
newScaleFactor = 2;
scale = 2;
break;
case GFX_TRIPLESIZE:
case GFX_ADVMAME3X:
#ifdef USE_HQ_SCALERS
case GFX_HQ3X:
#endif
newScaleFactor = 3;
scale = 3;
break;
#endif

default:
scale = -1;
}

return scale;
}

bool SurfaceSdlGraphicsManager::setGraphicsMode(int mode) {
Common::StackLock lock(_graphicsMutex);

assert(_transactionMode == kTransactionActive);

if (_oldVideoMode.setup && _oldVideoMode.mode == mode)
return true;

int newScaleFactor = getGraphicsModeScale(mode);

if (newScaleFactor == -1) {
warning("unknown gfx mode %d", mode);
return false;
}
Expand Down Expand Up @@ -774,6 +782,15 @@ void SurfaceSdlGraphicsManager::initSize(uint w, uint h, const Graphics::PixelFo
return;
#endif

if ((int)w != _videoMode.screenWidth || (int)h != _videoMode.screenHeight) {
const bool useDefault = defaultGraphicsModeConfig();
if (useDefault && w > 320) {
resetGraphicsScale();
} else {
setGraphicsMode(getGraphicsModeIdByName(ConfMan.get("gfx_mode")));
}
}

_videoMode.screenWidth = w;
_videoMode.screenHeight = h;

Expand Down
2 changes: 2 additions & 0 deletions backends/graphics/surfacesdl/surfacesdl-graphics.h
Expand Up @@ -190,6 +190,8 @@ class SurfaceSdlGraphicsManager : public SdlGraphicsManager, public Common::Even
/** Hardware screen */
SDL_Surface *_hwscreen;

virtual int getGraphicsModeScale(int mode) const override;

#if SDL_VERSION_ATLEAST(2, 0, 0)
/* SDL2 features a different API for 2D graphics. We create a wrapper
* around this API to keep the code paths as close as possible. */
Expand Down
4 changes: 4 additions & 0 deletions backends/modular-backend.cpp
Expand Up @@ -113,6 +113,10 @@ void ModularBackend::initSize(uint w, uint h, const Graphics::PixelFormat *forma
_graphicsManager->initSize(w, h, format);
}

void ModularBackend::initSizeHint(const Graphics::ModeList &modes) {
_graphicsManager->initSizeHint(modes);
}

int ModularBackend::getScreenChangeID() const {
return _graphicsManager->getScreenChangeID();
}
Expand Down
1 change: 1 addition & 0 deletions backends/modular-backend.h
Expand Up @@ -75,6 +75,7 @@ class ModularBackend : public BaseBackend {
virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const;
#endif
virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format = NULL);
virtual void initSizeHint(const Graphics::ModeList &modes) override;
virtual int getScreenChangeID() const;

virtual void beginGFXTransaction();
Expand Down
29 changes: 27 additions & 2 deletions backends/platform/sdl/sdl-window.cpp
Expand Up @@ -223,6 +223,33 @@ bool SdlWindow::createOrUpdateWindow(int width, int height, uint32 flags) {
const uint32 oldNonUpdateableFlags = _lastFlags & ~updateableFlagsMask;
const uint32 newNonUpdateableFlags = flags & ~updateableFlagsMask;

const uint32 fullscreenFlags = flags & fullscreenMask;

// This is terrible, but there is no way in SDL to get information on the
// maximum bounds of a window with decoration, and SDL is too dumb to make
// sure the window's surface doesn't grow beyond the display bounds, which
// can easily happen with 3x scalers. There is a function in SDL to get the
// window decoration size, but it only exists starting in SDL 2.0.5, which
// is a buggy release on some platforms so we can't safely use 2.0.5+
// features since some users replace the SDL dynamic library with 2.0.4, and
// the documentation says it only works on X11 anyway, which means it is
// basically worthless. So we'll just try to keep things closeish to the
// maximum for now.
SDL_DisplayMode displayMode;
SDL_GetDesktopDisplayMode(0, &displayMode);
if (!fullscreenFlags) {
displayMode.w -= 20;
displayMode.h -= 30;
}

if (width > displayMode.w) {
width = displayMode.w;
}

if (height > displayMode.h) {
height = displayMode.h;
}

if (!_window || oldNonUpdateableFlags != newNonUpdateableFlags) {
destroyWindow();
_window = SDL_CreateWindow(_windowCaption.c_str(), _lastX,
Expand All @@ -231,8 +258,6 @@ bool SdlWindow::createOrUpdateWindow(int width, int height, uint32 flags) {
setupIcon();
}
} else {
const uint32 fullscreenFlags = flags & fullscreenMask;

if (fullscreenFlags) {
SDL_DisplayMode fullscreenMode;
fullscreenMode.w = width;
Expand Down
13 changes: 13 additions & 0 deletions common/system.h
Expand Up @@ -27,6 +27,7 @@
#include "common/noncopyable.h"
#include "common/list.h" // For OSystem::getSupportedFormats()
#include "graphics/pixelformat.h"
#include "graphics/mode.h"

namespace Audio {
class Mixer;
Expand Down Expand Up @@ -633,6 +634,18 @@ class OSystem : Common::NonCopyable {
*/
virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format = NULL) = 0;

/**
* Send a list of graphics modes to the backend so it can make a decision
* about the best way to set up the display hardware.
*
* Engines that switch between different virtual screen sizes during a game
* should call this function prior to any call to initSize. Engines that use
* only a single screen size do not need to call this function.
*
* @param modes the list of graphics modes the engine will probably use.
*/
virtual void initSizeHint(const Graphics::ModeList &modes) = 0;

/**
* Return an int value which is changed whenever any screen
* parameters (like the resolution) change. That is, whenever a
Expand Down

0 comments on commit 69f09e1

Please sign in to comment.