use super::color_to_u32;
use kas::cast::traits::*;
use kas::draw::PassId;
use kas::draw::color;
use kas::geom::{Coord, Quad, Vec2};
use kas::prelude::{Offset, Rect};
#[derive(Clone, Debug, Default)]
struct PassData {
rects: Vec<(Quad, color::Rgba)>,
lines: Vec<(Vec2, Vec2, f32, color::Rgba)>,
}
#[derive(Debug, Default)]
pub struct Draw {
passes: Vec<PassData>,
}
impl Draw {
pub fn rect(&mut self, pass: PassId, rect: Quad, col: color::Rgba) {
if !(rect.a < rect.b) {
return;
}
let pass = pass.pass();
if self.passes.len() <= pass {
self.passes.resize(pass + 8, Default::default());
}
self.passes[pass].rects.push((rect, col));
}
pub fn frame(&mut self, pass: PassId, outer: Quad, inner: Quad, col: color::Rgba) {
let aa = outer.a;
let bb = outer.b;
let mut cc = inner.a;
let mut dd = inner.b;
if !(aa < bb) {
return;
}
if !(aa <= cc) || !(cc <= bb) {
cc = aa;
}
if !(aa <= dd) || !(dd <= bb) {
dd = bb;
}
if !(cc <= dd) {
dd = cc;
}
let ac = Vec2(aa.0, cc.1);
let ad = Vec2(aa.0, dd.1);
let bc = Vec2(bb.0, cc.1);
let bd = Vec2(bb.0, dd.1);
let cd = Vec2(cc.0, dd.1);
let dc = Vec2(dd.0, cc.1);
self.rect(pass, Quad::from_coords(aa, bc), col);
self.rect(pass, Quad::from_coords(ad, bb), col);
self.rect(pass, Quad::from_coords(ac, cd), col);
self.rect(pass, Quad::from_coords(dc, bd), col);
}
pub fn line(&mut self, pass: PassId, p1: Vec2, p2: Vec2, width: f32, col: color::Rgba) {
let pass = pass.pass();
if self.passes.len() <= pass {
self.passes.resize(pass + 8, Default::default());
}
let r = 0.5 * width;
self.passes[pass].lines.push((p1, p2, r, col));
}
pub fn render(
&mut self,
pass: usize,
buffer: &mut [u32],
size: (usize, usize),
clip_rect: Rect,
offset: Offset,
) {
let Some(pass) = self.passes.get_mut(pass) else {
return;
};
let (clip_p, clip_q) = (clip_rect.pos, clip_rect.pos2());
for (rect, col) in pass.rects.drain(..) {
let p = (Coord::conv_nearest(rect.a) - offset).clamp(clip_p, clip_q);
let q = (Coord::conv_nearest(rect.b) - offset).clamp(clip_p, clip_q);
let (x0, x1): (usize, usize) = (p.0.cast(), q.0.cast());
let c = color_to_u32(col);
for y in p.1..q.1 {
let offset = usize::conv(y) * size.0;
buffer[offset + x0..offset + x1].fill(c);
}
}
for (p1, p2, r, col) in pass.lines.drain(..) {
let c = color_to_u32(col);
let (dx, dy) = (p2.0 - p1.0, p2.1 - p1.1);
let d_inv = 1.0 / (dx * dx + dy * dy).sqrt();
let (mut a, mut b) = (p1, p2);
if a.0 > b.0 {
std::mem::swap(&mut a.0, &mut b.0);
}
if a.1 > b.1 {
std::mem::swap(&mut a.1, &mut b.1);
}
a -= Vec2::splat(r);
b += Vec2::splat(r);
let a = (Coord::conv_nearest(a) - offset).clamp(clip_p, clip_q);
let b = (Coord::conv_nearest(b) - offset).clamp(clip_p, clip_q);
for y in a.1..b.1 {
let d1 = dx * (f32::conv(y + offset.1) - p1.1);
for x in a.0..b.0 {
let d2 = dy * (f32::conv(x + offset.0) - p1.0);
let dist = (d1 - d2).abs() * d_inv;
if dist <= r {
buffer[usize::conv(y) * size.0 + usize::conv(x)] = c;
}
}
}
}
}
}