1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-06-19 00:17:56 +02:00

Implemented reserved area for iOS notch / cutout

This commit is contained in:
Ivan Savenko
2023-07-05 17:17:43 +03:00
parent 5143ca266d
commit 0c83e34093
3 changed files with 46 additions and 21 deletions

View File

@ -25,7 +25,7 @@
#include <SDL.h> #include <SDL.h>
// TODO: should be made into a private members of ScreenHandler // TODO: should be made into a private members of ScreenHandler
SDL_Window * mainWindow = nullptr; static SDL_Window * mainWindow = nullptr;
SDL_Renderer * mainRenderer = nullptr; SDL_Renderer * mainRenderer = nullptr;
SDL_Texture * screenTexture = nullptr; SDL_Texture * screenTexture = nullptr;
SDL_Surface * screen = nullptr; //main screen surface SDL_Surface * screen = nullptr; //main screen surface
@ -42,9 +42,12 @@ std::tuple<int, int> ScreenHandler::getSupportedScalingRange() const
// arbitrary limit on *downscaling*. Allow some downscaling, if requested by user. Should be generally limited to 100+ for all but few devices // arbitrary limit on *downscaling*. Allow some downscaling, if requested by user. Should be generally limited to 100+ for all but few devices
static const double minimalScaling = 50; static const double minimalScaling = 50;
Point renderResolution = getPreferredRenderingResolution(); Point renderResolution = getActualRenderResolution();
double maximalScalingWidth = 100.0 * renderResolution.x / minResolution.x; double reservedAreaWidth = settings["video"]["reservedWidth"].Float();
double maximalScalingHeight = 100.0 * renderResolution.y / minResolution.y; Point availableResolution = Point(renderResolution.x * (1 - reservedAreaWidth), renderResolution.y);
double maximalScalingWidth = 100.0 * availableResolution.x / minResolution.x;
double maximalScalingHeight = 100.0 * availableResolution.y / minResolution.y;
double maximalScaling = std::min(maximalScalingWidth, maximalScalingHeight); double maximalScaling = std::min(maximalScalingWidth, maximalScalingHeight);
return { minimalScaling, maximalScaling }; return { minimalScaling, maximalScaling };
@ -78,18 +81,31 @@ Rect ScreenHandler::convertLogicalPointsToWindow(const Rect & input) const
Point ScreenHandler::getPreferredLogicalResolution() const Point ScreenHandler::getPreferredLogicalResolution() const
{ {
Point renderResolution = getPreferredRenderingResolution(); Point renderResolution = getActualRenderResolution();
double reservedAreaWidth = settings["video"]["reservedWidth"].Float();
Point availableResolution = Point(renderResolution.x * (1 - reservedAreaWidth), renderResolution.y);
auto [minimalScaling, maximalScaling] = getSupportedScalingRange(); auto [minimalScaling, maximalScaling] = getSupportedScalingRange();
int userScaling = settings["video"]["resolution"]["scaling"].Integer(); int userScaling = settings["video"]["resolution"]["scaling"].Integer();
int scaling = std::clamp(userScaling, minimalScaling, maximalScaling); int scaling = std::clamp(userScaling, minimalScaling, maximalScaling);
Point logicalResolution = renderResolution * 100.0 / scaling; Point logicalResolution = availableResolution * 100.0 / scaling;
return logicalResolution; return logicalResolution;
} }
Point ScreenHandler::getPreferredRenderingResolution() const Point ScreenHandler::getActualRenderResolution() const
{
assert(mainRenderer != nullptr);
Point result;
SDL_GetRendererOutputSize(mainRenderer, &result.x, &result.y);
return result;
}
Point ScreenHandler::getPreferredWindowResolution() const
{ {
if (getPreferredWindowMode() == EWindowMode::FULLSCREEN_BORDERLESS_WINDOWED) if (getPreferredWindowMode() == EWindowMode::FULLSCREEN_BORDERLESS_WINDOWED)
{ {
@ -208,7 +224,7 @@ void ScreenHandler::updateWindowState()
SDL_DisplayMode mode; SDL_DisplayMode mode;
SDL_GetDesktopDisplayMode(displayIndex, &mode); SDL_GetDesktopDisplayMode(displayIndex, &mode);
Point resolution = getPreferredRenderingResolution(); Point resolution = getPreferredWindowResolution();
mode.w = resolution.x; mode.w = resolution.x;
mode.h = resolution.y; mode.h = resolution.y;
@ -226,7 +242,7 @@ void ScreenHandler::updateWindowState()
} }
case EWindowMode::WINDOWED: case EWindowMode::WINDOWED:
{ {
Point resolution = getPreferredRenderingResolution(); Point resolution = getPreferredWindowResolution();
SDL_SetWindowFullscreen(mainWindow, 0); SDL_SetWindowFullscreen(mainWindow, 0);
SDL_SetWindowSize(mainWindow, resolution.x, resolution.y); SDL_SetWindowSize(mainWindow, resolution.x, resolution.y);
SDL_SetWindowPosition(mainWindow, SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex), SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex)); SDL_SetWindowPosition(mainWindow, SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex), SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex));
@ -316,7 +332,7 @@ SDL_Window * ScreenHandler::createWindowImpl(Point dimensions, int flags, bool c
SDL_Window * ScreenHandler::createWindow() SDL_Window * ScreenHandler::createWindow()
{ {
#ifndef VCMI_MOBILE #ifndef VCMI_MOBILE
Point dimensions = getPreferredRenderingResolution(); Point dimensions = getPreferredWindowResolution();
switch(getPreferredWindowMode()) switch(getPreferredWindowMode())
{ {
@ -376,7 +392,7 @@ void ScreenHandler::validateSettings()
{ {
//we only check that our desired window size fits on screen //we only check that our desired window size fits on screen
int displayIndex = getPreferredDisplayIndex(); int displayIndex = getPreferredDisplayIndex();
Point resolution = getPreferredRenderingResolution(); Point resolution = getPreferredWindowResolution();
SDL_DisplayMode mode; SDL_DisplayMode mode;
@ -394,7 +410,7 @@ void ScreenHandler::validateSettings()
if (getPreferredWindowMode() == EWindowMode::FULLSCREEN_EXCLUSIVE) if (getPreferredWindowMode() == EWindowMode::FULLSCREEN_EXCLUSIVE)
{ {
auto legalOptions = getSupportedResolutions(); auto legalOptions = getSupportedResolutions();
Point selectedResolution = getPreferredRenderingResolution(); Point selectedResolution = getPreferredWindowResolution();
if(!vstd::contains(legalOptions, selectedResolution)) if(!vstd::contains(legalOptions, selectedResolution))
{ {

View File

@ -30,14 +30,17 @@ enum class EWindowMode
}; };
/// This class is responsible for management of game window and its main rendering surface /// This class is responsible for management of game window and its main rendering surface
class ScreenHandler : public IScreenHandler class ScreenHandler final : public IScreenHandler
{ {
/// Dimensions of target surfaces/textures, this value is what game logic views as screen size /// Dimensions of target surfaces/textures, this value is what game logic views as screen size
Point getPreferredLogicalResolution() const; Point getPreferredLogicalResolution() const;
/// Dimensions of output window, if different from logicalResolution SDL will perform scaling /// Dimensions of output window, if different from logicalResolution SDL will perform scaling
/// This value is what player views as window size /// This value is what player views as window size
Point getPreferredRenderingResolution() const; Point getPreferredWindowResolution() const;
/// Dimensions of render output, usually same as window size except for high-DPI screens on macOS / iOS
Point getActualRenderResolution() const;
EWindowMode getPreferredWindowMode() const; EWindowMode getPreferredWindowMode() const;

View File

@ -110,6 +110,7 @@
"default" : {}, "default" : {},
"required" : [ "required" : [
"resolution", "resolution",
"reservedWidth",
"fullscreen", "fullscreen",
"realFullscreen", "realFullscreen",
"cursor", "cursor",
@ -134,6 +135,11 @@
"defaultAndroid" : {"width" : 800, "height" : 600, "scaling" : 200 }, "defaultAndroid" : {"width" : 800, "height" : 600, "scaling" : 200 },
"default" : {"width" : 800, "height" : 600, "scaling" : 100 } "default" : {"width" : 800, "height" : 600, "scaling" : 100 }
}, },
"reservedWidth" : {
"type" : "number",
"defaultIOS" : 0.1, // iOS camera cutout / notch is excluded from available area by SDL
"default" : 0
},
"fullscreen" : { "fullscreen" : {
"type" : "boolean", "type" : "boolean",
"default" : false "default" : false