Files
Sylpheed/crates/sylpheed-formats/examples/prm_forced_first.rs
MechaCat02 d394ba6aed style: rustfmt sweep — 107 files the lint gate never saw
This branch predates CI on `main`. `cargo fmt --all` only; no behaviour.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 16:34:40 +02:00

96 lines
3.8 KiB
Rust

//! Which keyless primitives have their paint position FORCED by occlusion?
//!
//! An opaque full-screen quad must sort below every element visible at any
//! instant it is opaque. Where that set is *every* other element, its position is
//! forced to first — derived from the file, not analogised from a neighbour.
//!
//! Controls, both measured in the running game and both reproduced here:
//! * `palogo_eff0.prm` is measured painting FIRST — and comes out forced first.
//! * `pteff00.prm` is measured painting LAST — and is forced below only a
//! handful, so the constraint permits it on top.
//!
//! ⚠️ Assumes straight alpha-over blending. Blend mode is ❔ in
//! `ui-prm-primitives.md`; an additive quad at alpha 255 would not occlude.
use sylpheed_formats::{pak, ratc, ui_layout};
fn main() {
let root = std::env::var("SYLPHEED_DISC").unwrap_or_else(|_| "/disc".into());
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 (mut forced, mut partial, mut free) = (0usize, 0usize, 0usize);
let mut names: std::collections::BTreeMap<String, (usize, usize)> = Default::default();
for p in &paks {
let Ok(ar) = pak::PakArchive::open(p) else {
continue;
};
for e in ar.entries() {
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 ui_layout::sprite_layer_key(&b, &by, el).is_some() {
continue;
}
// full-screen only: a quad that does not cover cannot occlude
if el.pivot_x * 2 < 1280 || el.pivot_y * 2 < 720 {
continue;
}
let op: Vec<u32> = (0..=tmax)
.filter(|&t| el.pose_at(t).map(|k| k.fade >> 24) == Some(255))
.collect();
if op.is_empty() {
continue;
}
let others: Vec<&ui_layout::Element> =
b.elements.iter().filter(|o| o.index != el.index).collect();
if others.is_empty() {
continue;
}
let below = others
.iter()
.filter(|o| {
op.iter()
.any(|&t| o.pose_at(t).map(|k| k.fade >> 24).unwrap_or(0) > 0)
})
.count();
let ent = names.entry(el.name.clone()).or_default();
ent.1 += 1;
if below == others.len() {
forced += 1;
ent.0 += 1
} else if below > 0 {
partial += 1
} else {
free += 1
}
}
}
}
println!("keyless FULL-SCREEN primitives with an opaque interval:");
println!(" position FORCED FIRST (below every other element) : {forced}");
println!(" forced below SOME but not all : {partial}");
println!(" occludes nothing : {free}");
println!("\nby name — instances forced first / total:");
for (n, (f, t)) in &names {
println!(" {n:>24} {f:>4} / {t}");
}
}