mittens_engine/engine/ecs/component/
renderer_stats.rs1use crate::engine::ecs::ComponentId;
2use crate::engine::ecs::component::Component;
3use crate::engine::graphics::CameraTarget;
4
5#[derive(Debug, Clone)]
6pub struct RendererStatsComponent {
7 pub enabled: bool,
8
9 pub target: CameraTarget,
14
15 pub update_interval_sec: f32,
19
20 pub smoothing: f32,
25
26 pub color: [f32; 4],
28
29 pub emissive: bool,
31
32 component_id: Option<ComponentId>,
34 time_since_update_sec: f32,
35 smoothed_fps: Option<f32>,
36
37 text: Option<ComponentId>,
39 text_color: Option<ComponentId>,
40 text_emissive: Option<ComponentId>,
41}
42
43impl RendererStatsComponent {
44 pub fn new() -> Self {
45 Self {
46 enabled: true,
47 target: CameraTarget::Window,
48 update_interval_sec: 0.25,
49 smoothing: 0.9,
50 color: [1.0, 1.0, 1.0, 1.0],
51 emissive: true,
52
53 component_id: None,
54 time_since_update_sec: 0.0,
55 smoothed_fps: None,
56
57 text: None,
58 text_color: None,
59 text_emissive: None,
60 }
61 }
62
63 pub fn with_camera_target(mut self, target: CameraTarget) -> Self {
64 self.target = target;
65 self
66 }
67
68 pub fn id(&self) -> Option<ComponentId> {
69 self.component_id
70 }
71
72 pub fn accumulate_time(&mut self, dt_sec: f32) {
73 if !self.enabled {
74 return;
75 }
76 self.time_since_update_sec = (self.time_since_update_sec + dt_sec).max(0.0);
77 }
78
79 pub fn should_update(&self) -> bool {
80 if !self.enabled {
81 return false;
82 }
83 self.time_since_update_sec >= self.update_interval_sec.max(0.0)
84 }
85
86 pub fn reset_update_timer(&mut self) {
87 self.time_since_update_sec = 0.0;
88 }
89
90 pub fn smooth_fps(&mut self, fps: f32) -> f32 {
91 let fps = if fps.is_finite() { fps.max(0.0) } else { 0.0 };
92 let s = self.smoothing.clamp(0.0, 1.0);
93 let out = match self.smoothed_fps {
94 None => fps,
95 Some(prev) => prev * s + fps * (1.0 - s),
96 };
97 self.smoothed_fps = Some(out);
98 out
99 }
100
101 pub(crate) fn runtime_subtree_ids_mut(
102 &mut self,
103 ) -> (
104 &mut Option<ComponentId>,
105 &mut Option<ComponentId>,
106 &mut Option<ComponentId>,
107 ) {
108 (
109 &mut self.text,
110 &mut self.text_color,
111 &mut self.text_emissive,
112 )
113 }
114}
115
116impl Default for RendererStatsComponent {
117 fn default() -> Self {
118 Self::new()
119 }
120}
121
122impl Component for RendererStatsComponent {
123 fn name(&self) -> &'static str {
124 "renderer_stats"
125 }
126
127 fn set_id(&mut self, component: ComponentId) {
128 self.component_id = Some(component);
129 }
130
131 fn as_any(&self) -> &dyn std::any::Any {
132 self
133 }
134
135 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
136 self
137 }
138
139 fn to_mms_ast(
140 &self,
141 _world: &crate::engine::ecs::World,
142 ) -> crate::scripting::ast::ComponentExpression {
143 use crate::engine::ecs::component::ce_helpers::*;
144 let target_str = match self.target {
145 CameraTarget::Window => "Window",
146 CameraTarget::Xr => "Xr",
147 };
148 ce("RendererStats")
149 .with_call("enabled", vec![b(self.enabled)])
150 .with_call("camera_target", vec![s(target_str)])
151 .with_call(
152 "update_interval_sec",
153 vec![num(self.update_interval_sec as f64)],
154 )
155 .with_call("smoothing", vec![num(self.smoothing as f64)])
156 .with_call(
157 "color",
158 vec![array(nums(self.color.iter().map(|&v| v as f64)))],
159 )
160 .with_call("emissive", vec![b(self.emissive)])
161 }
162}