use binrw::{BinRead, BinWrite};
use half::f16 as half_f16;
#[repr(transparent)]
#[derive(BinRead, BinWrite, bytemuck::Pod, bytemuck::Zeroable, Copy, Clone, Debug)]
pub struct Vec3PackedSnorm(pub u32);
impl Vec3PackedSnorm {
#[allow(clippy::cast_precision_loss, clippy::cast_possible_wrap)]
pub fn unpack(self) -> [f32; 3] {
let packed = self.0;
let nx = (packed << 22) as i32 >> 22;
let ny = (packed << 12) as i32 >> 22;
let nz = (packed << 2) as i32 >> 22;
[nx as f32 / 511.0, ny as f32 / 511.0, nz as f32 / 511.0]
}
}
#[repr(transparent)]
#[derive(BinRead, BinWrite, bytemuck::Pod, bytemuck::Zeroable, Copy, Clone, Debug)]
pub struct Float16(u16);
impl Default for Float16 {
fn default() -> Self {
Float16(half_f16::default().to_bits())
}
}
impl Float16 {
pub fn from_bits(bits: u16) -> Self {
Float16(bits)
}
pub fn from_half(half: half_f16) -> Self {
Float16(half.to_bits())
}
pub fn from_f32(float: f32) -> Self {
Float16(half_f16::from_f32(float).to_bits())
}
pub fn as_half(self) -> half_f16 {
half_f16::from_bits(self.0)
}
pub fn as_f32(self) -> f32 {
self.as_half().to_f32()
}
}
#[cfg(test)]
mod tests {
use crate::packing::Vec3PackedSnorm;
#[test]
fn vec3_packed_snorm_test() {
for test in [0x567a_67ca, 0x567_a6436, 0x5675_9fca, 0x5675_9c36] {
for x in Vec3PackedSnorm(test).unpack() {
assert!(x.abs() <= 1.0, "Not normalised!");
}
}
}
}