@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
196 lines (158 loc) • 6.07 kB
JavaScript
/*
NOTE: this implementation is adapted from https://github.com/jwagner/simplex-noise.js
*/
// these #__PURE__ comments help uglifyjs with dead code removal
//
const F2 = /*#__PURE__*/ 0.5 * (Math.sqrt(3.0) - 1.0);
const G2 = /*#__PURE__*/ (3.0 - Math.sqrt(3.0)) / 6.0;
const F3 = 1.0 / 3.0;
const G3 = 1.0 / 6.0;
const F4 = /*#__PURE__*/ (Math.sqrt(5.0) - 1.0) / 4.0;
const G4 = /*#__PURE__*/ (5.0 - Math.sqrt(5.0)) / 20.0;
const grad2 = /*#__PURE__*/ new Int8Array([1, 1,
-1, 1,
1, -1,
-1, -1,
1, 0,
-1, 0,
1, 0,
-1, 0,
0, 1,
0, -1,
0, 1,
0, -1]);
// double seems to be faster than single or int's
// probably because most operations are in double precision
const grad3 = /*#__PURE__*/ new Float64Array([1, 1, 0,
-1, 1, 0,
1, -1, 0,
-1, -1, 0,
1, 0, 1,
-1, 0, 1,
1, 0, -1,
-1, 0, -1,
0, 1, 1,
0, -1, 1,
0, 1, -1,
0, -1, -1]);
// double is a bit quicker here as well
const grad4 = /*#__PURE__*/ new Float64Array([0, 1, 1, 1, 0, 1, 1, -1, 0, 1, -1, 1, 0, 1, -1, -1,
0, -1, 1, 1, 0, -1, 1, -1, 0, -1, -1, 1, 0, -1, -1, -1,
1, 0, 1, 1, 1, 0, 1, -1, 1, 0, -1, 1, 1, 0, -1, -1,
-1, 0, 1, 1, -1, 0, 1, -1, -1, 0, -1, 1, -1, 0, -1, -1,
1, 1, 0, 1, 1, 1, 0, -1, 1, -1, 0, 1, 1, -1, 0, -1,
-1, 1, 0, 1, -1, 1, 0, -1, -1, -1, 0, 1, -1, -1, 0, -1,
1, 1, 1, 0, 1, 1, -1, 0, 1, -1, 1, 0, 1, -1, -1, 0,
-1, 1, 1, 0, -1, 1, -1, 0, -1, -1, 1, 0, -1, -1, -1, 0]);
/**
* Creates a 2D noise function
* @param [random] the random function that will be used to build the permutation table
* @returns {function(x:number, y:number):number} producing values in range -1 .. 1
*/
export function create_simplex_noise_2d(random = Math.random) {
// allocate continuous chunk of memory
const buffer = new ArrayBuffer(512 * 2);
const perm = new Uint8Array(buffer, 0, 512);
buildPermutationTable(random, perm);
const permMod12 = new Uint8Array(buffer, 512, 512);
for (let i = 0; i < 512; i++) {
permMod12[i] = (perm[i] % 12) * 2;
}
/**
* @param {number} x
* @param {number} y
*/
return function noise2D(x, y) {
// if(!isFinite(x) || !isFinite(y)) return 0;
let n0 = 0; // Noise contributions from the three corners
let n1 = 0;
let n2 = 0;
// Skew the input space to determine which simplex cell we're in
const s = (x + y) * F2; // Hairy factor for 2D
const i = (x + s) | 0;
const j = (y + s) | 0;
const t = (i + j) * G2;
const X0 = i - t; // Unskew the cell origin back to (x,y) space
const Y0 = j - t;
const x0 = x - X0; // The x,y distances from the cell origin
const y0 = y - Y0;
// For the 2D case, the simplex shape is an equilateral triangle.
// Determine which simplex we are in.
let i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords
if (x0 > y0) {
i1 = 1;
j1 = 0;
} // lower triangle, XY order: (0,0)->(1,0)->(1,1)
else {
i1 = 0;
j1 = 1;
} // upper triangle, YX order: (0,0)->(0,1)->(1,1)
// A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
// a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
// c = (3-sqrt(3))/6
const x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords
const y1 = y0 - j1 + G2;
const x2 = x0 - 1.0 + 2.0 * G2; // Offsets for last corner in (x,y) unskewed coords
const y2 = y0 - 1.0 + 2.0 * G2;
// Work out the hashed gradient indices of the three simplex corners
const ii = i & 255;
const jj = j & 255;
// Calculate the contribution from the three corners
let t0 = 0.5 - x0 * x0 - y0 * y0;
if (t0 >= 0) {
const gi0 = ii + perm[jj];
const gi01 = permMod12[gi0];
const g0x = grad2[gi01];
const g0y = grad2[gi01 + 1];
t0 *= t0;
// n0 = t0 * t0 * (grad2[gi0] * x0 + grad2[gi0 + 1] * y0); // (x,y) of grad3 used for 2D gradient
n0 = t0 * t0 * (g0x * x0 + g0y * y0);
}
let t1 = 0.5 - x1 * x1 - y1 * y1;
if (t1 >= 0) {
const gi1 = ii + i1 + perm[jj + j1];
const gi11 = permMod12[gi1];
const g1x = grad2[gi11];
const g1y = grad2[gi11 + 1];
t1 *= t1;
// n1 = t1 * t1 * (grad2[gi1] * x1 + grad2[gi1 + 1] * y1);
n1 = t1 * t1 * (g1x * x1 + g1y * y1);
}
let t2 = 0.5 - x2 * x2 - y2 * y2;
if (t2 >= 0) {
const gi2 = ii + 1 + perm[jj + 1];
const gi21 = permMod12[gi2];
const g2x = grad2[gi21];
const g2y = grad2[gi21 + 1];
t2 *= t2;
// n2 = t2 * t2 * (grad2[gi2] * x2 + grad2[gi2 + 1] * y2);
n2 = t2 * t2 * (g2x * x2 + g2y * y2);
}
// Add contributions from each corner to get the final noise value.
// The result is scaled to return values in the interval [-1,1].
return 70.0 * (n0 + n1 + n2);
};
}
/**
* Builds a random permutation table
* @param {function} random
* @param {Uint8Array} p result will be written here
*/
function buildPermutationTable(random, p) {
const table_size = 512;
const half_table_size = table_size >>> 1;
for (let i = 0; i < half_table_size; i++) {
p[i] = i;
}
for (let i = 0; i < half_table_size - 1; i++) {
const r = i + ~~(random() * (256 - i));
const aux = p[i];
p[i] = p[r];
p[r] = aux;
}
for (let i = 256; i < table_size; i++) {
// second half of the table just repeats the first half
p[i] = p[i - 256];
}
return p;
}