use crate::{
interface::{Interface, InterfacePixelFormat},
models::Model,
Display,
};
use embedded_graphics_core::prelude::*;
use embedded_hal::digital::OutputPin;
pub trait DrawBatch<DI, M, I>
where
DI: Interface,
M: Model,
M::ColorFormat: InterfacePixelFormat<DI::Word>,
I: IntoIterator<Item = Pixel<M::ColorFormat>>,
{
fn draw_batch(&mut self, item_pixels: I) -> Result<(), DI::Error>;
}
impl<DI, M, RST, I> DrawBatch<DI, M, I> for Display<DI, M, RST>
where
DI: Interface,
M: Model,
M::ColorFormat: InterfacePixelFormat<DI::Word>,
I: IntoIterator<Item = Pixel<M::ColorFormat>>,
RST: OutputPin,
{
fn draw_batch(&mut self, item_pixels: I) -> Result<(), DI::Error> {
let pixels = item_pixels.into_iter();
let rows = to_rows(pixels);
let blocks = to_blocks(rows);
for PixelBlock {
x_left,
x_right,
y_top,
y_bottom,
colors,
..
} in blocks
{
self.set_pixels(x_left, y_top, x_right, y_bottom, colors)?;
}
Ok(())
}
}
const MAX_ROW_SIZE: usize = 50;
const MAX_BLOCK_SIZE: usize = 100;
type RowColors<C> = heapless::Vec<C, MAX_ROW_SIZE>;
type BlockColors<C> = heapless::Vec<C, MAX_BLOCK_SIZE>;
#[derive(Debug, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct RowIterator<C, P>
where
C: PixelColor,
P: Iterator<Item = Pixel<C>>,
{
pixels: P,
x_left: u16,
x_right: u16,
y: u16,
colors: RowColors<C>,
first_pixel: bool,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct BlockIterator<C, R>
where
C: PixelColor,
R: Iterator<Item = PixelRow<C>>,
{
rows: R,
x_left: u16,
x_right: u16,
y_top: u16,
y_bottom: u16,
colors: BlockColors<C>,
first_row: bool,
}
pub struct PixelRow<C>
where
C: PixelColor,
{
pub x_left: u16,
pub x_right: u16,
pub y: u16,
pub colors: RowColors<C>,
}
pub struct PixelBlock<C>
where
C: PixelColor,
{
pub x_left: u16,
pub x_right: u16,
pub y_top: u16,
pub y_bottom: u16,
pub colors: BlockColors<C>,
}
fn to_rows<C, P>(pixels: P) -> RowIterator<C, P>
where
C: PixelColor,
P: Iterator<Item = Pixel<C>>,
{
RowIterator::<C, P> {
pixels,
x_left: 0,
x_right: 0,
y: 0,
colors: RowColors::new(),
first_pixel: true,
}
}
fn to_blocks<C, R>(rows: R) -> BlockIterator<C, R>
where
C: PixelColor,
R: Iterator<Item = PixelRow<C>>,
{
BlockIterator::<C, R> {
rows,
x_left: 0,
x_right: 0,
y_top: 0,
y_bottom: 0,
colors: BlockColors::new(),
first_row: true,
}
}
impl<C, P> Iterator for RowIterator<C, P>
where
C: PixelColor,
P: Iterator<Item = Pixel<C>>,
{
type Item = PixelRow<C>;
fn next(&mut self) -> Option<Self::Item> {
loop {
let next_pixel = self.pixels.next();
match next_pixel {
None => {
if self.first_pixel {
return None; }
let row = PixelRow {
x_left: self.x_left,
x_right: self.x_right,
y: self.y,
colors: self.colors.clone(),
};
self.colors.clear();
self.first_pixel = true;
return Some(row);
}
Some(Pixel(coord, color)) => {
if coord.x < 0 || coord.y < 0 {
continue;
}
let x = coord.x as u16;
let y = coord.y as u16;
if self.first_pixel {
self.first_pixel = false;
self.x_left = x;
self.x_right = x;
self.y = y;
self.colors.clear();
if self.colors.push(color).is_err() {
return None;
}
continue;
}
if x == self.x_right.wrapping_add(1)
&& y == self.y
&& self.colors.push(color).is_ok()
{
self.x_right = x;
continue;
}
let row = PixelRow {
x_left: self.x_left,
x_right: self.x_right,
y: self.y,
colors: self.colors.clone(),
};
self.x_left = x;
self.x_right = x;
self.y = y;
self.colors.clear();
if self.colors.push(color).is_err() {
return None;
}
return Some(row);
}
}
}
}
}
impl<C, R> Iterator for BlockIterator<C, R>
where
C: PixelColor,
R: Iterator<Item = PixelRow<C>>,
{
type Item = PixelBlock<C>;
fn next(&mut self) -> Option<Self::Item> {
loop {
let next_row = self.rows.next();
match next_row {
None => {
if self.first_row {
return None; }
let row = PixelBlock {
x_left: self.x_left,
x_right: self.x_right,
y_top: self.y_top,
y_bottom: self.y_bottom,
colors: self.colors.clone(),
};
self.colors.clear();
self.first_row = true;
return Some(row);
}
Some(PixelRow {
x_left,
x_right,
y,
colors,
..
}) => {
if self.first_row {
self.first_row = false;
self.x_left = x_left;
self.x_right = x_right;
self.y_top = y;
self.y_bottom = y;
self.colors.clear();
self.colors.extend_from_slice(&colors).expect("never");
continue;
}
if y == self.y_bottom + 1 && x_left == self.x_left && x_right == self.x_right {
if self.colors.extend_from_slice(&colors).is_ok() {
self.y_bottom = y;
continue;
}
}
let row = PixelBlock {
x_left: self.x_left,
x_right: self.x_right,
y_top: self.y_top,
y_bottom: self.y_bottom,
colors: self.colors.clone(),
};
self.x_left = x_left;
self.x_right = x_right;
self.y_top = y;
self.y_bottom = y;
self.colors.clear();
self.colors.extend_from_slice(&colors).expect("never");
return Some(row);
}
}
}
}
}