use std::num::Wrapping;
pub struct PerlinNoise2D {
octaves: i32,
amplitude: f64,
frequency: f64,
persistence: f64,
lacunarity: f64,
scale: (f64, f64),
bias: f64,
seed: i32,
}
impl PerlinNoise2D {
pub fn new(
octaves: i32,
amplitude: f64,
frequency: f64,
persistence: f64,
lacunarity: f64,
scale: (f64, f64),
bias: f64,
seed: i32,
) -> Self {
Self {
octaves,
amplitude,
frequency,
persistence,
lacunarity,
scale,
bias,
seed,
}
}
pub fn get_octaves(&self) -> i32 {
self.octaves
}
pub fn get_amplitude(&self) -> f64 {
self.amplitude
}
pub fn get_frequency(&self) -> f64 {
self.frequency
}
pub fn get_persistence(&self) -> f64 {
self.persistence
}
pub fn get_lacunarity(&self) -> f64 {
self.lacunarity
}
pub fn get_scale(&self) -> (f64, f64) {
self.scale
}
pub fn get_bias(&self) -> f64 {
self.bias
}
pub fn get_seed(&self) -> i32 {
self.seed
}
pub fn set_octaves(&mut self, octaves: i32) {
self.octaves = octaves;
}
pub fn set_amplitude(&mut self, amplitude: f64) {
self.amplitude = amplitude;
}
pub fn set_frequency(&mut self, frequency: f64) {
self.frequency = frequency;
}
pub fn set_persistence(&mut self, persistence: f64) {
self.persistence = persistence;
}
pub fn set_lacunarity(&mut self, lacunarity: f64) {
self.lacunarity = lacunarity;
}
pub fn set_scale(&mut self, scale: (f64, f64)) {
self.scale = scale;
}
pub fn set_bias(&mut self, bias: f64) {
self.bias = bias;
}
pub fn set_seed(&mut self, seed: i32) {
self.seed = seed;
}
pub fn get_noise(&self, x: f64, y: f64) -> f64 {
self.bias + self.amplitude * self.total(x / self.scale.0, y / self.scale.1)
}
fn total(&self, x: f64, y: f64) -> f64 {
let mut t = 0.0;
let mut amp = 1.0;
let mut freq = self.frequency;
for _ in 0..self.octaves {
t += self.get_value(y * freq + self.seed as f64, x * freq + self.seed as f64) * amp;
amp *= self.persistence;
freq *= self.lacunarity;
}
t
}
fn interpolate(&self, x: f64, y: f64, a: f64) -> f64 {
let neg_a: f64 = 1.0 - a;
let neg_a_sqr: f64 = neg_a * neg_a;
let fac1: f64 = 3.0 * (neg_a_sqr) - 2.0 * (neg_a_sqr * neg_a);
let a_sqr: f64 = a * a;
let fac2: f64 = 3.0 * a_sqr - 2.0 * (a_sqr * a);
x * fac1 + y * fac2 }
fn noise(&self, x: i32, y: i32) -> f64 {
let mut n: i64 = x as i64 + y as i64 * 57;
n = (n << 13) ^ n;
let t = Wrapping(n) * Wrapping(n) * Wrapping(n * 15731 + 789221) + Wrapping(1376312589);
let t = t.0 & 0x7fffffff;
1.0 - (t as f64) * 0.931322574615478515625e-9
}
fn get_value(&self, x: f64, y: f64) -> f64 {
let x_int: i32 = x as i32;
let y_int: i32 = y as i32;
let x_frac: f64 = x - f64::floor(x);
let y_frac: f64 = y - f64::floor(y);
let n01: f64 = self.noise(x_int - 1, y_int - 1);
let n02: f64 = self.noise(x_int + 1, y_int - 1);
let n03: f64 = self.noise(x_int - 1, y_int + 1);
let n04: f64 = self.noise(x_int + 1, y_int + 1);
let n05: f64 = self.noise(x_int - 1, y_int);
let n06: f64 = self.noise(x_int + 1, y_int);
let n07: f64 = self.noise(x_int, y_int - 1);
let n08: f64 = self.noise(x_int, y_int + 1);
let n09: f64 = self.noise(x_int, y_int);
let n12: f64 = self.noise(x_int + 2, y_int - 1);
let n14: f64 = self.noise(x_int + 2, y_int + 1);
let n16: f64 = self.noise(x_int + 2, y_int);
let n23: f64 = self.noise(x_int - 1, y_int + 2);
let n24: f64 = self.noise(x_int + 1, y_int + 2);
let n28: f64 = self.noise(x_int, y_int + 2);
let n34: f64 = self.noise(x_int + 2, y_int + 2);
let x0y0: f64 = 0.0625 * (n01 + n02 + n03 + n04) + 0.125 * (n05 + n06 + n07 + n08) + 0.25 * (n09);
let x1y0: f64 = 0.0625 * (n07 + n12 + n08 + n14) + 0.125 * (n09 + n16 + n02 + n04) + 0.25 * (n06);
let x0y1: f64 = 0.0625 * (n05 + n06 + n23 + n24) + 0.125 * (n03 + n04 + n09 + n28) + 0.25 * (n08);
let x1y1: f64 = 0.0625 * (n09 + n16 + n28 + n34) + 0.125 * (n08 + n14 + n06 + n24) + 0.25 * (n04);
let v1: f64 = self.interpolate(x0y0, x1y0, x_frac); let v2: f64 = self.interpolate(x0y1, x1y1, x_frac); let fin: f64 = self.interpolate(v1, v2, y_frac);
return fin;
}
}