pixel_handler/
pixel_handler.rs1use 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 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 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}