1use crate::ease::Ease;
2use crate::motion::Sample;
3
4const SNAP: f64 = 1e-6;
5
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7pub enum Repeat {
8 Count(u32),
9 Forever,
10}
11
12impl Default for Repeat {
13 fn default() -> Self {
14 Repeat::Count(1)
15 }
16}
17
18#[derive(Clone, Copy, Debug, PartialEq)]
19pub struct Tween<T: Sample> {
20 pub from: T,
21 pub to: T,
22 pub duration: f32,
23 pub ease: Ease,
24 pub delay: f32,
25 pub repeat: Repeat,
26 pub yoyo: bool,
27 time: f64,
28}
29
30impl<T: Sample> Tween<T> {
31 pub fn new(from: T, to: T, duration: f32) -> Self {
32 Self {
33 from,
34 to,
35 duration,
36 ease: Ease::Linear,
37 delay: 0.0,
38 repeat: Repeat::default(),
39 yoyo: false,
40 time: 0.0,
41 }
42 }
43
44 pub fn with_ease(mut self, ease: Ease) -> Self {
45 self.ease = ease;
46 self
47 }
48
49 pub fn with_delay(mut self, delay: f32) -> Self {
50 self.delay = delay;
51 self
52 }
53
54 pub fn with_repeat(mut self, repeat: Repeat) -> Self {
55 self.repeat = repeat;
56 self
57 }
58
59 pub fn with_yoyo(mut self) -> Self {
60 self.yoyo = true;
61 self
62 }
63
64 pub fn step(&mut self, dt: f32) {
65 if !dt.is_finite() || dt <= 0.0 {
66 return;
67 }
68 self.advance(self.time + f64::from(dt));
69 }
70
71 pub fn seek(&mut self, seconds: f32) {
72 if seconds.is_finite() {
73 self.advance(f64::from(seconds).max(0.0));
74 }
75 }
76
77 pub fn reset(&mut self) {
78 self.time = 0.0;
79 }
80
81 pub fn time(&self) -> f64 {
82 self.time
83 }
84
85 pub fn value(&self) -> T {
86 self.sample(self.time)
87 }
88
89 pub fn at(&self, seconds: f32) -> T {
90 self.sample(f64::from(seconds))
91 }
92
93 pub fn finished(&self) -> bool {
94 self.length().is_some_and(|total| self.time >= total)
95 }
96
97 pub fn length(&self) -> Option<f64> {
98 match self.repeat {
99 Repeat::Count(count) => {
100 Some(self.delay_seconds() + f64::from(count.max(1)) * self.duration_seconds())
101 }
102 Repeat::Forever => None,
103 }
104 }
105
106 fn delay_seconds(&self) -> f64 {
107 f64::from(self.delay).max(0.0)
108 }
109
110 fn duration_seconds(&self) -> f64 {
111 f64::from(self.duration).max(0.0)
112 }
113
114 fn advance(&mut self, to: f64) {
115 self.time = match self.length() {
116 Some(total) if to + SNAP >= total => total,
117 _ => to,
118 };
119 }
120
121 fn sample(&self, seconds: f64) -> T {
122 let local = seconds - self.delay_seconds();
123 let duration = self.duration_seconds();
124 let cycles = match self.repeat {
125 Repeat::Count(count) => Some(u64::from(count.max(1))),
126 Repeat::Forever => None,
127 };
128 let done = match self.length() {
129 Some(total) => seconds >= total,
130 None => duration <= 0.0 && local > 0.0,
131 };
132 if !done && (local.is_nan() || local <= 0.0) {
133 return self.from;
134 }
135 let (cycle, fraction) = if done {
136 (cycles.map_or(0, |count| count - 1), 1.0)
137 } else {
138 let progress = local / duration;
139 let whole = progress.floor();
140 (whole as u64, progress - whole)
141 };
142 let mut x = fraction as f32;
143 if self.yoyo && cycle % 2 == 1 {
144 x = 1.0 - x;
145 }
146 self.from.lerp(self.to, self.ease.at(x))
147 }
148}
149
150#[derive(Clone, Debug, PartialEq)]
151pub struct Sequence<T: Sample> {
152 tweens: Vec<Tween<T>>,
153 time: f64,
154}
155
156impl<T: Sample> Default for Sequence<T> {
157 fn default() -> Self {
158 Self::new()
159 }
160}
161
162impl<T: Sample> Sequence<T> {
163 pub fn new() -> Self {
164 Self {
165 tweens: Vec::new(),
166 time: 0.0,
167 }
168 }
169
170 pub fn then(mut self, tween: Tween<T>) -> Self {
171 self.tweens.push(tween);
172 self
173 }
174
175 pub fn len(&self) -> usize {
176 self.tweens.len()
177 }
178
179 pub fn is_empty(&self) -> bool {
180 self.tweens.is_empty()
181 }
182
183 pub fn step(&mut self, dt: f32) {
184 if !dt.is_finite() || dt <= 0.0 {
185 return;
186 }
187 self.advance(self.time + f64::from(dt));
188 }
189
190 pub fn seek(&mut self, seconds: f32) {
191 if seconds.is_finite() {
192 self.advance(f64::from(seconds).max(0.0));
193 }
194 }
195
196 pub fn reset(&mut self) {
197 self.time = 0.0;
198 }
199
200 pub fn time(&self) -> f64 {
201 self.time
202 }
203
204 pub fn value(&self) -> T {
205 self.sample(self.time)
206 }
207
208 pub fn at(&self, seconds: f32) -> T {
209 self.sample(f64::from(seconds))
210 }
211
212 pub fn finished(&self) -> bool {
213 self.length().is_some_and(|total| self.time >= total)
214 }
215
216 pub fn length(&self) -> Option<f64> {
217 let mut total = 0.0;
218 for tween in &self.tweens {
219 total += tween.length()?;
220 }
221 Some(total)
222 }
223
224 pub fn current(&self) -> Option<usize> {
225 let mut start = 0.0;
226 for (index, tween) in self.tweens.iter().enumerate() {
227 match tween.length() {
228 Some(len) if self.time >= start + len => start += len,
229 _ => return Some(index),
230 }
231 }
232 None
233 }
234
235 fn advance(&mut self, to: f64) {
236 self.time = match self.length() {
237 Some(total) if to + SNAP >= total => total,
238 _ => to,
239 };
240 }
241
242 fn sample(&self, seconds: f64) -> T {
243 let mut start = 0.0;
244 let mut last = T::default();
245 for tween in &self.tweens {
246 match tween.length() {
247 Some(len) => {
248 let end = start + len;
249 if seconds >= end {
250 last = tween.sample(len);
251 start = end;
252 } else {
253 return tween.sample(seconds - start);
254 }
255 }
256 None => return tween.sample(seconds - start),
257 }
258 }
259 last
260 }
261}
262
263#[cfg(test)]
264mod tests {
265 use super::*;
266
267 const DT: f32 = 1.0 / 60.0;
268
269 fn close(a: f32, b: f32) -> bool {
270 (a - b).abs() < 1e-5
271 }
272
273 #[test]
274 fn sixty_steps_of_a_sixtieth_land_exactly_on_the_end() {
275 for ease in Ease::ALL {
276 let mut tween = Tween::new(2.0f32, 5.0, 1.0).with_ease(ease);
277 for _ in 0..59 {
278 tween.step(DT);
279 assert!(!tween.finished(), "{}", ease.name());
280 }
281 tween.step(DT);
282 assert!(tween.finished(), "{}", ease.name());
283 assert_eq!(tween.value().to_bits(), tween.at(1.0).to_bits());
284 assert_eq!(tween.value(), 5.0);
285 tween.step(DT);
286 assert_eq!(tween.value(), 5.0);
287 }
288 }
289
290 #[test]
291 fn stepping_agrees_with_random_access_all_the_way() {
292 for ease in Ease::ALL {
293 let mut tween = Tween::new(-1.0f32, 3.0, 1.0)
294 .with_ease(ease)
295 .with_delay(0.25);
296 let mut clock = 0.0f64;
297 for _ in 0..90 {
298 tween.step(DT);
299 clock += f64::from(DT);
300 assert!(
301 close(tween.value(), tween.sample(clock)),
302 "{} at {clock}",
303 ease.name()
304 );
305 }
306 assert_eq!(tween.value(), 3.0);
307 }
308 }
309
310 #[test]
311 fn other_frame_rates_land_on_the_same_end() {
312 for frames in [24u32, 30, 48, 60, 90, 120, 144, 240] {
313 let dt = 1.0 / frames as f32;
314 let mut tween = Tween::new(0.0f32, 1.0, 1.0).with_ease(Ease::CubicInOut);
315 for _ in 0..frames {
316 tween.step(dt);
317 }
318 assert!(tween.finished(), "{frames}");
319 assert_eq!(tween.value(), 1.0, "{frames}");
320 }
321 let mut fine = Tween::new(0.0f32, 1.0, 0.7);
322 let mut coarse = fine;
323 for _ in 0..70 {
324 fine.step(0.01);
325 }
326 for _ in 0..7 {
327 coarse.step(0.1);
328 }
329 assert!(fine.finished() && coarse.finished());
330 assert_eq!(fine.value(), coarse.value());
331 }
332
333 #[test]
334 fn a_tween_holds_its_start_through_the_delay() {
335 let tween = Tween::new(10.0f32, 20.0, 2.0).with_delay(1.0);
336 assert_eq!(tween.at(-5.0), 10.0);
337 assert_eq!(tween.at(0.0), 10.0);
338 assert_eq!(tween.at(1.0), 10.0);
339 assert_eq!(tween.at(2.0), 15.0);
340 assert_eq!(tween.at(3.0), 20.0);
341 assert_eq!(tween.at(99.0), 20.0);
342 assert_eq!(tween.length(), Some(3.0));
343 let mut stepped = tween;
344 stepped.step(0.5);
345 assert_eq!(stepped.value(), 10.0);
346 assert!(!stepped.finished());
347 }
348
349 #[test]
350 fn a_repeat_count_replays_from_the_start() {
351 let tween = Tween::new(0.0f32, 1.0, 2.0).with_repeat(Repeat::Count(3));
352 assert_eq!(tween.length(), Some(6.0));
353 assert_eq!(tween.at(1.0), 0.5);
354 assert_eq!(tween.at(2.0), 0.0);
355 assert_eq!(tween.at(3.0), 0.5);
356 assert_eq!(tween.at(5.0), 0.5);
357 assert_eq!(tween.at(6.0), 1.0);
358 assert_eq!(tween.at(60.0), 1.0);
359
360 let mut stepped = tween;
361 let mut previous = 0.0f32;
362 let mut drops = 0;
363 for _ in 0..360 {
364 stepped.step(DT);
365 let value = stepped.value();
366 if value < previous {
367 drops += 1;
368 }
369 previous = value;
370 }
371 assert_eq!(drops, 2);
372 assert!(stepped.finished());
373 assert_eq!(stepped.value(), 1.0);
374
375 let once = Tween::new(0.0f32, 1.0, 2.0).with_repeat(Repeat::Count(0));
376 assert_eq!(once.length(), Some(2.0));
377 assert_eq!(once.at(2.0), 1.0);
378 }
379
380 #[test]
381 fn yoyo_runs_every_other_cycle_backward() {
382 let tween = Tween::new(0.0f32, 4.0, 1.0)
383 .with_repeat(Repeat::Count(4))
384 .with_yoyo();
385 assert_eq!(tween.at(0.25), 1.0);
386 assert_eq!(tween.at(1.0), 4.0);
387 assert_eq!(tween.at(1.25), 3.0);
388 assert_eq!(tween.at(2.0), 0.0);
389 assert_eq!(tween.at(2.25), 1.0);
390 assert_eq!(tween.at(3.5), 2.0);
391 assert_eq!(tween.at(4.0), 0.0);
392 assert_eq!(tween.at(40.0), 0.0);
393
394 let odd = Tween::new(0.0f32, 4.0, 1.0)
395 .with_repeat(Repeat::Count(3))
396 .with_yoyo();
397 assert_eq!(odd.at(3.0), 4.0);
398
399 let mut stepped = tween;
400 for _ in 0..240 {
401 stepped.step(DT);
402 }
403 assert!(stepped.finished());
404 assert_eq!(stepped.value(), 0.0);
405
406 let single = Tween::new(0.0f32, 4.0, 1.0).with_yoyo();
407 assert_eq!(single.at(1.0), 4.0);
408 }
409
410 #[test]
411 fn yoyo_mirrors_an_eased_curve_in_time() {
412 let tween = Tween::new(0.0f32, 1.0, 1.0)
413 .with_ease(Ease::BackOut)
414 .with_repeat(Repeat::Count(2))
415 .with_yoyo();
416 for i in 1..100 {
417 let t = i as f32 / 100.0;
418 let eased = Ease::BackOut.at(t);
419 assert!(close(tween.at(t), eased), "{t}");
420 assert!(close(tween.at(1.0 + t), Ease::BackOut.at(1.0 - t)), "{t}");
421 assert!(close(tween.at(2.0 - t), eased), "{t}");
422 }
423 }
424
425 #[test]
426 fn forever_never_finishes() {
427 let tween = Tween::new(0.0f32, 1.0, 1.0)
428 .with_repeat(Repeat::Forever)
429 .with_yoyo();
430 assert_eq!(tween.length(), None);
431 assert_eq!(tween.at(0.5), 0.5);
432 assert_eq!(tween.at(1.5), 0.5);
433 assert_eq!(tween.at(1001.25), 0.75);
434 assert_eq!(tween.at(1000.25), 0.25);
435 let mut stepped = tween;
436 for _ in 0..6000 {
437 stepped.step(DT);
438 }
439 assert!(!stepped.finished());
440 assert_eq!(stepped.value(), stepped.sample(stepped.time()));
441
442 let plain = Tween::new(0.0f32, 8.0, 2.0).with_repeat(Repeat::Forever);
443 assert_eq!(plain.at(3.0), 4.0);
444 assert_eq!(plain.at(201.0), 4.0);
445 }
446
447 #[test]
448 fn a_zero_length_tween_jumps_to_its_end() {
449 let tween = Tween::new(1.0f32, 2.0, 0.0);
450 assert!(tween.finished());
451 assert_eq!(tween.at(-0.1), 1.0);
452 assert_eq!(tween.at(0.0), 2.0);
453 assert_eq!(tween.value(), 2.0);
454 let delayed = Tween::new(1.0f32, 2.0, 0.0).with_delay(1.0);
455 assert_eq!(delayed.at(0.5), 1.0);
456 assert_eq!(delayed.at(1.0), 2.0);
457 assert_eq!(delayed.at(1.1), 2.0);
458 let forever = Tween::new(1.0f32, 2.0, 0.0).with_repeat(Repeat::Forever);
459 assert_eq!(forever.at(5.0), 2.0);
460 assert_eq!(forever.at(0.0), 1.0);
461 }
462
463 #[test]
464 fn bad_time_is_ignored() {
465 let mut tween = Tween::new(0.0f32, 1.0, 1.0);
466 tween.step(f32::NAN);
467 tween.step(-1.0);
468 tween.step(f32::INFINITY);
469 tween.step(0.0);
470 assert_eq!(tween.time(), 0.0);
471 tween.seek(f32::NAN);
472 assert_eq!(tween.time(), 0.0);
473 tween.seek(0.25);
474 assert_eq!(tween.value(), 0.25);
475 tween.seek(-3.0);
476 assert_eq!(tween.value(), 0.0);
477 tween.seek(0.5);
478 tween.reset();
479 assert_eq!(tween.time(), 0.0);
480 assert_eq!(tween.value(), 0.0);
481 }
482
483 #[test]
484 fn a_tween_moves_a_vector_lane_by_lane() {
485 let tween = Tween::new([0.0f32, 10.0, -4.0], [4.0, 0.0, 4.0], 2.0).with_ease(Ease::QuadIn);
486 assert_eq!(tween.at(1.0), [1.0, 7.5, -2.0]);
487 assert_eq!(tween.at(2.0), [4.0, 0.0, 4.0]);
488 let mut stepped = tween;
489 for _ in 0..120 {
490 stepped.step(DT);
491 }
492 assert_eq!(stepped.value(), [4.0, 0.0, 4.0]);
493 }
494
495 #[test]
496 fn a_sequence_chains_tweens_end_to_start() {
497 let sequence = Sequence::new()
498 .then(Tween::new(0.0f32, 1.0, 1.0))
499 .then(Tween::new(5.0f32, 7.0, 2.0).with_delay(1.0))
500 .then(Tween::new(-1.0f32, -2.0, 1.0).with_repeat(Repeat::Count(2)));
501 assert_eq!(sequence.len(), 3);
502 assert!(!sequence.is_empty());
503 assert_eq!(sequence.length(), Some(6.0));
504 assert_eq!(sequence.at(-1.0), 0.0);
505 assert_eq!(sequence.at(0.5), 0.5);
506 assert_eq!(sequence.at(1.0), 5.0);
507 assert_eq!(sequence.at(1.5), 5.0);
508 assert_eq!(sequence.at(2.0), 5.0);
509 assert_eq!(sequence.at(3.0), 6.0);
510 assert_eq!(sequence.at(4.0), -1.0);
511 assert_eq!(sequence.at(4.5), -1.5);
512 assert_eq!(sequence.at(5.0), -1.0);
513 assert_eq!(sequence.at(6.0), -2.0);
514 assert_eq!(sequence.at(100.0), -2.0);
515 }
516
517 #[test]
518 fn a_sequence_steps_like_it_is_read_at_random() {
519 let sequence = Sequence::new()
520 .then(Tween::new(0.0f32, 1.0, 0.5).with_ease(Ease::ElasticOut))
521 .then(Tween::new(1.0f32, 0.0, 0.5).with_ease(Ease::BounceOut))
522 .then(
523 Tween::new(0.0f32, 3.0, 0.25)
524 .with_repeat(Repeat::Count(2))
525 .with_yoyo(),
526 );
527 let mut stepped = sequence.clone();
528 let mut clock = 0.0f64;
529 for _ in 0..90 {
530 stepped.step(DT);
531 clock += f64::from(DT);
532 assert!(close(stepped.value(), sequence.sample(clock)), "{clock}");
533 }
534 assert!(stepped.finished());
535 assert_eq!(stepped.value().to_bits(), sequence.at(1.5).to_bits());
536 assert_eq!(stepped.value(), 0.0);
537 }
538
539 #[test]
540 fn sixty_steps_land_on_a_two_part_sequence() {
541 let mut sequence = Sequence::new()
542 .then(Tween::new(0.0f32, 1.0, 0.5).with_ease(Ease::SineInOut))
543 .then(Tween::new(1.0f32, 9.0, 0.5).with_ease(Ease::CircOut));
544 for _ in 0..59 {
545 sequence.step(DT);
546 }
547 assert!(!sequence.finished());
548 sequence.step(DT);
549 assert!(sequence.finished());
550 assert_eq!(sequence.value().to_bits(), sequence.at(1.0).to_bits());
551 assert_eq!(sequence.value(), 9.0);
552 }
553
554 #[test]
555 fn a_sequence_reports_where_it_is() {
556 let mut sequence = Sequence::new()
557 .then(Tween::new(0.0f32, 1.0, 1.0))
558 .then(Tween::new(1.0f32, 2.0, 1.0));
559 assert_eq!(sequence.current(), Some(0));
560 sequence.seek(1.0);
561 assert_eq!(sequence.current(), Some(1));
562 sequence.seek(2.0);
563 assert_eq!(sequence.current(), None);
564 assert!(sequence.finished());
565 sequence.reset();
566 assert_eq!(sequence.current(), Some(0));
567 assert_eq!(sequence.value(), 0.0);
568 }
569
570 #[test]
571 fn a_forever_tween_ends_its_sequence() {
572 let sequence = Sequence::new()
573 .then(Tween::new(0.0f32, 1.0, 1.0))
574 .then(Tween::new(0.0f32, 2.0, 1.0).with_repeat(Repeat::Forever))
575 .then(Tween::new(9.0f32, 9.5, 1.0));
576 assert_eq!(sequence.length(), None);
577 assert_eq!(sequence.at(1.5), 1.0);
578 assert_eq!(sequence.at(500.5), 1.0);
579 let mut stepped = sequence.clone();
580 for _ in 0..600 {
581 stepped.step(DT);
582 }
583 assert!(!stepped.finished());
584 assert_eq!(stepped.current(), Some(1));
585 }
586
587 #[test]
588 fn an_empty_sequence_rests_at_the_default() {
589 let mut sequence = Sequence::<f32>::new();
590 assert!(sequence.is_empty());
591 assert_eq!(sequence.length(), Some(0.0));
592 assert!(sequence.finished());
593 sequence.step(DT);
594 assert_eq!(sequence.value(), 0.0);
595 assert_eq!(sequence.current(), None);
596 }
597}