use core::{ hint::black_box, slice::{Chunks, Iter}, }; use atmega_hal::{ Atmega, Usart, pac::USART0, port::{PB3, PB5, PD0, PD1, Pin, PinOps, mode}, }; use embedded_hal::delay::DelayNs; use ufmt::derive::uDebug; use crate::{ CoreClock, display::{Color, Display, Position, Rgb565, Writeable}, }; #[repr(u8)] enum NonBssByte { V = 1, } pub struct NonBss { _hack: NonBssByte, pub buf: Buf, } impl NonBss<[u8; N]> { pub const fn new(buf: [u8; N]) -> Self { Self { _hack: NonBssByte::V, buf, } } } macro_rules! non_bss_statics {( $( $(#$attr:tt)* $pub:vis static ref $NAME:ident : [$u8:ty] = *include_bytes!($($args:tt)*); )* ) => ( $( $(#$attr)* $pub const $NAME: &[u8] = { static $NAME: NonBss<[$u8; ::core::include_bytes!($($args)*).len()]> = NonBss::new(*::core::include_bytes!($($args)*)); &$NAME.buf }; )* )} // https://qoiformat.org/qoi-specification.pdf // static LARGE: [u8; 1966] = *include_bytes!("../images/large.qoi"); // static SHEEP: [u8; 852] = *include_bytes!("../images/sheep.qoi"); // non_bss_statics! { // static ref SHEEP: [u8] = *include_bytes!("../images/sheep.qoi"); // // static ref LARGE: [u8] = *include_bytes!("../images/large.qoi"); // } static SHEEP: [u8; 446] = *include_bytes!("../images/sheep.qoi"); // const LARGE_C1: [u8; 512] = LARGE.as_chunks().0[0]; // const LARGE_C2: [u8; 512] = LARGE.as_chunks().0[1]; // const LARGE_C3: [u8; 512] = LARGE.as_chunks().0[2]; // const LARGE_C4: &[u8] = LARGE.as_chunks::<512>().1; #[derive(Debug, uDebug)] pub enum QoiErr { InvalidMagicNumber, UnexpectedEOF, } // #[derive(Default)] // struct LargeIter { // index: usize, // } // impl Iterator for LargeIter { // type Item = u8; // fn next(&mut self) -> Option { // if self.index >= N { // return None; // } // let old_idx = self.index; // self.index += 1; // Some(SHEEP[old_idx]) // } // } pub fn draw_image( serial: &mut Usart, Pin, CoreClock>, display: &mut Display, position: Position, ) -> Result<(), QoiErr> { // let a = LARGE[black_box(50)]; // ufmt::uwriteln!(serial, "Successfully read QOI header {}", a).unwrap(); let mut iter = SHEEP.iter().map(|v| *v); if let (Some(113), Some(111), Some(105), Some(102)) = (iter.next(), iter.next(), iter.next(), iter.next()) { fn next(iter: &mut dyn Iterator) -> Result { iter.next().ok_or(QoiErr::UnexpectedEOF) } let width = u32::from_be_bytes([ next(&mut iter)?, next(&mut iter)?, next(&mut iter)?, next(&mut iter)?, ]) as u16; let height = u32::from_be_bytes([ next(&mut iter)?, next(&mut iter)?, next(&mut iter)?, next(&mut iter)?, ]) as u16; let _channels = next(&mut iter)?; let _colorspace = next(&mut iter)?; ufmt::uwriteln!(serial, "Successfully read QOI header").unwrap(); display.set_window( position, Position { x: position.x + 191, y: position.y + 191, }, ); let qoi_iter = QoiIterator::from(&mut iter, width * height); let scale_iter = ScaleIterator { qoi: qoi_iter, last_row: [Rgb565::yellow(); 64], scale_factor: 3, width: width as usize, counter: 0, index: 0, }; let mut counter = 0u32; for pixel in scale_iter { let [c1, c2] = pixel.as_color().bytes; display.write(Writeable::Data(&[c1, c2])); counter += 1; } ufmt::uwriteln!(serial, "Counter: {}", counter).unwrap(); Ok(()) } else { Err(QoiErr::InvalidMagicNumber) } } struct ScaleIterator<'a> { qoi: QoiIterator<'a>, last_row: [Rgb565; 64], width: usize, scale_factor: usize, counter: usize, index: usize, } impl<'a> Iterator for ScaleIterator<'a> { type Item = Rgb565; fn next(&mut self) -> Option { if self.index >= self.width * self.scale_factor { self.counter = (self.counter + 1) % self.scale_factor; self.index = 0; } let index_div = self.index / self.scale_factor; if self.counter % self.scale_factor == 0 { if (self.index % self.scale_factor) == 0 { if let Some(pixel) = self.qoi.next() { self.last_row[index_div] = pixel; self.index += 1; Some(pixel) } else { None } } else { let pixel = self.last_row[index_div]; self.index += 1; Some(pixel) } } else { let pixel = self.last_row[index_div]; self.index += 1; Some(pixel) } } } struct QoiIterator<'a> { inner: &'a mut dyn Iterator, prev_pixels: [Rgb565; 64], last_pixel: Rgb565, repeat: u8, expected_colors: u16, parsed_colors: u16, } impl<'a> QoiIterator<'a> { fn from(bytes: &'a mut dyn Iterator, expected: u16) -> Self { QoiIterator { inner: bytes, prev_pixels: [Rgb565(0, 255, 0); 64], last_pixel: Rgb565(0, 0, 0), repeat: 0, expected_colors: expected, parsed_colors: 0, } } } impl<'a> Iterator for QoiIterator<'a> { type Item = Rgb565; fn next(&mut self) -> Option { if self.parsed_colors >= self.expected_colors { return None; } self.parsed_colors += 1; if self.repeat > 0 { self.repeat -= 1; return Some(self.last_pixel); } if let Some(byte) = self.inner.next() { let color = if byte == 0xff { let red = self.inner.next().unwrap(); let green = self.inner.next().unwrap(); let blue = self.inner.next().unwrap(); let _alpha = self.inner.next().unwrap(); Rgb565(red, green, blue) } else if byte == 0b11111110 { let red = self.inner.next()?; let green = self.inner.next()?; let blue = self.inner.next()?; Rgb565(red, green, blue) } else { let tag = (0b11000000 & byte) >> 6; let data = 0b00111111 & byte; if tag == 0 { self.prev_pixels[data as usize] } else if tag == 1 { let dr = ((0b110000 & data) >> 4) as i8 - 2; let dg = ((0b001100 & data) >> 2) as i8 - 2; let db = (0b000011 & data) as i8 - 2; Rgb565( (self.last_pixel.0 as i8).wrapping_add(dr) as u8, (self.last_pixel.1 as i8).wrapping_add(dg) as u8, (self.last_pixel.2 as i8).wrapping_add(db) as u8, ) } else if tag == 2 { let second = self.inner.next()?; let dg = data as i8 - 32; let dr_dg = ((0b11110000 & second) >> 4) as i8 - 8; let db_dg = (0b00001111 & second) as i8 - 8; let dr = dr_dg + dg; let db = db_dg + dg; Rgb565( (self.last_pixel.0 as i8 + dr) as u8, (self.last_pixel.1 as i8 + dg) as u8, (self.last_pixel.2 as i8 + db) as u8, ) } else if tag == 3 { // QOI_OP_RUN self.repeat = data; self.last_pixel } else { Rgb565::green() } }; self.last_pixel = color; let hash = ((color.0 as u32 * 3 + color.1 as u32 * 5 + color.2 as u32 * 7 + 255 as u32 * 11) % 64) as usize; self.prev_pixels[hash] = color; Some(color) } else { None } } }