use std::{
rc::Rc,
sync::atomic::{AtomicU64, Ordering},
time::*,
};
pub struct FramerateStabilizer {
framerate: u64,
start: Instant,
last_render: Instant,
rendered_frames: u64,
fps: Rc<AtomicU64>,
}
impl FramerateStabilizer {
pub fn new(framerate: u64) -> Self {
Self {
framerate,
start: Instant::now(),
last_render: Instant::now(),
rendered_frames: u64::MIN,
fps: Rc::new(AtomicU64::new(u64::MIN)),
}
}
pub fn render(&mut self, mut render_callback: impl FnMut()) -> bool {
let next_due = Duration::from_secs(1) / self.framerate as u32;
if self.last_render.elapsed() >= next_due {
let start = Instant::now();
render_callback();
self.last_render = start;
self.rendered_frames += 1;
self.fps.store(
Self::calc_fps(self.rendered_frames, &self.start),
Ordering::Relaxed,
);
true
}
else {
false
}
}
pub fn fps(&self) -> Rc<AtomicU64> {
self.fps.clone()
}
fn calc_fps(frames: u64, start_time: &Instant) -> u64 {
let mut elapsed = start_time.elapsed().as_secs();
if elapsed == 0 {
elapsed = 1;
}
frames / elapsed
}
}