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>
140 lines
4.7 KiB
Rust
140 lines
4.7 KiB
Rust
//! An OPAQUE full-screen primitive cannot paint on top of elements that are
|
|
//! visible at the same time — the screen would be blank.
|
|
//!
|
|
//! That is a constraint read off the file, not a preference. For each keyless
|
|
//! primitive this computes the interval over which it is opaque, and the interval
|
|
//! over which any OTHER element is visible, and reports the overlap.
|
|
//!
|
|
//! The falsifier: `pteff00.prm` is MEASURED painting last on the title and the
|
|
//! main menu. If any of its instances is opaque while content is up, the
|
|
//! constraint is wrong and this whole line is dead.
|
|
use sylpheed_formats::{pak, ratc, ui_layout};
|
|
|
|
/// Interval(s) where alpha >= `thr`, sampled at every half unit.
|
|
fn opaque_span(el: &ui_layout::Element, thr: u32, tmax: u32) -> Vec<(f64, f64)> {
|
|
let mut out = Vec::new();
|
|
let mut cur: Option<f64> = None;
|
|
let mut t = 0.0;
|
|
while t <= tmax as f64 {
|
|
let a = el.pose_at(t as u32).map(|k| k.fade >> 24).unwrap_or(0);
|
|
if a >= thr {
|
|
if cur.is_none() {
|
|
cur = Some(t)
|
|
}
|
|
} else if let Some(s) = cur.take() {
|
|
out.push((s, t));
|
|
}
|
|
t += 0.5;
|
|
}
|
|
if let Some(s) = cur {
|
|
out.push((s, tmax as f64))
|
|
}
|
|
out
|
|
}
|
|
|
|
fn main() {
|
|
let root =
|
|
std::env::var("SYLPHEED_DISC").expect("set SYLPHEED_DISC to the extracted disc root");
|
|
let mut paks: Vec<_> = std::fs::read_dir(format!("{root}/dat"))
|
|
.expect("dat/")
|
|
.flatten()
|
|
.map(|e| e.path())
|
|
.filter(|p| p.extension().and_then(|s| s.to_str()) == Some("pak"))
|
|
.collect();
|
|
paks.sort();
|
|
let want = [
|
|
"pteff00.prm",
|
|
"pgloading_eff00.prm",
|
|
"palogo_eff0.prm",
|
|
"pfbase.tbm",
|
|
"pteff02.prm",
|
|
"pzeff00.prm",
|
|
"pceff00.prm",
|
|
"pdeff00.prm",
|
|
];
|
|
println!(
|
|
"{:>22} {:>5} {:>16} {:>18} overlap",
|
|
"primitive", "entry", "opaque while", "content visible"
|
|
);
|
|
for p in &paks {
|
|
let Ok(ar) = pak::PakArchive::open(p) else {
|
|
continue;
|
|
};
|
|
for (ei, 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 tmax = b
|
|
.elements
|
|
.iter()
|
|
.flat_map(|el| el.keyframes.iter().filter_map(|k| k.time))
|
|
.max()
|
|
.unwrap_or(0);
|
|
if tmax == 0 {
|
|
continue;
|
|
}
|
|
for el in &b.elements {
|
|
if !want.contains(&el.name.as_str()) {
|
|
continue;
|
|
}
|
|
if ui_layout::sprite_layer_key(&b, &by, el).is_some() {
|
|
continue;
|
|
}
|
|
let op = opaque_span(el, 255, tmax);
|
|
if op.is_empty() {
|
|
continue;
|
|
}
|
|
// when is any OTHER element visible?
|
|
let mut cmin = f64::MAX;
|
|
let mut cmax = f64::MIN;
|
|
for o in &b.elements {
|
|
if o.index == el.index {
|
|
continue;
|
|
}
|
|
for (s, t) in opaque_span(o, 1, tmax) {
|
|
cmin = cmin.min(s);
|
|
cmax = cmax.max(t)
|
|
}
|
|
}
|
|
if cmin > cmax {
|
|
continue;
|
|
}
|
|
// overlap of the primitive's opaque span with the content span
|
|
let ov: f64 = op
|
|
.iter()
|
|
.map(|&(s, t)| (t.min(cmax) - s.max(cmin)).max(0.0))
|
|
.sum();
|
|
let opd: String = op
|
|
.iter()
|
|
.map(|&(s, t)| format!("{s:.0}-{t:.0}"))
|
|
.collect::<Vec<_>>()
|
|
.join(",");
|
|
let flag = if ov > 2.0 {
|
|
" 🔴 CANNOT BE ON TOP"
|
|
} else {
|
|
""
|
|
};
|
|
println!(
|
|
"{:>22} {:>5} {:>16} {:>18} {ov:6.1}{flag}",
|
|
el.name,
|
|
format!(
|
|
"{}:{}",
|
|
p.file_name()
|
|
.unwrap()
|
|
.to_string_lossy()
|
|
.trim_end_matches(".pak")
|
|
.trim_start_matches("GP_"),
|
|
ei
|
|
),
|
|
opd,
|
|
format!("{cmin:.0}-{cmax:.0}")
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|