Skip to main content

glacier_texture/
mipblock.rs

1use crate::atlas::AtlasData;
2use crate::pack::TexturePackerError;
3use crate::texture_map::{
4    TextureMapError, TextureMapHeaderImpl, TextureMapHeaderV1, TextureMapHeaderV2,
5};
6use crate::GlacierGame;
7use binrw::{BinRead, BinReaderExt};
8use serde::{Deserialize, Serialize};
9use std::fs;
10use std::io::{BufWriter, Cursor, Read, Seek, Write};
11use std::path::Path;
12#[derive(Serialize, Deserialize, Clone, Debug)]
13pub struct MipblockData {
14    pub video_memory_requirement: usize,
15    pub header: Vec<u8>,
16    pub data: Vec<u8>,
17}
18
19impl From<MipblockData> for Vec<u8> {
20    fn from(value: MipblockData) -> Self {
21        value.data
22    }
23}
24
25impl MipblockData {
26    pub fn from_file<P: AsRef<Path>>(
27        path: P,
28        glacier_game: GlacierGame,
29    ) -> Result<Self, TextureMapError> {
30        let data = fs::read(path).map_err(TextureMapError::IoError)?;
31        Self::new_inner(&data, glacier_game)
32    }
33
34    pub fn from_memory(data: &[u8], glacier_game: GlacierGame) -> Result<Self, TextureMapError> {
35        Self::new_inner(data, glacier_game)
36    }
37
38    fn new_inner(data: &[u8], version: GlacierGame) -> Result<Self, TextureMapError> {
39        let mut stream = Cursor::new(data);
40        let mut header = vec![];
41        let mut memory_reqs = 0;
42
43        let read_size = match version {
44            GlacierGame::HM2016 => {
45                stream.set_position(8);
46                let data_size = stream.read_le::<u32>()?;
47                stream.set_position(0);
48
49                let texd_header = TextureMapHeaderV1::read_le_args(&mut stream, ())?;
50                let mut atlas: Option<AtlasData> = None;
51                if texd_header.has_atlas {
52                    atlas = Some(AtlasData::read_le(&mut stream)?);
53                }
54
55                header = vec![0u8; stream.position() as usize];
56                stream.set_position(0);
57                stream
58                    .read_exact(&mut header)
59                    .map_err(TextureMapError::IoError)?;
60
61                memory_reqs = (texd_header.mip_sizes.first().copied().unwrap_or(0x0)
62                    + texd_header.mip_sizes.get(1).copied().unwrap_or(0x0))
63                    as usize;
64
65                data_size as usize
66                    - (TextureMapHeaderV1::size() - 8)
67                    - atlas.map(|a| a.size()).unwrap_or(0)
68            }
69            GlacierGame::HM2 => {
70                stream.set_position(4);
71                let data_size = stream.read_le::<u32>()?;
72                stream.set_position(0);
73
74                let texd_header = TextureMapHeaderV2::read_le_args(&mut stream, ())?;
75                let mut atlas: Option<AtlasData> = None;
76                if texd_header.has_atlas {
77                    atlas = Some(AtlasData::read_le(&mut stream)?);
78                }
79
80                header = vec![0u8; stream.position() as usize];
81                stream.set_position(0);
82                stream
83                    .read_exact(&mut header)
84                    .map_err(TextureMapError::IoError)?;
85
86                memory_reqs = (texd_header.mip_sizes.first().copied().unwrap_or(0x0)
87                    + texd_header.mip_sizes.get(1).copied().unwrap_or(0x0))
88                    as usize;
89
90                data_size as usize
91                    - (TextureMapHeaderV2::size())
92                    - atlas.map(|a| a.size()).unwrap_or(0)
93            }
94            GlacierGame::HM3 | GlacierGame::KNT => data.len(),
95        };
96
97        let mut buffer = vec![0u8; read_size];
98        stream.read_exact(&mut buffer)?;
99        Ok(Self {
100            video_memory_requirement: memory_reqs,
101            header,
102            data: buffer,
103        })
104    }
105
106    pub fn video_memory_requirement(&self) -> usize {
107        self.video_memory_requirement
108    }
109
110    pub fn pack_to_vec(&self, glacier_game: GlacierGame) -> Result<Vec<u8>, TexturePackerError> {
111        let mut writer = Cursor::new(Vec::new());
112        self.pack_internal(&mut writer, glacier_game)?;
113        Ok(writer.into_inner())
114    }
115
116    pub fn pack_to_file<P: AsRef<Path>>(
117        &self,
118        path: P,
119        glacier_game: GlacierGame,
120    ) -> Result<(), TexturePackerError> {
121        let file = fs::File::create(path).map_err(TexturePackerError::IoError)?;
122        let mut writer = BufWriter::new(file);
123        self.pack_internal(&mut writer, glacier_game)?;
124        Ok(())
125    }
126
127    fn pack_internal<W: Write + Seek>(
128        &self,
129        writer: &mut W,
130        glacier_game: GlacierGame,
131    ) -> Result<(), TexturePackerError> {
132        writer
133            .write_all(
134                match glacier_game {
135                    GlacierGame::HM2016 | GlacierGame::HM2 => self
136                        .header
137                        .iter()
138                        .chain(&self.data)
139                        .cloned()
140                        .collect::<Vec<u8>>(),
141                    GlacierGame::HM3 | GlacierGame::KNT => self.data.clone(),
142                }
143                .as_slice(),
144            )
145            .map_err(|e| {
146                TexturePackerError::PackingError(format!("Unable to pack mipblock1: {e}"))
147            })?;
148        Ok(())
149    }
150}