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<u32>,
}
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<Mutex<Frame>> {
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<B: Iterator<Item = Pixel>>(&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<Mutex<PixelEncoding>>,
queue: ClockedQueue<Frame>,
}
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<Mutex<PixelEncoding>>,
queue: ClockedQueue<Frame>,
}
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()
}
}