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
extern crate failure; #[macro_use] extern crate log; extern crate winit; mod action; mod ticker; use std::collections::BinaryHeap; use std::sync::mpsc; use std::time::{Duration, Instant}; use std::{cmp, thread}; use winit::{ControlFlow, DeviceEvent, Event, EventsLoop, EventsLoopProxy, WindowEvent}; use self::action::Action; use self::ticker::Ticker; pub trait App: Sized { const UPDATES_PER_SECOND: u32; const RENDERS_PER_SECOND: u32; fn update(&mut self, dt: Duration); fn render(&mut self, dt: Duration); fn window_event(&mut self, event: WindowEvent) -> ControlFlow; fn device_event(&mut self, event: DeviceEvent) -> ControlFlow; } pub enum AppState { Continue, Quit, } pub fn run<A, F>(build: F) where A: App, F: FnOnce(&EventsLoop) -> A, { let mut events_loop = EventsLoop::new(); let mut app = build(&events_loop); const SECOND: Duration = Duration::from_secs(1); let intervals: [Duration; Action::COUNT] = [ SECOND / A::UPDATES_PER_SECOND, SECOND / A::RENDERS_PER_SECOND, SECOND, ]; let (tx, rx) = mpsc::channel(); let proxy = events_loop.create_proxy(); thread::spawn(move || wakeup(proxy, tx, &intervals)); let mut update_ticker = Ticker::new(); let mut render_ticker = Ticker::new(); events_loop.run_forever(|event| match event { Event::WindowEvent { event, .. } => app.window_event(event), Event::DeviceEvent { event, .. } => app.device_event(event), Event::Awakened => { let (deadline, action) = rx.recv().unwrap(); if deadline < Instant::now() { trace!("Skipping action {:?}.", action); } else { match action { Action::Update => app.update(update_ticker.tick()), Action::Render => app.render(render_ticker.tick()), Action::Log => { info!("Updates per second: {}.", update_ticker.split()); info!("Renders per second: {}.", render_ticker.split()); } } } ControlFlow::Continue } Event::Suspended(_) => ControlFlow::Continue, }) } fn wakeup( proxy: EventsLoopProxy, tx: mpsc::Sender<(Instant, Action)>, intervals: &[Duration; Action::COUNT], ) { if intervals.len() > 0 { let mut heap: BinaryHeap<_> = Action::values() .map(|action| (Instant::now(), action)) .map(cmp::Reverse) .collect(); loop { let cmp::Reverse((time, action)) = heap.pop().unwrap(); let next = time + intervals[action as usize]; heap.push(cmp::Reverse((next, action))); let now = Instant::now(); if now < time { thread::sleep(time - now); } if let Err(_) = tx.send((next, action)) { return; } if let Err(_) = proxy.wakeup() { return; } } } }