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}