use crate::coordinates::FONT_SIZE16; use super::coordinates::{CharPosition, CharRect, FONT_SIZE, PixelRect, WINDOW_SIZE}; use font8x8::UnicodeFonts; pub struct DrawBuffer { pub framebuffer: Box<[[u8; WINDOW_SIZE.0 as usize]; WINDOW_SIZE.1 as usize]>, } impl Default for DrawBuffer { fn default() -> Self { Self { framebuffer: Box::new([[0; WINDOW_SIZE.0 as usize]; WINDOW_SIZE.1 as usize]), } } } impl DrawBuffer { pub const BACKGROUND_COLOR: u8 = 2; pub fn set(&mut self, y: u16, x: u16, color: u8) { self.framebuffer[usize::from(y)][usize::from(x)] = color; } pub fn draw_char( &mut self, char_data: [u8; 8], position: CharPosition, fg_color: u8, bg_color: u8, ) { let pixel_pos = PixelRect::from(CharRect::from(position)); let position = (pixel_pos.left(), pixel_pos.top()); for (y, line) in char_data.iter().enumerate() { let y = u16::try_from(y).unwrap(); for x in 0..8 { let color = match (line >> x) & 1 == 1 { true => fg_color, false => bg_color, }; self.set(position.1 + y, position.0 + x, color); } } } pub fn draw_string( &mut self, string: &str, position: CharPosition, fg_color: u8, bg_color: u8, ) { for (num, char) in string.char_indices() { self.draw_char( font8x8::BASIC_FONTS.get(char).unwrap(), position + (u8::try_from(num).unwrap(), 0), fg_color, bg_color, ); } } /// cuts off the string if it's too long /// if it's too short it gets filled with whitespace pub fn draw_string_length( &mut self, string: &str, position: CharPosition, lenght: u8, fg_color: u8, bg_color: u8, ) { let ulen = usize::from(lenght); if string.len() > ulen { self.draw_string(&string[..=ulen], position, fg_color, bg_color) } else { self.draw_string(string, position, fg_color, bg_color); self.draw_rect( bg_color, CharRect::new( position.y(), position.y(), position.x() + u8::try_from(string.len()).unwrap(), position.x() + lenght, ), ); } } /// doesn't draw background. That should be done before calling this function pub fn draw_out_border( &mut self, char_rect: CharRect, top_left_color: u8, bot_right_color: u8, thickness: u8, ) { assert!(thickness <= FONT_SIZE); assert!(thickness > 0); let pixel_rect = PixelRect::from(char_rect); let thickness = u16::from(thickness); for x in pixel_rect.left()..=pixel_rect.right() { for y in 0..thickness { self.set(pixel_rect.top() + y, x, top_left_color); self.set(pixel_rect.bot() - y, x, bot_right_color); } } for y in pixel_rect.top()..=pixel_rect.bot() { for x in 0..thickness { self.set(y, pixel_rect.right() - x, bot_right_color); self.set(y, pixel_rect.left() + x, top_left_color); } } } pub fn draw_in_box( &mut self, char_rect: CharRect, background_color: u8, top_left_color: u8, bot_right_color: u8, thickness: u8, ) { assert!(thickness < FONT_SIZE); assert!(thickness > 0); let space_from_border = FONT_SIZE16 - u16::from(thickness); let pixel_rect = PixelRect::from(char_rect); // all pixel lines except those in top and bottom char line for y in (pixel_rect.top() + FONT_SIZE16)..=(pixel_rect.bot() - FONT_SIZE16) { // left side foreground for x in (pixel_rect.left() + space_from_border)..(pixel_rect.left() + FONT_SIZE16) { self.set(y, x, top_left_color); } // left side background for x in pixel_rect.left()..(pixel_rect.left() + space_from_border) { self.set(y, x, background_color); } // need the plus ones, as the '..' would need to be exclusive on the low and inclusive on the high, which i dont know how to do for x in (pixel_rect.right() - FONT_SIZE16 + 1)..(pixel_rect.right() - space_from_border + 1) { self.set(y, x, bot_right_color); } // right side background for x in (pixel_rect.right() - space_from_border + 1)..=pixel_rect.right() { self.set(y, x, background_color); } } // top char line for y in pixel_rect.top()..(pixel_rect.top() + FONT_SIZE16) { if y < pixel_rect.top() + space_from_border { for x in pixel_rect.horizontal_range() { self.set(y, x, background_color); } } else { for x in pixel_rect.left()..=pixel_rect.right() { let color = if x < pixel_rect.left() + space_from_border || x > pixel_rect.right() - space_from_border { background_color } else if x < pixel_rect.right() - space_from_border - (y - (pixel_rect.top() + space_from_border)) { top_left_color } else { bot_right_color }; self.set(y, x, color); } } } // bottom char line for y in (pixel_rect.bot() - FONT_SIZE16 + 1)..=pixel_rect.bot() { // does the top 'SPACE_FROM_BORDER' rows in background color if y > pixel_rect.bot() - space_from_border { for x in pixel_rect.horizontal_range() { self.set(y, x, background_color); } } else { for x in pixel_rect.horizontal_range() { let color = if x < pixel_rect.left() + space_from_border || x > pixel_rect.right() - space_from_border { background_color } else if x < pixel_rect.left() + (pixel_rect.bot() - y) { top_left_color } else { bot_right_color }; // self.framebuffer[y][x] = color; self.set(y, x, color); } } } } pub fn draw_rect(&mut self, color: u8, rect: CharRect) { let pixel_rect = PixelRect::from(rect); self.draw_pixel_rect(color, pixel_rect) } pub fn draw_pixel_rect(&mut self, color: u8, rect: PixelRect) { for line in &mut self.framebuffer[usize::from(rect.top())..=usize::from(rect.bot())] { line[usize::from(rect.left())..=usize::from(rect.right())].fill(color); } } pub fn show_colors(&mut self) { for i in 0..crate::render::palettes::PALETTE_SIZE as u8 { self.draw_rect(i, CharPosition::new(i, 5).into()); } } }