use lazy_static::lazy_static;
use std::ptr;
use crate::color::Color;
lazy_static! {
static ref DEFAULT_PIXEL: u32 = Color::black().to_raw();
}
#[repr(align(4))]
pub struct Pixmap {
map: Vec<u32>,
dimensions: (usize, usize),
}
impl Pixmap {
pub fn new(width: usize, height: usize) -> Self {
Pixmap {
map: vec![*DEFAULT_PIXEL; width * height],
dimensions: (width, height),
}
}
pub fn width(&self) -> usize {
self.dimensions.0
}
pub fn height(&self) -> usize {
self.dimensions.1
}
#[allow(dead_code)]
pub fn dimensions(&self) -> (usize, usize) {
self.dimensions
}
#[allow(dead_code)]
pub fn pixel(&self, x: usize, y: usize) -> Result<Color, PixmapErr> {
Ok(Color::new(self.pixel_raw(x, y)?))
}
pub fn pixel_raw(&self, x: usize, y: usize) -> Result<u32, PixmapErr> {
Ok(self.map[self.pixel_index(x, y)?])
}
pub fn set_pixel(&self, x: usize, y: usize, color: Color) -> Result<(), PixmapErr> {
let mut current_color = self.pixel(x, y)?;
current_color.blend(color);
self.set_pixel_raw(x, y, current_color.to_raw())
}
pub fn set_pixel_raw(&self, x: usize, y: usize, raw: u32) -> Result<(), PixmapErr> {
let index = self.pixel_index(x, y)?;
unsafe {
Pixmap::write_pixel_raw(&self.map, index, raw);
}
Ok(())
}
unsafe fn write_pixel_raw(map: &Vec<u32>, i: usize, raw: u32) {
let pixel_ptr: *mut u32 = (&map[i] as *const u32) as *mut u32;
ptr::write(pixel_ptr, raw);
}
fn pixel_index(&self, x: usize, y: usize) -> Result<usize, PixmapErr> {
if x >= self.dimensions.0 {
return Err(PixmapErr::OutOfBound("x coordinate out of bound"));
} else if y >= self.dimensions.1 {
return Err(PixmapErr::OutOfBound("y coordinate out of bound"));
}
Ok(y * self.dimensions.0 + x)
}
pub fn as_slice(&self) -> &[u32] {
self.map.as_slice()
}
pub fn as_bytes(&self) -> &[u8] {
let slice_u32 = self.as_slice();
let len = slice_u32.len() * 4;
unsafe { core::slice::from_raw_parts(slice_u32.as_ptr() as _, len) }
}
}
unsafe impl Send for Pixmap {}
unsafe impl Sync for Pixmap {}
#[derive(Debug)]
pub enum PixmapErr<'a> {
OutOfBound(&'a str),
}