pixel_handler/
pixel_handler.rs

1use std::{
2    collections::HashMap,
3    time::{self, Instant},
4};
5
6use ggez::{
7    glam::*,
8    graphics::{self, Canvas, Color, DrawParam, Drawable, Mesh, Rect, Text, PxScale},
9    Context,
10};
11
12use crate::structs::{drawable_object::DrawableObject, grid_position::GridPosition, pixel::Pixel};
13
14pub struct PixelHandler {
15    pub pixels: HashMap<GridPosition, Pixel>,
16    frame_time: time::Instant,
17    draw_stack: Vec<(DrawParam, DrawableObject)>,
18    cell_size: (f32, f32),
19}
20
21impl Default for PixelHandler {
22    fn default() -> Self {
23        Self::new((20.0, 20.0))
24    }
25}
26
27impl PixelHandler {
28    pub fn new(cell_size: (f32, f32)) -> Self {
29        Self {
30            draw_stack: Vec::new(),
31            pixels: HashMap::new(),
32            frame_time: Instant::now(),
33            cell_size,
34        }
35    }
36
37    fn add_to_draw_stack(&mut self, drawable: DrawableObject, params: DrawParam) {
38        self.draw_stack.push((params, drawable));
39    }
40
41    pub fn draw_grid(&mut self, ctx: &mut Context, grid_color: Color) {
42        let window_size = ctx.gfx.size();
43        let cell_size = self.cell_size;
44
45        let mut mesh_builder = graphics::MeshBuilder::new();
46
47        let horizontal_lines = (window_size.1 / cell_size.1) as i32; 
48        let vertical_lines = (window_size.0 / cell_size.0) as i32; 
49
50        // creating lines from left to right 
51        for y in 0..horizontal_lines {
52            let y_column = y as f32 * cell_size.1;
53
54            let left_point = Vec2::new(0.0, y_column);
55            let right_point = Vec2::new(window_size.0, y_column);
56
57            mesh_builder
58                .line(&[left_point, right_point], 1.0, grid_color)
59                .unwrap();
60        }
61
62        // creating lines from top to bottom
63        for x in 0..vertical_lines {
64            let x_row = x as f32 * cell_size.0;
65
66            let top_point = Vec2::new(x_row, 0.0);
67            let bottom_point = Vec2::new(x_row, window_size.1);
68
69            mesh_builder
70                .line(&[top_point, bottom_point], 1.0, grid_color)
71                .unwrap();
72        }
73
74        let mesh_data = mesh_builder.build();
75        let mesh = Mesh::from_data(ctx, mesh_data);
76
77        self.add_to_draw_stack(DrawableObject::Mesh(mesh), DrawParam::default());
78    }
79
80    pub fn get_fps(&self) -> f32 {
81        let frame_duration = self.frame_time.elapsed();
82        let fps = 1.0 / frame_duration.as_secs_f32();
83
84        fps
85    }
86
87    pub fn display_fps(&mut self, ctx: &mut Context) {
88        let fps = ctx.time.fps().round();
89        let bounds = Vec2::new(80.0, 20.0);
90        let rect = Rect::new(0.0, 0.0, bounds.x, bounds.y);
91
92        let mut fps_text = Text::new(format!("Fps: {}", fps));
93
94        fps_text.set_bounds(bounds);
95        fps_text.set_scale(PxScale::from(18.0));
96
97        let fps_background =
98            Mesh::new_rectangle(ctx, graphics::DrawMode::fill(), rect, Color::BLACK).unwrap();
99
100        self.add_to_draw_stack(DrawableObject::Mesh(fps_background), DrawParam::default());
101        self.add_to_draw_stack(DrawableObject::Text(fps_text), DrawParam::default());
102    }
103
104    pub fn register_pixel(&mut self, pixel: Pixel) {
105        self.pixels.insert(pixel.position, pixel);
106    }
107
108    pub fn position_occupied(&self, position: &GridPosition) -> bool {
109        self.pixels.contains_key(position)
110    }
111
112    pub fn get_pixel(&self, position: &GridPosition) -> Option<&Pixel> {
113        self.pixels.get(&position)
114    }
115
116    pub fn update(&mut self, canvas: &mut Canvas, ctx: &mut Context) {
117        let mut mesh_builder = graphics::MeshBuilder::new();
118        let mut new_pixels = HashMap::new();
119
120        for (_old_pos, pixel) in self.pixels.iter_mut() {
121            pixel.append_to_mesh(&mut mesh_builder);
122            new_pixels.insert(pixel.position, pixel.clone());
123        }
124
125        let mesh = Mesh::from_data(ctx, mesh_builder.build());
126        canvas.draw(&mesh, DrawParam::default());
127
128        for (params, drawable) in &self.draw_stack {
129            drawable.draw(canvas, *params);
130        }
131
132        self.pixels = new_pixels;
133
134        self.draw_stack.clear();
135        self.frame_time = Instant::now();
136    }
137}