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
128
129
130
131
132
133
134
135
mod parser;

pub use glam::Vec3;
pub use parser::parse;
use serde::{Deserialize, Serialize};

pub struct OpdFile {
    pub header: OpdHeader,
    pub centroids: Vec<Centroid>,
    pub frames: Frames,
}

#[derive(Deserialize, Debug, Serialize)]
pub struct OpdHeader {
    pub version: String,
    pub compressed: Option<String>,
    #[serde(rename = "type")]
    pub ty: String,
    pub directive: OpdHeaderDirective,
}

#[derive(Clone)]
pub struct Frame<T> {
    pub time: f32,
    pub data: Vec<T>,
}

impl<T: Copy> Frame<T> {
    pub fn frame_as_vec3a(&self) -> impl Iterator<Item = Vec3> + '_
    where
        T: Into<f32>,
    {
        let iter = self.data.iter();
        FrameIterator { iter }
    }
}
pub struct FrameIterator<'a, T> {
    iter: std::slice::Iter<'a, T>,
}
impl<'a, T: Copy> Iterator for FrameIterator<'a, T>
where
    T: Into<f32>,
{
    type Item = Vec3;
    fn next(&mut self) -> Option<Self::Item> {
        let max_value: usize = (1 << (std::mem::size_of::<T>() * 8 - 1)) - 1;
        let max_value = max_value as f32;
        let arr: [f32; 3] = [
            match self.iter.next() {
                Some(a) => (*a).into() / max_value,
                None => return None,
            },
            match self.iter.next() {
                Some(a) => (*a).into() / max_value,
                None => return None,
            },
            match self.iter.next() {
                Some(a) => (*a).into() / max_value,
                None => return None,
            },
        ];
        Some(arr.into())
    }
}

#[derive(Clone)]
pub enum Frames {
    I8(Vec<Frame<i8>>),
    I16(Vec<Frame<i16>>),
    I32(Vec<Frame<i32>>),
    I64(Vec<Frame<i64>>),
}

#[derive(Deserialize, Debug, Serialize, Clone)]
pub struct FrameMeta {
    pub time: f32,
    pub offset: usize,
}

#[derive(Deserialize, Debug, Serialize)]
pub struct OpdHeaderDirective {
    pub version: String,
    pub meta: OpdHeaderDirectiveMeta,

    #[serde(rename = "numCentroids")]
    pub num_centroids: Option<usize>,

    #[serde(rename = "numPoints")]
    pub num_points: Option<usize>,

    pub origin: OpdHeaderDirectiveOrigin,

    pub precision: usize,
    pub scale: Vec3,
    pub frames: Vec<FrameMeta>,

    pub index: Option<bool>,
    #[serde(rename = "subCentroids")]
    pub sub_centroids: Option<bool>,

    #[serde(rename = "lastFrameCorrected")]
    pub last_frame_corrected: Option<bool>,
}

#[derive(Deserialize, Debug, Serialize)]
pub struct OpdHeaderDirectiveOrigin {
    pub x: f32,
    pub y: f32,
    pub z: f32,
}
impl From<OpdHeaderDirectiveOrigin> for Vec3 {
    fn from(value: OpdHeaderDirectiveOrigin) -> Self {
        Vec3 {
            x: value.x,
            y: value.y,
            z: value.z,
        }
    }
}

#[derive(Deserialize, Debug, Serialize)]
pub struct OpdHeaderDirectiveMeta {
    #[serde(rename = "projectId")]
    pub project_id: String,

    #[serde(rename = "projectName")]
    pub project_name: String,
}

pub struct Centroid {
    pub parent_id: u32,

    /// Relative to origin defined in header
    pub offset: Vec3,
}