glacier_texture/
mipblock.rs

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