Skip to main content

dreamwell_runtime/
time.rs

1// Frame timing — fixed timestep, delta time, FPS tracking.
2
3use std::time::Instant;
4
5/// Frame timer with delta time and FPS tracking.
6pub struct FrameTimer {
7    last_frame: Instant,
8    delta: f32,
9    fps: f32,
10    frame_count: u64,
11}
12
13impl Default for FrameTimer {
14    fn default() -> Self {
15        Self::new()
16    }
17}
18
19impl FrameTimer {
20    pub fn new() -> Self {
21        Self {
22            last_frame: Instant::now(),
23            delta: 0.0,
24            fps: 0.0,
25            frame_count: 0,
26        }
27    }
28
29    /// Call once per frame to update timing.
30    pub fn tick(&mut self) {
31        let now = Instant::now();
32        self.delta = now.duration_since(self.last_frame).as_secs_f32();
33        self.last_frame = now;
34        self.frame_count += 1;
35
36        // Clamp delta to avoid division by zero or Inf propagation.
37        // Upper bound of 50ms prevents spiral-of-death on hitches.
38        let dt = self.delta.clamp(0.0001, 0.05);
39
40        // Exponential moving average FPS
41        let instant_fps = 1.0 / dt;
42        let new_fps = self.fps * 0.95 + instant_fps * 0.05;
43        if new_fps.is_finite() {
44            self.fps = new_fps.clamp(0.0, 1000.0);
45        }
46    }
47
48    /// Seconds since last frame.
49    pub fn delta_time(&self) -> f32 {
50        self.delta
51    }
52
53    /// Smoothed frames per second.
54    pub fn fps(&self) -> f32 {
55        self.fps
56    }
57
58    /// Total frames rendered.
59    pub fn frame_count(&self) -> u64 {
60        self.frame_count
61    }
62}