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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//! Implements bones egui debug windows and tools.

use crate::prelude::*;

/// Track frame time state synced from bevy frame time diagnostics for bones app.
#[derive(HasSchema, Clone)]
#[allow(missing_docs)]
pub struct FrameDiagState {
    pub fps: f64,
    pub fps_avg: f64,
    pub min_fps: f64,
    pub max_fps: f64,
    pub frame_time: f64,
    pub frame_time_avg: f64,
    pub min_frame_time: f64,
    pub max_frame_time: f64,
}

impl Default for FrameDiagState {
    fn default() -> Self {
        Self {
            fps: 0.0,
            fps_avg: 0.0,
            min_fps: f64::MAX,
            max_fps: 0.0,
            frame_time: 0.0,
            frame_time_avg: 0.0,
            min_frame_time: f64::MAX,
            max_frame_time: 0.0,
        }
    }
}

impl FrameDiagState {
    /// Reset min/max values to default
    pub fn reset(&mut self) {
        self.min_fps = f64::MAX;
        self.max_fps = 0.0;
        self.min_frame_time = f64::MAX;
        self.max_frame_time = 0.0;
    }
}

/// State of frame time diagnostic window. Stored in [`EguiCtx`] state,
/// setting open = true will open window if plugin installed.
#[derive(Clone, Default)]
pub struct FrameTimeWindowState {
    /// Is window open?
    pub open: bool,
}

/// If installed, allows opening egui window with [`FrameTimeWindowState`] in [`EguiCtx`] state
/// to get frame time information.
pub fn frame_time_diagnostics_plugin(core: &mut Session) {
    core.stages
        .add_system_to_stage(CoreStage::Last, frame_diagnostic_window);
}

/// Renders frame time diagnostic window in Egui if window is set to open in [`FrameTimeWindowState`]
/// stored in [`EguiCtx`] state.
pub fn frame_diagnostic_window(
    mut state: Option<ResMut<FrameDiagState>>,
    // localization: Res<Localization>,
    egui_ctx: ResMut<EguiCtx>,
) {
    let mut window_state = egui_ctx.get_state::<FrameTimeWindowState>();
    let window_open = &mut window_state.open;

    if *window_open {
        // egui::Window::new(&localization.get("frame-diagnostics"))
        egui::Window::new("Frame Diagnostics")
            .id(egui::Id::new("frame_diagnostics"))
            .default_width(500.0)
            .open(window_open)
            .show(&egui_ctx, |ui| {
                if let Some(state) = state.as_mut() {
                    // if ui.button(&localization.get("reset-min-max")).clicked() {
                    if ui.button("Reset Min/Max").clicked() {
                        state.reset();
                    }

                    ui.monospace(&format!(
                        "{label:20}: {fps:4.0}{suffix:3} ( {min:4.0}{suffix:3}, {avg:4.0}{suffix:3}, {max:4.0}{suffix:3} )",
                        // label = localization.get("frames-per-second"),
                        label = "Frames Per Second",
                        fps = state.fps,
                        // suffix = fps.suffix,
                        suffix = "fps",
                        min = state.min_fps,
                        avg = state.fps_avg,
                        max = state.max_fps,
                    ));
                    ui.monospace(&format!(
                        "{label:20}: {fps:4.1}{suffix:3} ( {min:4.1}{suffix:3}, {avg:4.0}{suffix:3}, {max:4.1}{suffix:3} )",
                        // label = localization.get("frame-time"),
                        label = "Frame Time",
                        fps = state.frame_time,
                        suffix = "ms",
                        min = state.min_frame_time,
                        avg = state.frame_time_avg,
                        max = state.max_frame_time,
                    ));
                }
                else {
                    ui.monospace(
                        "No frame time data from Bevy diagnostics.",
                    );
                }
            });
    }

    egui_ctx.set_state(window_state);
}