Plan SYS4INI logical resolution handling
This commit is contained in:
@@ -3358,6 +3358,169 @@ ADV-toggle, audio, and registration consumers.
|
||||
the Phase-B gameplay spine unless one of the cataloged ADV policy differences becomes a visible gameplay
|
||||
or input defect.
|
||||
|
||||
## SYS4INI logical-resolution implementation plan (planned 2026-07-28)
|
||||
|
||||
### Slice boundary
|
||||
|
||||
This first settings-application slice makes SYS4INI the runtime source of the game's logical canvas and
|
||||
uses that same size as the default windowed client size:
|
||||
|
||||
```text
|
||||
SYS4INI SCREENX/SCREENY
|
||||
-> effective logical canvas
|
||||
-> software backbuffer + retained presentation bounds + primary surface
|
||||
-> Godot content-scale base
|
||||
-> initial windowed client size
|
||||
```
|
||||
|
||||
AGE's registered `640x480` values remain the per-dimension fallback when a key is absent or cannot
|
||||
produce a positive integer. A present value that would overflow or exceed the runtime's explicitly
|
||||
bounded RGBA allocation policy is a profile error with a useful diagnostic, not a request to attempt an
|
||||
unbounded allocation.
|
||||
|
||||
The physical presentation size is deliberately not independently configurable in this slice. Slice two
|
||||
will add `--window-width` and `--window-height`; their defaults will be the logical canvas size established
|
||||
here. Those future parameters will change only the physical window, never VM coordinates, surface sizes,
|
||||
layout, or the software backbuffer.
|
||||
|
||||
### Non-goals
|
||||
|
||||
- Do not apply the other 34 SYS4INI settings yet.
|
||||
- Do not reproduce native fullscreen mode switching, `FULLSCREENBIT`, aspect/device selection, or
|
||||
DirectDraw behavior.
|
||||
- Do not add the window-width/window-height boot parameters early.
|
||||
- Do not turn Himegari-authored `800x600` operands, asset dimensions, or test fixtures into profile
|
||||
variables merely because they contain the same numbers.
|
||||
- Do not add a second SYS4INI decoder or read the generated `build/asset-index.json` at runtime.
|
||||
|
||||
### Design
|
||||
|
||||
1. **Parse the settings record at the existing catalog boundary.**
|
||||
|
||||
`Sys4AssetCatalog.Parse` already owns the decompressed S4IC blob and ends with `p` immediately after
|
||||
the raw file records. For a base S4IC catalog, continue from there through the bounded VM-metadata
|
||||
block and settings record documented in `sys4-format-notes.md`. Append S4AC catalogs do not provide
|
||||
the selected game's startup profile.
|
||||
|
||||
Add a platform-neutral settings value on the base catalog, tentatively
|
||||
`Sys4StartupSettings`. Preserve the ordered CP932 key/value pairs for diagnostics and expose a
|
||||
case-insensitive last-value-wins lookup matching AGE's registry assignment behavior. Unknown keys are
|
||||
retained rather than rejected by the generic parser so a newer game can be inspected before every
|
||||
setting has a runtime consumer.
|
||||
|
||||
The parser must bounds-check both length-prefixed blocks, the pair count, every terminating NUL, and
|
||||
exact settings-string consumption. A genuinely absent trailer yields an empty settings set and hence
|
||||
AGE defaults; a structurally present but truncated or inconsistent trailer is an
|
||||
`InvalidDataException` naming the source catalog and field.
|
||||
|
||||
2. **Resolve one immutable logical-canvas value.**
|
||||
|
||||
Add a small engine-owned integer size type or settings projection so Godot does not become the owner
|
||||
of SYS4 semantics. Resolve `SCREENX` and `SCREENY` independently from the raw settings, using 640 and
|
||||
480 respectively when missing, nonnumeric, zero, or negative. Validate checked pixel count and byte
|
||||
count once at this boundary. All downstream systems receive the already-validated size and must not
|
||||
reinterpret the strings or invent their own fallback.
|
||||
|
||||
3. **Reorder Godot bootstrap around the selected profile.**
|
||||
|
||||
Refactor `Main._Ready()` into the necessary startup phases:
|
||||
|
||||
```text
|
||||
read existing boot arguments
|
||||
-> load base catalog once
|
||||
-> obtain validated logical canvas
|
||||
-> configure root content-scale base and initial window
|
||||
-> allocate presentation nodes/buffers
|
||||
-> construct persistence, assets, host, and VM from the same catalog
|
||||
```
|
||||
|
||||
Remove the later duplicate normal-path `Sys4AssetCatalog.Load`. Keep `project.godot` dimensions only
|
||||
as a harmless pre-script bootstrap/fallback; they are not the selected game's resolution. In windowed
|
||||
mode, set the initial client size to the logical canvas. Configure the root viewport's content scale
|
||||
to that logical size with aspect preservation so slice two can vary the physical window without
|
||||
changing the game coordinate system. A pre-existing fullscreen launch retains the display's physical
|
||||
size while using the same logical base.
|
||||
|
||||
4. **Replace frontend canvas constants with runtime state.**
|
||||
|
||||
Replace `Main.ScreenWidth`/`ScreenHeight` and the field-initialized pixel array with validated
|
||||
`_screenWidth`, `_screenHeight`, and a buffer allocated after profile loading. Carry those dimensions
|
||||
through:
|
||||
|
||||
- immediate backbuffer creation/publication;
|
||||
- GPU/software compositor destination bounds and performance accounting;
|
||||
- whole-canvas fills and transition captures;
|
||||
- primary surface slot zero and native-sized movie surfaces;
|
||||
- fallback ADV layout bounds;
|
||||
- retained-object fallback geometry;
|
||||
- pointer-to-logical-coordinate conversion.
|
||||
|
||||
Give `GodotAdvHost` the logical size explicitly rather than letting it duplicate defaults.
|
||||
`RetainedSurfaceRasterizer` already receives an `RgbaImage` destination; its null-source whole-canvas
|
||||
fill fallback should use `destination.Width/Height`, not a new global.
|
||||
|
||||
Input conversion must have one scaling owner. Once Godot content scaling is active, derive logical
|
||||
coordinates through the root viewport/canvas transform (including letterbox exclusion) instead of
|
||||
applying the current whole-window `position * 800 / viewport` ratio a second time.
|
||||
|
||||
5. **Audit, do not mechanically replace, numeric fixtures.**
|
||||
|
||||
Review every runtime `800`/`600` occurrence. Replace values that mean “current engine canvas” and leave
|
||||
values that are:
|
||||
|
||||
- operands authored by Himegari scripts;
|
||||
- dimensions of installed Himegari assets;
|
||||
- focused regression inputs whose subject is unrelated to profile sizing;
|
||||
- opcode constants such as `0x8000`.
|
||||
|
||||
Update comments that currently call input or slot zero specifically “800x600” when they mean the
|
||||
selected logical canvas.
|
||||
|
||||
### Verification
|
||||
|
||||
Engine tests:
|
||||
|
||||
- parse the installed SYS4INI and assert all 36 pairs plus `800x600`;
|
||||
- parse a synthetic bounded trailer with `SCREENX=1024`, `SCREENY=576` and prove the projected canvas;
|
||||
- prove absent keys fall back independently to `640x480`;
|
||||
- reject truncated lengths, missing NULs, count/byte mismatches, and unsafe dimensions;
|
||||
- prove duplicate/case-varied keys use the last value while unknown keys remain inspectable;
|
||||
- composite a whole-canvas retained fill into a non-800 destination and prove its exact bounds;
|
||||
- construct host/canvas-facing state with a non-800 size and prove slot zero and fallback ADV layout use it.
|
||||
|
||||
Godot gates:
|
||||
|
||||
- zero-warning build and threaded `SELFTEST OK`;
|
||||
- selftest asserts/logs the selected logical canvas, root content-scale base, backbuffer dimensions, and
|
||||
default windowed size;
|
||||
- ordinary Himegari boot reports `SYS4INI 800x600`, opens at 800x600, and reaches the existing SC0000
|
||||
presentation with unchanged input coordinates and compositor output;
|
||||
- a diagnostic non-800 profile/settings fixture reaches presentation allocation without any 800x600
|
||||
fallback in buffer size, primary-surface size, compositor bounds, or pointer coordinates.
|
||||
|
||||
Static closeout:
|
||||
|
||||
- `rg` audit all runtime `800`/`600` occurrences and classify every survivor;
|
||||
- update `engine-re.md`, `sys4-format-notes.md`, the roadmap/profile boundary, portability inventory,
|
||||
this slice's result, and status memory;
|
||||
- update `PROJECT-STRUCTURE.md` only if the implementation introduces a new settings/profile source
|
||||
category, and `tools-reference.md` only if a tool changes.
|
||||
|
||||
### Slice-two handoff
|
||||
|
||||
After this slice, logical and physical size are equal by default but are represented separately. The next
|
||||
slice may add:
|
||||
|
||||
```text
|
||||
--window-width <pixels>
|
||||
--window-height <pixels>
|
||||
```
|
||||
|
||||
Those parameters will override only the physical window dimensions. Godot will scale the unchanged
|
||||
SYS4INI-sized logical canvas into that window using the aspect-preserving/letterbox policy. Validation of
|
||||
partial overrides, minimum sizes, fullscreen interaction, integer scaling, and alternate stretch/crop
|
||||
policies belongs to that second slice's configuration design.
|
||||
|
||||
## ADV requested-face selection implemented (2026-07-28)
|
||||
|
||||
Opcode `0x1a5` is no longer a presentation no-op. The VM retains its requested face in
|
||||
|
||||
@@ -27,7 +27,7 @@ or replaced before claiming portable exports.
|
||||
|
||||
| Area | Current dependency | Runtime impact | Portability status / future action |
|
||||
|---|---|---|---|
|
||||
| SYS4INI per-game startup profile | `Sys4AssetCatalog` currently parses only the asset directory; the frontend hard-codes Himegari's important results. Native SYS4INI also carries canvas, text, ADV input/skip, save ABI/path, audio, legacy renderer, and Windows registration settings | The port has the correct `800x600`, requested faces, save 3.10, and redirected `user://SAVE` result, but does not source `CancelMesSkipOnClick`, `CoexistMesSkip`, cursor/redraw policy, or wheel action ids from the trailer | Add one typed profile/settings parser. Apply cross-platform semantic keys explicitly; translate save roots through the host; classify DirectDraw/fullscreen-bit and registration/key settings as native compatibility metadata rather than OS-neutral requirements. Canonical inventory and consumers: `sys4-format-notes.md` and `engine-re.md` |
|
||||
| SYS4INI per-game startup profile | `Sys4AssetCatalog` currently parses only the asset directory; the frontend hard-codes Himegari's important results. Native SYS4INI also carries canvas, text, ADV input/skip, save ABI/path, audio, legacy renderer, and Windows registration settings | The port has the correct `800x600`, requested faces, save 3.10, and redirected `user://SAVE` result, but does not source `CancelMesSkipOnClick`, `CoexistMesSkip`, cursor/redraw policy, or wheel action ids from the trailer | First parse `SCREENX`/`SCREENY` into a platform-neutral logical canvas and default the physical window to it; later boot parameters may vary only the physical window while Godot scales/letterboxes the unchanged canvas. Apply further semantic keys explicitly, translate save roots through the host, and classify DirectDraw/fullscreen-bit and registration/key settings as native compatibility metadata. Canonical inventory and consumers: `sys4-format-notes.md` and `engine-re.md` |
|
||||
| Retained graphics presentation | Backend-neutral `GfxState`; accepted default Godot `Sprite2D` GPU stage plus the retained software pixel oracle, using runtime `ImageTexture`, canvas transforms/materials, and no native graphics API | GPU backend caches static/color-key variants, updates dynamic surfaces, handles retained range transitions, and falls back whole-frame for the legacy host screen-transition path | Godot owns D3D/Vulkan/Metal/OpenGL selection; validate shader/blend/filter behavior per target rather than adding a platform renderer |
|
||||
| AGE movie decode (`0x236` scene movies; `0x20f` modal LOGO/OP/ED) | `FfmpegMovieDecoder` is the sole factory over the project-owned `native/age_movie_ffmpeg` ABI | Windows-x64 passes the complete 213-payload installed video/audio corpus gate plus audible LOGO/OP/CHAPTER playback | Add target-specific native builds and export packaging |
|
||||
| Movie integration | Each surface owns a unique playback-instance id; `MovieRuntime` owns `IMovieDecoder` from an injected factory; video-only streams use monotonic pacing while audio-bearing streams use the Godot output clock | Concurrent/restarted uses of one asset have independent frame/audio/completion/teardown state; managed code is no longer Windows-annotated, while only the win-x64 native bundle exists today | Add Linux/macOS native builds and smoke gates |
|
||||
|
||||
@@ -685,8 +685,11 @@ Windows compatibility metadata. A future generic profile loader should parse tha
|
||||
unknown/profile-specific data for diagnostics, apply cross-platform semantic settings through explicit
|
||||
runtime seams, and classify legacy renderer/registration switches rather than blindly emulating them.
|
||||
The current frontend's scattered Himegari constants are acceptable while gameplay is the priority, but
|
||||
they are not the multi-profile architecture. This experiment was diagnostic only; no Kamidori support or
|
||||
`0x1be` semantics were implemented.
|
||||
they are not the multi-profile architecture. The first bounded implementation slice will source the
|
||||
logical canvas from `SCREENX`/`SCREENY` and use it as the default windowed size; a second slice will add
|
||||
independent physical `--window-width`/`--window-height` overrides without changing VM coordinates or
|
||||
surface geometry. The executable task plan and gates live in `phase-a-slice-plan.md`. This experiment was
|
||||
diagnostic only; no Kamidori support or `0x1be` semantics were implemented.
|
||||
|
||||
### Other engine versions (SYS3 / SYS5) — one app, not many
|
||||
Versions differ in: header (SYS4 `0x3C` vs SYS5 `0x44`), string codec (SYS4 cp932^0xFF vs SYS5
|
||||
|
||||
Reference in New Issue
Block a user