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