glacier_texture/
mipblock.rs1use 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}