use crate::geometry2d::Vec2;
#[derive(Clone, Copy)]
pub struct Color {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}
impl Color {
pub const fn rgb(r: u8, g: u8, b: u8) -> Self { Self { r, g, b, a: 255 } }
pub const fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self { Self { r, g, b, a } }
pub const WHITE: Color = Color::rgb(255, 255, 255);
pub const BLACK: Color = Color::rgb(0, 0, 0 );
pub const RED: Color = Color::rgb(255, 0, 0 );
pub const GREEN: Color = Color::rgb(0, 255, 0 );
pub const BLUE: Color = Color::rgb(0, 0, 255);
pub const YELLOW: Color = Color::rgb(255, 255, 0 );
pub const CYAN: Color = Color::rgb(0, 255, 255);
pub const MAGENTA: Color = Color::rgb(255, 0, 255);
}
#[repr(C)]
#[derive(Copy, Clone)]
pub(crate) struct ColorVert {
pub pos: [f32; 2],
pub color: [f32; 4],
}
pub(crate) fn to_ndc(px: f32, py: f32, sw: u32, sh: u32) -> [f32; 2] {
[px / sw as f32 * 2.0 - 1.0, 1.0 - py / sh as f32 * 2.0]
}
fn cf(c: Color) -> [f32; 4] {
[c.r as f32 / 255.0, c.g as f32 / 255.0, c.b as f32 / 255.0, c.a as f32 / 255.0]
}
fn push_quad(v: &mut Vec<ColorVert>, x0: f32, y0: f32, x1: f32, y1: f32, sw: u32, sh: u32, c: Color) {
let col = cf(c);
for (x, y) in [(x0,y0),(x1,y0),(x0,y1),(x1,y0),(x1,y1),(x0,y1)] {
v.push(ColorVert { pos: to_ndc(x, y, sw, sh), color: col });
}
}
fn push_line(v: &mut Vec<ColorVert>, x0: f32, y0: f32, x1: f32, y1: f32, sw: u32, sh: u32, c: Color) {
let p0 = Vec2::new(x0, y0);
let p1 = Vec2::new(x1, y1);
let dir = p1 - p0;
if dir.length() < 0.5 { push_quad(v, x0, y0, x0+1.0, y0+1.0, sw, sh, c); return; }
let n = dir.normalize().perp(); let col = cf(c);
for p in [p0+n, p1+n, p0-n, p1+n, p1-n, p0-n] {
v.push(ColorVert { pos: to_ndc(p.x, p.y, sw, sh), color: col });
}
}
pub(crate) fn verts_fill(sw: u32, sh: u32, c: Color) -> Vec<ColorVert> {
let mut v = Vec::with_capacity(6);
push_quad(&mut v, 0.0, 0.0, sw as f32, sh as f32, sw, sh, c);
v
}
pub(crate) fn verts_pixel(x: i32, y: i32, sw: u32, sh: u32, c: Color) -> Vec<ColorVert> {
let mut v = Vec::with_capacity(6);
push_quad(&mut v, x as f32, y as f32, x as f32 + 1.0, y as f32 + 1.0, sw, sh, c);
v
}
pub(crate) fn verts_line(x1: i32, y1: i32, x2: i32, y2: i32, sw: u32, sh: u32, c: Color) -> Vec<ColorVert> {
let mut v = Vec::with_capacity(6);
push_line(&mut v, x1 as f32, y1 as f32, x2 as f32, y2 as f32, sw, sh, c);
v
}
pub(crate) fn verts_rectangle(x: i32, y: i32, w: i32, h: i32, sw: u32, sh: u32, c: Color, filled: bool) -> Vec<ColorVert> {
let mut v = Vec::new();
if filled {
push_quad(&mut v, x as f32, y as f32, (x+w) as f32, (y+h) as f32, sw, sh, c);
} else {
push_quad(&mut v, x as f32, y as f32, (x+w) as f32, y as f32 + 1.0, sw, sh, c);
push_quad(&mut v, x as f32, (y+h-1) as f32, (x+w) as f32, (y+h) as f32, sw, sh, c);
push_quad(&mut v, x as f32, (y+1) as f32, x as f32 + 1.0, (y+h-1) as f32, sw, sh, c);
push_quad(&mut v, (x+w-1) as f32, (y+1) as f32, (x+w) as f32, (y+h-1) as f32, sw, sh, c);
}
v
}
pub(crate) fn verts_triangle(x1: i32, y1: i32, x2: i32, y2: i32, x3: i32, y3: i32, sw: u32, sh: u32, c: Color, filled: bool) -> Vec<ColorVert> {
let col = cf(c);
let mut v = Vec::new();
if filled {
for (x, y) in [(x1,y1),(x2,y2),(x3,y3)] {
v.push(ColorVert { pos: to_ndc(x as f32, y as f32, sw, sh), color: col });
}
} else {
push_line(&mut v, x1 as f32, y1 as f32, x2 as f32, y2 as f32, sw, sh, c);
push_line(&mut v, x2 as f32, y2 as f32, x3 as f32, y3 as f32, sw, sh, c);
push_line(&mut v, x3 as f32, y3 as f32, x1 as f32, y1 as f32, sw, sh, c);
}
v
}
pub(crate) fn verts_circle(cx: i32, cy: i32, radius: i32, sw: u32, sh: u32, c: Color, filled: bool) -> Vec<ColorVert> {
let col = cf(c);
let center = Vec2::new(cx as f32, cy as f32);
let r = radius.max(1) as f32;
let n = (radius * 4).clamp(16, 256) as usize;
let mut v = Vec::with_capacity(if filled { n * 3 } else { n * 6 });
for i in 0..n {
let a0 = i as f32 / n as f32 * std::f32::consts::TAU;
let a1 = (i + 1) as f32 / n as f32 * std::f32::consts::TAU;
let p0 = center + Vec2::from_angle(a0) * r;
let p1 = center + Vec2::from_angle(a1) * r;
if filled {
v.push(ColorVert { pos: to_ndc(center.x, center.y, sw, sh), color: col });
v.push(ColorVert { pos: to_ndc(p0.x, p0.y, sw, sh), color: col });
v.push(ColorVert { pos: to_ndc(p1.x, p1.y, sw, sh), color: col });
} else {
push_line(&mut v, p0.x, p0.y, p1.x, p1.y, sw, sh, c);
}
}
v
}