twin_mirror_audit applies the capture-derived rule to all 166 containers: of 34 equal-count twin pairs, 18 are exact X-mirrors, 15 related another way, 1 identical, 0 unrelated. Two calibration fixes were needed first (authored halves need a tolerance, and a mirrored pair may be stored in another vertex order). The one collapse, n206_01/_02, is a grouped-pool pair -- the path distinct assignment excludes -- so it names the next target. Added a disc-gated regression test; refreshed the stale ignore message on the consistency test. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
45 lines
1.8 KiB
Rust
45 lines
1.8 KiB
Rust
//! Does the container hold an X-mirrored copy of a resource's decoded buffer?
|
|
//!
|
|
//! The twin invariant (see `twin_mirror_audit`) flags `…_01`/`…_02` pairs that
|
|
//! decode to unrelated geometry. If the mirror of one twin's buffer exists
|
|
//! somewhere else in the container, that offset is where the other twin belongs
|
|
//! and the pair is a mis-anchor; if it does not exist, the pair is simply not a
|
|
//! mirrored pair.
|
|
//!
|
|
//! Usage: find_mirror <container.xpr> <resource>...
|
|
use sylpheed_formats::mesh::Xbg7Model;
|
|
use std::collections::HashSet;
|
|
|
|
fn main() {
|
|
let a: Vec<String> = std::env::args().collect();
|
|
let bytes = std::fs::read(&a[1]).expect("container");
|
|
let want: HashSet<String> = a[2..].iter().cloned().collect();
|
|
let models = Xbg7Model::models_named(&bytes, &want, &|| false);
|
|
let be = |at: usize| f32::from_be_bytes(bytes[at..at + 4].try_into().unwrap());
|
|
|
|
for m in &models {
|
|
let pos: Vec<[f32; 3]> = m.meshes.iter().flat_map(|s| s.positions.clone()).take(8).collect();
|
|
if pos.len() < 8 {
|
|
continue;
|
|
}
|
|
let anchored = m.meshes[0].vbuf_offset.unwrap_or(0);
|
|
let (mut direct, mut mirror) = (Vec::new(), Vec::new());
|
|
for o in (0..bytes.len().saturating_sub(12 + 8 * 24)).step_by(4) {
|
|
for (flip, out) in [(1.0f32, &mut direct), (-1.0f32, &mut mirror)] {
|
|
if (0..8).all(|k| {
|
|
let at = o + k * 24;
|
|
(be(at) - flip * pos[k][0]).abs() <= 1e-4
|
|
&& (be(at + 4) - pos[k][1]).abs() <= 1e-4
|
|
&& (be(at + 8) - pos[k][2]).abs() <= 1e-4
|
|
}) {
|
|
out.push(o);
|
|
}
|
|
}
|
|
}
|
|
println!(
|
|
"{:<20} anchored 0x{anchored:x} direct copies {:x?} mirrored copies {:x?}",
|
|
m.name, direct, mirror
|
|
);
|
|
}
|
|
}
|