envelope_screen measures per-axis protrusion past the sibling envelope, the relationship the eye used. It still does not flag e106_bdy_03, and dumping the static assembly shows why: e303_wep_01's world box is 1600x2100x4800 around a ~400x400x2000 hull, so nothing can protrude. The decode is innocent -- that resource is 49x23x42 in every container -- so the static assembler is inflating it 30-110x per axis, non-uniformly. The screen is only meaningful once placement is trustworthy, and the assembler now has a worse defect than the decoder had. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
107 lines
4.5 KiB
Rust
107 lines
4.5 KiB
Rust
//! Does every part of a ship sit inside the envelope its siblings describe?
|
|
//!
|
|
//! `slab_screen` compared *scale* and could not see the `e106` slab. What the eye
|
|
//! used when the render exposed it was **relationship**: a blocky mass sitting
|
|
//! apart from the hull. This measures that — assemble a ship, and for each part
|
|
//! ask how far its world box protrudes beyond the box of all the OTHER parts,
|
|
//! relative to the ship's own size. A mis-anchored block sticks out; a real part,
|
|
//! however big, is part of the silhouette.
|
|
//!
|
|
//! Usage: envelope_screen <resource3d_dir> [protrusion_fraction]
|
|
use sylpheed_formats::mesh::Xbg7Model;
|
|
use sylpheed_formats::ship::{assemble_ship, ship_id_of};
|
|
use std::collections::{BTreeSet, HashSet};
|
|
|
|
fn main() {
|
|
let dir = std::env::args().nth(1).expect("resource3d dir");
|
|
let limit: f32 = std::env::args().nth(2).and_then(|s| s.parse().ok()).unwrap_or(0.35);
|
|
let mut files: Vec<_> = std::fs::read_dir(&dir)
|
|
.unwrap()
|
|
.flatten()
|
|
.map(|e| e.path())
|
|
.filter(|p| p.extension().and_then(|s| s.to_str()) == Some("xpr"))
|
|
.collect();
|
|
files.sort();
|
|
|
|
let mut flagged = 0usize;
|
|
for f in &files {
|
|
let Ok(bytes) = std::fs::read(f) else { continue };
|
|
let ids: BTreeSet<String> = Xbg7Model::anchor_models_cancellable(&bytes, 0.0, &|| false)
|
|
.iter()
|
|
.filter_map(|m| ship_id_of(&m.name).map(|s| s.to_string()))
|
|
.collect();
|
|
for id in &ids {
|
|
let placed = assemble_ship(&bytes, id, true);
|
|
if placed.len() < 3 {
|
|
continue;
|
|
}
|
|
let want: HashSet<String> = placed.iter().map(|p| p.resource.clone()).collect();
|
|
let models = Xbg7Model::models_named(&bytes, &want, &|| false);
|
|
// World box per placement.
|
|
let mut boxes: Vec<(String, [f32; 3], [f32; 3])> = Vec::new();
|
|
for p in &placed {
|
|
let Some(m) = models.iter().find(|m| m.name == p.resource) else { continue };
|
|
let (mut lo, mut hi) = ([f32::MAX; 3], [f32::MIN; 3]);
|
|
for s in &m.meshes {
|
|
for q in &s.positions {
|
|
let w = p.apply(*q);
|
|
for k in 0..3 {
|
|
lo[k] = lo[k].min(w[k]);
|
|
hi[k] = hi[k].max(w[k]);
|
|
}
|
|
}
|
|
}
|
|
if lo[0] != f32::MAX {
|
|
boxes.push((p.resource.clone(), lo, hi));
|
|
}
|
|
}
|
|
if boxes.len() < 3 {
|
|
continue;
|
|
}
|
|
for i in 0..boxes.len() {
|
|
// Envelope of every OTHER part.
|
|
let (mut lo, mut hi) = ([f32::MAX; 3], [f32::MIN; 3]);
|
|
for (j, b) in boxes.iter().enumerate() {
|
|
if i == j {
|
|
continue;
|
|
}
|
|
for k in 0..3 {
|
|
lo[k] = lo[k].min(b.1[k]);
|
|
hi[k] = hi[k].max(b.2[k]);
|
|
}
|
|
}
|
|
// Per-AXIS: a bow legitimately extends the ship along its long
|
|
// axis, so protrusion only means something measured against the
|
|
// envelope's size IN THAT AXIS. The e106 slab stuck ~1 500 out in
|
|
// Y where its siblings spanned ~800.
|
|
let mut worst = 0.0f32;
|
|
let mut worst_out = 0.0f32;
|
|
for k in 0..3 {
|
|
let size_k = hi[k] - lo[k];
|
|
if size_k <= 1.0 {
|
|
continue;
|
|
}
|
|
let out_k = (lo[k] - boxes[i].1[k]).max(boxes[i].2[k] - hi[k]).max(0.0);
|
|
if out_k / size_k > worst {
|
|
worst = out_k / size_k;
|
|
worst_out = out_k;
|
|
}
|
|
}
|
|
let (out, size) = (worst_out, 1.0f32);
|
|
let _ = size;
|
|
if worst > limit {
|
|
flagged += 1;
|
|
println!(
|
|
"{:<20} {:<22} protrudes {:>7.0} beyond its siblings ({:.0}% of the ship)",
|
|
f.file_name().unwrap().to_string_lossy(),
|
|
boxes[i].0,
|
|
out,
|
|
100.0 * worst
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
println!("{flagged} parts protrude more than {:.0}% of their ship's size", 100.0 * limit);
|
|
}
|