feat(terrain): inspect packed material tags

This commit is contained in:
2026-07-18 16:36:25 +04:00
parent 1a8e1eaed1
commit e0f0e4a18e
2 changed files with 50 additions and 3 deletions
+33 -3
View File
@@ -26,8 +26,8 @@ use fparkan_assets::{
};
use fparkan_corpus::{discover, render_report_json, report, DiscoverOptions};
use fparkan_inspection::{
inspect_archive_file, inspect_land_msh_bounds_file, inspect_model_from_root, ArchiveInspection,
ModelInspection,
inspect_archive_file, inspect_land_msh_bounds_file, inspect_model_from_root,
load_land_msh_from_path, ArchiveInspection, ModelInspection,
};
use fparkan_path::{normalize_relative, PathPolicy};
use fparkan_prototype::build_prototype_graph_report;
@@ -125,6 +125,15 @@ struct TerrainInspectOutput {
positions: usize,
min: [f32; 3],
max: [f32; 3],
faces: usize,
slots: usize,
material_tags: Vec<TerrainMaterialTagCount>,
}
#[derive(Serialize)]
struct TerrainMaterialTagCount {
tag: u16,
faces: usize,
}
#[derive(Serialize)]
@@ -452,6 +461,18 @@ fn inspect_archive(args: &[String]) -> Result<(), String> {
fn inspect_terrain(args: &[String]) -> Result<(), String> {
let path = parse_file_path(args, "terrain inspect")?;
let bounds = inspect_land_msh_bounds_file(&path)?;
let terrain = load_land_msh_from_path(&path)?;
let mut material_tags = terrain
.faces
.iter()
.fold(std::collections::BTreeMap::new(), |mut counts, face| {
*counts.entry(face.material_tag).or_insert(0usize) += 1;
counts
})
.into_iter()
.map(|(tag, faces)| TerrainMaterialTagCount { tag, faces })
.collect::<Vec<_>>();
material_tags.sort_unstable_by_key(|entry| entry.tag);
println!(
"{}",
serialize_json(&TerrainInspectOutput {
@@ -460,6 +481,9 @@ fn inspect_terrain(args: &[String]) -> Result<(), String> {
positions: bounds.positions,
min: bounds.min,
max: bounds.max,
faces: terrain.faces.len(),
slots: terrain.slots.slots_raw.len(),
material_tags,
})?
);
Ok(())
@@ -703,12 +727,18 @@ mod tests {
positions: 3,
min: [-1.0, -2.0, -3.0],
max: [4.0, 5.0, 6.0],
faces: 2,
slots: 4,
material_tags: vec![
TerrainMaterialTagCount { tag: 0, faces: 1 },
TerrainMaterialTagCount { tag: 3, faces: 1 },
],
})
.expect("serialize terrain inspection");
assert_eq!(
json,
"{\"schema_version\":\"fparkan-terrain-inspect-v1\",\"path\":\"DATA/MAPS/AutoMAP/Land.msh\",\"positions\":3,\"min\":[-1.0,-2.0,-3.0],\"max\":[4.0,5.0,6.0]}"
"{\"schema_version\":\"fparkan-terrain-inspect-v1\",\"path\":\"DATA/MAPS/AutoMAP/Land.msh\",\"positions\":3,\"min\":[-1.0,-2.0,-3.0],\"max\":[4.0,5.0,6.0],\"faces\":2,\"slots\":4,\"material_tags\":[{\"tag\":0,\"faces\":1},{\"tag\":3,\"faces\":1}]}"
);
}
}
+17
View File
@@ -1538,6 +1538,23 @@ temporary vertex buffers или заменять render representation. UI/shell
диагностики полезно уметь сохранять world-only command list и финальный
framebuffer отдельно.
Terrain material discovery is now reproducible instead of inferred from the
mesh shape. The original AutoDemo map places two textual sidecar WEAR tables,
`Land1.wea` and `Land2.wea`, beside `Land.msh`; `Terrain.dll` contains the
corresponding `1.wea` and `2.wea` loading suffixes. The new terrain inspector
reports all packed face tags. For `DATA/MAPS/AutoMAP/Land.msh`, its 3,174 faces
use `0x0102` (592), `0x0203` (386), `0xff01` (918), `0xff02` (970), and
`0xff03` (308). The low byte is always a valid positional selector 1..3 in
`Land2.wea`; the high byte is a `Land1.wea` selector or sentinel `0xff`.
This is evidence for a two-layer terrain-material contract, but not yet for
its blend equation, so the Vulkan bridge intentionally remains texture-agnostic
until the base/overlay composition is recovered.
```powershell
cargo run -q -p fparkan-cli -- terrain inspect `
'C:\GOG Games\Parkan - Iron Strategy\DATA\MAPS\AutoMAP\Land.msh' --format json
```
## Проверки паритета
Главные риски совпадения кадра: