euv_engine/scheduler/
impl.rs1use super::*;
2
3impl Default for SchedulerConfig {
5 fn default() -> SchedulerConfig {
11 SchedulerConfig::new(DEFAULT_FIXED_TIMESTEP, DEFAULT_MAX_FRAME_TIME)
12 }
13}
14
15impl Default for SchedulerState {
17 fn default() -> SchedulerState {
23 SchedulerState::new(UNINITIALIZED_TIME)
24 }
25}
26
27impl SchedulerState {
29 pub fn current_time() -> f64 {
38 let Some(window_value) = window() else {
39 return 0.0;
40 };
41 let Ok(performance) = Reflect::get(
42 window_value.as_ref(),
43 &JsValue::from_str(PERFORMANCE_OBJECT),
44 ) else {
45 return 0.0;
46 };
47 let Ok(now_method) = Reflect::get(&performance, &JsValue::from_str(PERFORMANCE_NOW_METHOD))
48 else {
49 return 0.0;
50 };
51 let now_function: js_sys::Function = now_method.unchecked_into();
52 let Some(now_millis) = now_function
53 .call0(&performance)
54 .ok()
55 .and_then(|v: JsValue| v.as_f64())
56 else {
57 return 0.0;
58 };
59 now_millis / 1000.0
60 }
61
62 pub fn tick(&mut self, config: &SchedulerConfig, handler: &TickHandlerRc) {
73 let current_time: f64 = Self::current_time();
74 let frame_time: f64 = if self.get_last_time() == UNINITIALIZED_TIME {
75 config.get_fixed_timestep()
76 } else {
77 current_time - self.get_last_time()
78 };
79 self.set_last_time(current_time);
80 let clamped_frame_time: f64 = frame_time.min(config.get_max_frame_time());
81 *self.get_mut_accumulator() += clamped_frame_time;
82 while self.get_accumulator() >= config.get_fixed_timestep() {
83 handler.get_mut().on_update(config.get_fixed_timestep());
84 *self.get_mut_accumulator() -= config.get_fixed_timestep();
85 *self.get_mut_update_count() += 1;
86 }
87 let interpolation: f64 = self.get_accumulator() / config.get_fixed_timestep();
88 handler.get_mut().on_render(interpolation);
89 *self.get_mut_frame_count() += 1;
90 }
91}
92
93impl SchedulerHandle {
95 pub fn stop(&self) {
97 let state: &mut SchedulerState = self.get_state().get_mut();
98 state.set_running(false);
99 if let Some(id) = state.get_mut_raf_id().take() {
100 let Some(window_value) = window() else {
101 let _ = self.get_closure_cell().try_take();
103 return;
104 };
105 let _: Result<(), JsValue> = window_value.cancel_animation_frame(id);
106 }
107 let _ = self.get_closure_cell().try_take();
109 }
110
111 pub fn is_running(&self) -> bool {
117 self.get_state().get().get_running()
120 }
121
122 pub fn update_count(&self) -> u64 {
128 self.get_state().get().get_update_count()
129 }
130
131 pub fn frame_count(&self) -> u64 {
137 self.get_state().get().get_frame_count()
138 }
139
140 pub fn start(config: SchedulerConfig, handler: TickHandlerRc) -> SchedulerHandle {
157 let state: Rc<EngineCell<SchedulerState>> =
158 Rc::new(EngineCell::new(SchedulerState::new(UNINITIALIZED_TIME)));
159 let closure_cell: RafClosureCell = Rc::new(MaybeEngineCell::new());
160 let state_ref_init: &mut SchedulerState = state.get_mut();
162 state_ref_init.set_running(true);
163 let state_clone: Rc<EngineCell<SchedulerState>> = state.clone();
164 let closure_cell_clone: RafClosureCell = closure_cell.clone();
165 let handler_clone: TickHandlerRc = handler.clone();
166 let raf_closure: Closure<dyn FnMut()> = Closure::wrap(Box::new(move || {
167 {
168 let state_ref: &mut SchedulerState = state_clone.get_mut();
169 if !state_ref.get_running() {
170 return;
171 }
172 state_ref.tick(&config, &handler_clone);
173 }
174 let state_ro: &SchedulerState = state_clone.get();
175 if state_ro.get_running() {
176 let Some(window_value) = window() else {
177 return;
178 };
179 let cell: RafClosureCell = closure_cell_clone.clone();
180 let Some(raf_closure) = cell.try_get() else {
181 return;
182 };
183 let id: i32 = window_value
184 .request_animation_frame(raf_closure.as_ref().unchecked_ref())
185 .unwrap_or_default();
186 let state_ref_id: &mut SchedulerState = state_clone.get_mut();
187 state_ref_id.set_raf_id(Some(id));
188 }
189 }));
190 let Some(window_value) = window() else {
191 let state_ref_stop: &mut SchedulerState = state.get_mut();
194 state_ref_stop.set_running(false);
195 let _ = closure_cell.try_set(raf_closure);
196 return SchedulerHandle::new(state, closure_cell);
197 };
198 let id: i32 = window_value
199 .request_animation_frame(raf_closure.as_ref().unchecked_ref())
200 .unwrap_or_default();
201 let state_ref_id: &mut SchedulerState = state.get_mut();
202 state_ref_id.set_raf_id(Some(id));
203 let _ = closure_cell.try_set(raf_closure);
204 SchedulerHandle::new(state, closure_cell)
205 }
206}