diff options
| author | Freya Murphy <freya@freyacat.org> | 2025-11-14 11:52:23 -0500 |
|---|---|---|
| committer | Freya Murphy <freya@freyacat.org> | 2025-11-14 11:52:23 -0500 |
| commit | 8543609a95eca8b7cb22bbef5633730d50d7b737 (patch) | |
| tree | 85ac9e4925030a9aae46703840a1a00ae30b8d90 | |
| parent | Remove wildcard exports/imports (diff) | |
| download | DungeonCrawl-8543609a95eca8b7cb22bbef5633730d50d7b737.tar.gz DungeonCrawl-8543609a95eca8b7cb22bbef5633730d50d7b737.tar.bz2 DungeonCrawl-8543609a95eca8b7cb22bbef5633730d50d7b737.zip | |
graphics: refactor timer
| -rw-r--r-- | graphics/src/lib.rs | 2 | ||||
| -rw-r--r-- | graphics/src/render.rs | 6 | ||||
| -rw-r--r-- | graphics/src/timer.rs | 94 |
3 files changed, 53 insertions, 49 deletions
diff --git a/graphics/src/lib.rs b/graphics/src/lib.rs index b42845c..d12eac0 100644 --- a/graphics/src/lib.rs +++ b/graphics/src/lib.rs @@ -203,7 +203,7 @@ impl Window { } /// Returns the per frame delta time - pub fn delta_time(&self) -> Duration { + pub const fn delta_time(&self) -> Duration { self.renderer.delta_time() } diff --git a/graphics/src/render.rs b/graphics/src/render.rs index dff09df..ba6cf81 100644 --- a/graphics/src/render.rs +++ b/graphics/src/render.rs @@ -207,7 +207,7 @@ impl Renderer { self.debug = !self.debug; } - pub fn delta_time(&self) -> Duration { + pub const fn delta_time(&self) -> Duration { self.timer.delta_time() } @@ -654,7 +654,7 @@ impl Renderer { let player = &dungeon.player; // Draw FPS - draw_text!(self, r, UI_COL1, UI_ROW1, "FPS {}", self.timer.get_fps()); + draw_text!(self, r, UI_COL1, UI_ROW1, "FPS {}", self.timer.fps()); // Draw Player position let (x, y) = &player.entity.pos.xy(); @@ -673,7 +673,7 @@ impl Renderer { draw_text!(self, r, UI_COL2, UI_ROW2, "{hash:016X}"); // Draw current frame number - let frame = self.timer.get_frame(); + let frame = self.timer.frame(); draw_text!(self, r, UI_COL2, UI_ROW3, "FRAME {frame}"); } diff --git a/graphics/src/timer.rs b/graphics/src/timer.rs index a8317c7..e2209c7 100644 --- a/graphics/src/timer.rs +++ b/graphics/src/timer.rs @@ -1,67 +1,71 @@ -use std::{ - ops::{Add, Div, Mul}, - time::{Duration, Instant}, -}; +use std::time::{Duration, Instant}; -/// How often to update the fps interval on screen -const FPS_INTERVAL: Duration = Duration::from_millis(250); - -/// How much to smooth he `delta_avg` amount (`AVG_RATIO`:1) -const AVG_RATIO: u32 = 10; +/// Number of fps samples to store +const MAX_SAMPLES: usize = 100; /// Keeps track of frame intervals and FPS pub struct Timer { - /// Last time updated previous: Instant, - /// Current time - now: Instant, - /// Rolling delta time average - delta_avg: Duration, - /// Computed fps - fps: f64, - /// Last time the fps was updated - fps_time: Instant, - /// Frame count - count: u32, + tick_index: usize, + tick_sum: Duration, + tick_list: Box<[Duration; MAX_SAMPLES]>, + frame: u32, } impl Timer { pub fn new() -> Self { - let now = Instant::now(); + let previous = Instant::now(); + let tick_index = 0usize; + let tick_sum = Duration::ZERO; + let tick_list = Box::new([tick_sum; MAX_SAMPLES]); + let frame = 0u32; + Self { - previous: now, - now, - delta_avg: Duration::ZERO, - fps: 0.0, - fps_time: now, - count: 0, + previous, + tick_index, + tick_sum, + tick_list, + frame, } } pub fn update(&mut self) { - self.previous = self.now; - self.now = Instant::now(); - self.delta_avg = self - .delta_avg - .mul(AVG_RATIO) - .add(self.delta_time()) - .div(AVG_RATIO + 1); - if (self.now - self.fps_time) > FPS_INTERVAL { - self.fps = 1.0 / self.delta_avg.as_secs_f64(); - self.fps_time = self.now; - } - self.count += 1; + let time = self.previous.elapsed(); + self.previous = Instant::now(); + + // caculate average tick + self.tick_index += 1; + self.tick_index %= MAX_SAMPLES; + self.tick_sum -= self.tick_list[self.tick_index]; + self.tick_sum += time; + self.tick_list[self.tick_index] = time; + + // update frame frame + self.frame += 1; } - pub const fn get_frame(&self) -> u32 { - self.count + pub const fn frame(&self) -> u32 { + self.frame } #[expect(clippy::cast_possible_truncation)] - pub fn get_fps(&self) -> u32 { - self.fps.ceil() as u32 + pub const fn fps(&self) -> u32 { + match self.frame_time().as_nanos() { + 0 => u32::MAX, + // fps can never be bigger than u32::MAX since we're + // computing in nanoseconds + nanos => 1_000_000_000u128.div_ceil(nanos) as u32, + } + } + + #[expect(clippy::cast_possible_truncation)] + pub const fn frame_time(&self) -> Duration { + match self.tick_sum.checked_div(MAX_SAMPLES as u32) { + Some(duration) => duration, + None => Duration::ZERO, + } } - pub fn delta_time(&self) -> Duration { - self.now - self.previous + pub const fn delta_time(&self) -> Duration { + self.tick_list[self.tick_index] } } |