re: the pad word is REMAPPED -- my own bit table was mislabelled throughout
input-pad-read-path.md says of the word the C_PAD_DECODER reads: "There is no shift and no remap on the way in -- the bit positions are XINPUT's own." That is wrong. sub_8220D500 rebuilds the word out of XINPUT_GAMEPAD before anything else sees it, into the game's own numbering. bits 0-3 A B X Y bits 4-7 left stick UP DOWN LEFT RIGHT (+/-20000 of 32767) bits 8-11 right stick UP DOWN LEFT RIGHT bits 12-15 D-pad UP DOWN LEFT RIGHT bits 16-17 START, BACK bits 18-19 LB, RB bits 20-21 LT, RT -- digital, threshold >220 of 255 bits 22-23 L3, R3 Extracted mechanically from the image, no row typed by hand. The control is the shape of the result: the 24 assignments land on bits 0..23, each used exactly once, none repeated. A misdecode does not produce a bijection over a contiguous range, and coincidence does not put the stick and D-pad directions in the same order in two aligned nibbles. So every mask in that page's tables names the wrong button. The 0xE000 x18 site, read there as "B | X | Y", is "D-pad DOWN | LEFT | RIGHT" -- eighteen sites testing a menu cursor, which is what 18 sites should be. And its headline negative is REFUTED: "LB and RB are not menu inputs" is false. They are bound at config fields this+0x70 and this+0x84, LT/RT at +0x74/+0x80. The negative was searched for 0x0100/0x0200 -- LB and RB in XINPUT's numbering -- in a word where they live at 0x40000/0x80000. Right function, right buttons, wrong bit positions, so it could only come back empty. A negative is only as good as the numbering it was searched in. Also decodes the ring record: +12 HELD, +16 PRESSED, +20 RELEASED, +28/+32 raw trigger bytes. Edge and level are one struct four bytes apart, which displaces that page's guess that press-vs-hold was split between GetState and the XamInputGetKeystrokeEx queue. The superset claim in that page survives and is untouched: sub_82457038 really does compare every XINPUT_GAMEPAD field, and it really is XINPUT-layout. This page depends on it. Not decoded: which output bit means which ACTION, and per-screen sets. 5 of 18 output-bit sites did not resolve to a pad guard, so the output map is a lower bound -- in particular "START is not tested" is NOT claimed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
This commit is contained in:
@@ -143,6 +143,7 @@ files, which is how the same ground got covered twice.
|
||||
| [`h3-units-per-frame-measured.md`](h3-units-per-frame-measured.md) | How many keyframe units elapse per guest frame, and which declared time the title's settle anchor is | ✅ **measured against a pre-registration, 2026-09-01. 2 units per guest frame**, on `ptbtn00`'s own declared ramp (`t=214→236`, T=22): three consecutive gap-free steps of **exactly 23** = 255×2/22, ramp span 10 labels against a predicted 11 (±1). The Port's inferred **5 is excluded by >2×**. 🔴 Why 5 appeared: **an alpha step is not a clock rate** — `Δα/frame = 255·(units/frame)/T`, so splash B's 34-with-T=15 and the plate's 23-with-T=22 are ONE clock. Also: the **title settle anchor is t≈160**, not t=118 — it is `ptcopyright`, the last build-in element and the only glyph one, full at label 5350 → t≈168–176. 🔴 **units/SECOND is NOT settled** and two of my own captures disagree ~2.9× on it; the gap is in frames→seconds, not units→frames. |
|
||||
| [`h3-units-per-frame-preregistration.md`](h3-units-per-frame-preregistration.md) | The prediction, committed before the capture was read | ✅ kept as the control on the row above |
|
||||
| [`input-pad-read-path.md`](input-pad-read-path.md) | What the game asks the console for, on the pad | ✅ **decoded from the image, 2026-09-01.** `sub_82457038` is the only function that reads controller *data*, and it compares **every** field of `XINPUT_GAMEPAD` — `wButtons` (full 16 bits), both triggers, all four stick axes — against the previous state. **14/14** loads verified byte-for-byte against `/image/sylpheed.pe`, database used as an index only. **Two input paths**: the polled state and an 8-byte-record `XamInputGetKeystrokeEx` ring. ⚠️ This is the **superset the game can see, not the per-screen set** — reading a field is not acting on it. ❔ Which bits each screen tests is open; footholds are the image's own `C_PAD_DECODER` / `C_PAD_RINGBUF` trace strings (`sub_8220B610` / `sub_821A6470`). |
|
||||
| [`input-button-numbering-is-remapped.md`](input-button-numbering-is-remapped.md) | The bit numbering the game's pad decoder actually uses | ✅ **DECODED ⟨image⟩**, and 🔴 **refutes `input-pad-read-path.md`'s central claim** that there is *"no shift and no remap — the bit positions are XINPUT's own"*. `sub_8220D500` rebuilds the word out of `XINPUT_GAMEPAD` into the game's numbering: bits **0–3 A B X Y**, **4–7 left stick** (±20000), **8–11 right stick**, **12–15 D-pad**, **16–17 START/BACK**, **18–19 LB/RB**, **20–21 LT/RT** (digital >220), **22–23 L3/R3**. ✅ **Control**: the 24 assignments land on bits 0…23, each used exactly once — a misdecode does not yield a clean bijection. 🔴 **The old page's negative "LB and RB are not menu inputs" is FALSE** — bound at config fields `+0x70`/`+0x84`; it was searched at XINPUT's bit positions in a word that does not use them. ✅ Also decodes the ring record: `+12` HELD, `+16` PRESSED, `+20` RELEASED, `+28`/`+32` raw trigger bytes — so **edge and level are one struct** and the keystroke queue is not needed to tell a press from a hold. 📌 The left stick is digitised to 4 direction bits at 61 % deflection, which is why the game cannot move a cursor at a speed (play-test finding 2). ⚠️ Not decoded: which output bit means which ACTION, and per-screen sets; 5 of 18 output sites unresolved, so the map is a lower bound |
|
||||
| [`ui-splash-draw-pass.md`](ui-splash-draw-pass.md) | The splash draw pass — is there a post-process, and where does the fade come from | ✅ **decoded from GPU state, 2026-09-01.** **No post-process pass exists**: over all 1 048 draws of both splashes, one render target (`rt0=[tile=0…]` 1 048/1 048), one pitch, no MSAA, only kColorDepth/kCopy modes, resolve destinations only the two front buffers, and **no texture base anywhere equals a resolve destination**. The only texture bound is the sprite page. Three trivial pixel shaders; the sprite shader **premultiplies**, so `ONE/ONE_MINUS_SRC_ALPHA` is algebraically **source-over**. Parameters come from **per-vertex `k_8_8_8_8` colour** in a per-frame vertex buffer — the shaders read **zero** float constants (`ps_c[n=0]` 1 048/1 048). Ramp reproduces the ✅ 34/frame law. ⚠️ Censusing the whole 600-frame log instead finds the attract movie's 640×360 chroma planes and reads as a half-res blur chain — the frame window is what avoids that. |
|
||||
| [`splash-glow-is-a-baked-texture.md`](splash-glow-is-a-baked-texture.md) | What the splash "blur" actually is, and which quad is which sprite | ✅ **DECODED (disc), confirmed against the oracle 8/8.** Answers play-test finding 4 as a mechanism: **there is no blur pass and no filter — each logo ships a SECOND texture that IS the blur.** `palogo_<x>_eff.t32` is the same artwork **outset by exactly 10 px on every side**, concentric to ≤ 1.5 px, drawn as its own alpha-over quad. ✅ **The capture's Q0…Q7 are now NAMED**: predicting each NDC rect from the declared position + decoded sprite size matches all eight bijectively, every match ≤ 0.0061 with every runner-up ≥ 0.0272 (4.5–8.9× margin — the control). 🔴 **Refutes `splash-quad-timeline.txt`'s "the same rects scaled slightly larger"**: x/y scale factors differ by up to 0.28, so a port must **load the `_eff` texture, not transform the logo**. ✅ **Blend bit tested OUT of sample** on entries 10/11 (never in its 35-row fit): pre-registered `additive = false` for all eight against 0 additive draws in 1 048 — held 8/8, control still reports 9 additive on entry 6. 📌 The ⟨our-reader⟩ 🟡 on splash geometry resolves **in the reader's favour** — the prediction is ours, the target is the oracle, so agreement is evidence *about* the reader |
|
||||
| [`ui-keyframe-record-layout.md`](ui-keyframe-record-layout.md) | A keyframe's time word comes **before** its pose — the placement record, decoded | ✅ CONFIRMED, **decoded**. A group is an 8-byte header then `frames` records of `{u32 time; 36-byte pose}`, so the time precedes the pose; the group's lead-in word at `header+8` is pose 0's time and **every** pose is timed. Disc-wide over 13 991 groups in 33 archives, each test with a control: lead-in prepended is non-decreasing **13 991/13 991**; a non-zero lead-in is strictly below the next time **5 058/5 058** (control 70.9 %); a multi-segment alpha ramp runs at a constant `dα/dt` **857/1 540** against **0/1 042** under the old reading. 🔴 Retires two long-standing corpus claims — *"a group's data stops 4 bytes short of its final block's time slot"* and *"the last keyframe carries no time"* — both of which were this off-by-one. Adoption is free: all 12 `GP_TITLE` builds render byte-identically, and over 217 builds only two elements pick a different `rest()` pose, both between equally invisible ones. ❔ the executable's own parser was **not** found (the 40/60 stride query is weak, not negative) |
|
||||
|
||||
Reference in New Issue
Block a user