Skip to main content

plasma_prp/animation/
keys.rs

1//! Interpolation key types — hsScalarKey, hsPoint3Key, hsQuatKey, etc.
2//!
3//! Each key stores a frame number (u16) and a value. Keys are stored in
4//! contiguous arrays within leaf controllers.
5//!
6//! C++ ref: plInterp/hsKeys.h/.cpp
7
8use std::io::Read;
9
10use anyhow::{Result, bail};
11
12use crate::resource::prp::PlasmaRead;
13
14/// Key type enum values.
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16#[repr(u8)]
17pub enum KeyType {
18    Unknown = 0,
19    Point3 = 1,
20    BezPoint3 = 2,
21    Scalar = 3,
22    BezScalar = 4,
23    Scale = 5,
24    BezScale = 6,
25    Quat = 7,
26    CompressedQuat32 = 8,
27    CompressedQuat64 = 9,
28    MaxKey = 10,
29    Matrix33 = 11,
30    Matrix44 = 12,
31}
32
33impl KeyType {
34    pub fn from_u8(v: u8) -> Result<Self> {
35        match v {
36            0 => Ok(Self::Unknown),
37            1 => Ok(Self::Point3),
38            2 => Ok(Self::BezPoint3),
39            3 => Ok(Self::Scalar),
40            4 => Ok(Self::BezScalar),
41            5 => Ok(Self::Scale),
42            6 => Ok(Self::BezScale),
43            7 => Ok(Self::Quat),
44            8 => Ok(Self::CompressedQuat32),
45            9 => Ok(Self::CompressedQuat64),
46            10 => Ok(Self::MaxKey),
47            11 => Ok(Self::Matrix33),
48            12 => Ok(Self::Matrix44),
49            _ => bail!("Unknown key type: {}", v),
50        }
51    }
52}
53
54/// A single animation keyframe with its value.
55#[derive(Debug, Clone)]
56pub enum KeyFrame {
57    Scalar {
58        frame: u16,
59        value: f32,
60    },
61    BezScalar {
62        frame: u16,
63        in_tan: f32,
64        out_tan: f32,
65        value: f32,
66    },
67    Point3 {
68        frame: u16,
69        value: [f32; 3],
70    },
71    BezPoint3 {
72        frame: u16,
73        in_tan: [f32; 3],
74        out_tan: [f32; 3],
75        value: [f32; 3],
76    },
77    Quat {
78        frame: u16,
79        value: [f32; 4], // x, y, z, w
80    },
81    CompressedQuat32 {
82        frame: u16,
83        data: u32,
84    },
85    CompressedQuat64 {
86        frame: u16,
87        data: [u32; 2],
88    },
89    Scale {
90        frame: u16,
91        scale: [f32; 3],
92        quat: [f32; 4],
93    },
94    BezScale {
95        frame: u16,
96        in_tan: [f32; 3],
97        out_tan: [f32; 3],
98        scale: [f32; 3],
99        quat: [f32; 4],
100    },
101    Matrix44 {
102        frame: u16,
103        value: [f32; 16],
104    },
105}
106
107impl KeyFrame {
108    pub fn frame(&self) -> u16 {
109        match self {
110            KeyFrame::Scalar { frame, .. }
111            | KeyFrame::BezScalar { frame, .. }
112            | KeyFrame::Point3 { frame, .. }
113            | KeyFrame::BezPoint3 { frame, .. }
114            | KeyFrame::Quat { frame, .. }
115            | KeyFrame::CompressedQuat32 { frame, .. }
116            | KeyFrame::CompressedQuat64 { frame, .. }
117            | KeyFrame::Scale { frame, .. }
118            | KeyFrame::BezScale { frame, .. }
119            | KeyFrame::Matrix44 { frame, .. } => *frame,
120        }
121    }
122}
123
124/// Read an array of keys of the given type.
125pub fn read_keys(reader: &mut impl Read, key_type: KeyType, count: u32) -> Result<Vec<KeyFrame>> {
126    let mut keys = Vec::with_capacity(count as usize);
127
128    for _ in 0..count {
129        let frame = reader.read_u16()?;
130        let key = match key_type {
131            KeyType::Scalar => KeyFrame::Scalar {
132                frame,
133                value: reader.read_f32()?,
134            },
135            KeyType::BezScalar => KeyFrame::BezScalar {
136                frame,
137                in_tan: reader.read_f32()?,
138                out_tan: reader.read_f32()?,
139                value: reader.read_f32()?,
140            },
141            KeyType::Point3 => KeyFrame::Point3 {
142                frame,
143                value: [
144                    reader.read_f32()?,
145                    reader.read_f32()?,
146                    reader.read_f32()?,
147                ],
148            },
149            KeyType::BezPoint3 => KeyFrame::BezPoint3 {
150                frame,
151                in_tan: [
152                    reader.read_f32()?,
153                    reader.read_f32()?,
154                    reader.read_f32()?,
155                ],
156                out_tan: [
157                    reader.read_f32()?,
158                    reader.read_f32()?,
159                    reader.read_f32()?,
160                ],
161                value: [
162                    reader.read_f32()?,
163                    reader.read_f32()?,
164                    reader.read_f32()?,
165                ],
166            },
167            KeyType::Quat => KeyFrame::Quat {
168                frame,
169                value: [
170                    reader.read_f32()?,
171                    reader.read_f32()?,
172                    reader.read_f32()?,
173                    reader.read_f32()?,
174                ],
175            },
176            KeyType::CompressedQuat32 => KeyFrame::CompressedQuat32 {
177                frame,
178                data: reader.read_u32()?,
179            },
180            KeyType::CompressedQuat64 => KeyFrame::CompressedQuat64 {
181                frame,
182                data: [reader.read_u32()?, reader.read_u32()?],
183            },
184            KeyType::Scale => {
185                let scale = [
186                    reader.read_f32()?,
187                    reader.read_f32()?,
188                    reader.read_f32()?,
189                ];
190                let quat = [
191                    reader.read_f32()?,
192                    reader.read_f32()?,
193                    reader.read_f32()?,
194                    reader.read_f32()?,
195                ];
196                KeyFrame::Scale { frame, scale, quat }
197            }
198            KeyType::BezScale => {
199                let in_tan = [
200                    reader.read_f32()?,
201                    reader.read_f32()?,
202                    reader.read_f32()?,
203                ];
204                let out_tan = [
205                    reader.read_f32()?,
206                    reader.read_f32()?,
207                    reader.read_f32()?,
208                ];
209                let scale = [
210                    reader.read_f32()?,
211                    reader.read_f32()?,
212                    reader.read_f32()?,
213                ];
214                let quat = [
215                    reader.read_f32()?,
216                    reader.read_f32()?,
217                    reader.read_f32()?,
218                    reader.read_f32()?,
219                ];
220                KeyFrame::BezScale {
221                    frame,
222                    in_tan,
223                    out_tan,
224                    scale,
225                    quat,
226                }
227            }
228            KeyType::Matrix44 => {
229                // hsMatrix44::Read — flag byte, then 16 floats if non-identity
230                let flag = reader.read_u8()?;
231                let value = if flag == 0 {
232                    [
233                        1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
234                        0.0, 1.0,
235                    ]
236                } else {
237                    let mut m = [0f32; 16];
238                    for val in &mut m {
239                        *val = reader.read_f32()?;
240                    }
241                    m
242                };
243                KeyFrame::Matrix44 { frame, value }
244            }
245            KeyType::MaxKey => {
246                // hsAffineParts: translation (3 floats) + quat (4 floats) +
247                // scale quat (4 floats) + scale (3 floats) + det sign (float)
248                // = 15 floats total
249                for _ in 0..15 {
250                    reader.read_f32()?;
251                }
252                KeyFrame::Scale {
253                    frame,
254                    scale: [1.0, 1.0, 1.0],
255                    quat: [0.0, 0.0, 0.0, 1.0],
256                }
257            }
258            KeyType::Unknown => {
259                bail!("Cannot read unknown key type");
260            }
261            _ => {
262                bail!("Unsupported key type: {:?}", key_type);
263            }
264        };
265        keys.push(key);
266    }
267
268    Ok(keys)
269}
270
271/// Decompress a 32-bit compressed quaternion.
272pub fn decompress_quat32(data: u32) -> [f32; 4] {
273    let comp = (data >> 30) as usize;
274    let scale = 0.707107f32 * 2.0 / 1023.0;
275
276    let a = ((data >> 20) & 0x3FF) as f32 * scale - 0.707107;
277    let b = ((data >> 10) & 0x3FF) as f32 * scale - 0.707107;
278    let c = (data & 0x3FF) as f32 * scale - 0.707107;
279    let d = (1.0 - a * a - b * b - c * c).max(0.0).sqrt();
280
281    match comp {
282        0 => [d, a, b, c],
283        1 => [a, d, b, c],
284        2 => [a, b, d, c],
285        _ => [a, b, c, d],
286    }
287}
288
289/// Decompress a 64-bit compressed quaternion.
290pub fn decompress_quat64(data: [u32; 2]) -> [f32; 4] {
291    let comp = (data[0] >> 30) as usize;
292    let scale20 = 0.707107f32 * 2.0 / 1048575.0;
293    let scale21 = 0.707107f32 * 2.0 / 2097151.0;
294
295    let a = ((data[0] >> 10) & 0xFFFFF) as f32 * scale20 - 0.707107;
296    let b_hi = (data[0] & 0x3FF) as u32;
297    let b_lo = (data[1] >> 21) as u32;
298    let b = ((b_hi << 11) | b_lo) as f32 * scale21 - 0.707107;
299    let c = (data[1] & 0x1FFFFF) as f32 * scale21 - 0.707107;
300    let d = (1.0 - a * a - b * b - c * c).max(0.0).sqrt();
301
302    match comp {
303        0 => [d, a, b, c],
304        1 => [a, d, b, c],
305        2 => [a, b, d, c],
306        _ => [a, b, c, d],
307    }
308}