utils/
fps.rs

1//!
2//!  fps.rs
3//!
4//!  Created by Mitchell Nordine at 08:31PM on February 02, 2015.
5//!
6//!
7
8use std;
9use time;
10
11/// A signal that returns delta time at a rate so that
12/// there are `fps` frames per seconds.
13#[derive(Copy, Clone)]
14pub struct Fps {
15    fps: f64,
16    last_ns: u64,
17    high_priority: bool,
18}
19
20impl Fps {
21
22    /// Construct a new Fps struct with a maximum `frames_per_sec`.
23    pub fn new(fps: f64) -> Fps {
24        assert!(fps > 0.0, "The given frames per seconds must be greater than 0.");
25        Fps { fps: fps, last_ns: time::precise_time_ns(), high_priority: false }
26    }
27
28    /// A builder method for constructing a high priority Fps signal.
29    /// This will consume more cpu but will result in a far more accurate frame rate.
30    pub fn high_priority(self) -> Fps {
31        Fps { high_priority: true, ..self }
32    }
33
34    /// Return the time since the last frame.
35    #[inline]
36    pub fn frame_ns(&self) -> u64 { (BILLION / self.fps) as u64 }
37
38    /// Return the dt in nanoseconds for the given t in nanoseconds
39    #[inline]
40    pub fn get_dt_ns(&self, t: u64) -> u64 {
41        if t >= self.last_ns {
42            t - self.last_ns
43        } else {
44            use std::u64::MAX;
45            (MAX - self.last_ns) + t
46        }
47    }
48
49}
50
51const BILLION: f64 = 1_000_000_000.0;
52pub type DeltaSecs = f64;
53
54/// Convert nanoseconds to seconds.
55#[inline]
56fn ns_to_secs(n: u64) -> f64 { n as f64 / BILLION }
57
58impl Iterator for Fps {
59    type Item = DeltaSecs;
60    fn next(&mut self) -> Option<DeltaSecs> {
61        let frame_ns = self.frame_ns();
62        let t_ns = time::precise_time_ns();
63        let dt_ns = self.get_dt_ns(t_ns);
64        if dt_ns >= frame_ns {
65            self.last_ns = t_ns;
66            Some(ns_to_secs(dt_ns))
67        }
68        else {
69            if !self.high_priority {
70                // NOTE: Should sleep in nanoseconds and not convert to milliseconds!
71                let ms = ((frame_ns - dt_ns) as u64) / 1_000_000;
72                std::thread::sleep(std::time::Duration::from_millis(ms));
73            }
74            let mut t_ns = time::precise_time_ns();
75            let mut dt_ns = self.get_dt_ns(t_ns);
76            while dt_ns < frame_ns {
77                t_ns = time::precise_time_ns();
78                dt_ns = self.get_dt_ns(t_ns);
79            }
80            self.last_ns = t_ns;
81            Some(ns_to_secs(dt_ns))
82        }
83    }
84}
85