Skip to content
Snippets Groups Projects
vga.rs 2.49 KiB
Newer Older
Jeremy Soller's avatar
Jeremy Soller committed
use core::{fmt, slice};

#[derive(Clone, Copy)]
#[repr(packed)]
pub struct VgaTextBlock {
    pub char: u8,
    pub color: u8,
}

#[derive(Clone, Copy)]
#[repr(u8)]
pub enum VgaTextColor {
    Black = 0,
    Blue = 1,
    Green = 2,
    Cyan = 3,
    Red = 4,
    Purple = 5,
    Brown = 6,
    Gray = 7,
    DarkGray = 8,
    LightBlue = 9,
    LightGreen = 10,
    LightCyan = 11,
    LightRed = 12,
    LightPurple = 13,
    Yellow = 14,
    White = 15,
}

pub struct Vga {
    pub ptr: *mut VgaTextBlock,
Jeremy Soller's avatar
Jeremy Soller committed
    pub width: usize,
    pub height: usize,
    pub x: usize,
    pub y: usize,
    pub bg: VgaTextColor,
    pub fg: VgaTextColor,
}

impl Vga {
    pub const unsafe fn new(ptr: *mut VgaTextBlock, width: usize, height: usize) -> Self {
Jeremy Soller's avatar
Jeremy Soller committed
        Self {
Jeremy Soller's avatar
Jeremy Soller committed
            width,
            height,
            x: 0,
            y: 0,
            bg: VgaTextColor::DarkGray,
            fg: VgaTextColor::White,
        }
    }

    pub unsafe fn blocks(&mut self) -> &'static mut [VgaTextBlock] {
        slice::from_raw_parts_mut(
            self.ptr,
            self.width * self.height,
        )
    }
Jeremy Soller's avatar
Jeremy Soller committed
}

impl fmt::Write for Vga {
    fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
        let mut blocks = unsafe { self.blocks() };
Jeremy Soller's avatar
Jeremy Soller committed
        for c in s.chars() {
            if self.x >= self.width {
                self.x = 0;
                self.y += 1;
            }
            while self.y >= self.height {
                for y in 1..self.height {
                    for x in 0..self.width {
                        let i = y * self.width + x;
                        let j = i - self.width;
                        blocks[j] = blocks[i];
Jeremy Soller's avatar
Jeremy Soller committed
                        if y + 1 == self.height {
                            blocks[i].char = 0;
Jeremy Soller's avatar
Jeremy Soller committed
                        }
                    }
                }
                self.y -= 1;
            }
            match c {
                '\r' => {
                    self.x = 0;
                },
                '\n' => {
                    self.x = 0;
                    self.y += 1;
                },
                _ => {
                    let i = self.y * self.width + self.x;
                    if let Some(block) = blocks.get_mut(i) {
Jeremy Soller's avatar
Jeremy Soller committed
                        block.char = c as u8;
                        block.color =
                            ((self.bg as u8) << 4) |
                            (self.fg as u8);
                    }