re(ui): decode keyframe +12 as screen-plane rotation in degrees
The rotated quads on the title screen come from the keyframe block after all. The earlier negative -- "every GP_TITLE build 4 element has all three angle words at zero" -- read the right bytes over too small a region: it walked the top-level declaration table, and the rotated elements are the nested leaf records ptloop01.rat / ptloop02.rat. Confirmed against the framebuffer rather than against our own renderer. The two records declare +12 = 30 and -45; the GPU capture submits their quads at +30.26 and -45.28 degrees -- magnitude and sign, two different values. Corroborated by shape in GP_BUNK 117ca14f, where +12 ramps 0 -> 360 with position, scale and alpha constant: a spin in place. Identifying which draw it was needed edge lengths, not bounding boxes: 400x1076 and 400x1444 against pteff03/pteff03a 399x180 at the elements' two different declared scales, 600% (1080) and 800% (1440). The same test names three known-positives in the capture (ptlogo1, ptcopyright, ptbtn00), so it passes its own control. Keyframe gains rotation_deg plus unknown_4/unknown_8, carried rather than dropped. NOT rendered -- ui_layout::blit is axis-aligned only, so the reference renderer and the port will both draw these upright until a rotating blit exists. The census tool ships with the trap that broke its first version: nested RATC blobs are not 4-byte aligned, so an aligned scan found 0/3 of its own control blocks and missed 16 341 blocks. Disc-wide +12 is non-zero in 14.50 % of 83 862 blocks. sylpheed-formats tests, SYLPHEED_DISC set: 131 passed, 0 failed across the 6 suites finished at commit time; the run had not yet completed.
This commit is contained in:
@@ -662,12 +662,15 @@ rotation about three axes. 🟡 That reading is **not tied to an observed rotati
|
||||
it is the shape of the numbers, nothing more. The doc comment is corrected either
|
||||
way: "0 on every frame seen" was a sample artefact.
|
||||
|
||||
### 🔴 But they do not explain this screen
|
||||
### ✅ They *do* explain this screen — the earlier negative was wrong about reach
|
||||
|
||||
**Every element of `GP_TITLE` build 4 has all three at zero** — checked
|
||||
element by element. The game still submits rotated parallelograms there. So the
|
||||
title's rotation comes from **outside the keyframe data**, and remains
|
||||
unidentified.
|
||||
~~**Every element of `GP_TITLE` build 4 has all three at zero** — checked element
|
||||
by element. So the title's rotation comes from outside the keyframe data.~~
|
||||
**Withdrawn (2026-08-28).** That check walked build 4's **top-level declaration
|
||||
table**. The rotated quads belong to its two **nested leaf records**, and there
|
||||
`+12` reads **30** and **−45** — against a measured **+30.26°** and **−45.28°**.
|
||||
The bytes were read correctly; the *region* was too small. See
|
||||
[`structures/ui-keyframe-rotation.md`](structures/ui-keyframe-rotation.md).
|
||||
|
||||
⚠️ **One thing I should not have stated flatly:** that the skewed draw *is* the
|
||||
swoosh. It is the only skewed geometry in the capture and the swoosh is the only
|
||||
@@ -688,18 +691,43 @@ These span the **full screen height and well beyond it**. The swoosh
|
||||
(`ptlogo_back2`, rest `(71,126)`, 1118 × 262) is a **band** at y 126…360. Draw 2
|
||||
is not it.
|
||||
|
||||
🟡 **A candidate, offered as one:** the two `ptloop` sweeps. `pteff03a.t32` is
|
||||
399 × 180 and its element carries scale **`(100,800)`** — 399 × 1440 — while
|
||||
`pteff03` carries `(100,600)`. Two long thin sprites, two quads, and the drawn
|
||||
vertex alphas `0xC3`/`0xB6` sit inside the `0x80`→`0xff` ramp those records
|
||||
declare. **Not confirmed** — no texture or position match was made.
|
||||
## ✅ It is the two `ptloop` sweeps — confirmed
|
||||
|
||||
⚠️ **If** that is right it has a consequence worth flagging: our renderer parks
|
||||
those sweeps at their final keyframe (`x = 1521` and `−839`, both off-screen) and
|
||||
draws nothing, while the game draws them across the screen — which would mean the
|
||||
draw capture caught them **mid-sweep**, inside the `t = 150…600` window, and that
|
||||
the "groups hold" reading needs re-examining for these two elements specifically.
|
||||
Conditional on an unconfirmed identification, so recorded and not acted on.
|
||||
The bounding box was the wrong measurement; the quads are rotated, so what
|
||||
identifies them is their **edge lengths**:
|
||||
|
||||
| quad | size | rotation | centre |
|
||||
|---|---|---|---|
|
||||
| A | 400.1 × 1076.3 | **+30.26°** | (992.0, 359.1) |
|
||||
| B | 400.2 × 1444.5 | **−45.28°** | (467.2, 360.0) |
|
||||
|
||||
| quad | element | sprite × declared scale |
|
||||
|---|---|---|
|
||||
| A | `ptloop01.rat` | `pteff03.t32` 399×180 @ 100 %,**600 %** = 399 × **1080** |
|
||||
| B | `ptloop02.rat` | `pteff03a.t32` 399×180 @ 100 %,**800 %** = 399 × **1440** |
|
||||
|
||||
Five independent agreements, listed in
|
||||
[`structures/ui-keyframe-rotation.md`](structures/ui-keyframe-rotation.md): the
|
||||
count (two quads, two `ptloop` elements), both widths (400 vs 399), **both
|
||||
heights, which are different numbers that both land**, the direction each quad
|
||||
moves between the capture's two frames (matching each record's own sweep
|
||||
direction), and the vertex alphas falling inside the declared ramps.
|
||||
|
||||
The known-positives in the same capture pass the same test: draw 5 measures
|
||||
915 × 115 (`ptlogo1.t32` 919×113), draw 7 measures 691 × 18 (`ptcopyright.t32`
|
||||
694×20) and 512 × 50 (`ptbtn00.t32` 513×50).
|
||||
|
||||
### ✅ And "a keyframe group holds" survives
|
||||
|
||||
The consequence I flagged conditionally last iteration resolves the *other* way.
|
||||
Our renderer parks these two sweeps at their final keyframe (`x = 1521` and
|
||||
`−839`, both off-screen); the game draws them across the screen. That is not a
|
||||
contradiction — the capture caught them **mid-sweep**: the quad centres, x = 992
|
||||
and x = 467, both fall inside the decoded `t = 150…600` / `150…720` travel, the
|
||||
alphas are mid-ramp, and the sprites move in the decoded direction between
|
||||
frames. The capture is of the **build-in**, not of the settled screen, and the
|
||||
18 s stillness measurement (sd ≤ 0.01) still says the groups stop. No change to
|
||||
[the holds-not-loops finding](#-a-keyframe-group-holds-at-its-last-keyframe--it-does-not-loop).
|
||||
|
||||
### What this costs
|
||||
|
||||
|
||||
Reference in New Issue
Block a user