use crate::{quantize_half, quantize_snorm};
use float_cmp::ApproxEqUlps;
pub trait DecodePosition {
fn decode_position(&self) -> [f32; 3];
}
impl DecodePosition for [f32; 3] {
fn decode_position(&self) -> [f32; 3] {
*self
}
}
pub trait FromVertex {
fn fill_from_vertex(&mut self, vertex: &Vertex);
}
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
#[repr(C)]
pub struct PackedVertex {
pub p: [u16; 4],
pub n: [i8; 4],
pub t: [u16; 2],
}
impl FromVertex for PackedVertex {
fn fill_from_vertex(&mut self, vertex: &Vertex) {
self.p[0] = quantize_half(vertex.p[0]);
self.p[1] = quantize_half(vertex.p[1]);
self.p[2] = quantize_half(vertex.p[2]);
self.p[3] = 0u16;
self.n[0] = quantize_snorm(vertex.n[0], 8) as i8;
self.n[1] = quantize_snorm(vertex.n[1], 8) as i8;
self.n[2] = quantize_snorm(vertex.n[2], 8) as i8;
self.n[3] = 0i8;
self.t[0] = quantize_half(vertex.t[0]);
self.t[1] = quantize_half(vertex.t[1]);
}
}
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
#[repr(C)]
pub struct PackedVertexOct {
pub p: [u16; 3],
pub n: [u8; 2], pub t: [u16; 2],
}
impl FromVertex for PackedVertexOct {
fn fill_from_vertex(&mut self, vertex: &Vertex) {
self.p[0] = quantize_half(vertex.p[0]);
self.p[1] = quantize_half(vertex.p[1]);
self.p[2] = quantize_half(vertex.p[2]);
let nsum = vertex.n[0].abs() + vertex.n[1].abs() + vertex.n[2].abs();
let nx = vertex.n[0] / nsum;
let ny = vertex.n[1] / nsum;
let nz = vertex.n[2];
let nu = if nz >= 0f32 {
nx
} else {
(1f32 - ny.abs()) * if nx >= 0f32 { 1f32 } else { -1f32 }
};
let nv = if nz >= 0f32 {
ny
} else {
(1f32 - nx.abs()) * if ny >= 0f32 { 1f32 } else { -1f32 }
};
self.n[0] = quantize_snorm(nu, 8) as u8;
self.n[1] = quantize_snorm(nv, 8) as u8;
self.t[0] = quantize_half(vertex.t[0]);
self.t[1] = quantize_half(vertex.t[1]);
}
}
#[derive(Default, Debug, Copy, Clone, PartialOrd)]
#[repr(C)]
pub struct Vertex {
pub p: [f32; 3],
pub n: [f32; 3],
pub t: [f32; 2],
}
impl PartialEq for Vertex {
fn eq(&self, other: &Vertex) -> bool {
self.p[0].approx_eq_ulps(&other.p[0], 2)
&& self.p[1].approx_eq_ulps(&other.p[1], 2)
&& self.p[2].approx_eq_ulps(&other.p[2], 2)
&& self.n[0].approx_eq_ulps(&other.n[0], 2)
&& self.n[1].approx_eq_ulps(&other.n[1], 2)
&& self.n[2].approx_eq_ulps(&other.n[2], 2)
&& self.t[0].approx_eq_ulps(&other.t[0], 2)
&& self.t[1].approx_eq_ulps(&other.t[1], 2)
}
}
impl Eq for Vertex {}
impl Vertex {}
impl DecodePosition for Vertex {
fn decode_position(&self) -> [f32; 3] {
self.p
}
}
pub fn pack_vertices<T: FromVertex + Default + Clone>(input: &[Vertex]) -> Vec<T> {
let mut vertices: Vec<T> = vec![T::default(); input.len()];
for i in 0..input.len() {
vertices[i].fill_from_vertex(&input[i]);
}
vertices
}