Skip to content
Snippets Groups Projects
buffered_display.rs 2.16 KiB
Newer Older
// Uses too much RAM to be useful ):
// 320 * 240 * 2 * 2 bytes/pixel = 307KB of RAM

use embedded_graphics::{
Stephen D's avatar
Stephen D committed
    draw_target::DrawTarget, geometry::Dimensions, pixelcolor::PixelColor, Pixel,
};

pub struct BufferedDisplay<const L: usize, C: 'static, E, DT: DrawTarget<Color = C, Error = E>> {
    target: DT,
    width: usize,
    height: usize,
    cur: &'static mut [C; L],
}

impl<const L: usize, C: PixelColor, E, DT: DrawTarget<Color = C, Error = E>>
    BufferedDisplay<L, C, E, DT>
{
Stephen D's avatar
Stephen D committed
    pub fn new(mut target: DT, color: C, cur: &'static mut [C; L]) -> Result<Self, E> {
        let size = target.bounding_box().size;
        let width = size.width.try_into().unwrap();
        let height = size.height.try_into().unwrap();
        assert_eq!(L, width * height);
        target.fill_solid(&target.bounding_box(), color)?;

        Ok(Self {
            target,
            width,
            height,
            cur,
        })
    }
}

impl<const L: usize, C: PixelColor, E, DT: DrawTarget<Color = C, Error = E>> Dimensions
    for BufferedDisplay<L, C, E, DT>
{
    fn bounding_box(&self) -> embedded_graphics::primitives::Rectangle {
        self.target.bounding_box()
    }
}

impl<const L: usize, C: PixelColor, E, DT: DrawTarget<Color = C, Error = E>> DrawTarget
    for BufferedDisplay<L, C, E, DT>
{
    type Color = C;
Stephen D's avatar
Stephen D committed
    type Error = E;

    fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
    where
        I: IntoIterator<Item = embedded_graphics::prelude::Pixel<Self::Color>>,
    {
Stephen D's avatar
Stephen D committed
        self.target
            .draw_iter(pixels.into_iter().filter(|Pixel(p, c)| {
                if let Some(idx) = index(self.width, self.height, p.x, p.y) {
                    if self.cur[idx] != *c {
                        self.cur[idx] = *c;
                        return true;
                    }
                }

                false
            }))
Stephen D's avatar
Stephen D committed
#[inline(always)]
fn index<X: TryInto<usize>, Y: TryInto<usize>>(
    width: usize,
    height: usize,
Stephen D's avatar
Stephen D committed
    x: X,
    y: Y,
) -> Option<usize> {
    let x: usize = x.try_into().ok()?;
    let y: usize = y.try_into().ok()?;

    if y >= height || x >= width {
        return None;
Stephen D's avatar
Stephen D committed
    Some(x + y * width)