noilib_simple/
lib.rs

1#[inline(always)]
2fn lerp(a: f32, b: f32, t: f32) -> f32 {
3    return (b - a) * t + a;
4}
5#[inline(always)]
6fn smoothstep(a: f32, b: f32, t: f32) -> f32 {
7    return (b - a) * (t * (t * 6.0 - 15.0) + 10.0) * t * t * t + a;
8}
9
10pub struct NoiseGenerator {
11    permutations: [i32; 256],
12}
13impl NoiseGenerator {
14    pub fn new(seed: u64) -> Self {
15        const A: u64 = 6364136223846793005;
16        const C: u64 = 1442695040888963407;
17        let mut seed = seed;
18        let mut rand = || {
19            seed = A.wrapping_mul(seed).wrapping_add(C);
20            seed
21        };
22
23        let mut permutations = [0i32; 256];
24        for i in 0..256 {
25            permutations[i] = rand() as i32;
26        }
27        Self { permutations }
28    }
29    fn randomize_2_f(&self, x: i32, y: i32) -> f32 {
30        let sum = y.wrapping_mul(506791837).wrapping_add(x);
31        // let mut sum2 = 0;
32        // sum2 += self.permutations[(sum & 0x000000ff) as usize];
33        // for b in sum.to_le_bytes() {
34        //     sum2 += self.permutations[b as usize];
35        // }
36        (self.permutations[(sum & 0x000000ff) as usize]
37            .wrapping_add(self.permutations[(sum >> 8 & 0x000000ff) as usize])
38            .wrapping_add(self.permutations[(sum >> 16 & 0x000000ff) as usize])
39            .wrapping_add(self.permutations[(sum >> 24 & 0x000000ff) as usize])
40            % 123456) as f32
41            / 123456.0
42    }
43    fn random_gradient(&self, x: i32, y: i32) -> [f32; 2] {
44        let sum = y.wrapping_mul(506791837).wrapping_add(x);
45        let dir = (self.permutations[(sum & 0x000000ff) as usize]
46            .wrapping_add(self.permutations[(sum >> 8 & 0x000000ff) as usize])
47            .wrapping_add(self.permutations[(sum >> 16 & 0x000000ff) as usize])
48            .wrapping_add(self.permutations[(sum >> 24 & 0x000000ff) as usize])
49            % 123456) as f32
50            / 123456.0
51            * std::f32::consts::PI
52            * 8.0;
53        [dir.cos(), dir.sin()]
54    }
55    fn dot_gradient(&self, xi: i32, yi: i32, x: f32, y: f32) -> f32 {
56        let gradient = self.random_gradient(xi, yi);
57        let dx = xi as f32 - x;
58        let dy = yi as f32 - y;
59        dx * gradient[0] + dy * gradient[1]
60    }
61    pub fn perlin(&self, x: f32, y: f32) -> f32 {
62        let xff = x.floor();
63        let yff = y.floor();
64        let xf = xff as i32;
65        let yf = yff as i32;
66        let xc = xf + 1;
67        let yc = yf + 1;
68        let xo = x - xff;
69        let yo = y - yff;
70
71        smoothstep(
72            smoothstep(
73                self.dot_gradient(xf, yf, x, y),
74                self.dot_gradient(xc, yf, x, y),
75                xo,
76            ),
77            smoothstep(
78                self.dot_gradient(xf, yc, x, y),
79                self.dot_gradient(xc, yc, x, y),
80                xo,
81            ),
82            yo,
83        ) * std::f32::consts::SQRT_2
84    }
85    pub fn perlin_octaves(&self, x: f32, y: f32, octaves: usize, gain: f32) -> f32 {
86        let mut sum = 0.0;
87        let mut scale = 1.0;
88        for _ in 0..octaves {
89            sum = lerp(sum, self.perlin(x / scale, y / scale), scale);
90            scale *= gain;
91        }
92        sum
93    }
94    pub fn value(&self, x: f32, y: f32) -> f32 {
95        let xff = x.floor();
96        let yff = y.floor();
97        let xf = xff as i32;
98        let yf = yff as i32;
99        let xc = xf + 1;
100        let yc = yf + 1;
101        let xo = x - xff;
102        let yo = y - yff;
103
104        return lerp(
105            lerp(self.randomize_2_f(xf, yf), self.randomize_2_f(xc, yf), xo),
106            lerp(self.randomize_2_f(xf, yc), self.randomize_2_f(xc, yc), xo),
107            yo,
108        );
109    }
110    pub fn value_octaves(&self, x: f32, y: f32, octaves: usize, gain: f32) -> f32 {
111        let mut sum = 0.0;
112        let mut scale = 1.0;
113        for _ in 0..octaves {
114            sum = lerp(sum, self.value(x / scale, y / scale), scale);
115            scale *= gain;
116        }
117        sum
118    }
119}