use crate::*;
use embedded_graphics_core::pixelcolor::*;
use embedded_graphics_core::prelude::*;
use embedded_graphics_core::primitives::*;
pub struct AlphaCanvas<'a, C: RgbColor, const N: usize, const W: usize, const H: usize> {
buffer: &'a mut Framebuffer<C, N, W, H>,
}
impl<'a, C: RgbColor, const N: usize, const W: usize, const H: usize> AlphaCanvas<'a, C, N, W, H>
where
Rgba<C>: Blend<C>,
{
pub fn new(buffer: &'a mut Framebuffer<C, N, W, H>) -> Self {
Self { buffer }
}
}
impl<'a, C: RgbColor, const N: usize, const W: usize, const H: usize> OriginDimensions
for AlphaCanvas<'a, C, N, W, H>
where
Rgba<C>: Blend<C>,
{
fn size(&self) -> Size {
self.buffer.size()
}
}
impl<'a, C: RgbColor, const N: usize, const W: usize, const H: usize> DrawTarget
for AlphaCanvas<'a, C, N, W, H>
where
Rgba<C>: Blend<C>,
{
type Error = core::convert::Infallible;
type Color = Rgba<C>;
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item = Pixel<Self::Color>>,
{
let buf = self.buffer.buf_mut();
for Pixel(point, fg) in pixels {
let x = point.x;
let y = point.y;
if x >= 0 && x < W as i32 && y >= 0 && y < H as i32 {
let xi = x as usize;
let yi = y as usize;
let idx = yi * W + xi;
let bg = buf[idx];
buf[idx] = fg.blend(bg);
}
}
Ok(())
}
fn fill_contiguous<I>(&mut self, area: &Rectangle, colors: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item = Self::Color>,
{
use core::cmp::{max, min};
let mut it = colors.into_iter();
if area.size.width == 0 || area.size.height == 0 {
return Ok(());
}
let fb_left = 0i32;
let fb_top = 0i32;
let fb_right = W as i32; let fb_bottom = H as i32;
let area_left = area.top_left.x;
let area_top = area.top_left.y;
let area_right = area_left + area.size.width as i32; let area_bottom = area_top + area.size.height as i32;
let clip_left = max(fb_left, area_left);
let clip_top = max(fb_top, area_top);
let clip_right = min(fb_right, area_right);
let clip_bottom = min(fb_bottom, area_bottom);
if clip_left >= clip_right || clip_top >= clip_bottom {
let _ = it
.by_ref()
.take((area.size.width as usize) * (area.size.height as usize))
.for_each(drop);
return Ok(());
}
let buf = self.buffer.buf_mut();
for y in area_top..area_bottom {
let inside_y = y >= clip_top && y < clip_bottom;
let left_run = (clip_left - area_left).max(0) as usize;
let mid_run = if inside_y {
(clip_right - clip_left).max(0) as usize
} else {
0
};
let right_run = (area_right - clip_right).max(0) as usize;
for _ in 0..left_run {
let _ = it.next();
}
if inside_y {
let yi = y as usize;
let row_start = yi * W;
let x0 = clip_left as usize;
let idx0 = row_start + x0;
for i in 0..mid_run {
if let Some(fg) = it.next() {
let idx = idx0 + i;
let bg = buf[idx];
buf[idx] = fg.blend(bg);
} else {
break;
}
}
} else {
for _ in 0..((clip_right - clip_left).max(0) as usize) {
let _ = it.next();
}
}
for _ in 0..right_run {
let _ = it.next();
}
}
Ok(())
}
fn fill_solid(&mut self, area: &Rectangle, color: Self::Color) -> Result<(), Self::Error> {
use core::cmp::{max, min};
let a = color.a();
if a == 0 {
return Ok(());
}
let fb_left = 0i32;
let fb_top = 0i32;
let fb_right = W as i32; let fb_bottom = H as i32;
let area_left = area.top_left.x;
let area_top = area.top_left.y;
let area_right = area_left + area.size.width as i32; let area_bottom = area_top + area.size.height as i32;
let clip_left = max(fb_left, area_left);
let clip_top = max(fb_top, area_top);
let clip_right = min(fb_right, area_right);
let clip_bottom = min(fb_bottom, area_bottom);
if clip_left >= clip_right || clip_top >= clip_bottom {
return Ok(());
}
let buf = self.buffer.buf_mut();
if a == 255 {
let oc: C = color.rgb();
for y in clip_top as usize..clip_bottom as usize {
let row_start = y * W;
let start = row_start + clip_left as usize;
let end = row_start + clip_right as usize;
for idx in start..end {
buf[idx] = oc;
}
}
return Ok(());
}
for y in clip_top as usize..clip_bottom as usize {
let row_start = y * W;
let start = row_start + clip_left as usize;
let end = row_start + clip_right as usize;
for idx in start..end {
let bg = buf[idx];
buf[idx] = color.blend(bg);
}
}
Ok(())
}
fn clear(&mut self, color: Self::Color) -> Result<(), Self::Error> {
let a = color.a();
if a == 0 {
return Ok(());
}
let buf = self.buffer.buf_mut();
if a == 255 {
let oc: C = color.rgb();
for px in buf.iter_mut() {
*px = oc;
}
return Ok(());
}
for px in buf.iter_mut() {
let bg = *px;
*px = color.blend(bg);
}
Ok(())
}
}