1use minifb::{Window, WindowOptions, MouseMode, MouseButton};
2pub use minifb::Key;
3
4use crate::text::FONT_DATA;
5
6pub struct Ember {
7 buffer: Vec<u32>,
8 pub width: i32,
9 pub height: i32,
10
11 window: Window
12}
13
14pub struct MouseInfo {
15 pub position: Option<(f32, f32)>,
16 pub left_button: bool,
17 pub right_button: bool,
18 pub middle_button: bool,
19 pub wheel: Option<(f32, f32)>
20}
21
22impl Ember {
23 pub fn new(title: &str, width: i32, height: i32, fps: f32) -> Self {
24 let mut window = Window::new(
25 title,
26 width as usize,
27 height as usize,
28 WindowOptions::default(),
29 ).unwrap_or_else(|e| {
30 panic!("{}", e);
31 });
32
33 if fps > 0.0 {
34 let fps: f32 = 1.0 / (fps / 1_000_000.0);
35 let fps: u64 = fps as u64;
36
37 window.limit_update_rate(Some(std::time::Duration::from_micros(fps)));
38 }
39
40 let buffer: Vec<u32> = vec![0; (width * height) as usize];
41
42 Self { buffer, width, height, window }
43 }
44
45 pub fn update(&mut self) {
46 self.window
47 .update_with_buffer(&self.buffer[..], self.width as usize, self.height as usize)
48 .unwrap();
49 }
50
51 pub fn set_pixel(&mut self, x: i32, y: i32, color: u32) {
53 if let Some(index) = (y as usize).checked_mul(self.width as usize).and_then(|i| i.checked_add(x as usize)) {
54 if index < self.buffer.len() {
55 self.buffer[index] = color;
56 }
57 }
58 }
59
60 pub fn draw_line(&mut self, x1: i32, y1: i32, x2: i32, y2: i32, color: u32) {
61 let dx = (x2 - x1).abs();
62 let dy = (y2 - y1).abs();
63 let sx = if x1 < x2 { 1 } else { -1 };
64 let sy = if y1 < y2 { 1 } else { -1 };
65 let mut err = if dx > dy { dx } else { -dy } / 2;
66 let mut err2;
67
68 let mut x = x1;
69 let mut y = y1;
70 loop {
71 self.set_pixel(x, y, color);
72 if x == x2 && y == y2 {
73 break;
74 }
75 err2 = err;
76 if err2 > -dx {
77 err -= dy;
78 x += sx;
79 }
80 if err2 < dy {
81 err += dx;
82 y += sy;
83 }
84 }
85 }
86
87 pub fn draw_line_width(&mut self, x0: i32, y0: i32, x1: i32, y1: i32, width: i32, color: u32) {
88 let dx = (x1 - x0).abs();
89 let dy = (y1 - y0).abs();
90 let sx = if x0 < x1 { 1 } else { -1 };
91 let sy = if y0 < y1 { 1 } else { -1 };
92 let mut err = dx - dy;
93
94 let mut x = x0;
95 let mut y = y0;
96
97 let half_width = width / 2;
98
99 while x != x1 || y != y1 {
100 for i in -half_width..=half_width {
102 for j in -half_width..=half_width {
103 self.set_pixel(
104 x + i,
105 y + j,
106 color
107 );
108 }
109 }
110
111 let err2 = 2 * err;
112
113 if err2 > -dy {
114 err -= dy;
115 x += sx;
116 }
117 if err2 < dx {
118 err += dx;
119 y += sy;
120 }
121 }
122 }
123
124 pub fn draw_rectangle(&mut self, x: i32, y: i32, width: i32, height: i32, color: u32) {
125 let x2 = x + width;
126 let y2 = y + height;
127
128 self.draw_line(x, y, x2, y, color);
129 self.draw_line(x2, y, x2, y2, color);
130 self.draw_line(x2, y2, x, y2, color);
131 self.draw_line(x, y2, x, y, color);
132 }
133
134 pub fn draw_rectangle_fill(&mut self, x: i32, y: i32, width: i32, height: i32, color: u32) {
135 for row in y..y + height {
136 self.draw_line(x, row, x + width, row, color);
137 }
138 }
139
140 pub fn draw_circle(&mut self, x0: i32, y0: i32, radius: i32, color: u32) {
141 let mut x = radius;
142 let mut y = 0;
143 let mut err = 0;
144
145 while x >= y {
146 self.set_pixel(x0 + x, y0 + y, color);
147 self.set_pixel(x0 + y, y0 + x, color);
148 self.set_pixel(x0 - y, y0 + x, color);
149 self.set_pixel(x0 - x, y0 + y, color);
150 self.set_pixel(x0 - x, y0 - y, color);
151 self.set_pixel(x0 - y, y0 - x, color);
152 self.set_pixel(x0 + y, y0 - x, color);
153 self.set_pixel(x0 + x, y0 - y, color);
154
155 y += 1;
156 err += 1 + 2 * y;
157 if 2 * (err - x) + 1 > 0 {
158 x -= 1;
159 err += 1 - 2 * x;
160 }
161 }
162 }
163
164 pub fn draw_circle_fill(&mut self, x0: i32, y0: i32, radius: i32, color: u32) {
165 let mut x = 0;
166 let mut y = radius;
167 let mut dp = 1 - radius;
168
169 while x <= y {
170 self.draw_line(x0 - x, y0 - y, x0 + x, y0 - y, color);
171 self.draw_line(x0 - x, y0 + y, x0 + x, y0 + y, color);
172 self.draw_line(x0 - y, y0 - x, x0 + y, y0 - x, color);
173 self.draw_line(x0 - y, y0 + x, x0 + y, y0 + x, color);
174
175 if dp < 0 {
176 dp = dp + 2 * x + 3;
177 } else {
178 dp = dp + 2 * (x - y) + 5;
179 y -= 1;
180 }
181 x += 1;
182 }
183 }
184
185 pub fn draw_text(&mut self, text: &str, x: i32, y: i32, scale: i32, color: u32) {
186 let mut current_x = x;
187
188 for ch in text.to_uppercase().chars() {
189 let ascii = ch as usize;
190 if (ascii >= 65 && ascii <= 90) || (ascii >= 48 && ascii <= 57) || ch == '.' || ch == ':' {
191 let font_index = if ascii >= 65 {
192 ascii - 65
193 } else if ch == '.' {
194 26 + 10 } else if ch == ':' {
196 26 + 10 + 1 } else {
198 ascii - 48 + 26
199 };
200
201 let character = &FONT_DATA[font_index];
202
203 for i in 0..8 {
204 let row = character[i];
205 for j in 0..8 {
206 if row & (1 << (7 - j)) != 0 {
207 for s_y in 0..scale {
208 for s_x in 0..scale {
209 self.set_pixel(current_x + j * scale + s_x, y + i as i32 * scale + s_y, color);
210 }
211 }
212 }
213 }
214 }
215 }
216
217 current_x += 8 * scale;
218 }
219 }
220
221 pub fn get_keys(&mut self) -> Vec<Key> {
222 self.window.get_keys()
223 }
224
225 pub fn process_keys<F>(&mut self, f: F)
226 where
227 F: FnMut(&Key)
228 {
229 self.window.get_keys().iter().for_each(f);
230 }
231
232 pub fn get_mouse_info(&self) -> MouseInfo {
233 let position = self.window.get_mouse_pos(MouseMode::Clamp).map(|(x, y)| (x as f32, y as f32));
234 let left_button = self.window.get_mouse_down(MouseButton::Left);
235 let right_button = self.window.get_mouse_down(MouseButton::Right);
236 let middle_button = self.window.get_mouse_down(MouseButton::Middle);
237 let wheel = self.window.get_scroll_wheel().map(|(x, y)| (x as f32, y as f32));
238
239 MouseInfo {
240 position,
241 left_button,
242 right_button,
243 middle_button,
244 wheel
245 }
246 }
247
248 pub fn should_close(&mut self) -> bool {
249 !self.window.is_open() || self.window.is_key_down(Key::Escape)
250 }
251
252 pub fn clear(&mut self) {
253 for pixel in self.buffer.iter_mut() {
254 *pixel = 0;
255 }
256 }
257
258 pub fn clear_color(&mut self, color: u32) {
259 for pixel in self.buffer.iter_mut() {
260 *pixel = color;
261 }
262 }
263}