owl_patch/
screen_buffer.rs

1//! Screen Buffers for devices with displays
2//!
3//! See the [screen-test] example for usage
4//!
5//! [screen-test]: https://github.com/orukusaki/owl_patch/blob/main/examples/src/bin/screen-test.rs
6use core::convert::Infallible;
7
8use embedded_graphics_core::{
9    pixelcolor::BinaryColor,
10    prelude::{Dimensions, DrawTarget, OriginDimensions, Point, Size},
11    Pixel,
12};
13
14/// Monochrome Screen Buffer
15pub struct MonoScreenBuffer<'a> {
16    pixels: &'a mut [u8],
17    width: u16,
18    height: u16,
19}
20
21impl<'a> MonoScreenBuffer<'a> {
22    /// Constructor
23    pub fn new(pixels: &'a mut [u8], width: u16, height: u16) -> Self {
24        Self {
25            pixels,
26            width,
27            height,
28        }
29    }
30
31    /// Get pixel colour by coodinate (from top left)
32    pub fn get(&self, x: u16, y: u16) -> BinaryColor {
33        let (byte_index, offset) = self.index_offset(x, y);
34
35        (((self.pixels[byte_index] >> offset) & 1) == 1).into()
36    }
37
38    /// Set pixel colour by coodinate (from top left)
39    pub fn set(&mut self, x: u16, y: u16, colour: BinaryColor) {
40        let (byte_index, offset) = self.index_offset(x, y);
41
42        match colour {
43            BinaryColor::Off => self.pixels[byte_index] &= !(1 << offset),
44            BinaryColor::On => self.pixels[byte_index] |= 1 << offset,
45        }
46    }
47
48    /// Set pixel colour by coodinate (from top left)
49    pub fn get_pixel(&mut self, x: u16, y: u16) -> Pixel<BinaryColor> {
50        Pixel(Point::new(x as i32, y as i32), self.get(x, y))
51    }
52
53    /// Set pixel colour by coodinate (from top left)
54    pub fn set_pixel(&mut self, pixel: Pixel<BinaryColor>) {
55        self.set(pixel.0.x as u16, pixel.0.y as u16, pixel.1);
56    }
57
58    fn index_offset(&self, x: u16, y: u16) -> (usize, u8) {
59        // Pixels are arranged top->bottom, then left->right
60        let bit_index = x * self.height + y;
61        let byte_index = (bit_index / 8) as usize;
62        let offset = (bit_index % 8) as u8;
63        (byte_index, offset)
64    }
65
66    /// Screen height
67    pub fn height(&self) -> u16 {
68        self.height
69    }
70
71    /// Screen width
72    pub fn width(&self) -> u16 {
73        self.width
74    }
75}
76
77impl DrawTarget for MonoScreenBuffer<'_> {
78    type Color = BinaryColor;
79
80    type Error = Infallible;
81
82    fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
83    where
84        I: IntoIterator<Item = Pixel<Self::Color>>,
85    {
86        let bounding_box = self.bounding_box();
87
88        for p in pixels {
89            if bounding_box.contains(p.0) {
90                self.set_pixel(p);
91            }
92        }
93
94        Ok(())
95    }
96}
97
98impl OriginDimensions for MonoScreenBuffer<'_> {
99    fn size(&self) -> Size {
100        Size::new(self.width as u32, self.height as u32)
101    }
102}