diff --git a/docs/port/HANDOFF.md b/docs/port/HANDOFF.md index 7546d83f..2ae05741 100644 --- a/docs/port/HANDOFF.md +++ b/docs/port/HANDOFF.md @@ -109,6 +109,20 @@ authored version can be deleted. test is to blend bit-`0x02` sprites additively and re-correlate the title against the capture. Note `ptlogo_back2eff` is `0x8830` despite its name, so this is a field and not a naming pattern. ❔ Not diagnosed. + ✅ **SOLVED 2026-08-28 by draw capture — it is the GEOMETRY.** The game submits + the swoosh as **two rotated parallelograms** (edges `(0.54,−0.56)` and + `(0.44,0.79)`, ~45° and ~61°, extending to `y=±1.81` NDC). + `ui_layout::blit` draws **axis-aligned rectangles only**, so it blits the sprite + upright — right on average, right in position, wrong in shape, which is the + measured signature exactly. **A port that blits upright rects will have the same + defect.** + 🔴 Vertex colour is refuted with it: every colour in the capture is + `FFFFFF`, white RGB. + ❔ **Format gap:** the decoded keyframe has `fade`/`scale`/`tint`/`x`/`y`/`time` + and **no rotation**, so where the rotation comes from is not decoded. + ⚠️ The earlier "pink versus white" reading compared two differently-shaped + renderings and should be re-checked after geometry, not carried as a separate + defect. ❔ **Classified: undecodable from the disc, with reach.** Seven candidates eliminated — pivot (inert at scale 100 *and* no measured displacement), `fade`, `tint`, texture colour, additive blend via `+0x04` bit `0x02`, and diff --git a/docs/re/REFUTED.md b/docs/re/REFUTED.md index 750e1a6d..4cf9fefe 100644 --- a/docs/re/REFUTED.md +++ b/docs/re/REFUTED.md @@ -35,6 +35,11 @@ neighbourhood, not just the line. ## Screens, classes and RTTI +* "the game passes a pink per-vertex colour for the title swoosh" → **refuted by + draw capture.** Every vertex colour in the capture is `FFFFFF`, white RGB. +* "the swoosh discrepancy is undecodable" → **solved**: the game submits it as two + **rotated parallelograms**; `ui_layout::blit` only does axis-aligned rectangles. + [`ui-title-build-map.md`](ui-title-build-map.md) * "the `--log_ui_draws` per-draw capture reads the guest's blend state" → **mine, and wrong.** It records primitive type, index count, index-buffer address, VS/PS ucode hashes, texture bindings and vertex attribute 0 — no diff --git a/docs/re/captures/title-builds/title-draw-capture-vertex-colours.log b/docs/re/captures/title-builds/title-draw-capture-vertex-colours.log new file mode 100644 index 00000000..0346bc69 --- /dev/null +++ b/docs/re/captures/title-builds/title-draw-capture-vertex-colours.log @@ -0,0 +1,43 @@ +# every draw in SUBMISSION ORDER, undeduplicated, frames 1..3 +# tex dimensions identify the sprite; base is the guest address + 0 prim=8 indices=3 vs=0x0A6D1DD7767FDF27 ps=0x2E372EA28CC404B7 + vb=0x15036638 stride=28 attrs=[57@0 38@12 ] fmt0=57 v: [-0.50,-0.50,z=0.00000] [1279.50,-0.50,z=0.00000] [1279.50,719.50,z=0.00000] + 1 prim=13 indices=4 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x0BA60000 1280x768 fmt=6] + vb=0x15036690 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-1.00,1.00,z=0.00000,col=FFFFFFFF] [1.00,1.00,z=0.00000,col=FFFFFFFF] [1.00,-1.00,z=0.00000,col=FFFFFFFF] [-1.00,-1.00,z=0.00000,col=FFFFFFFF] + 2 prim=13 indices=8 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x11C80000 1280x768 fmt=6] + vb=0x150366F0 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [0.70,1.58,z=0.00000,col=C3FFFFFF] [1.24,1.02,z=0.00000,col=C3FFFFFF] [0.40,-1.57,z=0.00000,col=C3FFFFFF] [-0.14,-1.02,z=0.00000,col=C3FFFFFF] [-1.29,1.02,z=0.00000,col=B6FFFFFF] [-0.85,1.81,z=0.00000,col=B6FFFFFF] [0.75,-1.02,z=0.00000,col=B6FFFFFF] [0.31,-1.81,z=0.00000,col=B6FFFFFF] + 3 prim=13 indices=4 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x0B690000 1280x768 fmt=6] + vb=0x150367B0 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-1.00,1.00,z=0.00000,col=FFFFFFFF] [1.00,1.00,z=0.00000,col=FFFFFFFF] [1.00,-1.00,z=0.00000,col=FFFFFFFF] [-1.00,-1.00,z=0.00000,col=FFFFFFFF] + 4 prim=13 indices=8 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x0B2C0000 1280x768 fmt=6] + vb=0x15036810 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-0.90,0.68,z=0.00000,col=FFFFFFFF] [0.87,0.68,z=0.00000,col=FFFFFFFF] [0.87,-0.10,z=0.00000,col=FFFFFFFF] [-0.90,-0.10,z=0.00000,col=FFFFFFFF] [-0.89,0.65,z=0.00000,col=FFFFFFFF] [0.86,0.65,z=0.00000,col=FFFFFFFF] [0.86,-0.08,z=0.00000,col=FFFFFFFF] [-0.89,-0.08,z=0.00000,col=FFFFFFFF] + 5 prim=13 indices=8 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x11C80000 1280x768 fmt=6] + vb=0x150368D0 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-0.71,0.47,z=0.00000,col=FFFFFFFF] [0.72,0.47,z=0.00000,col=FFFFFFFF] [0.72,0.15,z=0.00000,col=FFFFFFFF] [-0.71,0.15,z=0.00000,col=FFFFFFFF] [0.76,-0.05,z=0.00000,col=FFFFFFFF] [0.82,-0.05,z=0.00000,col=FFFFFFFF] [0.82,-0.10,z=0.00000,col=FFFFFFFF] [0.76,-0.10,z=0.00000,col=FFFFFFFF] + 6 prim=13 indices=4 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x0BE30000 1280x768 fmt=6] + vb=0x15036990 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-0.79,0.15,z=0.00000,col=FFFFFFFF] [0.76,0.15,z=0.00000,col=FFFFFFFF] [0.76,-0.14,z=0.00000,col=FFFFFFFF] [-0.79,-0.14,z=0.00000,col=FFFFFFFF] + 7 prim=13 indices=8 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x11C80000 1280x768 fmt=6] + vb=0x150369F0 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-0.54,-0.82,z=0.00000,col=FFFFFFFF] [0.54,-0.82,z=0.00000,col=FFFFFFFF] [0.54,-0.87,z=0.00000,col=FFFFFFFF] [-0.54,-0.87,z=0.00000,col=FFFFFFFF] [-0.40,-0.53,z=0.00000,col=FFFFFFFF] [0.40,-0.53,z=0.00000,col=FFFFFFFF] [0.40,-0.67,z=0.00000,col=FFFFFFFF] [-0.40,-0.67,z=0.00000,col=FFFFFFFF] + 8 prim=13 indices=4 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x0B2C0000 1280x768 fmt=6] + vb=0x15036AB0 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-0.42,-0.49,z=0.00000,col=31FFFFFF] [0.42,-0.49,z=0.00000,col=31FFFFFF] [0.42,-0.70,z=0.00000,col=31FFFFFF] [-0.42,-0.70,z=0.00000,col=31FFFFFF] + 9 prim=8 indices=3 vs=0x72CBCAA6A7984111 ps=0xE59B2B3DA4AA9008 tex[base=0x10000000 1x1 fmt=26] + 10 prim=8 indices=3 vs=0x72CBCAA6A7984111 ps=0xE59B2B3DA4AA9008 tex[base=0x10000000 1x1 fmt=26] +--- frame 3 --- + 11 prim=8 indices=3 vs=0x0A6D1DD7767FDF27 ps=0x2E372EA28CC404B7 + vb=0x15076C38 stride=28 attrs=[57@0 38@12 ] fmt0=57 v: [-0.50,-0.50,z=0.00000] [1279.50,-0.50,z=0.00000] [1279.50,719.50,z=0.00000] + 12 prim=13 indices=4 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x0BA60000 1280x768 fmt=6] + vb=0x15076C90 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-1.00,1.00,z=0.00000,col=FFFFFFFF] [1.00,1.00,z=0.00000,col=FFFFFFFF] [1.00,-1.00,z=0.00000,col=FFFFFFFF] [-1.00,-1.00,z=0.00000,col=FFFFFFFF] + 13 prim=13 indices=8 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x11C80000 1280x768 fmt=6] + vb=0x15076CF0 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [0.73,1.58,z=0.00000,col=C5FFFFFF] [1.27,1.02,z=0.00000,col=C5FFFFFF] [0.43,-1.57,z=0.00000,col=C5FFFFFF] [-0.11,-1.02,z=0.00000,col=C5FFFFFF] [-1.32,1.02,z=0.00000,col=B8FFFFFF] [-0.88,1.81,z=0.00000,col=B8FFFFFF] [0.71,-1.02,z=0.00000,col=B8FFFFFF] [0.27,-1.81,z=0.00000,col=B8FFFFFF] + 14 prim=13 indices=4 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x0B690000 1280x768 fmt=6] + vb=0x15076DB0 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-1.00,1.00,z=0.00000,col=FFFFFFFF] [1.00,1.00,z=0.00000,col=FFFFFFFF] [1.00,-1.00,z=0.00000,col=FFFFFFFF] [-1.00,-1.00,z=0.00000,col=FFFFFFFF] + 15 prim=13 indices=8 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x0B2C0000 1280x768 fmt=6] + vb=0x15076E10 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-0.90,0.68,z=0.00000,col=FFFFFFFF] [0.87,0.68,z=0.00000,col=FFFFFFFF] [0.87,-0.10,z=0.00000,col=FFFFFFFF] [-0.90,-0.10,z=0.00000,col=FFFFFFFF] [-0.89,0.65,z=0.00000,col=FFFFFFFF] [0.86,0.65,z=0.00000,col=FFFFFFFF] [0.86,-0.08,z=0.00000,col=FFFFFFFF] [-0.89,-0.08,z=0.00000,col=FFFFFFFF] + 16 prim=13 indices=8 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x11C80000 1280x768 fmt=6] + vb=0x15076ED0 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-0.71,0.47,z=0.00000,col=FFFFFFFF] [0.72,0.47,z=0.00000,col=FFFFFFFF] [0.72,0.15,z=0.00000,col=FFFFFFFF] [-0.71,0.15,z=0.00000,col=FFFFFFFF] [0.76,-0.05,z=0.00000,col=FFFFFFFF] [0.82,-0.05,z=0.00000,col=FFFFFFFF] [0.82,-0.10,z=0.00000,col=FFFFFFFF] [0.76,-0.10,z=0.00000,col=FFFFFFFF] + 17 prim=13 indices=4 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x0BE30000 1280x768 fmt=6] + vb=0x15076F90 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-0.79,0.15,z=0.00000,col=FFFFFFFF] [0.76,0.15,z=0.00000,col=FFFFFFFF] [0.76,-0.14,z=0.00000,col=FFFFFFFF] [-0.79,-0.14,z=0.00000,col=FFFFFFFF] + 18 prim=13 indices=8 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x11C80000 1280x768 fmt=6] + vb=0x15076FF0 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-0.54,-0.82,z=0.00000,col=FFFFFFFF] [0.54,-0.82,z=0.00000,col=FFFFFFFF] [0.54,-0.87,z=0.00000,col=FFFFFFFF] [-0.54,-0.87,z=0.00000,col=FFFFFFFF] [-0.40,-0.53,z=0.00000,col=FFFFFFFF] [0.40,-0.53,z=0.00000,col=FFFFFFFF] [0.40,-0.67,z=0.00000,col=FFFFFFFF] [-0.40,-0.67,z=0.00000,col=FFFFFFFF] + 19 prim=13 indices=4 vs=0xE0BAFB4F520FE441 ps=0xE59B2B3DA4AA9008 tex[base=0x0B2C0000 1280x768 fmt=6] + vb=0x150770B0 stride=24 attrs=[57@0 6@12 37@16 ] fmt0=57 v: [-0.42,-0.49,z=0.00000,col=1EFFFFFF] [0.42,-0.49,z=0.00000,col=1EFFFFFF] [0.42,-0.70,z=0.00000,col=1EFFFFFF] [-0.42,-0.70,z=0.00000,col=1EFFFFFF] + 20 prim=8 indices=3 vs=0x72CBCAA6A7984111 ps=0xE59B2B3DA4AA9008 tex[base=0x10000000 1x1 fmt=26] + 21 prim=8 indices=3 vs=0x72CBCAA6A7984111 ps=0xE59B2B3DA4AA9008 tex[base=0x10000000 1x1 fmt=26] diff --git a/docs/re/ui-title-build-map.md b/docs/re/ui-title-build-map.md index 1f92ec09..66cd2d67 100644 --- a/docs/re/ui-title-build-map.md +++ b/docs/re/ui-title-build-map.md @@ -555,7 +555,7 @@ Identical to within 0.001 over 17.5 s. **The band is settled by t = 4.0 s**, the capture handed to the port agent is sound, and the caveat is withdrawn. It also corroborates that the groups **hold**: nothing crosses that band in 22 s. -## ❔ The swoosh: undecodable from the disc, with reach +## The swoosh — SOLVED by draw capture (see below); the elimination trail kept Seven candidates eliminated, none confirmed: @@ -595,3 +595,51 @@ So the route splits: Either way it is instrumentation of the running guest, not another field in the file. + + +## ✅ SOLVED — the game draws the swoosh as ROTATED QUADS, which our blit cannot + +The route named in the previous section was run: `--ui_draw_capture_frames=3`, +armed with F10 on the settled title. +[`title-draw-capture-vertex-colours.log`](captures/title-builds/title-draw-capture-vertex-colours.log) +is the capture, 22 draws over 3 frames. + +### 🔴 First, the vertex-colour hypothesis dies + +Every vertex colour in the entire capture is `FFFFFF` — **white RGB**, only +the alpha varying: `FFFFFFFF`, `C5FFFFFF`, `C3FFFFFF`, `B8FFFFFF`, `B6FFFFFF`, +`31FFFFFF`, `1EFFFFFF`. The game passes no colour. That was the eighth candidate. + +### ✅ And the ninth is the answer — it is the GEOMETRY + +Draw 2 submits **two parallelograms, neither axis-aligned**: + +| quad | corners (NDC) | edge `v0→v1` | axis-aligned? | +|---|---|---|---| +| A | `(0.70,1.58) (1.24,1.02) (0.40,−1.57) (−0.14,−1.02)` | `(0.54, −0.56)` | **no** | +| B | `(−1.29,1.02) (−0.85,1.81) (0.75,−1.02) (0.31,−1.81)` | `(0.44, 0.79)` | **no** | + +Both verified parallelograms (opposite edges equal to 0.01), both **rotated** — +roughly 45° and 61° — and both extending to `y = ±1.81`, well beyond the screen. +That is the diagonal `Z` stroke. + +**Our compositor cannot draw that.** `ui_layout::blit` walks destination rows and +columns of an **axis-aligned rectangle** (`for row in 0..dh { for col in 0..dw`), +sampling the source by a straight ratio. It has no rotation. So the swoosh is +blitted upright where the game draws it skewed — which is exactly the observed +signature: **right on average (+1.83), right in position (peak at (0,0)), wrong in +structure (edge-corr 0.70)**, dark on one side of the true stroke and bright on +the other. + +### ❔ And a real gap in the decoded format + +The keyframe carries `fade`, `scale_x`, `scale_y`, `tint`, `x`, `y`, `time` +([`ui_layout.rs`](../../crates/sylpheed-formats/src/ui_layout.rs)) — **no +rotation**. So where the game's rotation comes from is **not decoded**: either a +field not yet identified, or the element is positioned by code rather than by its +keyframes. That is the open question this leaves. + +⚠️ **The "pink versus white" reading is now suspect.** It was a visual comparison +of two differently-*shaped* renderings. Whether any colour difference survives +correct geometry is **untested**, and should be re-checked rather than carried +forward as a separate defect. \ No newline at end of file