Skip to main content

glacier_texture/
rpkg.rs

1use crate::box_reflection::BoxReflectionCache;
2use crate::mipblock::MipblockData;
3use crate::pack::TexturePackerError;
4use crate::texture_map::TextureMap;
5use crate::GlacierGame;
6use binrw::{BinRead, BinWrite};
7use rpkg_rs::{GlacierResource, GlacierResourceError};
8use std::io::Cursor;
9
10impl From<rpkg_rs::WoaVersion> for GlacierGame {
11    fn from(value: rpkg_rs::WoaVersion) -> Self {
12        match value {
13            rpkg_rs::WoaVersion::HM2016 => GlacierGame::HM2016,
14            rpkg_rs::WoaVersion::HM2 => GlacierGame::HM2,
15            rpkg_rs::WoaVersion::HM3 => GlacierGame::HM3,
16        }
17    }
18}
19
20impl From<GlacierGame> for rpkg_rs::WoaVersion {
21    fn from(value: GlacierGame) -> Self {
22        match value {
23            GlacierGame::HM2016 => rpkg_rs::WoaVersion::HM2016,
24            GlacierGame::HM2 => rpkg_rs::WoaVersion::HM2,
25            GlacierGame::HM3 => rpkg_rs::WoaVersion::HM3,
26            GlacierGame::KNT => {
27                todo!()
28            }
29        }
30    }
31}
32
33impl GlacierResource for TextureMap {
34    type Output = TextureMap;
35
36    fn process_data<R: AsRef<[u8]>>(
37        glacier_game: rpkg_rs::WoaVersion,
38        data: R,
39    ) -> Result<Self::Output, GlacierResourceError> {
40        let mut stream = Cursor::new(data);
41        TextureMap::read_le_args(&mut stream, (GlacierGame::from(glacier_game),))
42            .map_err(|e| GlacierResourceError::ReadError(e.to_string()))
43    }
44
45    fn serialize(&self, _: rpkg_rs::WoaVersion) -> Result<Vec<u8>, GlacierResourceError> {
46        //TODO: woa version gets ignored currently. Getting the packer to accept TextureMap would allow for easy porting.
47        let mut writer = Cursor::new(Vec::new());
48        self.write_le_args(&mut writer, ())
49            .map_err(TexturePackerError::SerializationError)
50            .map_err(|e| GlacierResourceError::ReadError(e.to_string()))?; //TODO: change this
51        Ok(writer.into_inner())
52    }
53
54    fn resource_type() -> [u8; 4] {
55        *b"TEXT"
56    }
57
58    fn video_memory_requirement(&self) -> u64 {
59        self.video_memory_requirement() as u64
60    }
61
62    fn system_memory_requirement(&self) -> u64 {
63        0xFFFFFFFF
64    }
65
66    fn should_scramble(&self) -> bool {
67        true
68    }
69
70    fn should_compress(&self) -> bool {
71        match self.version() {
72            GlacierGame::HM2016 => true,
73            GlacierGame::HM2 | GlacierGame::HM3 | GlacierGame::KNT => false,
74        }
75    }
76}
77
78impl GlacierResource for MipblockData {
79    type Output = MipblockData;
80
81    fn process_data<R: AsRef<[u8]>>(
82        woa_version: rpkg_rs::WoaVersion,
83        data: R,
84    ) -> Result<Self::Output, GlacierResourceError> {
85        let mipblock = MipblockData::from_memory(data.as_ref(), woa_version.into())
86            .map_err(|e| GlacierResourceError::ReadError(e.to_string()))?;
87        Ok(mipblock)
88    }
89
90    fn serialize(&self, woa_version: rpkg_rs::WoaVersion) -> Result<Vec<u8>, GlacierResourceError> {
91        if self.header.is_empty()
92            && (woa_version == rpkg_rs::WoaVersion::HM2016
93                || woa_version == rpkg_rs::WoaVersion::HM2)
94        {
95            return Err(GlacierResourceError::ReadError(format!(
96                "Cannot serialize to {woa_version:?} without header data :("
97            )));
98        }
99        self.pack_to_vec(woa_version.into())
100            .map_err(|e| GlacierResourceError::WriteError(format!("Texd packing error: {e}")))
101    }
102
103    fn resource_type() -> [u8; 4] {
104        *b"TEXD"
105    }
106
107    fn video_memory_requirement(&self) -> u64 {
108        self.video_memory_requirement() as u64
109    }
110
111    fn system_memory_requirement(&self) -> u64 {
112        0xFFFFFFFF
113    }
114
115    fn should_scramble(&self) -> bool {
116        false
117    }
118
119    fn should_compress(&self) -> bool {
120        false
121    }
122}
123
124pub fn full_texture(
125    manager: &rpkg_rs::resource::partition_manager::PartitionManager,
126    woa_version: rpkg_rs::WoaVersion,
127    rrid: rpkg_rs::resource::runtime_resource_id::RuntimeResourceID,
128) -> Result<TextureMap, GlacierResourceError> {
129    let res_info = manager
130        .resource_info_from(&"chunk0".parse().unwrap(), &rrid)
131        .map_err(|e| GlacierResourceError::ReadError(e.to_string()))?;
132    let data = manager
133        .read_resource_from("chunk0".parse().unwrap(), rrid)
134        .map_err(|e| GlacierResourceError::ReadError(e.to_string()))?;
135
136    let mut stream = Cursor::new(data);
137    let mut texture_map = TextureMap::read_le_args(&mut stream, (GlacierGame::from(woa_version),))
138        .map_err(|e| GlacierResourceError::ReadError(e.to_string()))?;
139
140    if let Some((rrid, _)) = res_info.references().first() {
141        let texd_data = manager
142            .read_resource_from("chunk0".parse().unwrap(), *rrid)
143            .map_err(|e| {
144                GlacierResourceError::ReadError(format!("Tried to load broken depend: {e}"))
145            })?;
146        let mipblock = MipblockData::from_memory(texd_data.as_slice(), woa_version.into())
147            .map_err(|e| GlacierResourceError::ReadError(format!("Failed to read texd: {e}")))?;
148        texture_map.set_mipblock1(mipblock);
149    }
150    Ok(texture_map)
151}
152
153impl GlacierResource for BoxReflectionCache {
154    type Output = BoxReflectionCache;
155
156    fn process_data<R: AsRef<[u8]>>(
157        _: rpkg_rs::WoaVersion,
158        data: R,
159    ) -> Result<Self::Output, GlacierResourceError> {
160        BoxReflectionCache::from_memory(data.as_ref())
161            .map_err(|e| GlacierResourceError::ReadError(e.to_string()))
162    }
163
164    fn serialize(&self, _: rpkg_rs::WoaVersion) -> Result<Vec<u8>, GlacierResourceError> {
165        self.pack_to_vec()
166            .map_err(|e| GlacierResourceError::WriteError(format!("Boxc packing error: {e}")))
167    }
168
169    fn resource_type() -> [u8; 4] {
170        *b"BOXC"
171    }
172
173    fn video_memory_requirement(&self) -> u64 {
174        self.iter().map(|e| e.buffer_size() as u64).sum()
175    }
176
177    fn system_memory_requirement(&self) -> u64 {
178        0xffffffff
179    }
180
181    fn should_scramble(&self) -> bool {
182        true
183    }
184
185    fn should_compress(&self) -> bool {
186        true
187    }
188}