use super::{Image, ImageMut};
use crate::util::vector::Vector;
#[derive(Clone, Debug)]
pub struct Canvas<P> {
data: Box<[P]>,
width: usize,
height: usize,
}
impl<P> Canvas<P>
where
P: Clone,
{
pub fn with_resolution(color: P, width: usize, height: usize) -> Self {
let data = vec![color; width * height].into_boxed_slice();
Self {
data,
width,
height,
}
}
pub fn try_from_raw_data(data: Box<[P]>, width: usize, height: usize) -> Option<Self> {
if data.len() != width * height {
return None;
}
Some(Self {
data,
width,
height,
})
}
pub fn raw_data(&self) -> &[P] {
&self.data
}
}
impl<P> Image<P> for Canvas<P>
where
P: Clone,
{
fn pixel(&self, position: Vector<i32>) -> Option<P> {
if position.x() < 0 || position.y() < 0 {
return None;
}
let (x, y) = (position.x() as usize, position.y() as usize);
if x >= self.width || y >= self.height {
None
} else {
self.data.get(x + self.width * y).cloned()
}
}
unsafe fn pixel_unchecked(&self, position: Vector<i32>) -> P {
let (x, y) = (position.x() as usize, position.y() as usize);
self.data[x + self.width * y].clone()
}
fn width(&self) -> i32 {
self.width as i32
}
fn height(&self) -> i32 {
self.height as i32
}
}
impl<P> ImageMut<P> for Canvas<P>
where
P: Clone,
{
fn set_pixel(&mut self, position: Vector<i32>, value: &P) {
if position.x() < 0 || position.y() < 0 {
return;
}
let (x, y) = (position.x() as usize, position.y() as usize);
if x < self.width && y < self.height {
self.data[x + self.width * y] = value.clone();
}
}
fn modify_pixel(
&mut self,
position: Vector<i32>,
function: &mut dyn FnMut((i32, i32), P) -> P,
) {
if position.x() < 0 || position.y() < 0 {
return;
}
let (x, y) = (position.x() as usize, position.y() as usize);
if x < self.width && y < self.height {
self.data[x + self.width * y] =
function(position.split(), self.data[x + self.width * y].clone());
}
}
unsafe fn set_pixel_unchecked(&mut self, position: Vector<i32>, value: &P) {
let (x, y) = (position.x() as usize, position.y() as usize);
self.data[x + self.width * y] = value.clone();
}
fn clear(&mut self, color: P) {
self.data.fill(color);
}
}