old school music tracker
at main 228 lines 7.7 kB view raw
1use crate::palettes; 2 3use super::coordinates::{CharPosition, CharRect, FONT_SIZE, PixelRect, WINDOW_SIZE}; 4use font8x8::UnicodeFonts; 5 6pub struct DrawBuffer { 7 pub framebuffer: Box<[[u8; WINDOW_SIZE.0]; WINDOW_SIZE.1]>, 8} 9 10impl Default for DrawBuffer { 11 fn default() -> Self { 12 Self { 13 framebuffer: Box::new([[0; WINDOW_SIZE.0]; WINDOW_SIZE.1]), 14 } 15 } 16} 17 18impl DrawBuffer { 19 pub const BACKGROUND_COLOR: u8 = 2; 20 21 pub fn new() -> Self { 22 Self { 23 framebuffer: Box::new([[0; WINDOW_SIZE.0]; WINDOW_SIZE.1]), 24 } 25 } 26 27 pub fn draw_char( 28 &mut self, 29 char_data: [u8; 8], 30 position: CharPosition, 31 fg_color: u8, 32 bg_color: u8, 33 ) { 34 // this is the top_left pixel 35 let position = (position.x() * FONT_SIZE, position.y() * FONT_SIZE); 36 for (y, line) in char_data.iter().enumerate() { 37 for x in 0..8 { 38 let color = match (line >> x) & 1 == 1 { 39 true => fg_color, 40 false => bg_color, 41 }; 42 self.framebuffer[position.1 + y][position.0 + x] = color; 43 } 44 } 45 } 46 47 pub fn draw_string( 48 &mut self, 49 string: &str, 50 position: CharPosition, 51 fg_color: u8, 52 bg_color: u8, 53 ) { 54 for (num, char) in string.char_indices() { 55 self.draw_char( 56 font8x8::BASIC_FONTS.get(char).unwrap(), 57 position + (num, 0), 58 fg_color, 59 bg_color, 60 ); 61 } 62 } 63 64 /// cuts off the string if it's too long 65 /// if it's too short it gets filled with whitespace 66 pub fn draw_string_length( 67 &mut self, 68 string: &str, 69 position: CharPosition, 70 lenght: usize, 71 fg_color: u8, 72 bg_color: u8, 73 ) { 74 if string.len() > lenght { 75 self.draw_string(&string[..=lenght], position, fg_color, bg_color) 76 } else { 77 self.draw_string(string, position, fg_color, bg_color); 78 self.draw_rect( 79 bg_color, 80 CharRect::new( 81 position.y(), 82 position.y(), 83 position.x() + string.len(), 84 position.x() + lenght, 85 ), 86 ); 87 } 88 } 89 90 /// doesn't draw background. That should be done before calling this function 91 pub fn draw_out_border( 92 &mut self, 93 char_rect: CharRect, 94 top_left_color: u8, 95 bot_right_color: u8, 96 thickness: usize, 97 ) { 98 assert!(thickness <= FONT_SIZE); 99 assert!(thickness > 0); 100 let pixel_rect = PixelRect::from(char_rect); 101 102 for x in pixel_rect.left()..=pixel_rect.right() { 103 for y in 0..thickness { 104 self.framebuffer[pixel_rect.top() + y][x] = top_left_color; 105 self.framebuffer[pixel_rect.bot() - y][x] = bot_right_color; 106 } 107 } 108 for y in pixel_rect.top()..=pixel_rect.bot() { 109 for x in 0..thickness { 110 self.framebuffer[y][pixel_rect.right() - x] = bot_right_color; 111 self.framebuffer[y][pixel_rect.left() + x] = top_left_color; 112 } 113 } 114 } 115 116 pub fn draw_in_box( 117 &mut self, 118 char_rect: CharRect, 119 background_color: u8, 120 top_left_color: u8, 121 bot_right_color: u8, 122 thickness: usize, 123 ) { 124 assert!(thickness < FONT_SIZE); 125 assert!(thickness > 0); 126 // needs to be between 0 and FONT_SIZE 127 // const BOX_THICKNESS: usize = 1; 128 // const SPACE_FROM_BORDER: usize = FONT_SIZE - BOX_THICKNESS; 129 let space_from_border = FONT_SIZE - thickness; 130 131 let pixel_rect = PixelRect::from(char_rect); 132 133 // all pixel lines except those in top and bottom char line 134 for y in (pixel_rect.top() + FONT_SIZE)..=(pixel_rect.bot() - FONT_SIZE) { 135 // left side foreground 136 for x in (pixel_rect.left() + space_from_border)..(pixel_rect.left() + FONT_SIZE) { 137 self.framebuffer[y][x] = top_left_color; 138 } 139 // left side background 140 for x in pixel_rect.left()..(pixel_rect.left() + space_from_border) { 141 self.framebuffer[y][x] = background_color; 142 } 143 144 // 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 145 for x in 146 (pixel_rect.right() - FONT_SIZE + 1)..(pixel_rect.right() - space_from_border + 1) 147 { 148 self.framebuffer[y][x] = bot_right_color; 149 } 150 // right side background 151 for x in (pixel_rect.right() - space_from_border + 1)..=pixel_rect.right() { 152 self.framebuffer[y][x] = background_color; 153 } 154 } 155 156 // top char line 157 for y in pixel_rect.top()..(pixel_rect.top() + FONT_SIZE) { 158 if y < pixel_rect.top() + space_from_border { 159 for x in pixel_rect.horizontal_range() { 160 self.framebuffer[y][x] = background_color; 161 } 162 } else { 163 for x in pixel_rect.left()..=pixel_rect.right() { 164 let color = if x < pixel_rect.left() + space_from_border 165 || x > pixel_rect.right() - space_from_border 166 { 167 background_color 168 } else if x < pixel_rect.right() 169 - space_from_border 170 - (y - (pixel_rect.top() + space_from_border)) 171 { 172 top_left_color 173 } else { 174 bot_right_color 175 }; 176 177 self.framebuffer[y][x] = color; 178 } 179 } 180 } 181 182 // bottom char line 183 for y in (pixel_rect.bot() - FONT_SIZE + 1)..=pixel_rect.bot() { 184 // does the top 'SPACE_FROM_BORDER' rows in background color 185 if y > pixel_rect.bot() - space_from_border { 186 for x in pixel_rect.horizontal_range() { 187 self.framebuffer[y][x] = background_color; 188 } 189 } else { 190 for x in pixel_rect.horizontal_range() { 191 let color = if x < pixel_rect.left() + space_from_border 192 || x > pixel_rect.right() - space_from_border 193 { 194 background_color 195 } else if x < pixel_rect.left() + (pixel_rect.bot() - y) { 196 top_left_color 197 } else { 198 bot_right_color 199 }; 200 201 self.framebuffer[y][x] = color; 202 } 203 } 204 } 205 } 206 207 pub fn draw_rect(&mut self, color: u8, rect: CharRect) { 208 let pixel_rect = PixelRect::from(rect); 209 self.draw_pixel_rect(color, pixel_rect) 210 } 211 212 pub fn draw_pixel_rect(&mut self, color: u8, rect: PixelRect) { 213 for line in &mut self.framebuffer[rect.top()..=rect.bot()] { 214 line[rect.left()..=rect.right()].fill(color); 215 } 216 } 217 218 /// for debugging. draws a pixel in the middle of the char 219 fn mark_char(&mut self, position: CharPosition) { 220 self.framebuffer[(position.y() + 4) * WINDOW_SIZE.0][position.x() + 4] = 1; 221 } 222 223 pub fn show_colors(&mut self) { 224 for i in 0..palettes::PALETTE_SIZE as u8 { 225 self.draw_rect(i, CharPosition::new(i as usize, 5).into()); 226 } 227 } 228}