rive_rs/animation/
linear_animation_instance.rs
1use crate::animation::{LinearAnimation, Loop};
6use crate::artboard::Artboard;
7use crate::core::Object;
8
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10enum Direction {
11 Forwards,
12 Backwards,
13}
14
15impl From<Direction> for f32 {
16 fn from(direction: Direction) -> Self {
17 match direction {
18 Direction::Forwards => 1.0,
19 Direction::Backwards => -1.0,
20 }
21 }
22}
23
24#[derive(Clone, Debug)]
25pub struct LinearAnimationInstance {
26 linear_animation: Object<LinearAnimation>,
27 time: f32,
28 direction: Direction,
29 did_loop: bool,
30}
31
32impl LinearAnimationInstance {
33 pub fn new(linear_animation: Object<LinearAnimation>) -> Self {
34 let time = linear_animation
35 .as_ref()
36 .enable_work_area()
37 .then(|| {
38 linear_animation.as_ref().work_start() as f32
39 / linear_animation.as_ref().fps() as f32
40 })
41 .unwrap_or_default();
42
43 Self { linear_animation, time, direction: Direction::Forwards, did_loop: false }
44 }
45
46 pub fn is_done(&self) -> bool {
47 self.linear_animation.as_ref().r#loop() == Loop::OneShot && self.did_loop
48 }
49
50 pub fn reset(&mut self) {
51 *self = Self::new(self.linear_animation.clone());
52 }
53
54 pub fn set_time(&mut self, time: f32) {
55 if time == self.time {
56 return;
57 }
58
59 self.time = time;
60 self.direction = Direction::Forwards;
61 }
62
63 pub fn advance(&mut self, elapsed_seconds: f32) -> bool {
64 let linear_animation = self.linear_animation.as_ref();
65 let direction: f32 = self.direction.into();
66 self.time += elapsed_seconds * linear_animation.speed() * direction;
67
68 let fps = linear_animation.fps() as f32;
69 let mut frames = self.time * fps;
70
71 let start = linear_animation
72 .enable_work_area()
73 .then(|| linear_animation.work_start() as f32)
74 .unwrap_or_default();
75 let end = linear_animation
76 .enable_work_area()
77 .then(|| linear_animation.work_end() as f32)
78 .unwrap_or_else(|| linear_animation.duration() as f32);
79 let range = end - start;
80
81 self.did_loop = false;
82 let mut keep_going = true;
83
84 match linear_animation.r#loop() {
85 Loop::OneShot => {
86 if frames > end {
87 keep_going = false;
88 frames = end;
89 self.time = frames / fps;
90 self.did_loop = true;
91 }
92 }
93 Loop::Loop => {
94 if frames >= end {
95 frames = start + (self.time * fps - start) % range;
96 self.time = frames / fps;
97 self.did_loop = true;
98 }
99 }
100 Loop::PingPong => loop {
101 if self.direction == Direction::Forwards && frames >= end {
102 self.direction = Direction::Backwards;
103 frames = end + (end - frames);
104 self.time = frames / fps;
105 self.did_loop = true;
106 } else if self.direction == Direction::Backwards && frames < start {
107 self.direction = Direction::Forwards;
108 frames = start + (start - frames);
109 self.time = frames / fps;
110 self.did_loop = true;
111 } else {
112 break;
113 }
114 },
115 }
116
117 keep_going
118 }
119
120 pub fn apply(&self, artboard: Object<Artboard>, mix: f32) {
121 self.linear_animation.as_ref().apply(artboard, self.time, mix);
122 }
123}