#![allow(clippy::match_single_binding)]
#![allow(clippy::use_self)]
pub mod algorithms;
use crate::noise::algorithms::Algorithm;
use crate::noise::algorithms::AlgorithmInitializer;
use crate::noise::algorithms::Perlin;
use crate::noise::algorithms::Simplex;
use crate::noise::algorithms::Wavelet;
use crate::random::algorithms::Algorithm as RandomAlgorithm;
use crate::random::Random;
use derivative::Derivative;
pub const MAX_OCTAVES: usize = 128;
pub const MAX_DIMENSIONS: usize = 4;
pub const DEFAULT_LACUNARITY: f32 = 2.0;
const DELTA: f32 = 1.0e-6;
#[derive(Derivative)]
#[derivative(Debug)]
pub struct Noise<A: Algorithm> {
pub(crate) dimensions: usize,
algorithm: A,
#[derivative(Debug = "ignore")]
exponent: [f32; MAX_OCTAVES],
lacunarity: f32,
}
impl<A: Algorithm> Noise<A> {
pub fn flat(&self, f: &[f32]) -> f32 {
assert_eq!(
self.dimensions,
f.len(),
"Number of coordinates given in 'f' must match the dimensions."
);
self.algorithm.generate(f)
}
pub fn fbm(&self, f: &[f32], mut octaves: f32) -> f32 {
assert_eq!(
self.dimensions,
f.len(),
"Number of coordinates given in 'f' must match the dimensions."
);
let mut tf = [0.0_f32; MAX_DIMENSIONS];
tf[0..self.dimensions].copy_from_slice(f);
let mut value: f64 = 0.0;
for &e in self.exponent.iter().take(octaves.trunc() as usize) {
value += f64::from(self.algorithm.generate(&tf)) * f64::from(e);
for tfe in tf.iter_mut().take(f.len()) {
*tfe *= self.lacunarity;
}
}
let exp_i = octaves.trunc() as usize;
octaves -= octaves.trunc();
if octaves > DELTA {
value +=
f64::from(octaves * self.algorithm.generate(&tf)) * f64::from(self.exponent[exp_i]);
}
value.max(-0.99999).min(0.99999) as f32
}
pub fn turbulence(&self, f: &[f32], mut octaves: f32) -> f32 {
assert_eq!(
self.dimensions,
f.len(),
"Number of coordinates given in 'f' must match the dimensions."
);
let mut tf = [0.0_f32; MAX_DIMENSIONS];
tf[0..self.dimensions].copy_from_slice(f);
let mut value: f64 = 0.0;
for &e in self.exponent.iter().take(octaves.trunc() as usize) {
value += f64::from(self.algorithm.generate(&tf).abs()) * f64::from(e);
for tfe in tf.iter_mut().take(f.len()) {
*tfe *= self.lacunarity;
}
}
let exp_i = octaves.trunc() as usize;
octaves -= octaves.trunc();
if octaves > DELTA {
value += f64::from(octaves * self.algorithm.generate(&tf).abs())
* f64::from(self.exponent[exp_i]);
}
value.max(-0.99999).min(0.99999) as f32
}
fn new<R: RandomAlgorithm>(
mut dimensions: usize,
lacunarity: f32,
random: Random<R>,
) -> Self {
dimensions = dimensions.min(4);
let initializer = AlgorithmInitializer::new(random);
Self {
dimensions,
algorithm: A::new(dimensions, initializer),
exponent: Self::exponent(lacunarity),
lacunarity,
}
}
fn exponent(lacunarity: f32) -> [f32; MAX_OCTAVES] {
let mut exponent = [0.0; MAX_OCTAVES];
let mut f = 1.0;
for e in exponent.iter_mut() {
*e = 1.0 / f;
f *= lacunarity;
}
exponent
}
}
impl Noise<Perlin> {
pub fn new_perlin<R: RandomAlgorithm>(
dimensions: usize,
lacunarity: f32,
random: Random<R>,
) -> Self {
Self::new(dimensions, lacunarity, random)
}
}
impl Noise<Simplex> {
pub fn new_simplex<R: RandomAlgorithm>(
dimensions: usize,
lacunarity: f32,
random: Random<R>,
) -> Self {
Self::new(dimensions, lacunarity, random)
}
}
impl Noise<Wavelet> {
pub fn new_wavelet<R: RandomAlgorithm>(
dimensions: usize,
lacunarity: f32,
random: Random<R>,
) -> Self {
Self::new(dimensions, lacunarity, random)
}
}