From e0f0e4a18ef9f2b6ca34917d4436e42eeb7f1eb1 Mon Sep 17 00:00:00 2001 From: Valentin Popov Date: Sat, 18 Jul 2026 16:36:25 +0400 Subject: [PATCH] feat(terrain): inspect packed material tags --- apps/fparkan-cli/src/main.rs | 36 +++++++++++++++++++++++++++++++++--- docs/tomes/05-render.md | 17 +++++++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/apps/fparkan-cli/src/main.rs b/apps/fparkan-cli/src/main.rs index fd3f9ef..c59ca1f 100644 --- a/apps/fparkan-cli/src/main.rs +++ b/apps/fparkan-cli/src/main.rs @@ -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, +} + +#[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::>(); + 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}]}" ); } } diff --git a/docs/tomes/05-render.md b/docs/tomes/05-render.md index 45bb058..d9bae22 100644 --- a/docs/tomes/05-render.md +++ b/docs/tomes/05-render.md @@ -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 +``` + ## Проверки паритета Главные риски совпадения кадра: