import seedrandom from 'seedrandom' class PerlinNoise { constructor (rand = Math.random) { let perm = new Int8Array(257) for (let i = 0; i < 256; i++) { perm[i] = i & 1 ? 1 : -1 } for (let i = 0; i < 256; i++) { let j = rand() * 4294967296 & 255 var _ref = [perm[j], perm[i]] perm[i] = _ref[0] perm[j] = _ref[1] } perm[256] = perm[0] function noise1d (x) { let x0 = x | 0 let x1 = x - x0 let xi = x0 & 255 let fx = (3 - 2 * x1) * x1 * x1 let a = x1 * perm[xi] let b = (x1 - 1) * perm[xi + 1] return a + fx * (b - a) } function noise (x) { let sum = 0 sum += (1 + noise1d(x)) * 0.25 sum += (1 + noise1d(x * 2)) * 0.125 sum += (1 + noise1d(x * 4)) * 0.0625 sum += (1 + noise1d(x * 8)) * 0.03125 return sum } this.noise = noise } } class HeightMap { // amplitude - Controls the amount the height changes. The higher, the taller the hills. // persistence - Controls details, value in [0,1]. Higher increases grain, lower increases smoothness. // octaves - Number of noise layers // period - Distance above which we start to see similarities. The higher, the longer "hills" will be on a terrain. // lacunarity - Controls period change across octaves. 2 is usually a good value to address all detail levels. constructor (offsetY, seed, amplitude = 30, persistence = 0.5, octaves = 5, period = 80, lacunarity = 2) { this.iy = offsetY this.seed = seed this.noise = new PerlinNoise(seedrandom(seed)) this.amplitude = amplitude this.period = period this.lacunarity = lacunarity this.octaves = octaves this.persistence = persistence } getNoise (zx) { let x = zx / this.period let amp = 1.0 let max = 1.0 let sum = this.noise.noise(x) let i = 0 while (++i < this.octaves) { x *= this.lacunarity amp *= this.persistence max += amp sum += this.noise.noise(x) * amp } return sum / max } getHeight (x) { return this.getNoise(x) * this.amplitude + this.iy } } export { HeightMap }