lime-main-loop 0.1.0

Main loop.
Documentation
extern crate failure;
#[macro_use]
extern crate log;
extern crate winit;

use std::time::{Duration, Instant};
use std::thread;
use log::LogLevel;
use winit::{WindowEvent, DeviceEvent};

pub trait App {
    const UPDATES_PER_SECOND: u64;

    fn update(&mut self, dt: Duration);

    fn window_event(&mut self, event: WindowEvent) -> bool;
    fn device_event(&mut self, event: DeviceEvent) -> bool;
}

pub fn run<A: App>(mut app: A, mut events_loop: winit::EventsLoop) {
    let proxy = events_loop.create_proxy();
    thread::spawn(move || {
        let dt = Duration::from_millis(1_000 / A::UPDATES_PER_SECOND);
        loop {
            thread::sleep(dt);
            proxy.wakeup().ok();
        }
    });

    let mut last_update = Instant::now();
    let mut next_second = last_update + Duration::from_secs(1);
    let mut update_count = 0;
    let mut events_queue = Vec::new();
    loop {
        events_loop.poll_events(|event| events_queue.push(event));

        let mut update = false;
        for event in events_queue.drain(..) {
            use winit::Event::*;

            match event {
                WindowEvent { event, .. } => update |= app.window_event(event),
                DeviceEvent { event, .. } => update |= app.device_event(event),
                Awakened => update = true,
                Suspended(_) => (),
            };
        }

        if update {
            let now = Instant::now();
            app.update(now - last_update);
            last_update = now;

            if log_enabled!(LogLevel::Info) {
                if next_second < now {
                    next_second += Duration::from_secs(1);
                    info!("Updates per second: {}. (Target: {})", update_count, A::UPDATES_PER_SECOND);
                    update_count = 0;
                }
                update_count += 1;
            }
        }
    }
}