use arrayvec::ArrayVec;
use rand::prelude::*;
use crate::{
Chunk,
debug::{Debug, DebugContent},
rolling_grid::GridPoint,
vec2::{Num, Point2d},
};
fn poisson_1(val: f32) -> u8 {
match val {
0.0..0.3679 => 0,
0.3670..0.7358 => 1,
0.7358..0.9197 => 2,
0.9197..0.981 => 3,
0.981..0.9963 => 4,
0.9963..0.9994 => 5,
0.9994..0.9999 => 6,
0.9999..1.0 => 7,
_ => panic!("{val} is not in range 0..1"),
}
}
#[derive(PartialEq, Debug, Clone)]
pub struct UniformPoint<P, const SIZE: u8, const SALT: u64> {
pub points: ArrayVec<P, 7>,
}
impl<P, const SIZE: u8, const SALT: u64> Default for UniformPoint<P, SIZE, SALT> {
fn default() -> Self {
Self {
points: Default::default(),
}
}
}
impl<P: Reducible, const SIZE: u8, const SALT: u64> Chunk for UniformPoint<P, SIZE, SALT> {
type LayerStore<T> = T;
type Dependencies = ();
const SIZE: Point2d<u8> = Point2d::splat(SIZE);
fn compute((): &Self::Dependencies, index: GridPoint<Self>) -> Self {
let points = generate_points::<SALT, Self>(index);
Self {
points: points.map(P::from).collect(),
}
}
fn clear((): &Self::Dependencies, _index: GridPoint<Self>) {
}
}
impl<P: Reducible, const SIZE: u8, const SALT: u64> Debug for UniformPoint<P, SIZE, SALT> {
fn debug(&self) -> Vec<DebugContent> {
self.points.iter().flat_map(Reducible::debug).collect()
}
}
fn generate_points<const SALT: u64, C: Chunk + 'static>(
index: GridPoint<C>,
) -> impl Iterator<Item = Point2d> {
let chunk_bounds = C::bounds(index);
let mut rng = rng_for_point::<SALT, _>(index);
let n = poisson_1(rng.random_range(0.0..=1.0)).into();
std::iter::from_fn(move || Some(chunk_bounds.sample(&mut rng))).take(n)
}
pub fn rng_for_point<const SALT: u64, T: Num>(index: Point2d<T>) -> SmallRng {
let x = SmallRng::seed_from_u64(index.x.as_u64());
let y = SmallRng::seed_from_u64(index.y.as_u64());
let salt = SmallRng::seed_from_u64(SALT);
let mut seed = <SmallRng as SeedableRng>::Seed::default();
for mut rng in [x, y, salt] {
let mut tmp = <SmallRng as SeedableRng>::Seed::default();
rng.fill_bytes(&mut tmp);
for (seed, tmp) in seed.iter_mut().zip(tmp.iter()) {
*seed ^= *tmp;
}
}
SmallRng::from_seed(seed)
}
mod reduced_points;
pub use reduced_points::*;