est_render/math/
timing.rs

1use std::{
2    thread,
3    time::{Duration, Instant},
4};
5
6// Based on: https://stackoverflow.com/a/33554241
7// Totally obscure and not very well explained, but it works.
8// I'm not sure if it's the best way to do it, but it's the only way I found.
9#[derive(Debug, Clone)]
10pub struct Timing {
11    fps: u32,
12    fps_start_time: Instant,
13    fps_frame_count: u32,
14
15    last_time: Instant,
16    frame_time: f64,
17}
18
19impl Timing {
20    pub fn new(tick_rate: u32) -> Timing {
21        Timing {
22            fps: tick_rate as u32,
23            fps_start_time: Instant::now(),
24            fps_frame_count: 0,
25            frame_time: 0.0,
26            last_time: Instant::now(),
27        }
28    }
29
30    pub fn sleep(&mut self) {
31        if self.fps > 60 {
32            let freq = 1_000_000_000; // Nanoseconds per second
33            let mut frame = Instant::now();
34
35            while (frame.duration_since(self.fps_start_time).as_nanos() as u64 * self.fps as u64)
36                < (freq * self.fps_frame_count as u64)
37            {
38                let sleep_time = ((self.fps_start_time.elapsed().as_nanos() as u64
39                    * self.fps as u64
40                    + freq * self.fps_frame_count as u64
41                    - frame.elapsed().as_nanos() as u64 * self.fps as u64)
42                    * 1_000
43                    / (freq * self.fps as u64)) as u64;
44
45                if sleep_time > 0 {
46                    thread::sleep(Duration::from_millis(sleep_time / 1_000_000));
47                }
48
49                frame = Instant::now();
50            }
51
52            self.fps_frame_count += 1;
53            if self.fps_frame_count > self.fps || self.fps_start_time.elapsed().as_secs() >= 1 {
54                self.fps_frame_count = 1;
55                self.fps_start_time = Instant::now();
56            }
57
58            let delta_in_seconds = self.last_time.elapsed().as_secs_f64();
59            self.last_time = Instant::now();
60            self.frame_time = delta_in_seconds;
61        } else {
62            let delta_in_seconds = self.last_time.elapsed().as_secs_f64();
63            self.last_time = Instant::now();
64            self.frame_time = delta_in_seconds;
65
66            if self.fps > 0 {
67                let sleep_time = (1.0 / self.fps as f64 - delta_in_seconds) * 1_000_000_000.0;
68                if sleep_time > 0.0 {
69                    thread::sleep(Duration::from_nanos(sleep_time as u64));
70                }
71            }
72        }
73    }
74
75    pub fn get_fps(&self) -> u32 {
76        (1.0 / self.frame_time) as u32
77    }
78
79    pub fn set_fps(&mut self, fps: u32) {
80        self.fps = fps;
81    }
82
83    pub fn get_frame_time(&self) -> f64 {
84        self.frame_time
85    }
86}