-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
framebuffer.rs
111 lines (99 loc) · 3.13 KB
/
framebuffer.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use bootloader_api::info::{FrameBuffer, PixelFormat};
use embedded_graphics::{
draw_target::DrawTarget,
geometry::{self, Point},
pixelcolor::{Rgb888, RgbColor},
Pixel,
};
pub struct Display {
framebuffer: &'static mut FrameBuffer,
width: usize,
height: usize,
}
impl Display {
pub fn new(framebuffer: &'static mut FrameBuffer) -> Display {
Self {
width: framebuffer.info().width,
height: framebuffer.info().height,
framebuffer,
}
}
fn draw_pixel(&mut self, coordinates: Point, color: Rgb888) {
// ignore any pixels that are out of bounds.
let position = match (coordinates.x.try_into(), coordinates.y.try_into()) {
(Ok(x), Ok(y)) if x < self.width && y < self.height => Position { x, y },
_ => return, // ignore out-of-bounds pixel
};
let color = Color {
red: color.r(),
green: color.g(),
blue: color.b(),
};
set_pixel_in(self.framebuffer, position, color);
}
}
impl DrawTarget for Display {
type Color = Rgb888;
/// Drawing operations can never fail.
type Error = core::convert::Infallible;
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item = Pixel<Self::Color>>,
{
for Pixel(coordinates, color) in pixels.into_iter() {
self.draw_pixel(coordinates, color);
}
Ok(())
}
}
impl geometry::OriginDimensions for Display {
fn size(&self) -> geometry::Size {
geometry::Size::new(
self.width.try_into().unwrap(),
self.height.try_into().unwrap(),
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Position {
pub x: usize,
pub y: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Color {
pub red: u8,
pub green: u8,
pub blue: u8,
}
pub fn set_pixel_in(framebuffer: &mut FrameBuffer, position: Position, color: Color) {
let info = framebuffer.info();
// calculate offset to first byte of pixel
let byte_offset = {
// use stride to calculate pixel offset of target line
let line_offset = position.y * info.stride;
// add x position to get the absolute pixel offset in buffer
let pixel_offset = line_offset + position.x;
// convert to byte offset
pixel_offset * info.bytes_per_pixel
};
// set pixel based on color format
let pixel_buffer = &mut framebuffer.buffer_mut()[byte_offset..];
match info.pixel_format {
PixelFormat::Rgb => {
pixel_buffer[0] = color.red;
pixel_buffer[1] = color.green;
pixel_buffer[2] = color.blue;
}
PixelFormat::Bgr => {
pixel_buffer[0] = color.blue;
pixel_buffer[1] = color.green;
pixel_buffer[2] = color.red;
}
PixelFormat::U8 => {
// use a simple average-based grayscale transform
let gray = color.red / 3 + color.green / 3 + color.blue / 3;
pixel_buffer[0] = gray;
}
other => panic!("unknown pixel format {other:?}"),
}
}