// Uses too much RAM to be useful ): // 320 * 240 * 2 * 2 bytes/pixel = 307KB of RAM use embedded_graphics::{ 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> { 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; type Error = E; fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error> where I: IntoIterator<Item = embedded_graphics::prelude::Pixel<Self::Color>>, { 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 })) } } #[inline(always)] fn index<X: TryInto<usize>, Y: TryInto<usize>>( width: usize, height: usize, 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; } Some(x + y * width) }