engine: complete portable glyph text backend
This commit is contained in:
@@ -118,7 +118,8 @@ S:\Game Hacking\Eushully\Himegari\ ← workspace root (three siblings)
|
||||
├── tools/frida/ runtime-capture + engine-dump scripts (see tools/frida/README.md)
|
||||
└── godot/ DELIVERABLE — the Godot/C# ADV front-end (references Age.Engine
|
||||
plus the optional exact Windows text adapter), including the
|
||||
TITLE-only F4 debug scene launcher
|
||||
portable TextServer glyph adapter, per-profile font-substitution
|
||||
configuration, and TITLE-only F4 debug scene launcher
|
||||
```
|
||||
|
||||
The disposable `build/page-map-<SCENE>.jsonl` files are produced by normal Godot runs and map runtime ADV
|
||||
|
||||
@@ -3650,6 +3650,30 @@ The required fidelity follow-up is implementation of that decoded mask contract;
|
||||
validation evidence, not the source of rendering behavior. That work is deferred until gameplay settles
|
||||
and is scoped in `docs/remake-architecture-and-roadmap.md`; it is not the next Phase A/B slice.
|
||||
|
||||
## ADV portable glyph backend and Label retirement (2026-07-30)
|
||||
|
||||
Godot TextServer is now the portable glyph-mask source. It exposes rasterized atlas coverage plus glyph
|
||||
offset and horizontal advance without adding a second native font library; AGE's existing deterministic
|
||||
compositor still owns effects, integer blending, layout, surfaces, and retained publication. Portable
|
||||
requests use Unicode directly and carry CP932 only when representable so the existing Japanese wrap rules
|
||||
remain available. TextServer's second advance component is intentionally ignored because it describes
|
||||
vertical-layout advance rather than GDI's horizontal `gmCellIncY`.
|
||||
|
||||
`godot/config/himegari-text-rendering.json` owns the policy id, bounded font/glyph cache capacities, and
|
||||
ordered Mincho/Gothic/default system-family substitutions. The backend reports itself as explicitly
|
||||
non-GDI-exact. Startup option `--text-backend auto|gdi|portable` retains the acceptance seam: `auto` chooses
|
||||
the exact ACP-932 GDI path when available and otherwise the portable policy, while forced `gdi` fails
|
||||
clearly instead of changing fidelity silently.
|
||||
|
||||
After forced portable and forced exact modes both passed immediate-surface, live-layout, History,
|
||||
complete-line, bounded-cache, retained publication/reset, GPU-upload, surface-copy, and clear gates, the
|
||||
gameplay `Label` pools were deleted. Immediate, live, and History text no longer has a top-level overlay or
|
||||
metadata projection path; mask/backend failures are explicit, and all gameplay text inherits the bound
|
||||
surface's z-order, alpha, tint, fade, transform, clipping, capture, and lifetime.
|
||||
|
||||
Validation: engine **580/580**, zero-warning Godot build, and threaded `SELFTEST OK` in both forced
|
||||
`portable-godot-textserver` and forced `windows-gdi-gray4` modes.
|
||||
|
||||
## Persistence native-format reconnaissance complete (2026-07-24)
|
||||
|
||||
The deferred save/profile ownership question now has a compatibility-mode answer. The remaining native
|
||||
|
||||
@@ -33,7 +33,7 @@ or replaced before claiming portable exports.
|
||||
| AGE movie decode (`0x236` scene movies; `0x20f` modal LOGO/OP/ED; `0x24d` movie masks) | `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 and real TEST.AGF green-mask decode | 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. Opcode `0x24d` redirects decoded green bytes through the platform-neutral retained rasterizer and exact managed packed-alpha mask helper | Concurrent/restarted uses of one asset have independent frame/audio/completion/teardown state. Ordinary and mask movies share VFS/FFmpeg ownership; the mask result is a backend-neutral dynamic RGBA surface consumed by either Godot renderer. Managed code is no longer Windows-annotated, while only the win-x64 native bundle exists today | Add Linux/macOS native builds and smoke gates |
|
||||
| Movie audio | ABI v2 returns timestamped stereo float PCM; bounded managed buffering feeds a per-playback Godot `AudioStreamGenerator` and routes native movie flags to engine buses | All 29 installed audio-bearing streams decode with signal; synchronized LOGO/OP/CHAPTER playback is audibly accepted | Treat absent, distorted, or unsynchronized audio from an audio-bearing movie as a runtime bug |
|
||||
| ADV font discovery/raster fidelity | `Age.Engine.Text` remains OS-neutral. Godot selects the separate `Age.Engine.Text.Windows` backend for immediate `0x204`/`0x205` strings, live ADV, and retained History when Windows ACP 932 is available; exact masks are cached, composited into layout/numbered RGBA surfaces, and published through ordinary retained handles. The wait atlas is likewise bound at its script-configured handle and no longer uses a detached Godot node. The fallback loads Windows `MS 明朝`/`MS ゴシック` when available and otherwise chooses the Japanese/default font with FreeType embolden and a Godot outline | Three Mincho/Gothic regular/bold samples byte-match an independent Unicode GDI oracle. Immediate, live, History, and wait-marker presentation now obey retained ordering, alpha/tint/fade, transforms, clipping, capture, HIDEWIN suspension, partial erase/republication, reset, and History teardown. Non-Windows/non-932 runs report why exact text selection failed and atomically retain the old Label presentations; they do not claim GDI parity | Add an explicitly non-identical portable backend and face-substitution policy, then remove the unavailable-rasterizer Label fallback and its remaining overlay compensations. Keep the GDI project out of non-Windows deliverables rather than hiding failed exact selection |
|
||||
| ADV font discovery/raster fidelity | `Age.Engine.Text` remains OS-neutral. On compatible ACP-932 Windows, `auto` selects the separate exact `Age.Engine.Text.Windows` GDI gray-4 backend. Otherwise Godot TextServer supplies Unicode masks and metrics from ordered system-font substitutions in `godot/config/himegari-text-rendering.json`; this policy is explicitly not GDI pixel-exact. Immediate `0x204`/`0x205`, live ADV, retained History, and the wait atlas all enter ordinary RGBA surfaces/retained handles | Three Mincho/Gothic regular/bold samples byte-match an independent Unicode GDI oracle. Forced exact and forced portable self-tests cover immediate, live, and History rasterization, bounded caching, complete-line materialization, retained ordering, alpha/tint/fade, transforms, clipping, capture, HIDEWIN suspension, partial erase/republication, reset, and teardown. Gameplay `Label` pools and overlay projection are gone | Produce and smoke-test Linux/macOS exports, confirm installed family availability/fallback selection there, and keep the GDI project out of non-Windows deliverables |
|
||||
| Filesystem semantics | Several filename and containment comparisons use `OrdinalIgnoreCase`; installed assets are conventionally uppercase | Needs validation on case-sensitive filesystems; may hide casing or containment mistakes | Add Linux/macOS tests with mixed-case synthetic roots and use filesystem-appropriate containment rules |
|
||||
| Save/profile/settings storage | `Sys4PersistencePaths` models AGE's independent `SAVEPATH` and `REGFILEPATH` resolutions. Godot replaces Himegari's related profile directory with `user://`, yielding `user://SAVE` for native S3SD/S4SD/S3RT files and thumbnails plus `user://SYS4REG.INI` for the BOM-less CP932 options file; the preserving writer changes only its nine `[sound]` keys | Save payloads and engine options are isolated together without changing either native format. Native/drop-in resolution remains available through `USEAPPDATAFOLDER` plus both SYS4INI paths. A single-root override is rejected when `SAVEPATH` is not beneath `REGFILEPATH`, preventing cross-profile guesses | Expose explicit profile/native selection through the future launcher and allow independent overrides for profiles whose two native paths are unrelated. Validate CP932 availability, replace/flush, case, permissions, and interrupted-write behavior on each export target |
|
||||
| Game-install and repository discovery | `GameRootSelection` accepts `--game-root`, then probes the executable directory and current working directory for `SYS4INI.BIN`; on Unix the frontend prefers inherited shell `PWD` because Godot may change the process directory during project startup. Godot injects the selected root into its catalog and loose-first ALF store. `Paths.cs` remains the development/test locator for generated opcode data, diagnostics, and CLI conveniences | Installed game data no longer depends on the workspace sibling layout, enabling an executable beside `AGE.EXE`, a terminal launch from the install, or a launcher-supplied absolute profile root. A packaged export still needs its generated runtime metadata bundled independently of repository discovery | Add export packaging for the opcode/profile artifacts, let the future profile launcher pass `--game-root`, and run executable-directory/CWD plus case/permission smoke gates on Linux and macOS |
|
||||
|
||||
@@ -635,16 +635,17 @@ primitive, which cannot be made equivalent by choosing another embolden constant
|
||||
the persisted backlog. The configured wait atlas now binds at op `0x212`'s handle, advances source cells
|
||||
only on the configured frame boundary, participates in op-`0x20a` republication and HIDEWIN suspension,
|
||||
and disappears when the wait service stops. The standalone Godot wait `TextureRect` and its raw-callback
|
||||
visibility exception are gone. Exact History no longer enters the layout-keyed Label pool; that code and
|
||||
the live/immediate Label pools remain solely as the explicit unavailable-rasterizer fallback until step 7
|
||||
supplies the portable glyph backend. Focused lifecycle tests, all 579 engine tests, the exact History
|
||||
visibility exception are gone. At this checkpoint exact History no longer entered the layout-keyed Label
|
||||
pool; step 7 subsequently supplied the portable backend and removed every remaining gameplay Label pool.
|
||||
Focused lifecycle tests, all 579 engine tests, the exact History
|
||||
Godot self-test, and a real SC0000 Vulkan capture cover the retained path.
|
||||
7. **Complete and select the portable backend.** Spike the smallest maintainable way to obtain portable
|
||||
font masks/metrics (Godot/TextServer offscreen extraction versus a bounded FreeType-compatible adapter)
|
||||
before choosing a dependency. Define face substitution and raster policy as profile/configuration data,
|
||||
keep its output explicitly non-identical to GDI, and run the same layout/compositor tests. Retain a
|
||||
development-only backend switch through acceptance; remove the old Label fallback only when both exact
|
||||
Windows and portable startup/legibility gates pass.
|
||||
7. **Complete and select the portable backend — completed 2026-07-30.** Godot's TextServer atlas is the
|
||||
portable mask/metrics source, avoiding another native dependency. Profile data in
|
||||
`godot/config/himegari-text-rendering.json` owns ordered Mincho/Gothic substitutions and bounded cache
|
||||
sizes. `auto` selects exact GDI when its ACP-932 gate passes and otherwise selects the explicitly
|
||||
non-pixel-exact Unicode backend; development runs can force either with `--text-backend`. Both modes pass
|
||||
the same immediate/live/History retained-glyph self-test. Gameplay `Label` pools and surface-text overlay
|
||||
projection are removed, so text always participates in the ordinary surface compositor.
|
||||
|
||||
**Acceptance gates:**
|
||||
|
||||
|
||||
@@ -346,6 +346,11 @@ use the last `input-wait` event in `timeline.jsonl` as the authoritative manual
|
||||
are current-working-directory-relative. This is the stable handoff for future game-profile launchers.
|
||||
- `--scene <NAME>` — override the default `SYSTEM4` root with a direct diagnostic scene, e.g. `--scene SC0240` (executes 29 nested subroutines).
|
||||
- `--selftest` — headless; runs a **synthesized** scene through the thread/suspend/`CallDeferred` plumbing and asserts it matches a live headless run (full handling; no vm0/frozen golden). Exits.
|
||||
- `--text-backend auto|gdi|portable` — select gameplay glyph-mask rasterization. `auto` (default) uses the
|
||||
exact GDI gray-4 backend only when the Windows ACP-932 gate passes, otherwise the explicitly non-identical
|
||||
Godot TextServer Unicode policy. `gdi` fails startup when exact selection is unavailable; `portable`
|
||||
never initializes GDI and is the cross-platform acceptance/debug mode. The selected backend and portable
|
||||
policy id are printed at startup.
|
||||
- `--window-width <pixels>` / `--window-height <pixels>` — override only the physical windowed client
|
||||
dimensions; each omitted dimension defaults independently to the SYS4INI logical canvas. Godot keeps
|
||||
that logical canvas and aspect-preserving letterboxing, so these options do not change VM coordinates,
|
||||
|
||||
Reference in New Issue
Block a user