mc-beta-server/external/OpenSimplex2D.ts

196 lines
3.5 KiB
TypeScript

// This is free and unencumbered software released into the public domain
import shuffleSeed from "./shuffle_seed";
const NORM_2D = 1.0 / 47.0;
const SQUISH_2D = (Math.sqrt(2 + 1) - 1) / 2;
const STRETCH_2D = (1 / Math.sqrt(2 + 1) - 1) / 2;
export type Noise2D = (x: number, y: number) => number;
interface Contribution2D {
dx: number;
dy: number;
next?: Contribution2D;
xsb: number;
ysb: number;
}
function contribution2D(
multiplier: number,
xsb: number,
ysb: number,
): Contribution2D {
return {
dx: -xsb - multiplier * SQUISH_2D,
dy: -ysb - multiplier * SQUISH_2D,
xsb,
ysb,
};
}
export function makeNoise2D(clientSeed: number): Noise2D {
const contributions: Contribution2D[] = [];
for (let i = 0; i < p2D.length; i += 4) {
const baseSet = base2D[p2D[i]];
let previous: Contribution2D | null = null;
let current: Contribution2D | null = null;
for (let k = 0; k < baseSet.length; k += 3) {
current = contribution2D(baseSet[k], baseSet[k + 1], baseSet[k + 2]);
if (previous === null) contributions[i / 4] = current;
else previous.next = current;
previous = current;
}
current!.next = contribution2D(p2D[i + 1], p2D[i + 2], p2D[i + 3]);
}
const lookup: Contribution2D[] = [];
for (let i = 0; i < lookupPairs2D.length; i += 2) {
lookup[lookupPairs2D[i]] = contributions[lookupPairs2D[i + 1]];
}
const perm = new Uint8Array(256);
const perm2D = new Uint8Array(256);
const source = new Uint8Array(256);
for (let i = 0; i < 256; i++) source[i] = i;
let seed = new Uint32Array(1);
seed[0] = clientSeed;
seed = shuffleSeed(shuffleSeed(shuffleSeed(seed)));
for (let i = 255; i >= 0; i--) {
seed = shuffleSeed(seed);
const r = new Uint32Array(1);
r[0] = (seed[0] + 31) % (i + 1);
if (r[0] < 0) r[0] += i + 1;
perm[i] = source[r[0]];
perm2D[i] = perm[i] & 0x0e;
source[r[0]] = source[i];
}
return (x: number, y: number): number => {
const stretchOffset = (x + y) * STRETCH_2D;
const xs = x + stretchOffset;
const ys = y + stretchOffset;
const xsb = Math.floor(xs);
const ysb = Math.floor(ys);
const squishOffset = (xsb + ysb) * SQUISH_2D;
const dx0 = x - (xsb + squishOffset);
const dy0 = y - (ysb + squishOffset);
const xins = xs - xsb;
const yins = ys - ysb;
const inSum = xins + yins;
const hash = (xins - yins + 1) |
(inSum << 1) |
((inSum + yins) << 2) |
((inSum + xins) << 4);
let value = 0;
for (
let c: Contribution2D | undefined = lookup[hash];
c !== undefined;
c = c.next
) {
const dx = dx0 + c.dx;
const dy = dy0 + c.dy;
const attn = 2 - dx * dx - dy * dy;
if (attn > 0) {
const px = xsb + c.xsb;
const py = ysb + c.ysb;
const indexPartA = perm[px & 0xff];
const index = perm2D[(indexPartA + py) & 0xff];
const valuePart = gradients2D[index] * dx + gradients2D[index + 1] * dy;
value += attn * attn * attn * attn * valuePart;
}
}
return value * NORM_2D;
};
}
const base2D = [
[1, 1, 0, 1, 0, 1, 0, 0, 0],
[1, 1, 0, 1, 0, 1, 2, 1, 1],
];
const gradients2D = [
5,
2,
2,
5,
-5,
2,
-2,
5,
5,
-2,
2,
-5,
-5,
-2,
-2,
-5,
];
const lookupPairs2D = [
0,
1,
1,
0,
4,
1,
17,
0,
20,
2,
21,
2,
22,
5,
23,
5,
26,
4,
39,
3,
42,
4,
43,
3,
];
const p2D = [
0,
0,
1,
-1,
0,
0,
-1,
1,
0,
2,
1,
1,
1,
2,
2,
0,
1,
2,
0,
2,
1,
0,
0,
0,
];