use super::traits::Drawable;
use crate::Result;
pub struct Circle {
pub position: [u32; 2],
pub color: [u8; 4],
pub radius: u32,
pub filled: bool,
pub thickness: u32,
}
impl Drawable for Circle {
fn draw_on(&self, image: &mut crate::img::Image) -> Result<()> {
let (cx, cy) = (self.position[0] as i32, self.position[1] as i32);
let radius = self.radius as i32;
let thickness = self.thickness as i32;
let dims = image.dimensions();
let outer_radius = radius + thickness;
let outer_radius_sq = outer_radius.pow(2);
let inner_radius_sq = radius.pow(2);
for dy in -outer_radius..outer_radius {
for dx in -outer_radius..outer_radius {
let nx = cx + dx;
let ny = cy + dy;
if nx < 0 || ny < 0 {
continue;
}
let (nx, ny) = (nx as u32, ny as u32);
if nx >= dims[0] || ny >= dims[1] {
continue;
}
let distance_sq = dx * dx + dy * dy;
let draw_pixel = match self.filled {
true => distance_sq <= inner_radius_sq,
false => distance_sq <= outer_radius_sq && distance_sq >= inner_radius_sq,
};
if draw_pixel {
image.alpha_blend_pixel([nx, ny], self.color)?;
}
}
}
Ok(())
}
}
pub struct AABB {
pub position: [u32; 2],
pub size: [u32; 2],
pub color: [u8; 4],
pub filled: bool,
pub thickness: u32,
}
impl Drawable for AABB {
fn draw_on(&self, image: &mut crate::img::Image) -> Result<()> {
let (cx, cy) = (self.position[0] as i32, self.position[1] as i32);
let dims = image.dimensions();
let width = self.size[0] as i32;
let height = self.size[1] as i32;
let thickness = self.thickness as i32;
let left_x = cx - thickness;
let right_x = cx + width + thickness;
let top_y = cy - thickness;
let bottom_y = cy + height + thickness;
for x in left_x..right_x {
for y in top_y..bottom_y {
if x < 0 || y < 0 {
continue;
}
let nx = x as u32;
let ny = y as u32;
if nx >= dims[0] || ny >= dims[1] {
continue;
}
let on_left_edge = x - left_x <= thickness;
let on_right_edge = right_x - x <= thickness;
let on_top_edge = y - top_y < thickness;
let on_bottom_edge = bottom_y - y <= thickness;
let draw_pixel =
self.filled || on_left_edge || on_right_edge || on_top_edge || on_bottom_edge;
if draw_pixel {
image.alpha_blend_pixel([nx, ny], self.color)?;
}
}
}
Ok(())
}
}
pub struct Line {
pub start: [u32; 2],
pub end: [u32; 2],
pub color: [u8; 4],
pub thickness: u32,
}
impl Drawable for Line {
fn draw_on(&self, image: &mut crate::img::Image) -> Result<()> {
let [x0, y0] = self.start;
let [x1, y1] = self.end;
let dims = image.dimensions();
let x0 = x0 as i32;
let y0 = y0 as i32;
let x1 = x1 as i32;
let y1 = y1 as i32;
let thickness = self.thickness as i32;
let half_thickness = thickness / 2;
let dx = (x1 - x0).abs();
let dy = -(y1 - y0).abs();
let sx = if x0 < x1 { 1 } else { -1 };
let sy = if y0 < y1 { 1 } else { -1 };
let mut err = dx + dy;
let mut x = x0;
let mut y = y0;
loop {
for tx in -half_thickness..=half_thickness {
for ty in -half_thickness..=half_thickness {
let nx = x + tx;
let ny = y + ty;
if nx < 0 || ny < 0 {
continue;
}
let (nx, ny) = (nx as u32, ny as u32);
if nx >= dims[0] || ny >= dims[1] {
continue;
}
image.alpha_blend_pixel([nx, ny], self.color)?;
}
}
if x == x1 && y == y1 {
break;
}
let err_twice = 2 * err;
if err_twice >= dy {
err += dy;
x += sx;
}
if err_twice <= dx {
err += dx;
y += sy;
}
}
Ok(())
}
}