use image::{Rgba, RgbaImage};
#[derive(Clone, Copy, Debug)]
pub struct BlitRect {
pub x: u32,
pub y: u32,
pub w: u32,
pub h: u32,
}
impl BlitRect {
pub fn new(x: u32, y: u32, w: u32, h: u32) -> Self {
Self { x, y, w, h }
}
}
#[derive(Clone, Copy, Debug)]
pub struct BlitOptions {
pub rotated: bool,
pub extrude: u32,
pub outlines: bool,
}
pub fn blit_rgba(
src: &RgbaImage,
canvas: &mut RgbaImage,
dst: BlitRect,
src_rect: BlitRect,
options: BlitOptions,
) {
let (cw, ch) = canvas.dimensions();
let BlitRect {
x: dx,
y: dy,
w: _,
h: _,
} = dst;
let BlitRect {
x: sx,
y: sy,
w: sw,
h: sh,
} = src_rect;
let BlitOptions {
rotated,
extrude,
outlines,
} = options;
let (rw, rh) = if rotated { (sh, sw) } else { (sw, sh) };
for yy in 0..rh {
for xx in 0..rw {
let (ix, iy) = if rotated {
(sx + yy, sy + (sh - 1 - xx))
} else {
(sx + xx, sy + yy)
};
if dx + xx < cw && dy + yy < ch {
let px = *src.get_pixel(ix, iy);
canvas.put_pixel(dx + xx, dy + yy, px);
}
}
}
if outlines {
let red = Rgba([255, 0, 0, 255]);
for xx in 0..rw {
if dx + xx < cw && dy < ch {
canvas.put_pixel(dx + xx, dy, red);
}
let by = dy + rh.saturating_sub(1);
if dx + xx < cw && by < ch {
canvas.put_pixel(dx + xx, by, red);
}
}
for yy in 0..rh {
if dx < cw && dy + yy < ch {
canvas.put_pixel(dx, dy + yy, red);
}
let rx = dx + rw.saturating_sub(1);
if rx < cw && dy + yy < ch {
canvas.put_pixel(rx, dy + yy, red);
}
}
}
if extrude > 0 {
for e in 1..=extrude {
if dy >= e && dy < ch {
for xx in 0..rw {
if dx + xx < cw {
let p = *canvas.get_pixel(dx + xx, dy);
if dy >= e {
canvas.put_pixel(dx + xx, dy - e, p);
}
}
}
}
if dy + rh - 1 < ch && dy + rh - 1 + e < ch {
for xx in 0..rw {
if dx + xx < cw {
let p = *canvas.get_pixel(dx + xx, dy + rh - 1);
canvas.put_pixel(dx + xx, dy + rh - 1 + e, p);
}
}
}
if dx >= e && dx < cw {
for yy in 0..rh {
if dy + yy < ch {
let p = *canvas.get_pixel(dx, dy + yy);
canvas.put_pixel(dx - e, dy + yy, p);
}
}
}
if dx + rw - 1 < cw && dx + rw - 1 + e < cw {
for yy in 0..rh {
if dy + yy < ch {
let p = *canvas.get_pixel(dx + rw - 1, dy + yy);
canvas.put_pixel(dx + rw - 1 + e, dy + yy, p);
}
}
}
}
let c00 = if dx < cw && dy < ch {
*canvas.get_pixel(dx, dy)
} else {
Rgba([0, 0, 0, 0])
};
let c10 = if dx + rw > 0 && dx + rw - 1 < cw && dy < ch {
*canvas.get_pixel(dx + rw - 1, dy)
} else {
Rgba([0, 0, 0, 0])
};
let c01 = if dx < cw && dy + rh > 0 && dy + rh - 1 < ch {
*canvas.get_pixel(dx, dy + rh - 1)
} else {
Rgba([0, 0, 0, 0])
};
let c11 = if dx + rw > 0 && dx + rw - 1 < cw && dy + rh > 0 && dy + rh - 1 < ch {
*canvas.get_pixel(dx + rw - 1, dy + rh - 1)
} else {
Rgba([0, 0, 0, 0])
};
if dx >= 1 && dy >= 1 {
for ex in 1..=extrude {
for ey in 1..=extrude {
if dx >= ex && dy >= ey {
canvas.put_pixel(dx - ex, dy - ey, c00);
}
}
}
}
if dy >= 1 && dx + rw - 1 < cw {
for ex in 1..=extrude {
for ey in 1..=extrude {
if dy >= ey && dx + rw - 1 + ex < cw {
canvas.put_pixel(dx + rw - 1 + ex, dy - ey, c10);
}
}
}
}
if dx >= 1 && dy + rh - 1 < ch {
for ex in 1..=extrude {
for ey in 1..=extrude {
if dx >= ex && dy + rh - 1 + ey < ch {
canvas.put_pixel(dx - ex, dy + rh - 1 + ey, c01);
}
}
}
}
if dx + rw - 1 < cw && dy + rh - 1 < ch {
for ex in 1..=extrude {
for ey in 1..=extrude {
if dx + rw - 1 + ex < cw && dy + rh - 1 + ey < ch {
canvas.put_pixel(dx + rw - 1 + ex, dy + rh - 1 + ey, c11);
}
}
}
}
}
}