summaryrefslogtreecommitdiff
path: root/graphics/src/timer.rs
blob: 9d4fcfccb8407a4f98cddd7bfb60f5a6d532bb8f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use std::time::{Duration, Instant};

/// Number of fps samples to store
const MAX_SAMPLES: usize = 100;

/// Keeps track of frame intervals and FPS
pub struct Timer {
	start: Instant,
	since_start: Duration,
	previous: Instant,
	tick_index: usize,
	tick_sum: Duration,
	tick_list: Box<[Duration; MAX_SAMPLES]>,
	frame: u32,
}
impl Timer {
	pub fn new() -> Self {
		let start = Instant::now();
		let since_start = Duration::ZERO;
		let previous = start;
		let tick_index = 0usize;
		let tick_sum = Duration::ZERO;
		let tick_list = Box::new([tick_sum; MAX_SAMPLES]);
		let frame = 0u32;

		Self {
			start,
			since_start,
			previous,
			tick_index,
			tick_sum,
			tick_list,
			frame,
		}
	}

	pub fn update(&mut self) {
		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 count
		self.frame += 1;

		// update since
		self.since_start = self.previous.duration_since(self.start);
	}

	pub const fn frame(&self) -> u32 {
		self.frame
	}

	#[expect(clippy::cast_possible_truncation)]
	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 const fn delta_time(&self) -> Duration {
		self.tick_list[self.tick_index]
	}

	pub const fn since_start(&self) -> Duration {
		self.since_start
	}
}