com_croftsoft_lib_animation/frame_rater/simple/
mod.rs

1// =============================================================================
2//! - Simple Frame Rater
3//!
4//! # Metadata
5//! - Copyright: © 2023 [`CroftSoft Inc`]
6//! - Author: [`David Wallace Croft`]
7//! - Created: 2023-03-01
8//! - Updated: 2023-03-01
9//!
10//! [`CroftSoft Inc`]: https://www.croftsoft.com/
11//! [`David Wallace Croft`]: https://www.croftsoft.com/people/david/
12// =============================================================================
13
14use super::FrameRater;
15use std::collections::VecDeque;
16
17const FRAME_SAMPLE_SIZE_MAX: usize = 1_000;
18const MILLIS_PER_SECOND: f64 = 1_000.;
19const SAMPLE_TIME_MILLIS: f64 = 1_000.;
20
21pub struct SimpleFrameRater {
22  frame_rate: f64,
23  frame_sample_size_target: usize,
24  update_time_millis_next: f64,
25  update_times: VecDeque<f64>,
26}
27
28impl SimpleFrameRater {
29  fn calculate_frame_sample_size_target(frame_period_millis: f64) -> usize {
30    let mut frame_sample_size = if frame_period_millis > 0. {
31      (SAMPLE_TIME_MILLIS / frame_period_millis) as usize
32    } else {
33      FRAME_SAMPLE_SIZE_MAX
34    };
35    if frame_sample_size < 1 {
36      frame_sample_size = 1;
37    } else if frame_sample_size > FRAME_SAMPLE_SIZE_MAX {
38      frame_sample_size = FRAME_SAMPLE_SIZE_MAX;
39    }
40    frame_sample_size
41  }
42
43  pub fn new(frame_period_millis_target: f64) -> Self {
44    let mut frame_rater = Self {
45      frame_rate: 0.,
46      frame_sample_size_target: 0,
47      update_time_millis_next: 0.,
48      update_times: VecDeque::new(),
49    };
50    frame_rater.update_frame_sample_size(frame_period_millis_target);
51    frame_rater
52  }
53}
54
55impl FrameRater for SimpleFrameRater {
56  fn clear(&mut self) {
57    self.update_times.clear();
58    self.frame_rate = 0.;
59  }
60
61  fn get_frames_per_second_sampled(&self) -> f64 {
62    self.frame_rate
63  }
64
65  fn sample(
66    &mut self,
67    update_time_millis: f64,
68  ) -> bool {
69    let deltas = self.update_times.len();
70    self.update_times.push_back(update_time_millis);
71    if deltas < 1 {
72      return false;
73    }
74    let mut frame_sample_size = self.frame_sample_size_target;
75    if frame_sample_size > deltas {
76      frame_sample_size = deltas;
77    }
78    let index = deltas - frame_sample_size;
79    let first_update_time = self.update_times[index];
80    let delta = update_time_millis - first_update_time;
81    self.frame_rate = frame_sample_size as f64 * MILLIS_PER_SECOND / delta;
82    if deltas >= FRAME_SAMPLE_SIZE_MAX {
83      self.update_times.pop_front();
84    }
85    false
86  }
87
88  fn update_frame_sample_size(
89    &mut self,
90    frame_period_millis: f64,
91  ) {
92    let adjusted_frame_period_millis: f64 = if frame_period_millis < 0. {
93      0.
94    } else {
95      frame_period_millis
96    };
97    self.update_time_millis_next = 0.;
98    self.frame_sample_size_target =
99      Self::calculate_frame_sample_size_target(adjusted_frame_period_millis);
100    self.update_times.clear();
101    self.frame_rate = 0.;
102  }
103}