#![deny(missing_docs)]
#![deny(missing_copy_implementations)]
extern crate time;
extern crate current;
use std::io::timer::sleep;
use std::time::duration::Duration;
use current::{ Current, Get, Modifier, Set };
use std::cmp;
use std::cell::RefCell;
#[deriving(Copy)]
pub struct ShouldClose(pub bool);
pub trait GetShouldClose: Get<ShouldClose> {
fn get_should_close(&self) -> ShouldClose {
self.get()
}
}
impl<T: Get<ShouldClose>> GetShouldClose for T {}
pub trait SetShouldClose: Set<ShouldClose> {
fn set_should_close(&mut self, val: ShouldClose) {
self.set_mut(val);
}
}
impl<T: Set<ShouldClose>> SetShouldClose for T {}
#[deriving(Copy)]
pub struct Size(pub [u32, ..2]);
pub trait GetSize: Get<Size> {
fn get_size(&self) -> Size {
self.get()
}
}
impl<T: Get<Size>> GetSize for T {}
pub trait SetSize: Set<Size> {
fn set_size(&mut self, val: Size) {
self.set_mut(val);
}
}
impl<T: Set<Size>> SetSize for T {}
pub trait SwapBuffers {
fn swap_buffers(&mut self);
}
impl<W: SwapBuffers> SwapBuffers for Current<W> {
#[inline(always)]
fn swap_buffers(&mut self) {
self.deref_mut().swap_buffers();
}
}
impl<'a, W: 'a + SwapBuffers> SwapBuffers for &'a RefCell<W> {
#[inline(always)]
fn swap_buffers(&mut self) {
self.borrow_mut().deref_mut().swap_buffers()
}
}
pub trait PollEvent<E> {
fn poll_event(&mut self) -> Option<E>;
}
impl<W: PollEvent<I>, I> PollEvent<I> for Current<W> {
fn poll_event(&mut self) -> Option<I> {
self.deref_mut().poll_event()
}
}
impl<'a, W: 'a + PollEvent<I>, I> PollEvent<I> for &'a RefCell<W> {
#[inline(always)]
fn poll_event(&mut self) -> Option<I> {
self.borrow_mut().deref_mut().poll_event()
}
}
#[deriving(Copy, Clone, PartialEq, Show)]
pub struct RenderArgs {
pub ext_dt: f64,
pub width: u32,
pub height: u32,
}
#[deriving(Copy, Clone, PartialEq, Show)]
pub struct UpdateArgs {
pub dt: f64,
}
pub trait EventMap<I> {
fn render(args: RenderArgs) -> Self;
fn update(args: UpdateArgs) -> Self;
fn input(args: I) -> Self;
}
#[deriving(Copy, Show)]
enum State {
Render,
SwapBuffers,
UpdateLoop,
HandleEvents,
Update,
}
#[deriving(Copy)]
pub struct Ups(pub u64);
impl<W> Modifier<Events<W>> for Ups {
fn modify(self, events: &mut Events<W>) {
let Ups(frames) = self;
events.dt_update_in_ns = BILLION / frames;
}
}
pub trait SetUps: Set<Ups> {
fn set_ups(&mut self, val: Ups) {
self.set_mut(val);
}
}
impl<T: Set<Ups>> SetUps for T {}
#[deriving(Copy)]
pub struct MaxFps(pub u64);
impl<W> Modifier<Events<W>> for MaxFps {
fn modify(self, events: &mut Events<W>) {
let MaxFps(frames) = self;
events.dt_frame_in_ns = BILLION / frames;
}
}
pub trait SetMaxFps: Set<MaxFps> {
fn set_max_fps(&mut self, val: MaxFps) {
self.set_mut(val);
}
}
impl<T: Set<MaxFps>> SetMaxFps for T {}
pub trait EventWindow<I>:
PollEvent<I>
+ GetShouldClose
+ GetSize
+ SwapBuffers {}
impl<T: PollEvent<I> + GetShouldClose + GetSize + SwapBuffers, I>
EventWindow<I> for T {}
pub struct Events<W> {
pub window: W,
state: State,
last_update: u64,
last_frame: u64,
dt_update_in_ns: u64,
dt_frame_in_ns: u64,
dt: f64,
}
static BILLION: u64 = 1_000_000_000;
pub const DEFAULT_UPS: Ups = Ups(120);
pub const DEFAULT_MAX_FPS: MaxFps = MaxFps(60);
impl<W: EventWindow<I>, I> Events<W> {
pub fn new(window: W) -> Events<W> {
let start = time::precise_time_ns();
let Ups(updates_per_second) = DEFAULT_UPS;
let MaxFps(max_frames_per_second) = DEFAULT_MAX_FPS;
Events {
window: window,
state: State::Render,
last_update: start,
last_frame: start,
dt_update_in_ns: BILLION / updates_per_second,
dt_frame_in_ns: BILLION / max_frames_per_second,
dt: 1.0 / updates_per_second as f64,
}
}
}
impl<W: EventWindow<I>, I, E: EventMap<I>>
Iterator<E>
for Events<W> {
fn next(&mut self) -> Option<E> {
loop {
self.state = match self.state {
State::Render => {
let ShouldClose(should_close) = self.window.get_should_close();
if should_close { return None; }
let start_render = time::precise_time_ns();
self.last_frame = start_render;
let Size([w, h]) = self.window.get_size();
if w != 0 && h != 0 {
self.state = State::SwapBuffers;
return Some(EventMap::render(RenderArgs {
ext_dt: (start_render - self.last_update) as f64
/ BILLION as f64,
width: w,
height: h,
}));
}
State::UpdateLoop
}
State::SwapBuffers => {
self.window.swap_buffers();
State::UpdateLoop
}
State::UpdateLoop => {
let current_time = time::precise_time_ns();
let next_frame = self.last_frame + self.dt_frame_in_ns;
let next_update = self.last_update + self.dt_update_in_ns;
let next_event = cmp::min(next_frame, next_update);
if next_event > current_time {
sleep( Duration::nanoseconds((next_event - current_time) as i64) );
State::UpdateLoop
} else if next_event == next_frame {
State::Render
} else {
State::HandleEvents
}
}
State::HandleEvents => {
match self.window.poll_event() {
None => State::Update,
Some(x) => { return Some(EventMap::input(x)); },
}
}
State::Update => {
self.state = State::UpdateLoop;
self.last_update += self.dt_update_in_ns;
return Some(EventMap::update(UpdateArgs{ dt: self.dt }));
}
};
}
}
}