Files
Sylpheed/crates/sylpheed-formats/examples/splash_blend_check.rs
sylph-decoder e263041337 re: the splash blur is a TEXTURE -- palogo_*_eff is a baked 10-px glow
Play-test finding 4, answered as a mechanism and from the disc, so it
generalises instead of describing one boot.

ui-splash-draw-pass.md excluded a post-process from GPU state and closed
with "that softness is in the texture or in which quads are drawn, not in
a pass", leaving the two unseparated. It is both, and they are one fact:
each logo ships a second texture that IS the blur -- the same artwork
outset by exactly 10 px per side, concentric to <=1.5 px, drawn as its
own alpha-over quad.

Three results, each with its control:

* The capture's eight anonymous quads are NAMED from the disc. Predicting
  each NDC rect from declared position + decoded sprite size matches all
  eight bijectively; every match <=0.0061, every runner-up >=0.0272, a
  4.5-8.9x margin. That margin is the control -- eight similar boxes
  would match anything.

* REFUTES splash-quad-timeline.txt's "the same three rects scaled
  slightly larger" (my own earlier wording). The x and y scale factors
  differ by up to 0.28; a uniform scale cannot do that, a fixed 10-px
  border can. The conclusion it supported (draw all six quads) stands;
  the model was wrong, and the wrong model tells a port to scale a
  sprite.

* The T8aD blend bit tested OUT of sample on entries 10/11, which were
  not in its 35-row fit and are the screens under complaint.
  Pre-registered additive=false for all eight against 0 additive draws in
  1048; held 8/8, with the control still reporting 9 additive on entry 6.

Also resolves a REFUTED.md 🟡 <our-reader> in the reader's favour: the
prediction is ours and the target is the oracle, so the agreement is
evidence about the reader rather than a claim resting on it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
2026-09-01 18:24:14 +00:00

76 lines
3.6 KiB
Rust

//! Out-of-sample test of the `T8aD +0x04` blend bit on the **boot splashes**.
//!
//! `ui-blend-mode-decoded.md` established the field on 35 elements over three
//! screens (GP_TITLE entries 2, 4, 5, 6). The two splashes -- entries 10 and 11 --
//! were NOT in that sample, and they are the screens the 2026-09-01 play-test
//! says are wrong.
//!
//! The oracle for these two screens is `data/splash-draw-pass-census.txt`: over
//! **1048 draws of frames 4..226**, covering both splashes end to end, the only
//! blend states submitted are `0x00010001` (the clear) and `0x07010701`
//! (source-over). Additive, `0x01010101`, appears **zero** times.
//!
//! PRE-REGISTERED PREDICTION, written before reading the disc: if the bit is the
//! blend selector and it generalises off its training screens, then every sprite
//! in entries 10 and 11 must report `additive = false`. Any `true` is a
//! discrepancy the field has to answer for.
//!
//! cargo run --release -p sylpheed-formats --example splash_blend_check
use std::path::PathBuf;
use sylpheed_formats::{pak::PakArchive, ui_layout};
fn main() {
let root = PathBuf::from(std::env::var("SYLPHEED_DISC").expect("SYLPHEED_DISC"));
let ar = PakArchive::open(root.join("dat/GP_TITLE.pak")).expect("GP_TITLE");
let mut additive = 0usize;
let mut alpha_over = 0usize;
let mut no_header = 0usize;
for entry in [10usize, 11] {
let by = ar.read(&ar.entries()[entry]).expect("entry");
let Some(b) = ui_layout::parse_build(&by) else {
println!("entry {entry}: not a build");
continue;
};
println!("\n## GP_TITLE entry {entry} -- {} elements, {} sprites",
b.elements.len(), b.sprites.len());
// Every sprite the bundle carries, not only those a top-level element
// names: a focused variant is reached through `focus_link` and would
// otherwise be invisible to this check.
let mut names: Vec<&String> = b.sprites.keys().collect();
names.sort();
for n in names {
match ui_layout::blend_additive_by_name(&b, &by, n) {
Some(true) => { additive += 1;
println!(" {n:<26} word04=0x{:08X} ADDITIVE",
ui_layout::header_word_04_by_name(&b, &by, n).unwrap()); }
Some(false) => { alpha_over += 1;
println!(" {n:<26} word04=0x{:08X} alpha-over",
ui_layout::header_word_04_by_name(&b, &by, n).unwrap()); }
None => { no_header += 1; println!(" {n:<26} (no T8aD header)"); }
}
}
}
println!("\nadditive={additive} alpha-over={alpha_over} no-header={no_header}");
println!("oracle (splash-draw-pass-census.txt, 1048 draws): additive draws = 0");
if additive == 0 {
println!("PREDICTION HELD -- the bit agrees with the capture on both splashes");
} else {
println!("PREDICTION FAILED -- {additive} sprite(s) claim additive, \
the capture submits none");
}
// Control: this harness must be able to REPORT additive, or "additive=0"
// is a property of the harness and not of the splashes. Entry 6 is a screen
// the oracle measures as mixed.
let by6 = ar.read(&ar.entries()[6]).expect("entry 6");
let b6 = ui_layout::parse_build(&by6).expect("build 6");
let c_add = b6.sprites.keys()
.filter(|n| ui_layout::blend_additive_by_name(&b6, &by6, n) == Some(true)).count();
println!("control -- entry 6 through the SAME code path reports additive={c_add} \
(must be > 0): {}", if c_add > 0 { "PASS" } else { "FAIL" });
}