#[derive(Debug, Clone)]
pub struct Light {
pub x: f32,
pub y: f32,
pub z: f32,
pub r: f32,
pub g: f32,
pub b: f32,
pub intensity: f32,
pub radius: f32,
}
#[inline]
pub fn cel_quantize(v: f32) -> f32 {
if v < 0.25 {
0.08
} else if v < 0.60 {
0.50
} else {
1.00
}
}
pub fn compute_lit_color(
base: u32,
normal: [f32; 3],
centroid: [f32; 3],
lights: &[Light],
ambient: f32,
) -> u32 {
let br = ((base >> 16) & 0xFF) as f32;
let bg = ((base >> 8) & 0xFF) as f32;
let bb = (base & 0xFF) as f32;
let mut acc_r = br * ambient;
let mut acc_g = bg * ambient;
let mut acc_b = bb * ambient;
let [nx, ny, nz] = normal;
let nlen = (nx * nx + ny * ny + nz * nz).sqrt();
if nlen < 1e-6 {
return pack(acc_r.min(255.0), acc_g.min(255.0), acc_b.min(255.0));
}
let nx = nx / nlen;
let ny = ny / nlen;
let nz = nz / nlen;
for l in lights {
let dx = l.x - centroid[0];
let dy = l.y - centroid[1];
let dz = l.z - centroid[2];
let dist = (dx * dx + dy * dy + dz * dz).sqrt().max(1e-6);
let atten = if l.radius > 0.0 {
(1.0 - dist / l.radius).max(0.0)
} else {
1.0
};
if atten <= 0.0 {
continue;
}
let lx = dx / dist;
let ly = dy / dist;
let lz = dz / dist;
let raw = (nx * lx + ny * ly + nz * lz).abs();
let shaded = cel_quantize(raw) * l.intensity * atten;
acc_r += br * shaded * l.r;
acc_g += bg * shaded * l.g;
acc_b += bb * shaded * l.b;
}
pack(acc_r.min(255.0), acc_g.min(255.0), acc_b.min(255.0))
}
#[inline]
fn pack(r: f32, g: f32, b: f32) -> u32 {
((r as u32) << 16) | ((g as u32) << 8) | (b as u32)
}