onedrop_engine/
transition.rs1use std::time::{Duration, Instant};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum TransitionMode {
8 Cut,
10 Fade,
12 EaseInOut,
14 Crossfade,
16}
17
18#[derive(Debug, Clone)]
20pub struct Transition {
21 mode: TransitionMode,
23
24 duration: Duration,
26
27 start_time: Instant,
29
30 progress: f32,
32
33 active: bool,
35}
36
37impl Transition {
38 pub fn new(mode: TransitionMode, duration: Duration) -> Self {
40 Self {
41 mode,
42 duration,
43 start_time: Instant::now(),
44 progress: 0.0,
45 active: false,
46 }
47 }
48
49 pub fn start(&mut self) {
51 self.start_time = Instant::now();
52 self.progress = 0.0;
53 self.active = true;
54 }
55
56 pub fn update(&mut self) {
58 if !self.active {
59 return;
60 }
61
62 let elapsed = self.start_time.elapsed();
63 let t = elapsed.as_secs_f32() / self.duration.as_secs_f32();
64
65 if t >= 1.0 {
66 self.progress = 1.0;
67 self.active = false;
68 } else {
69 self.progress = match self.mode {
70 TransitionMode::Cut => 1.0,
71 TransitionMode::Fade => t,
72 TransitionMode::EaseInOut => Self::ease_in_out(t),
73 TransitionMode::Crossfade => t,
74 };
75 }
76 }
77
78 pub fn progress(&self) -> f32 {
80 self.progress
81 }
82
83 pub fn is_complete(&self) -> bool {
85 !self.active
86 }
87
88 pub fn old_blend(&self) -> f32 {
90 1.0 - self.progress
91 }
92
93 pub fn new_blend(&self) -> f32 {
95 self.progress
96 }
97
98 fn ease_in_out(t: f32) -> f32 {
100 if t < 0.5 {
101 2.0 * t * t
102 } else {
103 1.0 - 2.0 * (1.0 - t) * (1.0 - t)
104 }
105 }
106}
107
108impl Default for Transition {
109 fn default() -> Self {
110 Self::new(TransitionMode::Fade, Duration::from_secs(2))
111 }
112}
113
114pub struct TransitionManager {
116 transition: Option<Transition>,
118
119 default_mode: TransitionMode,
121
122 default_duration: Duration,
124}
125
126impl TransitionManager {
127 pub fn new(mode: TransitionMode, duration: Duration) -> Self {
129 Self {
130 transition: None,
131 default_mode: mode,
132 default_duration: duration,
133 }
134 }
135
136 pub fn start_transition(&mut self) {
138 let mut transition = Transition::new(self.default_mode, self.default_duration);
139 transition.start();
140 self.transition = Some(transition);
141 }
142
143 pub fn start_custom_transition(&mut self, mode: TransitionMode, duration: Duration) {
145 let mut transition = Transition::new(mode, duration);
146 transition.start();
147 self.transition = Some(transition);
148 }
149
150 pub fn update(&mut self) {
152 if let Some(ref mut transition) = self.transition {
153 transition.update();
154
155 if transition.is_complete() {
156 self.transition = None;
157 }
158 }
159 }
160
161 pub fn is_transitioning(&self) -> bool {
163 self.transition.is_some()
164 }
165
166 pub fn progress(&self) -> f32 {
168 self.transition
169 .as_ref()
170 .map(|t| t.progress())
171 .unwrap_or(1.0)
172 }
173
174 pub fn blend_factors(&self) -> (f32, f32) {
176 if let Some(ref transition) = self.transition {
177 (transition.old_blend(), transition.new_blend())
178 } else {
179 (0.0, 1.0) }
181 }
182}
183
184impl Default for TransitionManager {
185 fn default() -> Self {
186 Self::new(TransitionMode::Fade, Duration::from_secs(2))
187 }
188}
189
190#[cfg(test)]
191mod tests {
192 use super::*;
193 use std::thread;
194
195 #[test]
196 fn test_transition_progress() {
197 let mut transition = Transition::new(TransitionMode::Fade, Duration::from_millis(100));
198 transition.start();
199
200 assert_eq!(transition.progress(), 0.0);
201 assert!(!transition.is_complete());
202
203 thread::sleep(Duration::from_millis(50));
204 transition.update();
205
206 assert!(transition.progress() > 0.0 && transition.progress() < 1.0);
207
208 thread::sleep(Duration::from_millis(60));
209 transition.update();
210
211 assert_eq!(transition.progress(), 1.0);
212 assert!(transition.is_complete());
213 }
214
215 #[test]
216 fn test_ease_in_out() {
217 assert_eq!(Transition::ease_in_out(0.0), 0.0);
218 assert_eq!(Transition::ease_in_out(1.0), 1.0);
219
220 let mid = Transition::ease_in_out(0.5);
221 assert!(mid > 0.4 && mid < 0.6);
222 }
223
224 #[test]
225 fn test_blend_factors() {
226 let mut transition = Transition::new(TransitionMode::Fade, Duration::from_secs(1));
227 transition.start();
228
229 assert_eq!(transition.old_blend(), 1.0);
231 assert_eq!(transition.new_blend(), 0.0);
232
233 transition.progress = 0.5;
235 assert_eq!(transition.old_blend(), 0.5);
236 assert_eq!(transition.new_blend(), 0.5);
237 }
238
239 #[test]
240 fn test_transition_manager() {
241 let mut manager = TransitionManager::default();
242
243 assert!(!manager.is_transitioning());
244
245 manager.start_transition();
246 assert!(manager.is_transitioning());
247
248 thread::sleep(Duration::from_millis(100));
249 manager.update();
250
251 assert!(manager.progress() > 0.0);
252 }
253}