Skip to main content

framebuffer_draw/
lib.rs

1#![no_std]
2//! Draw pixels on a raw framebuffer.
3//!
4//! This crate provides a small `no_std` API for writing individual pixels into
5//! a framebuffer-backed memory region. It is designed for low-level graphics
6//! code where you already have a pointer, dimensions, stride, and pixel format.
7//!
8//! # Example
9//!
10//! ```no_run
11//! use framebuffer_draw::{Color, Framebuffer, PixelFormat};
12//!
13//! let framebuffer = Framebuffer {
14//!     // Pointer to the first byte of the framebuffer memory.
15//!     ptr: todo!(),
16//!     // The total framebuffer size in bytes.
17//!     size: todo!(),
18//!     // The number of pixels in each row.
19//!     stride: todo!(),
20//!     // The pixel format used when writing pixel data.
21//!     pixel_format: PixelFormat::Rgb,
22//!     // Width of the framebuffer in pixels.
23//!     width: todo!(),
24//!     // Height of the framebuffer in pixels.
25//!     height: todo!(),
26//!     // The number of bytes used by each pixel.
27//!     bytes_per_pixel: todo!(),
28//! };
29//!
30//! // Draws a straight line.
31//! let limit = core::cmp::min(framebuffer.width, framebuffer.height);
32//! for i in 0..limit {
33//!     framebuffer.draw_pixel(i, i, Color::rgb(255, 0, 0));
34//! }
35//! ```
36
37mod roxyloader_fb;
38#[cfg(test)]
39mod tests;
40
41/// Metadata that describes a framebuffer.
42#[derive(Clone, Copy)]
43pub struct Framebuffer {
44    pub ptr: *mut u8,
45    /// The total size of the framebuffer in bytes.
46    pub size: usize,
47    /// The number of pixels in each row of the framebuffer.
48    pub stride: usize,
49    /// Pixel format of the framebuffer.
50    pub pixel_format: PixelFormat,
51    /// Width of the framebuffer in pixels.
52    pub width: usize,
53    /// Height of the framebuffer in pixels.
54    pub height: usize,
55    /// Bytes each pixel will take on the framebuffer.
56    pub bytes_per_pixel: usize,
57}
58
59#[derive(Clone, Copy, Debug, PartialEq, Eq)]
60pub enum PixelFormat {
61    Rgb,
62    Bgr,
63}
64
65pub struct Color {
66    r: u8,
67    g: u8,
68    b: u8,
69}
70
71impl Color {
72    /// Creates an RGB color.
73    pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
74        Self { r, g, b }
75    }
76}
77
78impl Framebuffer {
79    /// Draws a single pixel at `(x, y)`.
80    ///
81    /// This panics if the coordinates are outside the framebuffer bounds.
82    pub fn draw_pixel(&self, x: usize, y: usize, color: Color) {
83        self.validate_range(x, y);
84
85        let index = self.pixel_index(x, y);
86
87        unsafe {
88            match self.pixel_format {
89                PixelFormat::Rgb => {
90                    *self.ptr.add(index) = color.r;
91                    *self.ptr.add(index + 1) = color.g;
92                    *self.ptr.add(index + 2) = color.b;
93                }
94                PixelFormat::Bgr => {
95                    *self.ptr.add(index) = color.b;
96                    *self.ptr.add(index + 1) = color.g;
97                    *self.ptr.add(index + 2) = color.r;
98                }
99            }
100        }
101    }
102
103    fn validate_range(&self, x: usize, y: usize) {
104        assert!(x < self.width);
105        assert!(y < self.height);
106    }
107
108    fn pixel_index(&self, x: usize, y: usize) -> usize {
109        let pixel_index = (y * self.stride) + x;
110
111        pixel_index * self.bytes_per_pixel
112    }
113}