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
//! # GUI
//!
//! The `gui` module provides utilities for common GUI elements. Currently, it includes an
//! [`FPSCounter`] that provides the user easy access to the application framerate without them
//! needing to make any time calculations.
//!
//! More examples of use of the [`FPSCounter`] can be found in the
//! [examples](https://github.com/lemunozm/ruscii/tree/master/examples) folder of the
//! [`ruscii`](https://github.com/lemunozm/ruscii) repository.

use std::time::SystemTime;

/// A struct that provides access to the application's framerate.
///
/// This FPS counter does not update automatically. [`FPSCounter::update`] should be called
/// to update the FPS for every frame, i.e., in the `frame_action` function parameter of
/// [`App::run`](super::app::App::run).
///
/// The FPS value can be obtained by calling [`FPSCounter::count`].
///
/// ## Example
///
/// ```rust,no_run
/// # use ruscii::app::{App, State};
/// # use ruscii::terminal::Window;
/// # use ruscii::drawing::{Pencil};
/// # use ruscii::spatial::{Vec2};
/// # use ruscii::gui::{FPSCounter};
///
/// let mut app = App::default();
/// let mut fps_counter = FPSCounter::default();
///
/// app.run(|app_state: &mut State, window: &mut Window| {
///     fps_counter.update();  // Updates the FPS
///
///     let mut pencil = Pencil::new(window.canvas_mut());
///     pencil.draw_text(
///         &format!("FPS: {}", fps_counter.count()),  // Draws the FPS
///         Vec2::xy(1, 0)
///     );
/// });
/// ```
#[derive(Default)]
pub struct FPSCounter {
    fps: u32,
    fps_time_stamp: u128,
    frame_counter: u32,
}

impl FPSCounter {
    /// Retrieves the framerate and updates the [`FPSCounter`].
    pub fn update(&mut self) {
        let current_time = SystemTime::now()
            .duration_since(SystemTime::UNIX_EPOCH)
            .unwrap()
            .as_micros();
        self.frame_counter += 1;
        if current_time - self.fps_time_stamp > 1000000 {
            self.fps = self.frame_counter;
            self.fps_time_stamp = current_time;
            self.frame_counter = 0;
        }
    }

    /// Returns the framerate.
    pub fn count(&self) -> u32 {
        self.fps
    }
}