OPENGL: Allow the window to be resized

Fixes #1500.
This commit is contained in:
Bastien Bouclet 2018-07-27 20:17:18 +02:00
parent 6e6fa26620
commit ef0155a50c
8 changed files with 134 additions and 147 deletions

View file

@ -151,16 +151,15 @@ void OpenGLSdlGraphicsManager::setupScreen(uint gameWidth, uint gameHeight, bool
void OpenGLSdlGraphicsManager::createOrUpdateScreen() { void OpenGLSdlGraphicsManager::createOrUpdateScreen() {
closeOverlay(); closeOverlay();
bool engineSupportsArbitraryResolutions = g_engine && g_engine->hasFeature(Engine::kSupportsArbitraryResolutions); // If the game can't adapt to any resolution, render it to a framebuffer
// so it can be scaled to fill the available space.
// Select how the game screen is going to be drawn bool engineSupportsArbitraryResolutions = !g_engine || g_engine->hasFeature(Engine::kSupportsArbitraryResolutions);
GameRenderTarget gameRenderTarget = selectGameRenderTarget(_fullscreen, true, engineSupportsArbitraryResolutions, bool renderToFrameBuffer = !engineSupportsArbitraryResolutions && _capabilities.openGLFrameBuffer;
_capabilities.openGLFrameBuffer, _lockAspectRatio);
// Choose the effective window size or fullscreen mode // Choose the effective window size or fullscreen mode
uint effectiveWidth; uint effectiveWidth;
uint effectiveHeight; uint effectiveHeight;
if (_fullscreen && canUsePreferredResolution(gameRenderTarget, engineSupportsArbitraryResolutions)) { if (_fullscreen && !renderToFrameBuffer) {
Common::Rect fullscreenResolution = getPreferredFullscreenResolution(); Common::Rect fullscreenResolution = getPreferredFullscreenResolution();
effectiveWidth = fullscreenResolution.width(); effectiveWidth = fullscreenResolution.width();
effectiveHeight = fullscreenResolution.height(); effectiveHeight = fullscreenResolution.height();
@ -169,10 +168,8 @@ void OpenGLSdlGraphicsManager::createOrUpdateScreen() {
effectiveHeight = _engineRequestedHeight; effectiveHeight = _engineRequestedHeight;
} }
// Compute the rectangle where to draw the game inside the effective screen if (!createOrUpdateGLContext(_engineRequestedWidth, _engineRequestedHeight,
_gameRect = computeGameRect(gameRenderTarget, _engineRequestedWidth, _engineRequestedHeight, effectiveWidth, effectiveHeight); effectiveWidth, effectiveHeight, renderToFrameBuffer)) {
if (!createOrUpdateGLContext(effectiveWidth, effectiveHeight, gameRenderTarget)) {
warning("SDL Error: %s", SDL_GetError()); warning("SDL Error: %s", SDL_GetError());
g_system->quit(); g_system->quit();
} }
@ -185,22 +182,32 @@ void OpenGLSdlGraphicsManager::createOrUpdateScreen() {
} }
#endif #endif
#if SDL_VERSION_ATLEAST(2, 0, 1)
int obtainedWidth = 0, obtainedHeight = 0;
SDL_GL_GetDrawableSize(_window->getSDLWindow(), &obtainedWidth, &obtainedHeight);
#else
int obtainedWidth = effectiveWidth;
int obtainedHeight = effectiveHeight;
#endif
// Compute the rectangle where to draw the game inside the effective screen
_gameRect = computeGameRect(renderToFrameBuffer, _engineRequestedWidth, _engineRequestedHeight,
obtainedWidth, obtainedHeight);
initializeOpenGLContext(); initializeOpenGLContext();
_surfaceRenderer = OpenGL::createBestSurfaceRenderer(); _surfaceRenderer = OpenGL::createBestSurfaceRenderer();
_overlayFormat = OpenGL::Texture::getRGBAPixelFormat(); _overlayFormat = OpenGL::Texture::getRGBAPixelFormat();
_overlayScreen = new OpenGL::TiledSurface(effectiveWidth, effectiveHeight, _overlayFormat); _overlayScreen = new OpenGL::TiledSurface(obtainedWidth, obtainedHeight, _overlayFormat);
_overlayWidth = effectiveWidth;
_overlayHeight = effectiveHeight;
_screenFormat = _overlayFormat; _screenFormat = _overlayFormat;
_screenChangeCount++; _screenChangeCount++;
_eventSource->resetKeyboardEmulation(effectiveWidth - 1, effectiveHeight - 1); _eventSource->resetKeyboardEmulation(obtainedWidth - 1, obtainedHeight - 1);
#if !defined(AMIGAOS) #if !defined(AMIGAOS)
if (gameRenderTarget == kFramebuffer) { if (renderToFrameBuffer) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
_frameBuffer = createFramebuffer(_engineRequestedWidth, _engineRequestedHeight); _frameBuffer = createFramebuffer(_engineRequestedWidth, _engineRequestedHeight);
_frameBuffer->attach(); _frameBuffer->attach();
@ -208,6 +215,57 @@ void OpenGLSdlGraphicsManager::createOrUpdateScreen() {
#endif #endif
} }
Math::Rect2d OpenGLSdlGraphicsManager::computeGameRect(bool renderToFrameBuffer, uint gameWidth, uint gameHeight,
uint screenWidth, uint screenHeight) {
if (renderToFrameBuffer) {
if (_lockAspectRatio) {
// The game is scaled to fit the screen, keeping the same aspect ratio
float scale = MIN(screenHeight / float(gameHeight), screenWidth / float(gameWidth));
float scaledW = scale * (gameWidth / float(screenWidth));
float scaledH = scale * (gameHeight / float(screenHeight));
return Math::Rect2d(
Math::Vector2d(0.5 - (0.5 * scaledW), 0.5 - (0.5 * scaledH)),
Math::Vector2d(0.5 + (0.5 * scaledW), 0.5 + (0.5 * scaledH))
);
} else {
// The game occupies the whole screen
return Math::Rect2d(Math::Vector2d(0, 0), Math::Vector2d(1, 1));
}
} else {
return Math::Rect2d(Math::Vector2d(0, 0), Math::Vector2d(1, 1));
}
}
void OpenGLSdlGraphicsManager::notifyResize(const uint width, const uint height) {
#if SDL_VERSION_ATLEAST(2, 0, 0)
// Get the updated size directly from SDL, in case there are multiple
// resize events in the message queue.
int newWidth = 0, newHeight = 0;
SDL_GL_GetDrawableSize(_window->getSDLWindow(), &newWidth, &newHeight);
if (newWidth == _overlayScreen->getWidth() && newHeight == _overlayScreen->getHeight()) {
return; // nothing to do
}
// Compute the rectangle where to draw the game inside the effective screen
_gameRect = computeGameRect(_frameBuffer != nullptr,
_engineRequestedWidth, _engineRequestedHeight,
newWidth, newHeight);
// Update the overlay
delete _overlayScreen;
_overlayScreen = new OpenGL::TiledSurface(newWidth, newHeight, _overlayFormat);
// Clear the overlay background so it is not displayed distorted while resizing
delete _overlayBackground;
_overlayBackground = nullptr;
_screenChangeCount++;
_eventSource->resetKeyboardEmulation(newWidth - 1, newHeight- 1);
#endif
}
Graphics::PixelBuffer OpenGLSdlGraphicsManager::getScreenPixelBuffer() { Graphics::PixelBuffer OpenGLSdlGraphicsManager::getScreenPixelBuffer() {
error("Direct screen buffer access is not allowed when using OpenGL"); error("Direct screen buffer access is not allowed when using OpenGL");
} }
@ -240,11 +298,12 @@ OpenGLSdlGraphicsManager::OpenGLPixelFormat::OpenGLPixelFormat(uint screenBytesP
} }
bool OpenGLSdlGraphicsManager::createOrUpdateGLContext(uint effectiveWidth, uint effectiveHeight, bool OpenGLSdlGraphicsManager::createOrUpdateGLContext(uint gameWidth, uint gameHeight,
GameRenderTarget gameRenderTarget) { uint effectiveWidth, uint effectiveHeight,
bool renderToFramebuffer) {
// Build a list of OpenGL pixel formats usable by ResidualVM // Build a list of OpenGL pixel formats usable by ResidualVM
Common::Array<OpenGLPixelFormat> pixelFormats; Common::Array<OpenGLPixelFormat> pixelFormats;
if (_antialiasing > 0 && gameRenderTarget == kScreen) { if (_antialiasing > 0 && !renderToFramebuffer) {
// Don't enable screen level multisampling when rendering to a framebuffer // Don't enable screen level multisampling when rendering to a framebuffer
pixelFormats.push_back(OpenGLPixelFormat(32, 8, 8, 8, 8, _antialiasing)); pixelFormats.push_back(OpenGLPixelFormat(32, 8, 8, 8, 8, _antialiasing));
pixelFormats.push_back(OpenGLPixelFormat(16, 5, 5, 5, 1, _antialiasing)); pixelFormats.push_back(OpenGLPixelFormat(16, 5, 5, 5, 1, _antialiasing));
@ -295,7 +354,7 @@ bool OpenGLSdlGraphicsManager::createOrUpdateGLContext(uint effectiveWidth, uint
#endif #endif
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
uint32 sdlflags = SDL_WINDOW_OPENGL; uint32 sdlflags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE;
if (_fullscreen) { if (_fullscreen) {
// On Linux/X11, when toggling to fullscreen, the window manager saves // On Linux/X11, when toggling to fullscreen, the window manager saves
// the window size to be able to restore it when going back to windowed mode. // the window size to be able to restore it when going back to windowed mode.
@ -305,7 +364,7 @@ bool OpenGLSdlGraphicsManager::createOrUpdateGLContext(uint effectiveWidth, uint
// to windowed mode, the window manager has a window size to apply instead // to windowed mode, the window manager has a window size to apply instead
// of leaving the window at the fullscreen resolution size. // of leaving the window at the fullscreen resolution size.
if (!_window->getSDLWindow()) { if (!_window->getSDLWindow()) {
_window->createOrUpdateWindow(effectiveWidth, effectiveHeight, sdlflags); _window->createOrUpdateWindow(gameWidth, gameHeight, sdlflags);
} }
sdlflags |= SDL_WINDOW_FULLSCREEN; sdlflags |= SDL_WINDOW_FULLSCREEN;
@ -364,7 +423,7 @@ bool OpenGLSdlGraphicsManager::isVSyncEnabled() const {
} }
void OpenGLSdlGraphicsManager::drawOverlay() { void OpenGLSdlGraphicsManager::drawOverlay() {
glViewport(0, 0, _overlayWidth, _overlayHeight); glViewport(0, 0, _overlayScreen->getWidth(), _overlayScreen->getHeight());
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
_surfaceRenderer->prepareState(); _surfaceRenderer->prepareState();
@ -384,15 +443,15 @@ void OpenGLSdlGraphicsManager::drawSideTextures() {
if (_fullscreen && _lockAspectRatio) { if (_fullscreen && _lockAspectRatio) {
_surfaceRenderer->setFlipY(true); _surfaceRenderer->setFlipY(true);
const Math::Vector2d nudge(1.0 / float(_overlayWidth), 0); const Math::Vector2d nudge(1.0 / float(_overlayScreen->getWidth()), 0);
if (_sideTextures[0] != nullptr) { if (_sideTextures[0] != nullptr) {
float left = _gameRect.getBottomLeft().getX() - (float(_overlayHeight) / float(_sideTextures[0]->getHeight())) * _sideTextures[0]->getWidth() / float(_overlayWidth); float left = _gameRect.getBottomLeft().getX() - (float(_overlayScreen->getHeight()) / float(_sideTextures[0]->getHeight())) * _sideTextures[0]->getWidth() / float(_overlayScreen->getWidth());
Math::Rect2d leftRect(Math::Vector2d(left, 0.0), _gameRect.getBottomLeft() + nudge); Math::Rect2d leftRect(Math::Vector2d(left, 0.0), _gameRect.getBottomLeft() + nudge);
_surfaceRenderer->render(_sideTextures[0], leftRect); _surfaceRenderer->render(_sideTextures[0], leftRect);
} }
if (_sideTextures[1] != nullptr) { if (_sideTextures[1] != nullptr) {
float right = _gameRect.getTopRight().getX() + (float(_overlayHeight) / float(_sideTextures[1]->getHeight())) * _sideTextures[1]->getWidth() / float(_overlayWidth); float right = _gameRect.getTopRight().getX() + (float(_overlayScreen->getHeight()) / float(_sideTextures[1]->getHeight())) * _sideTextures[1]->getWidth() / float(_overlayScreen->getWidth());
Math::Rect2d rightRect(_gameRect.getTopRight() - nudge, Math::Vector2d(right, 1.0)); Math::Rect2d rightRect(_gameRect.getTopRight() - nudge, Math::Vector2d(right, 1.0));
_surfaceRenderer->render(_sideTextures[1], rightRect); _surfaceRenderer->render(_sideTextures[1], rightRect);
} }
@ -417,7 +476,7 @@ OpenGL::FrameBuffer *OpenGLSdlGraphicsManager::createFramebuffer(uint width, uin
void OpenGLSdlGraphicsManager::updateScreen() { void OpenGLSdlGraphicsManager::updateScreen() {
if (_frameBuffer) { if (_frameBuffer) {
_frameBuffer->detach(); _frameBuffer->detach();
glViewport(0, 0, _overlayWidth, _overlayHeight); glViewport(0, 0, _overlayScreen->getWidth(), _overlayScreen->getHeight());
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
_surfaceRenderer->prepareState(); _surfaceRenderer->prepareState();
drawSideTextures(); drawSideTextures();
@ -451,7 +510,7 @@ int16 OpenGLSdlGraphicsManager::getHeight() const {
if (_frameBuffer) if (_frameBuffer)
return _frameBuffer->getHeight(); return _frameBuffer->getHeight();
else else
return _overlayHeight; return _overlayScreen->getHeight();
} }
int16 OpenGLSdlGraphicsManager::getWidth() const { int16 OpenGLSdlGraphicsManager::getWidth() const {
@ -459,7 +518,7 @@ int16 OpenGLSdlGraphicsManager::getWidth() const {
if (_frameBuffer) if (_frameBuffer)
return _frameBuffer->getWidth(); return _frameBuffer->getWidth();
else else
return _overlayWidth; return _overlayScreen->getWidth();
} }
#pragma mark - #pragma mark -
@ -492,7 +551,7 @@ void OpenGLSdlGraphicsManager::showOverlay() {
if (_frameBuffer) if (_frameBuffer)
_frameBuffer->detach(); _frameBuffer->detach();
// If there is a game running capture the screen, so that it can be shown "below" the overlay. // If there is a game running capture the screen, so that it can be shown "below" the overlay.
_overlayBackground = new OpenGL::TiledSurface(_overlayWidth, _overlayHeight, _overlayFormat); _overlayBackground = new OpenGL::TiledSurface(_overlayScreen->getWidth(), _overlayScreen->getHeight(), _overlayFormat);
Graphics::Surface *background = _overlayBackground->getBackingSurface(); Graphics::Surface *background = _overlayBackground->getBackingSurface();
glReadPixels(0, 0, background->w, background->h, GL_RGBA, GL_UNSIGNED_BYTE, background->getPixels()); glReadPixels(0, 0, background->w, background->h, GL_RGBA, GL_UNSIGNED_BYTE, background->getPixels());
if (_frameBuffer) if (_frameBuffer)
@ -550,15 +609,23 @@ void OpenGLSdlGraphicsManager::closeOverlay() {
OpenGL::Context::destroy(); OpenGL::Context::destroy();
} }
int16 OpenGLSdlGraphicsManager::getOverlayHeight() const {
return _overlayScreen->getHeight();
}
int16 OpenGLSdlGraphicsManager::getOverlayWidth() const {
return _overlayScreen->getWidth();
}
void OpenGLSdlGraphicsManager::warpMouse(int x, int y) { void OpenGLSdlGraphicsManager::warpMouse(int x, int y) {
//ResidualVM specific //ResidualVM specific
if (_frameBuffer) { if (_frameBuffer) {
// Scale from game coordinates to screen coordinates // Scale from game coordinates to screen coordinates
x = (x * _gameRect.getWidth() * _overlayWidth) / _frameBuffer->getWidth(); x = (x * _gameRect.getWidth() * _overlayScreen->getWidth()) / _frameBuffer->getWidth();
y = (y * _gameRect.getHeight() * _overlayHeight) / _frameBuffer->getHeight(); y = (y * _gameRect.getHeight() * _overlayScreen->getHeight()) / _frameBuffer->getHeight();
x += _gameRect.getTopLeft().getX() * _overlayWidth; x += _gameRect.getTopLeft().getX() * _overlayScreen->getWidth();
y += _gameRect.getTopLeft().getY() * _overlayHeight; y += _gameRect.getTopLeft().getY() * _overlayScreen->getHeight();
} }
_window->warpMouseInWindow(x, y); _window->warpMouseInWindow(x, y);
@ -569,11 +636,11 @@ void OpenGLSdlGraphicsManager::transformMouseCoordinates(Common::Point &point) {
return; return;
// Scale from screen coordinates to game coordinates // Scale from screen coordinates to game coordinates
point.x -= _gameRect.getTopLeft().getX() * _overlayWidth; point.x -= _gameRect.getTopLeft().getX() * _overlayScreen->getWidth();
point.y -= _gameRect.getTopLeft().getY() * _overlayHeight; point.y -= _gameRect.getTopLeft().getY() * _overlayScreen->getHeight();
point.x = (point.x * _frameBuffer->getWidth()) / (_gameRect.getWidth() * _overlayWidth); point.x = (point.x * _frameBuffer->getWidth()) / (_gameRect.getWidth() * _overlayScreen->getWidth());
point.y = (point.y * _frameBuffer->getHeight()) / (_gameRect.getHeight() * _overlayHeight); point.y = (point.y * _frameBuffer->getHeight()) / (_gameRect.getHeight() * _overlayScreen->getHeight());
// Make sure we only supply valid coordinates. // Make sure we only supply valid coordinates.
point.x = CLIP<int16>(point.x, 0, _frameBuffer->getWidth() - 1); point.x = CLIP<int16>(point.x, 0, _frameBuffer->getWidth() - 1);

View file

@ -62,6 +62,8 @@ public:
virtual void clearOverlay() override; virtual void clearOverlay() override;
virtual void grabOverlay(void *buf, int pitch) const override; virtual void grabOverlay(void *buf, int pitch) const override;
virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) override; virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) override;
int16 getOverlayWidth() const override;
int16 getOverlayHeight() const override;
/* Render the passed Surfaces besides the game texture. /* Render the passed Surfaces besides the game texture.
* This is used for widescreen support in the Grim engine. * This is used for widescreen support in the Grim engine.
@ -75,6 +77,8 @@ public:
// SdlGraphicsManager API // SdlGraphicsManager API
virtual void transformMouseCoordinates(Common::Point &point) override; virtual void transformMouseCoordinates(Common::Point &point) override;
void notifyResize(const uint width, const uint height) override;
protected: protected:
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_GLContext _glContext; SDL_GLContext _glContext;
@ -100,10 +104,14 @@ protected:
* When unable to create a context with anti-aliasing this tries without. * When unable to create a context with anti-aliasing this tries without.
* When unable to create a context with the desired pixel depth this tries lower values. * When unable to create a context with the desired pixel depth this tries lower values.
*/ */
bool createOrUpdateGLContext(uint effectiveWidth, uint effectiveHeight, GameRenderTarget gameRenderTarget); bool createOrUpdateGLContext(uint gameWidth, uint gameHeight, uint effectiveWidth, uint effectiveHeight, bool renderToFramebuffer);
void createOrUpdateScreen(); void createOrUpdateScreen();
/** Compute the size and position of the game rectangle in the screen */
Math::Rect2d computeGameRect(bool renderToFrameBuffer, uint gameWidth, uint gameHeight,
uint screenWidth, uint screenHeight);
int _antialiasing; int _antialiasing;
bool _vsync; bool _vsync;

View file

@ -37,8 +37,6 @@ ResVmSdlGraphicsManager::ResVmSdlGraphicsManager(SdlEventSource *source, SdlWind
_fullscreen(false), _fullscreen(false),
_lockAspectRatio(true), _lockAspectRatio(true),
_overlayVisible(false), _overlayVisible(false),
_overlayWidth(0),
_overlayHeight(0),
_screenChangeCount(0), _screenChangeCount(0),
_capabilities(capabilities), _capabilities(capabilities),
_engineRequestedWidth(0), _engineRequestedWidth(0),
@ -67,71 +65,6 @@ void ResVmSdlGraphicsManager::deactivateManager() {
SdlGraphicsManager::deactivateManager(); SdlGraphicsManager::deactivateManager();
} }
ResVmSdlGraphicsManager::GameRenderTarget ResVmSdlGraphicsManager::selectGameRenderTarget(bool fullscreen,
bool accel3d,
bool engineSupportsArbitraryResolutions,
bool framebufferSupported,
bool lockAspectRatio) {
if (!fullscreen) {
return kScreen;
}
if (!accel3d && lockAspectRatio) {
return kSubScreen;
}
if (!engineSupportsArbitraryResolutions && framebufferSupported) {
return kFramebuffer;
}
return kScreen;
}
Math::Rect2d ResVmSdlGraphicsManager::computeGameRect(GameRenderTarget gameRenderTarget, uint gameWidth, uint gameHeight,
uint effectiveWidth, uint effectiveHeight) {
switch (gameRenderTarget) {
case kScreen:
// The game occupies the whole screen
return Math::Rect2d(Math::Vector2d(0, 0), Math::Vector2d(1, 1));
case kSubScreen:
// The game is centered on the screen
return Math::Rect2d(
Math::Vector2d((effectiveWidth - gameWidth) / 2, (effectiveHeight - gameHeight) / 2),
Math::Vector2d((effectiveWidth + gameWidth) / 2, (effectiveHeight + gameHeight) / 2)
);
case kFramebuffer:
if (_lockAspectRatio) {
// The game is scaled to fit the screen, keeping the same aspect ratio
float scale = MIN(effectiveHeight / float(gameHeight), effectiveWidth / float(gameWidth));
float scaledW = scale * (gameWidth / float(effectiveWidth));
float scaledH = scale * (gameHeight / float(effectiveHeight));
return Math::Rect2d(
Math::Vector2d(0.5 - (0.5 * scaledW), 0.5 - (0.5 * scaledH)),
Math::Vector2d(0.5 + (0.5 * scaledW), 0.5 + (0.5 * scaledH))
);
} else {
// The game occupies the whole screen
return Math::Rect2d(Math::Vector2d(0, 0), Math::Vector2d(1, 1));
}
default:
error("Unhandled game render target '%d'", gameRenderTarget);
}
}
bool ResVmSdlGraphicsManager::canUsePreferredResolution(GameRenderTarget gameRenderTarget,
bool engineSupportsArbitraryResolutions) {
switch (gameRenderTarget) {
case kScreen:
// If the game supports arbitrary resolutions, use the preferred mode as the game mode
return engineSupportsArbitraryResolutions;
case kSubScreen:
case kFramebuffer:
return true;
default:
error("Unhandled game render target '%d'", gameRenderTarget);
}
}
Common::Rect ResVmSdlGraphicsManager::getPreferredFullscreenResolution() { Common::Rect ResVmSdlGraphicsManager::getPreferredFullscreenResolution() {
// Default to the desktop resolution ... // Default to the desktop resolution ...
uint preferredWidth = _capabilities.desktopWidth; uint preferredWidth = _capabilities.desktopWidth;
@ -318,7 +251,7 @@ bool ResVmSdlGraphicsManager::notifyEvent(const Common::Event &event) {
void ResVmSdlGraphicsManager::notifyVideoExpose() { void ResVmSdlGraphicsManager::notifyVideoExpose() {
//ResidualVM specific: //ResidualVM specific:
updateScreen(); //updateScreen();
} }
bool ResVmSdlGraphicsManager::notifyMousePosition(Common::Point mouse) { bool ResVmSdlGraphicsManager::notifyMousePosition(Common::Point mouse) {

View file

@ -105,8 +105,6 @@ public:
virtual void clearFocusRectangle() override; virtual void clearFocusRectangle() override;
// GraphicsManager API - Overlay // GraphicsManager API - Overlay
virtual int16 getOverlayHeight() const override { return _overlayHeight; }
virtual int16 getOverlayWidth() const override { return _overlayWidth; }
virtual Graphics::PixelFormat getOverlayFormat() const override { return _overlayFormat; } virtual Graphics::PixelFormat getOverlayFormat() const override { return _overlayFormat; }
// GraphicsManager API - Mouse // GraphicsManager API - Mouse
@ -139,35 +137,12 @@ protected:
bool _overlayVisible; bool _overlayVisible;
Graphics::PixelFormat _overlayFormat; Graphics::PixelFormat _overlayFormat;
int _overlayWidth, _overlayHeight;
#ifdef USE_RGB_COLOR #ifdef USE_RGB_COLOR
Graphics::PixelFormat _screenFormat; Graphics::PixelFormat _screenFormat;
Common::List<Graphics::PixelFormat> _supportedFormats; Common::List<Graphics::PixelFormat> _supportedFormats;
#endif #endif
/**
* Places where the game can be drawn
*/
enum GameRenderTarget {
kScreen, /** The game is drawn directly on the screen */
kSubScreen, /** The game is drawn to a surface, which is centered on the screen */
kFramebuffer /** The game is drawn to a framebuffer, which is scaled to fit the screen */
};
/** Select the best draw target according to the specified parameters */
GameRenderTarget selectGameRenderTarget(bool fullscreen, bool accel3d,
bool engineSupportsArbitraryResolutions,
bool framebufferSupported,
bool lockAspectRatio);
/** Compute the size and position of the game rectangle in the screen */
Math::Rect2d computeGameRect(GameRenderTarget gameRenderTarget, uint gameWidth, uint gameHeight,
uint effectiveWidth, uint effectiveHeight);
/** Checks if the render target supports drawing at arbitrary resolutions */
bool canUsePreferredResolution(GameRenderTarget gameRenderTarget, bool engineSupportsArbitraryResolutions);
/** Obtain the user configured fullscreen resolution, or default to the desktop resolution */ /** Obtain the user configured fullscreen resolution, or default to the desktop resolution */
Common::Rect getPreferredFullscreenResolution(); Common::Rect getPreferredFullscreenResolution();
}; };

View file

@ -155,8 +155,6 @@ void SurfaceSdlGraphicsManager::createOrUpdateScreen() {
SDL_SetSurfaceBlendMode(_overlayscreen, SDL_BLENDMODE_NONE); SDL_SetSurfaceBlendMode(_overlayscreen, SDL_BLENDMODE_NONE);
#endif // SDL_VERSION_ATLEAST(2, 0, 0) #endif // SDL_VERSION_ATLEAST(2, 0, 0)
_overlayWidth = effectiveWidth;
_overlayHeight = effectiveHeight;
_screenFormat = _overlayFormat; _screenFormat = _overlayFormat;
_screenChangeCount++; _screenChangeCount++;
@ -269,7 +267,7 @@ void SurfaceSdlGraphicsManager::showOverlay() {
clearOverlay(); clearOverlay();
_eventSource->resetKeyboardEmulation(_overlayWidth - 1, _overlayHeight - 1); _eventSource->resetKeyboardEmulation(getOverlayWidth() - 1, getOverlayHeight() - 1);
} }
void SurfaceSdlGraphicsManager::hideOverlay() { void SurfaceSdlGraphicsManager::hideOverlay() {
@ -292,9 +290,9 @@ void SurfaceSdlGraphicsManager::grabOverlay(void *buf, int pitch) const {
byte *src = (byte *)_overlayscreen->pixels; byte *src = (byte *)_overlayscreen->pixels;
byte *dst = (byte *)buf; byte *dst = (byte *)buf;
int h = _overlayHeight; int h = _overlayscreen->h;
do { do {
memcpy(dst, src, _overlayWidth * _overlayscreen->format->BytesPerPixel); memcpy(dst, src, _overlayscreen->w * _overlayscreen->format->BytesPerPixel);
src += _overlayscreen->pitch; src += _overlayscreen->pitch;
dst += pitch; dst += pitch;
} while (--h); } while (--h);
@ -321,12 +319,12 @@ void SurfaceSdlGraphicsManager::copyRectToOverlay(const void *buf, int pitch, in
y = 0; y = 0;
} }
if (w > _overlayWidth - x) { if (w > _overlayscreen->w - x) {
w = _overlayWidth - x; w = _overlayscreen->w - x;
} }
if (h > _overlayHeight - y) { if (h > _overlayscreen->h - y) {
h = _overlayHeight - y; h = _overlayscreen->h - y;
} }
if (w <= 0 || h <= 0) if (w <= 0 || h <= 0)

View file

@ -54,6 +54,8 @@ public:
virtual void clearOverlay() override; virtual void clearOverlay() override;
virtual void grabOverlay(void *buf, int pitch) const override; virtual void grabOverlay(void *buf, int pitch) const override;
virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) override; virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) override;
virtual int16 getOverlayWidth() const override { return _overlayscreen->w; }
virtual int16 getOverlayHeight() const override { return _overlayscreen->h; }
/* Render the passed Surfaces besides the game texture. /* Render the passed Surfaces besides the game texture.
* This is used for widescreen support in the Grim engine. * This is used for widescreen support in the Grim engine.

View file

@ -48,7 +48,7 @@ public:
* *
* The format of the input data needs to match the format returned by * The format of the input data needs to match the format returned by
* getFormat. * getFormat.
* This does not immediatly updates the textures. * This does not immediately updates the textures.
* *
* @param x X coordinate of upper left corner to copy data to. * @param x X coordinate of upper left corner to copy data to.
* @param y Y coordinate of upper left corner to copy data to. * @param y Y coordinate of upper left corner to copy data to.
@ -98,6 +98,15 @@ public:
*/ */
const Graphics::Surface *getBackingSurface() const; const Graphics::Surface *getBackingSurface() const;
/**
* Get the dimensions in pixels of the surface
*
* This does not include the unused area in the textures at the edges
* of the grid.
*/
uint16 getWidth() const { return _backingSurface.w; }
uint16 getHeight() const { return _backingSurface.h; }
private: private:
static const uint maxTextureSize = 256; static const uint maxTextureSize = 256;

View file

@ -330,7 +330,7 @@ void OptionsDialog::build() {
_filteringCheckbox->setVisible(false); _filteringCheckbox->setVisible(false);
// Aspect ratio setting // Aspect ratio setting
if (_guioptions.contains(GUIO_NOASPECT) || !_fullscreenCheckbox->getState()) { // ResidualVM specific change if (_guioptions.contains(GUIO_NOASPECT)) { // ResidualVM specific change
_aspectCheckbox->setState(true); // ResidualVM specific change _aspectCheckbox->setState(true); // ResidualVM specific change
_aspectCheckbox->setEnabled(false); _aspectCheckbox->setEnabled(false);
} else { } else {
@ -870,11 +870,6 @@ void OptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data
case kGraphicsTabContainerReflowCmd: case kGraphicsTabContainerReflowCmd:
setupGraphicsTab(); setupGraphicsTab();
break; break;
// ResidualVM specific
case kFullscreenToggled:
_aspectCheckbox->setEnabled(_fullscreenCheckbox->getState());
g_gui.scheduleTopDialogRedraw();
break;
case kApplyCmd: case kApplyCmd:
apply(); apply();
break; break;
@ -905,7 +900,7 @@ void OptionsDialog::setGraphicSettingsState(bool enabled) {
#ifndef GUI_ENABLE_KEYSDIALOG #ifndef GUI_ENABLE_KEYSDIALOG
#ifndef GUI_ONLY_FULLSCREEN #ifndef GUI_ONLY_FULLSCREEN
_fullscreenCheckbox->setEnabled(enabled); _fullscreenCheckbox->setEnabled(enabled);
if (_guioptions.contains(GUIO_NOASPECT) || !_fullscreenCheckbox->getState()) if (_guioptions.contains(GUIO_NOASPECT))
#endif // !GUI_ONLY_FULLSCREEN #endif // !GUI_ONLY_FULLSCREEN
_aspectCheckbox->setEnabled(false); _aspectCheckbox->setEnabled(false);
else else