use super::hash2;
pub fn film_grain(position: [f32; 2], seed: u64) -> f32 {
let [value] = film_grain_multi(position, [seed]);
value
}
pub fn film_grain_multi<const N: usize>(position: [f32; 2], seeds: [u64; N]) -> [f32; N] {
let cell = position.map(|value| value.floor() as u32);
let fraction = position.map(|value| value - value.floor());
let variance = fraction.map(|value| (1.0 - value) * (1.0 - value) + value * value);
let normalisation = (variance[0] * variance[1]).sqrt();
let next = [cell[0].wrapping_add(1), cell[1].wrapping_add(1)];
let uniform =
|x: u32, y: u32, seed: u32| (hash2(x as i32, y as i32, seed) >> 8) as f32 / 16777216.0;
seeds.map(|seed| {
let folded = seed as u32 ^ (seed >> 32) as u32;
let sample = |x: u32, y: u32| {
(uniform(x, y, folded) + uniform(x, y, folded ^ 0xa511e9b3) - 1.0) * 2.4494898
};
let top =
sample(cell[0], cell[1]) * (1.0 - fraction[0]) + sample(next[0], cell[1]) * fraction[0];
let bottom =
sample(cell[0], next[1]) * (1.0 - fraction[0]) + sample(next[0], next[1]) * fraction[0];
(top * (1.0 - fraction[1]) + bottom * fraction[1]) / normalisation
})
}