• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Xevion / Pac-Man / 17075858891

19 Aug 2025 04:31PM UTC coverage: 51.198% (-0.4%) from 51.621%
17075858891

push

github

Xevion
refactor: update debug state management and rendering systems

1 of 75 new or added lines in 4 files covered. (1.33%)

4 existing lines in 2 files now uncovered.

1047 of 2045 relevant lines covered (51.2%)

1101.58 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/systems/debug.rs
1
//! Debug rendering system
2
use std::cmp::Ordering;
3

4
use crate::constants::BOARD_PIXEL_OFFSET;
5
use crate::map::builder::Map;
6
use crate::systems::components::Collider;
7
use crate::systems::input::CursorPosition;
8
use crate::systems::movement::Position;
9
use crate::systems::profiling::SystemTimings;
10
use crate::systems::render::BackbufferResource;
11
use bevy_ecs::prelude::*;
12
use glam::{IVec2, UVec2, Vec2};
13
use sdl2::pixels::Color;
14
use sdl2::rect::{Point, Rect};
15
use sdl2::render::{Canvas, Texture, TextureCreator};
16
use sdl2::ttf::Font;
17
use sdl2::video::{Window, WindowContext};
18

19
#[derive(Resource, Default, Debug, Copy, Clone)]
20
pub struct DebugState {
21
    pub enabled: bool,
22
}
23

NEW
24
fn f32_to_u8(value: f32) -> u8 {
×
NEW
25
    (value * 255.0) as u8
×
UNCOV
26
}
×
27

28
/// Resource to hold the debug texture for persistent rendering
29
pub struct DebugTextureResource(pub Texture<'static>);
30

31
/// Resource to hold the debug font
32
pub struct DebugFontResource(pub Font<'static, 'static>);
33

34
/// Transforms a position from logical canvas coordinates to output canvas coordinates (with board offset)
35
fn transform_position_with_offset(pos: Vec2, scale: f32) -> IVec2 {
×
36
    ((pos + BOARD_PIXEL_OFFSET.as_vec2()) * scale).as_ivec2()
×
37
}
×
38

39
/// Renders timing information in the top-left corner of the screen
40
fn render_timing_display(
×
41
    canvas: &mut Canvas<Window>,
×
42
    texture_creator: &mut TextureCreator<WindowContext>,
×
43
    timings: &SystemTimings,
×
44
    font: &Font,
×
45
) {
×
46
    // Format timing information using the formatting module
×
47
    let lines = timings.format_timing_display();
×
48
    let line_height = 14; // Approximate line height for 12pt font
×
49
    let padding = 10;
×
50

×
51
    // Calculate background dimensions
×
52
    let max_width = lines
×
53
        .iter()
×
54
        .filter(|l| !l.is_empty()) // Don't consider empty lines for width
×
55
        .map(|line| font.size_of(line).unwrap().0)
×
56
        .max()
×
57
        .unwrap_or(0);
×
58

×
59
    // Only draw background if there is text to display
×
60
    if max_width > 0 {
×
61
        let total_height = (lines.len() as u32) * line_height as u32;
×
62
        let bg_padding = 5;
×
63

×
64
        // Draw background
×
65
        let bg_rect = Rect::new(
×
66
            padding - bg_padding,
×
67
            padding - bg_padding,
×
68
            max_width + (bg_padding * 2) as u32,
×
69
            total_height + bg_padding as u32,
×
70
        );
×
71
        canvas.set_blend_mode(sdl2::render::BlendMode::Blend);
×
72
        canvas.set_draw_color(Color::RGBA(40, 40, 40, 180));
×
73
        canvas.fill_rect(bg_rect).unwrap();
×
74
    }
×
75

76
    for (i, line) in lines.iter().enumerate() {
×
77
        if line.is_empty() {
×
78
            continue;
×
79
        }
×
80

×
81
        // Render each line
×
82
        let surface = font.render(line).blended(Color::RGBA(255, 255, 255, 200)).unwrap();
×
83
        let texture = texture_creator.create_texture_from_surface(&surface).unwrap();
×
84

×
85
        // Position each line below the previous one
×
86
        let y_pos = padding + (i * line_height) as i32;
×
87
        let dest = Rect::new(padding, y_pos, texture.query().width, texture.query().height);
×
88
        canvas.copy(&texture, None, dest).unwrap();
×
89
    }
90
}
×
91

92
#[allow(clippy::too_many_arguments)]
93
pub fn debug_render_system(
×
94
    mut canvas: NonSendMut<&mut Canvas<Window>>,
×
95
    backbuffer: NonSendMut<BackbufferResource>,
×
96
    mut debug_texture: NonSendMut<DebugTextureResource>,
×
97
    debug_font: NonSendMut<DebugFontResource>,
×
98
    debug_state: Res<DebugState>,
×
99
    timings: Res<SystemTimings>,
×
100
    map: Res<Map>,
×
101
    colliders: Query<(&Collider, &Position)>,
×
102
    cursor: Res<CursorPosition>,
×
103
) {
×
NEW
104
    if !debug_state.enabled {
×
105
        return;
×
106
    }
×
107
    let scale =
×
108
        (UVec2::from(canvas.output_size().unwrap()).as_vec2() / UVec2::from(canvas.logical_size()).as_vec2()).min_element();
×
109

×
110
    // Copy the current backbuffer to the debug texture
×
111
    canvas
×
112
        .with_texture_canvas(&mut debug_texture.0, |debug_canvas| {
×
113
            // Clear the debug canvas
×
114
            debug_canvas.set_draw_color(Color::BLACK);
×
115
            debug_canvas.clear();
×
116

×
117
            // Copy the backbuffer to the debug canvas
×
118
            debug_canvas.copy(&backbuffer.0, None, None).unwrap();
×
119
        })
×
120
        .unwrap();
×
121

×
122
    // Get texture creator before entering the closure to avoid borrowing conflicts
×
123
    let mut texture_creator = canvas.texture_creator();
×
124
    let font = &debug_font.0;
×
125

126
    let cursor_world_pos = match *cursor {
×
127
        CursorPosition::None => None,
×
128
        CursorPosition::Some { position, .. } => Some(position - BOARD_PIXEL_OFFSET.as_vec2()),
×
129
    };
130

131
    // Draw debug info on the high-resolution debug texture
132
    canvas
×
133
        .with_texture_canvas(&mut debug_texture.0, |debug_canvas| {
×
134
            // Find the closest node to the cursor
135

NEW
136
            let closest_node = if let Some(cursor_world_pos) = cursor_world_pos {
×
NEW
137
                map.graph
×
NEW
138
                    .nodes()
×
NEW
139
                    .map(|node| node.position.distance(cursor_world_pos))
×
NEW
140
                    .enumerate()
×
NEW
141
                    .min_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap_or(Ordering::Less))
×
NEW
142
                    .map(|(id, _)| id)
×
143
            } else {
NEW
144
                None
×
145
            };
146

NEW
147
            debug_canvas.set_draw_color(Color::GREEN);
×
NEW
148
            for (collider, position) in colliders.iter() {
×
NEW
149
                let pos = position.get_pixel_position(&map.graph).unwrap();
×
NEW
150

×
NEW
151
                // Transform position and size using common methods
×
NEW
152
                let pos = (pos * scale).as_ivec2();
×
NEW
153
                let size = (collider.size * scale) as u32;
×
NEW
154

×
NEW
155
                let rect = Rect::from_center(Point::from((pos.x, pos.y)), size, size);
×
NEW
156
                debug_canvas.draw_rect(rect).unwrap();
×
NEW
157
            }
×
158

NEW
159
            debug_canvas.set_draw_color(Color {
×
NEW
160
                a: f32_to_u8(0.4),
×
NEW
161
                ..Color::RED
×
NEW
162
            });
×
NEW
163
            debug_canvas.set_blend_mode(sdl2::render::BlendMode::Blend);
×
NEW
164
            for (start_node, end_node) in map.graph.edges() {
×
NEW
165
                let start_node_model = map.graph.get_node(start_node).unwrap();
×
NEW
166
                let end_node = map.graph.get_node(end_node.target).unwrap().position;
×
NEW
167

×
NEW
168
                // Transform positions using common method
×
NEW
169
                let start = transform_position_with_offset(start_node_model.position, scale);
×
NEW
170
                let end = transform_position_with_offset(end_node, scale);
×
NEW
171

×
NEW
172
                debug_canvas
×
NEW
173
                    .draw_line(Point::from((start.x, start.y)), Point::from((end.x, end.y)))
×
NEW
174
                    .unwrap();
×
NEW
175
            }
×
176

NEW
177
            for (id, node) in map.graph.nodes().enumerate() {
×
NEW
178
                let pos = node.position;
×
NEW
179

×
NEW
180
                // Set color based on whether the node is the closest to the cursor
×
NEW
181
                debug_canvas.set_draw_color(Color {
×
NEW
182
                    a: f32_to_u8(if Some(id) == closest_node { 0.75 } else { 0.6 }),
×
NEW
183
                    ..(if Some(id) == closest_node {
×
NEW
184
                        Color::YELLOW
×
185
                    } else {
NEW
186
                        Color::BLUE
×
187
                    })
188
                });
189

190
                // Transform position using common method
NEW
191
                let pos = transform_position_with_offset(pos, scale);
×
NEW
192
                let size = (2.0 * scale) as u32;
×
NEW
193

×
NEW
194
                debug_canvas
×
NEW
195
                    .fill_rect(Rect::new(pos.x - (size as i32 / 2), pos.y - (size as i32 / 2), size, size))
×
NEW
196
                    .unwrap();
×
197
            }
198

199
            // Render node ID if a node is highlighted
NEW
200
            if let Some(closest_node_id) = closest_node {
×
NEW
201
                let node = map.graph.get_node(closest_node_id).unwrap();
×
NEW
202
                let pos = transform_position_with_offset(node.position, scale);
×
NEW
203

×
NEW
204
                let surface = font
×
NEW
205
                    .render(&closest_node_id.to_string())
×
NEW
206
                    .blended(Color {
×
NEW
207
                        a: f32_to_u8(0.4),
×
NEW
208
                        ..Color::WHITE
×
NEW
209
                    })
×
NEW
210
                    .unwrap();
×
NEW
211
                let texture = texture_creator.create_texture_from_surface(&surface).unwrap();
×
NEW
212
                let dest = Rect::new(pos.x + 10, pos.y - 5, texture.query().width, texture.query().height);
×
NEW
213
                debug_canvas.copy(&texture, None, dest).unwrap();
×
UNCOV
214
            }
×
215

216
            // Render timing information in the top-left corner
217
            render_timing_display(debug_canvas, &mut texture_creator, &timings, font);
×
218
        })
×
219
        .unwrap();
×
220

×
221
    // Draw the debug texture directly onto the main canvas at full resolution
×
222
    canvas.copy(&debug_texture.0, None, None).unwrap();
×
NEW
223
    canvas.present();
×
UNCOV
224
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc