UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

196 lines (158 loc) • 6.07 kB
/* 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; }