use crate::{Error, ST7789};
use display_interface::WriteOnlyDataCommand;
use embedded_graphics_core::{
pixelcolor::{raw::RawU16, Rgb565},
prelude::*,
};
use embedded_hal::digital::v2::OutputPin;
pub trait DrawBatch<DI, RST, BL, T, PinE>
where
DI: WriteOnlyDataCommand,
RST: OutputPin<Error = PinE>,
BL: OutputPin<Error = PinE>,
T: IntoIterator<Item = Pixel<Rgb565>>,
{
fn draw_batch(&mut self, item_pixels: T) -> Result<(), Error<PinE>>;
}
impl<DI, RST, BL, T, PinE> DrawBatch<DI, RST, BL, T, PinE> for ST7789<DI, RST, BL>
where
DI: WriteOnlyDataCommand,
RST: OutputPin<Error = PinE>,
BL: OutputPin<Error = PinE>,
T: IntoIterator<Item = Pixel<Rgb565>>,
{
fn draw_batch(&mut self, item_pixels: T) -> Result<(), Error<PinE>> {
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 = heapless::Vec<u16, MAX_ROW_SIZE>;
type BlockColors = heapless::Vec<u16, MAX_BLOCK_SIZE>;
#[derive(Debug, Clone)]
pub struct RowIterator<P: Iterator<Item = Pixel<Rgb565>>> {
pixels: P,
x_left: u16,
x_right: u16,
y: u16,
colors: RowColors,
first_pixel: bool,
}
#[derive(Debug, Clone)]
pub struct BlockIterator<R: Iterator<Item = PixelRow>> {
rows: R,
x_left: u16,
x_right: u16,
y_top: u16,
y_bottom: u16,
colors: BlockColors,
first_row: bool,
}
pub struct PixelRow {
pub x_left: u16,
pub x_right: u16,
pub y: u16,
pub colors: RowColors,
}
pub struct PixelBlock {
pub x_left: u16,
pub x_right: u16,
pub y_top: u16,
pub y_bottom: u16,
pub colors: BlockColors,
}
fn to_rows<P>(pixels: P) -> RowIterator<P>
where
P: Iterator<Item = Pixel<Rgb565>>,
{
RowIterator::<P> {
pixels,
x_left: 0,
x_right: 0,
y: 0,
colors: RowColors::new(),
first_pixel: true,
}
}
fn to_blocks<R>(rows: R) -> BlockIterator<R>
where
R: Iterator<Item = PixelRow>,
{
BlockIterator::<R> {
rows,
x_left: 0,
x_right: 0,
y_top: 0,
y_bottom: 0,
colors: BlockColors::new(),
first_row: true,
}
}
impl<P: Iterator<Item = Pixel<Rgb565>>> Iterator for RowIterator<P> {
type Item = PixelRow;
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;
let color = RawU16::from(color).into_inner();
if self.first_pixel {
self.first_pixel = false;
self.x_left = x;
self.x_right = x;
self.y = y;
self.colors.clear();
self.colors.push(color).expect("never");
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();
self.colors.push(color).expect("never");
return Some(row);
}
}
}
}
}
impl<R: Iterator<Item = PixelRow>> Iterator for BlockIterator<R> {
type Item = PixelBlock;
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);
}
}
}
}
}