1use crate::common::Palette;
2use crate::error;
3use crate::lump::{Image, MipTexture, MipTextureHead};
4use crate::BinParseResult;
5use std::boxed::Box;
6use std::io::{Read, Seek, SeekFrom};
7use std::mem::{size_of, transmute, MaybeUninit};
8use std::string::ToString;
9
10pub fn parse_mip_texture(
12 cursor: &mut (impl Seek + Read),
13) -> BinParseResult<MipTexture> {
14 let mut head_bytes = [0u8; size_of::<MipTextureHead>()];
15 let lump_start = cursor.stream_position()?;
16
17 cursor.read_exact(&mut head_bytes)?;
18
19 let head: MipTextureHead = head_bytes.try_into()?;
20 let mip0_length = u64::from(head.width) * u64::from(head.height);
21 const UNINIT_IMAGE: MaybeUninit<Image> = MaybeUninit::uninit();
22 let mut mips = [UNINIT_IMAGE; 4];
23
24 for i in 0u32..4u32 {
25 let pix_start: u64 = head.offsets[i as usize].into();
26 let length: usize = (mip0_length >> (i * 2)).try_into().unwrap();
27
28 cursor.seek(SeekFrom::Start(
29 lump_start
30 .checked_add(pix_start)
31 .ok_or(error::BinParse::Parse("Bad offset".to_string()))?,
32 ))?;
33
34 let mut pixels = vec![0u8; length].into_boxed_slice();
35 cursor.read_exact(&mut pixels)?;
36
37 mips[i as usize].write(Image::from_pixels(head.width >> i, pixels));
38 }
39
40 Ok(MipTexture::from_parts(head.name, unsafe {
41 mips.map(|elem| elem.assume_init())
42 }))
43}
44
45pub fn parse_palette(reader: &mut impl Read) -> BinParseResult<Box<Palette>> {
47 let mut bytes = [0u8; size_of::<Palette>()];
48 reader.read_exact(&mut bytes[..])?;
49 Ok(Box::from(unsafe {
50 transmute::<[u8; size_of::<Palette>()], Palette>(bytes)
51 }))
52}
53
54pub fn parse_image(reader: &mut impl Read) -> BinParseResult<Image> {
56 let mut u32_buf = [0u8; size_of::<u32>()];
57 reader.read_exact(&mut u32_buf[..])?;
58 let width = u32::from_le_bytes(u32_buf);
59 reader.read_exact(&mut u32_buf[..])?;
60 let height = u32::from_le_bytes(u32_buf);
61
62 let pixel_ct = width
63 .checked_mul(height)
64 .ok_or(error::BinParse::Parse("Image too large".to_string()))?;
65
66 let mut pixels = vec![0u8; pixel_ct as usize].into_boxed_slice();
67 reader.read_exact(&mut pixels)?;
68
69 Ok(Image::from_pixels(width, pixels))
70}
71
72pub fn read_raw(
74 reader: &mut impl Read,
75 length: usize,
76) -> BinParseResult<Box<[u8]>> {
77 let mut bytes = vec![0u8; length].into_boxed_slice();
78 reader.read_exact(&mut bytes)?;
79 Ok(bytes)
80}