re: CORRECTION -- the static assembler is not at fault, the pre-fix decoder was
Last iteration reported e303_wep_01 as inflated 30-110x by assemble_ship. Wrong: the composite nodes carry scale 1.0 and orthonormal matrices, and under the current decoder the turret places as 49x23x42 at +/-179. The 1600x2100x4800 box only appears with XBG7_COVER_SLACK=4 -- the exact-coverage fix had already repaired the turret too. The error came from comparing a deliberately pre-fix render against post-fix measurements. The containment screen's blindness therefore has a mundane cause: one mis-decode inflated the envelope and hid another. Kept as a forward-looking invariant with that caveat. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
35
crates/sylpheed-formats/examples/filter_consistency.rs
Normal file
35
crates/sylpheed-formats/examples/filter_consistency.rs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
//! Does a FILTERED decode agree with the full one?
|
||||||
|
//!
|
||||||
|
//! Distinct anchor assignment resolves collisions against the set of resources
|
||||||
|
//! being decoded — so `models_named` (a filtered subset, used by the ship
|
||||||
|
//! assembler and the viewer) can reach a different answer from a whole-container
|
||||||
|
//! decode. This measures that directly.
|
||||||
|
//! Usage: filter_consistency <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 full = Xbg7Model::anchor_models_cancellable(&bytes, 0.0, &|| false);
|
||||||
|
let names: Vec<String> = if a.len() > 2 {
|
||||||
|
a[2..].to_vec()
|
||||||
|
} else {
|
||||||
|
full.iter().map(|m| m.name.clone()).collect()
|
||||||
|
};
|
||||||
|
let mut differ = 0usize;
|
||||||
|
for n in &names {
|
||||||
|
let want: HashSet<String> = std::iter::once(n.clone()).collect();
|
||||||
|
let one = Xbg7Model::models_named(&bytes, &want, &|| false);
|
||||||
|
let (Some(f), Some(s)) = (full.iter().find(|m| &m.name == n), one.first()) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let off = |m: &Xbg7Model| m.meshes.first().and_then(|s| s.vbuf_offset).unwrap_or(0);
|
||||||
|
if off(f) != off(s) {
|
||||||
|
differ += 1;
|
||||||
|
if differ <= 10 {
|
||||||
|
println!("{n}: full decode at 0x{:x}, filtered at 0x{:x}", off(f), off(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("{differ} of {} resources decode differently when filtered", names.len());
|
||||||
|
}
|
||||||
20
crates/sylpheed-formats/examples/node_scale.rs
Normal file
20
crates/sylpheed-formats/examples/node_scale.rs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
//! Dump a composite's scene nodes with their scale — the transform the static
|
||||||
|
//! assembler copies verbatim into a placement.
|
||||||
|
//! Usage: node_scale <container.xpr> <composite name>
|
||||||
|
use sylpheed_formats::mesh::scene_world_nodes;
|
||||||
|
fn main() {
|
||||||
|
let a: Vec<String> = std::env::args().collect();
|
||||||
|
let bytes = std::fs::read(&a[1]).expect("container");
|
||||||
|
for n in scene_world_nodes(&bytes, &a[2]) {
|
||||||
|
// Row norms of `m`: a rotation has all three at 1.0; anything else is a
|
||||||
|
// scale baked into the matrix, which `s` does not show.
|
||||||
|
let norm = |r: [f32; 3]| (r[0] * r[0] + r[1] * r[1] + r[2] * r[2]).sqrt();
|
||||||
|
println!(
|
||||||
|
"{:<26} s[{:7.3}{:7.3}{:7.3}] |m rows|[{:7.3}{:7.3}{:7.3}] t[{:9.1}{:9.1}{:9.1}]",
|
||||||
|
n.resource,
|
||||||
|
n.s[0], n.s[1], n.s[2],
|
||||||
|
norm(n.m[0]), norm(n.m[1]), norm(n.m[2]),
|
||||||
|
n.t[0], n.t[1], n.t[2]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1097,33 +1097,30 @@ that carry it) and `t901_e01_D` is 58×59×3013 (a mast). And `f101_bdy_01` flag
|
|||||||
at 6× while being **capture-verified exact** in the truth table — a useful
|
at 6× while being **capture-verified exact** in the truth table — a useful
|
||||||
reminder that a bulky hull is not a bug.
|
reminder that a bulky hull is not a bug.
|
||||||
|
|
||||||
### The containment screen fails too — because the static placement is worse
|
### The containment screen, and a correction: the assembler is NOT at fault
|
||||||
|
|
||||||
`examples/envelope_screen.rs` is the metric the eye actually used: assemble a
|
`examples/envelope_screen.rs` is the metric the eye actually used: assemble a
|
||||||
ship, and for each part measure how far its world box protrudes past the box of
|
ship, and for each part measure how far its world box protrudes past the box of
|
||||||
all the *other* parts, **per axis** (a bow legitimately extends the long axis, so
|
all the *other* parts, **per axis** (a bow legitimately extends the long axis, so
|
||||||
protrusion only means something against that axis' own envelope).
|
protrusion only counts against that axis' own envelope).
|
||||||
|
|
||||||
It does not flag `e106_bdy_03` either, before or after the coverage fix. Dumping
|
It does not flag `e106_bdy_03` under the **pre-fix** decoder, and the reason is
|
||||||
the static assembly shows why, and the reason is a bigger finding than the screen:
|
now established. Dumping the pre-fix static assembly shows the shared turret
|
||||||
|
`e303_wep_01` occupying **1600×2100×4800** around a ~400×400×2000 hull — an
|
||||||
|
envelope nothing can protrude past.
|
||||||
|
|
||||||
```
|
⚠️ **This was first written up here as a static-assembler defect. That was
|
||||||
e106_bdy_03 X[ -300, 300] Y[ 0, 1600] Z[ 188, 1186]
|
wrong.** The composite's nodes are clean — `rou_e303_wep_01_root` carries scale
|
||||||
e303_wep_01 X[-1179, 421] Y[ -996, 1104] Z[-2368, 2432] ← shared turret
|
`1.0` and an orthonormal matrix at `t[±179, 54, 32]` — and under the **current**
|
||||||
e106_bdy_04 X[ -215, 215] Y[ -165, 234] Z[ -991, 389]
|
decoder the same assembly places the turret as a tidy `49×23×42` box at ±179.
|
||||||
```
|
The inflation only appears with `XBG7_COVER_SLACK=4`, i.e. the pre-fix decode:
|
||||||
|
**the exact-coverage fix repaired the turret as well as `e106_bdy_03`.** The
|
||||||
|
error came from comparing a deliberately pre-fix render against post-fix
|
||||||
|
measurements of the same resource.
|
||||||
|
|
||||||
The **turret swallows the ship**: `e303_wep_01`'s world box is 1600×2100×4800
|
So the screen's blindness had a mundane cause — one mis-decode hid another by
|
||||||
around a hull of ~400×400×2000, so nothing can protrude past the envelope. Its
|
inflating the envelope — and it is worth keeping as a forward-looking invariant,
|
||||||
*decode* is not at fault — the resource comes out 49×23×42 in `Stage_S01` through
|
with that caveat: it can only see a protruding part when nothing else is inflated.
|
||||||
`Stage_S06` alike, consistent everywhere — so this is a **static-assembler**
|
|
||||||
defect: the placement blows a 49-unit turret up by 30–110× per axis (and
|
|
||||||
non-uniformly, so it is not a simple scale factor).
|
|
||||||
|
|
||||||
Two conclusions. The screen is only meaningful once placement is trustworthy, and
|
|
||||||
**the static assembler has a worse defect than the decoder did** — one that the
|
|
||||||
capture-baked path for `e106` hides, because the baked table places the ship
|
|
||||||
correctly and is what the viewer prefers.
|
|
||||||
|
|
||||||
### The anchor work has plateaued at 98.7 % — state and what is left
|
### The anchor work has plateaued at 98.7 % — state and what is left
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user