Files
Sylpheed/crates/sylpheed-formats/examples/kf_flip_test.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

87 lines
3.5 KiB
Rust

//! Do `+4` / `+8` = 180 mean MIRROR?
//!
//! The disc-wide census shows `+4` and `+8` are dominated by 180 and ±90, while
//! `+12` (the decoded screen-plane rotation) takes 157 distinct values including
//! odd ones. That shape says flips rather than free rotation.
//!
//! Structural test, no renderer involved: if 180 means "mirror", then the same
//! sprite should appear both with the field 0 and with it 180 **within one
//! build** -- a mirrored pair. Free-rotation semantics predicts no such pairing.
//!
//! CONTROL: the same search run on `+12`, which is decoded as a real rotation
//! and should NOT show a 0/180 pairing pattern of the same strength.
use std::collections::{BTreeMap, BTreeSet};
use sylpheed_formats::{pak, ui_layout};
fn main() {
let dir = std::env::args().nth(1).expect("<disc>/dat");
let mut paks: Vec<_> = std::fs::read_dir(&dir)
.expect("dir")
.filter_map(|e| e.ok().map(|e| e.path()))
.filter(|p| p.extension().map(|x| x == "pak").unwrap_or(false))
.collect();
paks.sort();
// field -> (pak, entry, sprite) -> set of values seen
let mut seen: [BTreeMap<(String, usize, String), BTreeSet<i32>>; 3] =
[BTreeMap::new(), BTreeMap::new(), BTreeMap::new()];
for p in &paks {
let Ok(ar) = pak::PakArchive::open(p) else {
continue;
};
let pn = p.file_name().unwrap().to_string_lossy().to_string();
for (i, e) in ar.entries().to_vec().iter().enumerate() {
let Ok(bytes) = ar.read(e) else { continue };
let Some(b) = ui_layout::parse_build(&bytes) else {
continue;
};
let mut groups: Vec<(String, Vec<ui_layout::Keyframe>)> = b
.elements
.iter()
.map(|el| (el.name.clone(), el.keyframes.clone()))
.collect();
for el in &b.elements {
if let Some(&(off, size)) = b.records.get(&el.name) {
if let Some(lb) = ui_layout::parse_build(&bytes[off..off + size]) {
for le in &lb.elements {
groups.push((le.name.clone(), le.keyframes.clone()));
}
}
}
}
for (nm, ks) in groups {
for k in &ks {
let key = (pn.clone(), i, nm.clone());
seen[0].entry(key.clone()).or_default().insert(k.unknown_4);
seen[1].entry(key.clone()).or_default().insert(k.unknown_8);
seen[2].entry(key).or_default().insert(k.rotation_deg);
}
}
}
}
for (idx, label) in [(0, "+4"), (1, "+8"), (2, "+12 (rotation, CONTROL)")] {
let m = &seen[idx];
let mut pair_0_180 = 0usize; // a sprite seen at BOTH 0 and 180 in one build
let mut only_180 = 0usize;
let mut multi = 0usize; // more than two distinct values
for v in m.values() {
if v.len() > 2 {
multi += 1;
}
let has0 = v.contains(&0);
let has180 = v.contains(&180) || v.contains(&-180);
if has0 && has180 {
pair_0_180 += 1;
} else if has180 && !has0 {
only_180 += 1;
}
}
println!("{label}: {} sprite-instances", m.len());
println!(" both 0 and ±180 in one build : {pair_0_180}");
println!(" ±180 without any 0 : {only_180}");
println!(" more than 2 distinct values : {multi}");
}
}