zodiac 0.2.0

Rust OS framework that offers safe interfaces for kernel development
Documentation
use limine::request::FramebufferRequest;

#[used]
#[unsafe(link_section = ".requests")]
static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new();

type Rgb = (u8, u8, u8);

/// The framebuffer structure.
pub struct FrameBuffer {
    width: usize,
    height: usize,
    stride: usize,
    buffer: *mut u32,
    shifts: (u8, u8, u8),
    convert_color: fn(Rgb, Rgb) -> u32,
}

impl FrameBuffer {
    /// Get the size of the framebuffer. Order: (width, height)
    pub fn size(&self) -> (usize, usize) {
        (self.width, self.height)
    }

    /// Draw a pixel at the given coordinates with the given color.
    /// Color format: (red, green, blue)
    pub fn draw_pixel(&mut self, x: usize, y: usize, color: Rgb) {
        let color = (self.convert_color)(self.shifts, color);
        unsafe { self.buffer.add(y * self.stride + x).write(color) }
    }
}

impl Default for FrameBuffer {
    fn default() -> Self {
        let response = FRAMEBUFFER_REQUEST.get_response().unwrap();
        let frame_buffer = response.framebuffers().next().unwrap();

        let red_mask_size = frame_buffer.red_mask_size();
        let green_mask_size = frame_buffer.green_mask_size();
        let blue_mask_size = frame_buffer.blue_mask_size();

        let shifts = (
            frame_buffer.red_mask_shift() + (red_mask_size - 8),
            frame_buffer.green_mask_shift() + (green_mask_size - 8),
            frame_buffer.blue_mask_shift() + (blue_mask_size - 8),
        );

        let convert_color = |shifts: (u8, u8, u8), color: (u8, u8, u8)| {
            ((color.0 as u32) << shifts.0)
                | ((color.1 as u32) << shifts.1)
                | ((color.2 as u32) << shifts.2)
        };

        Self {
            shifts,
            convert_color,
            width: frame_buffer.width() as usize,
            height: frame_buffer.height() as usize,
            buffer: frame_buffer.addr() as *mut u32,
            stride: frame_buffer.pitch() as usize / size_of::<u32>(),
        }
    }
}