re: the transition between screens is a fade through black, and most of
its timing is on the disc Q7. Every title-side screen carries a full-screen black .prm quad that paints last, and its keyframe group IS the transition: black at T0, clear by T1, clear until T2, then back to black on exit. Read with the corpus's start-of-a-ramp rule and Q1's time unit that gives 0.87s for EXTRAS, 0.97s for the main menu, 4.08s for the title -- from the file, not from a stopwatch. The disc-wide check is per-pak all-or-nothing rather than the 41% the headline count suggests, and GP_TITLE's 6 of 12 is the useful row: the six builds carrying a fade quad are exactly the six SCREENS, and the six without are exactly the six overlays. GP_DIALOG is 0 of 133. That is independent corroboration of the overlay finding from two iterations ago. One piece is NOT on the disc and says so: the fade-OUT length. The fourth keyframe has no time slot, because a group's last block stops four bytes short. Measured instead, at 30fps, ~0.4s and the same both directions. And a warning I earned: the luminance rise after a transition is NOT the quad's ramp. The incoming screen's own elements animate in after the quad has cleared -- 1.47s observed against a declared 0.97s. Time the fade from where the frame is pure black. Rig: screenshot samples at 0.5 Hz and cannot see a 0.4s fade at all, which is why an earlier burst called this an instant cut. ffmpeg x11grab at 30fps instead; both go in METHOD.
This commit is contained in:
@@ -31,9 +31,9 @@ authored version can be deleted.
|
|||||||
| Q2 | which build is which screen state | ✅ answered | `GP_TITLE` is **8 screens shipped twice, EN/JP**: 4/7 title art, 2/3 the `PRESS Ⓐ` plate, 5/8 main menu, 6/9 `EXTRAS`, 0/1 and 10/11 two unidentified `DELTASABER` plates — [`ui-title-build-map.md`](../re/ui-title-build-map.md) |
|
| Q2 | which build is which screen state | ✅ answered | `GP_TITLE` is **8 screens shipped twice, EN/JP**: 4/7 title art, 2/3 the `PRESS Ⓐ` plate, 5/8 main menu, 6/9 `EXTRAS`, 0/1 and 10/11 two unidentified `DELTASABER` plates — [`ui-title-build-map.md`](../re/ui-title-build-map.md) |
|
||||||
| Q3 | paint order for the six screens | ✅ answered | **decoded**: a `u16` layer key at `+0x0A` of each `T8aD` sprite header, stable-sorted with declaration index; unkeyed elements get an implied key. Confirmed on 5 measured orders + `EXTRAS` vs a capture. One residual: the **tie-break** is unknown and bites on one element of the title — [`structures/ui-paint-order-key.md`](../re/structures/ui-paint-order-key.md) |
|
| Q3 | paint order for the six screens | ✅ answered | **decoded**: a `u16` layer key at `+0x0A` of each `T8aD` sprite header, stable-sorted with declaration index; unkeyed elements get an implied key. Confirmed on 5 measured orders + `EXTRAS` vs a capture. One residual: the **tie-break** is unknown and bites on one element of the title — [`structures/ui-paint-order-key.md`](../re/structures/ui-paint-order-key.md) |
|
||||||
| Q4 | button → GamePart | 🟡 mostly answered | **measured** which screen each button opens (4 of 5; `NEW GAME` untested — it hangs). The **GamePart id is a name match** onto the decoded id table, not a measurement — [`menu-navigation-semantics.md`](../re/menu-navigation-semantics.md) |
|
| Q4 | button → GamePart | 🟡 mostly answered | **measured** which screen each button opens (4 of 5; `NEW GAME` untested — it hangs). The **GamePart id is a name match** onto the decoded id table, not a measurement — [`menu-navigation-semantics.md`](../re/menu-navigation-semantics.md) |
|
||||||
| Q5 | navigation semantics | ✅ answered | **measured**: opens on `TUTORIAL` (not the top); ⬆⬇ one step, **wraps both ends**; ⬅➡ do nothing; Ⓑ returns to the parent **with focus restored**; Ⓑ on the main menu → title; Ⓑ on the title → nothing — [`menu-navigation-semantics.md`](../re/menu-navigation-semantics.md) |
|
| Q5 | navigation semantics | ✅ answered | **measured**: initial focus varies boot to boot (2× `TUTORIAL`, 1× `NEW GAME`); ⬆⬇ one step, **wraps both ends**; ⬅➡ do nothing; Ⓑ returns to the parent **with focus restored**; Ⓑ on the main menu → title; Ⓑ on the title → nothing — [`menu-navigation-semantics.md`](../re/menu-navigation-semantics.md) |
|
||||||
| Q6 | boot sequence + what drives it | 🟡 partial | order observed, and the **attract cycle is timed**: ~8–10 s idle on the title → fade to black → ~85 s of video → title again, plate and all. The driver is still not decoded |
|
| Q6 | boot sequence + what drives it | 🟡 partial | order observed, and the **attract cycle is timed**: ~8–10 s idle on the title → fade to black → ~85 s of video → title again, plate and all. The driver is still not decoded |
|
||||||
| Q7 | transitions | ❔ open | |
|
| Q7 | transitions | ✅ answered | a **fade through black**, drawn by the screen's own last-painting `.prm` quad. Fade-in ramp is **decoded** from its keyframes; the ~0.4 s fade-out is **measured** (not in the file) — [`screen-transitions.md`](../re/screen-transitions.md) |
|
||||||
| Q8 | menu audio bindings | ❔ open | cue table complete, event binding is not |
|
| 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 |
|
| 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 |
|
| Q10 | music-bank sub-wave roles (intro+loop?) | ❔ open | we concatenate blindly today |
|
||||||
@@ -97,10 +97,9 @@ authored version can be deleted.
|
|||||||
* **Menu movement, measured off the running game.** ⬆⬇ move one item per press
|
* **Menu movement, measured off the running game.** ⬆⬇ move one item per press
|
||||||
and **wrap at both ends** (5-item main menu and 3-item `EXTRAS` both). ⬅➡ do
|
and **wrap at both ends** (5-item main menu and 3-item `EXTRAS` both). ⬅➡ do
|
||||||
nothing. Ⓑ goes up one level **and restores focus to the item you came from**;
|
nothing. Ⓑ goes up one level **and restores focus to the item you came from**;
|
||||||
Ⓑ on the main menu returns to the title; Ⓑ on the title does nothing. The main
|
Ⓑ on the main menu returns to the title; Ⓑ on the title does nothing. **Initial
|
||||||
menu opens focused on **`TUTORIAL`**, the middle item — 🟡 reproducible in this
|
focus is not stable**: three boots of the same script gave `TUTORIAL`,
|
||||||
harness (2/2) but a third recorded run implies `NEW GAME`, so re-test before
|
`TUTORIAL`, `NEW GAME`. Do not hardcode it; pick one and say you picked it. All **measured**, none of it on the disc.
|
||||||
hardcoding it. All **measured**, none of it on the disc.
|
|
||||||
* **Each button's destination is measured; its GamePart id is not.**
|
* **Each button's destination is measured; its GamePart id is not.**
|
||||||
`LOAD GAME` → the save-slot list, `TUTORIAL` → the lesson list, `OPTIONS` →
|
`LOAD GAME` → the save-slot list, `TUTORIAL` → the lesson list, `OPTIONS` →
|
||||||
the settings menu, `EXTRAS` → `GP_TITLE` build 6, `EXTRAS ▸ MISSION SELECT` →
|
the settings menu, `EXTRAS` → `GP_TITLE` build 6, `EXTRAS ▸ MISSION SELECT` →
|
||||||
@@ -108,6 +107,18 @@ authored version can be deleted.
|
|||||||
GamePart ids (`3`, `25`, `8`, `5`, `7`) are the entries of the decoded id table
|
GamePart ids (`3`, `25`, `8`, `5`, `7`) are the entries of the decoded id table
|
||||||
whose **names match the screens seen**; that binding is authored, not measured.
|
whose **names match the screens seen**; that binding is authored, not measured.
|
||||||
|
|
||||||
|
* **A screen change is a fade through black.** Each screen carries a full-screen
|
||||||
|
black `.prm` quad that paints last (`pteff00.prm` / `pfeff00.prm`) whose
|
||||||
|
keyframe group *is* the transition: black at `T0`, clear by `T1`, clear until
|
||||||
|
`T2`, then back to black on exit. ✅ decoded, with a disc-wide check — and in
|
||||||
|
`GP_TITLE` exactly the six **screen** builds carry it while the six overlays do
|
||||||
|
not. The fade-in length is `T1 − T0` and is read from the file (0.87 s for
|
||||||
|
`EXTRAS`, 0.97 s main menu, 4.08 s title). ❔ **The fade-OUT length is not on
|
||||||
|
the disc** — the last keyframe has no time slot; **measured ~0.4 s**, twice.
|
||||||
|
The black hold measures 0.17–0.23 s. ⚠️ Do not time the fade-in off a capture's
|
||||||
|
brightness: the incoming screen's own element animations dominate it and run
|
||||||
|
much longer than the quad.
|
||||||
|
|
||||||
* **The GamePart id table** — 29 entries at `.rdata 0x820A1630`, confirmed by the
|
* **The GamePart id table** — 29 entries at `.rdata 0x820A1630`, confirmed by the
|
||||||
executable's own registration strings. ✅ This is the screen vocabulary; which
|
executable's own registration strings. ✅ This is the screen vocabulary; which
|
||||||
button reaches which entry is Q4 and is *not* part of it.
|
button reaches which entry is Q4 and is *not* part of it.
|
||||||
|
|||||||
@@ -150,6 +150,7 @@ files, which is how the same ground got covered twice.
|
|||||||
| [`ui-paint-order-third-permutation.md`](ui-paint-order-third-permutation.md) | A third measured paint order — tool built and validated, screen not reached | ✅ the reader works and is CONFIRMED against both previously |
|
| [`ui-paint-order-third-permutation.md`](ui-paint-order-third-permutation.md) | A third measured paint order — tool built and validated, screen not reached | ✅ the reader works and is CONFIRMED against both previously |
|
||||||
| [`ui-quad-class-foothold.md`](ui-quad-class-foothold.md) | The guest's UI quad class — a foothold found from the capture's vertex layout | 🟡 PROBABLE for the identification below (it is a static read, but |
|
| [`ui-quad-class-foothold.md`](ui-quad-class-foothold.md) | The guest's UI quad class — a foothold found from the capture's vertex layout | 🟡 PROBABLE for the identification below (it is a static read, but |
|
||||||
| [`menu-navigation-semantics.md`](menu-navigation-semantics.md) | The title menu — how it moves, and where each button goes | ✅ measured: wraps both ends, Ⓑ restores focus, ⬅➡ inert; 4 of 5 destinations driven. 🟡 GamePart id is a name match, ❔ `NEW GAME` untested |
|
| [`menu-navigation-semantics.md`](menu-navigation-semantics.md) | The title menu — how it moves, and where each button goes | ✅ measured: wraps both ends, Ⓑ restores focus, ⬅➡ inert; 4 of 5 destinations driven. 🟡 GamePart id is a name match, ❔ `NEW GAME` untested |
|
||||||
|
| [`screen-transitions.md`](screen-transitions.md) | Between two screens — a fade through black, and where its timing lives | ✅ the fade quad's keyframe group is decoded (disc-wide: per-pak all-or-nothing; `GP_TITLE` = the 6 screens, not the 6 overlays); the ~0.4 s fade-OUT is measured, not on the disc |
|
||||||
| [`ui-title-build-map.md`](ui-title-build-map.md) | Which `GP_TITLE` build is which screen state | ✅ CONFIRMED for title / `PRESS Ⓐ` / main menu / `EXTRAS` against live captures; the archive is 8 screens × EN/JP, and "6/8/9 are submenus" is withdrawn |
|
| [`ui-title-build-map.md`](ui-title-build-map.md) | Which `GP_TITLE` build is which screen state | ✅ CONFIRMED for title / `PRESS Ⓐ` / main menu / `EXTRAS` against live captures; the archive is 8 screens × EN/JP, and "6/8/9 are submenus" is withdrawn |
|
||||||
| [`ui-title-paint-order-capture.md`](ui-title-paint-order-capture.md) | The title screen's paint order, measured from the guest's draw submissions | ✅ CONFIRMED — the order in which the running game paints the title |
|
| [`ui-title-paint-order-capture.md`](ui-title-paint-order-capture.md) | The title screen's paint order, measured from the guest's draw submissions | ✅ CONFIRMED — the order in which the running game paints the title |
|
||||||
| [`upstream-baseline.md`](upstream-baseline.md) | A stock-upstream baseline runs Stage 02 crash-free | ✅ CONFIRMED — upstream canary_experimental + only the pad |
|
| [`upstream-baseline.md`](upstream-baseline.md) | A stock-upstream baseline runs Stage 02 crash-free | ✅ CONFIRMED — upstream canary_experimental + only the pad |
|
||||||
|
|||||||
@@ -140,3 +140,15 @@ agent's loop prompt, i.e. nowhere durable. See [`README.md`](README.md) for the
|
|||||||
Detect the **focus ring** in the gutter left of the labels instead
|
Detect the **focus ring** in the gutter left of the labels instead
|
||||||
(`tools/re-capture/menu_focus.py`, 254 vs <82 — no threshold tuning needed),
|
(`tools/re-capture/menu_focus.py`, 254 vs <82 — no threshold tuning needed),
|
||||||
and look at the PNG before believing either.
|
and look at the PNG before believing either.
|
||||||
|
* **`screenshot` samples at 0.5 Hz — it cannot time an animation.** Measured:
|
||||||
|
~2 s per grab (an `import` of the root plus an ImageMagick crop). A 0.4 s fade
|
||||||
|
falls entirely between two samples, which is why a 40-frame burst across a
|
||||||
|
screen change looked like an instant cut. For anything timed, record the
|
||||||
|
display instead: `ffmpeg -f x11grab -framerate 30 -video_size <W>x<H> -i
|
||||||
|
:98+<X>,<Y> -t <secs>`, then read per-frame statistics off the file. Take the
|
||||||
|
geometry from `xwininfo -root -tree`, the same way `bin/screenshot` does.
|
||||||
|
* **A screen's brightness curve is not its fade quad.** The incoming screen's own
|
||||||
|
elements animate in *after* the transition quad has cleared, so mean luminance
|
||||||
|
keeps rising long after the fade is over — 1.47 s against a declared 0.97 s on
|
||||||
|
one screen. Time the fade from where the frame is *pure black*, and take the
|
||||||
|
ramp itself from the keyframes.
|
||||||
|
|||||||
@@ -35,6 +35,11 @@ neighbourhood, not just the line.
|
|||||||
|
|
||||||
## Screens, classes and RTTI
|
## Screens, classes and RTTI
|
||||||
|
|
||||||
|
* "the transition between menu screens is a cut" → it is a **fade through
|
||||||
|
black**; a 0.5 Hz screenshot burst simply samples too slowly to see it.
|
||||||
|
[`screen-transitions.md`](screen-transitions.md)
|
||||||
|
* "the main menu's initial focus is fixed" → three boots of one script gave
|
||||||
|
`TUTORIAL`, `TUTORIAL`, `NEW GAME`.
|
||||||
* "the title menus drop d-pad presses shorter than ~0.3 s" → **refuted by my
|
* "the title menus drop d-pad presses shorter than ~0.3 s" → **refuted by my
|
||||||
own data.** The menu **wraps at both ends**; every press registered, and the
|
own data.** The menu **wraps at both ends**; every press registered, and the
|
||||||
"missing" step was the wrap. See [`menu-navigation-semantics.md`](menu-navigation-semantics.md).
|
"missing" step was the wrap. See [`menu-navigation-semantics.md`](menu-navigation-semantics.md).
|
||||||
|
|||||||
BIN
docs/re/captures/transitions/transition-filmstrip.png
Normal file
BIN
docs/re/captures/transitions/transition-filmstrip.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 160 KiB |
421
docs/re/captures/transitions/transition-luminance.csv
Normal file
421
docs/re/captures/transitions/transition-luminance.csv
Normal file
@@ -0,0 +1,421 @@
|
|||||||
|
frame,seconds,mean_luminance
|
||||||
|
0,0.0000,26.045
|
||||||
|
1,0.0333,26.054
|
||||||
|
2,0.0667,26.051
|
||||||
|
3,0.1000,26.054
|
||||||
|
4,0.1333,26.049
|
||||||
|
5,0.1667,26.054
|
||||||
|
6,0.2000,26.052
|
||||||
|
7,0.2333,26.053
|
||||||
|
8,0.2667,26.046
|
||||||
|
9,0.3000,26.053
|
||||||
|
10,0.3333,26.049
|
||||||
|
11,0.3667,26.052
|
||||||
|
12,0.4000,26.047
|
||||||
|
13,0.4333,26.050
|
||||||
|
14,0.4667,26.048
|
||||||
|
15,0.5000,26.049
|
||||||
|
16,0.5333,26.047
|
||||||
|
17,0.5667,26.049
|
||||||
|
18,0.6000,26.048
|
||||||
|
19,0.6333,26.048
|
||||||
|
20,0.6667,26.045
|
||||||
|
21,0.7000,26.048
|
||||||
|
22,0.7333,26.049
|
||||||
|
23,0.7667,26.048
|
||||||
|
24,0.8000,26.046
|
||||||
|
25,0.8333,26.048
|
||||||
|
26,0.8667,26.048
|
||||||
|
27,0.9000,26.049
|
||||||
|
28,0.9333,26.047
|
||||||
|
29,0.9667,26.048
|
||||||
|
30,1.0000,26.048
|
||||||
|
31,1.0333,26.048
|
||||||
|
32,1.0667,26.047
|
||||||
|
33,1.1000,26.048
|
||||||
|
34,1.1333,26.047
|
||||||
|
35,1.1667,26.047
|
||||||
|
36,1.2000,26.046
|
||||||
|
37,1.2333,26.046
|
||||||
|
38,1.2667,26.046
|
||||||
|
39,1.3000,26.047
|
||||||
|
40,1.3333,26.046
|
||||||
|
41,1.3667,26.047
|
||||||
|
42,1.4000,26.047
|
||||||
|
43,1.4333,26.048
|
||||||
|
44,1.4667,26.047
|
||||||
|
45,1.5000,26.049
|
||||||
|
46,1.5333,26.050
|
||||||
|
47,1.5667,26.052
|
||||||
|
48,1.6000,26.051
|
||||||
|
49,1.6333,26.052
|
||||||
|
50,1.6667,26.052
|
||||||
|
51,1.7000,26.052
|
||||||
|
52,1.7333,26.052
|
||||||
|
53,1.7667,26.055
|
||||||
|
54,1.8000,26.056
|
||||||
|
55,1.8333,26.056
|
||||||
|
56,1.8667,26.055
|
||||||
|
57,1.9000,26.058
|
||||||
|
58,1.9333,26.059
|
||||||
|
59,1.9667,26.059
|
||||||
|
60,2.0000,26.057
|
||||||
|
61,2.0333,26.062
|
||||||
|
62,2.0667,26.022
|
||||||
|
63,2.1000,22.032
|
||||||
|
64,2.1333,21.744
|
||||||
|
65,2.1667,17.909
|
||||||
|
66,2.2000,13.996
|
||||||
|
67,2.2333,13.966
|
||||||
|
68,2.2667,11.113
|
||||||
|
69,2.3000,8.072
|
||||||
|
70,2.3333,7.862
|
||||||
|
71,2.3667,6.270
|
||||||
|
72,2.4000,3.375
|
||||||
|
73,2.4333,1.771
|
||||||
|
74,2.4667,0.020
|
||||||
|
75,2.5000,0.020
|
||||||
|
76,2.5333,0.020
|
||||||
|
77,2.5667,0.020
|
||||||
|
78,2.6000,0.020
|
||||||
|
79,2.6333,0.020
|
||||||
|
80,2.6667,0.020
|
||||||
|
81,2.7000,5.985
|
||||||
|
82,2.7333,5.991
|
||||||
|
83,2.7667,5.990
|
||||||
|
84,2.8000,5.991
|
||||||
|
85,2.8333,5.986
|
||||||
|
86,2.8667,7.432
|
||||||
|
87,2.9000,9.300
|
||||||
|
88,2.9333,9.283
|
||||||
|
89,2.9667,9.484
|
||||||
|
90,3.0000,11.294
|
||||||
|
91,3.0333,11.263
|
||||||
|
92,3.0667,11.606
|
||||||
|
93,3.1000,12.608
|
||||||
|
94,3.1333,12.807
|
||||||
|
95,3.1667,12.790
|
||||||
|
96,3.2000,14.517
|
||||||
|
97,3.2333,18.497
|
||||||
|
98,3.2667,26.935
|
||||||
|
99,3.3000,27.008
|
||||||
|
100,3.3333,27.010
|
||||||
|
101,3.3667,27.039
|
||||||
|
102,3.4000,27.036
|
||||||
|
103,3.4333,27.083
|
||||||
|
104,3.4667,27.239
|
||||||
|
105,3.5000,27.294
|
||||||
|
106,3.5333,27.293
|
||||||
|
107,3.5667,27.294
|
||||||
|
108,3.6000,27.289
|
||||||
|
109,3.6333,27.291
|
||||||
|
110,3.6667,27.290
|
||||||
|
111,3.7000,27.291
|
||||||
|
112,3.7333,27.289
|
||||||
|
113,3.7667,27.292
|
||||||
|
114,3.8000,27.291
|
||||||
|
115,3.8333,27.292
|
||||||
|
116,3.8667,27.291
|
||||||
|
117,3.9000,27.294
|
||||||
|
118,3.9333,27.291
|
||||||
|
119,3.9667,27.293
|
||||||
|
120,4.0000,27.290
|
||||||
|
121,4.0333,27.292
|
||||||
|
122,4.0667,27.291
|
||||||
|
123,4.1000,27.292
|
||||||
|
124,4.1333,27.290
|
||||||
|
125,4.1667,27.293
|
||||||
|
126,4.2000,27.293
|
||||||
|
127,4.2333,27.293
|
||||||
|
128,4.2667,27.292
|
||||||
|
129,4.3000,27.297
|
||||||
|
130,4.3333,27.296
|
||||||
|
131,4.3667,27.297
|
||||||
|
132,4.4000,27.296
|
||||||
|
133,4.4333,27.299
|
||||||
|
134,4.4667,27.300
|
||||||
|
135,4.5000,27.302
|
||||||
|
136,4.5333,27.301
|
||||||
|
137,4.5667,27.304
|
||||||
|
138,4.6000,27.304
|
||||||
|
139,4.6333,27.304
|
||||||
|
140,4.6667,27.302
|
||||||
|
141,4.7000,27.306
|
||||||
|
142,4.7333,27.308
|
||||||
|
143,4.7667,27.309
|
||||||
|
144,4.8000,27.309
|
||||||
|
145,4.8333,27.312
|
||||||
|
146,4.8667,27.311
|
||||||
|
147,4.9000,27.311
|
||||||
|
148,4.9333,27.310
|
||||||
|
149,4.9667,27.317
|
||||||
|
150,5.0000,27.319
|
||||||
|
151,5.0333,27.321
|
||||||
|
152,5.0667,27.322
|
||||||
|
153,5.1000,27.327
|
||||||
|
154,5.1333,27.327
|
||||||
|
155,5.1667,27.328
|
||||||
|
156,5.2000,27.327
|
||||||
|
157,5.2333,27.333
|
||||||
|
158,5.2667,27.334
|
||||||
|
159,5.3000,27.335
|
||||||
|
160,5.3333,27.334
|
||||||
|
161,5.3667,27.344
|
||||||
|
162,5.4000,27.347
|
||||||
|
163,5.4333,27.350
|
||||||
|
164,5.4667,27.351
|
||||||
|
165,5.5000,27.359
|
||||||
|
166,5.5333,27.359
|
||||||
|
167,5.5667,27.360
|
||||||
|
168,5.6000,27.358
|
||||||
|
169,5.6333,27.365
|
||||||
|
170,5.6667,27.366
|
||||||
|
171,5.7000,27.369
|
||||||
|
172,5.7333,27.367
|
||||||
|
173,5.7667,27.383
|
||||||
|
174,5.8000,27.386
|
||||||
|
175,5.8333,27.387
|
||||||
|
176,5.8667,27.386
|
||||||
|
177,5.9000,27.399
|
||||||
|
178,5.9333,27.400
|
||||||
|
179,5.9667,27.402
|
||||||
|
180,6.0000,27.400
|
||||||
|
181,6.0333,27.413
|
||||||
|
182,6.0667,27.414
|
||||||
|
183,6.1000,27.415
|
||||||
|
184,6.1333,27.413
|
||||||
|
185,6.1667,27.432
|
||||||
|
186,6.2000,27.434
|
||||||
|
187,6.2333,27.438
|
||||||
|
188,6.2667,27.436
|
||||||
|
189,6.3000,27.449
|
||||||
|
190,6.3333,27.448
|
||||||
|
191,6.3667,27.451
|
||||||
|
192,6.4000,27.449
|
||||||
|
193,6.4333,27.466
|
||||||
|
194,6.4667,27.471
|
||||||
|
195,6.5000,27.472
|
||||||
|
196,6.5333,27.470
|
||||||
|
197,6.5667,27.480
|
||||||
|
198,6.6000,27.478
|
||||||
|
199,6.6333,27.480
|
||||||
|
200,6.6667,27.476
|
||||||
|
201,6.7000,27.509
|
||||||
|
202,6.7333,27.510
|
||||||
|
203,6.7667,27.516
|
||||||
|
204,6.8000,27.514
|
||||||
|
205,6.8333,27.519
|
||||||
|
206,6.8667,27.519
|
||||||
|
207,6.9000,27.518
|
||||||
|
208,6.9333,27.516
|
||||||
|
209,6.9667,27.538
|
||||||
|
210,7.0000,27.537
|
||||||
|
211,7.0333,27.539
|
||||||
|
212,7.0667,27.538
|
||||||
|
213,7.1000,27.558
|
||||||
|
214,7.1333,27.556
|
||||||
|
215,7.1667,27.558
|
||||||
|
216,7.2000,27.554
|
||||||
|
217,7.2333,27.577
|
||||||
|
218,7.2667,27.576
|
||||||
|
219,7.3000,27.577
|
||||||
|
220,7.3333,27.572
|
||||||
|
221,7.3667,27.596
|
||||||
|
222,7.4000,27.598
|
||||||
|
223,7.4333,27.603
|
||||||
|
224,7.4667,27.597
|
||||||
|
225,7.5000,27.610
|
||||||
|
226,7.5333,27.611
|
||||||
|
227,7.5667,27.613
|
||||||
|
228,7.6000,27.607
|
||||||
|
229,7.6333,27.621
|
||||||
|
230,7.6667,27.621
|
||||||
|
231,7.7000,27.622
|
||||||
|
232,7.7333,27.617
|
||||||
|
233,7.7667,27.624
|
||||||
|
234,7.8000,27.626
|
||||||
|
235,7.8333,27.630
|
||||||
|
236,7.8667,27.622
|
||||||
|
237,7.9000,27.640
|
||||||
|
238,7.9333,27.637
|
||||||
|
239,7.9667,27.639
|
||||||
|
240,8.0000,27.633
|
||||||
|
241,8.0333,27.642
|
||||||
|
242,8.0667,27.639
|
||||||
|
243,8.1000,27.642
|
||||||
|
244,8.1333,27.637
|
||||||
|
245,8.1667,27.658
|
||||||
|
246,8.2000,27.653
|
||||||
|
247,8.2333,27.655
|
||||||
|
248,8.2667,27.649
|
||||||
|
249,8.3000,27.645
|
||||||
|
250,8.3333,27.648
|
||||||
|
251,8.3667,26.704
|
||||||
|
252,8.4000,23.887
|
||||||
|
253,8.4333,23.723
|
||||||
|
254,8.4667,16.471
|
||||||
|
255,8.5000,13.119
|
||||||
|
256,8.5333,13.102
|
||||||
|
257,8.5667,12.118
|
||||||
|
258,8.6000,10.955
|
||||||
|
259,8.6333,10.956
|
||||||
|
260,8.6667,5.365
|
||||||
|
261,8.7000,3.422
|
||||||
|
262,8.7333,3.416
|
||||||
|
263,8.7667,2.820
|
||||||
|
264,8.8000,0.020
|
||||||
|
265,8.8333,0.020
|
||||||
|
266,8.8667,0.020
|
||||||
|
267,8.9000,0.020
|
||||||
|
268,8.9333,0.020
|
||||||
|
269,8.9667,3.267
|
||||||
|
270,9.0000,5.012
|
||||||
|
271,9.0333,5.449
|
||||||
|
272,9.0667,7.339
|
||||||
|
273,9.1000,9.208
|
||||||
|
274,9.1333,10.415
|
||||||
|
275,9.1667,10.418
|
||||||
|
276,9.2000,10.462
|
||||||
|
277,9.2333,10.459
|
||||||
|
278,9.2667,10.569
|
||||||
|
279,9.3000,10.701
|
||||||
|
280,9.3333,10.868
|
||||||
|
281,9.3667,12.924
|
||||||
|
282,9.4000,14.688
|
||||||
|
283,9.4333,14.756
|
||||||
|
284,9.4667,17.184
|
||||||
|
285,9.5000,19.441
|
||||||
|
286,9.5333,19.438
|
||||||
|
287,9.5667,19.492
|
||||||
|
288,9.6000,19.492
|
||||||
|
289,9.6333,19.492
|
||||||
|
290,9.6667,19.508
|
||||||
|
291,9.7000,23.405
|
||||||
|
292,9.7333,23.417
|
||||||
|
293,9.7667,23.414
|
||||||
|
294,9.8000,23.416
|
||||||
|
295,9.8333,23.409
|
||||||
|
296,9.8667,23.467
|
||||||
|
297,9.9000,24.927
|
||||||
|
298,9.9333,24.929
|
||||||
|
299,9.9667,24.926
|
||||||
|
300,10.0000,25.788
|
||||||
|
301,10.0333,25.785
|
||||||
|
302,10.0667,25.789
|
||||||
|
303,10.1000,25.893
|
||||||
|
304,10.1333,25.908
|
||||||
|
305,10.1667,25.905
|
||||||
|
306,10.2000,25.905
|
||||||
|
307,10.2333,25.976
|
||||||
|
308,10.2667,25.986
|
||||||
|
309,10.3000,25.980
|
||||||
|
310,10.3333,25.981
|
||||||
|
311,10.3667,25.976
|
||||||
|
312,10.4000,25.984
|
||||||
|
313,10.4333,26.020
|
||||||
|
314,10.4667,26.022
|
||||||
|
315,10.5000,26.016
|
||||||
|
316,10.5333,26.021
|
||||||
|
317,10.5667,26.018
|
||||||
|
318,10.6000,26.020
|
||||||
|
319,10.6333,26.016
|
||||||
|
320,10.6667,26.021
|
||||||
|
321,10.7000,26.021
|
||||||
|
322,10.7333,26.021
|
||||||
|
323,10.7667,26.019
|
||||||
|
324,10.8000,26.022
|
||||||
|
325,10.8333,26.022
|
||||||
|
326,10.8667,26.022
|
||||||
|
327,10.9000,26.020
|
||||||
|
328,10.9333,26.025
|
||||||
|
329,10.9667,26.025
|
||||||
|
330,11.0000,26.025
|
||||||
|
331,11.0333,26.023
|
||||||
|
332,11.0667,26.029
|
||||||
|
333,11.1000,26.027
|
||||||
|
334,11.1333,26.028
|
||||||
|
335,11.1667,26.024
|
||||||
|
336,11.2000,26.024
|
||||||
|
337,11.2333,26.024
|
||||||
|
338,11.2667,26.024
|
||||||
|
339,11.3000,26.029
|
||||||
|
340,11.3333,26.029
|
||||||
|
341,11.3667,26.027
|
||||||
|
342,11.4000,26.029
|
||||||
|
343,11.4333,26.024
|
||||||
|
344,11.4667,26.027
|
||||||
|
345,11.5000,26.027
|
||||||
|
346,11.5333,26.027
|
||||||
|
347,11.5667,26.025
|
||||||
|
348,11.6000,26.031
|
||||||
|
349,11.6333,26.030
|
||||||
|
350,11.6667,26.033
|
||||||
|
351,11.7000,26.028
|
||||||
|
352,11.7333,26.032
|
||||||
|
353,11.7667,26.032
|
||||||
|
354,11.8000,26.032
|
||||||
|
355,11.8333,26.029
|
||||||
|
356,11.8667,26.034
|
||||||
|
357,11.9000,26.039
|
||||||
|
358,11.9333,26.041
|
||||||
|
359,11.9667,26.041
|
||||||
|
360,12.0000,26.040
|
||||||
|
361,12.0333,26.046
|
||||||
|
362,12.0667,26.047
|
||||||
|
363,12.1000,26.046
|
||||||
|
364,12.1333,26.050
|
||||||
|
365,12.1667,26.051
|
||||||
|
366,12.2000,26.051
|
||||||
|
367,12.2333,26.051
|
||||||
|
368,12.2667,26.051
|
||||||
|
369,12.3000,26.051
|
||||||
|
370,12.3333,26.051
|
||||||
|
371,12.3667,26.051
|
||||||
|
372,12.4000,26.050
|
||||||
|
373,12.4333,26.055
|
||||||
|
374,12.4667,26.056
|
||||||
|
375,12.5000,26.056
|
||||||
|
376,12.5333,26.055
|
||||||
|
377,12.5667,26.056
|
||||||
|
378,12.6000,26.056
|
||||||
|
379,12.6333,26.056
|
||||||
|
380,12.6667,26.055
|
||||||
|
381,12.7000,26.056
|
||||||
|
382,12.7333,26.056
|
||||||
|
383,12.7667,26.056
|
||||||
|
384,12.8000,26.055
|
||||||
|
385,12.8333,26.055
|
||||||
|
386,12.8667,26.056
|
||||||
|
387,12.9000,26.056
|
||||||
|
388,12.9333,26.056
|
||||||
|
389,12.9667,26.056
|
||||||
|
390,13.0000,26.055
|
||||||
|
391,13.0333,26.071
|
||||||
|
392,13.0667,26.072
|
||||||
|
393,13.1000,26.074
|
||||||
|
394,13.1333,26.082
|
||||||
|
395,13.1667,26.083
|
||||||
|
396,13.2000,26.083
|
||||||
|
397,13.2333,26.083
|
||||||
|
398,13.2667,26.083
|
||||||
|
399,13.3000,26.110
|
||||||
|
400,13.3333,26.111
|
||||||
|
401,13.3667,26.114
|
||||||
|
402,13.4000,26.113
|
||||||
|
403,13.4333,26.118
|
||||||
|
404,13.4667,26.119
|
||||||
|
405,13.5000,26.121
|
||||||
|
406,13.5333,26.119
|
||||||
|
407,13.5667,26.140
|
||||||
|
408,13.6000,26.140
|
||||||
|
409,13.6333,26.144
|
||||||
|
410,13.6667,26.142
|
||||||
|
411,13.7000,26.155
|
||||||
|
412,13.7333,26.157
|
||||||
|
413,13.7667,26.158
|
||||||
|
414,13.8000,26.157
|
||||||
|
415,13.8333,26.165
|
||||||
|
416,13.8667,26.165
|
||||||
|
417,13.9000,26.168
|
||||||
|
418,13.9333,26.165
|
||||||
|
419,13.9667,26.165
|
||||||
|
117
docs/re/screen-transitions.md
Normal file
117
docs/re/screen-transitions.md
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
# What happens between two screens — a fade through black, and where its timing lives
|
||||||
|
|
||||||
|
**Status:** ✅ `CONFIRMED`. The quad and its ramp are **decoded** (a keyframe
|
||||||
|
group on the disc, with a disc-wide check); the wall-clock timings are
|
||||||
|
**measured** off the running game at 30 fps. One piece is **undecodable from this
|
||||||
|
field** and is called out below.
|
||||||
|
|
||||||
|
Answers [MISSION Q7](../port/MISSION.md).
|
||||||
|
|
||||||
|
## The mechanism — decoded
|
||||||
|
|
||||||
|
Every title-side screen carries a full-screen untextured primitive that is
|
||||||
|
**black, and paints last**: `pteff00.prm` in `GP_TITLE`, `pfeff00.prm` in
|
||||||
|
`GP_SAVE_LOAD`. That it sorts last was already established
|
||||||
|
([`structures/ui-paint-order-key.md`](structures/ui-paint-order-key.md)); what is
|
||||||
|
new here is that its **keyframe group is the transition**.
|
||||||
|
|
||||||
|
The group is always four blocks, and always this shape:
|
||||||
|
|
||||||
|
| block | alpha | meaning |
|
||||||
|
|---|---|---|
|
||||||
|
| 1 | `0xff` at `t = T0` | the screen starts **black** |
|
||||||
|
| 2 | `0x00` at `t = T1` | ramp to fully clear — the screen **fades in** |
|
||||||
|
| 3 | `0x00` at `t = T2` | clear; this is the resting pose, the quad is invisible |
|
||||||
|
| 4 | `0xff`, **no time** | ramp back to black — the screen **fades out** on exit |
|
||||||
|
|
||||||
|
Read with the corpus's rule that a keyframe is the *start* of a ramp
|
||||||
|
([`structures/ui-resting-pose.md`](structures/ui-resting-pose.md)).
|
||||||
|
|
||||||
|
```
|
||||||
|
$ tools/re-capture/fade_quads.py 4 5 6 # GP_TITLE
|
||||||
|
build 4 (title) pteff00.prm t=16 α=255 t=261 α=0 t=269 α=0 t=— α=255
|
||||||
|
build 5 (main menu) pteff00.prm t=12 α=255 t= 70 α=0 t= 80 α=0 t=— α=255
|
||||||
|
build 6 (EXTRAS) pteff00.prm t=12 α=255 t= 64 α=0 t= 74 α=0 t=— α=255
|
||||||
|
```
|
||||||
|
|
||||||
|
Under [Q1](ui-keyframe-time-unit.md)'s `1 unit = 1/60 s`: the screen holds black
|
||||||
|
for **0.20 s**, then fades in over **0.87 s** (`EXTRAS`), **0.97 s** (main menu)
|
||||||
|
or **4.08 s** (the title).
|
||||||
|
|
||||||
|
### ❔ The fade-OUT duration is not in this field
|
||||||
|
|
||||||
|
The fourth block has **no time** — a group's last block stops 4 bytes short and
|
||||||
|
that word is already the next group's element index
|
||||||
|
([`ui_layout.rs`](../../crates/sylpheed-formats/src/ui_layout.rs) documents the
|
||||||
|
packing). So the disc gives the ramp's *target* (black) and not its length. That
|
||||||
|
duration is **measured** below, and the port is authoring it.
|
||||||
|
|
||||||
|
### The disc-wide check, and what it shows about overlays
|
||||||
|
|
||||||
|
Over every `GP_*.pak`, counting bundles that have a `.prm` element **and** ≥8
|
||||||
|
elements (screen-sized rather than a two-element fragment):
|
||||||
|
|
||||||
|
> **40 of 97** carry a 255 → 0 → 255 quad; 56 of the 60 found disc-wide have
|
||||||
|
> exactly 4 keyframes.
|
||||||
|
|
||||||
|
41 % sounds weak until it is read per pak, where it is nearly all-or-nothing:
|
||||||
|
|
||||||
|
| pak | with quad / screen-sized |
|
||||||
|
|---|---|
|
||||||
|
| `GP_MISSION_SELECT`, `GP_MOVIE_THEATER`, `GP_OPTIONS`, `GP_TUTORIAL`, `GP_SYSTEM` | 2/2 each |
|
||||||
|
| `GP_BUNK`, `GP_CHALLENGE` | 6/6 |
|
||||||
|
| `GP_STAGE_CLEAR` | 4/4 |
|
||||||
|
| `GP_SAVE_LOAD` | 10/12 |
|
||||||
|
| **`GP_TITLE`** | **6/12** |
|
||||||
|
| `GP_DIALOG` | 0/133 |
|
||||||
|
| `GP_DEBRIEFING_PILOTLOG` | 4/102 |
|
||||||
|
|
||||||
|
**`GP_TITLE`'s 6 of 12 is the interesting row, and it is not a gap.** The six
|
||||||
|
that carry the quad are exactly the six *screen* builds — title, main menu and
|
||||||
|
`EXTRAS`, English and Japanese. The six that do not are exactly the six
|
||||||
|
**overlays**: the `PRESS Ⓐ BUTTON` plate and the two `DELTASABER` plates
|
||||||
|
([`ui-title-build-map.md`](ui-title-build-map.md)). An overlay composited onto a
|
||||||
|
screen has no transition of its own, so it has no fade quad — which is
|
||||||
|
independent corroboration that those builds are overlays rather than screens.
|
||||||
|
`GP_DIALOG`'s 0/133 says the same thing about dialog boxes.
|
||||||
|
|
||||||
|
## The timing — measured
|
||||||
|
|
||||||
|
Recorded with `ffmpeg -f x11grab -framerate 30` over the game surface, mean
|
||||||
|
frame luminance per frame; raw data in
|
||||||
|
[`captures/transitions/transition-luminance.csv`](captures/transitions/transition-luminance.csv),
|
||||||
|
filmstrip in
|
||||||
|
[`transition-filmstrip.png`](captures/transitions/transition-filmstrip.png).
|
||||||
|
|
||||||
|
| | main menu → `EXTRAS` (Ⓐ) | `EXTRAS` → main menu (Ⓑ) |
|
||||||
|
|---|---|---|
|
||||||
|
| press → first visible change | 0.07 s | 0.37 s |
|
||||||
|
| **fade-out to black** | **0.367 s** | **0.400 s** |
|
||||||
|
| **pure black** (luminance 0.02) | 0.233 s | 0.167 s |
|
||||||
|
| luminance rise until settled | 0.567 s | 1.467 s |
|
||||||
|
|
||||||
|
The fade-out is the number the file cannot give, and it comes out the same both
|
||||||
|
ways: **~0.4 s**, i.e. ~24 units under Q1's rule.
|
||||||
|
|
||||||
|
The black hold is *consistent with* the file's 12 units (0.20 s) but does not
|
||||||
|
confirm it — the plateau spans the tail of the outgoing screen's fade-out and the
|
||||||
|
head of the incoming screen's black, and this measurement cannot separate them.
|
||||||
|
|
||||||
|
### ⚠️ The luminance rise is **not** the quad's ramp
|
||||||
|
|
||||||
|
The two columns differ by 2.6× where the quad's declared ramps differ by only
|
||||||
|
1.12× (58 units vs 52). The filmstrip says why: the background reappears *first*
|
||||||
|
and the labels arrive after it, so what the luminance curve is timing is the
|
||||||
|
incoming screen's **own element animations**, not the fade quad. Quoting 1.47 s
|
||||||
|
as "the main menu's fade" would be wrong. The quad's ramp is decoded; the
|
||||||
|
screen's build-in is a separate, longer thing.
|
||||||
|
|
||||||
|
## For the port
|
||||||
|
|
||||||
|
* a screen change is: **fade the outgoing screen to black over ~0.4 s**, hold
|
||||||
|
black briefly, then **fade the incoming screen in over its own declared ramp**
|
||||||
|
while its elements play their own keyframes;
|
||||||
|
* the fade-in ramp is **read from the file** (`T1 − T0` on the screen's fade
|
||||||
|
quad);
|
||||||
|
* the ~0.4 s fade-out and the black hold are **authored from this page** — the
|
||||||
|
disc does not carry them.
|
||||||
52
tools/re-capture/fade_quads.py
Executable file
52
tools/re-capture/fade_quads.py
Executable file
@@ -0,0 +1,52 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Dump every `.prm` primitive's keyframe group (alpha + time) for a UI build.
|
||||||
|
|
||||||
|
The screen-transition fade lives here -- see docs/re/screen-transitions.md.
|
||||||
|
Usage: PAK=<pak> fade_quads.py [build...] (default: GP_TITLE, builds 2 4 5 6)"""
|
||||||
|
import struct, sys, glob, os, zlib
|
||||||
|
sys.path.insert(0, "/work/Syplheed-Reborn/tools/re-capture")
|
||||||
|
src = open("/work/Syplheed-Reborn/tools/re-capture/regn_decode.py").read()
|
||||||
|
exec(src.split("# ── POF0")[0])
|
||||||
|
|
||||||
|
DECL_AT, DECL_ENTRY, KF = 0x20, 60, 40
|
||||||
|
def be32(b,o): return struct.unpack_from(">I", b, o)[0]
|
||||||
|
|
||||||
|
def parse(bundle):
|
||||||
|
n = be32(bundle, 0x14)
|
||||||
|
names=[]
|
||||||
|
for i in range(n):
|
||||||
|
o = DECL_AT + i*DECL_ENTRY
|
||||||
|
names.append(bundle[o:o+28].split(b"\0")[0].decode("ascii","replace"))
|
||||||
|
groups={}
|
||||||
|
pos = DECL_AT + n*DECL_ENTRY
|
||||||
|
for _ in range(n):
|
||||||
|
if pos+8 > len(bundle): break
|
||||||
|
idx = be32(bundle,pos); frames = be32(bundle,pos+4)
|
||||||
|
if idx>=n or frames==0 or frames>4096: break
|
||||||
|
first = pos+12; end = first + frames*KF - 4
|
||||||
|
g=[]
|
||||||
|
for k in range(frames):
|
||||||
|
blk = first + k*KF
|
||||||
|
if blk+36 > len(bundle) or blk+36 > end: break
|
||||||
|
g.append(dict(fade=be32(bundle,blk), sx=be32(bundle,blk+16), sy=be32(bundle,blk+20),
|
||||||
|
x=struct.unpack_from(">i",bundle,blk+28)[0], y=struct.unpack_from(">i",bundle,blk+32)[0],
|
||||||
|
t=(be32(bundle,blk+36) if blk+40<=end else None)))
|
||||||
|
groups[idx]=g; pos=end
|
||||||
|
return names, groups
|
||||||
|
|
||||||
|
pak = os.environ.get("PAK", "/work/sylph_extract/dat/GP_TITLE.pak")
|
||||||
|
E = pak_entries(pak)
|
||||||
|
E = [b for h,b in E]
|
||||||
|
# build index -> pak entry index, from `screen list`: 0..9 then 12, 15
|
||||||
|
BUILDS = {0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,10:12,11:15}
|
||||||
|
want = [int(a) for a in sys.argv[1:]] or [2,4,5,6]
|
||||||
|
for b in want:
|
||||||
|
names, groups = parse(E[BUILDS[b]])
|
||||||
|
print(f"=== build {b} ===")
|
||||||
|
for i,nm in enumerate(names):
|
||||||
|
if not nm.endswith(".prm"): continue
|
||||||
|
g = groups.get(i, [])
|
||||||
|
print(f" [{i}] {nm} {len(g)} kf")
|
||||||
|
for k in g:
|
||||||
|
a=(k['fade']>>24)&0xff
|
||||||
|
print(f" t={str(k['t']):>5} fade=0x{k['fade']:08x} (alpha {a:3d}) scale={k['sx']}x{k['sy']} pos=({k['x']},{k['y']})")
|
||||||
Reference in New Issue
Block a user