1use std::{
2 error::Error,
3 io::{self, Read, SeekFrom},
4};
5
6pub fn u16_to_f32(num: u16) -> f32 {
7 half::f16::from_bits(num).to_f32()
8}
9
10/// Signed, normalized Vec3 + w component packed in a u32.
11/// [x: 10; y: 10; z: 10; w: 2]
12pub struct Vec3PackedSnorm(pub u32);
13
14impl Vec3PackedSnorm {
15 /// The w component is discarded.
16 #[allow(clippy::cast_precision_loss, clippy::cast_possible_wrap)]
17 pub fn unpack(self) -> [f32; 3] {
18 let packed = self.0;
19
20 let nx = (packed << 22) as i32 >> 22;
21 let ny = (packed << 12) as i32 >> 22;
22 let nz = (packed << 2) as i32 >> 22;
23
24 [nx as f32 / 511.0, ny as f32 / 511.0, nz as f32 / 511.0]
25 }
26}
27
28/// Abstraction over anything that can be read as Seek or Read
29pub trait ReadSeek: std::io::Seek + std::io::Read {}
30impl<T: ?Sized> ReadSeek for T where T: std::io::Seek + std::io::Read {}
31
32pub(crate) fn read_byte_slice(
33 file: &mut dyn ReadSeek, // Dynamic param: Anything that impl's Read + Seek
34 start: u64,
35 count: usize,
36) -> Result<Vec<u8>, Box<dyn Error>> {
37 file.seek(SeekFrom::Start(start))?;
38 let mut buf = vec![0; count];
39 file.read_exact(&mut buf)?;
40
41 Ok(buf)
42}
43
44#[cfg(feature = "res")]
45pub(crate) fn inflate_bytes(bytes: &[u8]) -> io::Result<Vec<u8>> {
46 use flate2::read::ZlibDecoder;
47
48 let mut z = ZlibDecoder::new(bytes);
49 // z.read_to_string(&mut s)?;
50 let mut vec = Vec::new();
51 z.read_to_end(&mut vec)?;
52 Ok(vec)
53}
54
55#[cfg(test)]
56mod tests {
57 use super::Vec3PackedSnorm;
58
59 #[test]
60 fn vec3_packed_snorm_test() {
61 for test in [0x567a_67ca, 0x567_a6436, 0x5675_9fca, 0x5675_9c36] {
62 for x in Vec3PackedSnorm(test).unpack() {
63 assert!(x.abs() <= 1.0, "Not normalised!");
64 }
65 }
66 }
67}