1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
use async_std::prelude::FutureExt as _;
pub fn spawn_task(
event_w: async_std::channel::Sender<crate::event::Event>,
frames: async_std::sync::Arc<
async_std::sync::Mutex<crate::frames::FrameData>,
>,
timer_r: async_std::channel::Receiver<crate::event::TimerAction>,
) -> async_std::task::JoinHandle<()> {
async_std::task::spawn(async move {
let mut idx = 0;
let mut start_time = std::time::Instant::now();
let mut paused_time = None;
let mut force_update_time = false;
loop {
enum Res {
Wait(Option<vt100::Screen>),
TimerAction(
Result<
crate::event::TimerAction,
async_std::channel::RecvError,
>,
),
}
let wait = async {
let wait_read = frames.lock_arc().await.wait_for_frame(idx);
if wait_read.await {
let frame =
frames.lock_arc().await.get(idx).unwrap().clone();
if force_update_time {
let now = std::time::Instant::now();
start_time = now - frame.delay()
// give a bit of extra time before moving to the
// next frame, otherwise backing up behind two
// frames that are extremely close together
// doesn't work
+ std::time::Duration::from_millis(200);
if paused_time.take().is_some() {
paused_time = Some(now);
}
force_update_time = false;
} else if paused_time.is_some() {
std::future::pending::<()>().await;
} else {
async_std::task::sleep(
(start_time + frame.delay())
.saturating_duration_since(
std::time::Instant::now(),
),
)
.await;
}
Res::Wait(Some(frame.into_screen()))
} else {
Res::Wait(None)
}
};
let action = async { Res::TimerAction(timer_r.recv().await) };
match wait.race(action).await {
Res::Wait(Some(screen)) => {
event_w
.send(crate::event::Event::FrameTransition((
idx, screen,
)))
.await
.unwrap();
idx += 1;
}
Res::Wait(None) => {
idx = frames.lock_arc().await.count() - 1;
paused_time = Some(std::time::Instant::now());
event_w
.send(crate::event::Event::Paused(true))
.await
.unwrap();
}
Res::TimerAction(Ok(action)) => match action {
crate::event::TimerAction::Pause => {
let now = std::time::Instant::now();
if let Some(time) = paused_time.take() {
start_time += now - time;
} else {
paused_time = Some(now);
}
event_w
.send(crate::event::Event::Paused(
paused_time.is_some(),
))
.await
.unwrap();
}
crate::event::TimerAction::FirstFrame => {
idx = 0;
force_update_time = true;
}
crate::event::TimerAction::LastFrame => {
idx = frames.lock_arc().await.count() - 1;
force_update_time = true;
}
// force_update_time will immediately transition to the
// next frame and do idx += 1 on its own
crate::event::TimerAction::NextFrame => {
force_update_time = true;
}
crate::event::TimerAction::PreviousFrame => {
idx = idx.saturating_sub(2);
force_update_time = true;
}
crate::event::TimerAction::Quit => break,
},
Res::TimerAction(Err(e)) => panic!("{}", e),
}
}
})
}
|