[Scummvm-git-logs] scummvm master -> 488353480fe108078bd53f42749582c059f945cf

bluegr noreply at scummvm.org
Sat Sep 28 23:10:42 UTC 2024


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
488353480f SDL, COMMON: Support screen rotation


Commit: 488353480fe108078bd53f42749582c059f945cf
    https://github.com/scummvm/scummvm/commit/488353480fe108078bd53f42749582c059f945cf
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2024-09-29T02:10:39+03:00

Commit Message:
SDL, COMMON: Support screen rotation

Changed paths:
  A common/rotationmode.cpp
  A common/rotationmode.h
    backends/graphics/graphics.h
    backends/graphics/ios/renderbuffer.cpp
    backends/graphics/ios/renderbuffer.h
    backends/graphics/opengl/framebuffer.cpp
    backends/graphics/opengl/framebuffer.h
    backends/graphics/opengl/opengl-graphics.cpp
    backends/graphics/opengl/pipelines/libretro.cpp
    backends/graphics/opengl/texture.cpp
    backends/graphics/openglsdl/openglsdl-graphics.cpp
    backends/graphics/sdl/sdl-graphics.cpp
    backends/graphics/sdl/sdl-graphics.h
    backends/graphics/surfacesdl/surfacesdl-graphics.cpp
    backends/graphics/windowed.h
    common/module.mk
    common/system.h
    gui/options.cpp
    gui/options.h
    gui/themes/common/highres_layout.stx
    gui/themes/common/lowres_layout.stx
    gui/themes/default.inc
    gui/themes/residualvm.zip
    gui/themes/scummclassic.zip
    gui/themes/scummclassic/classic_layout.stx
    gui/themes/scummclassic/classic_layout_lowres.stx
    gui/themes/scummmodern.zip
    gui/themes/scummremastered.zip


diff --git a/backends/graphics/graphics.h b/backends/graphics/graphics.h
index 463ec7d133d..b4a200cd8a5 100644
--- a/backends/graphics/graphics.h
+++ b/backends/graphics/graphics.h
@@ -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"
@@ -59,6 +60,7 @@ public:
 	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; }
diff --git a/backends/graphics/ios/renderbuffer.cpp b/backends/graphics/ios/renderbuffer.cpp
index 9e568ad358f..b4d2e08cc6a 100644
--- a/backends/graphics/ios/renderbuffer.cpp
+++ b/backends/graphics/ios/renderbuffer.cpp
@@ -53,7 +53,7 @@ void RenderbufferTarget::activateInternal() {
 	}
 }
 
-bool RenderbufferTarget::setSize(uint width, uint height) {
+bool RenderbufferTarget::setSize(uint width, uint height, Common::RotationMode rotation) {
 	// Set viewport dimensions.
 	_viewport[0] = 0;
 	_viewport[1] = 0;
diff --git a/backends/graphics/ios/renderbuffer.h b/backends/graphics/ios/renderbuffer.h
index 0047f9c2f1c..758672d7757 100644
--- a/backends/graphics/ios/renderbuffer.h
+++ b/backends/graphics/ios/renderbuffer.h
@@ -40,7 +40,7 @@ public:
 	/**
 	 * Set size of the render target.
 	 */
-	bool setSize(uint width, uint height) override;
+	bool setSize(uint width, uint height, Common::RotationMode rotation) override;
 
 protected:
 	void activateInternal() override;
diff --git a/backends/graphics/opengl/framebuffer.cpp b/backends/graphics/opengl/framebuffer.cpp
index 3b2b3efe04d..16b61b407ac 100644
--- a/backends/graphics/opengl/framebuffer.cpp
+++ b/backends/graphics/opengl/framebuffer.cpp
@@ -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 {
 
@@ -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;
@@ -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();
@@ -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;
 	}
diff --git a/backends/graphics/opengl/framebuffer.h b/backends/graphics/opengl/framebuffer.h
index 53ef00960db..f9bb5825d44 100644
--- a/backends/graphics/opengl/framebuffer.h
+++ b/backends/graphics/opengl/framebuffer.h
@@ -26,6 +26,8 @@
 
 #include "math/matrix4.h"
 
+#include "common/rotationmode.h"
+
 namespace OpenGL {
 
 class Pipeline;
@@ -147,7 +149,7 @@ public:
 	/**
 	 * 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.
@@ -183,7 +185,7 @@ public:
 	/**
 	 * 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;
@@ -216,7 +218,7 @@ public:
 	/**
 	 * 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.
diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index 101d6519409..0f89cce524f 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -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;
 	}
@@ -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());
 	}
@@ -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(),
@@ -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.
@@ -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
@@ -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;
@@ -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);
diff --git a/backends/graphics/opengl/pipelines/libretro.cpp b/backends/graphics/opengl/pipelines/libretro.cpp
index 9c20a1eef23..635dcf8b5a8 100644
--- a/backends/graphics/opengl/pipelines/libretro.cpp
+++ b/backends/graphics/opengl/pipelines/libretro.cpp
@@ -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;
 		}
 
diff --git a/backends/graphics/opengl/texture.cpp b/backends/graphics/opengl/texture.cpp
index a7ca8ff73ae..4c36455569d 100644
--- a/backends/graphics/opengl/texture.cpp
+++ b/backends/graphics/opengl/texture.cpp
@@ -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.
diff --git a/backends/graphics/openglsdl/openglsdl-graphics.cpp b/backends/graphics/openglsdl/openglsdl-graphics.cpp
index c9f0844a8ae..528886e2fb2 100644
--- a/backends/graphics/openglsdl/openglsdl-graphics.cpp
+++ b/backends/graphics/openglsdl/openglsdl-graphics.cpp
@@ -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;
 
@@ -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);
 	}
diff --git a/backends/graphics/sdl/sdl-graphics.cpp b/backends/graphics/sdl/sdl-graphics.cpp
index 72adec5fa88..516c421c63d 100644
--- a/backends/graphics/sdl/sdl-graphics.cpp
+++ b/backends/graphics/sdl/sdl-graphics.cpp
@@ -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 Common::kRotationNormal;
+#endif
+}
+
 bool SdlGraphicsManager::setState(const State &state) {
 	beginGFXTransaction();
 #ifdef USE_RGB_COLOR
@@ -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
@@ -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;
diff --git a/backends/graphics/sdl/sdl-graphics.h b/backends/graphics/sdl/sdl-graphics.h
index 6774a96830d..6c978a9e129 100644
--- a/backends/graphics/sdl/sdl-graphics.h
+++ b/backends/graphics/sdl/sdl-graphics.h
@@ -91,6 +91,8 @@ public:
 	 */
 	virtual bool notifyMousePosition(Common::Point &mouse);
 
+	Common::RotationMode getRotationMode() const override;
+
 	virtual bool showMouse(bool visible) override;
 	bool lockMouse(bool lock) override;
 
diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp
index aacb0641692..840fee5a82e 100644
--- a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp
+++ b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp
@@ -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) ||
@@ -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;
 	}
@@ -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);
 }
 
diff --git a/backends/graphics/windowed.h b/backends/graphics/windowed.h
index 9f4500b2d1c..e39177c8bdf 100644
--- a/backends/graphics/windowed.h
+++ b/backends/graphics/windowed.h
@@ -408,6 +408,17 @@ protected:
 private:
 	void populateDisplayAreaDrawRect(const frac_t displayAspect, int originalWidth, int originalHeight, Common::Rect &drawRect) const {
 		int mode = getStretchMode();
+		Common::RotationMode rotation = getRotationMode();
+		int rotatedWindowWidth;
+		int rotatedWindowHeight;
+
+		if (rotation == Common::kRotation90 || rotation == Common::kRotation270) {
+			rotatedWindowWidth = _windowHeight;
+			rotatedWindowHeight = _windowWidth;
+		} else {
+			rotatedWindowWidth = _windowWidth;
+			rotatedWindowHeight = _windowHeight;
+		}
 		// Mode Center   = use original size, or divide by an integral amount if window is smaller than game surface
 		// Mode Integral = scale by an integral amount.
 		// Mode Fit      = scale to fit the window while respecting the aspect ratio
@@ -418,30 +429,30 @@ private:
 		if (mode == STRETCH_CENTER || mode == STRETCH_INTEGRAL || mode == STRETCH_INTEGRAL_AR) {
 			width = originalWidth;
 			height = intToFrac(width) / displayAspect;
-			if (width > _windowWidth || height > _windowHeight) {
-				int fac = 1 + MAX((width - 1) / _windowWidth, (height - 1) / _windowHeight);
+			if (width > rotatedWindowWidth || height > rotatedWindowHeight) {
+				int fac = 1 + MAX((width - 1) / rotatedWindowWidth, (height - 1) / rotatedWindowHeight);
 				width /= fac;
 				height /= fac;
 			} else if (mode == STRETCH_INTEGRAL) {
-				int fac = MIN(_windowWidth / width, _windowHeight / height);
+				int fac = MIN(rotatedWindowWidth / width, rotatedWindowHeight / height);
 				width *= fac;
 				height *= fac;
 			}  else if (mode == STRETCH_INTEGRAL_AR) {
 				int targetHeight = height;
-				int horizontalFac = _windowWidth / width;
+				int horizontalFac = rotatedWindowWidth / width;
 				do {
 					width = originalWidth * horizontalFac;
 					int verticalFac = (targetHeight * horizontalFac + originalHeight / 2) / originalHeight;
 					height = originalHeight * verticalFac;
 					--horizontalFac;
-				} while (horizontalFac > 0 && height > _windowHeight);
-				if (height > _windowHeight)
+				} while (horizontalFac > 0 && height > rotatedWindowHeight);
+				if (height > rotatedWindowHeight)
 					height = targetHeight;
 			}
 		} else {
-			frac_t windowAspect = intToFrac(_windowWidth) / _windowHeight;
-			width = _windowWidth;
-			height = _windowHeight;
+			frac_t windowAspect = intToFrac(rotatedWindowWidth) / rotatedWindowHeight;
+			width = rotatedWindowWidth;
+			height = rotatedWindowHeight;
 			if (mode == STRETCH_FIT_FORCE_ASPECT) {
 				frac_t ratio = intToFrac(4) / 3;
 				if (windowAspect < ratio)
@@ -460,26 +471,26 @@ private:
 		switch (_screenAlign & SCREEN_ALIGN_XMASK) {
 			default:
 			case SCREEN_ALIGN_CENTER:
-				alignX = ((_windowWidth - width) / 2);
+				alignX = ((rotatedWindowWidth - width) / 2);
 				break;
 			case SCREEN_ALIGN_LEFT:
 				alignX = 0;
 				break;
 			case SCREEN_ALIGN_RIGHT:
-				alignX = (_windowWidth - width);
+				alignX = (rotatedWindowWidth - width);
 				break;
 		}
 
 		switch (_screenAlign & SCREEN_ALIGN_YMASK) {
 			default:
 			case SCREEN_ALIGN_MIDDLE:
-				alignY = ((_windowHeight - height) / 2);
+				alignY = ((rotatedWindowHeight - height) / 2);
 				break;
 			case SCREEN_ALIGN_TOP:
 				alignY = 0;
 				break;
 			case SCREEN_ALIGN_BOTTOM:
-				alignY = (_windowHeight - height);
+				alignY = (rotatedWindowHeight - height);
 				break;
 		}
 
diff --git a/common/module.mk b/common/module.mk
index a98010d1c22..315ef171341 100644
--- a/common/module.mk
+++ b/common/module.mk
@@ -30,6 +30,7 @@ MODULE_OBJS := \
 	random.o \
 	rational.o \
 	rendermode.o \
+	rotationmode.o \
 	str.o \
 	stream.o \
 	streamdebug.o \
diff --git a/common/rotationmode.cpp b/common/rotationmode.cpp
new file mode 100644
index 00000000000..7ca36ab2c2e
--- /dev/null
+++ b/common/rotationmode.cpp
@@ -0,0 +1,46 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/rotationmode.h"
+
+#include "common/gui_options.h"
+#include "common/str.h"
+#include "common/translation.h"
+
+
+namespace Common {
+
+
+const RotationModeDescription g_rotationModes[] = {
+	{ _s("No rotation"), kRotationNormal },
+	{ _s("Clockwise"), kRotation90 },
+	{ _s("180 degress"), kRotation180 },
+	{ _s("Counter-clockwise"), kRotation270 },
+	{ nullptr, kRotationNormal}
+};
+
+RotationMode parseRotationMode(int val) {
+	if ((val % 90) != 0 || val < 0 || val > 270)
+		return kRotationNormal;
+
+	return static_cast<RotationMode>(val);
+}
+}
diff --git a/common/rotationmode.h b/common/rotationmode.h
new file mode 100644
index 00000000000..15d31035e94
--- /dev/null
+++ b/common/rotationmode.h
@@ -0,0 +1,62 @@
+/* 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef COMMON_ROTATIONMODE_H
+#define COMMON_ROTATIONMODE_H
+
+#include "common/scummsys.h"
+
+namespace Common {
+
+/**
+ * @defgroup common_rotationmode Rotation modes
+ * @ingroup common
+ *
+ * @brief API for rotation modes.
+ *
+ * @{
+ */
+
+class String;
+
+/**
+ * List of rotation modes.
+ *
+ */
+enum RotationMode {
+	kRotationNormal = 0,
+	kRotation90 = 90,
+	kRotation180 = 180,
+	kRotation270 = 270,
+};
+
+struct RotationModeDescription {
+	const char *description;
+	RotationMode id;
+};
+
+extern const RotationModeDescription g_rotationModes[];
+
+extern RotationMode parseRotationMode(int val);
+
+}
+
+#endif
diff --git a/common/system.h b/common/system.h
index f3bba6a62f7..0c3949cd43b 100644
--- a/common/system.h
+++ b/common/system.h
@@ -628,6 +628,11 @@ public:
 		* Covers a wide range of platforms, Apple Macs, XBox 360, PS3, and more
 		*/
 		kFeatureCpuAltivec,
+
+		/**
+		* Graphics code is able to rotate the screen
+		*/
+		kFeatureRotationMode,
 	};
 
 	/**
diff --git a/gui/options.cpp b/gui/options.cpp
index 6de2cf21ab8..d000413fae8 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -38,6 +38,7 @@
 #include "common/config-manager.h"
 #include "common/gui_options.h"
 #include "common/rendermode.h"
+#include "common/rotationmode.h"
 #include "common/savefile.h"
 #include "common/system.h"
 #include "common/textconsole.h"
@@ -205,6 +206,8 @@ void OptionsDialog::init() {
 	_gfxPopUpDesc = nullptr;
 	_renderModePopUp = nullptr;
 	_renderModePopUpDesc = nullptr;
+	_rotationModePopUp = nullptr;
+	_rotationModePopUpDesc = nullptr;
 	_stretchPopUp = nullptr;
 	_stretchPopUpDesc = nullptr;
 	_scalerPopUp = nullptr;
@@ -343,6 +346,21 @@ void OptionsDialog::build() {
 			_renderModePopUp->setSelectedTag(sel);
 		}
 
+		if (g_system->hasFeature(OSystem::kFeatureRotationMode)) {
+			_rotationModePopUp->setSelected(0);
+
+			if (ConfMan.hasKey("rotation_mode", _domain)) {
+				const Common::RotationModeDescription *p = Common::g_rotationModes;
+				const Common::RotationMode rotationMode = Common::parseRotationMode(ConfMan.getInt("rotation_mode", _domain));
+				int sel = 0;
+				for (int i = 0; p->description; ++p, ++i) {
+					if (rotationMode == p->id)
+						sel = p->id;
+				}
+				_rotationModePopUp->setSelectedTag(sel);
+			}
+		}
+
 		// Fullscreen setting
 		if (g_system->hasFeature(OSystem::kFeatureFullscreenMode)) {
 			_fullscreenCheckbox->setState(ConfMan.getBool("fullscreen", _domain));
@@ -660,6 +678,17 @@ void OptionsDialog::apply() {
 				}
 			}
 
+			if (g_system->hasFeature(OSystem::kFeatureRotationMode)) {
+				if ((int32)_rotationModePopUp->getSelectedTag() >= 0) {
+					int rotationModeCode = ((Common::RotationMode)_rotationModePopUp->getSelectedTag());
+					if (_rotationModePopUp->getSelectedTag() == 0 || ConfMan.getInt("rotation_mode", _domain) != rotationModeCode) {
+						ConfMan.setInt("rotation_mode", rotationModeCode, _domain);
+						_rotationModePopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorNormal);
+					}
+					g_system->setFeatureState(OSystem::kFeatureRotationMode, true);
+				}
+			}
+
 			if (g_system->hasFeature(OSystem::kFeatureStretchMode)) {
 				isSet = false;
 				if ((int32)_stretchPopUp->getSelectedTag() >= 0) {
@@ -1232,6 +1261,10 @@ void OptionsDialog::setGraphicSettingsState(bool enabled) {
 	_gfxPopUp->setEnabled(enabled);
 	_renderModePopUpDesc->setEnabled(enabled);
 	_renderModePopUp->setEnabled(enabled);
+	if (_rotationModePopUp) {
+		_rotationModePopUpDesc->setEnabled(enabled);
+		_rotationModePopUp->setEnabled(enabled);
+	}
 
 	if (_rendererTypePopUp) {
 		_rendererTypePopUpDesc->setEnabled(enabled);
@@ -1628,6 +1661,21 @@ void OptionsDialog::addGraphicControls(GuiObject *boss, const Common::String &pr
 		updateScaleFactors(_scalerPopUp->getSelectedTag());
 	}
 
+	if (g_system->hasFeature(OSystem::kFeatureRotationMode)) {
+		const Common::RotationModeDescription *rotm = Common::g_rotationModes;
+		_rotationModePopUpDesc = new StaticTextWidget(boss, prefix + "grRotationModePopupDesc", _("Rotation mode:"));
+		if (ConfMan.isKeyTemporary("rotation_mode"))
+			_rotationModePopUpDesc->setFontColor(ThemeEngine::FontColor::kFontColorOverride);
+		_rotationModePopUp = new PopUpWidget(boss, prefix + "grRotationModePopup");
+
+		_rotationModePopUp->appendEntry(_("<default>"));
+		_rotationModePopUp->appendEntry(Common::U32String());
+		while (rotm->description) {
+			_rotationModePopUp->appendEntry(_c(rotm->description, context), rotm->id);
+			rotm++;
+		}
+	}
+
 	if (!g_gui.useLowResGUI())
 		_shaderButton = new ButtonWidget(boss, prefix + "grShaderButton", _("Shader:"), _("Specifies path to the shader used for scaling the game screen"), kChooseShaderCmd);
 	else
@@ -2046,6 +2094,10 @@ void OptionsDialog::setupGraphicsTab() {
 		_stretchPopUpDesc->setVisible(true);
 		_stretchPopUp->setVisible(true);
 	}
+	if (g_system->hasFeature(OSystem::kFeatureRotationMode)) {
+		_rotationModePopUpDesc->setVisible(true);
+		_rotationModePopUp->setVisible(true);
+	}
 	_fullscreenCheckbox->setVisible(true);
 	if (g_system->hasFeature(OSystem::kFeatureFilteringMode))
 		_filteringCheckbox->setVisible(true);
diff --git a/gui/options.h b/gui/options.h
index 2fa503ccd6f..f88638e0a70 100644
--- a/gui/options.h
+++ b/gui/options.h
@@ -170,6 +170,8 @@ private:
 	PopUpWidget *_antiAliasPopUp;
 	StaticTextWidget *_renderModePopUpDesc;
 	PopUpWidget *_renderModePopUp;
+	StaticTextWidget *_rotationModePopUpDesc;
+	PopUpWidget *_rotationModePopUp;
 
 	//
 	// Audio controls
diff --git a/gui/themes/common/highres_layout.stx b/gui/themes/common/highres_layout.stx
index ad47197531e..945f33fa142 100644
--- a/gui/themes/common/highres_layout.stx
+++ b/gui/themes/common/highres_layout.stx
@@ -760,6 +760,14 @@
 						type = 'PopUp'
 				/>
 			</layout>
+			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
+				<widget name = 'grRotationModePopupDesc'
+						type = 'OptionsLabel'
+				/>
+				<widget name = 'grRotationModePopup'
+						type = 'PopUp'
+				/>
+			</layout>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
 				<widget name = 'grStretchModePopupDesc'
 						type = 'OptionsLabel'
diff --git a/gui/themes/common/lowres_layout.stx b/gui/themes/common/lowres_layout.stx
index 4b85e9af246..c59daa0e8e5 100644
--- a/gui/themes/common/lowres_layout.stx
+++ b/gui/themes/common/lowres_layout.stx
@@ -600,6 +600,14 @@
 						type = 'PopUp'
 				/>
 			</layout>
+			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' align = 'center'>
+				<widget name = 'grRotationModePopupDesc'
+						type = 'OptionsLabel'
+				/>
+				<widget name = 'grRotationModePopup'
+						type = 'PopUp'
+				/>
+			</layout>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' align = 'center'>
 				<widget name = 'grStretchModePopupDesc'
 						type = 'OptionsLabel'
diff --git a/gui/themes/default.inc b/gui/themes/default.inc
index 689bf34a29b..59e76bfa97a 100644
--- a/gui/themes/default.inc
+++ b/gui/themes/default.inc
@@ -1829,6 +1829,14 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
 "/>"
 "</layout>"
 "<layout type='horizontal' padding='0,0,0,0' spacing='10' align='center'>"
+"<widget name='grRotationModePopupDesc' "
+"type='OptionsLabel' "
+"/>"
+"<widget name='grRotationModePopup' "
+"type='PopUp' "
+"/>"
+"</layout>"
+"<layout type='horizontal' padding='0,0,0,0' spacing='10' align='center'>"
 "<widget name='grStretchModePopupDesc' "
 "type='OptionsLabel' "
 "/>"
@@ -4219,6 +4227,14 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
 "/>"
 "</layout>"
 "<layout type='horizontal' padding='0,0,0,0' spacing='6' align='center'>"
+"<widget name='grRotationModePopupDesc' "
+"type='OptionsLabel' "
+"/>"
+"<widget name='grRotationModePopup' "
+"type='PopUp' "
+"/>"
+"</layout>"
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' align='center'>"
 "<widget name='grStretchModePopupDesc' "
 "type='OptionsLabel' "
 "/>"
diff --git a/gui/themes/residualvm.zip b/gui/themes/residualvm.zip
index 0882c25147b..bad63cc4c23 100644
Binary files a/gui/themes/residualvm.zip and b/gui/themes/residualvm.zip differ
diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip
index 397150d76fd..acf1f00f761 100644
Binary files a/gui/themes/scummclassic.zip and b/gui/themes/scummclassic.zip differ
diff --git a/gui/themes/scummclassic/classic_layout.stx b/gui/themes/scummclassic/classic_layout.stx
index 3554aebd31e..dc9f9c54c68 100644
--- a/gui/themes/scummclassic/classic_layout.stx
+++ b/gui/themes/scummclassic/classic_layout.stx
@@ -438,6 +438,14 @@
 						type = 'PopUp'
 				/>
 			</layout>
+			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
+				<widget name = 'grRotationModePopupDesc'
+						type = 'OptionsLabel'
+				/>
+				<widget name = 'grRotationModePopup'
+						type = 'PopUp'
+				/>
+			</layout>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' align = 'center'>
 				<widget name = 'grStretchModePopupDesc'
 						type = 'OptionsLabel'
diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx
index a509bbd77ed..4b6e659ac73 100644
--- a/gui/themes/scummclassic/classic_layout_lowres.stx
+++ b/gui/themes/scummclassic/classic_layout_lowres.stx
@@ -445,6 +445,14 @@
 						type = 'PopUp'
 				/>
 			</layout>
+			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' align = 'center'>
+				<widget name = 'grRotationModePopupDesc'
+						type = 'OptionsLabel'
+				/>
+				<widget name = 'grRotationModePopup'
+						type = 'PopUp'
+				/>
+			</layout>
 			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' align = 'center'>
 				<widget name = 'grStretchModePopupDesc'
 						type = 'OptionsLabel'
diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip
index 30e28f8bcb8..6be0f764629 100644
Binary files a/gui/themes/scummmodern.zip and b/gui/themes/scummmodern.zip differ
diff --git a/gui/themes/scummremastered.zip b/gui/themes/scummremastered.zip
index 0ff105c4af0..2d95e797a17 100644
Binary files a/gui/themes/scummremastered.zip and b/gui/themes/scummremastered.zip differ




More information about the Scummvm-git-logs mailing list