1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
//! Lightning fast two dimensional perlin noise generation library using prime numbers.
//! It is small and efficient with zero dependencies.
//!
//! # Example
//!
//! ```no run
//! // For example, to generate a Perlin noise 2D terrain:
//! use perlin2d::PerlinNoise2D;
//!
//! let perlin_obj = PerlinNoise2D::new(6, 10.0, 0.5, 1.0, 2.0, (100.0, 100.0), 101);
//!
//! let noise = perlin_obj.get_noise(5.0, 10.0);
//! ```

use std::num::Wrapping;

/// Perlin Noise struct
///
/// Member variables:
///
/// * `octaves` - The amount of detail in Perlin noise.
/// * `amplitude` - The maximum absolute value that the Perlin noise can output.
/// * `frequeny` - The number of cycles per unit length that the Perlin noise outputs.
/// * `persistence` - A multiplier that determines how quickly the amplitudes diminish for each successive octave in a Perlin-noise function.
/// * `lacunarity` - A multiplier that determines how quickly the frequency increases for each successive octave in a Perlin-noise function.
/// * `scale` - A Tuple. A number that determines at what distance to view the noisemap.
/// * `seed` -  A value that changes the output of a coherent-noise function.
/// * `bias` - Amount of change in Perlin noise. Used , for example, to make all Perlin noise values positive.
///
/// Additional Info:
/// http://libnoise.sourceforge.net/glossary/
pub struct PerlinNoise2D {
    octaves: i32,
    amplitude: f64,
    frequency: f64,
    persistence: f64,
    lacunarity: f64,
    scale: (f64, f64),
    bias: f64,
    seed: i32,
}

impl PerlinNoise2D {
    /// Create and return a new PerlinNoise2D object
    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,
        }
    }

    /// Getter function for octaves
    pub fn get_octaves(&self) -> i32 {
        self.octaves
    }
    //// Getter function for amplitude
    pub fn get_amplitude(&self) -> f64 {
        self.amplitude
    }
    /// Getter function for frequency
    pub fn get_frequency(&self) -> f64 {
        self.frequency
    }
    /// Getter function for persistence
    pub fn get_persistence(&self) -> f64 {
        self.persistence
    }
    /// Getter function for lacunarity
    pub fn get_lacunarity(&self) -> f64 {
        self.lacunarity
    }
    /// Getter function for scale
    pub fn get_scale(&self) -> (f64, f64) {
        self.scale
    }
    /// Getter function for bias
    pub fn get_bias(&self) -> f64 {
        self.bias
    }
    /// Getter function for seed
    pub fn get_seed(&self) -> i32 {
        self.seed
    }

    /// Setter function for octaves
    pub fn set_octaves(&mut self, octaves: i32) {
        self.octaves = octaves;
    }
    /// Setter function for amplitude
    pub fn set_amplitude(&mut self, amplitude: f64) {
        self.amplitude = amplitude;
    }
    /// Setter function for frequency
    pub fn set_frequency(&mut self, frequency: f64) {
        self.frequency = frequency;
    }
    /// Setter function for persistence
    pub fn set_persistence(&mut self, persistence: f64) {
        self.persistence = persistence;
    }
    /// Setter function for lacunarity
    pub fn set_lacunarity(&mut self, lacunarity: f64) {
        self.lacunarity = lacunarity;
    }
    /// Setter function for scale
    pub fn set_scale(&mut self, scale: (f64, f64)) {
        self.scale = scale;
    }
    /// Setter function for bias
    pub fn set_bias(&mut self, bias: f64) {
        self.bias = bias;
    }
    /// Setter function for seed
    pub fn set_seed(&mut self, seed: i32) {
        self.seed = seed;
    }

    /// generates and returns 2D perlin noise
    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 // add the weighted factors
    }

    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);

        // noise values
        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);

        // find the noise values of the four corners
        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);

        // interpolate between those values according to the x and y fractions
        let v1: f64 = self.interpolate(x0y0, x1y0, x_frac); // interpolate in x
                                                            // direction (y)
        let v2: f64 = self.interpolate(x0y1, x1y1, x_frac); // interpolate in x
                                                            // direction (y+1)
        let fin: f64 = self.interpolate(v1, v2, y_frac); // interpolate in y direction

        return fin;
    }
}