141 lines
3.9 KiB
Rust
141 lines
3.9 KiB
Rust
#![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<const W: usize, const H: usize> {
|
|
pixels: [[Color; W]; H],
|
|
pub flushes: usize,
|
|
}
|
|
|
|
impl<const W: usize, const H: usize> GridFramebuffer<W, H> {
|
|
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<Color> {
|
|
self.pixels.get(y).and_then(|row| row.get(x)).copied()
|
|
}
|
|
}
|
|
|
|
impl<const W: usize, const H: usize> Default for GridFramebuffer<W, H> {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
impl<const W: usize, const H: usize> Framebuffer for GridFramebuffer<W, H> {
|
|
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] };
|
|
}
|
|
}
|
|
}
|