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
116
117
118
119
120
121
use crate::errors::Error;
use crate::window::get_window;
use log::info;
use std::cell::Cell;
use std::cell::RefCell;
use std::rc::Rc;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use web_sys::Window;
#[derive(Copy, Clone, Debug)]
pub struct Timestamp {
pub time: f64,
pub delta: f64,
pub elapsed: f64,
}
pub struct TimestampLoop {
raf_loop: RafLoop,
}
impl TimestampLoop {
pub fn start<F>(mut on_tick: F) -> Result<Self, Error>
where
F: (FnMut(Timestamp) -> ()) + 'static,
{
let mut last_time: Option<f64> = None;
let mut first_time = 0f64;
let raf_loop = RafLoop::start(move |time| {
match last_time {
Some(last_time) => {
on_tick(Timestamp {
time,
delta: time - last_time,
elapsed: time - first_time,
});
}
None => {
on_tick(Timestamp {
time,
delta: 0.0,
elapsed: 0.0,
});
first_time = time;
}
}
last_time = Some(time);
})?;
Ok(Self { raf_loop })
}
}
pub struct RafLoop {
raf_id: Rc<Cell<Option<i32>>>,
}
impl Drop for RafLoop {
fn drop(&mut self) {
if let Some(id) = self.raf_id.get() {
let window = get_window().unwrap();
window.cancel_animation_frame(id).unwrap();
self.raf_id.set(None);
}
}
}
impl RafLoop {
pub fn start<F>(mut on_tick: F) -> Result<Self, Error>
where
F: (FnMut(f64) -> ()) + 'static,
{
let f = Rc::new(RefCell::new(None));
let g = f.clone();
let mut raf_id = Rc::new(Cell::new(None as Option<i32>));
let window = get_window()?;
{
let raf_id = Rc::clone(&raf_id);
*g.borrow_mut() = Some(Closure::wrap(Box::new(move |time| {
let id = raf_id.get();
if id.is_some() {
raf_id.set(request_animation_frame(&window, f.borrow().as_ref().unwrap()).ok());
on_tick(time);
}
}) as Box<dyn FnMut(f64) -> ()>));
}
let window = get_window()?;
raf_id.set(request_animation_frame(&window, g.borrow().as_ref().unwrap()).ok());
Ok(Self { raf_id })
}
}
fn request_animation_frame(
window: &Window,
f: &Closure<dyn FnMut(f64) -> ()>,
) -> Result<i32, Error> {
window
.request_animation_frame(f.as_ref().unchecked_ref())
.map_err(|e| e.into())
}