1use crate::crc::type_id;
11use crate::crs::{self, Reader, Writer};
12use crate::error::{format_err, Result};
13
14#[derive(Debug, Clone)]
16pub struct Decal {
17 pub material: Option<String>,
19 pub ints: [i32; 5],
21 pub byte: u8,
23 pub int6: i32,
25 pub flag7: bool,
27 pub floats: [f32; 5],
29 pub flag13: bool,
31 pub flag_v2: bool,
33 pub flag_bytes: [u8; 3],
35 pub vertices: Vec<[u8; 20]>,
37 pub indices: Vec<u16>,
39}
40
41#[derive(Debug, Clone)]
43pub struct MapComponent {
44 pub version: u32,
46 pub dims: [i32; 6],
49 pub heights: Vec<i16>,
51 pub terrain_material: Option<String>,
53 pub surface: Vec<u8>,
57 pub water_vertices: Vec<[u8; 16]>,
59 pub water_indices: Vec<u16>,
61 pub river_material: Option<String>,
63 pub lake_material: Option<String>,
65 pub river_ranges: Vec<[i32; 4]>,
67 pub lake_ranges: Vec<[i32; 4]>,
69 pub river_paths: Vec<Vec<[f32; 2]>>,
71 pub decals: Vec<Decal>,
73 pub extra_decals: Vec<Decal>,
75 pub ints: Vec<i32>,
77 pub decal_materials: Vec<Option<String>>,
79}
80
81#[derive(Debug, Clone, Copy)]
83pub struct Placement {
84 pub floats: [f32; 7],
86 pub mesh: i16,
88 pub material: i16,
90}
91
92#[derive(Debug, Clone, Copy)]
94pub struct SceneCamera {
95 pub rotation: [f32; 4],
97 pub position: [f32; 3],
99 pub target: [f32; 3],
101 pub floats: [f32; 3],
103}
104
105#[derive(Debug, Clone, Copy)]
107pub struct ParticlePlacement {
108 pub position: [f32; 3],
110 pub yaw: f32,
112 pub system: i32,
114}
115
116#[derive(Debug, Clone)]
118pub struct MenuScene {
119 pub name: String,
121 pub map: MapComponent,
123 pub camera: SceneCamera,
125 pub placements: Vec<Placement>,
127 pub meshes: Vec<Option<String>>,
129 pub sky: Option<String>,
131 pub vector: [f32; 4],
133 pub colors: [u32; 3],
135 pub floats: [f32; 5],
137 pub effect: Option<String>,
139 pub effect_value: f32,
141 pub particles: Vec<ParticlePlacement>,
143 pub particle_systems: Vec<Option<String>>,
145}
146
147fn f32s<const N: usize>(r: &mut Reader) -> Result<[f32; N]> {
148 let mut out = [0.0; N];
149 for v in &mut out {
150 *v = r.f32()?;
151 }
152 Ok(out)
153}
154
155fn i16(r: &mut Reader) -> Result<i16> {
156 Ok(i16::from_le_bytes(r.bytes(2)?.try_into().unwrap()))
157}
158
159fn u16s(r: &mut Reader) -> Result<Vec<u16>> {
160 let n = r.count()?;
161 Ok(r.bytes(n * 2)?
162 .chunks_exact(2)
163 .map(|c| u16::from_le_bytes([c[0], c[1]]))
164 .collect())
165}
166
167fn refs(r: &mut Reader) -> Result<Vec<Option<String>>> {
168 (0..r.count()?).map(|_| r.external_ref()).collect()
169}
170
171fn ranges(r: &mut Reader) -> Result<Vec<[i32; 4]>> {
172 (0..r.count()?)
173 .map(|_| Ok([r.i32()?, r.i32()?, r.i32()?, r.i32()?]))
174 .collect()
175}
176
177fn decals(r: &mut Reader, version: u32) -> Result<Vec<Decal>> {
179 (0..r.count()?)
180 .map(|_| {
181 let material = r.external_ref()?;
182 let ints = [r.i32()?, r.i32()?, r.i32()?, r.i32()?, r.i32()?];
183 let byte = r.u8()?;
184 let int6 = r.i32()?;
185 let mut flag_bytes = [0; 3];
186 flag_bytes[0] = r.u8()?;
187 let floats = f32s::<5>(r)?;
188 flag_bytes[1] = r.u8()?;
189 if version > 1 {
190 flag_bytes[2] = r.u8()?;
191 }
192 let [flag7, flag13, flag_v2] = flag_bytes.map(|b| b != 0);
193 let (vertices, indices) = if version > 0 {
194 let n = r.count()?;
195 let vertices = (0..n)
196 .map(|_| Ok(r.bytes(20)?.try_into().unwrap()))
197 .collect::<Result<_>>()?;
198 (vertices, u16s(r)?)
199 } else {
200 (Vec::new(), Vec::new())
201 };
202 Ok(Decal {
203 material,
204 ints,
205 byte,
206 int6,
207 flag7,
208 floats,
209 flag13,
210 flag_v2,
211 flag_bytes,
212 vertices,
213 indices,
214 })
215 })
216 .collect()
217}
218
219pub fn read_map_component(r: &mut Reader) -> Result<MapComponent> {
223 r.block(|r, version| {
224 let mut dims = [0; 6];
225 for d in &mut dims {
226 *d = r.i32()?;
227 }
228 let n = r.count()?;
229 let heights = r
230 .bytes(n * 2)?
231 .chunks_exact(2)
232 .map(|c| i16::from_le_bytes([c[0], c[1]]))
233 .collect();
234 let terrain_material = r.external_ref()?;
235 let size = dims[0].max(0) as usize;
236 let surface = r.bytes(size * size * 4)?.to_vec();
237 let (water_vertices, water_indices) = if version < 3 {
238 r.bool()?;
239 let vb = r.count()?;
240 let vertices = r
241 .bytes(vb)?
242 .chunks_exact(16)
243 .map(|c| c.try_into().unwrap())
244 .collect();
245 r.bool()?;
246 let ib = r.count()?;
247 let indices = r
248 .bytes(ib)?
249 .chunks_exact(2)
250 .map(|c| u16::from_le_bytes([c[0], c[1]]))
251 .collect();
252 (vertices, indices)
253 } else {
254 let n = r.count()?;
255 let vertices = (0..n)
256 .map(|_| Ok(r.bytes(16)?.try_into().unwrap()))
257 .collect::<Result<_>>()?;
258 (vertices, u16s(r)?)
259 };
260 let river_material = r.external_ref()?;
261 let lake_material = r.external_ref()?;
262 let river_ranges = ranges(r)?;
263 let lake_ranges = ranges(r)?;
264 let river_paths = (0..r.count()?)
265 .map(|_| (0..r.count()?).map(|_| f32s::<2>(r)).collect())
266 .collect::<Result<_>>()?;
267 let decals = decals(r, version)?;
268 let ints = if version > 3 {
269 (0..r.count()?).map(|_| r.i32()).collect::<Result<_>>()?
270 } else {
271 Vec::new()
272 };
273 let decal_materials = if version > 5 { refs(r)? } else { Vec::new() };
274 Ok(MapComponent {
275 version,
276 dims,
277 heights,
278 terrain_material,
279 surface,
280 water_vertices,
281 water_indices,
282 river_material,
283 lake_material,
284 river_ranges,
285 lake_ranges,
286 river_paths,
287 decals,
288 extra_decals: Vec::new(),
289 ints,
290 decal_materials,
291 })
292 })
293}
294
295fn write_decals(w: &mut Writer, decals: &[Decal], version: u32) -> Result<()> {
296 w.count(decals.len());
297 for d in decals {
298 let flag = |k: usize, v: bool| {
300 if (d.flag_bytes[k] != 0) == v {
301 d.flag_bytes[k]
302 } else {
303 v as u8
304 }
305 };
306 w.external_ref(d.material.as_deref())?;
307 d.ints.iter().for_each(|&v| w.i32(v));
308 w.u8(d.byte);
309 w.i32(d.int6);
310 w.u8(flag(0, d.flag7));
311 d.floats.iter().for_each(|&v| w.f32(v));
312 w.u8(flag(1, d.flag13));
313 if version > 1 {
314 w.u8(flag(2, d.flag_v2));
315 }
316 if version > 0 {
317 w.count(d.vertices.len());
318 d.vertices.iter().for_each(|v| w.bytes(v));
319 w.count(d.indices.len());
320 d.indices.iter().for_each(|&i| w.u16(i));
321 }
322 }
323 Ok(())
324}
325
326pub fn write_map_component(w: &mut Writer, map: &MapComponent) -> Result<()> {
328 let version = map.version;
329 if version < 3 {
330 return format_err("writing a MapComponent below version 3 is not supported");
331 }
332 w.block(version, |w| {
333 map.dims.iter().for_each(|&d| w.i32(d));
334 w.count(map.heights.len());
335 map.heights.iter().for_each(|&h| w.i16(h));
336 w.external_ref(map.terrain_material.as_deref())?;
337 w.bytes(&map.surface);
338 w.count(map.water_vertices.len());
339 map.water_vertices.iter().for_each(|v| w.bytes(v));
340 w.count(map.water_indices.len());
341 map.water_indices.iter().for_each(|&i| w.u16(i));
342 w.external_ref(map.river_material.as_deref())?;
343 w.external_ref(map.lake_material.as_deref())?;
344 for ranges in [&map.river_ranges, &map.lake_ranges] {
345 w.count(ranges.len());
346 ranges.iter().flatten().for_each(|&v| w.i32(v));
347 }
348 w.count(map.river_paths.len());
349 for path in &map.river_paths {
350 w.count(path.len());
351 path.iter().flatten().for_each(|&v| w.f32(v));
352 }
353 write_decals(w, &map.decals, version)?;
354 if version > 3 {
355 w.count(map.ints.len());
356 map.ints.iter().for_each(|&v| w.i32(v));
357 }
358 if version > 5 {
359 w.count(map.decal_materials.len());
360 for m in &map.decal_materials {
361 w.external_ref(m.as_deref())?;
362 }
363 }
364 Ok(())
365 })
366}
367
368pub fn write_camera(w: &mut Writer, c: &SceneCamera) -> Result<()> {
370 w.block(0, |w| {
371 c.rotation
372 .iter()
373 .chain(&c.position)
374 .chain(&c.target)
375 .chain(&c.floats)
376 .for_each(|&v| w.f32(v));
377 Ok(())
378 })
379}
380
381fn read_map_decals(r: &mut Reader, map: &mut MapComponent) -> Result<()> {
383 r.block(|r, version| {
384 map.extra_decals = decals(r, version)?;
385 map.decals = decals(r, version)?;
386 if version > 3 {
387 map.decal_materials = refs(r)?;
388 }
389 Ok(())
390 })
391}
392
393pub fn read_camera(r: &mut Reader) -> Result<SceneCamera> {
397 r.block(|r, _| {
398 Ok(SceneCamera {
399 rotation: f32s::<4>(r)?,
400 position: f32s::<3>(r)?,
401 target: f32s::<3>(r)?,
402 floats: f32s::<3>(r)?,
403 })
404 })
405}
406
407pub fn menu_scene(data: &[u8]) -> Result<MenuScene> {
409 let (_, value) = crs::parse(data, |r: &mut Reader, h| {
410 if h.type_id != type_id("MenuScene") {
411 return format_err(format!("expected MenuScene, found {:#010x}", h.type_id));
412 }
413 r.block(|r, version| {
414 let name = r.string()?;
415 let mut map = read_map_component(r)?;
416 if version > 0 {
417 read_map_decals(r, &mut map)?;
418 }
419 let camera = read_camera(r)?;
420 let placements = (0..r.count()?)
421 .map(|_| {
422 Ok(Placement {
423 floats: f32s::<7>(r)?,
424 mesh: i16(r)?,
425 material: i16(r)?,
426 })
427 })
428 .collect::<Result<_>>()?;
429 let meshes = refs(r)?;
430 let sky = r.external_ref()?;
431 let vector = f32s::<4>(r)?;
432 let colors = [r.u32()?, r.u32()?, r.u32()?];
433 let floats = f32s::<5>(r)?;
434 let (mut effect, mut effect_value, mut particles, mut particle_systems) =
435 (None, 0.0, Vec::new(), Vec::new());
436 if version > 1 {
437 effect = r.external_ref()?;
438 effect_value = r.f32()?;
439 particles = (0..r.count()?)
440 .map(|_| {
441 Ok(ParticlePlacement {
442 position: f32s::<3>(r)?,
443 yaw: r.f32()?,
444 system: r.i32()?,
445 })
446 })
447 .collect::<Result<_>>()?;
448 particle_systems = refs(r)?;
449 }
450 Ok(MenuScene {
451 name,
452 map,
453 camera,
454 placements,
455 meshes,
456 sky,
457 vector,
458 colors,
459 floats,
460 effect,
461 effect_value,
462 particles,
463 particle_systems,
464 })
465 })
466 })?;
467 Ok(value)
468}