This branch predates CI on `main`. `cargo fmt --all` only; no behaviour. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
112 lines
4.1 KiB
Rust
112 lines
4.1 KiB
Rust
//! How often does posing at the SCREEN's settle instant catch an element
|
||
//! mid-ramp? The adversarial census of my own proposal.
|
||
//!
|
||
//! The port agent found `ptmsg` — the main menu's footer — at alpha **127.5 of
|
||
//! 255** at that screen's settle instant, because the longest keyframe-free
|
||
//! interval ends exactly as the footer starts to arrive. `screen render --settle`
|
||
//! already prints "⚠️ narrow — this bundle may never settle" there: the window is
|
||
//! **12 units**.
|
||
//!
|
||
//! ⚠️ **And my `rest_vs_settle` filter was too permissive**: it dropped bundles
|
||
//! with a window under 10 units, so a 12-unit window passed while the tool itself
|
||
//! was flagging it. This splits by width instead of picking one cutoff.
|
||
//!
|
||
//! "Mid-ramp" = at the settle instant the element sits strictly inside an interval
|
||
//! whose two endpoint poses DIFFER — it is interpolating, not held.
|
||
//!
|
||
//! cargo run -p sylpheed-formats --example settle_midramp_census
|
||
use std::path::PathBuf;
|
||
use sylpheed_formats::{pak::PakArchive, ui_layout};
|
||
|
||
fn main() {
|
||
let root = PathBuf::from(std::env::var("SYLPHEED_DISC").expect("SYLPHEED_DISC"));
|
||
let mut paks: Vec<PathBuf> = std::fs::read_dir(root.join("dat"))
|
||
.expect("dat/")
|
||
.filter_map(|e| e.ok().map(|e| e.path()))
|
||
.filter(|p| p.extension().is_some_and(|x| x == "pak"))
|
||
.collect();
|
||
paks.sort();
|
||
// buckets by settle-window width
|
||
let edges = [0u32, 10, 20, 30, 60, u32::MAX];
|
||
let names = ["< 10", "10–19", "20–29", "30–59", ">= 60"];
|
||
let mut els = [0usize; 5];
|
||
let mut mid = [0usize; 5];
|
||
let mut bundles = [0usize; 5];
|
||
for pak in &paks {
|
||
let Ok(ar) = PakArchive::open(pak) else {
|
||
continue;
|
||
};
|
||
for e in ar.entries() {
|
||
let Ok(by) = ar.read(e) else { continue };
|
||
let Some(b) = ui_layout::parse_build(&by) else {
|
||
continue;
|
||
};
|
||
let Some((lo, hi)) = b.settle_window() else {
|
||
continue;
|
||
};
|
||
let w = hi - lo;
|
||
let bi = edges
|
||
.windows(2)
|
||
.position(|p| w >= p[0] && w < p[1])
|
||
.unwrap_or(4);
|
||
bundles[bi] += 1;
|
||
let st = lo + w / 2;
|
||
for el in &b.elements {
|
||
let k = &el.keyframes;
|
||
if k.len() < 2 {
|
||
continue;
|
||
}
|
||
els[bi] += 1;
|
||
// the interval containing the settle instant
|
||
let mut interpolating = false;
|
||
for pair in k.windows(2) {
|
||
if let (Some(t0), Some(t1)) = (pair[0].time, pair[1].time) {
|
||
if t0 <= st && st <= t1 && t0 != t1 {
|
||
let same = pair[0].fade == pair[1].fade
|
||
&& pair[0].x == pair[1].x
|
||
&& pair[0].y == pair[1].y
|
||
&& pair[0].scale_x == pair[1].scale_x
|
||
&& pair[0].scale_y == pair[1].scale_y;
|
||
if !same && st != t0 && st != t1 {
|
||
interpolating = true
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if interpolating {
|
||
mid[bi] += 1
|
||
}
|
||
}
|
||
}
|
||
}
|
||
println!(
|
||
"{:8}{:>10}{:>10}{:>12}{:>10}",
|
||
"window", "bundles", "elements", "mid-ramp", "share"
|
||
);
|
||
for i in 0..5 {
|
||
if els[i] == 0 {
|
||
continue;
|
||
}
|
||
println!(
|
||
"{:8}{:>10}{:>10}{:>12}{:>9.1}%",
|
||
names[i],
|
||
bundles[i],
|
||
els[i],
|
||
mid[i],
|
||
100.0 * mid[i] as f64 / els[i] as f64
|
||
);
|
||
}
|
||
let te: usize = els.iter().sum();
|
||
let tm: usize = mid.iter().sum();
|
||
println!(
|
||
"{:8}{:>10}{:>10}{:>12}{:>9.1}%",
|
||
"ALL",
|
||
bundles.iter().sum::<usize>(),
|
||
te,
|
||
tm,
|
||
100.0 * tm as f64 / te as f64
|
||
);
|
||
println!("\n--- END (if this line is missing, the run did not finish) ---");
|
||
}
|