UNPKG

4.45 kBJavaScriptView Raw
1'use strict';
2
3Math.$random = function (min = 0, max = 10) {
4 return Math.floor(Math.random() * (max - min + 1)) + min;
5};
6
7//////////
8// Mersenne Twister - pseudo random number generator
9
10function MersenneTwister (seed) {
11 seed = seed || Date.now();
12 this.N = 624;
13 this.M = 397;
14 this.MATRIX_A = 0x9908b0df;
15 this.UPPER_MASK = 0x80000000;
16 this.LOWER_MASK = 0x7fffffff;
17 this.I = Math.pow(2, 32);
18
19 this.mt = new Array(this.N);
20 this.mti = this.N + 1;
21
22 this.mt[0] = seed >>> 0;
23 for (this.mti = 1; this.mti < this.N; this.mti++) {
24 const s = this.mt[this.mti - 1] ^ this.mt[this.mti - 1] >>> 30;
25 this.mt[this.mti] = (((s & 0xffff0000) >>> 16) * 1812433253 << 16) +
26 (s & 0x0000ffff) * 1812433253 + this.mti;
27 this.mt[this.mti] >>>= 0;
28 }
29}
30
31MersenneTwister.prototype.random = function (min, max) {
32 if (min !== undefined && max !== undefined) {
33 return Math.floor(this.random() * (max - min + 1)) + min;
34 } else if (min !== undefined) {
35 return this.random(0, min);
36 }
37
38 const mag01 = new Array(0x0, this.MATRIX_A);
39 let y;
40
41 if (this.mti >= this.N) {
42 let kk;
43
44 for (kk = 0; kk < this.N - this.M; kk++) {
45 y = this.mt[kk] & this.UPPER_MASK | this.mt[kk + 1] & this.LOWER_MASK;
46 this.mt[kk] = this.mt[kk + this.M] ^ y >>> 1 ^ mag01[y & 0x1];
47 }
48
49 for (;kk < this.N - 1; kk++) {
50 y = this.mt[kk] & this.UPPER_MASK | this.mt[kk + 1] & this.LOWER_MASK;
51 this.mt[kk] = this.mt[kk + (this.M - this.N)] ^ y >>> 1 ^ mag01[y & 0x1];
52 }
53
54 y = this.mt[this.N - 1] & this.UPPER_MASK | this.mt[0] & this.LOWER_MASK;
55
56 this.mt[this.N - 1] = this.mt[this.M - 1] ^ y >>> 1 ^ mag01[y & 0x1];
57
58 this.mti = 0;
59 }
60
61 y = this.mt[this.mti++];
62
63 y ^= y >>> 11;
64 y ^= y << 7 & 0x9d2c5680;
65 y ^= y << 15 & 0xefc60000;
66 y ^= y >>> 18;
67 y = y >>> 0;
68
69 return (y + 0.5) / this.I;
70};
71
72//////////
73// Perlin Noise
74
75function interpolate (x0, x1, alpha) {
76 return x0 * (1 - alpha) + alpha * x1;
77}
78
79function generateWhiteNoise (width, height, prng) {
80 const noise = new Array(width * height);
81 for (let i = 0; i < noise.length; ++i) {
82 if (prng) {
83 noise[i] = prng.random();
84 } else {
85 noise[i] = Math.random();
86 }
87 }
88 return noise;
89}
90
91function generatePerlinNoise (width, height, options) {
92 options = options || {};
93
94 let prng = null;
95 if (options.prng) {
96 prng = options.prng;
97 } else if (options.seed) {
98 prng = new MersenneTwister(options.seed);
99 }
100
101 const octaveCount = options.octaveCount || 4;
102 const persistence = options.persistence || 0.2;
103 const whiteNoise = generateWhiteNoise(width, height, prng);
104
105 let amplitude = options.amplitude || 0.1;
106
107 function generateSmoothNoise (octave) {
108 const noise = new Array(width * height);
109 const samplePeriod = Math.pow(2, octave);
110 const sampleFrequency = 1 / samplePeriod;
111 let noiseIndex = 0;
112 for (let y = 0; y < height; ++y) {
113 const sampleY0 = Math.floor(y / samplePeriod) * samplePeriod;
114 const sampleY1 = (sampleY0 + samplePeriod) % height;
115 const vertBlend = (y - sampleY0) * sampleFrequency;
116 for (let x = 0; x < width; ++x) {
117 const sampleX0 = Math.floor(x / samplePeriod) * samplePeriod;
118 const sampleX1 = (sampleX0 + samplePeriod) % width;
119 const horizBlend = (x - sampleX0) * sampleFrequency;
120
121 const top = interpolate(whiteNoise[sampleY0 * width + sampleX0],
122 whiteNoise[sampleY1 * width + sampleX0],
123 vertBlend);
124
125 const bottom = interpolate(whiteNoise[sampleY0 * width + sampleX1],
126 whiteNoise[sampleY1 * width + sampleX1],
127 vertBlend);
128
129 noise[noiseIndex] = interpolate(top, bottom, horizBlend);
130 noiseIndex += 1;
131 }
132 }
133 return noise;
134 }
135
136 const smoothNoiseList = new Array(octaveCount);
137 for (let i = 0; i < octaveCount; ++i) {
138 smoothNoiseList[i] = generateSmoothNoise(i);
139 }
140 const perlinNoise = new Array(width * height);
141 let totalAmplitude = 0;
142
143 for (let i = octaveCount - 1; i >= 0; --i) {
144 amplitude *= persistence;
145 totalAmplitude += amplitude;
146
147 for (let j = 0; j < perlinNoise.length; ++j) {
148 perlinNoise[j] = perlinNoise[j] || 0;
149 perlinNoise[j] += smoothNoiseList[i][j] * amplitude;
150 }
151 }
152
153 for (let i = 0; i < perlinNoise.length; ++i) {
154 perlinNoise[i] /= totalAmplitude;
155 }
156
157 return perlinNoise;
158}
159
160//////////
161
162module.exports = {
163 MersenneTwister,
164 generatePerlinNoise
165};