Q1 of the menu port, measured against the running game rather than reasoned
about. The developer-logo splash is the cheap target: it is the first thing the
guest draws and its bundle declares short, unambiguous ramps.
Two results, both frame-exact and both emulator-speed-independent (frame numbers
are VdSwap counts, the guest's own frames):
* the ramp is LINEAR. A declared 15-unit fade lands on round(255*k/15) for all
seven of its samples with zero error, k stepping 2,4,6,8,10,12,14. No ease
can reproduce a constant step of 34 at both ends.
* the animation clock advances 2.000 time units per submitted frame, over six
consecutive intervals with no residual, with 1 unit as the quantum
underneath (one frame in the fade-out advances by 1).
The conversion to seconds is one step further and is flagged as such: 300 frames
took 10.87 s = 27.6 present-frames/second, which reads as a 30 Hz title at 92 %
under the emulator and gives 1 unit = 1/60 s -- the title build 4.2 s, the main
menu build 1.1 s. That reading is not proven, because the rate was measured
while the guest was still streaming from the ISO; the page names the one test
that would settle it and says what changes if it goes the other way.
Committed beside it: the raw draw capture and the per-frame quad CSV, so the
numbers can be re-derived without a disc or an emulator.
110 lines
6.4 KiB
Markdown
110 lines
6.4 KiB
Markdown
# Handoff — what the menu port needs, and where it stands
|
||
|
||
The single page the **port agent** reads. Everything here is produced by the
|
||
container agent's reverse engineering; nothing here is a design decision about
|
||
the port itself.
|
||
|
||
Keep it current. It is a summary with links into `docs/re/`, not a second copy of
|
||
the findings — but an answer that is not reachable from this page has not been
|
||
delivered.
|
||
|
||
## How to read an answer
|
||
|
||
Every row below is one of exactly three things, and the distinction is the point:
|
||
|
||
| | meaning | what the port should do |
|
||
|---|---|---|
|
||
| **decoded** | a field on the disc, with a disc-wide check | read it from the data |
|
||
| **measured** | not on the disc in any form we found, but the running game does *this* | hardcode it, and cite this page |
|
||
| **undecodable** | we looked in these places, it is not there, here is the reach of the negative | author it by hand, knowingly |
|
||
|
||
There is no fourth kind. If a row says *measured* or *undecodable*, the port is
|
||
**authoring** that value, not transcribing it — and it should be kept somewhere a
|
||
human can see it is a human decision, so that when it is later decoded the
|
||
authored version can be deleted.
|
||
|
||
## Status
|
||
|
||
| | Question | State | Answer / link |
|
||
|---|---|---|---|
|
||
| Q1 | keyframe time unit + ramp shape | ✅ answered | ramp is **linear**; the clock advances **2 units per rendered frame**; working conversion **1 unit = 1/60 s** — [`ui-keyframe-time-unit.md`](../re/ui-keyframe-time-unit.md) |
|
||
| Q2 | which build is which screen state | 🟡 partial | build 4 title, 5 main menu, 6/8/9 submenus, `palogo` splash — unconfirmed against captures |
|
||
| Q3 | paint order for the six screens | ❔ open | runtime-solved only; declaration table is refuted |
|
||
| Q4 | button → GamePart | ❔ open | labels are baked into sprites |
|
||
| Q5 | navigation semantics | ❔ open | |
|
||
| Q6 | boot sequence + what drives it | 🟡 partial | order observed; the driver is not decoded |
|
||
| Q7 | transitions | ❔ open | |
|
||
| Q8 | menu audio bindings | ❔ open | cue table complete, event binding is not |
|
||
| Q9 | video binding + playback rules | 🟡 partial | `ADV.wmv` is the boot intro; new-game intro unidentified |
|
||
| Q10 | music-bank sub-wave roles (intro+loop?) | ❔ open | we concatenate blindly today |
|
||
| S1 | Ready Room go/no-go | ❔ open | probe not run |
|
||
|
||
## Already settled — the port can rely on these today
|
||
|
||
* **`GP_TITLE.pak` is the whole title-side tree.** Build 4 is the title with the
|
||
animating wordmarks, build 5 the five-button main menu, builds 6/8/9 are
|
||
submenus, and the developer splash is the `palogo` bundle in the same archive.
|
||
✅ decoded (enumeration), 🟡 the state labels are not yet capture-confirmed.
|
||
* **Buttons are identifiable as data.** Element kind `0x3002` = button, `0x0` =
|
||
decoration, `0x10` = primitive. ✅ decoded.
|
||
* **Menu order is geometric.** Buttons sorted top-to-bottom by resting Y. This is
|
||
✅ correct for a vertical menu and is **not** a decoded neighbour graph — the
|
||
disc's real navigation structure is unknown, and `opt ` is *not* a focus link
|
||
(measured and refuted, see
|
||
[`ui-focus-and-effect-elements.md`](../re/structures/ui-focus-and-effect-elements.md)).
|
||
* **Highlighted states pair by name** — `ptbtn01.rat` ↔ `ptbtn01f.rat`. 🟡 a
|
||
naming convention that holds for all 54 real pairs, not a decoded field.
|
||
* **The resting pose is the hold**, not the first, last or longest-dwell keyframe;
|
||
a keyframe is the **start of a ramp**.
|
||
[`ui-resting-pose.md`](../re/structures/ui-resting-pose.md). ✅
|
||
* **That ramp is linear, and it runs at 2 keyframe time units per rendered
|
||
frame.** Measured frame-by-frame off the running game's own draw stream: a
|
||
declared 15-unit fade lands on `round(255·k/15)` for all seven of its samples,
|
||
with `k` stepping 2, 4, 6, 8, 10, 12, 14 on seven consecutive submitted frames.
|
||
**measured**, not decoded — the disc says `t=30`, it does not say what a `t` is.
|
||
The seconds conversion (`1 unit = 1/60 s`, so a 30 fps screen) rests on a
|
||
measured 27.6 present-frames/second and is the one part still worth re-testing;
|
||
[`ui-keyframe-time-unit.md`](../re/ui-keyframe-time-unit.md) names the test.
|
||
If it turns out the game presents at 60 Hz, every duration halves — nothing
|
||
else on this page changes.
|
||
* **The GamePart id table** — 29 entries at `.rdata 0x820A1630`, confirmed by the
|
||
executable's own registration strings. ✅ This is the screen vocabulary; which
|
||
button reaches which entry is Q4 and is *not* part of it.
|
||
* **The logo splash is a screen, not a video.** `logo1`–`logo4` are
|
||
manifest-bound with no `.wmv` on the disc. ✅
|
||
* **Sprites carry their own labels.** No font rendering or localisation is needed
|
||
for this milestone. ✅
|
||
|
||
## Facts the port will trip over
|
||
|
||
* **`ADV.wmv` is WMV3 video + WMA Pro audio**, 1280×720 at 30 fps, 137 s. Godot 4
|
||
plays only Ogg Theora natively. How to handle that is the port's decision, not
|
||
ours — but it is not optional.
|
||
* **The disc holds 3.3 GB of video.** Only the boot intro and the one new-game
|
||
intro are in scope.
|
||
* **`Static.slb` over-declares its size** by 616 768 bytes — it is the
|
||
highest-offset entry in `sound.pak` and its size field is an allocation size. A
|
||
reader must allow a short read there and only there.
|
||
* **Voice downmixes to mono, music does not.** The left-channel downmix is correct
|
||
for spoken lines and discards half a music mix.
|
||
* **A music bank has several sub-waves and we glue them together.** `BGM_001`
|
||
is 10 KB + 4.47 MB + 4.67 MB, concatenated into one 347 s track. Nobody has
|
||
established whether those are intro + loop, two variations, or two halves —
|
||
see Q10. Do not build menu looping on the concatenated track until it is
|
||
answered.
|
||
* **`JNGL_001.slb` does not decode.** One bank in 9 519; its payload is not a whole
|
||
number of XMA1 packets from any known data offset.
|
||
|
||
## Reference data
|
||
|
||
Committed alongside the findings, so the port can be built without a disc in the
|
||
loop during development:
|
||
|
||
* `sylpheed-cli screen info --build <n> GP_TITLE.pak` — the element table, per
|
||
build, with pivots, kinds, focus links, keyframes and resting poses.
|
||
* `sylpheed-cli screen render` — the reference composite. When the port draws a
|
||
screen, this is what it should be diffed against; where they disagree, one of
|
||
them is wrong and the disagreement is worth reporting back.
|
||
* `docs/re/captures/` — framebuffer captures of the real screens, for anything
|
||
that has to be checked against the game rather than against our renderer.
|