spring_cartographer_rs/
smf.rs

1use binrw::{BinRead, NullString};
2use std::io::{Read, Seek, SeekFrom};
3
4/// Parse a stream into the SMF structure
5/// 
6/// # Example
7/// 
8/// ```
9/// let file = std::fs::File::open("assets/Great_Divide.smf").unwrap();
10/// let mut buf_reader = std::io::BufReader::new(file); 
11/// 
12/// let smf = spring_cartographer_rs::smf::parse_smf(&mut buf_reader).unwrap();
13/// ```
14pub fn parse_smf<R: Read + Seek>(reader: &mut R) -> Result<SMF, binrw::Error> {
15    SMF::read(reader)
16}
17
18#[derive(BinRead, Debug, Clone)]
19#[br(magic = b"spring map file\0", little)]
20pub struct SMF {
21    pub header: SMFHeader,
22
23    #[br(count = header.extra_header_count)]
24    pub extra_headers: Vec<ExtraHeaders>,
25
26    #[br(
27        args { width: header.width, length: header.length },
28        seek_before = SeekFrom::Start(header.height_map_ptr as u64)
29    )]
30    pub height_map: HeightMap,
31
32    #[br(
33        args { width: header.width, length: header.length },
34        seek_before = SeekFrom::Start(header.type_map_ptr as u64)
35    )]
36    pub type_map: TypeMap,
37
38    #[br(seek_before = SeekFrom::Start(header.minimap_ptr as u64))]
39    pub mini_map: MiniMap,
40
41    #[br(
42        args { width: header.width, length: header.length },
43        seek_before = SeekFrom::Start(header.tiles_ptr as u64)
44    )]
45    pub smt_file_info: TileInfo,
46
47    #[br(
48        args { width: header.width, length: header.length },
49        seek_before = SeekFrom::Start(header.metal_map_ptr as u64)
50    )]
51    pub metal_map: MetalMap,
52
53    #[br(seek_before = SeekFrom::Start(header.feature_ptr as u64))]
54    pub features: Features,
55}
56
57#[derive(BinRead, Debug, Clone)]
58#[br()]
59pub struct SMFHeader {
60    pub version: u32,
61    pub id: u32,
62    pub width: u32,
63    pub length: u32,
64    pub square_size: u32,
65    pub texel_per_square: u32,
66    pub tile_size: u32,
67    pub min_height: f32,
68    pub max_height: f32,
69    pub height_map_ptr: u32,
70    pub type_map_ptr: u32,
71    pub tiles_ptr: u32,
72    pub minimap_ptr: u32,
73    pub metal_map_ptr: u32,
74    pub feature_ptr: u32,
75    pub extra_header_count: u32,
76}
77
78#[derive(BinRead, Debug, Clone)]
79#[br()]
80pub struct ExtraHeaders {
81    pub size_of_header: u32,
82    pub type_of_header: u32,
83
84    #[br(count = size_of_header)]
85    pub data: Vec<u8>,
86}
87
88#[derive(BinRead, Debug, Clone)]
89#[br(import { length: u32, width: u32 })]
90pub struct HeightMap(#[br(count = (width + 1) * (length + 1))] pub Vec<u16>);
91
92#[derive(BinRead, Debug, Clone)]
93#[br(import { length: u32, width: u32 })]
94pub struct TypeMap(#[br(count = (width / 2)*(length / 2))] pub Vec<u8>);
95
96#[derive(BinRead, Debug, Clone)]
97#[br()]
98pub struct MiniMap(#[br(count = 699048)] pub Vec<u8>); // raw DXT1 compressed 1024x1024 image.
99
100#[derive(BinRead, Debug, Clone)]
101#[br(import { length: u32, width: u32 })]
102pub struct TileInfo {
103    pub header: TileIndexHeader,
104
105    #[br(count = header.number_of_tile_files)]
106    pub smt_file_info: Vec<SMTFileInfos>,
107
108    #[br(args { width: width, length: length })]
109    pub tile_index: TileIndex,
110}
111
112#[derive(BinRead, Debug, Clone)]
113#[br()]
114pub struct TileIndexHeader {
115    pub number_of_tile_files: u32,
116    pub total_number_of_tiles_in_all_files: u32,
117}
118
119#[derive(BinRead, Debug, Clone)]
120pub struct SMTFileInfos {
121    pub number_of_tiles_in_this_file: u32,
122    pub smt_filename: NullString,
123}
124
125#[derive(BinRead, Debug, Clone)]
126#[br(import { length: u32, width: u32 })]
127pub struct TileIndex(#[br(count = (width / 4) * (length / 4))] pub Vec<u32>);
128
129#[derive(BinRead, Debug, Clone)]
130#[br(import { length: u32, width: u32 })]
131pub struct MetalMap(#[br(count = (width / 2)*(length / 2))] pub Vec<u8>);
132
133#[derive(BinRead, Debug, Clone)]
134#[br()]
135pub struct Features {
136    pub header: FeaturesHeader,
137
138    #[br(count = header.num_feature_types)]
139    pub features: Vec<Feature>,
140}
141
142#[derive(BinRead, Debug, Clone)]
143#[br()]
144pub struct FeaturesHeader {
145    pub num_features: i32,
146    pub num_feature_types: i32,
147
148    #[br(count = num_features)]
149    pub feature_names: Vec<NullString>,
150}
151
152#[derive(BinRead, Debug, Clone)]
153#[br()]
154pub struct Feature {
155    pub feature_type: u32,
156    pub x: f32,
157    pub y: f32,
158    pub z: f32,
159    pub rotation: f32,
160    pub relative_size: f32,
161}
162
163#[cfg(test)]
164mod test {
165    use super::*;
166
167    #[test]
168    fn test() {
169        let file = std::fs::File::open("assets/Great_Divide.smf").unwrap();
170        let mut buf_reader = std::io::BufReader::new(file);
171
172        let smf = parse_smf(&mut buf_reader).unwrap();
173
174        dbg!(smf.header);
175
176        dbg!(smf.smt_file_info.header);
177        dbg!(smf.smt_file_info.smt_file_info);
178        dbg!(smf.features);
179    }
180}