Skip to content

Commit

Permalink
SDL, COMMON: Support screen rotation
Browse files Browse the repository at this point in the history
  • Loading branch information
phcoder committed Sep 28, 2024
1 parent 1baf441 commit e107235
Show file tree
Hide file tree
Showing 26 changed files with 393 additions and 34 deletions.
2 changes: 2 additions & 0 deletions backends/graphics/graphics.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "common/system.h"
#include "common/noncopyable.h"
#include "common/keyboard.h"
#include "common/rotationmode.h"

#include "graphics/mode.h"
#include "graphics/paletteman.h"
Expand Down Expand Up @@ -59,6 +60,7 @@ class GraphicsManager : public PaletteManager {
virtual int getDefaultStretchMode() const { return 0; }
virtual bool setStretchMode(int mode) { return false; }
virtual int getStretchMode() const { return 0; }
virtual Common::RotationMode getRotationMode() const { return Common::kRotationNormal; }
virtual uint getDefaultScaler() const { return 0; }
virtual uint getDefaultScaleFactor() const { return 1; }
virtual bool setScaler(uint mode, int factor) { return false; }
Expand Down
40 changes: 38 additions & 2 deletions backends/graphics/opengl/framebuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "backends/graphics/opengl/pipelines/pipeline.h"
#include "backends/graphics/opengl/texture.h"
#include "graphics/opengl/debug.h"
#include "common/rotationmode.h"

namespace OpenGL {

Expand Down Expand Up @@ -188,7 +189,7 @@ void Backbuffer::activateInternal() {
#endif
}

bool Backbuffer::setSize(uint width, uint height) {
bool Backbuffer::setSize(uint width, uint height, Common::RotationMode rotation) {
// Set viewport dimensions.
_viewport[0] = 0;
_viewport[1] = 0;
Expand Down Expand Up @@ -216,6 +217,41 @@ bool Backbuffer::setSize(uint width, uint height) {
_projectionMatrix(3, 2) = 0.0f;
_projectionMatrix(3, 3) = 1.0f;

switch (rotation) {
default:
_projectionMatrix(0, 0) = 2.0f / width;
_projectionMatrix(0, 1) = 0.0f;
_projectionMatrix(1, 0) = 0.0f;
_projectionMatrix(1, 1) = -2.0f / height;
_projectionMatrix(3, 0) = -1.0f;
_projectionMatrix(3, 1) = 1.0f;
break;
case Common::kRotation90:
_projectionMatrix(0, 0) = 0.0f;
_projectionMatrix(0, 1) = -2.0f / height;
_projectionMatrix(1, 0) = -2.0f / width;
_projectionMatrix(1, 1) = 0.0f;
_projectionMatrix(3, 0) = 1.0f;
_projectionMatrix(3, 1) = 1.0f;
break;
case Common::kRotation180:
_projectionMatrix(0, 0) = -2.0f / width;
_projectionMatrix(0, 1) = 0.0f;
_projectionMatrix(1, 0) = 0.0f;
_projectionMatrix(1, 1) = 2.0f / height;
_projectionMatrix(3, 0) = 1.0f;
_projectionMatrix(3, 1) = -1.0f;
break;
case Common::kRotation270:
_projectionMatrix(0, 0) = 0.0f;
_projectionMatrix(0, 1) = 2.0f / height;
_projectionMatrix(1, 0) = 2.0f / width;
_projectionMatrix(1, 1) = 0.0f;
_projectionMatrix(3, 0) = -1.0f;
_projectionMatrix(3, 1) = -1.0f;
break;
}

// Directly apply changes when we are active.
if (isActive()) {
applyViewport();
Expand Down Expand Up @@ -268,7 +304,7 @@ void TextureTarget::create() {
_needUpdate = true;
}

bool TextureTarget::setSize(uint width, uint height) {
bool TextureTarget::setSize(uint width, uint height, Common::RotationMode rotation) {
if (!_texture->setSize(width, height)) {
return false;
}
Expand Down
8 changes: 5 additions & 3 deletions backends/graphics/opengl/framebuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@

#include "math/matrix4.h"

#include "common/rotationmode.h"

namespace OpenGL {

class Pipeline;
Expand Down Expand Up @@ -147,7 +149,7 @@ class Framebuffer {
/**
* Set the size of the target buffer.
*/
virtual bool setSize(uint width, uint height) = 0;
virtual bool setSize(uint width, uint height, Common::RotationMode rotation) = 0;

/**
* Accessor to activate framebuffer for pipeline.
Expand Down Expand Up @@ -183,7 +185,7 @@ class Backbuffer : public Framebuffer {
/**
* Set the size of the back buffer.
*/
bool setSize(uint width, uint height) override;
bool setSize(uint width, uint height, Common::RotationMode rotation) override;

protected:
void activateInternal() override;
Expand Down Expand Up @@ -216,7 +218,7 @@ class TextureTarget : public Framebuffer {
/**
* Set size of the texture target.
*/
bool setSize(uint width, uint height) override;
bool setSize(uint width, uint height, Common::RotationMode rotation) override;

/**
* Query pointer to underlying GL texture.
Expand Down
53 changes: 42 additions & 11 deletions backends/graphics/opengl/opengl-graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,15 @@ void OpenGLGraphicsManager::renderCursor() {
}

void OpenGLGraphicsManager::updateScreen() {
int rotation = getRotationMode();
int rotatedWidth = _windowWidth;
int rotatedHeight = _windowHeight;

if (rotation == Common::kRotation90 || rotation == Common::kRotation270) {
rotatedWidth = _windowHeight;
rotatedHeight = _windowWidth;
}

if (!_gameScreen || !_pipeline) {
return;
}
Expand Down Expand Up @@ -726,8 +735,8 @@ void OpenGLGraphicsManager::updateScreen() {

// Third step: Draw the overlay if visible.
if (_overlayVisible) {
int dstX = (_windowWidth - _overlayDrawRect.width()) / 2;
int dstY = (_windowHeight - _overlayDrawRect.height()) / 2;
int dstX = (rotatedWidth - _overlayDrawRect.width()) / 2;
int dstY = (rotatedHeight - _overlayDrawRect.height()) / 2;
_targetBuffer->enableBlend(Framebuffer::kBlendModeTraditionalTransparency);
_pipeline->drawTexture(_overlay->getGLTexture(), dstX, dstY, _overlayDrawRect.width(), _overlayDrawRect.height());
}
Expand Down Expand Up @@ -762,8 +771,8 @@ void OpenGLGraphicsManager::updateScreen() {
// Set the OSD transparency.
_pipeline->setColor(1.0f, 1.0f, 1.0f, _osdMessageAlpha / 100.0f);

int dstX = (_windowWidth - _osdMessageSurface->getWidth()) / 2;
int dstY = (_windowHeight - _osdMessageSurface->getHeight()) / 2;
int dstX = (rotatedWidth - _osdMessageSurface->getWidth()) / 2;
int dstY = (rotatedHeight - _osdMessageSurface->getHeight()) / 2;

// Draw the OSD texture.
_pipeline->drawTexture(_osdMessageSurface->getGLTexture(),
Expand All @@ -783,7 +792,7 @@ void OpenGLGraphicsManager::updateScreen() {
}

if (_osdIconSurface) {
int dstX = _windowWidth - _osdIconSurface->getWidth() - kOSDIconRightMargin;
int dstX = rotatedWidth - _osdIconSurface->getWidth() - kOSDIconRightMargin;
int dstY = kOSDIconTopMargin;

// Draw the OSD icon texture.
Expand Down Expand Up @@ -1267,11 +1276,22 @@ void OpenGLGraphicsManager::grabPalette(byte *colors, uint start, uint num) cons

void OpenGLGraphicsManager::handleResizeImpl(const int width, const int height) {
// Setup backbuffer size.
_targetBuffer->setSize(width, height);
_targetBuffer->setSize(width, height, getRotationMode());

int rotation = getRotationMode();
uint overlayWidth = width;
uint overlayHeight = height;

int rotatedWidth = _windowWidth;
int rotatedHeight = _windowHeight;

if (rotation == Common::kRotation90 || rotation == Common::kRotation270) {
overlayWidth = height;
overlayHeight = width;
rotatedWidth = _windowHeight;
rotatedHeight = _windowWidth;
}

// WORKAROUND: We can only support surfaces up to the maximum supported
// texture size. Thus, in case we encounter a physical size bigger than
// this maximum texture size we will simply use an overlay as big as
Expand All @@ -1280,7 +1300,7 @@ void OpenGLGraphicsManager::handleResizeImpl(const int width, const int height)
// anyway. Thus, it should not be a real issue for modern hardware.
if ( overlayWidth > (uint)OpenGLContext.maxTextureSize
|| overlayHeight > (uint)OpenGLContext.maxTextureSize) {
const frac_t outputAspect = intToFrac(_windowWidth) / _windowHeight;
const frac_t outputAspect = intToFrac(rotatedWidth) / rotatedHeight;

if (outputAspect > (frac_t)FRAC_ONE) {
overlayWidth = OpenGLContext.maxTextureSize;
Expand Down Expand Up @@ -1648,10 +1668,21 @@ void OpenGLGraphicsManager::recalculateDisplayAreas() {
// Setup drawing limitation for game graphics.
// This involves some trickery because OpenGL's viewport coordinate system
// is upside down compared to ours.
_targetBuffer->setScissorBox(_gameDrawRect.left,
_windowHeight - _gameDrawRect.height() - _gameDrawRect.top,
_gameDrawRect.width(),
_gameDrawRect.height());
switch (getRotationMode()) {
case Common::kRotation90:
case Common::kRotation180:
_targetBuffer->setScissorBox(_gameDrawRect.top,
_gameDrawRect.left,
_gameDrawRect.height(),
_gameDrawRect.width());
break;
default:
_targetBuffer->setScissorBox(_gameDrawRect.left,
_windowHeight - _gameDrawRect.height() - _gameDrawRect.top,
_gameDrawRect.width(),
_gameDrawRect.height());
}


_shakeOffsetScaled = Common::Point(_gameScreenShakeXOffset * _gameDrawRect.width() / (int)_currentState.gameWidth,
_gameScreenShakeYOffset * _gameDrawRect.height() / (int)_currentState.gameHeight);
Expand Down
2 changes: 1 addition & 1 deletion backends/graphics/opengl/pipelines/libretro.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,7 @@ bool LibRetroPipeline::setupFBOs() {
pass.shaderPass->applyScale(sourceW, sourceH, viewportW, viewportH, &sourceW, &sourceH);

// Resize FBO to fit the output of the pass.
if (!pass.target->setSize((uint)sourceW, (uint)sourceH)) {
if (!pass.target->setSize((uint)sourceW, (uint)sourceH, Common::kRotationNormal)) {
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion backends/graphics/opengl/texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -756,7 +756,7 @@ void TextureCLUT8GPU::enableLinearFiltering(bool enable) {
void TextureCLUT8GPU::allocate(uint width, uint height) {
// Assure the texture can contain our user data.
_clut8Texture.setSize(width, height);
_target->setSize(width, height);
_target->setSize(width, height, Common::kRotationNormal);

// In case the needed texture dimension changed we will reinitialize the
// texture data buffer.
Expand Down
5 changes: 5 additions & 0 deletions backends/graphics/openglsdl/openglsdl-graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ bool OpenGLSdlGraphicsManager::hasFeature(OSystem::Feature f) const {
case OSystem::kFeatureVSync:
#if SDL_VERSION_ATLEAST(2, 0, 0)
case OSystem::kFeatureFullscreenToggleKeepsContext:
case OSystem::kFeatureRotationMode:
#endif
return true;

Expand All @@ -242,6 +243,10 @@ void OpenGLSdlGraphicsManager::setFeatureState(OSystem::Feature f, bool enable)
}
break;

case OSystem::kFeatureRotationMode:
notifyResize(getWindowWidth(), getWindowHeight());
break;

default:
OpenGLGraphicsManager::setFeatureState(f, enable);
}
Expand Down
38 changes: 36 additions & 2 deletions backends/graphics/sdl/sdl-graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@ SdlGraphicsManager::State SdlGraphicsManager::getState() const {
return state;
}

Common::RotationMode SdlGraphicsManager::getRotationMode() const {
#if SDL_VERSION_ATLEAST(2, 0, 0)
return Common::parseRotationMode(ConfMan.getInt("rotation_mode"));
#else
return kRotationNormal;
#endif
}

bool SdlGraphicsManager::setState(const State &state) {
beginGFXTransaction();
#ifdef USE_RGB_COLOR
Expand Down Expand Up @@ -218,8 +226,27 @@ bool SdlGraphicsManager::lockMouse(bool lock) {
}

bool SdlGraphicsManager::notifyMousePosition(Common::Point &mouse) {
mouse.x = CLIP<int16>(mouse.x, 0, _windowWidth - 1);
mouse.y = CLIP<int16>(mouse.y, 0, _windowHeight - 1);
switch (getRotationMode()) {
case Common::kRotationNormal:
break;
case Common::kRotation90: {
int x0 = mouse.x, y0 = mouse.y;
mouse.x = CLIP<int16>(y0, 0, _windowHeight - 1);
mouse.y = CLIP<int16>(_windowWidth - 1 - x0, 0, _windowWidth - 1);
break;
}
case Common::kRotation180: {
mouse.x = CLIP<int16>(_windowWidth - 1 - mouse.x, 0, _windowWidth - 1);
mouse.y = CLIP<int16>(_windowHeight - 1 - mouse.y, 0, _windowHeight - 1);
break;
}
case Common::kRotation270: {
int x0 = mouse.x, y0 = mouse.y;
mouse.x = CLIP<int16>(_windowHeight - 1 - y0, 0, _windowHeight - 1);
mouse.y = CLIP<int16>(x0, 0, _windowWidth - 1);
break;
}
}

bool showCursor = false;
// Currently on macOS we need to scale the events for HiDPI screen, but on
Expand Down Expand Up @@ -300,6 +327,13 @@ bool SdlGraphicsManager::createOrUpdateWindow(int width, int height, const Uint3
if (!_window) {
return false;
}
Common::RotationMode rotation = getRotationMode();

if (rotation == Common::kRotation90 || rotation == Common::kRotation270) {
int w = width, h = height;
width = h;
height = w;
}

// width *=3;
// height *=3;
Expand Down
2 changes: 2 additions & 0 deletions backends/graphics/sdl/sdl-graphics.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ class SdlGraphicsManager : virtual public WindowedGraphicsManager, public Common
*/
virtual bool notifyMousePosition(Common::Point &mouse);

Common::RotationMode getRotationMode() const override;

virtual bool showMouse(bool visible) override;
bool lockMouse(bool lock) override;

Expand Down
22 changes: 21 additions & 1 deletion backends/graphics/surfacesdl/surfacesdl-graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ bool SurfaceSdlGraphicsManager::hasFeature(OSystem::Feature f) const {
#if SDL_VERSION_ATLEAST(2, 0, 0)
(f == OSystem::kFeatureFullscreenToggleKeepsContext) ||
(f == OSystem::kFeatureStretchMode) ||
(f == OSystem::kFeatureRotationMode) ||
(f == OSystem::kFeatureVSync) ||
#endif
(f == OSystem::kFeatureCursorPalette) ||
Expand Down Expand Up @@ -247,6 +248,9 @@ void SurfaceSdlGraphicsManager::setFeatureState(OSystem::Feature f, bool enable)
if (enable)
_window->iconifyWindow();
break;
case OSystem::kFeatureRotationMode:
notifyResize(getWindowWidth(), getWindowHeight());
break;
default:
break;
}
Expand Down Expand Up @@ -2908,11 +2912,27 @@ void SurfaceSdlGraphicsManager::SDL_UpdateRects(SDL_Surface *screen, int numrect
Common::Rect &drawRect = (_overlayVisible) ? _overlayDrawRect : _gameDrawRect;
viewport.x = drawRect.left;
viewport.y = drawRect.top;
#if SDL_VERSION_ATLEAST(2, 0, 0)
int rotation = getRotationMode();
int rotangle = 0;
if (rotation == Common::kRotation90 || rotation == Common::kRotation270) {
int delta = (drawRect.width() - drawRect.height()) / 2;
viewport.x = drawRect.top - delta;
viewport.y = drawRect.left + delta;
}
rotangle = rotation;
#endif
viewport.w = drawRect.width();
viewport.h = drawRect.height();

SDL_RenderClear(_renderer);
SDL_RenderCopy(_renderer, _screenTexture, nullptr, &viewport);
#if SDL_VERSION_ATLEAST(2, 0, 0)
if (rotangle != 0)
SDL_RenderCopyEx(_renderer, _screenTexture, nullptr, &viewport, rotangle, nullptr, SDL_FLIP_NONE);
else
#endif
SDL_RenderCopy(_renderer, _screenTexture, nullptr, &viewport);

SDL_RenderPresent(_renderer);
}

Expand Down
Loading

0 comments on commit e107235

Please sign in to comment.