BACKENDS: Refactor OpenGL & SDL graphics backends

This patch refactors the OpenGL and SDL graphics backends,
primarily to unify window scaling and mouse handling, and to
fix coordinate mapping between the ScummVM window and the
virtual game screen when they have different aspect ratios.

Unified code for these two backends has been moved to a new
header-only WindowedGraphicsManager class, so named because it
contains code for managing graphics managers that interact with
a windowing system and render virtual screens within a larger
physical content window.

The biggest behavioral change here is with the coordinate
system mapping:

Previously, mouse offsets were converted by mapping the whole
space within the window as input to the virtual game screen
without maintaining aspect ratio. This was done to prevent
'stickiness' when the mouse cursor was within the window but
outside of the virtual game screen, but it caused noticeable
distortion of mouse movement speed on the axis with blank
space.

Instead of introducing mouse speed distortion to prevent
stickiness, this patch changes coordinate transformation to
show the system cursor when the mouse moves outside of the virtual
game screen when mouse grab is off, or by holding the mouse inside
the virtual game screen (instead of the entire window) when mouse
grab is on.

This patch also improves some other properties of the
GraphicsManager/PaletteManager interfaces:

* Nullipotent operations (getWidth, getHeight, etc.) of the
  PaletteManager/GraphicsManager interfaces are now const
* Methods marked `virtual` but not inherited by any subclass have
  been de-virtualized
* Extra unnecessary calculations of hardware height in
  SurfaceSdlGraphicsManager have been removed
* Methods have been renamed where appropriate for clarity
  (setWindowSize -> handleResize, etc.)
* C++11 support improved with `override` specifier added on
  overridden virtual methods in subclasses (primarily to avoid
  myself accidentally creating new methods in the subclasses
  by changing types/names during refactoring)

Additional refactoring can and should be done at some point to
continue to deduplicate code between the OpenGL and SDL backends.
Since the primary goal here was to improve the coordinate mapping,
full refactoring of these backends was not completed here.
This commit is contained in:
Colin Snover 2017-07-19 19:15:12 -05:00
parent 0ad03e492a
commit de2bbe3b97
15 changed files with 820 additions and 851 deletions

View File

@ -174,8 +174,7 @@ void SdlEventSource::processMouseEvent(Common::Event &event, int x, int y) {
event.mouse.y = y;
if (_graphicsManager) {
_graphicsManager->notifyMousePos(Common::Point(x, y));
_graphicsManager->transformMouseCoordinates(event.mouse);
_graphicsManager->notifyMousePosition(event.mouse);
}
}

View File

@ -38,9 +38,9 @@ class GraphicsManager : public PaletteManager {
public:
virtual ~GraphicsManager() {}
virtual bool hasFeature(OSystem::Feature f) = 0;
virtual bool hasFeature(OSystem::Feature f) const = 0;
virtual void setFeatureState(OSystem::Feature f, bool enable) = 0;
virtual bool getFeatureState(OSystem::Feature f) = 0;
virtual bool getFeatureState(OSystem::Feature f) const = 0;
virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const = 0;
virtual int getDefaultGraphicsMode() const = 0;
@ -65,10 +65,10 @@ public:
virtual void beginGFXTransaction() = 0;
virtual OSystem::TransactionError endGFXTransaction() = 0;
virtual int16 getHeight() = 0;
virtual int16 getWidth() = 0;
virtual int16 getHeight() const = 0;
virtual int16 getWidth() const = 0;
virtual void setPalette(const byte *colors, uint start, uint num) = 0;
virtual void grabPalette(byte *colors, uint start, uint num) = 0;
virtual void grabPalette(byte *colors, uint start, uint num) const = 0;
virtual void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) = 0;
virtual Graphics::Surface *lockScreen() = 0;
virtual void unlockScreen() = 0;
@ -82,10 +82,10 @@ public:
virtual void hideOverlay() = 0;
virtual Graphics::PixelFormat getOverlayFormat() const = 0;
virtual void clearOverlay() = 0;
virtual void grabOverlay(void *buf, int pitch) = 0;
virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h)= 0;
virtual int16 getOverlayHeight() = 0;
virtual int16 getOverlayWidth() = 0;
virtual void grabOverlay(void *buf, int pitch) const = 0;
virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) = 0;
virtual int16 getOverlayHeight() const = 0;
virtual int16 getOverlayWidth() const = 0;
virtual bool showMouse(bool visible) = 0;
virtual void warpMouse(int x, int y) = 0;

View File

@ -54,8 +54,8 @@ public:
void beginGFXTransaction() {}
OSystem::TransactionError endGFXTransaction() { return OSystem::kTransactionSuccess; }
int16 getHeight() { return 0; }
int16 getWidth() { return 0; }
int16 getHeight() const { return 0; }
int16 getWidth() const { return 0; }
void setPalette(const byte *colors, uint start, uint num) {}
void grabPalette(byte *colors, uint start, uint num) {}
void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) {}

View File

@ -53,14 +53,12 @@ namespace OpenGL {
OpenGLGraphicsManager::OpenGLGraphicsManager()
: _currentState(), _oldState(), _transactionMode(kTransactionNone), _screenChangeID(1 << (sizeof(int) * 8 - 2)),
_pipeline(nullptr),
_outputScreenWidth(0), _outputScreenHeight(0), _displayX(0), _displayY(0),
_displayWidth(0), _displayHeight(0), _defaultFormat(), _defaultFormatAlpha(),
_defaultFormat(), _defaultFormatAlpha(),
_gameScreen(nullptr), _gameScreenShakeOffset(0), _overlay(nullptr),
_overlayVisible(false), _cursor(nullptr),
_cursorX(0), _cursorY(0), _cursorDisplayX(0),_cursorDisplayY(0), _cursorHotspotX(0), _cursorHotspotY(0),
_cursor(nullptr),
_cursorHotspotX(0), _cursorHotspotY(0),
_cursorHotspotXScaled(0), _cursorHotspotYScaled(0), _cursorWidthScaled(0), _cursorHeightScaled(0),
_cursorKeyColor(0), _cursorVisible(false), _cursorDontScale(false), _cursorPaletteEnabled(false),
_forceRedraw(false)
_cursorKeyColor(0), _cursorVisible(false), _cursorDontScale(false), _cursorPaletteEnabled(false)
#ifdef USE_OSD
, _osdMessageChangeRequest(false), _osdMessageAlpha(0), _osdMessageFadeStartTime(0), _osdMessageSurface(nullptr),
_osdIconSurface(nullptr)
@ -83,7 +81,7 @@ OpenGLGraphicsManager::~OpenGLGraphicsManager() {
#endif
}
bool OpenGLGraphicsManager::hasFeature(OSystem::Feature f) {
bool OpenGLGraphicsManager::hasFeature(OSystem::Feature f) const {
switch (f) {
case OSystem::kFeatureAspectRatioCorrection:
case OSystem::kFeatureCursorPalette:
@ -129,7 +127,7 @@ void OpenGLGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
}
}
bool OpenGLGraphicsManager::getFeatureState(OSystem::Feature f) {
bool OpenGLGraphicsManager::getFeatureState(OSystem::Feature f) const {
switch (f) {
case OSystem::kFeatureAspectRatioCorrection:
return _currentState.aspectRatioCorrection;
@ -220,10 +218,9 @@ OSystem::TransactionError OpenGLGraphicsManager::endGFXTransaction() {
#endif
do {
uint requestedWidth = _currentState.gameWidth;
uint requestedHeight = _currentState.gameHeight;
const uint desiredAspect = getDesiredGameScreenAspect();
requestedHeight = intToFrac(requestedWidth) / desiredAspect;
const uint desiredAspect = getDesiredGameAspectRatio();
const uint requestedWidth = _currentState.gameWidth;
const uint requestedHeight = intToFrac(requestedWidth) / desiredAspect;
if (!loadVideoMode(requestedWidth, requestedHeight,
#ifdef USE_RGB_COLOR
@ -317,7 +314,7 @@ OSystem::TransactionError OpenGLGraphicsManager::endGFXTransaction() {
// Update our display area and cursor scaling. This makes sure we pick up
// aspect ratio correction and game screen changes correctly.
recalculateDisplayArea();
recalculateDisplayAreas();
recalculateCursorScaling();
// Something changed, so update the screen change ID.
@ -347,11 +344,11 @@ void OpenGLGraphicsManager::initSize(uint width, uint height, const Graphics::Pi
_currentState.gameHeight = height;
}
int16 OpenGLGraphicsManager::getWidth() {
int16 OpenGLGraphicsManager::getWidth() const {
return _currentState.gameWidth;
}
int16 OpenGLGraphicsManager::getHeight() {
int16 OpenGLGraphicsManager::getHeight() const {
return _currentState.gameHeight;
}
@ -392,6 +389,7 @@ void OpenGLGraphicsManager::updateScreen() {
// We only update the screen when there actually have been any changes.
if ( !_forceRedraw
&& !_cursorNeedsRedraw
&& !_gameScreen->isDirty()
&& !(_overlayVisible && _overlay->isDirty())
&& !(_cursorVisible && _cursor && _cursor->isDirty())
@ -401,7 +399,6 @@ void OpenGLGraphicsManager::updateScreen() {
) {
return;
}
_forceRedraw = false;
// Update changes to textures.
_gameScreen->updateGLTexture();
@ -420,14 +417,14 @@ void OpenGLGraphicsManager::updateScreen() {
_backBuffer.enableScissorTest(true);
}
const GLfloat shakeOffset = _gameScreenShakeOffset * (GLfloat)_displayHeight / _gameScreen->getHeight();
const GLfloat shakeOffset = _gameScreenShakeOffset * (GLfloat)_gameDrawRect.height() / _gameScreen->getHeight();
// First step: Draw the (virtual) game screen.
g_context.getActivePipeline()->drawTexture(_gameScreen->getGLTexture(), _displayX, _displayY + shakeOffset, _displayWidth, _displayHeight);
g_context.getActivePipeline()->drawTexture(_gameScreen->getGLTexture(), _gameDrawRect.left, _gameDrawRect.top + shakeOffset, _gameDrawRect.width(), _gameDrawRect.height());
// Second step: Draw the overlay if visible.
if (_overlayVisible) {
g_context.getActivePipeline()->drawTexture(_overlay->getGLTexture(), 0, 0, _outputScreenWidth, _outputScreenHeight);
g_context.getActivePipeline()->drawTexture(_overlay->getGLTexture(), 0, 0, _overlayDrawRect.width(), _overlayDrawRect.height());
}
// Third step: Draw the cursor if visible.
@ -437,8 +434,8 @@ void OpenGLGraphicsManager::updateScreen() {
const GLfloat cursorOffset = _overlayVisible ? 0 : shakeOffset;
g_context.getActivePipeline()->drawTexture(_cursor->getGLTexture(),
_cursorDisplayX - _cursorHotspotXScaled,
_cursorDisplayY - _cursorHotspotYScaled + cursorOffset,
_cursorX - _cursorHotspotXScaled,
_cursorY - _cursorHotspotYScaled + cursorOffset,
_cursorWidthScaled, _cursorHeightScaled);
}
@ -464,8 +461,8 @@ void OpenGLGraphicsManager::updateScreen() {
// Set the OSD transparency.
g_context.getActivePipeline()->setColor(1.0f, 1.0f, 1.0f, _osdMessageAlpha / 100.0f);
int dstX = (_outputScreenWidth - _osdMessageSurface->getWidth()) / 2;
int dstY = (_outputScreenHeight - _osdMessageSurface->getHeight()) / 2;
int dstX = (_windowWidth - _osdMessageSurface->getWidth()) / 2;
int dstY = (_windowHeight - _osdMessageSurface->getHeight()) / 2;
// Draw the OSD texture.
g_context.getActivePipeline()->drawTexture(_osdMessageSurface->getGLTexture(),
@ -481,7 +478,7 @@ void OpenGLGraphicsManager::updateScreen() {
}
if (_osdIconSurface) {
int dstX = _outputScreenWidth - _osdIconSurface->getWidth() - kOSDIconRightMargin;
int dstX = _windowWidth - _osdIconSurface->getWidth() - kOSDIconRightMargin;
int dstY = kOSDIconTopMargin;
// Draw the OSD icon texture.
@ -490,6 +487,8 @@ void OpenGLGraphicsManager::updateScreen() {
}
#endif
_cursorNeedsRedraw = false;
_forceRedraw = false;
refreshScreen();
}
@ -507,7 +506,7 @@ void OpenGLGraphicsManager::setFocusRectangle(const Common::Rect& rect) {
void OpenGLGraphicsManager::clearFocusRectangle() {
}
int16 OpenGLGraphicsManager::getOverlayWidth() {
int16 OpenGLGraphicsManager::getOverlayWidth() const {
if (_overlay) {
return _overlay->getWidth();
} else {
@ -515,7 +514,7 @@ int16 OpenGLGraphicsManager::getOverlayWidth() {
}
}
int16 OpenGLGraphicsManager::getOverlayHeight() {
int16 OpenGLGraphicsManager::getOverlayHeight() const {
if (_overlay) {
return _overlay->getHeight();
} else {
@ -523,22 +522,6 @@ int16 OpenGLGraphicsManager::getOverlayHeight() {
}
}
void OpenGLGraphicsManager::showOverlay() {
_overlayVisible = true;
_forceRedraw = true;
// Update cursor position.
setMousePosition(_cursorX, _cursorY);
}
void OpenGLGraphicsManager::hideOverlay() {
_overlayVisible = false;
_forceRedraw = true;
// Update cursor position.
setMousePosition(_cursorX, _cursorY);
}
Graphics::PixelFormat OpenGLGraphicsManager::getOverlayFormat() const {
return _overlay->getFormat();
}
@ -551,7 +534,7 @@ void OpenGLGraphicsManager::clearOverlay() {
_overlay->fill(0);
}
void OpenGLGraphicsManager::grabOverlay(void *buf, int pitch) {
void OpenGLGraphicsManager::grabOverlay(void *buf, int pitch) const {
const Graphics::Surface *overlayData = _overlay->getSurface();
const byte *src = (const byte *)overlayData->getPixels();
@ -568,7 +551,7 @@ bool OpenGLGraphicsManager::showMouse(bool visible) {
// In case the mouse cursor visibility changed we need to redraw the whole
// screen even when nothing else changed.
if (_cursorVisible != visible) {
_forceRedraw = true;
_cursorNeedsRedraw = true;
}
bool last = _cursorVisible;
@ -576,43 +559,6 @@ bool OpenGLGraphicsManager::showMouse(bool visible) {
return last;
}
void OpenGLGraphicsManager::warpMouse(int x, int y) {
int16 currentX = _cursorX;
int16 currentY = _cursorY;
adjustMousePosition(currentX, currentY);
// Check whether the (virtual) coordinate actually changed. If not, then
// simply do nothing. This avoids ugly "jittering" due to the actual
// output screen having a bigger resolution than the virtual coordinates.
if (currentX == x && currentY == y) {
return;
}
// Scale the virtual coordinates into actual physical coordinates.
if (_overlayVisible) {
if (!_overlay) {
return;
}
// It might be confusing that we actually have to handle something
// here when the overlay is visible. This is because for very small
// resolutions we have a minimal overlay size and have to adjust
// for that.
x = (x * _outputScreenWidth) / _overlay->getWidth();
y = (y * _outputScreenHeight) / _overlay->getHeight();
} else {
if (!_gameScreen) {
return;
}
x = (x * _outputScreenWidth) / _gameScreen->getWidth();
y = (y * _outputScreenHeight) / _gameScreen->getHeight();
}
setMousePosition(x, y);
setInternalMousePosition(x, y);
}
namespace {
template<typename DstPixel, typename SrcPixel>
void applyColorKey(DstPixel *dst, const SrcPixel *src, uint w, uint h, uint dstPitch, uint srcPitch, SrcPixel keyColor, DstPixel alphaMask) {
@ -720,7 +666,6 @@ void OpenGLGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int
updateCursorPalette();
}
// Update the scaling.
recalculateCursorScaling();
}
@ -765,8 +710,8 @@ void OpenGLGraphicsManager::osdMessageUpdateSurface() {
}
// Clip the rect
width = MIN<uint>(width, _displayWidth);
height = MIN<uint>(height, _displayHeight);
width = MIN<uint>(width, _gameDrawRect.width());
height = MIN<uint>(height, _gameDrawRect.height());
delete _osdMessageSurface;
_osdMessageSurface = nullptr;
@ -849,16 +794,13 @@ void OpenGLGraphicsManager::setPalette(const byte *colors, uint start, uint num)
updateCursorPalette();
}
void OpenGLGraphicsManager::grabPalette(byte *colors, uint start, uint num) {
void OpenGLGraphicsManager::grabPalette(byte *colors, uint start, uint num) const {
assert(_gameScreen->hasPalette());
memcpy(colors, _gamePalette + start * 3, num * 3);
}
void OpenGLGraphicsManager::setActualScreenSize(uint width, uint height) {
_outputScreenWidth = width;
_outputScreenHeight = height;
void OpenGLGraphicsManager::handleResizeImpl(const int width, const int height) {
// Setup backbuffer size.
_backBuffer.setDimensions(width, height);
@ -873,7 +815,7 @@ void OpenGLGraphicsManager::setActualScreenSize(uint width, uint height) {
// anyway. Thus, it should not be a real issue for modern hardware.
if ( overlayWidth > (uint)g_context.maxTextureSize
|| overlayHeight > (uint)g_context.maxTextureSize) {
const frac_t outputAspect = intToFrac(_outputScreenWidth) / _outputScreenHeight;
const frac_t outputAspect = intToFrac(_windowWidth) / _windowHeight;
if (outputAspect > (frac_t)FRAC_ONE) {
overlayWidth = g_context.maxTextureSize;
@ -906,7 +848,7 @@ void OpenGLGraphicsManager::setActualScreenSize(uint width, uint height) {
_overlay->fill(0);
// Re-setup the scaling for the screen and cursor
recalculateDisplayArea();
recalculateDisplayAreas();
recalculateCursorScaling();
// Something changed, so update the screen change ID.
@ -960,8 +902,8 @@ void OpenGLGraphicsManager::notifyContextCreate(const Graphics::PixelFormat &def
GL_CALL(glPixelStorei(GL_PACK_ALIGNMENT, 4));
// Refresh the output screen dimensions if some are set up.
if (_outputScreenWidth != 0 && _outputScreenHeight != 0) {
setActualScreenSize(_outputScreenWidth, _outputScreenHeight);
if (_windowWidth != 0 && _windowHeight != 0) {
handleResize(_windowWidth, _windowHeight);
}
// TODO: Should we try to convert textures into one of those formats if
@ -1031,46 +973,6 @@ void OpenGLGraphicsManager::notifyContextDestroy() {
g_context.reset();
}
void OpenGLGraphicsManager::adjustMousePosition(int16 &x, int16 &y) {
if (_overlayVisible) {
// It might be confusing that we actually have to handle something
// here when the overlay is visible. This is because for very small
// resolutions we have a minimal overlay size and have to adjust
// for that.
// This can also happen when the overlay is smaller than the actual
// display size because of texture size limitations.
if (_overlay) {
x = (x * _overlay->getWidth()) / _outputScreenWidth;
y = (y * _overlay->getHeight()) / _outputScreenHeight;
}
} else if (_gameScreen) {
const int16 width = _gameScreen->getWidth();
const int16 height = _gameScreen->getHeight();
x = (x * width) / (int)_outputScreenWidth;
y = (y * height) / (int)_outputScreenHeight;
}
}
void OpenGLGraphicsManager::setMousePosition(int x, int y) {
// Whenever the mouse position changed we force a screen redraw to reflect
// changes properly.
if (_cursorX != x || _cursorY != y) {
_forceRedraw = true;
}
_cursorX = x;
_cursorY = y;
if (_overlayVisible) {
_cursorDisplayX = x;
_cursorDisplayY = y;
} else {
_cursorDisplayX = _displayX + (x * _displayWidth) / _outputScreenWidth;
_cursorDisplayY = _displayY + (y * _displayHeight) / _outputScreenHeight;
}
}
Surface *OpenGLGraphicsManager::createSurface(const Graphics::PixelFormat &format, bool wantAlpha) {
GLenum glIntFormat, glFormat, glType;
if (format.bytesPerPixel == 1) {
@ -1191,51 +1093,34 @@ bool OpenGLGraphicsManager::getGLPixelFormat(const Graphics::PixelFormat &pixelF
}
}
frac_t OpenGLGraphicsManager::getDesiredGameScreenAspect() const {
const uint width = _currentState.gameWidth;
const uint height = _currentState.gameHeight;
bool OpenGLGraphicsManager::gameNeedsAspectRatioCorrection() const {
if (_currentState.aspectRatioCorrection) {
const uint width = getWidth();
const uint height = getHeight();
// In case we enable aspect ratio correction we force a 4/3 ratio.
// But just for 320x200 and 640x400 games, since other games do not need
// this.
if ((width == 320 && height == 200) || (width == 640 && height == 400)) {
return intToFrac(4) / 3;
}
return (width == 320 && height == 200) || (width == 640 && height == 400);
}
return intToFrac(width) / height;
return false;
}
void OpenGLGraphicsManager::recalculateDisplayArea() {
if (!_gameScreen || _outputScreenHeight == 0) {
void OpenGLGraphicsManager::recalculateDisplayAreas() {
if (!_gameScreen) {
return;
}
const frac_t outputAspect = intToFrac(_outputScreenWidth) / _outputScreenHeight;
const frac_t desiredAspect = getDesiredGameScreenAspect();
_displayWidth = _outputScreenWidth;
_displayHeight = _outputScreenHeight;
// Adjust one dimension for mantaining the aspect ratio.
if (outputAspect < desiredAspect) {
_displayHeight = intToFrac(_displayWidth) / desiredAspect;
} else if (outputAspect > desiredAspect) {
_displayWidth = fracToInt(_displayHeight * desiredAspect);
}
// We center the screen in the middle for now.
_displayX = (_outputScreenWidth - _displayWidth ) / 2;
_displayY = (_outputScreenHeight - _displayHeight) / 2;
WindowedGraphicsManager::recalculateDisplayAreas();
// Setup drawing limitation for game graphics.
// This involves some trickery because OpenGL's viewport coordinate system
// is upside down compared to ours.
_backBuffer.setScissorBox(_displayX,
_outputScreenHeight - _displayHeight - _displayY,
_displayWidth,
_displayHeight);
_backBuffer.setScissorBox(_gameDrawRect.left,
_windowHeight - _gameDrawRect.height() - _gameDrawRect.top,
_gameDrawRect.width(),
_gameDrawRect.height());
// Update the cursor position to adjust for new display area.
setMousePosition(_cursorX, _cursorY);
@ -1272,8 +1157,8 @@ void OpenGLGraphicsManager::recalculateCursorScaling() {
// In case scaling is actually enabled we will scale the cursor according
// to the game screen.
if (!_cursorDontScale) {
const frac_t screenScaleFactorX = intToFrac(_displayWidth) / _gameScreen->getWidth();
const frac_t screenScaleFactorY = intToFrac(_displayHeight) / _gameScreen->getHeight();
const frac_t screenScaleFactorX = intToFrac(_gameDrawRect.width()) / _gameScreen->getWidth();
const frac_t screenScaleFactorY = intToFrac(_gameDrawRect.height()) / _gameScreen->getHeight();
_cursorHotspotXScaled = fracToInt(_cursorHotspotXScaled * screenScaleFactorX);
_cursorWidthScaled = fracToInt(_cursorWidthScaled * screenScaleFactorX);
@ -1284,14 +1169,14 @@ void OpenGLGraphicsManager::recalculateCursorScaling() {
}
#ifdef USE_OSD
const Graphics::Font *OpenGLGraphicsManager::getFontOSD() {
const Graphics::Font *OpenGLGraphicsManager::getFontOSD() const {
return FontMan.getFontByUsage(Graphics::FontManager::kLocalizedFont);
}
#endif
bool OpenGLGraphicsManager::saveScreenshot(const Common::String &filename) const {
const uint width = _outputScreenWidth;
const uint height = _outputScreenHeight;
const uint width = _windowWidth;
const uint height = _windowHeight;
// A line of a BMP image must have a size divisible by 4.
// We calculate the padding bytes needed here.

View File

@ -25,7 +25,7 @@
#include "backends/graphics/opengl/opengl-sys.h"
#include "backends/graphics/opengl/framebuffer.h"
#include "backends/graphics/graphics.h"
#include "backends/graphics/windowed.h"
#include "common/frac.h"
#include "common/mutex.h"
@ -53,74 +53,70 @@ enum {
GFX_OPENGL = 0
};
class OpenGLGraphicsManager : virtual public GraphicsManager {
class OpenGLGraphicsManager : virtual public WindowedGraphicsManager {
public:
OpenGLGraphicsManager();
virtual ~OpenGLGraphicsManager();
// GraphicsManager API
virtual bool hasFeature(OSystem::Feature f);
virtual void setFeatureState(OSystem::Feature f, bool enable);
virtual bool getFeatureState(OSystem::Feature f);
virtual bool hasFeature(OSystem::Feature f) const override;
virtual void setFeatureState(OSystem::Feature f, bool enable) override;
virtual bool getFeatureState(OSystem::Feature f) const override;
virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const;
virtual int getDefaultGraphicsMode() const;
virtual bool setGraphicsMode(int mode);
virtual int getGraphicsMode() const;
virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const override;
virtual int getDefaultGraphicsMode() const override;
virtual bool setGraphicsMode(int mode) override;
virtual int getGraphicsMode() const override;
virtual void resetGraphicsScale() {}
virtual void resetGraphicsScale() override {}
#ifdef USE_RGB_COLOR
virtual Graphics::PixelFormat getScreenFormat() const;
virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const = 0;
virtual Graphics::PixelFormat getScreenFormat() const override;
virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const override = 0;
#endif
virtual void beginGFXTransaction();
virtual OSystem::TransactionError endGFXTransaction();
virtual void beginGFXTransaction() override;
virtual OSystem::TransactionError endGFXTransaction() override;
virtual int getScreenChangeID() const;
virtual int getScreenChangeID() const override;
virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format);
virtual void initSize(uint width, uint height, const Graphics::PixelFormat *format) override;
virtual int16 getWidth();
virtual int16 getHeight();
virtual int16 getWidth() const override;
virtual int16 getHeight() const override;
virtual void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h);
virtual void fillScreen(uint32 col);
virtual void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) override;
virtual void fillScreen(uint32 col) override;
virtual void setShakePos(int shakeOffset);
virtual void setShakePos(int shakeOffset) override;
virtual void updateScreen();
virtual void updateScreen() override;
virtual Graphics::Surface *lockScreen();
virtual void unlockScreen();
virtual Graphics::Surface *lockScreen() override;
virtual void unlockScreen() override;
virtual void setFocusRectangle(const Common::Rect& rect);
virtual void clearFocusRectangle();
virtual void setFocusRectangle(const Common::Rect& rect) override;
virtual void clearFocusRectangle() override;
virtual int16 getOverlayWidth();
virtual int16 getOverlayHeight();
virtual int16 getOverlayWidth() const override;
virtual int16 getOverlayHeight() const override;
virtual void showOverlay();
virtual void hideOverlay();
virtual Graphics::PixelFormat getOverlayFormat() const override;
virtual Graphics::PixelFormat getOverlayFormat() const;
virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) override;
virtual void clearOverlay() 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);
virtual void clearOverlay();
virtual void grabOverlay(void *buf, int pitch);
virtual bool showMouse(bool visible) override;
virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) override;
virtual void setCursorPalette(const byte *colors, uint start, uint num) override;
virtual bool showMouse(bool visible);
virtual void warpMouse(int x, int y);
virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format);
virtual void setCursorPalette(const byte *colors, uint start, uint num);
virtual void displayMessageOnOSD(const char *msg);
virtual void displayActivityIconOnOSD(const Graphics::Surface *icon);
virtual void displayMessageOnOSD(const char *msg) override;
virtual void displayActivityIconOnOSD(const Graphics::Surface *icon) override;
// PaletteManager interface
virtual void setPalette(const byte *colors, uint start, uint num);
virtual void grabPalette(byte *colors, uint start, uint num);
virtual void setPalette(const byte *colors, uint start, uint num) override;
virtual void grabPalette(byte *colors, uint start, uint num) const override;
protected:
/**
@ -128,15 +124,6 @@ protected:
*/
bool isGLESContext() const { return g_context.type == kContextGLES || g_context.type == kContextGLES2; }
/**
* Set up the actual screen size available for the OpenGL code to do any
* drawing.
*
* @param width The width of the screen.
* @param height The height of the screen.
*/
void setActualScreenSize(uint width, uint height);
/**
* Sets the OpenGL (ES) type the graphics manager shall work with.
*
@ -166,33 +153,6 @@ protected:
*/
void notifyContextDestroy();
/**
* Adjust the physical mouse coordinates according to the currently visible screen.
*/
void adjustMousePosition(int16 &x, int16 &y);
/**
* Set up the mouse position for graphics output.
*
* @param x X coordinate in physical coordinates.
* @param y Y coordinate in physical coordinates.
*/
void setMousePosition(int x, int y);
/**
* Query the mouse position in physical coordinates.
*/
void getMousePosition(int16 &x, int16 &y) const { x = _cursorX; y = _cursorY; }
/**
* Set up the mouse position for the (event) system.
*
* @param x X coordinate in physical coordinates.
* @param y Y coordinate in physical coordinates.
*/
virtual void setInternalMousePosition(int x, int y) = 0;
private:
/**
* Create a surface with the specified pixel format.
*
@ -292,8 +252,7 @@ protected:
virtual void refreshScreen() = 0;
/**
* Save a screenshot of the full display as BMP to the given file. This
* uses Common::DumpFile for writing the screenshot.
* Saves a screenshot of the entire window, excluding window decorations.
*
* @param filename The output filename.
* @return true on success, false otherwise
@ -334,7 +293,6 @@ protected:
*/
virtual void *getProcAddress(const char *name) const = 0;
private:
/**
* Try to determine the internal parameters for a given pixel format.
*
@ -342,49 +300,9 @@ private:
*/
bool getGLPixelFormat(const Graphics::PixelFormat &pixelFormat, GLenum &glIntFormat, GLenum &glFormat, GLenum &glType) const;
//
// Actual hardware screen
//
/**
* The width of the physical output.
*/
uint _outputScreenWidth;
/**
* The height of the physical output.
*/
uint _outputScreenHeight;
/**
* @return The desired aspect of the game screen.
*/
frac_t getDesiredGameScreenAspect() const;
/**
* Recalculates the area used to display the game screen.
*/
void recalculateDisplayArea();
/**
* The X coordinate of the game screen.
*/
uint _displayX;
/**
* The Y coordinate of the game screen.
*/
uint _displayY;
/**
* The width of the game screen in physical coordinates.
*/
uint _displayWidth;
/**
* The height of the game screen in physical coordinates.
*/
uint _displayHeight;
virtual bool gameNeedsAspectRatioCorrection() const override;
virtual void recalculateDisplayAreas() override;
virtual void handleResizeImpl(const int width, const int height) override;
/**
* The default pixel format of the backend.
@ -396,12 +314,8 @@ private:
*/
Graphics::PixelFormat _defaultFormatAlpha;
//
// Game screen
//
/**
* The virtual game screen.
* The rendering surface for the virtual game screen.
*/
Surface *_gameScreen;
@ -420,15 +334,10 @@ private:
//
/**
* The overlay screen.
* The rendering surface for the overlay.
*/
Surface *_overlay;
/**
* Whether the overlay is visible or not.
*/
bool _overlayVisible;
//
// Cursor
//
@ -439,37 +348,17 @@ private:
void updateCursorPalette();
/**
* The cursor image.
* The rendering surface for the mouse cursor.
*/
Surface *_cursor;
/**
* X coordinate of the cursor in physical coordinates.
*/
int _cursorX;
/**
* Y coordinate of the cursor in physical coordinates.
*/
int _cursorY;
/**
* X coordinate used for drawing the cursor.
*/
int _cursorDisplayX;
/**
* Y coordinate used for drawing the cursor.
*/
int _cursorDisplayY;
/**
* The X offset for the cursor hotspot in unscaled coordinates.
* The X offset for the cursor hotspot in unscaled game coordinates.
*/
int _cursorHotspotX;
/**
* The Y offset for the cursor hotspot in unscaled coordinates.
* The Y offset for the cursor hotspot in unscaled game coordinates.
*/
int _cursorHotspotY;
@ -480,22 +369,24 @@ private:
void recalculateCursorScaling();
/**
* The X offset for the cursor hotspot in scaled coordinates.
* The X offset for the cursor hotspot in scaled game display area
* coordinates.
*/
int _cursorHotspotXScaled;
/**
* The Y offset for the cursor hotspot in scaled coordinates.
* The Y offset for the cursor hotspot in scaled game display area
* coordinates.
*/
int _cursorHotspotYScaled;
/**
* The width of the cursor scaled coordinates.
* The width of the cursor in scaled game display area coordinates.
*/
uint _cursorWidthScaled;
/**
* The height of the cursor scaled coordinates.
* The height of the cursor in scaled game display area coordinates.
*/
uint _cursorHeightScaled;
@ -524,15 +415,6 @@ private:
*/
byte _cursorPalette[3 * 256];
//
// Misc
//
/**
* Whether the screen contents shall be forced to redrawn.
*/
bool _forceRedraw;
#ifdef USE_OSD
//
// OSD
@ -541,7 +423,7 @@ protected:
/**
* Returns the font used for on screen display
*/
virtual const Graphics::Font *getFontOSD();
virtual const Graphics::Font *getFontOSD() const;
private:
/**

View File

@ -21,8 +21,10 @@
*/
#include "backends/graphics/openglsdl/openglsdl-graphics.h"
#include "backends/graphics/opengl/texture.h"
#include "backends/events/sdl/sdl-events.h"
#include "backends/platform/sdl/sdl.h"
#include "graphics/scaler/aspect.h"
#include "common/textconsole.h"
#include "common/config-manager.h"
@ -35,7 +37,7 @@ OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(uint desktopWidth, uint deskt
#if SDL_VERSION_ATLEAST(2, 0, 0)
_glContext(),
#else
_lastVideoModeLoad(0), _hwScreen(nullptr),
_lastVideoModeLoad(0),
#endif
_graphicsScale(2), _ignoreLoadVideoMode(false), _gotResize(false), _wantsFullScreen(false), _ignoreResizeEvents(0),
_desiredFullscreenWidth(0), _desiredFullscreenHeight(0) {
@ -52,14 +54,16 @@ OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(uint desktopWidth, uint deskt
// Context version 1.4 is choosen arbitrarily based on what most shader
// extensions were written against.
#define DEFAULT_GL_MAJOR 1
#define DEFAULT_GL_MINOR 4
enum {
DEFAULT_GL_MAJOR = 1,
DEFAULT_GL_MINOR = 4,
#define DEFAULT_GLES_MAJOR 1
#define DEFAULT_GLES_MINOR 1
DEFAULT_GLES_MAJOR = 1,
DEFAULT_GLES_MINOR = 1,
#define DEFAULT_GLES2_MAJOR 2
#define DEFAULT_GLES2_MINOR 0
DEFAULT_GLES2_MAJOR = 2,
DEFAULT_GLES2_MINOR = 0
};
#if USE_FORCED_GL
glContextType = OpenGL::kContextGL;
@ -127,12 +131,6 @@ OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(uint desktopWidth, uint deskt
} else {
glContextType = OpenGL::kContextGL;
}
#undef DEFAULT_GL_MAJOR
#undef DEFAULT_GL_MINOR
#undef DEFAULT_GLES_MAJOR
#undef DEFAULT_GLES_MINOR
#undef DEFAULT_GLES2_MAJOR
#undef DEFAULT_GLES2_MINOR
#endif
setContextType(glContextType);
@ -217,7 +215,7 @@ void OpenGLSdlGraphicsManager::deactivateManager() {
SdlGraphicsManager::deactivateManager();
}
bool OpenGLSdlGraphicsManager::hasFeature(OSystem::Feature f) {
bool OpenGLSdlGraphicsManager::hasFeature(OSystem::Feature f) const {
switch (f) {
case OSystem::kFeatureFullscreenMode:
case OSystem::kFeatureIconifyWindow:
@ -246,7 +244,7 @@ void OpenGLSdlGraphicsManager::setFeatureState(OSystem::Feature f, bool enable)
}
}
bool OpenGLSdlGraphicsManager::getFeatureState(OSystem::Feature f) {
bool OpenGLSdlGraphicsManager::getFeatureState(OSystem::Feature f) const {
switch (f) {
case OSystem::kFeatureFullscreenMode:
#if SDL_VERSION_ATLEAST(2, 0, 0)
@ -344,7 +342,7 @@ void OpenGLSdlGraphicsManager::updateScreen() {
void OpenGLSdlGraphicsManager::notifyVideoExpose() {
}
void OpenGLSdlGraphicsManager::notifyResize(const uint width, const uint height) {
void OpenGLSdlGraphicsManager::notifyResize(const int width, const int height) {
#if SDL_VERSION_ATLEAST(2, 0, 0)
// We sometime get outdated resize events from SDL2. So check that the size we get
// is the actual current window size. If not ignore the resize.
@ -354,11 +352,10 @@ void OpenGLSdlGraphicsManager::notifyResize(const uint width, const uint height)
// causes a SDL_WINDOWEVENT_RESIZED event with the old resolution to be sent, and this
// event is processed after recreating the window at the new resolution.
int currentWidth, currentHeight;
getWindowDimensions(&currentWidth, &currentHeight);
if (width != (uint)currentWidth || height != (uint)currentHeight)
getWindowSizeFromSdl(&currentWidth, &currentHeight);
if (width != currentWidth || height != currentHeight)
return;
setActualScreenSize(width, height);
_eventSource->resetKeyboardEmulation(width - 1, height - 1);
handleResize(width, height);
#else
if (!_ignoreResizeEvents && _hwScreen && !(_hwScreen->flags & SDL_FULLSCREEN)) {
// We save that we handled a resize event here. We need to know this
@ -373,18 +370,6 @@ void OpenGLSdlGraphicsManager::notifyResize(const uint width, const uint height)
#endif
}
void OpenGLSdlGraphicsManager::transformMouseCoordinates(Common::Point &point) {
adjustMousePosition(point.x, point.y);
}
void OpenGLSdlGraphicsManager::notifyMousePos(Common::Point mouse) {
setMousePosition(mouse.x, mouse.y);
}
void OpenGLSdlGraphicsManager::setInternalMousePosition(int x, int y) {
_window->warpMouseInWindow(x, y);
}
bool OpenGLSdlGraphicsManager::loadVideoMode(uint requestedWidth, uint requestedHeight, const Graphics::PixelFormat &format) {
// In some cases we might not want to load the requested video mode. This
// will assure that the window size is not altered.
@ -422,6 +407,11 @@ void *OpenGLSdlGraphicsManager::getProcAddress(const char *name) const {
return SDL_GL_GetProcAddress(name);
}
void OpenGLSdlGraphicsManager::handleResizeImpl(const int width, const int height) {
OpenGLGraphicsManager::handleResizeImpl(width, height);
SdlGraphicsManager::handleResizeImpl(width, height);
}
bool OpenGLSdlGraphicsManager::setupMode(uint width, uint height) {
// In case we request a fullscreen mode we will use the mode the user
// has chosen last time or the biggest mode available.
@ -517,9 +507,8 @@ bool OpenGLSdlGraphicsManager::setupMode(uint width, uint height) {
notifyContextCreate(rgba8888, rgba8888);
int actualWidth, actualHeight;
getWindowDimensions(&actualWidth, &actualHeight);
setActualScreenSize(actualWidth, actualHeight);
_eventSource->resetKeyboardEmulation(actualWidth - 1, actualHeight - 1);
getWindowSizeFromSdl(&actualWidth, &actualHeight);
handleResize(actualWidth, actualHeight);
return true;
#else
// WORKAROUND: Working around infamous SDL bugs when switching
@ -566,8 +555,7 @@ bool OpenGLSdlGraphicsManager::setupMode(uint width, uint height) {
if (_hwScreen) {
notifyContextCreate(rgba8888, rgba8888);
setActualScreenSize(_hwScreen->w, _hwScreen->h);
_eventSource->resetKeyboardEmulation(_hwScreen->w - 1, _hwScreen->h - 1);
handleResize(_hwScreen->w, _hwScreen->h);
}
// Ignore resize events (from SDL) for a few frames, if this isn't
@ -580,20 +568,6 @@ bool OpenGLSdlGraphicsManager::setupMode(uint width, uint height) {
#endif
}
void OpenGLSdlGraphicsManager::getWindowDimensions(int *width, int *height) {
#if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_GetWindowSize(_window->getSDLWindow(), width, height);
#else
if (width) {
*width = _hwScreen->w;
}
if (height) {
*height = _hwScreen->h;
}
#endif
}
bool OpenGLSdlGraphicsManager::notifyEvent(const Common::Event &event) {
switch (event.type) {
case Common::EVENT_KEYUP:
@ -707,7 +681,7 @@ bool OpenGLSdlGraphicsManager::notifyEvent(const Common::Event &event) {
// current scale setting in case the user resized the
// window. Then we apply the direction change.
int windowWidth = 0, windowHeight = 0;
getWindowDimensions(&windowWidth, &windowHeight);
getWindowSizeFromSdl(&windowWidth, &windowHeight);
_graphicsScale = MAX<int>(windowWidth / _lastRequestedWidth, windowHeight / _lastRequestedHeight);
_graphicsScale = MAX<int>(_graphicsScale + direction, 1);
@ -725,7 +699,7 @@ bool OpenGLSdlGraphicsManager::notifyEvent(const Common::Event &event) {
#ifdef USE_OSD
int windowWidth = 0, windowHeight = 0;
getWindowDimensions(&windowWidth, &windowHeight);
getWindowSizeFromSdl(&windowWidth, &windowHeight);
const Common::String osdMsg = Common::String::format(_("Resolution: %dx%d"), windowWidth, windowHeight);
displayMessageOnOSD(osdMsg.c_str());
#endif
@ -785,7 +759,7 @@ bool OpenGLSdlGraphicsManager::notifyEvent(const Common::Event &event) {
}
}
bool OpenGLSdlGraphicsManager::isHotkey(const Common::Event &event) {
bool OpenGLSdlGraphicsManager::isHotkey(const Common::Event &event) const {
if (event.kbd.hasFlags(Common::KBD_ALT)) {
return event.kbd.keycode == Common::KEYCODE_RETURN
|| event.kbd.keycode == (Common::KeyCode)SDLK_KP_ENTER

View File

@ -36,38 +36,37 @@ public:
virtual ~OpenGLSdlGraphicsManager();
// GraphicsManager API
virtual void activateManager();
virtual void deactivateManager();
virtual void activateManager() override;
virtual void deactivateManager() override;
virtual bool hasFeature(OSystem::Feature f);
virtual void setFeatureState(OSystem::Feature f, bool enable);
virtual bool getFeatureState(OSystem::Feature f);
virtual bool hasFeature(OSystem::Feature f) const override;
virtual void setFeatureState(OSystem::Feature f, bool enable) override;
virtual bool getFeatureState(OSystem::Feature f) const override;
virtual void initSize(uint w, uint h, const Graphics::PixelFormat *format) override;
#ifdef USE_RGB_COLOR
virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const;
virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const override;
#endif
virtual void updateScreen();
virtual void updateScreen() override;
// EventObserver API
virtual bool notifyEvent(const Common::Event &event);
virtual bool notifyEvent(const Common::Event &event) override;
// SdlGraphicsManager API
virtual void notifyVideoExpose();
virtual void notifyResize(const uint width, const uint height);
virtual void transformMouseCoordinates(Common::Point &point);
virtual void notifyMousePos(Common::Point mouse);
virtual void notifyVideoExpose() override;
virtual void notifyResize(const int width, const int height) override;
protected:
virtual void setInternalMousePosition(int x, int y);
virtual bool loadVideoMode(uint requestedWidth, uint requestedHeight, const Graphics::PixelFormat &format) override;
virtual bool loadVideoMode(uint requestedWidth, uint requestedHeight, const Graphics::PixelFormat &format);
virtual void refreshScreen() override;
virtual void refreshScreen();
virtual void *getProcAddress(const char *name) const override;
virtual void handleResizeImpl(const int width, const int height) override;
virtual void *getProcAddress(const char *name) const;
virtual int getGraphicsModeScale(int mode) const override { return 1; }
private:
@ -78,11 +77,8 @@ private:
SDL_GLContext _glContext;
#else
uint32 _lastVideoModeLoad;
SDL_Surface *_hwScreen;
#endif
void getWindowDimensions(int *width, int *height);
uint _lastRequestedWidth;
uint _lastRequestedHeight;
uint _graphicsScale;
@ -122,7 +118,7 @@ private:
uint _desiredFullscreenWidth;
uint _desiredFullscreenHeight;
virtual bool isHotkey(const Common::Event &event);
bool isHotkey(const Common::Event &event) const;
};
#endif

View File

@ -28,15 +28,11 @@
#include "graphics/scaler/aspect.h"
SdlGraphicsManager::SdlGraphicsManager(SdlEventSource *source, SdlWindow *window)
: _eventSource(source), _window(window)
: _eventSource(source), _window(window), _hwScreen(nullptr)
#if SDL_VERSION_ATLEAST(2, 0, 0)
, _allowWindowSizeReset(false), _hintedWidth(0), _hintedHeight(0), _lastFlags(0)
#endif
{
}
SdlGraphicsManager::~SdlGraphicsManager() {
}
{}
void SdlGraphicsManager::activateManager() {
_eventSource->setGraphicsManager(this);
@ -46,7 +42,7 @@ void SdlGraphicsManager::deactivateManager() {
_eventSource->setGraphicsManager(0);
}
SdlGraphicsManager::State SdlGraphicsManager::getState() {
SdlGraphicsManager::State SdlGraphicsManager::getState() const {
State state;
state.screenWidth = getWidth();
@ -152,6 +148,32 @@ void SdlGraphicsManager::initSizeHint(const Graphics::ModeList &modes) {
#endif
}
void SdlGraphicsManager::notifyMousePosition(Common::Point &mouse) {
int showCursor;
if (_activeArea.drawRect.contains(mouse)) {
showCursor = SDL_DISABLE;
} else {
mouse.x = CLIP<int>(mouse.x, _activeArea.drawRect.left, _activeArea.drawRect.right - 1);
mouse.y = CLIP<int>(mouse.y, _activeArea.drawRect.top, _activeArea.drawRect.bottom - 1);
if (_window->mouseIsGrabbed()) {
setSystemMousePosition(mouse.x, mouse.y);
showCursor = SDL_DISABLE;
} else {
showCursor = SDL_ENABLE;
}
}
SDL_ShowCursor(showCursor);
setMousePosition(mouse.x, mouse.y);
mouse = convertWindowToVirtual(mouse.x, mouse.y);
}
void SdlGraphicsManager::handleResizeImpl(const int width, const int height) {
_eventSource->resetKeyboardEmulation(width - 1, height - 1);
_forceRedraw = true;
}
#if SDL_VERSION_ATLEAST(2, 0, 0)
bool SdlGraphicsManager::createOrUpdateWindow(int width, int height, const Uint32 flags) {
if (!_window) {

View File

@ -23,7 +23,7 @@
#ifndef BACKENDS_GRAPHICS_SDL_SDLGRAPHICS_H
#define BACKENDS_GRAPHICS_SDL_SDLGRAPHICS_H
#include "backends/graphics/graphics.h"
#include "backends/graphics/windowed.h"
#include "backends/platform/sdl/sdl-window.h"
#include "common/rect.h"
@ -32,13 +32,11 @@ class SdlEventSource;
/**
* Base class for a SDL based graphics manager.
*
* It features a few extra a few extra features required by SdlEventSource.
*/
class SdlGraphicsManager : virtual public GraphicsManager {
class SdlGraphicsManager : virtual public WindowedGraphicsManager {
public:
SdlGraphicsManager(SdlEventSource *source, SdlWindow *window);
virtual ~SdlGraphicsManager();
virtual ~SdlGraphicsManager() {}
/**
* Makes this graphics manager active. That means it should be ready to
@ -74,23 +72,20 @@ public:
* @param width Requested window width.
* @param height Requested window height.
*/
virtual void notifyResize(const uint width, const uint height) {}
virtual void notifyResize(const int width, const int height) {}
/**
* Transforms real screen coordinates into the current active screen
* coordinates (may be either game screen or overlay).
* Notifies the graphics manager about a mouse position change.
*
* @param point Mouse coordinates to transform.
*/
virtual void transformMouseCoordinates(Common::Point &point) = 0;
/**
* Notifies the graphics manager about a position change according to the
* real screen coordinates.
* The passed point *must* be converted from window coordinates to virtual
* coordinates in order for the event to be processed correctly by the game
* engine. Just use `convertWindowToVirtual` for this unless you need to do
* something special.
*
* @param mouse Mouse position.
* @param mouse The mouse position in window coordinates, which must be
* converted synchronously to virtual coordinates.
*/
virtual void notifyMousePos(Common::Point mouse) = 0;
virtual void notifyMousePosition(Common::Point &mouse);
/**
* A (subset) of the graphic manager's state. This is used when switching
@ -108,17 +103,17 @@ public:
};
/**
* Queries the current state of the graphic manager.
* Gets the current state of the graphics manager.
*/
State getState();
State getState() const;
/**
* Setup a basic state of the graphic manager.
* Sets up a basic state of the graphics manager.
*/
bool setState(const State &state);
/**
* Queries the SDL window.
* @returns the SDL window.
*/
SdlWindow *getWindow() const { return _window; }
@ -130,6 +125,34 @@ protected:
bool defaultGraphicsModeConfig() const;
int getGraphicsModeIdByName(const Common::String &name) const;
/**
* Gets the dimensions of the window directly from SDL instead of from the
* values stored by the graphics manager.
*/
void getWindowSizeFromSdl(int *width, int *height) const {
#if SDL_VERSION_ATLEAST(2, 0, 0)
assert(_window);
SDL_GetWindowSize(_window->getSDLWindow(), width, height);
#else
assert(_hwScreen);
if (width) {
*width = _hwScreen->w;
}
if (height) {
*height = _hwScreen->h;
}
#endif
}
virtual void setSystemMousePosition(const int x, const int y) override {
assert(_window);
_window->warpMouseInWindow(x, y);
}
virtual void handleResizeImpl(const int width, const int height) override;
#if SDL_VERSION_ATLEAST(2, 0, 0)
public:
void unlockWindowSize() {
@ -146,6 +169,7 @@ protected:
bool createOrUpdateWindow(const int width, const int height, const Uint32 flags);
#endif
SDL_Surface *_hwScreen;
SdlEventSource *_eventSource;
SdlWindow *_window;
};

View File

@ -23,7 +23,6 @@
#include "common/scummsys.h"
#if defined(SDL_BACKEND)
#include "backends/graphics/surfacesdl/surfacesdl-graphics.h"
#include "backends/events/sdl/sdl-events.h"
#include "backends/platform/sdl/sdl.h"
@ -133,10 +132,8 @@ SurfaceSdlGraphicsManager::SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSou
_osdMessageSurface(nullptr), _osdMessageAlpha(SDL_ALPHA_TRANSPARENT), _osdMessageFadeStartTime(0),
_osdIconSurface(nullptr),
#endif
_hwscreen(0),
#if SDL_VERSION_ATLEAST(2, 0, 0)
_renderer(nullptr), _screenTexture(nullptr),
_viewport(), _windowWidth(1), _windowHeight(1),
#endif
#if defined(WIN32) && !SDL_VERSION_ATLEAST(2, 0, 0)
_originalBitsPerPixel(0),
@ -146,10 +143,9 @@ SurfaceSdlGraphicsManager::SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSou
_screenFormat(Graphics::PixelFormat::createFormatCLUT8()),
_cursorFormat(Graphics::PixelFormat::createFormatCLUT8()),
#endif
_overlayVisible(false),
_overlayscreen(0), _tmpscreen2(0),
_scalerProc(0), _screenChangeCount(0),
_mouseVisible(false), _mouseNeedsRedraw(false), _mouseData(0), _mouseSurface(0),
_mouseVisible(false), _mouseData(0), _mouseSurface(0),
_mouseOrigSurface(0), _cursorDontScale(false), _cursorPaletteDisabled(true),
_currentShakePos(0), _newShakePos(0),
_paletteDirtyStart(0), _paletteDirtyEnd(0),
@ -247,7 +243,7 @@ void SurfaceSdlGraphicsManager::deactivateManager() {
SdlGraphicsManager::deactivateManager();
}
bool SurfaceSdlGraphicsManager::hasFeature(OSystem::Feature f) {
bool SurfaceSdlGraphicsManager::hasFeature(OSystem::Feature f) const {
return
(f == OSystem::kFeatureFullscreenMode) ||
(f == OSystem::kFeatureAspectRatioCorrection) ||
@ -284,7 +280,7 @@ void SurfaceSdlGraphicsManager::setFeatureState(OSystem::Feature f, bool enable)
}
}
bool SurfaceSdlGraphicsManager::getFeatureState(OSystem::Feature f) {
bool SurfaceSdlGraphicsManager::getFeatureState(OSystem::Feature f) const {
// We need to allow this to be called from within a transaction, since we
// currently use it to retreive the graphics state, when switching from
// SDL->OpenGL mode for example.
@ -555,16 +551,16 @@ void SurfaceSdlGraphicsManager::detectSupportedFormats() {
Graphics::PixelFormat(2, 4, 4, 4, 4, 4, 8, 12, 0)
};
if (_hwscreen) {
if (_hwScreen) {
// Get our currently set hardware format
Graphics::PixelFormat hwFormat(_hwscreen->format->BytesPerPixel,
8 - _hwscreen->format->Rloss, 8 - _hwscreen->format->Gloss,
8 - _hwscreen->format->Bloss, 8 - _hwscreen->format->Aloss,
_hwscreen->format->Rshift, _hwscreen->format->Gshift,
_hwscreen->format->Bshift, _hwscreen->format->Ashift);
Graphics::PixelFormat hwFormat(_hwScreen->format->BytesPerPixel,
8 - _hwScreen->format->Rloss, 8 - _hwScreen->format->Gloss,
8 - _hwScreen->format->Bloss, 8 - _hwScreen->format->Aloss,
_hwScreen->format->Rshift, _hwScreen->format->Gshift,
_hwScreen->format->Bshift, _hwScreen->format->Ashift);
// Workaround to SDL not providing an accurate Aloss value on Mac OS X.
if (_hwscreen->format->Amask == 0)
if (_hwScreen->format->Amask == 0)
hwFormat.aLoss = 8;
_supportedFormats.push_back(hwFormat);
@ -579,7 +575,7 @@ void SurfaceSdlGraphicsManager::detectSupportedFormats() {
// Push some RGB formats
for (i = 0; i < ARRAYSIZE(RGBList); i++) {
if (_hwscreen && (RGBList[i].bytesPerPixel > format.bytesPerPixel))
if (_hwScreen && (RGBList[i].bytesPerPixel > format.bytesPerPixel))
continue;
if (RGBList[i] != format)
_supportedFormats.push_back(RGBList[i]);
@ -587,7 +583,7 @@ void SurfaceSdlGraphicsManager::detectSupportedFormats() {
// Push some BGR formats
for (i = 0; i < ARRAYSIZE(BGRList); i++) {
if (_hwscreen && (BGRList[i].bytesPerPixel > format.bytesPerPixel))
if (_hwScreen && (BGRList[i].bytesPerPixel > format.bytesPerPixel))
continue;
if (BGRList[i] != format)
_supportedFormats.push_back(BGRList[i]);
@ -722,11 +718,11 @@ void SurfaceSdlGraphicsManager::setGraphicsModeIntern() {
}
}
if (!_screen || !_hwscreen)
if (!_screen || !_hwScreen)
return;
// Blit everything to the screen
_forceFull = true;
_forceRedraw = true;
// Even if the old and new scale factors are the same, we may have a
// different scaler for the cursor now.
@ -797,13 +793,6 @@ void SurfaceSdlGraphicsManager::initSize(uint w, uint h, const Graphics::PixelFo
_transactionDetails.sizeChanged = true;
}
int SurfaceSdlGraphicsManager::effectiveScreenHeight() const {
return _videoMode.scaleFactor *
(_videoMode.aspectRatioCorrection
? real2Aspect(_videoMode.screenHeight)
: _videoMode.screenHeight);
}
static void fixupResolutionForAspectRatio(AspectRatio desiredAspectRatio, int &width, int &height) {
assert(&width != &height);
@ -864,7 +853,7 @@ static void fixupResolutionForAspectRatio(AspectRatio desiredAspectRatio, int &w
}
bool SurfaceSdlGraphicsManager::loadGFXMode() {
_forceFull = true;
_forceRedraw = true;
#if !defined(__MAEMO__) && !defined(DINGUX) && !defined(GPH_DEVICE) && !defined(LINUXMOTO) && !defined(OPENPANDORA)
_videoMode.overlayWidth = _videoMode.screenWidth * _videoMode.scaleFactor;
@ -873,11 +862,14 @@ bool SurfaceSdlGraphicsManager::loadGFXMode() {
if (_videoMode.screenHeight != 200 && _videoMode.screenHeight != 400)
_videoMode.aspectRatioCorrection = false;
if (_videoMode.aspectRatioCorrection)
_videoMode.overlayHeight = real2Aspect(_videoMode.overlayHeight);
_videoMode.hardwareWidth = _videoMode.screenWidth * _videoMode.scaleFactor;
_videoMode.hardwareHeight = effectiveScreenHeight();
_videoMode.hardwareHeight = _videoMode.screenHeight * _videoMode.scaleFactor;
if (_videoMode.aspectRatioCorrection) {
_videoMode.overlayHeight = real2Aspect(_videoMode.overlayHeight);
_videoMode.hardwareHeight = real2Aspect(_videoMode.hardwareHeight);
}
// On GPH devices ALL the _videoMode.hardware... are setup in GPHGraphicsManager::loadGFXMode()
#elif !defined(GPH_DEVICE)
_videoMode.hardwareWidth = _videoMode.overlayWidth;
@ -924,7 +916,7 @@ bool SurfaceSdlGraphicsManager::loadGFXMode() {
_displayDisabled = ConfMan.getBool("disable_display");
if (_displayDisabled) {
_hwscreen = g_eventRec.getSurface(_videoMode.hardwareWidth, _videoMode.hardwareHeight);
_hwScreen = g_eventRec.getSurface(_videoMode.hardwareWidth, _videoMode.hardwareHeight);
} else
#endif
{
@ -937,7 +929,7 @@ bool SurfaceSdlGraphicsManager::loadGFXMode() {
}
#endif
_hwscreen = SDL_SetVideoMode(_videoMode.hardwareWidth, _videoMode.hardwareHeight, 16,
_hwScreen = SDL_SetVideoMode(_videoMode.hardwareWidth, _videoMode.hardwareHeight, 16,
_videoMode.fullscreen ? (SDL_FULLSCREEN|SDL_SWSURFACE) : SDL_SWSURFACE
);
}
@ -946,9 +938,9 @@ bool SurfaceSdlGraphicsManager::loadGFXMode() {
detectSupportedFormats();
#endif
if (_hwscreen == NULL) {
if (_hwScreen == NULL) {
// DON'T use error(), as this tries to bring up the debug
// console, which WON'T WORK now that _hwscreen is hosed.
// console, which WON'T WORK now that _hwScreen is hosed.
if (!_oldVideoMode.setup) {
warning("SDL_SetVideoMode says we can't switch to that mode (%s)", SDL_GetError());
@ -958,6 +950,10 @@ bool SurfaceSdlGraphicsManager::loadGFXMode() {
}
}
#if !SDL_VERSION_ATLEAST(2, 0, 0)
handleResize(_videoMode.hardwareWidth, _videoMode.hardwareHeight);
#endif
//
// Create the surface used for the graphics in 16 bit before scaling, and also the overlay
//
@ -965,20 +961,20 @@ bool SurfaceSdlGraphicsManager::loadGFXMode() {
// Need some extra bytes around when using 2xSaI
_tmpscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth + 3, _videoMode.screenHeight + 3,
16,
_hwscreen->format->Rmask,
_hwscreen->format->Gmask,
_hwscreen->format->Bmask,
_hwscreen->format->Amask);
_hwScreen->format->Rmask,
_hwScreen->format->Gmask,
_hwScreen->format->Bmask,
_hwScreen->format->Amask);
if (_tmpscreen == NULL)
error("allocating _tmpscreen failed");
_overlayscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth, _videoMode.overlayHeight,
16,
_hwscreen->format->Rmask,
_hwscreen->format->Gmask,
_hwscreen->format->Bmask,
_hwscreen->format->Amask);
_hwScreen->format->Rmask,
_hwScreen->format->Gmask,
_hwScreen->format->Bmask,
_hwScreen->format->Amask);
if (_overlayscreen == NULL)
error("allocating _overlayscreen failed");
@ -997,25 +993,16 @@ bool SurfaceSdlGraphicsManager::loadGFXMode() {
_tmpscreen2 = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth + 3, _videoMode.overlayHeight + 3,
16,
_hwscreen->format->Rmask,
_hwscreen->format->Gmask,
_hwscreen->format->Bmask,
_hwscreen->format->Amask);
_hwScreen->format->Rmask,
_hwScreen->format->Gmask,
_hwScreen->format->Bmask,
_hwScreen->format->Amask);
if (_tmpscreen2 == NULL)
error("allocating _tmpscreen2 failed");
#if !SDL_VERSION_ATLEAST(2, 0, 0)
// For SDL2 the output resolution might differ from the requested
// resolution. We handle resetting the keyboard emulation properly inside
// our SDL_SetVideoMode wrapper for SDL2.
_eventSource->resetKeyboardEmulation(
_videoMode.screenWidth * _videoMode.scaleFactor - 1,
effectiveScreenHeight() - 1);
#endif
// Distinguish 555 and 565 mode
if (_hwscreen->format->Rmask == 0x7C00)
if (_hwScreen->format->Rmask == 0x7C00)
InitScalers(555);
else
InitScalers(565);
@ -1033,9 +1020,9 @@ void SurfaceSdlGraphicsManager::unloadGFXMode() {
deinitializeRenderer();
#endif
if (_hwscreen) {
SDL_FreeSurface(_hwscreen);
_hwscreen = NULL;
if (_hwScreen) {
SDL_FreeSurface(_hwScreen);
_hwScreen = NULL;
}
if (_tmpscreen) {
@ -1087,9 +1074,9 @@ bool SurfaceSdlGraphicsManager::hotswapGFXMode() {
_overlayscreen = NULL;
// Release the HW screen surface
if (_hwscreen) {
SDL_FreeSurface(_hwscreen);
_hwscreen = NULL;
if (_hwScreen) {
SDL_FreeSurface(_hwScreen);
_hwScreen = NULL;
}
if (_tmpscreen) {
SDL_FreeSurface(_tmpscreen);
@ -1155,25 +1142,19 @@ void SurfaceSdlGraphicsManager::internUpdateScreen() {
ScalerProc *scalerProc;
int scale1;
// definitions not available for non-DEBUG here. (needed this to compile in SYMBIAN32 & linux?)
#if defined(DEBUG) && !defined(WIN32) && !defined(_WIN32_WCE)
assert(_hwscreen != NULL);
assert(_hwscreen->map->sw_data != NULL);
#endif
// If the shake position changed, fill the dirty area with blackness
if (_currentShakePos != _newShakePos ||
(_mouseNeedsRedraw && _mouseBackup.y <= _currentShakePos)) {
(_cursorNeedsRedraw && _mouseBackup.y <= _currentShakePos)) {
SDL_Rect blackrect = {0, 0, (Uint16)(_videoMode.screenWidth * _videoMode.scaleFactor), (Uint16)(_newShakePos * _videoMode.scaleFactor)};
if (_videoMode.aspectRatioCorrection && !_overlayVisible)
blackrect.h = real2Aspect(blackrect.h - 1) + 1;
SDL_FillRect(_hwscreen, &blackrect, 0);
SDL_FillRect(_hwScreen, &blackrect, 0);
_currentShakePos = _newShakePos;
_forceFull = true;
_forceRedraw = true;
}
// Check whether the palette was changed in the meantime and update the
@ -1185,7 +1166,7 @@ void SurfaceSdlGraphicsManager::internUpdateScreen() {
_paletteDirtyEnd = 0;
_forceFull = true;
_forceRedraw = true;
}
if (!_overlayVisible) {
@ -1207,7 +1188,7 @@ void SurfaceSdlGraphicsManager::internUpdateScreen() {
// Add the area covered by the mouse cursor to the list of dirty rects if
// we have to redraw the mouse.
if (_mouseNeedsRedraw)
if (_cursorNeedsRedraw)
undrawMouse();
#ifdef USE_OSD
@ -1215,7 +1196,7 @@ void SurfaceSdlGraphicsManager::internUpdateScreen() {
#endif
// Force a full redraw if requested
if (_forceFull) {
if (_forceRedraw) {
_numDirtyRects = 1;
_dirtyRectList[0].x = 0;
_dirtyRectList[0].y = 0;
@ -1224,7 +1205,7 @@ void SurfaceSdlGraphicsManager::internUpdateScreen() {
}
// Only draw anything if necessary
if (_numDirtyRects > 0 || _mouseNeedsRedraw) {
if (_numDirtyRects > 0 || _cursorNeedsRedraw) {
SDL_Rect *r;
SDL_Rect dst;
uint32 srcPitch, dstPitch;
@ -1240,10 +1221,10 @@ void SurfaceSdlGraphicsManager::internUpdateScreen() {
}
SDL_LockSurface(srcSurf);
SDL_LockSurface(_hwscreen);
SDL_LockSurface(_hwScreen);
srcPitch = srcSurf->pitch;
dstPitch = _hwscreen->pitch;
dstPitch = _hwScreen->pitch;
for (r = _dirtyRectList; r != lastRect; ++r) {
register int dst_y = r->y + _currentShakePos;
@ -1268,7 +1249,7 @@ void SurfaceSdlGraphicsManager::internUpdateScreen() {
assert(scalerProc != NULL);
scalerProc((byte *)srcSurf->pixels + (r->x * 2 + 2) + (r->y + 1) * srcPitch, srcPitch,
(byte *)_hwscreen->pixels + rx1 * 2 + dst_y * dstPitch, dstPitch, r->w, dst_h);
(byte *)_hwScreen->pixels + rx1 * 2 + dst_y * dstPitch, dstPitch, r->w, dst_h);
}
r->x = rx1;
@ -1278,17 +1259,17 @@ void SurfaceSdlGraphicsManager::internUpdateScreen() {
#ifdef USE_SCALERS
if (_videoMode.aspectRatioCorrection && orig_dst_y < height && !_overlayVisible)
r->h = stretch200To240((uint8 *) _hwscreen->pixels, dstPitch, r->w, r->h, r->x, r->y, orig_dst_y * scale1);
r->h = stretch200To240((uint8 *) _hwScreen->pixels, dstPitch, r->w, r->h, r->x, r->y, orig_dst_y * scale1);
#endif
}
SDL_UnlockSurface(srcSurf);
SDL_UnlockSurface(_hwscreen);
SDL_UnlockSurface(_hwScreen);
// Readjust the dirty rect list in case we are doing a full update.
// This is necessary if shaking is active.
if (_forceFull) {
if (_forceRedraw) {
_dirtyRectList[0].y = 0;
_dirtyRectList[0].h = effectiveScreenHeight();
_dirtyRectList[0].h = _videoMode.hardwareHeight;
}
drawMouse();
@ -1318,18 +1299,18 @@ void SurfaceSdlGraphicsManager::internUpdateScreen() {
y = real2Aspect(y);
if (h > 0 && w > 0) {
SDL_LockSurface(_hwscreen);
SDL_LockSurface(_hwScreen);
// Use white as color for now.
Uint32 rectColor = SDL_MapRGB(_hwscreen->format, 0xFF, 0xFF, 0xFF);
Uint32 rectColor = SDL_MapRGB(_hwScreen->format, 0xFF, 0xFF, 0xFF);
// First draw the top and bottom lines
// then draw the left and right lines
if (_hwscreen->format->BytesPerPixel == 2) {
uint16 *top = (uint16 *)((byte *)_hwscreen->pixels + y * _hwscreen->pitch + x * 2);
uint16 *bottom = (uint16 *)((byte *)_hwscreen->pixels + (y + h) * _hwscreen->pitch + x * 2);
byte *left = ((byte *)_hwscreen->pixels + y * _hwscreen->pitch + x * 2);
byte *right = ((byte *)_hwscreen->pixels + y * _hwscreen->pitch + (x + w - 1) * 2);
if (_hwScreen->format->BytesPerPixel == 2) {
uint16 *top = (uint16 *)((byte *)_hwScreen->pixels + y * _hwScreen->pitch + x * 2);
uint16 *bottom = (uint16 *)((byte *)_hwScreen->pixels + (y + h) * _hwScreen->pitch + x * 2);
byte *left = ((byte *)_hwScreen->pixels + y * _hwScreen->pitch + x * 2);
byte *right = ((byte *)_hwScreen->pixels + y * _hwScreen->pitch + (x + w - 1) * 2);
while (w--) {
*top++ = rectColor;
@ -1340,14 +1321,14 @@ void SurfaceSdlGraphicsManager::internUpdateScreen() {
*(uint16 *)left = rectColor;
*(uint16 *)right = rectColor;
left += _hwscreen->pitch;
right += _hwscreen->pitch;
left += _hwScreen->pitch;
right += _hwScreen->pitch;
}
} else if (_hwscreen->format->BytesPerPixel == 4) {
uint32 *top = (uint32 *)((byte *)_hwscreen->pixels + y * _hwscreen->pitch + x * 4);
uint32 *bottom = (uint32 *)((byte *)_hwscreen->pixels + (y + h) * _hwscreen->pitch + x * 4);
byte *left = ((byte *)_hwscreen->pixels + y * _hwscreen->pitch + x * 4);
byte *right = ((byte *)_hwscreen->pixels + y * _hwscreen->pitch + (x + w - 1) * 4);
} else if (_hwScreen->format->BytesPerPixel == 4) {
uint32 *top = (uint32 *)((byte *)_hwScreen->pixels + y * _hwScreen->pitch + x * 4);
uint32 *bottom = (uint32 *)((byte *)_hwScreen->pixels + (y + h) * _hwScreen->pitch + x * 4);
byte *left = ((byte *)_hwScreen->pixels + y * _hwScreen->pitch + x * 4);
byte *right = ((byte *)_hwScreen->pixels + y * _hwScreen->pitch + (x + w - 1) * 4);
while (w--) {
*top++ = rectColor;
@ -1358,12 +1339,12 @@ void SurfaceSdlGraphicsManager::internUpdateScreen() {
*(uint32 *)left = rectColor;
*(uint32 *)right = rectColor;
left += _hwscreen->pitch;
right += _hwscreen->pitch;
left += _hwScreen->pitch;
right += _hwScreen->pitch;
}
}
SDL_UnlockSurface(_hwscreen);
SDL_UnlockSurface(_hwScreen);
}
}
}
@ -1371,17 +1352,17 @@ void SurfaceSdlGraphicsManager::internUpdateScreen() {
// Finally, blit all our changes to the screen
if (!_displayDisabled) {
SDL_UpdateRects(_hwscreen, _numDirtyRects, _dirtyRectList);
SDL_UpdateRects(_hwScreen, _numDirtyRects, _dirtyRectList);
}
}
_numDirtyRects = 0;
_forceFull = false;
_mouseNeedsRedraw = false;
_forceRedraw = false;
_cursorNeedsRedraw = false;
}
bool SurfaceSdlGraphicsManager::saveScreenshot(const char *filename) {
assert(_hwscreen != NULL);
assert(_hwScreen != NULL);
Common::StackLock lock(_graphicsMutex);
#ifdef USE_PNG
@ -1391,12 +1372,12 @@ bool SurfaceSdlGraphicsManager::saveScreenshot(const char *filename) {
}
#if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_Surface *rgbScreen = SDL_ConvertSurfaceFormat(_hwscreen, SDL_PIXELFORMAT_RGB24, 0);
SDL_Surface *rgbScreen = SDL_ConvertSurfaceFormat(_hwScreen, SDL_PIXELFORMAT_RGB24, 0);
#else
// This block of code was taken mostly as-is from SDL 1.2's SDL_SaveBMP_RW
SDL_Surface *rgbScreen = SDL_CreateRGBSurface(SDL_SWSURFACE,
_hwscreen->w,
_hwscreen->h,
_hwScreen->w,
_hwScreen->h,
24,
#ifdef SCUMM_LITTLE_ENDIAN
0x0000FF, 0x00FF00, 0xFF0000,
@ -1411,9 +1392,9 @@ bool SurfaceSdlGraphicsManager::saveScreenshot(const char *filename) {
SDL_Rect bounds;
bounds.x = bounds.y = 0;
bounds.w = _hwscreen->w;
bounds.h = _hwscreen->h;
if (SDL_LowerBlit(_hwscreen, &bounds, rgbScreen, &bounds) < 0) {
bounds.w = _hwScreen->w;
bounds.h = _hwScreen->h;
if (SDL_LowerBlit(_hwScreen, &bounds, rgbScreen, &bounds) < 0) {
SDL_FreeSurface(rgbScreen);
rgbScreen = nullptr;
}
@ -1441,7 +1422,7 @@ bool SurfaceSdlGraphicsManager::saveScreenshot(const char *filename) {
return success;
#else
return SDL_SaveBMP(_hwscreen, filename) == 0;
return SDL_SaveBMP(_hwScreen, filename) == 0;
#endif
}
@ -1571,7 +1552,7 @@ void SurfaceSdlGraphicsManager::unlockScreen() {
SDL_UnlockSurface(_screen);
// Trigger a full screen update
_forceFull = true;
_forceRedraw = true;
// Finally unlock the graphics mutex
g_system->unlockMutex(_graphicsMutex);
@ -1585,11 +1566,11 @@ void SurfaceSdlGraphicsManager::fillScreen(uint32 col) {
}
void SurfaceSdlGraphicsManager::addDirtyRect(int x, int y, int w, int h, bool realCoordinates) {
if (_forceFull)
if (_forceRedraw)
return;
if (_numDirtyRects == NUM_DIRTY_RECT) {
_forceFull = true;
_forceRedraw = true;
return;
}
@ -1608,8 +1589,8 @@ void SurfaceSdlGraphicsManager::addDirtyRect(int x, int y, int w, int h, bool re
if (!realCoordinates) {
x--;
y--;
w+=2;
h+=2;
w += 2;
h += 2;
}
// clip
@ -1620,7 +1601,7 @@ void SurfaceSdlGraphicsManager::addDirtyRect(int x, int y, int w, int h, bool re
if (y < 0) {
h += y;
y=0;
y = 0;
}
if (w > width - x) {
@ -1638,7 +1619,7 @@ void SurfaceSdlGraphicsManager::addDirtyRect(int x, int y, int w, int h, bool re
#endif
if (w == width && h == height) {
_forceFull = true;
_forceRedraw = true;
return;
}
@ -1652,11 +1633,11 @@ void SurfaceSdlGraphicsManager::addDirtyRect(int x, int y, int w, int h, bool re
}
}
int16 SurfaceSdlGraphicsManager::getHeight() {
int16 SurfaceSdlGraphicsManager::getHeight() const {
return _videoMode.screenHeight;
}
int16 SurfaceSdlGraphicsManager::getWidth() {
int16 SurfaceSdlGraphicsManager::getWidth() const {
return _videoMode.screenWidth;
}
@ -1697,7 +1678,7 @@ void SurfaceSdlGraphicsManager::setPalette(const byte *colors, uint start, uint
blitCursor();
}
void SurfaceSdlGraphicsManager::grabPalette(byte *colors, uint start, uint num) {
void SurfaceSdlGraphicsManager::grabPalette(byte *colors, uint start, uint num) const {
assert(colors);
#ifdef USE_RGB_COLOR
@ -1777,56 +1758,7 @@ void SurfaceSdlGraphicsManager::clearFocusRectangle() {
#pragma mark --- Overlays ---
#pragma mark -
void SurfaceSdlGraphicsManager::showOverlay() {
assert(_transactionMode == kTransactionNone);
int x, y;
if (_overlayVisible)
return;
_overlayVisible = true;
// Since resolution could change, put mouse to adjusted position
// Fixes bug #1349059
x = _mouseCurState.x * _videoMode.scaleFactor;
if (_videoMode.aspectRatioCorrection)
y = real2Aspect(_mouseCurState.y) * _videoMode.scaleFactor;
else
y = _mouseCurState.y * _videoMode.scaleFactor;
warpMouse(x, y);
clearOverlay();
}
void SurfaceSdlGraphicsManager::hideOverlay() {
assert(_transactionMode == kTransactionNone);
if (!_overlayVisible)
return;
int x, y;
_overlayVisible = false;
// Since resolution could change, put mouse to adjusted position
// Fixes bug #1349059
x = _mouseCurState.x / _videoMode.scaleFactor;
y = _mouseCurState.y / _videoMode.scaleFactor;
if (_videoMode.aspectRatioCorrection)
y = aspect2Real(y);
warpMouse(x, y);
clearOverlay();
_forceFull = true;
}
void SurfaceSdlGraphicsManager::clearOverlay() {
//assert(_transactionMode == kTransactionNone);
Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends
if (!_overlayVisible)
@ -1854,10 +1786,10 @@ void SurfaceSdlGraphicsManager::clearOverlay() {
SDL_UnlockSurface(_tmpscreen);
SDL_UnlockSurface(_overlayscreen);
_forceFull = true;
_forceRedraw = true;
}
void SurfaceSdlGraphicsManager::grabOverlay(void *buf, int pitch) {
void SurfaceSdlGraphicsManager::grabOverlay(void *buf, int pitch) const {
assert(_transactionMode == kTransactionNone);
if (_overlayscreen == NULL)
@ -1937,56 +1869,11 @@ bool SurfaceSdlGraphicsManager::showMouse(bool visible) {
bool last = _mouseVisible;
_mouseVisible = visible;
_mouseNeedsRedraw = true;
_cursorNeedsRedraw = true;
return last;
}
void SurfaceSdlGraphicsManager::setMousePos(int x, int y) {
if (x != _mouseCurState.x || y != _mouseCurState.y) {
_mouseNeedsRedraw = true;
_mouseCurState.x = x;
_mouseCurState.y = y;
}
}
void SurfaceSdlGraphicsManager::warpMouse(int x, int y) {
// Don't change actual mouse position, when mouse is outside of our window (in case of windowed mode)
if (!_window->hasMouseFocus()) {
setMousePos(x, y); // but change game cursor position
return;
}
int x1 = x, y1 = y;
if (_videoMode.aspectRatioCorrection && !_overlayVisible)
y1 = real2Aspect(y1);
if (_mouseCurState.x != x || _mouseCurState.y != y) {
if (!_overlayVisible) {
x1 *= _videoMode.scaleFactor;
y1 *= _videoMode.scaleFactor;
}
#if SDL_VERSION_ATLEAST(2, 0, 0)
// Transform our coordinates in "virtual" output coordinate space into
// actual output coordinate space.
x1 = x1 * _windowWidth / _videoMode.hardwareWidth;
y1 = y1 * _windowHeight / _videoMode.hardwareHeight;
#endif
_window->warpMouseInWindow(x1, y1);
// SDL_WarpMouse() generates a mouse movement event, so
// setMousePos() would be called eventually. However, the
// cannon script in CoMI calls this function twice each time
// the cannon is reloaded. Unless we update the mouse position
// immediately the second call is ignored, causing the cannon
// to change its aim.
setMousePos(x, y);
}
}
void SurfaceSdlGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) {
#ifdef USE_RGB_COLOR
if (!format)
@ -2022,10 +1909,10 @@ void SurfaceSdlGraphicsManager::setMouseCursor(const void *buf, uint w, uint h,
_mouseCurState.w + 2,
_mouseCurState.h + 2,
16,
_hwscreen->format->Rmask,
_hwscreen->format->Gmask,
_hwscreen->format->Bmask,
_hwscreen->format->Amask);
_hwScreen->format->Rmask,
_hwScreen->format->Gmask,
_hwScreen->format->Bmask,
_hwScreen->format->Amask);
if (_mouseOrigSurface == NULL)
error("allocating _mouseOrigSurface failed");
@ -2057,7 +1944,7 @@ void SurfaceSdlGraphicsManager::blitCursor() {
if (!_mouseOrigSurface || !_mouseData)
return;
_mouseNeedsRedraw = true;
_cursorNeedsRedraw = true;
w = _mouseCurState.w;
h = _mouseCurState.h;
@ -2159,10 +2046,10 @@ void SurfaceSdlGraphicsManager::blitCursor() {
_mouseCurState.rW,
_mouseCurState.rH,
16,
_hwscreen->format->Rmask,
_hwscreen->format->Gmask,
_hwscreen->format->Bmask,
_hwscreen->format->Amask);
_hwScreen->format->Rmask,
_hwScreen->format->Gmask,
_hwScreen->format->Bmask,
_hwScreen->format->Amask);
if (_mouseSurface == NULL)
error("allocating _mouseSurface failed");
@ -2245,8 +2132,10 @@ void SurfaceSdlGraphicsManager::drawMouse() {
int scale;
int hotX, hotY;
dst.x = _mouseCurState.x;
dst.y = _mouseCurState.y;
const Common::Point virtualCursor = convertWindowToVirtual(_cursorX, _cursorY);
dst.x = virtualCursor.x;
dst.y = virtualCursor.y;
if (!_overlayVisible) {
scale = _videoMode.scaleFactor;
@ -2286,7 +2175,7 @@ void SurfaceSdlGraphicsManager::drawMouse() {
// Note that SDL_BlitSurface() and addDirtyRect() will both perform any
// clipping necessary
if (SDL_BlitSurface(_mouseSurface, NULL, _hwscreen, &dst) != 0)
if (SDL_BlitSurface(_mouseSurface, NULL, _hwScreen, &dst) != 0)
error("SDL_BlitSurface failed: %s", SDL_GetError());
// The screen will be updated using real surface coordinates, i.e.
@ -2335,14 +2224,14 @@ void SurfaceSdlGraphicsManager::displayMessageOnOSD(const char *msg) {
}
// Clip the rect
if (width > _hwscreen->w)
width = _hwscreen->w;
if (height > _hwscreen->h)
height = _hwscreen->h;
if (width > _hwScreen->w)
width = _hwScreen->w;
if (height > _hwScreen->h)
height = _hwScreen->h;
_osdMessageSurface = SDL_CreateRGBSurface(
SDL_SWSURFACE | SDL_RLEACCEL | SDL_SRCALPHA,
width, height, 16, _hwscreen->format->Rmask, _hwscreen->format->Gmask, _hwscreen->format->Bmask, _hwscreen->format->Amask
width, height, 16, _hwScreen->format->Rmask, _hwScreen->format->Gmask, _hwScreen->format->Bmask, _hwScreen->format->Amask
);
// Lock the surface
@ -2379,8 +2268,8 @@ void SurfaceSdlGraphicsManager::displayMessageOnOSD(const char *msg) {
SDL_Rect SurfaceSdlGraphicsManager::getOSDMessageRect() const {
SDL_Rect rect;
rect.x = (_hwscreen->w - _osdMessageSurface->w) / 2;
rect.y = (_hwscreen->h - _osdMessageSurface->h) / 2;
rect.x = (_hwScreen->w - _osdMessageSurface->w) / 2;
rect.y = (_hwScreen->h - _osdMessageSurface->h) / 2;
rect.w = _osdMessageSurface->w;
rect.h = _osdMessageSurface->h;
return rect;
@ -2393,7 +2282,7 @@ void SurfaceSdlGraphicsManager::displayActivityIconOnOSD(const Graphics::Surface
if (_osdIconSurface && !icon) {
// Force a redraw to clear the icon on the next update
_forceFull = true;
_forceRedraw = true;
}
if (_osdIconSurface) {
@ -2432,7 +2321,7 @@ void SurfaceSdlGraphicsManager::displayActivityIconOnOSD(const Graphics::Surface
SDL_Rect SurfaceSdlGraphicsManager::getOSDIconRect() const {
SDL_Rect dstRect;
dstRect.x = _hwscreen->w - _osdIconSurface->w - 10;
dstRect.x = _hwScreen->w - _osdIconSurface->w - 10;
dstRect.y = 10;
dstRect.w = _osdIconSurface->w;
dstRect.h = _osdIconSurface->h;
@ -2464,7 +2353,7 @@ void SurfaceSdlGraphicsManager::updateOSD() {
_osdMessageAlpha = startAlpha + diff * (SDL_ALPHA_TRANSPARENT - startAlpha) / kOSDFadeOutDuration;
}
SDL_SetAlpha(_osdMessageSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, _osdMessageAlpha);
_forceFull = true;
_forceRedraw = true;
}
if (_osdMessageAlpha == SDL_ALPHA_TRANSPARENT) {
@ -2474,26 +2363,30 @@ void SurfaceSdlGraphicsManager::updateOSD() {
if (_osdIconSurface) {
// Redraw the area below the icon for the transparent blit to give correct results.
_forceFull = true;
_forceRedraw = true;
}
}
void SurfaceSdlGraphicsManager::drawOSD() {
if (_osdMessageSurface) {
SDL_Rect dstRect = getOSDMessageRect();
SDL_BlitSurface(_osdMessageSurface, 0, _hwscreen, &dstRect);
SDL_BlitSurface(_osdMessageSurface, 0, _hwScreen, &dstRect);
}
if (_osdIconSurface) {
SDL_Rect dstRect = getOSDIconRect();
SDL_BlitSurface(_osdIconSurface, 0, _hwscreen, &dstRect);
SDL_BlitSurface(_osdIconSurface, 0, _hwScreen, &dstRect);
}
}
#endif
bool SurfaceSdlGraphicsManager::handleScalerHotkeys(Common::KeyCode key) {
void SurfaceSdlGraphicsManager::handleResizeImpl(const int width, const int height) {
SdlGraphicsManager::handleResizeImpl(width, height);
recalculateDisplayAreas();
}
bool SurfaceSdlGraphicsManager::handleScalerHotkeys(Common::KeyCode key) {
// Ctrl-Alt-a toggles aspect ratio correction
if (key == 'a') {
beginGFXTransaction();
@ -2505,13 +2398,13 @@ bool SurfaceSdlGraphicsManager::handleScalerHotkeys(Common::KeyCode key) {
message = Common::String::format("%s\n%d x %d -> %d x %d",
_("Enabled aspect ratio correction"),
_videoMode.screenWidth, _videoMode.screenHeight,
_hwscreen->w, _hwscreen->h
_hwScreen->w, _hwScreen->h
);
else
message = Common::String::format("%s\n%d x %d -> %d x %d",
_("Disabled aspect ratio correction"),
_videoMode.screenWidth, _videoMode.screenHeight,
_hwscreen->w, _hwscreen->h
_hwScreen->w, _hwScreen->h
);
displayMessageOnOSD(message.c_str());
#endif
@ -2532,7 +2425,7 @@ bool SurfaceSdlGraphicsManager::handleScalerHotkeys(Common::KeyCode key) {
displayMessageOnOSD(_("Filtering disabled"));
}
#endif
_forceFull = true;
_forceRedraw = true;
internUpdateScreen();
return true;
}
@ -2542,12 +2435,19 @@ bool SurfaceSdlGraphicsManager::handleScalerHotkeys(Common::KeyCode key) {
int factor = _videoMode.scaleFactor - 1;
SDLKey sdlKey = (SDLKey)key;
#if SDL_VERSION_ATLEAST(2, 0, 0)
bool sizeChanged = false;
#endif
// Increase/decrease the scale factor
if (sdlKey == SDLK_EQUALS || sdlKey == SDLK_PLUS || sdlKey == SDLK_MINUS ||
sdlKey == SDLK_KP_PLUS || sdlKey == SDLK_KP_MINUS) {
factor += (sdlKey == SDLK_MINUS || sdlKey == SDLK_KP_MINUS) ? -1 : +1;
if (0 <= factor && factor <= 3) {
newMode = s_gfxModeSwitchTable[_scalerType][factor];
#if SDL_VERSION_ATLEAST(2, 0, 0)
sizeChanged = true;
#endif
}
}
@ -2585,10 +2485,19 @@ bool SurfaceSdlGraphicsManager::handleScalerHotkeys(Common::KeyCode key) {
_("Active graphics filter:"),
newScalerName,
_videoMode.screenWidth, _videoMode.screenHeight,
_hwscreen->w, _hwscreen->h);
_hwScreen->w, _hwScreen->h);
displayMessageOnOSD(message.c_str());
}
#endif
#if SDL_VERSION_ATLEAST(2, 0, 0)
if (sizeChanged) {
// Forcibly resizing the window here since a user switching scaler
// size will not normally cause the window to update
_window->createOrUpdateWindow(_hwScreen->w, _hwScreen->h, _lastFlags);
}
#endif
internUpdateScreen();
return true;
@ -2700,37 +2609,11 @@ bool SurfaceSdlGraphicsManager::notifyEvent(const Common::Event &event) {
}
void SurfaceSdlGraphicsManager::notifyVideoExpose() {
_forceFull = true;
_forceRedraw = true;
}
void SurfaceSdlGraphicsManager::notifyResize(const uint width, const uint height) {
#if SDL_VERSION_ATLEAST(2, 0, 0)
setWindowResolution(width, height);
#endif
}
void SurfaceSdlGraphicsManager::transformMouseCoordinates(Common::Point &point) {
#if SDL_VERSION_ATLEAST(2, 0, 0)
// In SDL2 the actual output resolution might be different from what we
// requested. Thus, we transform the coordinates from actual output
// coordinate space into the "virtual" output coordinate space.
// Please note that we ignore the possible existence of black bars here,
// this avoids the feeling of stickyness to black bars.
point.x = point.x * _videoMode.hardwareWidth / _windowWidth;
point.y = point.y * _videoMode.hardwareHeight / _windowHeight;
#endif
if (!_overlayVisible) {
point.x /= _videoMode.scaleFactor;
point.y /= _videoMode.scaleFactor;
if (_videoMode.aspectRatioCorrection)
point.y = aspect2Real(point.y);
}
}
void SurfaceSdlGraphicsManager::notifyMousePos(Common::Point mouse) {
transformMouseCoordinates(mouse);
setMousePos(mouse.x, mouse.y);
void SurfaceSdlGraphicsManager::notifyResize(const int width, const int height) {
handleResize(width, height);
}
#if SDL_VERSION_ATLEAST(2, 0, 0)
@ -2742,39 +2625,6 @@ void SurfaceSdlGraphicsManager::deinitializeRenderer() {
_renderer = nullptr;
}
void SurfaceSdlGraphicsManager::setWindowResolution(int width, int height) {
_windowWidth = width;
_windowHeight = height;
// We expect full screen resolution as inputs coming from the event system.
_eventSource->resetKeyboardEmulation(_windowWidth - 1, _windowHeight - 1);
// Calculate the "viewport" for the actual area we draw in. In fullscreen
// we can easily get a different resolution than what we requested. In
// this case, we add black bars if necessary to assure the aspect ratio
// is preserved.
const frac_t outputAspect = intToFrac(_windowWidth) / _windowHeight;
const frac_t desiredAspect = intToFrac(_videoMode.hardwareWidth) / _videoMode.hardwareHeight;
_viewport.w = _windowWidth;
_viewport.h = _windowHeight;
// Adjust one dimension for mantaining the aspect ratio.
if (abs(outputAspect - desiredAspect) >= (int)(FRAC_ONE / 1000)) {
if (outputAspect < desiredAspect) {
_viewport.h = _videoMode.hardwareHeight * _windowWidth / _videoMode.hardwareWidth;
} else if (outputAspect > desiredAspect) {
_viewport.w = _videoMode.hardwareWidth * _windowHeight / _videoMode.hardwareHeight;
}
}
_viewport.x = (_windowWidth - _viewport.w) / 2;
_viewport.y = (_windowHeight - _viewport.h) / 2;
// Force a full redraw because we changed the viewport.
_forceFull = true;
}
void SurfaceSdlGraphicsManager::recreateScreenTexture() {
if (!_renderer)
return;
@ -2807,8 +2657,8 @@ SDL_Surface *SurfaceSdlGraphicsManager::SDL_SetVideoMode(int width, int height,
return nullptr;
}
SDL_GetWindowSize(_window->getSDLWindow(), &_windowWidth, &_windowHeight);
setWindowResolution(_windowWidth, _windowHeight);
getWindowSizeFromSdl(&_windowWidth, &_windowHeight);
handleResize(_windowWidth, _windowHeight);
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, _videoMode.filtering ? "linear" : "nearest");
@ -2830,8 +2680,14 @@ SDL_Surface *SurfaceSdlGraphicsManager::SDL_SetVideoMode(int width, int height,
void SurfaceSdlGraphicsManager::SDL_UpdateRects(SDL_Surface *screen, int numrects, SDL_Rect *rects) {
SDL_UpdateTexture(_screenTexture, nullptr, screen->pixels, screen->pitch);
SDL_Rect viewport;
viewport.x = _activeArea.drawRect.left;
viewport.y = _activeArea.drawRect.top;
viewport.w = _activeArea.drawRect.width();
viewport.h = _activeArea.drawRect.height();
SDL_RenderClear(_renderer);
SDL_RenderCopy(_renderer, _screenTexture, NULL, &_viewport);
SDL_RenderCopy(_renderer, _screenTexture, NULL, &viewport);
SDL_RenderPresent(_renderer);
}
#endif // SDL_VERSION_ATLEAST(2, 0, 0)

View File

@ -40,7 +40,6 @@
#endif
#if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
// Uncomment this to enable the 'on screen display' code.
#define USE_OSD 1
#endif
@ -80,76 +79,71 @@ public:
SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window);
virtual ~SurfaceSdlGraphicsManager();
virtual void activateManager();
virtual void deactivateManager();
virtual void activateManager() override;
virtual void deactivateManager() override;
virtual bool hasFeature(OSystem::Feature f);
virtual void setFeatureState(OSystem::Feature f, bool enable);
virtual bool getFeatureState(OSystem::Feature f);
virtual bool hasFeature(OSystem::Feature f) const override;
virtual void setFeatureState(OSystem::Feature f, bool enable) override;
virtual bool getFeatureState(OSystem::Feature f) const override;
virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const;
virtual int getDefaultGraphicsMode() const;
virtual bool setGraphicsMode(int mode);
virtual int getGraphicsMode() const;
virtual void resetGraphicsScale();
virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const override;
virtual int getDefaultGraphicsMode() const override;
virtual bool setGraphicsMode(int mode) override;
virtual int getGraphicsMode() const override;
virtual void resetGraphicsScale() override;
#ifdef USE_RGB_COLOR
virtual Graphics::PixelFormat getScreenFormat() const { return _screenFormat; }
virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const;
virtual Graphics::PixelFormat getScreenFormat() const override { return _screenFormat; }
virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const override;
#endif
virtual const OSystem::GraphicsMode *getSupportedShaders() const;
virtual int getShader() const;
virtual bool setShader(int id);
virtual void initSize(uint w, uint h, const Graphics::PixelFormat *format = NULL);
virtual int getScreenChangeID() const { return _screenChangeCount; }
virtual const OSystem::GraphicsMode *getSupportedShaders() const override;
virtual int getShader() const override;
virtual bool setShader(int id) override;
virtual void initSize(uint w, uint h, const Graphics::PixelFormat *format = NULL) override;
virtual int getScreenChangeID() const override { return _screenChangeCount; }
virtual void beginGFXTransaction();
virtual OSystem::TransactionError endGFXTransaction();
virtual void beginGFXTransaction() override;
virtual OSystem::TransactionError endGFXTransaction() override;
virtual int16 getHeight();
virtual int16 getWidth();
virtual int16 getHeight() const override;
virtual int16 getWidth() const override;
protected:
// PaletteManager API
virtual void setPalette(const byte *colors, uint start, uint num);
virtual void grabPalette(byte *colors, uint start, uint num);
virtual void setPalette(const byte *colors, uint start, uint num) override;
virtual void grabPalette(byte *colors, uint start, uint num) const override;
public:
virtual void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h);
virtual Graphics::Surface *lockScreen();
virtual void unlockScreen();
virtual void fillScreen(uint32 col);
virtual void updateScreen();
virtual void setShakePos(int shakeOffset);
virtual void setFocusRectangle(const Common::Rect& rect);
virtual void clearFocusRectangle();
virtual void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) override;
virtual Graphics::Surface *lockScreen() override;
virtual void unlockScreen() override;
virtual void fillScreen(uint32 col) override;
virtual void updateScreen() override;
virtual void setShakePos(int shakeOffset) override;
virtual void setFocusRectangle(const Common::Rect& rect) override;
virtual void clearFocusRectangle() override;
virtual void showOverlay();
virtual void hideOverlay();
virtual Graphics::PixelFormat getOverlayFormat() const { return _overlayFormat; }
virtual void clearOverlay();
virtual void grabOverlay(void *buf, int pitch);
virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h);
virtual int16 getOverlayHeight() { return _videoMode.overlayHeight; }
virtual int16 getOverlayWidth() { return _videoMode.overlayWidth; }
virtual Graphics::PixelFormat getOverlayFormat() const override { return _overlayFormat; }
virtual void clearOverlay() 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 int16 getOverlayHeight() const override { return _videoMode.overlayHeight; }
virtual int16 getOverlayWidth() const override { return _videoMode.overlayWidth; }
virtual bool showMouse(bool visible);
virtual void warpMouse(int x, int y);
virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL);
virtual void setCursorPalette(const byte *colors, uint start, uint num);
virtual bool showMouse(bool visible) override;
virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL) override;
virtual void setCursorPalette(const byte *colors, uint start, uint num) override;
#ifdef USE_OSD
virtual void displayMessageOnOSD(const char *msg);
virtual void displayActivityIconOnOSD(const Graphics::Surface *icon);
virtual void displayMessageOnOSD(const char *msg) override;
virtual void displayActivityIconOnOSD(const Graphics::Surface *icon) override;
#endif
// Override from Common::EventObserver
bool notifyEvent(const Common::Event &event);
virtual bool notifyEvent(const Common::Event &event) override;
// SdlGraphicsManager interface
virtual void notifyVideoExpose();
virtual void notifyResize(const uint width, const uint height);
virtual void transformMouseCoordinates(Common::Point &point);
virtual void notifyMousePos(Common::Point mouse);
virtual void notifyVideoExpose() override;
virtual void notifyResize(const int width, const int height) override;
protected:
#ifdef USE_OSD
@ -178,8 +172,11 @@ protected:
void drawOSD();
#endif
/** Hardware screen */
SDL_Surface *_hwscreen;
virtual bool gameNeedsAspectRatioCorrection() const override {
return _videoMode.aspectRatioCorrection;
}
virtual void handleResizeImpl(const int width, const int height) override;
virtual int getGraphicsModeScale(int mode) const override;
@ -188,10 +185,7 @@ protected:
* around this API to keep the code paths as close as possible. */
SDL_Renderer *_renderer;
SDL_Texture *_screenTexture;
SDL_Rect _viewport;
int _windowWidth, _windowHeight;
void deinitializeRenderer();
void setWindowResolution(int width, int height);
void recreateScreenTexture();
virtual SDL_Surface *SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags);
@ -218,7 +212,6 @@ protected:
SDL_Surface *_tmpscreen2;
SDL_Surface *_overlayscreen;
bool _overlayVisible;
Graphics::PixelFormat _overlayFormat;
enum {
@ -280,14 +273,11 @@ protected:
uint8 _originalBitsPerPixel;
#endif
/** Force full redraw on next updateScreen */
bool _forceFull;
ScalerProc *_scalerProc;
int _scalerType;
int _transactionMode;
// Indicates whether it is needed to free _hwsurface in destructor
// Indicates whether it is needed to free _hwSurface in destructor
bool _displayDisabled;
bool _screenIsLocked;
@ -308,10 +298,6 @@ protected:
int _numDirtyRects;
struct MousePos {
// The mouse position, using either virtual (game) or real
// (overlay) coordinates.
int16 x, y;
// The size and hotspot of the original cursor image.
int16 w, h;
int16 hotX, hotY;
@ -326,14 +312,13 @@ protected:
int16 vW, vH;
int16 vHotX, vHotY;
MousePos() : x(0), y(0), w(0), h(0), hotX(0), hotY(0),
MousePos() : w(0), h(0), hotX(0), hotY(0),
rW(0), rH(0), rHotX(0), rHotY(0), vW(0), vH(0),
vHotX(0), vHotY(0)
{ }
};
bool _mouseVisible;
bool _mouseNeedsRedraw;
byte *_mouseData;
SDL_Rect _mouseBackup;
MousePos _mouseCurState;
@ -386,21 +371,45 @@ protected:
virtual void unloadGFXMode();
virtual bool hotswapGFXMode();
virtual void setFullscreenMode(bool enable);
virtual void setAspectRatioCorrection(bool enable);
#if SDL_VERSION_ATLEAST(2, 0, 0)
virtual void setFilteringMode(bool enable);
void setFilteringMode(bool enable);
#endif
virtual int effectiveScreenHeight() const;
virtual bool saveScreenshot(const char *filename);
virtual void setGraphicsModeIntern();
virtual bool handleScalerHotkeys(Common::KeyCode key);
virtual bool isScalerHotkey(const Common::Event &event);
virtual void setMousePos(int x, int y);
virtual void toggleFullScreen();
virtual bool saveScreenshot(const char *filename);
private:
void setFullscreenMode(bool enable);
bool handleScalerHotkeys(Common::KeyCode key);
bool isScalerHotkey(const Common::Event &event);
void toggleFullScreen();
/**
* Converts the given point from the overlay's coordinate space to the
* game's coordinate space.
*/
Common::Point convertOverlayToGame(const int x, const int y) const {
if (getOverlayWidth() == 0 || getOverlayHeight() == 0) {
error("convertOverlayToGame called without a valid overlay");
}
return Common::Point(x * getWidth() / getOverlayWidth(),
y * getHeight() / getOverlayHeight());
}
/**
* Converts the given point from the game's coordinate space to the
* overlay's coordinate space.
*/
Common::Point convertGameToOverlay(const int x, const int y) const {
if (getWidth() == 0 || getHeight() == 0) {
error("convertGameToOverlay called without a valid overlay");
}
return Common::Point(x * getOverlayWidth() / getWidth(),
y * getOverlayHeight() / getHeight());
}
};
#endif

View File

@ -0,0 +1,313 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef BACKENDS_GRAPHICS_WINDOWED_H
#define BACKENDS_GRAPHICS_WINDOWED_H
#include "backends/graphics/graphics.h"
#include "common/frac.h"
#include "common/rect.h"
#include "common/textconsole.h"
#include "graphics/scaler/aspect.h"
class WindowedGraphicsManager : virtual public GraphicsManager {
public:
WindowedGraphicsManager() :
_windowWidth(0),
_windowHeight(0),
_overlayVisible(false),
_forceRedraw(false),
_cursorX(0),
_cursorY(0),
_cursorNeedsRedraw(false) {}
virtual void showOverlay() override {
if (_overlayVisible)
return;
_activeArea.drawRect = _overlayDrawRect;
_activeArea.width = getOverlayWidth();
_activeArea.height = getOverlayHeight();
_overlayVisible = true;
_forceRedraw = true;
}
virtual void hideOverlay() override {
if (!_overlayVisible)
return;
_activeArea.drawRect = _gameDrawRect;
_activeArea.width = getWidth();
_activeArea.height = getHeight();
_overlayVisible = false;
_forceRedraw = true;
}
protected:
/**
* @returns whether or not the game screen must have aspect ratio correction
* applied for correct rendering.
*/
virtual bool gameNeedsAspectRatioCorrection() const = 0;
/**
* Backend-specific implementation for updating internal surfaces that need
* to reflect the new window size.
*/
virtual void handleResizeImpl(const int width, const int height) = 0;
/**
* Converts the given point from the active virtual screen's coordinate
* space to the window's coordinate space (i.e. game-to-window or
* overlay-to-window).
*/
Common::Point convertVirtualToWindow(const int x, const int y) const {
const int targetX = _activeArea.drawRect.left;
const int targetY = _activeArea.drawRect.top;
const int targetWidth = _activeArea.drawRect.width();
const int targetHeight = _activeArea.drawRect.height();
const int sourceWidth = _activeArea.width;
const int sourceHeight = _activeArea.height;
if (sourceWidth == 0 || sourceHeight == 0) {
error("convertVirtualToWindow called without a valid draw rect");
}
return Common::Point(targetX + x * targetWidth / sourceWidth,
targetY + y * targetHeight / sourceHeight);
}
/**
* Converts the given point from the window's coordinate space to the
* active virtual screen's coordinate space (i.e. window-to-game or
* window-to-overlay).
*/
Common::Point convertWindowToVirtual(int x, int y) const {
const int sourceX = _activeArea.drawRect.left;
const int sourceY = _activeArea.drawRect.top;
const int sourceMaxX = _activeArea.drawRect.right - 1;
const int sourceMaxY = _activeArea.drawRect.bottom - 1;
const int sourceWidth = _activeArea.drawRect.width();
const int sourceHeight = _activeArea.drawRect.height();
const int targetWidth = _activeArea.width;
const int targetHeight = _activeArea.height;
if (sourceWidth == 0 || sourceHeight == 0) {
error("convertWindowToVirtual called without a valid draw rect");
}
x = CLIP<int>(x, sourceX, sourceMaxX);
y = CLIP<int>(y, sourceY, sourceMaxY);
return Common::Point(((x - sourceX) * targetWidth) / sourceWidth,
((y - sourceY) * targetHeight) / sourceHeight);
}
/**
* @returns the desired aspect ratio of the game surface.
*/
frac_t getDesiredGameAspectRatio() const {
if (getHeight() == 0 || gameNeedsAspectRatioCorrection()) {
return intToFrac(4) / 3;
}
return intToFrac(getWidth()) / getHeight();
}
/**
* Called after the window has been updated with new dimensions.
*
* @param width The new width of the window, excluding window decoration.
* @param height The new height of the window, excluding window decoration.
*/
void handleResize(const int width, const int height) {
_windowWidth = width;
_windowHeight = height;
handleResizeImpl(width, height);
}
/**
* Recalculates the display areas for the game and overlay surfaces within
* the window.
*/
virtual void recalculateDisplayAreas() {
if (_windowHeight == 0) {
return;
}
const frac_t outputAspect = intToFrac(_windowWidth) / _windowHeight;
populateDisplayAreaDrawRect(getDesiredGameAspectRatio(), outputAspect, _gameDrawRect);
if (getOverlayHeight()) {
const frac_t overlayAspect = intToFrac(getOverlayWidth()) / getOverlayHeight();
populateDisplayAreaDrawRect(overlayAspect, outputAspect, _overlayDrawRect);
}
if (_overlayVisible) {
_activeArea.drawRect = _overlayDrawRect;
_activeArea.width = getOverlayWidth();
_activeArea.height = getOverlayHeight();
} else {
_activeArea.drawRect = _gameDrawRect;
_activeArea.width = getWidth();
_activeArea.height = getHeight();
}
}
/**
* Sets the position of the hardware mouse cursor in the host system,
* relative to the window.
*
* @param x X coordinate in window coordinates.
* @param y Y coordinate in window coordinates.
*/
virtual void setSystemMousePosition(const int x, const int y) = 0;
/**
* Move ("warp") the mouse cursor to the specified position.
*
* @param x The new X position of the mouse in virtual screen coordinates.
* @param y The new Y position of the mouse in virtual screen coordinates.
*/
void warpMouse(const int x, const int y) {
// Check active coordinate instead of window coordinate to avoid warping
// the mouse if it is still within the same virtual pixel
const Common::Point virtualCursor = convertWindowToVirtual(_cursorX, _cursorY);
if (virtualCursor.x != x || virtualCursor.y != y) {
// Warping the mouse in SDL generates a mouse movement event, so
// `setMousePosition` would be called eventually through the
// `notifyMousePosition` callback if we *only* set the system mouse
// position here. However, this can cause problems with some games.
// For example, the cannon script in CoMI calls to warp the mouse
// twice each time the cannon is reloaded, and unless we update the
// mouse position immediately, the second call is ignored, which
// causes the cannon to change its aim.
const Common::Point windowCursor = convertVirtualToWindow(x, y);
setMousePosition(windowCursor.x, windowCursor.y);
setSystemMousePosition(windowCursor.x, windowCursor.y);
}
}
/**
* Sets the position of the rendered mouse cursor in the window.
*
* @param x X coordinate in window coordinates.
* @param y Y coordinate in window coordinates.
*/
void setMousePosition(int x, int y) {
if (_cursorX != x || _cursorY != y) {
_cursorNeedsRedraw = true;
}
_cursorX = x;
_cursorY = y;
}
/**
* The width of the window, excluding window decoration.
*/
int _windowWidth;
/**
* The height of the window, excluding window decoration.
*/
int _windowHeight;
/**
* Whether the overlay (i.e. launcher, including the out-of-game launcher)
* is visible or not.
*/
bool _overlayVisible;
/**
* The scaled draw rectangle for the game surface within the window.
*/
Common::Rect _gameDrawRect;
/**
* The scaled draw rectangle for the overlay (launcher) surface within the
* window.
*/
Common::Rect _overlayDrawRect;
/**
* Data about the display area of a virtual screen.
*/
struct DisplayArea {
/**
* The scaled area where the virtual screen is drawn within the window.
*/
Common::Rect drawRect;
/**
* The width of the virtual screen's unscaled coordinate space.
*/
int width;
/**
* The height of the virtual screen's unscaled coordinate space.
*/
int height;
};
/**
* Display area information about the currently active virtual screen. This
* will be the overlay screen when the overlay is active, and the game
* screen otherwise.
*/
DisplayArea _activeArea;
/**
* Whether the screen must be redrawn on the next frame.
*/
bool _forceRedraw;
/**
* Whether the mouse cursor needs to be redrawn on the next frame.
*/
bool _cursorNeedsRedraw;
/**
* The position of the mouse cursor, in window coordinates.
*/
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);
}
drawRect.left = (_windowWidth - width) / 2;
drawRect.top = (_windowHeight - height) / 2;
drawRect.setWidth(width);
drawRect.setHeight(height);
}
};
#endif

View File

@ -135,8 +135,10 @@ void SdlWindow::toggleMouseGrab() {
#else
if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF) {
SDL_WM_GrabInput(SDL_GRAB_ON);
_inputGrabState = true;
} else {
SDL_WM_GrabInput(SDL_GRAB_OFF);
_inputGrabState = false;
}
#endif
}
@ -154,13 +156,15 @@ bool SdlWindow::hasMouseFocus() const {
}
void SdlWindow::warpMouseInWindow(int x, int y) {
if (hasMouseFocus()) {
#if SDL_VERSION_ATLEAST(2, 0, 0)
if (_window && hasMouseFocus()) {
SDL_WarpMouseInWindow(_window, x, y);
}
if (_window) {
SDL_WarpMouseInWindow(_window, x, y);
}
#else
SDL_WarpMouse(x, y);
SDL_WarpMouse(x, y);
#endif
}
}
void SdlWindow::iconifyWindow() {

View File

@ -56,7 +56,8 @@ public:
bool hasMouseFocus() const;
/**
* Warp the mouse to the specified position in window coordinates.
* Warp the mouse to the specified position in window coordinates. The mouse
* will only be warped if the window is focused in the window manager.
*/
void warpMouseInWindow(int x, int y);
@ -73,6 +74,11 @@ public:
*/
bool getSDLWMInformation(SDL_SysWMinfo *info) const;
bool mouseIsGrabbed() const { return _inputGrabState; }
private:
bool _inputGrabState;
#if SDL_VERSION_ATLEAST(2, 0, 0)
public:
/**
@ -108,7 +114,6 @@ private:
*/
int _lastX, _lastY;
bool _inputGrabState;
Common::String _windowCaption;
#endif
};

View File

@ -96,7 +96,7 @@ public:
*
* @see getScreenFormat
*/
virtual void grabPalette(byte *colors, uint start, uint num) = 0;
virtual void grabPalette(byte *colors, uint start, uint num) const = 0;
};
#endif