Add Graphics.UIScale setting to modify UI size.

This commit is contained in:
Paul Chote
2019-12-25 18:00:04 +00:00
committed by teinarss
parent ce445f993c
commit 6388a6bff4
12 changed files with 78 additions and 42 deletions

View File

@@ -193,14 +193,13 @@ namespace OpenRA.Graphics
// Cursor is rendered in native window coordinates // Cursor is rendered in native window coordinates
// Apply same scaling rules as hardware cursors // Apply same scaling rules as hardware cursors
var ws = Game.Renderer.WindowScale; if (Game.Renderer.NativeWindowScale > 1.5f)
if (ws > 1.5f)
cursorSize = 2 * cursorSize; cursorSize = 2 * cursorSize;
var mousePos = isLocked ? lockedPosition : Viewport.LastMousePos; var mousePos = isLocked ? lockedPosition : Viewport.LastMousePos;
renderer.RgbaSpriteRenderer.DrawSprite(cursorSprite, renderer.RgbaSpriteRenderer.DrawSprite(cursorSprite,
mousePos, mousePos,
cursorSize / ws); cursorSize / Game.Renderer.WindowScale);
} }
public void Lock() public void Lock()

View File

@@ -17,7 +17,7 @@ namespace OpenRA
{ {
public interface IPlatform public interface IPlatform
{ {
IPlatformWindow CreateWindow(Size size, WindowMode windowMode, int batchSize); IPlatformWindow CreateWindow(Size size, WindowMode windowMode, float scaleModifier, int batchSize);
ISoundEngine CreateSound(string device); ISoundEngine CreateSound(string device);
IFont CreateFont(byte[] data); IFont CreateFont(byte[] data);
} }
@@ -39,11 +39,13 @@ namespace OpenRA
{ {
IGraphicsContext Context { get; } IGraphicsContext Context { get; }
Size WindowSize { get; } Size NativeWindowSize { get; }
float WindowScale { get; } Size EffectiveWindowSize { get; }
float NativeWindowScale { get; }
float EffectiveWindowScale { get; }
Size SurfaceSize { get; } Size SurfaceSize { get; }
event Action<float, float> OnWindowScaleChanged; event Action<float, float, float, float> OnWindowScaleChanged;
void PumpInput(IInputHandler inputHandler); void PumpInput(IInputHandler inputHandler);
string GetClipboardText(); string GetClipboardText();

View File

@@ -78,7 +78,7 @@ namespace OpenRA.Graphics
private set private set
{ {
zoom = value; zoom = value;
viewportSize = (1f / zoom * new float2(Game.Renderer.Resolution)).ToInt2(); viewportSize = (1f / zoom * new float2(Game.Renderer.NativeResolution)).ToInt2();
cellsDirty = true; cellsDirty = true;
allCellsDirty = true; allCellsDirty = true;
} }
@@ -181,7 +181,7 @@ namespace OpenRA.Graphics
float CalculateMinimumZoom(float minHeight, float maxHeight) float CalculateMinimumZoom(float minHeight, float maxHeight)
{ {
var h = Game.Renderer.Resolution.Height; var h = Game.Renderer.NativeResolution.Height;
// Check the easy case: the native resolution is within the maximum limit // Check the easy case: the native resolution is within the maximum limit
// Also catches the case where the user may force a resolution smaller than the minimum window size // Also catches the case where the user may force a resolution smaller than the minimum window size
@@ -222,7 +222,7 @@ namespace OpenRA.Graphics
minZoom = CalculateMinimumZoom(range.X, range.Y); minZoom = CalculateMinimumZoom(range.X, range.Y);
} }
maxZoom = Math.Min(minZoom * viewportSizes.MaxZoomScale, Game.Renderer.Resolution.Height * 1f / viewportSizes.MaxZoomWindowHeight); maxZoom = Math.Min(minZoom * viewportSizes.MaxZoomScale, Game.Renderer.NativeResolution.Height * 1f / viewportSizes.MaxZoomWindowHeight);
if (unlockMinZoom) if (unlockMinZoom)
{ {
@@ -304,9 +304,9 @@ namespace OpenRA.Graphics
yield return new MPos(u, v); yield return new MPos(u, v);
} }
public int2 ViewToWorldPx(int2 view) { return (1f / Zoom * view.ToFloat2()).ToInt2() + TopLeft; } public int2 ViewToWorldPx(int2 view) { return (graphicSettings.UIScale / Zoom * view.ToFloat2()).ToInt2() + TopLeft; }
public int2 WorldToViewPx(int2 world) { return (Zoom * (world - TopLeft).ToFloat2()).ToInt2(); } public int2 WorldToViewPx(int2 world) { return ((Zoom / graphicSettings.UIScale) * (world - TopLeft).ToFloat2()).ToInt2(); }
public int2 WorldToViewPx(float3 world) { return (Zoom * (world - TopLeft).XY).ToInt2(); } public int2 WorldToViewPx(float3 world) { return ((Zoom / graphicSettings.UIScale) * (world - TopLeft).XY).ToInt2(); }
public void Center(IEnumerable<Actor> actors) public void Center(IEnumerable<Actor> actors)
{ {

View File

@@ -66,7 +66,7 @@ namespace OpenRA
this.platform = platform; this.platform = platform;
var resolution = GetResolution(graphicSettings); var resolution = GetResolution(graphicSettings);
Window = platform.CreateWindow(new Size(resolution.Width, resolution.Height), graphicSettings.Mode, graphicSettings.BatchSize); Window = platform.CreateWindow(new Size(resolution.Width, resolution.Height), graphicSettings.Mode, graphicSettings.UIScale, graphicSettings.BatchSize);
Context = Window.Context; Context = Window.Context;
TempBufferSize = graphicSettings.BatchSize; TempBufferSize = graphicSettings.BatchSize;
@@ -103,17 +103,17 @@ namespace OpenRA
fontSheetBuilder = new SheetBuilder(SheetType.BGRA, 512); fontSheetBuilder = new SheetBuilder(SheetType.BGRA, 512);
Fonts = modData.Manifest.Get<Fonts>().FontList.ToDictionary(x => x.Key, Fonts = modData.Manifest.Get<Fonts>().FontList.ToDictionary(x => x.Key,
x => new SpriteFont(x.Value.Font, modData.DefaultFileSystem.Open(x.Value.Font).ReadAllBytes(), x => new SpriteFont(x.Value.Font, modData.DefaultFileSystem.Open(x.Value.Font).ReadAllBytes(),
x.Value.Size, x.Value.Ascender, Window.WindowScale, fontSheetBuilder)).AsReadOnly(); x.Value.Size, x.Value.Ascender, Window.EffectiveWindowScale, fontSheetBuilder)).AsReadOnly();
} }
Window.OnWindowScaleChanged += (before, after) => Window.OnWindowScaleChanged += (oldNative, oldEffective, newNative, newEffective) =>
{ {
Game.RunAfterTick(() => Game.RunAfterTick(() =>
{ {
ChromeProvider.SetDPIScale(after); ChromeProvider.SetDPIScale(newEffective);
foreach (var f in Fonts) foreach (var f in Fonts)
f.Value.SetScale(after); f.Value.SetScale(newEffective);
}); });
}; };
} }
@@ -159,7 +159,7 @@ namespace OpenRA
// but to have a higher resolution backing surface with more than 1 texture pixel per viewport pixel. // but to have a higher resolution backing surface with more than 1 texture pixel per viewport pixel.
// We must convert the surface buffer size to a viewport size - in general this is NOT just the window size // We must convert the surface buffer size to a viewport size - in general this is NOT just the window size
// rounded to the next power of two, as the NextPowerOf2 calculation is done in the surface pixel coordinates // rounded to the next power of two, as the NextPowerOf2 calculation is done in the surface pixel coordinates
var scale = Window.WindowScale; var scale = Window.EffectiveWindowScale;
var bufferSize = new Size((int)(surfaceBufferSize.Width / scale), (int)(surfaceBufferSize.Height / scale)); var bufferSize = new Size((int)(surfaceBufferSize.Width / scale), (int)(surfaceBufferSize.Height / scale));
if (lastBufferSize != bufferSize) if (lastBufferSize != bufferSize)
{ {
@@ -220,7 +220,7 @@ namespace OpenRA
// Render the world buffer into the UI buffer // Render the world buffer into the UI buffer
screenBuffer.Bind(); screenBuffer.Bind();
var scale = Window.WindowScale; var scale = Window.EffectiveWindowScale;
var bufferSize = new Size((int)(screenSprite.Bounds.Width / scale), (int)(-screenSprite.Bounds.Height / scale)); var bufferSize = new Size((int)(screenSprite.Bounds.Width / scale), (int)(-screenSprite.Bounds.Height / scale));
SpriteRenderer.SetAntialiasingPixelsPerTexel(Window.SurfaceSize.Height * 1f / worldSprite.Bounds.Height); SpriteRenderer.SetAntialiasingPixelsPerTexel(Window.SurfaceSize.Height * 1f / worldSprite.Bounds.Height);
@@ -292,8 +292,10 @@ namespace OpenRA
CurrentBatchRenderer = null; CurrentBatchRenderer = null;
} }
public Size Resolution { get { return Window.WindowSize; } } public Size Resolution { get { return Window.EffectiveWindowSize; } }
public float WindowScale { get { return Window.WindowScale; } } public Size NativeResolution { get { return Window.NativeWindowSize; } }
public float WindowScale { get { return Window.EffectiveWindowScale; } }
public float NativeWindowScale { get { return Window.NativeWindowScale; } }
public interface IBatchRenderer { void Flush(); } public interface IBatchRenderer { void Flush(); }
@@ -385,7 +387,7 @@ namespace OpenRA
throw new InvalidOperationException("EndFrame called with renderType = {0}, expected RenderType.UI.".F(renderType)); throw new InvalidOperationException("EndFrame called with renderType = {0}, expected RenderType.UI.".F(renderType));
Flush(); Flush();
SpriteRenderer.SetAntialiasingPixelsPerTexel(Window.WindowScale); SpriteRenderer.SetAntialiasingPixelsPerTexel(Window.EffectiveWindowScale);
} }
public void DisableAntialiasingFilter() public void DisableAntialiasingFilter()

View File

@@ -156,6 +156,7 @@ namespace OpenRA
public bool CursorDouble = false; public bool CursorDouble = false;
public WorldViewport ViewportDistance = WorldViewport.Medium; public WorldViewport ViewportDistance = WorldViewport.Medium;
public float UIScale = 1;
[Desc("Add a frame rate limiter.")] [Desc("Add a frame rate limiter.")]
public bool CapFramerate = false; public bool CapFramerate = false;

View File

@@ -44,7 +44,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
bool newsOpen; bool newsOpen;
// Increment the version number when adding new stats // Increment the version number when adding new stats
const int SystemInformationVersion = 3; const int SystemInformationVersion = 4;
Dictionary<string, Pair<string, string>> GetSystemInformation() Dictionary<string, Pair<string, string>> GetSystemInformation()
{ {
var lang = System.Globalization.CultureInfo.InstalledUICulture.TwoLetterISOLanguageName; var lang = System.Globalization.CultureInfo.InstalledUICulture.TwoLetterISOLanguageName;
@@ -57,8 +57,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
{ "x64process", Pair.New("Process is 64 bit", Environment.Is64BitProcess.ToString()) }, { "x64process", Pair.New("Process is 64 bit", Environment.Is64BitProcess.ToString()) },
{ "runtime", Pair.New(".NET Runtime", Platform.RuntimeVersion) }, { "runtime", Pair.New(".NET Runtime", Platform.RuntimeVersion) },
{ "gl", Pair.New("OpenGL Version", Game.Renderer.GLVersion) }, { "gl", Pair.New("OpenGL Version", Game.Renderer.GLVersion) },
{ "windowsize", Pair.New("Window Size", "{0}x{1}".F(Game.Renderer.Resolution.Width, Game.Renderer.Resolution.Height)) }, { "windowsize", Pair.New("Window Size", "{0}x{1}".F(Game.Renderer.NativeResolution.Width, Game.Renderer.NativeResolution.Height)) },
{ "windowscale", Pair.New("Window Scale", Game.Renderer.WindowScale.ToString("F2", CultureInfo.InvariantCulture)) }, { "windowscale", Pair.New("Window Scale", Game.Renderer.NativeWindowScale.ToString("F2", CultureInfo.InvariantCulture)) },
{ "uiscale", Pair.New("UI Scale", Game.Settings.Graphics.UIScale.ToString("F2", CultureInfo.InvariantCulture)) },
{ "lang", Pair.New("System Language", lang) } { "lang", Pair.New("System Language", lang) }
}; };
} }

View File

@@ -841,7 +841,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
}; };
var viewportSizes = Game.ModData.Manifest.Get<WorldViewportSizes>(); var viewportSizes = Game.ModData.Manifest.Get<WorldViewportSizes>();
var windowHeight = Game.Renderer.Resolution.Height; var windowHeight = Game.Renderer.NativeResolution.Height;
var validSizes = new List<WorldViewport>() { WorldViewport.Close }; var validSizes = new List<WorldViewport>() { WorldViewport.Close };
if (viewportSizes.GetSizeRange(WorldViewport.Medium).X < windowHeight) if (viewportSizes.GetSizeRange(WorldViewport.Medium).X < windowHeight)

View File

@@ -39,9 +39,8 @@ namespace OpenRA.Mods.Common.Widgets
// Cursor is rendered in native window coordinates // Cursor is rendered in native window coordinates
// Apply same scaling rules as hardware cursors // Apply same scaling rules as hardware cursors
var ws = Game.Renderer.WindowScale; var scale = (graphicSettings.CursorDouble ? 2 : 1) * (Game.Renderer.NativeWindowScale > 1.5f ? 2 : 1);
var scale = (graphicSettings.CursorDouble ? 2 : 1) * (ws > 1.5f ? 2 : 1); WidgetUtils.DrawSHPCentered(sprite, ChildOrigin, directionPalette, scale / Game.Renderer.WindowScale);
WidgetUtils.DrawSHPCentered(sprite, ChildOrigin, directionPalette, scale / ws);
} }
} }

View File

@@ -16,9 +16,9 @@ namespace OpenRA.Platforms.Default
{ {
public class DefaultPlatform : IPlatform public class DefaultPlatform : IPlatform
{ {
public IPlatformWindow CreateWindow(Size size, WindowMode windowMode, int batchSize) public IPlatformWindow CreateWindow(Size size, WindowMode windowMode, float scaleModifier, int batchSize)
{ {
return new Sdl2PlatformWindow(size, windowMode, batchSize); return new Sdl2PlatformWindow(size, windowMode, scaleModifier, batchSize);
} }
public ISoundEngine CreateSound(string device) public ISoundEngine CreateSound(string device)

View File

@@ -98,8 +98,8 @@ namespace OpenRA.Platforms.Default
if (height < 0) if (height < 0)
height = 0; height = 0;
var windowSize = window.WindowSize; var windowSize = window.EffectiveWindowSize;
var windowScale = window.WindowScale; var windowScale = window.EffectiveWindowScale;
var surfaceSize = window.SurfaceSize; var surfaceSize = window.SurfaceSize;
if (windowSize != surfaceSize) if (windowSize != surfaceSize)

View File

@@ -44,8 +44,19 @@ namespace OpenRA.Platforms.Default
{ {
// On Windows and Linux (X11) events are given in surface coordinates // On Windows and Linux (X11) events are given in surface coordinates
// These must be scaled to our effective window coordinates // These must be scaled to our effective window coordinates
if (Platform.CurrentPlatform != PlatformType.OSX && device.WindowSize != device.SurfaceSize) // Round fractional components up to avoid rounding small deltas to 0
return new int2((int)(x / device.WindowScale), (int)(y / device.WindowScale)); if (Platform.CurrentPlatform != PlatformType.OSX && device.EffectiveWindowSize != device.SurfaceSize)
{
var s = 1 / device.EffectiveWindowScale;
return new int2((int)(Math.Sign(x) / 2f + x * s), (int)(Math.Sign(x) / 2f + y * s));
}
// On macOS we must still account for the user-requested scale modifier
if (Platform.CurrentPlatform == PlatformType.OSX && device.EffectiveWindowScale != device.NativeWindowScale)
{
var s = device.NativeWindowScale / device.EffectiveWindowScale;
return new int2((int)(Math.Sign(x) / 2f + x * s), (int)(Math.Sign(x) / 2f + y * s));
}
return new int2(x, y); return new int2(x, y);
} }

View File

@@ -31,6 +31,7 @@ namespace OpenRA.Platforms.Default
Size surfaceSize; Size surfaceSize;
float windowScale = 1f; float windowScale = 1f;
int2? lockedMousePosition; int2? lockedMousePosition;
float scaleModifier;
internal IntPtr Window internal IntPtr Window
{ {
@@ -41,7 +42,7 @@ namespace OpenRA.Platforms.Default
} }
} }
public Size WindowSize public Size NativeWindowSize
{ {
get get
{ {
@@ -50,7 +51,16 @@ namespace OpenRA.Platforms.Default
} }
} }
public float WindowScale public Size EffectiveWindowSize
{
get
{
lock (syncObject)
return new Size((int)(windowSize.Width / scaleModifier), (int)(windowSize.Height / scaleModifier));
}
}
public float NativeWindowScale
{ {
get get
{ {
@@ -59,6 +69,15 @@ namespace OpenRA.Platforms.Default
} }
} }
public float EffectiveWindowScale
{
get
{
lock (syncObject)
return windowScale * scaleModifier;
}
}
public Size SurfaceSize public Size SurfaceSize
{ {
get get
@@ -68,16 +87,18 @@ namespace OpenRA.Platforms.Default
} }
} }
public event Action<float, float> OnWindowScaleChanged = (before, after) => { }; public event Action<float, float, float, float> OnWindowScaleChanged = (oldNative, oldEffective, newNative, newEffective) => { };
[DllImport("user32.dll")] [DllImport("user32.dll")]
static extern bool SetProcessDPIAware(); static extern bool SetProcessDPIAware();
public Sdl2PlatformWindow(Size requestEffectiveWindowSize, WindowMode windowMode, int batchSize) public Sdl2PlatformWindow(Size requestEffectiveWindowSize, WindowMode windowMode, float scaleModifier, int batchSize)
{ {
// Lock the Window/Surface properties until initialization is complete // Lock the Window/Surface properties until initialization is complete
lock (syncObject) lock (syncObject)
{ {
this.scaleModifier = scaleModifier;
// Disable legacy scaling on Windows // Disable legacy scaling on Windows
if (Platform.CurrentPlatform == PlatformType.Windows) if (Platform.CurrentPlatform == PlatformType.Windows)
SetProcessDPIAware(); SetProcessDPIAware();
@@ -269,7 +290,7 @@ namespace OpenRA.Platforms.Default
{ {
// Pixel double the cursor on non-OSX if the window scale is large enough // Pixel double the cursor on non-OSX if the window scale is large enough
// OSX does this for us automatically // OSX does this for us automatically
if (Platform.CurrentPlatform != PlatformType.OSX && WindowScale > 1.5) if (Platform.CurrentPlatform != PlatformType.OSX && NativeWindowScale > 1.5f)
{ {
data = DoublePixelData(data, size); data = DoublePixelData(data, size);
size = new Size(2 * size.Width, 2 * size.Height); size = new Size(2 * size.Width, 2 * size.Height);
@@ -341,7 +362,7 @@ namespace OpenRA.Platforms.Default
windowScale = width * 1f / windowSize.Width; windowScale = width * 1f / windowSize.Width;
} }
OnWindowScaleChanged(oldScale, windowScale); OnWindowScaleChanged(oldScale, oldScale * scaleModifier, windowScale, windowScale * scaleModifier);
} }
} }
} }