The Decoder decoded the rule I refused to guess: draw the leaf on its own timeline, do NOT multiply the parent's alpha in. Multiplying is refuted rather than unsupported -- at the fitted time the parent has expired, so leaf x parent predicts zero for both quads and the sweeps would be invisible. They are drawn. Implemented: `_draw_leaf` runs the leaf unclamped, like the spinning ring and for the same reason -- held at its own rest.t the leaf sits at x=1521, entirely off the right edge, so `holding` would delete the sweeps rather than settle them. AND IT CHANGES NOTHING MEASURABLE. The title is still 1.82% against the oracle: 1.82 at t=261, 1.81 at t=355, 1.79 at t=420. At t=355 my interpolation puts the leaf's top-left at x ~ -324, off-screen left, where the Decoder's model puts the quad's CENTRE at 981. Those cannot both be right, and it is not something to tune away -- it is a disagreement about how the leaf's keyframes become a placed quad, most likely in the pivot and the rotation about it. Handed back with both numbers. So: the exporter no longer drops the data, the composition rule is implemented as decoded, and the port's largest oracle gap is exactly where it was. Fixing the export was necessary and not sufficient. TWO FLAGGED ELEMENTS DELIBERATELY NOT DRAWN, in authored/rendering.json with reasons. title_jp/ptlogo_eff2 (parent 125%, leaf 100%) is the same shape and is the element DECISIONS has recorded since P1 as the largest render disagreement -- but the Decoder said plainly "I have not tested it", and drawing it would extend a decode past the case it was fitted on. pgloading_loop5's leaf is scale (0,0), and scale-0 is one of the three historical failures this corpus names. Neither can be adjudicated here: title_jp has no oracle capture, and verify-screen compares against a renderer that draws no leaves at all, so ANY leaf drawing increases that divergence whether right or wrong. Its max went 155 -> 232 when they were drawn, and that number is not evidence in either direction. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF
50 lines
2.5 KiB
Rust
50 lines
2.5 KiB
Rust
//! Probe: does a `.rat` leaf record carry geometry the parent element does not?
|
||
//!
|
||
//! The GPU capture says the title submits `ptloop01`/`ptloop02` scaled 600 %/800 %
|
||
//! and rotated +30.26°/−45.28°, while the export writes scale 100 % and rotation
|
||
//! 0 for both. `ui_layout`'s own note says the rotated quads come from the
|
||
//! **nested `.rat` leaf records**, which is where `export_screen` already looks
|
||
//! for focus records and nowhere else.
|
||
use sylpheed_formats::{pak::PakArchive, ui_layout};
|
||
|
||
fn main() {
|
||
let disc = std::env::var("SYLPHEED_DISC").unwrap_or_else(|_| "/disc".into());
|
||
let ar = PakArchive::open(format!("{disc}/dat/GP_TITLE.pak")).expect("open");
|
||
let e = &ar.entries()[4]; // entry 4 = the English title
|
||
let bundle = ar.read(e).expect("read");
|
||
let b = ui_layout::parse_build(&bundle).expect("parse");
|
||
println!("build has {} elements, {} records", b.elements.len(), b.records.len());
|
||
let mut names: Vec<&String> = b.records.keys().collect();
|
||
names.sort();
|
||
println!("records: {names:?}");
|
||
for el in &b.elements {
|
||
if !el.name.starts_with("ptloop") { continue; }
|
||
let r = el.rest();
|
||
println!("\nPARENT {} sprite={:?} -> rest scale {:?} rot {:?}", el.name, el.sprite,
|
||
r.map(|r| (r.scale_x, r.scale_y)), r.map(|r| r.rotation_deg));
|
||
if let Some(&(off, size)) = b.records.get(&el.name) {
|
||
match ui_layout::parse_build(&bundle[off..off + size]) {
|
||
Some(leaf) => {
|
||
println!(" LEAF {} parses: {} element(s)", el.name, leaf.elements.len());
|
||
for le in &leaf.elements {
|
||
let lr = le.rest();
|
||
println!(" {:<20} rest scale {:?} rot {:?} pos {:?}",
|
||
le.name,
|
||
lr.map(|r| (r.scale_x, r.scale_y)),
|
||
lr.map(|r| r.rotation_deg),
|
||
lr.map(|r| (r.x, r.y)));
|
||
for k in &le.keyframes {
|
||
println!(" t={:?} scale=({},{}) rot={} pos=({},{}) fade={:#010x} u4={} u8={}",
|
||
k.time, k.scale_x, k.scale_y, k.rotation_deg, k.x, k.y,
|
||
k.fade, k.unknown_4, k.unknown_8);
|
||
}
|
||
}
|
||
}
|
||
None => println!(" LEAF {} does NOT parse as a build", el.name),
|
||
}
|
||
} else {
|
||
println!(" no record named {}", el.name);
|
||
}
|
||
}
|
||
}
|