#![no_std] #![forbid(unsafe_code)] use port_framebuffer::Framebuffer; use types::display::{Color, Dimension, ScreenCoord}; pub struct MockFramebuffer { width: Dimension, height: Dimension, pixels: [(ScreenCoord, ScreenCoord, Color); 4096], pixel_count: usize, flushed: bool, scrolls: usize, } impl MockFramebuffer { pub fn new(width: Dimension, height: Dimension) -> Self { Self { width, height, pixels: [(ScreenCoord::new(0), ScreenCoord::new(0), Color::from_raw(0)); 4096], pixel_count: 0, flushed: false, scrolls: 0, } } pub fn pixel_count(&self) -> usize { self.pixel_count } /// How many times the screen was scrolled. pub fn scrolls(&self) -> usize { self.scrolls } pub fn was_flushed(&self) -> bool { self.flushed } pub fn pixel_at(&self, index: usize) -> (ScreenCoord, ScreenCoord, Color) { self.pixels[index] } } impl Framebuffer for MockFramebuffer { fn width(&self) -> Dimension { self.width } fn height(&self) -> Dimension { self.height } fn write_pixel(&mut self, x: ScreenCoord, y: ScreenCoord, color: Color) { if self.pixel_count < self.pixels.len() { self.pixels[self.pixel_count] = (x, y, color); self.pixel_count += 1; } } fn fill_rect(&mut self, x: ScreenCoord, y: ScreenCoord, w: Dimension, h: Dimension, color: Color) { for dy in 0..h.raw() { for dx in 0..w.raw() { self.write_pixel(ScreenCoord::new(x.raw() + dx), ScreenCoord::new(y.raw() + dy), color); } } } fn clear(&mut self, _color: Color) { self.pixel_count = 0; } fn flush(&mut self) { self.flushed = true; } fn scroll_up(&mut self, _top: ScreenCoord, _height: Dimension, _by: Dimension, _fill: Color) { self.scrolls += 1; } } /// A screen of `W` by `H` pixels that keeps what is drawn, for tests that /// look at the picture rather than the calls. pub struct GridFramebuffer { pixels: [[Color; W]; H], pub flushes: usize, } impl GridFramebuffer { pub fn new() -> Self { Self { pixels: [[Color::from_raw(0); W]; H], flushes: 0 } } /// The pixel at (x, y), `None` off the screen. pub fn pixel(&self, x: usize, y: usize) -> Option { self.pixels.get(y).and_then(|row| row.get(x)).copied() } } impl Default for GridFramebuffer { fn default() -> Self { Self::new() } } impl Framebuffer for GridFramebuffer { fn width(&self) -> Dimension { Dimension::new(W as u16) } fn height(&self) -> Dimension { Dimension::new(H as u16) } fn write_pixel(&mut self, x: ScreenCoord, y: ScreenCoord, color: Color) { if let Some(px) = self.pixels.get_mut(y.raw() as usize).and_then(|r| r.get_mut(x.raw() as usize)) { *px = color; } } fn fill_rect(&mut self, x: ScreenCoord, y: ScreenCoord, w: Dimension, h: Dimension, color: Color) { for row in y.raw()..y.raw().saturating_add(h.raw()) { for col in x.raw()..x.raw().saturating_add(w.raw()) { self.write_pixel(ScreenCoord::new(col), ScreenCoord::new(row), color); } } } fn clear(&mut self, color: Color) { self.pixels = [[color; W]; H]; } fn flush(&mut self) { self.flushes += 1; } fn scroll_up(&mut self, top: ScreenCoord, height: Dimension, by: Dimension, fill: Color) { let (top, height, by) = (top.raw() as usize, height.raw() as usize, by.raw() as usize); let end = (top + height).min(H); for y in top..end { self.pixels[y] = if y + by < end { self.pixels[y + by] } else { [fill; W] }; } } }