anvilkit_render/renderer/
debug.rs1use bevy_ecs::prelude::*;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub enum DebugMode {
26 None,
28 Wireframe,
30 Normals,
32 DiffuseOnly,
34 SpecularOnly,
36 Metallic,
38 Roughness,
40 AmbientOcclusion,
42 UVs,
44 Depth,
46}
47
48impl DebugMode {
49 pub fn is_normal(&self) -> bool {
51 matches!(self, DebugMode::None)
52 }
53}
54
55impl Default for DebugMode {
56 fn default() -> Self {
57 DebugMode::None
58 }
59}
60
61#[derive(Debug, Clone, Resource)]
75pub struct RenderStats {
76 pub draw_calls: u32,
78 pub triangles: u32,
80 pub vertices: u32,
82 pub active_lights: u32,
84 pub culled_objects: u32,
86 pub visible_objects: u32,
88 pub frame_time_ms: f32,
90 pub fps: f32,
92 pub gpu_memory_bytes: u64,
94}
95
96impl RenderStats {
97 pub fn new() -> Self {
98 Self {
99 draw_calls: 0,
100 triangles: 0,
101 vertices: 0,
102 active_lights: 0,
103 culled_objects: 0,
104 visible_objects: 0,
105 frame_time_ms: 0.0,
106 fps: 0.0,
107 gpu_memory_bytes: 0,
108 }
109 }
110
111 pub fn record_draw_call(&mut self, triangle_count: u32) {
113 self.draw_calls += 1;
114 self.triangles += triangle_count;
115 }
116
117 pub fn update_frame_time(&mut self, dt_seconds: f32) {
119 self.frame_time_ms = dt_seconds * 1000.0;
120 self.fps = if dt_seconds > 0.0 { 1.0 / dt_seconds } else { 0.0 };
121 }
122
123 pub fn reset_frame(&mut self) {
125 self.draw_calls = 0;
126 self.triangles = 0;
127 self.vertices = 0;
128 self.culled_objects = 0;
129 self.visible_objects = 0;
130 }
131
132 pub fn summary(&self) -> String {
134 format!(
135 "FPS: {:.0} | {:.1}ms | Draw: {} | Tri: {} | Vis: {}/{}",
136 self.fps, self.frame_time_ms,
137 self.draw_calls, self.triangles,
138 self.visible_objects, self.visible_objects + self.culled_objects,
139 )
140 }
141}
142
143impl Default for RenderStats {
144 fn default() -> Self {
145 Self::new()
146 }
147}
148
149#[derive(Debug, Clone, Resource)]
161pub struct DebugOverlay {
162 pub show_stats: bool,
164 pub show_wireframe: bool,
166 pub show_bounds: bool,
168 pub show_lights: bool,
170 pub show_skeleton: bool,
172 pub debug_mode: DebugMode,
174}
175
176impl Default for DebugOverlay {
177 fn default() -> Self {
178 Self {
179 show_stats: false,
180 show_wireframe: false,
181 show_bounds: false,
182 show_lights: false,
183 show_skeleton: false,
184 debug_mode: DebugMode::None,
185 }
186 }
187}
188
189#[cfg(test)]
190mod tests {
191 use super::*;
192
193 #[test]
194 fn test_debug_mode() {
195 assert!(DebugMode::None.is_normal());
196 assert!(!DebugMode::Wireframe.is_normal());
197 assert!(!DebugMode::Normals.is_normal());
198 }
199
200 #[test]
201 fn test_render_stats() {
202 let mut stats = RenderStats::new();
203 stats.record_draw_call(100);
204 stats.record_draw_call(50);
205 assert_eq!(stats.draw_calls, 2);
206 assert_eq!(stats.triangles, 150);
207
208 stats.update_frame_time(1.0 / 60.0);
209 assert!((stats.fps - 60.0).abs() < 1.0);
210
211 let summary = stats.summary();
212 assert!(summary.contains("FPS:"));
213 assert!(summary.contains("Draw: 2"));
214 }
215
216 #[test]
217 fn test_render_stats_reset() {
218 let mut stats = RenderStats::new();
219 stats.record_draw_call(100);
220 stats.visible_objects = 5;
221 stats.culled_objects = 3;
222
223 stats.reset_frame();
224 assert_eq!(stats.draw_calls, 0);
225 assert_eq!(stats.triangles, 0);
226 assert_eq!(stats.visible_objects, 0);
228 }
229
230 #[test]
231 fn test_debug_overlay_default() {
232 let overlay = DebugOverlay::default();
233 assert!(!overlay.show_stats);
234 assert!(overlay.debug_mode.is_normal());
235 }
236}