1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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 {
    /// Unsigned 16-bit value, use pos_offset/pos_scale to unpack
    pub p: [u16; 4],

    /// Normalized signed 8-bit value
    pub n: [i8; 4],

    /// Unsigned 16-bit value, use uv_offset/uv_scale to unpack
    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], // octahedron encoded normal, aliases .pw
    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)]
/// A basic Vertex type that can be used with most mesh processing functions.
/// You don't _need_ to use this type, you can use your own type by implementing
/// the `DecodePosition` trait and making a [`VertexDataAdapter`] from slices of it.
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
}