euv_engine/scheduler/
impl.rs1use super::*;
2
3impl Default for SchedulerConfig {
5 fn default() -> SchedulerConfig {
6 SchedulerConfig::new(DEFAULT_FIXED_TIMESTEP, DEFAULT_MAX_FRAME_TIME)
7 }
8}
9
10impl Default for SchedulerState {
12 fn default() -> SchedulerState {
13 SchedulerState::new(UNINITIALIZED_TIME)
14 }
15}
16
17impl SchedulerState {
19 pub fn current_time() -> f64 {
25 let window_value: Window = window().expect("no global window exists");
26 let performance: JsValue = Reflect::get(
27 window_value.as_ref(),
28 &JsValue::from_str(PERFORMANCE_OBJECT),
29 )
30 .expect("performance object should exist");
31 let now_value: JsValue =
32 Reflect::get(&performance, &JsValue::from_str(PERFORMANCE_NOW_METHOD))
33 .expect("performance.now should exist");
34 let now_millis: f64 = now_value
35 .as_f64()
36 .expect("performance.now should return a number");
37 now_millis / 1000.0
38 }
39
40 pub fn tick(&mut self, config: &SchedulerConfig, handler: &TickHandlerRc) {
51 let current_time: f64 = Self::current_time();
52 let frame_time: f64 = if self.get_last_time() == UNINITIALIZED_TIME {
53 config.get_fixed_timestep()
54 } else {
55 current_time - self.get_last_time()
56 };
57 self.set_last_time(current_time);
58 let clamped_frame_time: f64 = frame_time.min(config.get_max_frame_time());
59 *self.get_mut_accumulator() += clamped_frame_time;
60 while self.get_accumulator() >= config.get_fixed_timestep() {
61 handler.get_mut().on_update(config.get_fixed_timestep());
62 *self.get_mut_accumulator() -= config.get_fixed_timestep();
63 *self.get_mut_update_count() += 1;
64 }
65 let interpolation: f64 = self.get_accumulator() / config.get_fixed_timestep();
66 handler.get_mut().on_render(interpolation);
67 *self.get_mut_frame_count() += 1;
68 }
69}
70
71impl SchedulerHandle {
73 pub fn stop(&self) {
75 let state: &mut SchedulerState = self.get_state().get_mut();
76 state.set_running(false);
77 if let Some(id) = state.get_mut_raf_id().take() {
78 let window_value: Window = window().expect("no global window exists");
79 let _: Result<(), JsValue> = window_value.cancel_animation_frame(id);
80 }
81 let _ = self.get_closure_cell().try_take();
83 }
84
85 pub fn is_running(&self) -> bool {
91 self.get_state().get().get_running()
94 }
95
96 pub fn update_count(&self) -> u64 {
102 self.get_state().get().get_update_count()
103 }
104
105 pub fn frame_count(&self) -> u64 {
111 self.get_state().get().get_frame_count()
112 }
113
114 pub fn start(config: SchedulerConfig, handler: TickHandlerRc) -> SchedulerHandle {
128 let state: Rc<EngineCell<SchedulerState>> =
129 Rc::new(EngineCell::new(SchedulerState::new(UNINITIALIZED_TIME)));
130 let closure_cell: RafClosureCell = Rc::new(MaybeEngineCell::new());
131 let state_ref_init: &mut SchedulerState = state.get_mut();
133 state_ref_init.set_running(true);
134 let state_clone: Rc<EngineCell<SchedulerState>> = state.clone();
135 let closure_cell_clone: RafClosureCell = closure_cell.clone();
136 let handler_clone: TickHandlerRc = handler.clone();
137 let raf_closure: Closure<dyn FnMut()> = Closure::wrap(Box::new(move || {
138 {
139 let state_ref: &mut SchedulerState = state_clone.get_mut();
140 if !state_ref.get_running() {
141 return;
142 }
143 state_ref.tick(&config, &handler_clone);
144 }
145 let state_ro: &SchedulerState = state_clone.get();
146 if state_ro.get_running() {
147 let window_value: Window = window().expect("no global window exists");
148 let cell: RafClosureCell = closure_cell_clone.clone();
149 let id: i32 = window_value
150 .request_animation_frame(
151 cell.try_get()
152 .expect("raf closure should exist")
153 .as_ref()
154 .unchecked_ref(),
155 )
156 .unwrap_or(0);
157 let state_ref_id: &mut SchedulerState = state_clone.get_mut();
158 state_ref_id.set_raf_id(Some(id));
159 }
160 }));
161 let window_value: Window = window().expect("no global window exists");
162 let id: i32 = window_value
163 .request_animation_frame(raf_closure.as_ref().unchecked_ref())
164 .unwrap_or(0);
165 let state_ref_id: &mut SchedulerState = state.get_mut();
166 state_ref_id.set_raf_id(Some(id));
167 let _ = closure_cell.try_set(raf_closure);
168 SchedulerHandle::new(state, closure_cell)
169 }
170}