Add physical window size overrides

This commit is contained in:
gamer147
2026-07-28 22:10:01 -04:00
parent c6f1a60e79
commit e313a14480
9 changed files with 179 additions and 12 deletions

View File

@@ -22,6 +22,7 @@ public partial class Main : Godot.Control
private const int NativeBoldGlyphSpacing = 1;
private int _screenWidth = Sys4LogicalCanvas.DefaultWidth;
private int _screenHeight = Sys4LogicalCanvas.DefaultHeight;
private WindowLaunchOptions _windowOptions;
private TextureRect _screenView = null!; // shows the composited screen backbuffer
private Image _screen = null!; // SYS4INI-sized immediate-mode canvas
private ImageTexture _screenTex = null!;
@@ -108,10 +109,21 @@ public partial class Main : Godot.Control
public override void _Ready()
{
var userArgs = OS.GetCmdlineUserArgs();
// Resolve the selected game's logical canvas before any presentation allocation. The same catalog
// instance is reused for scripts and assets later in startup.
var catalog = Sys4AssetCatalog.Load(Paths.Sys4Ini);
var logicalCanvas = catalog.LogicalCanvas;
try
{
_windowOptions = WindowLaunchOptions.Resolve(userArgs, logicalCanvas);
}
catch (System.ArgumentException error)
{
GD.PushError($"[startup] {error.Message}");
GetTree().Quit(2);
return;
}
_screenWidth = logicalCanvas.Width;
_screenHeight = logicalCanvas.Height;
_screenPixels = new byte[logicalCanvas.RgbaByteCount];
@@ -120,9 +132,11 @@ public partial class Main : Godot.Control
rootWindow.ContentScaleAspect = Window.ContentScaleAspectEnum.Keep;
rootWindow.ContentScaleSize = new Vector2I(_screenWidth, _screenHeight);
if (rootWindow.Mode == Window.ModeEnum.Windowed)
rootWindow.Size = new Vector2I(_screenWidth, _screenHeight);
rootWindow.Size = new Vector2I(_windowOptions.Width, _windowOptions.Height);
GD.Print($"[profile] SYS4INI logical canvas={_screenWidth}x{_screenHeight} " +
$"window={rootWindow.Size.X}x{rootWindow.Size.Y}");
$"requested window={_windowOptions.Width}x{_windowOptions.Height} " +
$"source={(_windowOptions.IsOverridden ? "boot-arguments" : "logical-canvas")} " +
$"actual={rootWindow.Size.X}x{rootWindow.Size.Y} mode={rootWindow.Mode}");
// One logical canvas that draw-texture blits into, shown behind the dialogue.
_screen = Image.CreateEmpty(_screenWidth, _screenHeight, false, Image.Format.Rgba8);
@@ -205,7 +219,6 @@ public partial class Main : Godot.Control
}
_audioOutputLatencySeconds = AudioServer.GetOutputLatency();
var userArgs = OS.GetCmdlineUserArgs();
_selftest = System.Array.IndexOf(userArgs, "--selftest") >= 0;
bool boot = System.Array.IndexOf(userArgs, "--boot") >= 0; // diagnostic prefix for direct-scene runs
bool nativeDebugMenu = System.Array.IndexOf(userArgs, "--native-debug-menu") >= 0;
@@ -2158,7 +2171,10 @@ public partial class Main : Godot.Control
&& _screen.GetHeight() == _screenHeight
&& _screenPixels.Length == checked(_screenWidth * _screenHeight * 4)
&& rootWindow.ContentScaleSize
== new Vector2I(_screenWidth, _screenHeight);
== new Vector2I(_screenWidth, _screenHeight)
&& _windowOptions == WindowLaunchOptions.Resolve(
OS.GetCmdlineUserArgs(),
new Sys4LogicalCanvas(_screenWidth, _screenHeight));
textEffectSmoke.QueueFree();
ok &= launcherOk && sleepMinimumOk && inputTranslationOk && cp932WavMetadataOk
&& bgmReplacementCancelsFade && textEffectModesOk && fontCalibrationOk
@@ -2167,13 +2183,15 @@ public partial class Main : Godot.Control
$"debug launcher catalog/UI smoke ({debugEntries.Count} packed scripts); " +
$"sleep-min=1ms; native-key-translation=ok; cp932-wav-info=ok; " +
$"bgm-fade-replacement=ok; text-effect-modes=ok; font-calibration=ok; " +
$"logical-canvas={_screenWidth}x{_screenHeight}");
$"logical-canvas={_screenWidth}x{_screenHeight}; " +
$"window-request={_windowOptions.Width}x{_windowOptions.Height}");
else GD.Print($"SELFTEST FAIL: threaded={actual.Count} vs headless={expected.Count}; " +
$"debug-launcher={launcherOk}; sleep-min={sleepMinimumOk}; " +
$"native-key-translation={inputTranslationOk}; cp932-wav-info={cp932WavMetadataOk}; " +
$"bgm-fade-replacement={bgmReplacementCancelsFade}; " +
$"text-effect-modes={textEffectModesOk}; font-calibration={fontCalibrationOk}; " +
$"logical-canvas={logicalCanvasOk}({_screenWidth}x{_screenHeight})");
$"logical-canvas={logicalCanvasOk}({_screenWidth}x{_screenHeight}); " +
$"window-request={_windowOptions.Width}x{_windowOptions.Height}");
GetTree().Quit(ok ? 0 : 1);
}

View File

@@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using Age.Engine.Sys4;
/// <summary>
/// Presentation-only window dimensions resolved from Godot user arguments. These never redefine the
/// SYS4 logical canvas, VM coordinates, or AGE surface dimensions.
/// </summary>
public readonly record struct WindowLaunchOptions(
int Width, int Height, bool WidthOverridden, bool HeightOverridden)
{
public const int MaximumDimension = Sys4LogicalCanvas.MaximumDimension;
public bool IsOverridden => WidthOverridden || HeightOverridden;
public static WindowLaunchOptions Resolve(
IReadOnlyList<string> arguments, Sys4LogicalCanvas logicalCanvas)
{
ArgumentNullException.ThrowIfNull(arguments);
int width = logicalCanvas.Width;
int height = logicalCanvas.Height;
bool widthOverridden = false;
bool heightOverridden = false;
for (int index = 0; index < arguments.Count; index++)
{
string argument = arguments[index];
if (argument is not ("--window-width" or "--window-height")) continue;
if (index + 1 >= arguments.Count)
throw new ArgumentException($"{argument} requires a pixel value");
string raw = arguments[++index];
if (!int.TryParse(raw, NumberStyles.Integer, CultureInfo.InvariantCulture, out int value)
|| value <= 0 || value > MaximumDimension)
throw new ArgumentException(
$"{argument} must be an integer from 1 through {MaximumDimension}; got '{raw}'");
if (argument == "--window-width")
{
width = value;
widthOverridden = true;
}
else
{
height = value;
heightOverridden = true;
}
}
return new WindowLaunchOptions(width, height, widthOverridden, heightOverridden);
}
}