Looked in four places. The bundle has no field: a primitive has no RATC child at all and the declaration words are constant across every element of three measured screens -- the two grounds ui-prm-primitives.md already used to refute a bundle-side LAYER key, and they apply identically to blend. The colour census: every full-screen *eff00* primitive on the disc carries pure black at its various alphas, and the only non-black primitive anywhere is pbafc.prm, RGB 00e8e0 cyan. The occlusion constraint cannot reach that one. pbafc.prm looked alarming at a declared 844x600 and alpha ff; it is a small moving glint. It strobes between alpha 255 and 124 every 2 units, travels from x=178 to x=291, and is scaled 2%x3%, so it draws about 17x18 pixels. At that size it occludes essentially nothing. The oracle is unavailable: GP_READY_ROOM is a recorded no-go and gameplay needs the A press that faults the guest in this container. But the consequence closes even though the question does not. For a BLACK quad -- which is every primitive forced_backdrop touches -- the hypotheses differ only in whether it hides what is beneath. Drawn first it is correct under both; drawn last it is correct only under additive. So the rule's verdict is robust to the open question, and the port's original "layerless sorts last" was wrong under alpha-over and merely pointless under additive. This is explicitly NOT evidence for alpha-over. The investigation also found forced_backdrop judging coverage from the pivot alone, ignoring scale -- pbafc.prm is the disc's own proof that a nominally 844x600 element can draw at 2%. Checked before changing anything: all 80 forced instances are at scale 100% on every opaque instant, so no verdict moved. The guard now requires scale >= 100 at the instants it counts as opaque. Defensive, not a fix. 4 + 13 disc tests green either side. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsEPXWVaEpyfudtR6re1Pd
40 lines
2.2 KiB
Rust
40 lines
2.2 KiB
Rust
use sylpheed_formats::{pak, ratc, ui_layout};
|
|
fn main(){
|
|
let root=std::env::var("SYLPHEED_DISC").unwrap_or_else(|_|"/disc".into());
|
|
let ar=pak::PakArchive::open(format!("{root}/dat/GP_READY_ROOM.pak")).unwrap();
|
|
for (i,e) in ar.entries().iter().enumerate() {
|
|
let Ok(by)=ar.read(e) else { continue };
|
|
if !ratc::is_ratc(&by) { continue }
|
|
let Some(b)=ui_layout::parse_build(&by) else { continue };
|
|
let Some(p)=b.elements.iter().find(|el|el.name=="pbafc.prm") else { continue };
|
|
println!("=== entry {i}: {} elements ===", b.elements.len());
|
|
println!(" pbafc.prm pivot=({},{}) -> {}x{}", p.pivot_x,p.pivot_y,p.pivot_x*2,p.pivot_y*2);
|
|
for k in &p.keyframes {
|
|
println!(" t={:<5} fade={:08x} a={:<4} xy=({},{}) s={}/{}",
|
|
k.time.map(|v|v as i64).unwrap_or(-1), k.fade, k.fade>>24, k.x,k.y,k.scale_x,k.scale_y);
|
|
}
|
|
// what does it cover, and is anything visible while it is opaque?
|
|
let rest=p.rest().unwrap();
|
|
let (px,py,pw,ph)=(rest.x, rest.y, (p.pivot_x*2) as i32, (p.pivot_y*2) as i32);
|
|
println!(" its rect at rest: ({px},{py}) {pw}x{ph}");
|
|
let tmax=b.elements.iter().flat_map(|e|e.keyframes.iter().filter_map(|k|k.time)).max().unwrap_or(0);
|
|
let op:Vec<u32>=(0..=tmax).filter(|&t|p.pose_at(t).map(|k|k.fade>>24)==Some(255)).collect();
|
|
println!(" opaque at {} instants (t={:?}..{:?}) of 0..{tmax}", op.len(), op.first(), op.last());
|
|
let mut cov=0; let mut vis=0;
|
|
for o in &b.elements {
|
|
if o.index==p.index { continue }
|
|
let Some(ok)=o.rest() else { continue };
|
|
let (ow,oh)=((o.pivot_x*2) as i32,(o.pivot_y*2) as i32);
|
|
let overlap=(px+pw).min(ok.x+ow)-px.max(ok.x)>0 && (py+ph).min(ok.y+oh)-py.max(ok.y)>0;
|
|
if !overlap { continue }
|
|
cov+=1;
|
|
if op.iter().any(|&t| o.pose_at(t).map(|k|k.fade>>24).unwrap_or(0)>0) {
|
|
vis+=1;
|
|
if vis<=6 { println!(" covered AND visible while opaque: {}", o.name); }
|
|
}
|
|
}
|
|
println!(" elements its rect covers: {cov}; visible while it is opaque: {vis}");
|
|
break;
|
|
}
|
|
}
|