#[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)
}