Files
Sylpheed/crates/sylpheed-formats/examples/prm_occlusion_check.rs
sim cc9392bde4 test: one disc resolver, no machine-specific defaults, all three corpora in the container
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>
2026-09-17 22:18:59 +02:00

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}")
);
}
}
}
}