use core::fmt; use limine::framebuffer::Framebuffer; #[derive(Debug)] #[repr(C, packed)] struct Psf2Header { magic: u32, version: u32, header_size: u32, flags: u32, num_glyphs: u32, bytes_per_glyph: u32, height: u32, width: u32, } pub struct Console<'a> { framebuffer: &'a Framebuffer<'a>, font: &'static [u8], pub x: usize, pub y: usize, pub fg_color: u32, pub bg_color: u32, } impl<'a> Console<'a> { pub fn new(framebuffer: &'a Framebuffer<'a>, font: &'static [u8]) -> Self { Self { framebuffer, font, x: 0, y: 0, fg_color: 0xFFFFFF, // White bg_color: 0x000000, // Black } } pub fn set_color(&mut self, fg: u32) { self.fg_color = fg; } pub fn clear(&mut self) { let fb = self.framebuffer; unsafe { core::ptr::write_bytes(fb.addr(), 0, (fb.pitch() * fb.height()) as usize); } self.x = 0; self.y = 0; } fn header(&self) -> &Psf2Header { unsafe { &*(self.font.as_ptr() as *const Psf2Header) } } fn scroll(&mut self) { let header = self.header(); let font_height = header.height as usize; let fb = self.framebuffer; let pitch = fb.pitch() as usize; let height = fb.height() as usize; let shift = font_height * pitch; let size = pitch * (height - font_height); unsafe { let addr = fb.addr(); core::ptr::copy(addr.add(shift), addr, size); core::ptr::write_bytes(addr.add(size), 0, shift); } self.y -= font_height; } fn draw_glyph(&mut self, glyph_index: u32, x: usize, y: usize) { let header = self.header(); let bytes_per_line = (header.width + 7) / 8; let glyph_offset = header.header_size + (glyph_index * header.bytes_per_glyph); let fb = self.framebuffer; let fb_pitch = fb.pitch() as usize; let fb_addr = fb.addr(); for cy in 0..header.height { let glyph_row = self.font[(glyph_offset + cy * bytes_per_line) as usize]; for cx in 0..header.width { if (glyph_row & (0x80 >> cx)) != 0 { let offset = ((y + cy as usize) * fb_pitch) + ((x + cx as usize) * 4); unsafe { fb_addr.add(offset).cast::().write_volatile(self.fg_color); } } } } } pub fn write_char(&mut self, c: char) { let (font_width, font_height, num_glyphs) = { let h = self.header(); (h.width as usize, h.height as usize, h.num_glyphs) }; if c == '\n' { self.x = 0; self.y += font_height; } else { if self.x + font_width > self.framebuffer.width() as usize { self.x = 0; self.y += font_height; } let glyph_index = if (c as u32) < num_glyphs { c as u32 } else { 0 // symbol placeholder }; self.draw_glyph(glyph_index, self.x, self.y); self.x += font_width; } if self.y + font_height > self.framebuffer.height() as usize { self.scroll(); } } } impl fmt::Write for Console<'_> { fn write_str(&mut self, s: &str) -> fmt::Result { for c in s.chars() { self.write_char(c); } Ok(()) } }