1#[derive(Debug, Clone, Copy)]
8pub struct Keyframe<'a> {
9 pub vertices: &'a [[f32; 3]],
10 pub time: f32,
11}
12
13#[derive(Debug)]
15pub struct VertexAnimation<'a> {
16 keyframes: &'a [Keyframe<'a>],
17 looping: bool,
18}
19
20impl<'a> VertexAnimation<'a> {
21 pub fn new(keyframes: &'a [Keyframe<'a>], looping: bool) -> Self {
30 assert!(!keyframes.is_empty(), "Keyframes array cannot be empty");
31
32 let vertex_count = keyframes[0].vertices.len();
34 for kf in keyframes.iter() {
35 assert_eq!(
36 kf.vertices.len(),
37 vertex_count,
38 "All keyframes must have the same number of vertices"
39 );
40 }
41
42 Self { keyframes, looping }
43 }
44
45 pub fn sample(&self, time: f32, output: &mut [[f32; 3]]) {
54 assert_eq!(
55 output.len(),
56 self.keyframes[0].vertices.len(),
57 "Output buffer size must match keyframe vertex count"
58 );
59
60 if self.keyframes.len() == 1 {
62 output.copy_from_slice(self.keyframes[0].vertices);
63 return;
64 }
65
66 let duration = self.keyframes.last().unwrap().time;
68
69 let t = if self.looping {
71 if duration > 0.0 { time % duration } else { 0.0 }
72 } else {
73 time.clamp(0.0, duration)
74 };
75
76 let mut kf1_idx = self
78 .keyframes
79 .partition_point(|kf| kf.time <= t)
80 .saturating_sub(1);
81 if self.keyframes[kf1_idx].time > t {
82 kf1_idx = 0;
83 }
84 let kf2_idx = (kf1_idx + 1).min(self.keyframes.len() - 1);
85
86 if kf1_idx == self.keyframes.len() - 1 {
88 output.copy_from_slice(self.keyframes[kf1_idx].vertices);
89 return;
90 }
91
92 let kf1 = &self.keyframes[kf1_idx];
93 let kf2 = &self.keyframes[kf2_idx];
94
95 let alpha = if kf2.time > kf1.time {
97 (t - kf1.time) / (kf2.time - kf1.time)
98 } else {
99 0.0
100 };
101
102 for (i, out_vertex) in output.iter_mut().enumerate() {
104 let v1 = &kf1.vertices[i];
105 let v2 = &kf2.vertices[i];
106
107 out_vertex[0] = v1[0] + alpha * (v2[0] - v1[0]);
108 out_vertex[1] = v1[1] + alpha * (v2[1] - v1[1]);
109 out_vertex[2] = v1[2] + alpha * (v2[2] - v1[2]);
110 }
111 }
112
113 pub fn duration(&self) -> f32 {
115 self.keyframes.last().map(|kf| kf.time).unwrap_or(0.0)
116 }
117
118 pub fn keyframe_count(&self) -> usize {
120 self.keyframes.len()
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 extern crate std;
127 use super::*;
128
129 #[test]
130 fn test_single_keyframe() {
131 let vertices = [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]];
132 let kf = Keyframe {
133 vertices: &vertices,
134 time: 0.0,
135 };
136 let keyframes = [kf];
137 let anim = VertexAnimation::new(&keyframes, false);
138
139 let mut output = [[0.0, 0.0, 0.0]; 2];
140 anim.sample(0.5, &mut output);
141
142 assert_eq!(output[0], [0.0, 0.0, 0.0]);
143 assert_eq!(output[1], [1.0, 0.0, 0.0]);
144 }
145
146 #[test]
147 fn test_two_keyframe_interpolation() {
148 let vertices1 = [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]];
149 let vertices2 = [[0.0, 2.0, 0.0], [1.0, 2.0, 0.0]];
150
151 let kf1 = Keyframe {
152 vertices: &vertices1,
153 time: 0.0,
154 };
155 let kf2 = Keyframe {
156 vertices: &vertices2,
157 time: 1.0,
158 };
159
160 let keyframes = [kf1, kf2];
161 let anim = VertexAnimation::new(&keyframes, false);
162
163 let mut output = [[0.0, 0.0, 0.0]; 2];
165 anim.sample(0.5, &mut output);
166
167 assert_eq!(output[0], [0.0, 1.0, 0.0]);
168 assert_eq!(output[1], [1.0, 1.0, 0.0]);
169 }
170
171 #[test]
172 fn test_looping_animation() {
173 let vertices1 = [[0.0, 0.0, 0.0]];
174 let vertices2 = [[1.0, 0.0, 0.0]];
175
176 let kf1 = Keyframe {
177 vertices: &vertices1,
178 time: 0.0,
179 };
180 let kf2 = Keyframe {
181 vertices: &vertices2,
182 time: 1.0,
183 };
184
185 let keyframes = [kf1, kf2];
186 let anim = VertexAnimation::new(&keyframes, true);
187
188 let mut output = [[0.0, 0.0, 0.0]; 1];
190 anim.sample(1.5, &mut output);
191
192 assert_eq!(output[0], [0.5, 0.0, 0.0]);
194 }
195
196 #[test]
197 fn test_clamping_non_looping() {
198 let vertices1 = [[0.0, 0.0, 0.0]];
199 let vertices2 = [[1.0, 0.0, 0.0]];
200
201 let kf1 = Keyframe {
202 vertices: &vertices1,
203 time: 0.0,
204 };
205 let kf2 = Keyframe {
206 vertices: &vertices2,
207 time: 1.0,
208 };
209
210 let keyframes = [kf1, kf2];
211 let anim = VertexAnimation::new(&keyframes, false);
212
213 let mut output = [[0.0, 0.0, 0.0]; 1];
215 anim.sample(2.0, &mut output);
216
217 assert_eq!(output[0], [1.0, 0.0, 0.0]);
218 }
219
220 #[test]
221 fn test_duration() {
222 let vertices1 = [[0.0, 0.0, 0.0]];
223 let vertices2 = [[1.0, 0.0, 0.0]];
224
225 let kf1 = Keyframe {
226 vertices: &vertices1,
227 time: 0.0,
228 };
229 let kf2 = Keyframe {
230 vertices: &vertices2,
231 time: 2.5,
232 };
233
234 let keyframes = [kf1, kf2];
235 let anim = VertexAnimation::new(&keyframes, false);
236 assert_eq!(anim.duration(), 2.5);
237 assert_eq!(anim.keyframe_count(), 2);
238 }
239
240 #[test]
241 #[should_panic(expected = "Keyframes array cannot be empty")]
242 fn test_empty_keyframes_panics() {
243 let keyframes: &[Keyframe] = &[];
244 let _anim = VertexAnimation::new(keyframes, false);
245 }
246
247 #[test]
248 #[should_panic(expected = "All keyframes must have the same number of vertices")]
249 fn test_inconsistent_vertex_count_panics() {
250 let vertices1 = [[0.0, 0.0, 0.0]];
251 let vertices2 = [[1.0, 0.0, 0.0], [2.0, 0.0, 0.0]];
252
253 let kf1 = Keyframe {
254 vertices: &vertices1,
255 time: 0.0,
256 };
257 let kf2 = Keyframe {
258 vertices: &vertices2,
259 time: 1.0,
260 };
261
262 let keyframes = [kf1, kf2];
263 let _anim = VertexAnimation::new(&keyframes, false);
264 }
265}