Rendering assembled e106 from Stage_S02 showed the old slab: e106_bdy_03 spanning 600x1600x998 where three other containers give 276x236x941. Its anchor had slack 3, and the coverage gate tolerated up to three unreferenced tail vertices -- tolerance that was hiding a mis-anchor, since real blocks reach their last vertex exactly (8580 of 8629). Requiring exact coverage moves it to the block the other containers agree on and the slab disappears. Costs 3 resources (6212 -> 6209), inconsistency 39 -> 38, capture oracle unchanged at 46/46, suite green. Evidence: captures/e106-cover-slack-before-after.png Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
35 lines
1.5 KiB
Rust
35 lines
1.5 KiB
Rust
//! Per-sub-mesh vertex/index/coverage dump for one resource.
|
|
//! Usage: submesh_dump <container.xpr> <resource>...
|
|
use sylpheed_formats::mesh::{debug_resource_params, 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();
|
|
for m in Xbg7Model::models_named(&bytes, &want, &|| false) {
|
|
let markers = debug_resource_params(&bytes, &m.name).map(|(mk, _)| mk).unwrap_or_default();
|
|
println!("{} — {} sub-meshes decoded, {} markers declared", m.name, m.meshes.len(), markers.len());
|
|
for (i, s) in m.meshes.iter().enumerate() {
|
|
let max_idx = s.indices.iter().max().copied().unwrap_or(0) as usize;
|
|
let (mut lo, mut hi) = ([f32::MAX; 3], [f32::MIN; 3]);
|
|
for q in &s.positions {
|
|
for k in 0..3 {
|
|
lo[k] = lo[k].min(q[k]);
|
|
hi[k] = hi[k].max(q[k]);
|
|
}
|
|
}
|
|
println!(
|
|
" #{i:<2} at 0x{:<9x} verts {:<6} idx {:<6} max_idx {:<6} slack {} span [{:.0} {:.0} {:.0}]",
|
|
s.vbuf_offset.unwrap_or(0),
|
|
s.positions.len(),
|
|
s.indices.len(),
|
|
max_idx,
|
|
s.positions.len() as i64 - 1 - max_idx as i64,
|
|
hi[0] - lo[0],
|
|
hi[1] - lo[1],
|
|
hi[2] - lo[2]
|
|
);
|
|
}
|
|
}
|
|
}
|