use std::sync::{Arc, Mutex}; use femtos::Instant; use crate::traits::ClockedQueue; pub const MASK_COLOUR: u32 = 0xFFFFFFFF; #[derive(Copy, Clone, Default, Debug, PartialEq, Eq)] pub enum PixelEncoding { #[default] RGBA, ARGB, ABGR, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Pixel { Rgb(u8, u8, u8), Rgba(u8, u8, u8, u8), Mask, } impl Pixel { #[inline] pub fn encode(self, encoding: PixelEncoding) -> u32 { let (r, g, b, a) = match self { Pixel::Rgb(r, g, b) => (r as u32, g as u32, b as u32, 255), Pixel::Rgba(r, g, b, a) => (r as u32, g as u32, b as u32, a as u32), Pixel::Mask => return MASK_COLOUR, }; match encoding { PixelEncoding::RGBA => (r << 24) | (g << 16) | (b << 8) | a, PixelEncoding::ARGB => (a << 24) | (r << 16) | (g << 8) | b, PixelEncoding::ABGR => (a << 24) | (b << 16) | (g << 8) | r, } } } #[derive(Clone, Default)] pub struct Frame { pub width: u32, pub height: u32, pub encoding: PixelEncoding, pub bitmap: Vec, } impl Frame { pub fn new(width: u32, height: u32, encoding: PixelEncoding) -> Self { Self { width, height, encoding, bitmap: vec![0; (width * height) as usize], } } pub fn new_shared(width: u32, height: u32, encoding: PixelEncoding) -> Arc> { Arc::new(Mutex::new(Frame::new(width, height, encoding))) } pub fn set_size(&mut self, width: u32, height: u32) { self.width = width; self.height = height; self.bitmap.resize((width * height) as usize, 0); } #[inline] pub fn set_pixel(&mut self, pos_x: u32, pos_y: u32, pixel: Pixel) { match pixel { Pixel::Mask => {}, value if pos_x < self.width && pos_y < self.height => { self.bitmap[(pos_x + (pos_y * self.width)) as usize] = value.encode(self.encoding); }, _ => {}, } } #[inline] pub fn set_encoded_pixel(&mut self, pos_x: u32, pos_y: u32, pixel: u32) { match pixel { MASK_COLOUR => {}, value if pos_x < self.width && pos_y < self.height => { self.bitmap[(pos_x + (pos_y * self.width)) as usize] = value; }, _ => {}, } } pub fn blit>(&mut self, pos_x: u32, pos_y: u32, mut bitmap: B, width: u32, height: u32) { for y in pos_y..(pos_y + height) { for x in pos_x..(pos_x + width) { match bitmap.next().unwrap() { Pixel::Mask => {}, value if x < self.width && y < self.height => { self.bitmap[(x + (y * self.width)) as usize] = value.encode(self.encoding); }, _ => {}, } } } } pub fn clear(&mut self, value: Pixel) { let value = value.encode(self.encoding); self.bitmap.iter_mut().for_each(|pixel| *pixel = value); } } pub fn frame_queue(width: u32, height: u32) -> (FrameSender, FrameReceiver) { let sender = FrameSender { encoding: Arc::new(Mutex::new(PixelEncoding::RGBA)), queue: ClockedQueue::new(10), }; let receiver = FrameReceiver { max_size: (width, height), encoding: sender.encoding.clone(), queue: sender.queue.clone(), }; (sender, receiver) } pub struct FrameSender { encoding: Arc>, queue: ClockedQueue, } impl FrameSender { pub fn encoding(&self) -> PixelEncoding { *self.encoding.lock().unwrap() } pub fn add(&self, clock: Instant, frame: Frame) { self.queue.push(clock, frame); } } pub struct FrameReceiver { max_size: (u32, u32), encoding: Arc>, queue: ClockedQueue, } impl FrameReceiver { pub fn max_size(&self) -> (u32, u32) { self.max_size } pub fn request_encoding(&self, encoding: PixelEncoding) { *self.encoding.lock().unwrap() = encoding; } pub fn latest(&self) -> Option<(Instant, Frame)> { self.queue.pop_latest() } }