Finishes #16 in the three places its earlier remedies missed. `tests/`: the last four local `disc_root()` copies now use `tests/common`, and with them goes the one real hardcoded fallback — `ui_keyframe_record_disc.rs` fell back to an absolute path on one machine, which made `unset SYLPHEED_DISC` a no-op there. Control: with the corpus absent that suite now finishes in 0.00s instead of 57.55s, so it skips rather than finding a disc of its own. `examples/`: seventeen examples defaulted to `/disc`, the mount point inside the CI container. Redundant there — `docker/ci/run` sets `SYLPHEED_DISC=/disc` — and wrong everywhere else, where a missing corpus turned into a file-not-found against a path that has never existed on the host. They now name the variable to set, like the other hundred examples already did. `docker/ci/run`: mount `$SYLPHEED_RES3D` and `$SYLPHEED_ISO` alongside the disc. Only the disc was mounted, so an in-container run sat out the res3d and iso suites while looking like a full one — the defect this issue is about, in the runner itself. Measured in the container on this desktop with all three corpora present: 45 suites / 377 passed / 0 failed / 14 ignored, and `sylpheed-corpus-report.txt` now reports PRESENT for all three rather than for the disc alone. Refs #16. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
89 lines
2.9 KiB
Rust
89 lines
2.9 KiB
Rust
use sylpheed_formats::{pak, ratc, ui_layout};
|
|
fn main() {
|
|
let root =
|
|
std::env::var("SYLPHEED_DISC").expect("set SYLPHEED_DISC to the extracted disc root");
|
|
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;
|
|
}
|
|
}
|