Skip to content

Instantly share code, notes, and snippets.

@KdotJPG
Last active February 9, 2024 03:42
Star You must be signed in to star a gist
Save KdotJPG/b1270127455a94ac5d19 to your computer and use it in GitHub Desktop.
Visually isotropic coherent noise algorithm based on alternate constructions of the A* lattice.
/**
* K.jpg's OpenSimplex 2, smooth variant ("SuperSimplex")
*
* More language ports, as well as legacy 2014 OpenSimplex, can be found here:
* https://github.com/KdotJPG/OpenSimplex2
*/
public class OpenSimplex2S {
private static final long PRIME_X = 0x5205402B9270C86FL;
private static final long PRIME_Y = 0x598CD327003817B5L;
private static final long PRIME_Z = 0x5BCC226E9FA0BACBL;
private static final long PRIME_W = 0x56CC5227E58F554BL;
private static final long HASH_MULTIPLIER = 0x53A3F72DEEC546F5L;
private static final long SEED_FLIP_3D = -0x52D547B2E96ED629L;
private static final double ROOT2OVER2 = 0.7071067811865476;
private static final double SKEW_2D = 0.366025403784439;
private static final double UNSKEW_2D = -0.21132486540518713;
private static final double ROOT3OVER3 = 0.577350269189626;
private static final double FALLBACK_ROTATE3 = 2.0 / 3.0;
private static final double ROTATE3_ORTHOGONALIZER = UNSKEW_2D;
private static final float SKEW_4D = 0.309016994374947f;
private static final float UNSKEW_4D = -0.138196601125011f;
private static final int N_GRADS_2D_EXPONENT = 7;
private static final int N_GRADS_3D_EXPONENT = 8;
private static final int N_GRADS_4D_EXPONENT = 9;
private static final int N_GRADS_2D = 1 << N_GRADS_2D_EXPONENT;
private static final int N_GRADS_3D = 1 << N_GRADS_3D_EXPONENT;
private static final int N_GRADS_4D = 1 << N_GRADS_4D_EXPONENT;
private static final double NORMALIZER_2D = 0.05481866495625118;
private static final double NORMALIZER_3D = 0.2781926117527186;
private static final double NORMALIZER_4D = 0.11127401889945551;
private static final float RSQUARED_2D = 2.0f / 3.0f;
private static final float RSQUARED_3D = 3.0f / 4.0f;
private static final float RSQUARED_4D = 4.0f / 5.0f;
/*
* Noise Evaluators
*/
/**
* 2D OpenSimplex2S/SuperSimplex noise, standard lattice orientation.
*/
public static float noise2(long seed, double x, double y) {
// Get points for A2* lattice
double s = SKEW_2D * (x + y);
double xs = x + s, ys = y + s;
return noise2_UnskewedBase(seed, xs, ys);
}
/**
* 2D OpenSimplex2S/SuperSimplex noise, with Y pointing down the main diagonal.
* Might be better for a 2D sandbox style game, where Y is vertical.
* Probably slightly less optimal for heightmaps or continent maps,
* unless your map is centered around an equator. It's a slight
* difference, but the option is here to make it easy.
*/
public static float noise2_ImproveX(long seed, double x, double y) {
// Skew transform and rotation baked into one.
double xx = x * ROOT2OVER2;
double yy = y * (ROOT2OVER2 * (1 + 2 * SKEW_2D));
return noise2_UnskewedBase(seed, yy + xx, yy - xx);
}
/**
* 2D OpenSimplex2S/SuperSimplex noise base.
*/
private static float noise2_UnskewedBase(long seed, double xs, double ys) {
// Get base points and offsets.
int xsb = fastFloor(xs), ysb = fastFloor(ys);
float xi = (float)(xs - xsb), yi = (float)(ys - ysb);
// Prime pre-multiplication for hash.
long xsbp = xsb * PRIME_X, ysbp = ysb * PRIME_Y;
// Unskew.
float t = (xi + yi) * (float)UNSKEW_2D;
float dx0 = xi + t, dy0 = yi + t;
// First vertex.
float a0 = RSQUARED_2D - dx0 * dx0 - dy0 * dy0;
float value = (a0 * a0) * (a0 * a0) * grad(seed, xsbp, ysbp, dx0, dy0);
// Second vertex.
float a1 = (float)(2 * (1 + 2 * UNSKEW_2D) * (1 / UNSKEW_2D + 2)) * t + ((float)(-2 * (1 + 2 * UNSKEW_2D) * (1 + 2 * UNSKEW_2D)) + a0);
float dx1 = dx0 - (float)(1 + 2 * UNSKEW_2D);
float dy1 = dy0 - (float)(1 + 2 * UNSKEW_2D);
value += (a1 * a1) * (a1 * a1) * grad(seed, xsbp + PRIME_X, ysbp + PRIME_Y, dx1, dy1);
// Third and fourth vertices.
// Nested conditionals were faster than compact bit logic/arithmetic.
float xmyi = xi - yi;
if (t < UNSKEW_2D) {
if (xi + xmyi > 1) {
float dx2 = dx0 - (float)(3 * UNSKEW_2D + 2);
float dy2 = dy0 - (float)(3 * UNSKEW_2D + 1);
float a2 = RSQUARED_2D - dx2 * dx2 - dy2 * dy2;
if (a2 > 0) {
value += (a2 * a2) * (a2 * a2) * grad(seed, xsbp + (PRIME_X << 1), ysbp + PRIME_Y, dx2, dy2);
}
}
else
{
float dx2 = dx0 - (float)UNSKEW_2D;
float dy2 = dy0 - (float)(UNSKEW_2D + 1);
float a2 = RSQUARED_2D - dx2 * dx2 - dy2 * dy2;
if (a2 > 0) {
value += (a2 * a2) * (a2 * a2) * grad(seed, xsbp, ysbp + PRIME_Y, dx2, dy2);
}
}
if (yi - xmyi > 1) {
float dx3 = dx0 - (float)(3 * UNSKEW_2D + 1);
float dy3 = dy0 - (float)(3 * UNSKEW_2D + 2);
float a3 = RSQUARED_2D - dx3 * dx3 - dy3 * dy3;
if (a3 > 0) {
value += (a3 * a3) * (a3 * a3) * grad(seed, xsbp + PRIME_X, ysbp + (PRIME_Y << 1), dx3, dy3);
}
}
else
{
float dx3 = dx0 - (float)(UNSKEW_2D + 1);
float dy3 = dy0 - (float)UNSKEW_2D;
float a3 = RSQUARED_2D - dx3 * dx3 - dy3 * dy3;
if (a3 > 0) {
value += (a3 * a3) * (a3 * a3) * grad(seed, xsbp + PRIME_X, ysbp, dx3, dy3);
}
}
}
else
{
if (xi + xmyi < 0) {
float dx2 = dx0 + (float)(1 + UNSKEW_2D);
float dy2 = dy0 + (float)UNSKEW_2D;
float a2 = RSQUARED_2D - dx2 * dx2 - dy2 * dy2;
if (a2 > 0) {
value += (a2 * a2) * (a2 * a2) * grad(seed, xsbp - PRIME_X, ysbp, dx2, dy2);
}
}
else
{
float dx2 = dx0 - (float)(UNSKEW_2D + 1);
float dy2 = dy0 - (float)UNSKEW_2D;
float a2 = RSQUARED_2D - dx2 * dx2 - dy2 * dy2;
if (a2 > 0) {
value += (a2 * a2) * (a2 * a2) * grad(seed, xsbp + PRIME_X, ysbp, dx2, dy2);
}
}
if (yi < xmyi) {
float dx2 = dx0 + (float)UNSKEW_2D;
float dy2 = dy0 + (float)(UNSKEW_2D + 1);
float a2 = RSQUARED_2D - dx2 * dx2 - dy2 * dy2;
if (a2 > 0) {
value += (a2 * a2) * (a2 * a2) * grad(seed, xsbp, ysbp - PRIME_Y, dx2, dy2);
}
}
else
{
float dx2 = dx0 - (float)UNSKEW_2D;
float dy2 = dy0 - (float)(UNSKEW_2D + 1);
float a2 = RSQUARED_2D - dx2 * dx2 - dy2 * dy2;
if (a2 > 0) {
value += (a2 * a2) * (a2 * a2) * grad(seed, xsbp, ysbp + PRIME_Y, dx2, dy2);
}
}
}
return value;
}
/**
* 3D OpenSimplex2S/SuperSimplex noise, with better visual isotropy in (X, Y).
* Recommended for 3D terrain and time-varied animations.
* The Z coordinate should always be the "different" coordinate in whatever your use case is.
* If Y is vertical in world coordinates, call noise3_ImproveXZ(x, z, Y) or use noise3_XZBeforeY.
* If Z is vertical in world coordinates, call noise3_ImproveXZ(x, y, Z).
* For a time varied animation, call noise3_ImproveXY(x, y, T).
*/
public static float noise3_ImproveXY(long seed, double x, double y, double z) {
// Re-orient the cubic lattices without skewing, so Z points up the main lattice diagonal,
// and the planes formed by XY are moved far out of alignment with the cube faces.
// Orthonormal rotation. Not a skew transform.
double xy = x + y;
double s2 = xy * ROTATE3_ORTHOGONALIZER;
double zz = z * ROOT3OVER3;
double xr = x + s2 + zz;
double yr = y + s2 + zz;
double zr = xy * -ROOT3OVER3 + zz;
// Evaluate both lattices to form a BCC lattice.
return noise3_UnrotatedBase(seed, xr, yr, zr);
}
/**
* 3D OpenSimplex2S/SuperSimplex noise, with better visual isotropy in (X, Z).
* Recommended for 3D terrain and time-varied animations.
* The Y coordinate should always be the "different" coordinate in whatever your use case is.
* If Y is vertical in world coordinates, call noise3_ImproveXZ(x, Y, z).
* If Z is vertical in world coordinates, call noise3_ImproveXZ(x, Z, y) or use noise3_ImproveXY.
* For a time varied animation, call noise3_ImproveXZ(x, T, y) or use noise3_ImproveXY.
*/
public static float noise3_ImproveXZ(long seed, double x, double y, double z) {
// Re-orient the cubic lattices without skewing, so Y points up the main lattice diagonal,
// and the planes formed by XZ are moved far out of alignment with the cube faces.
// Orthonormal rotation. Not a skew transform.
double xz = x + z;
double s2 = xz * -0.211324865405187;
double yy = y * ROOT3OVER3;
double xr = x + s2 + yy;
double zr = z + s2 + yy;
double yr = xz * -ROOT3OVER3 + yy;
// Evaluate both lattices to form a BCC lattice.
return noise3_UnrotatedBase(seed, xr, yr, zr);
}
/**
* 3D OpenSimplex2S/SuperSimplex noise, fallback rotation option
* Use noise3_ImproveXY or noise3_ImproveXZ instead, wherever appropriate.
* They have less diagonal bias. This function's best use is as a fallback.
*/
public static float noise3_Fallback(long seed, double x, double y, double z) {
// Re-orient the cubic lattices via rotation, to produce a familiar look.
// Orthonormal rotation. Not a skew transform.
double r = FALLBACK_ROTATE3 * (x + y + z);
double xr = r - x, yr = r - y, zr = r - z;
// Evaluate both lattices to form a BCC lattice.
return noise3_UnrotatedBase(seed, xr, yr, zr);
}
/**
* Generate overlapping cubic lattices for 3D Re-oriented BCC noise.
* Lookup table implementation inspired by DigitalShadow.
* It was actually faster to narrow down the points in the loop itself,
* than to build up the index with enough info to isolate 8 points.
*/
private static float noise3_UnrotatedBase(long seed, double xr, double yr, double zr) {
// Get base points and offsets.
int xrb = fastFloor(xr), yrb = fastFloor(yr), zrb = fastFloor(zr);
float xi = (float)(xr - xrb), yi = (float)(yr - yrb), zi = (float)(zr - zrb);
// Prime pre-multiplication for hash. Also flip seed for second lattice copy.
long xrbp = xrb * PRIME_X, yrbp = yrb * PRIME_Y, zrbp = zrb * PRIME_Z;
long seed2 = seed ^ -0x52D547B2E96ED629L;
// -1 if positive, 0 if negative.
int xNMask = (int)(-0.5f - xi), yNMask = (int)(-0.5f - yi), zNMask = (int)(-0.5f - zi);
// First vertex.
float x0 = xi + xNMask;
float y0 = yi + yNMask;
float z0 = zi + zNMask;
float a0 = RSQUARED_3D - x0 * x0 - y0 * y0 - z0 * z0;
float value = (a0 * a0) * (a0 * a0) * grad(seed,
xrbp + (xNMask & PRIME_X), yrbp + (yNMask & PRIME_Y), zrbp + (zNMask & PRIME_Z), x0, y0, z0);
// Second vertex.
float x1 = xi - 0.5f;
float y1 = yi - 0.5f;
float z1 = zi - 0.5f;
float a1 = RSQUARED_3D - x1 * x1 - y1 * y1 - z1 * z1;
value += (a1 * a1) * (a1 * a1) * grad(seed2,
xrbp + PRIME_X, yrbp + PRIME_Y, zrbp + PRIME_Z, x1, y1, z1);
// Shortcuts for building the remaining falloffs.
// Derived by subtracting the polynomials with the offsets plugged in.
float xAFlipMask0 = ((xNMask | 1) << 1) * x1;
float yAFlipMask0 = ((yNMask | 1) << 1) * y1;
float zAFlipMask0 = ((zNMask | 1) << 1) * z1;
float xAFlipMask1 = (-2 - (xNMask << 2)) * x1 - 1.0f;
float yAFlipMask1 = (-2 - (yNMask << 2)) * y1 - 1.0f;
float zAFlipMask1 = (-2 - (zNMask << 2)) * z1 - 1.0f;
boolean skip5 = false;
float a2 = xAFlipMask0 + a0;
if (a2 > 0) {
float x2 = x0 - (xNMask | 1);
float y2 = y0;
float z2 = z0;
value += (a2 * a2) * (a2 * a2) * grad(seed,
xrbp + (~xNMask & PRIME_X), yrbp + (yNMask & PRIME_Y), zrbp + (zNMask & PRIME_Z), x2, y2, z2);
}
else
{
float a3 = yAFlipMask0 + zAFlipMask0 + a0;
if (a3 > 0) {
float x3 = x0;
float y3 = y0 - (yNMask | 1);
float z3 = z0 - (zNMask | 1);
value += (a3 * a3) * (a3 * a3) * grad(seed,
xrbp + (xNMask & PRIME_X), yrbp + (~yNMask & PRIME_Y), zrbp + (~zNMask & PRIME_Z), x3, y3, z3);
}
float a4 = xAFlipMask1 + a1;
if (a4 > 0) {
float x4 = (xNMask | 1) + x1;
float y4 = y1;
float z4 = z1;
value += (a4 * a4) * (a4 * a4) * grad(seed2,
xrbp + (xNMask & (PRIME_X * 2)), yrbp + PRIME_Y, zrbp + PRIME_Z, x4, y4, z4);
skip5 = true;
}
}
boolean skip9 = false;
float a6 = yAFlipMask0 + a0;
if (a6 > 0) {
float x6 = x0;
float y6 = y0 - (yNMask | 1);
float z6 = z0;
value += (a6 * a6) * (a6 * a6) * grad(seed,
xrbp + (xNMask & PRIME_X), yrbp + (~yNMask & PRIME_Y), zrbp + (zNMask & PRIME_Z), x6, y6, z6);
}
else
{
float a7 = xAFlipMask0 + zAFlipMask0 + a0;
if (a7 > 0) {
float x7 = x0 - (xNMask | 1);
float y7 = y0;
float z7 = z0 - (zNMask | 1);
value += (a7 * a7) * (a7 * a7) * grad(seed,
xrbp + (~xNMask & PRIME_X), yrbp + (yNMask & PRIME_Y), zrbp + (~zNMask & PRIME_Z), x7, y7, z7);
}
float a8 = yAFlipMask1 + a1;
if (a8 > 0) {
float x8 = x1;
float y8 = (yNMask | 1) + y1;
float z8 = z1;
value += (a8 * a8) * (a8 * a8) * grad(seed2,
xrbp + PRIME_X, yrbp + (yNMask & (PRIME_Y << 1)), zrbp + PRIME_Z, x8, y8, z8);
skip9 = true;
}
}
boolean skipD = false;
float aA = zAFlipMask0 + a0;
if (aA > 0) {
float xA = x0;
float yA = y0;
float zA = z0 - (zNMask | 1);
value += (aA * aA) * (aA * aA) * grad(seed,
xrbp + (xNMask & PRIME_X), yrbp + (yNMask & PRIME_Y), zrbp + (~zNMask & PRIME_Z), xA, yA, zA);
}
else
{
float aB = xAFlipMask0 + yAFlipMask0 + a0;
if (aB > 0) {
float xB = x0 - (xNMask | 1);
float yB = y0 - (yNMask | 1);
float zB = z0;
value += (aB * aB) * (aB * aB) * grad(seed,
xrbp + (~xNMask & PRIME_X), yrbp + (~yNMask & PRIME_Y), zrbp + (zNMask & PRIME_Z), xB, yB, zB);
}
float aC = zAFlipMask1 + a1;
if (aC > 0) {
float xC = x1;
float yC = y1;
float zC = (zNMask | 1) + z1;
value += (aC * aC) * (aC * aC) * grad(seed2,
xrbp + PRIME_X, yrbp + PRIME_Y, zrbp + (zNMask & (PRIME_Z << 1)), xC, yC, zC);
skipD = true;
}
}
if (!skip5) {
float a5 = yAFlipMask1 + zAFlipMask1 + a1;
if (a5 > 0) {
float x5 = x1;
float y5 = (yNMask | 1) + y1;
float z5 = (zNMask | 1) + z1;
value += (a5 * a5) * (a5 * a5) * grad(seed2,
xrbp + PRIME_X, yrbp + (yNMask & (PRIME_Y << 1)), zrbp + (zNMask & (PRIME_Z << 1)), x5, y5, z5);
}
}
if (!skip9) {
float a9 = xAFlipMask1 + zAFlipMask1 + a1;
if (a9 > 0) {
float x9 = (xNMask | 1) + x1;
float y9 = y1;
float z9 = (zNMask | 1) + z1;
value += (a9 * a9) * (a9 * a9) * grad(seed2,
xrbp + (xNMask & (PRIME_X * 2)), yrbp + PRIME_Y, zrbp + (zNMask & (PRIME_Z << 1)), x9, y9, z9);
}
}
if (!skipD) {
float aD = xAFlipMask1 + yAFlipMask1 + a1;
if (aD > 0) {
float xD = (xNMask | 1) + x1;
float yD = (yNMask | 1) + y1;
float zD = z1;
value += (aD * aD) * (aD * aD) * grad(seed2,
xrbp + (xNMask & (PRIME_X << 1)), yrbp + (yNMask & (PRIME_Y << 1)), zrbp + PRIME_Z, xD, yD, zD);
}
}
return value;
}
/**
* 4D SuperSimplex noise, with XYZ oriented like noise3_ImproveXY
* and W for an extra degree of freedom. W repeats eventually.
* Recommended for time-varied animations which texture a 3D object (W=time)
* in a space where Z is vertical
*/
public static float noise4_ImproveXYZ_ImproveXY(long seed, double x, double y, double z, double w) {
double xy = x + y;
double s2 = xy * -0.21132486540518699998;
double zz = z * 0.28867513459481294226;
double ww = w * 1.118033988749894;
double xr = x + (zz + ww + s2), yr = y + (zz + ww + s2);
double zr = xy * -0.57735026918962599998 + (zz + ww);
double wr = z * -0.866025403784439 + ww;
return noise4_UnskewedBase(seed, xr, yr, zr, wr);
}
/**
* 4D SuperSimplex noise, with XYZ oriented like noise3_ImproveXZ
* and W for an extra degree of freedom. W repeats eventually.
* Recommended for time-varied animations which texture a 3D object (W=time)
* in a space where Y is vertical
*/
public static float noise4_ImproveXYZ_ImproveXZ(long seed, double x, double y, double z, double w) {
double xz = x + z;
double s2 = xz * -0.21132486540518699998;
double yy = y * 0.28867513459481294226;
double ww = w * 1.118033988749894;
double xr = x + (yy + ww + s2), zr = z + (yy + ww + s2);
double yr = xz * -0.57735026918962599998 + (yy + ww);
double wr = y * -0.866025403784439 + ww;
return noise4_UnskewedBase(seed, xr, yr, zr, wr);
}
/**
* 4D SuperSimplex noise, with XYZ oriented like noise3_Fallback
* and W for an extra degree of freedom. W repeats eventually.
* Recommended for time-varied animations which texture a 3D object (W=time)
* where there isn't a clear distinction between horizontal and vertical
*/
public static float noise4_ImproveXYZ(long seed, double x, double y, double z, double w) {
double xyz = x + y + z;
double ww = w * 1.118033988749894;
double s2 = xyz * -0.16666666666666666 + ww;
double xs = x + s2, ys = y + s2, zs = z + s2, ws = -0.5 * xyz + ww;
return noise4_UnskewedBase(seed, xs, ys, zs, ws);
}
/**
* 4D SuperSimplex noise, with XY and ZW forming orthogonal triangular-based planes.
* Recommended for 3D terrain, where X and Y (or Z and W) are horizontal.
* Recommended for noise(x, y, sin(time), cos(time)) trick.
*/
public static float noise4_ImproveXY_ImproveZW(long seed, double x, double y, double z, double w) {
double s2 = (x + y) * -0.28522513987434876941 + (z + w) * 0.83897065470611435718;
double t2 = (z + w) * 0.21939749883706435719 + (x + y) * -0.48214856493302476942;
double xs = x + s2, ys = y + s2, zs = z + t2, ws = w + t2;
return noise4_UnskewedBase(seed, xs, ys, zs, ws);
}
/**
* 4D SuperSimplex noise, fallback lattice orientation.
*/
public static float noise4_Fallback(long seed, double x, double y, double z, double w) {
// Get points for A4 lattice
double s = SKEW_4D * (x + y + z + w);
double xs = x + s, ys = y + s, zs = z + s, ws = w + s;
return noise4_UnskewedBase(seed, xs, ys, zs, ws);
}
/**
* 4D SuperSimplex noise base.
* Using ultra-simple 4x4x4x4 lookup partitioning.
* This isn't as elegant or SIMD/GPU/etc. portable as other approaches,
* but it competes performance-wise with optimized 2014 OpenSimplex.
*/
private static float noise4_UnskewedBase(long seed, double xs, double ys, double zs, double ws) {
// Get base points and offsets
int xsb = fastFloor(xs), ysb = fastFloor(ys), zsb = fastFloor(zs), wsb = fastFloor(ws);
float xsi = (float)(xs - xsb), ysi = (float)(ys - ysb), zsi = (float)(zs - zsb), wsi = (float)(ws - wsb);
// Unskewed offsets
float ssi = (xsi + ysi + zsi + wsi) * UNSKEW_4D;
float xi = xsi + ssi, yi = ysi + ssi, zi = zsi + ssi, wi = wsi + ssi;
// Prime pre-multiplication for hash.
long xsvp = xsb * PRIME_X, ysvp = ysb * PRIME_Y, zsvp = zsb * PRIME_Z, wsvp = wsb * PRIME_W;
// Index into initial table.
int index = ((fastFloor(xs * 4) & 3) << 0)
| ((fastFloor(ys * 4) & 3) << 2)
| ((fastFloor(zs * 4) & 3) << 4)
| ((fastFloor(ws * 4) & 3) << 6);
// Point contributions
float value = 0;
int secondaryIndexStartAndStop = LOOKUP_4D_A[index];
int secondaryIndexStart = secondaryIndexStartAndStop & 0xFFFF;
int secondaryIndexStop = secondaryIndexStartAndStop >> 16;
for (int i = secondaryIndexStart; i < secondaryIndexStop; i++) {
LatticeVertex4D c = LOOKUP_4D_B[i];
float dx = xi + c.dx, dy = yi + c.dy, dz = zi + c.dz, dw = wi + c.dw;
float a = (dx * dx + dy * dy) + (dz * dz + dw * dw);
if (a < RSQUARED_4D) {
a -= RSQUARED_4D;
a *= a;
value += a * a * grad(seed, xsvp + c.xsvp, ysvp + c.ysvp, zsvp + c.zsvp, wsvp + c.wsvp, dx, dy, dz, dw);
}
}
return value;
}
/*
* Utility
*/
private static float grad(long seed, long xsvp, long ysvp, float dx, float dy) {
long hash = seed ^ xsvp ^ ysvp;
hash *= HASH_MULTIPLIER;
hash ^= hash >> (64 - N_GRADS_2D_EXPONENT + 1);
int gi = (int)hash & ((N_GRADS_2D - 1) << 1);
return GRADIENTS_2D[gi | 0] * dx + GRADIENTS_2D[gi | 1] * dy;
}
private static float grad(long seed, long xrvp, long yrvp, long zrvp, float dx, float dy, float dz) {
long hash = (seed ^ xrvp) ^ (yrvp ^ zrvp);
hash *= HASH_MULTIPLIER;
hash ^= hash >> (64 - N_GRADS_3D_EXPONENT + 2);
int gi = (int)hash & ((N_GRADS_3D - 1) << 2);
return GRADIENTS_3D[gi | 0] * dx + GRADIENTS_3D[gi | 1] * dy + GRADIENTS_3D[gi | 2] * dz;
}
private static float grad(long seed, long xsvp, long ysvp, long zsvp, long wsvp, float dx, float dy, float dz, float dw) {
long hash = seed ^ (xsvp ^ ysvp) ^ (zsvp ^ wsvp);
hash *= HASH_MULTIPLIER;
hash ^= hash >> (64 - N_GRADS_4D_EXPONENT + 2);
int gi = (int)hash & ((N_GRADS_4D - 1) << 2);
return (GRADIENTS_4D[gi | 0] * dx + GRADIENTS_4D[gi | 1] * dy) + (GRADIENTS_4D[gi | 2] * dz + GRADIENTS_4D[gi | 3] * dw);
}
private static int fastFloor(double x) {
int xi = (int)x;
return x < xi ? xi - 1 : xi;
}
/*
* Lookup Tables & Gradients
*/
private static float[] GRADIENTS_2D;
private static float[] GRADIENTS_3D;
private static float[] GRADIENTS_4D;
private static int[] LOOKUP_4D_A;
private static LatticeVertex4D[] LOOKUP_4D_B;
static {
GRADIENTS_2D = new float[N_GRADS_2D * 2];
float[] grad2 = {
0.38268343236509f, 0.923879532511287f,
0.923879532511287f, 0.38268343236509f,
0.923879532511287f, -0.38268343236509f,
0.38268343236509f, -0.923879532511287f,
-0.38268343236509f, -0.923879532511287f,
-0.923879532511287f, -0.38268343236509f,
-0.923879532511287f, 0.38268343236509f,
-0.38268343236509f, 0.923879532511287f,
//-------------------------------------//
0.130526192220052f, 0.99144486137381f,
0.608761429008721f, 0.793353340291235f,
0.793353340291235f, 0.608761429008721f,
0.99144486137381f, 0.130526192220051f,
0.99144486137381f, -0.130526192220051f,
0.793353340291235f, -0.60876142900872f,
0.608761429008721f, -0.793353340291235f,
0.130526192220052f, -0.99144486137381f,
-0.130526192220052f, -0.99144486137381f,
-0.608761429008721f, -0.793353340291235f,
-0.793353340291235f, -0.608761429008721f,
-0.99144486137381f, -0.130526192220052f,
-0.99144486137381f, 0.130526192220051f,
-0.793353340291235f, 0.608761429008721f,
-0.608761429008721f, 0.793353340291235f,
-0.130526192220052f, 0.99144486137381f,
};
for (int i = 0; i < grad2.length; i++) {
grad2[i] = (float)(grad2[i] / NORMALIZER_2D);
}
for (int i = 0, j = 0; i < GRADIENTS_2D.length; i++, j++) {
if (j == grad2.length) j = 0;
GRADIENTS_2D[i] = grad2[j];
}
GRADIENTS_3D = new float[N_GRADS_3D * 4];
float[] grad3 = {
2.22474487139f, 2.22474487139f, -1.0f, 0.0f,
2.22474487139f, 2.22474487139f, 1.0f, 0.0f,
3.0862664687972017f, 1.1721513422464978f, 0.0f, 0.0f,
1.1721513422464978f, 3.0862664687972017f, 0.0f, 0.0f,
-2.22474487139f, 2.22474487139f, -1.0f, 0.0f,
-2.22474487139f, 2.22474487139f, 1.0f, 0.0f,
-1.1721513422464978f, 3.0862664687972017f, 0.0f, 0.0f,
-3.0862664687972017f, 1.1721513422464978f, 0.0f, 0.0f,
-1.0f, -2.22474487139f, -2.22474487139f, 0.0f,
1.0f, -2.22474487139f, -2.22474487139f, 0.0f,
0.0f, -3.0862664687972017f, -1.1721513422464978f, 0.0f,
0.0f, -1.1721513422464978f, -3.0862664687972017f, 0.0f,
-1.0f, -2.22474487139f, 2.22474487139f, 0.0f,
1.0f, -2.22474487139f, 2.22474487139f, 0.0f,
0.0f, -1.1721513422464978f, 3.0862664687972017f, 0.0f,
0.0f, -3.0862664687972017f, 1.1721513422464978f, 0.0f,
//--------------------------------------------------------------------//
-2.22474487139f, -2.22474487139f, -1.0f, 0.0f,
-2.22474487139f, -2.22474487139f, 1.0f, 0.0f,
-3.0862664687972017f, -1.1721513422464978f, 0.0f, 0.0f,
-1.1721513422464978f, -3.0862664687972017f, 0.0f, 0.0f,
-2.22474487139f, -1.0f, -2.22474487139f, 0.0f,
-2.22474487139f, 1.0f, -2.22474487139f, 0.0f,
-1.1721513422464978f, 0.0f, -3.0862664687972017f, 0.0f,
-3.0862664687972017f, 0.0f, -1.1721513422464978f, 0.0f,
-2.22474487139f, -1.0f, 2.22474487139f, 0.0f,
-2.22474487139f, 1.0f, 2.22474487139f, 0.0f,
-3.0862664687972017f, 0.0f, 1.1721513422464978f, 0.0f,
-1.1721513422464978f, 0.0f, 3.0862664687972017f, 0.0f,
-1.0f, 2.22474487139f, -2.22474487139f, 0.0f,
1.0f, 2.22474487139f, -2.22474487139f, 0.0f,
0.0f, 1.1721513422464978f, -3.0862664687972017f, 0.0f,
0.0f, 3.0862664687972017f, -1.1721513422464978f, 0.0f,
-1.0f, 2.22474487139f, 2.22474487139f, 0.0f,
1.0f, 2.22474487139f, 2.22474487139f, 0.0f,
0.0f, 3.0862664687972017f, 1.1721513422464978f, 0.0f,
0.0f, 1.1721513422464978f, 3.0862664687972017f, 0.0f,
2.22474487139f, -2.22474487139f, -1.0f, 0.0f,
2.22474487139f, -2.22474487139f, 1.0f, 0.0f,
1.1721513422464978f, -3.0862664687972017f, 0.0f, 0.0f,
3.0862664687972017f, -1.1721513422464978f, 0.0f, 0.0f,
2.22474487139f, -1.0f, -2.22474487139f, 0.0f,
2.22474487139f, 1.0f, -2.22474487139f, 0.0f,
3.0862664687972017f, 0.0f, -1.1721513422464978f, 0.0f,
1.1721513422464978f, 0.0f, -3.0862664687972017f, 0.0f,
2.22474487139f, -1.0f, 2.22474487139f, 0.0f,
2.22474487139f, 1.0f, 2.22474487139f, 0.0f,
1.1721513422464978f, 0.0f, 3.0862664687972017f, 0.0f,
3.0862664687972017f, 0.0f, 1.1721513422464978f, 0.0f,
};
for (int i = 0; i < grad3.length; i++) {
grad3[i] = (float)(grad3[i] / NORMALIZER_3D);
}
for (int i = 0, j = 0; i < GRADIENTS_3D.length; i++, j++) {
if (j == grad3.length) j = 0;
GRADIENTS_3D[i] = grad3[j];
}
GRADIENTS_4D = new float[N_GRADS_4D * 4];
float[] grad4 = {
-0.6740059517812944f, -0.3239847771997537f, -0.3239847771997537f, 0.5794684678643381f,
-0.7504883828755602f, -0.4004672082940195f, 0.15296486218853164f, 0.5029860367700724f,
-0.7504883828755602f, 0.15296486218853164f, -0.4004672082940195f, 0.5029860367700724f,
-0.8828161875373585f, 0.08164729285680945f, 0.08164729285680945f, 0.4553054119602712f,
-0.4553054119602712f, -0.08164729285680945f, -0.08164729285680945f, 0.8828161875373585f,
-0.5029860367700724f, -0.15296486218853164f, 0.4004672082940195f, 0.7504883828755602f,
-0.5029860367700724f, 0.4004672082940195f, -0.15296486218853164f, 0.7504883828755602f,
-0.5794684678643381f, 0.3239847771997537f, 0.3239847771997537f, 0.6740059517812944f,
-0.6740059517812944f, -0.3239847771997537f, 0.5794684678643381f, -0.3239847771997537f,
-0.7504883828755602f, -0.4004672082940195f, 0.5029860367700724f, 0.15296486218853164f,
-0.7504883828755602f, 0.15296486218853164f, 0.5029860367700724f, -0.4004672082940195f,
-0.8828161875373585f, 0.08164729285680945f, 0.4553054119602712f, 0.08164729285680945f,
-0.4553054119602712f, -0.08164729285680945f, 0.8828161875373585f, -0.08164729285680945f,
-0.5029860367700724f, -0.15296486218853164f, 0.7504883828755602f, 0.4004672082940195f,
-0.5029860367700724f, 0.4004672082940195f, 0.7504883828755602f, -0.15296486218853164f,
-0.5794684678643381f, 0.3239847771997537f, 0.6740059517812944f, 0.3239847771997537f,
-0.6740059517812944f, 0.5794684678643381f, -0.3239847771997537f, -0.3239847771997537f,
-0.7504883828755602f, 0.5029860367700724f, -0.4004672082940195f, 0.15296486218853164f,
-0.7504883828755602f, 0.5029860367700724f, 0.15296486218853164f, -0.4004672082940195f,
-0.8828161875373585f, 0.4553054119602712f, 0.08164729285680945f, 0.08164729285680945f,
-0.4553054119602712f, 0.8828161875373585f, -0.08164729285680945f, -0.08164729285680945f,
-0.5029860367700724f, 0.7504883828755602f, -0.15296486218853164f, 0.4004672082940195f,
-0.5029860367700724f, 0.7504883828755602f, 0.4004672082940195f, -0.15296486218853164f,
-0.5794684678643381f, 0.6740059517812944f, 0.3239847771997537f, 0.3239847771997537f,
0.5794684678643381f, -0.6740059517812944f, -0.3239847771997537f, -0.3239847771997537f,
0.5029860367700724f, -0.7504883828755602f, -0.4004672082940195f, 0.15296486218853164f,
0.5029860367700724f, -0.7504883828755602f, 0.15296486218853164f, -0.4004672082940195f,
0.4553054119602712f, -0.8828161875373585f, 0.08164729285680945f, 0.08164729285680945f,
0.8828161875373585f, -0.4553054119602712f, -0.08164729285680945f, -0.08164729285680945f,
0.7504883828755602f, -0.5029860367700724f, -0.15296486218853164f, 0.4004672082940195f,
0.7504883828755602f, -0.5029860367700724f, 0.4004672082940195f, -0.15296486218853164f,
0.6740059517812944f, -0.5794684678643381f, 0.3239847771997537f, 0.3239847771997537f,
//------------------------------------------------------------------------------------------//
-0.753341017856078f, -0.37968289875261624f, -0.37968289875261624f, -0.37968289875261624f,
-0.7821684431180708f, -0.4321472685365301f, -0.4321472685365301f, 0.12128480194602098f,
-0.7821684431180708f, -0.4321472685365301f, 0.12128480194602098f, -0.4321472685365301f,
-0.7821684431180708f, 0.12128480194602098f, -0.4321472685365301f, -0.4321472685365301f,
-0.8586508742123365f, -0.508629699630796f, 0.044802370851755174f, 0.044802370851755174f,
-0.8586508742123365f, 0.044802370851755174f, -0.508629699630796f, 0.044802370851755174f,
-0.8586508742123365f, 0.044802370851755174f, 0.044802370851755174f, -0.508629699630796f,
-0.9982828964265062f, -0.03381941603233842f, -0.03381941603233842f, -0.03381941603233842f,
-0.37968289875261624f, -0.753341017856078f, -0.37968289875261624f, -0.37968289875261624f,
-0.4321472685365301f, -0.7821684431180708f, -0.4321472685365301f, 0.12128480194602098f,
-0.4321472685365301f, -0.7821684431180708f, 0.12128480194602098f, -0.4321472685365301f,
0.12128480194602098f, -0.7821684431180708f, -0.4321472685365301f, -0.4321472685365301f,
-0.508629699630796f, -0.8586508742123365f, 0.044802370851755174f, 0.044802370851755174f,
0.044802370851755174f, -0.8586508742123365f, -0.508629699630796f, 0.044802370851755174f,
0.044802370851755174f, -0.8586508742123365f, 0.044802370851755174f, -0.508629699630796f,
-0.03381941603233842f, -0.9982828964265062f, -0.03381941603233842f, -0.03381941603233842f,
-0.37968289875261624f, -0.37968289875261624f, -0.753341017856078f, -0.37968289875261624f,
-0.4321472685365301f, -0.4321472685365301f, -0.7821684431180708f, 0.12128480194602098f,
-0.4321472685365301f, 0.12128480194602098f, -0.7821684431180708f, -0.4321472685365301f,
0.12128480194602098f, -0.4321472685365301f, -0.7821684431180708f, -0.4321472685365301f,
-0.508629699630796f, 0.044802370851755174f, -0.8586508742123365f, 0.044802370851755174f,
0.044802370851755174f, -0.508629699630796f, -0.8586508742123365f, 0.044802370851755174f,
0.044802370851755174f, 0.044802370851755174f, -0.8586508742123365f, -0.508629699630796f,
-0.03381941603233842f, -0.03381941603233842f, -0.9982828964265062f, -0.03381941603233842f,
-0.37968289875261624f, -0.37968289875261624f, -0.37968289875261624f, -0.753341017856078f,
-0.4321472685365301f, -0.4321472685365301f, 0.12128480194602098f, -0.7821684431180708f,
-0.4321472685365301f, 0.12128480194602098f, -0.4321472685365301f, -0.7821684431180708f,
0.12128480194602098f, -0.4321472685365301f, -0.4321472685365301f, -0.7821684431180708f,
-0.508629699630796f, 0.044802370851755174f, 0.044802370851755174f, -0.8586508742123365f,
0.044802370851755174f, -0.508629699630796f, 0.044802370851755174f, -0.8586508742123365f,
0.044802370851755174f, 0.044802370851755174f, -0.508629699630796f, -0.8586508742123365f,
-0.03381941603233842f, -0.03381941603233842f, -0.03381941603233842f, -0.9982828964265062f,
-0.3239847771997537f, -0.6740059517812944f, -0.3239847771997537f, 0.5794684678643381f,
-0.4004672082940195f, -0.7504883828755602f, 0.15296486218853164f, 0.5029860367700724f,
0.15296486218853164f, -0.7504883828755602f, -0.4004672082940195f, 0.5029860367700724f,
0.08164729285680945f, -0.8828161875373585f, 0.08164729285680945f, 0.4553054119602712f,
-0.08164729285680945f, -0.4553054119602712f, -0.08164729285680945f, 0.8828161875373585f,
-0.15296486218853164f, -0.5029860367700724f, 0.4004672082940195f, 0.7504883828755602f,
0.4004672082940195f, -0.5029860367700724f, -0.15296486218853164f, 0.7504883828755602f,
0.3239847771997537f, -0.5794684678643381f, 0.3239847771997537f, 0.6740059517812944f,
-0.3239847771997537f, -0.3239847771997537f, -0.6740059517812944f, 0.5794684678643381f,
-0.4004672082940195f, 0.15296486218853164f, -0.7504883828755602f, 0.5029860367700724f,
0.15296486218853164f, -0.4004672082940195f, -0.7504883828755602f, 0.5029860367700724f,
0.08164729285680945f, 0.08164729285680945f, -0.8828161875373585f, 0.4553054119602712f,
-0.08164729285680945f, -0.08164729285680945f, -0.4553054119602712f, 0.8828161875373585f,
-0.15296486218853164f, 0.4004672082940195f, -0.5029860367700724f, 0.7504883828755602f,
0.4004672082940195f, -0.15296486218853164f, -0.5029860367700724f, 0.7504883828755602f,
0.3239847771997537f, 0.3239847771997537f, -0.5794684678643381f, 0.6740059517812944f,
-0.3239847771997537f, -0.6740059517812944f, 0.5794684678643381f, -0.3239847771997537f,
-0.4004672082940195f, -0.7504883828755602f, 0.5029860367700724f, 0.15296486218853164f,
0.15296486218853164f, -0.7504883828755602f, 0.5029860367700724f, -0.4004672082940195f,
0.08164729285680945f, -0.8828161875373585f, 0.4553054119602712f, 0.08164729285680945f,
-0.08164729285680945f, -0.4553054119602712f, 0.8828161875373585f, -0.08164729285680945f,
-0.15296486218853164f, -0.5029860367700724f, 0.7504883828755602f, 0.4004672082940195f,
0.4004672082940195f, -0.5029860367700724f, 0.7504883828755602f, -0.15296486218853164f,
0.3239847771997537f, -0.5794684678643381f, 0.6740059517812944f, 0.3239847771997537f,
-0.3239847771997537f, -0.3239847771997537f, 0.5794684678643381f, -0.6740059517812944f,
-0.4004672082940195f, 0.15296486218853164f, 0.5029860367700724f, -0.7504883828755602f,
0.15296486218853164f, -0.4004672082940195f, 0.5029860367700724f, -0.7504883828755602f,
0.08164729285680945f, 0.08164729285680945f, 0.4553054119602712f, -0.8828161875373585f,
-0.08164729285680945f, -0.08164729285680945f, 0.8828161875373585f, -0.4553054119602712f,
-0.15296486218853164f, 0.4004672082940195f, 0.7504883828755602f, -0.5029860367700724f,
0.4004672082940195f, -0.15296486218853164f, 0.7504883828755602f, -0.5029860367700724f,
0.3239847771997537f, 0.3239847771997537f, 0.6740059517812944f, -0.5794684678643381f,
-0.3239847771997537f, 0.5794684678643381f, -0.6740059517812944f, -0.3239847771997537f,
-0.4004672082940195f, 0.5029860367700724f, -0.7504883828755602f, 0.15296486218853164f,
0.15296486218853164f, 0.5029860367700724f, -0.7504883828755602f, -0.4004672082940195f,
0.08164729285680945f, 0.4553054119602712f, -0.8828161875373585f, 0.08164729285680945f,
-0.08164729285680945f, 0.8828161875373585f, -0.4553054119602712f, -0.08164729285680945f,
-0.15296486218853164f, 0.7504883828755602f, -0.5029860367700724f, 0.4004672082940195f,
0.4004672082940195f, 0.7504883828755602f, -0.5029860367700724f, -0.15296486218853164f,
0.3239847771997537f, 0.6740059517812944f, -0.5794684678643381f, 0.3239847771997537f,
-0.3239847771997537f, 0.5794684678643381f, -0.3239847771997537f, -0.6740059517812944f,
-0.4004672082940195f, 0.5029860367700724f, 0.15296486218853164f, -0.7504883828755602f,
0.15296486218853164f, 0.5029860367700724f, -0.4004672082940195f, -0.7504883828755602f,
0.08164729285680945f, 0.4553054119602712f, 0.08164729285680945f, -0.8828161875373585f,
-0.08164729285680945f, 0.8828161875373585f, -0.08164729285680945f, -0.4553054119602712f,
-0.15296486218853164f, 0.7504883828755602f, 0.4004672082940195f, -0.5029860367700724f,
0.4004672082940195f, 0.7504883828755602f, -0.15296486218853164f, -0.5029860367700724f,
0.3239847771997537f, 0.6740059517812944f, 0.3239847771997537f, -0.5794684678643381f,
0.5794684678643381f, -0.3239847771997537f, -0.6740059517812944f, -0.3239847771997537f,
0.5029860367700724f, -0.4004672082940195f, -0.7504883828755602f, 0.15296486218853164f,
0.5029860367700724f, 0.15296486218853164f, -0.7504883828755602f, -0.4004672082940195f,
0.4553054119602712f, 0.08164729285680945f, -0.8828161875373585f, 0.08164729285680945f,
0.8828161875373585f, -0.08164729285680945f, -0.4553054119602712f, -0.08164729285680945f,
0.7504883828755602f, -0.15296486218853164f, -0.5029860367700724f, 0.4004672082940195f,
0.7504883828755602f, 0.4004672082940195f, -0.5029860367700724f, -0.15296486218853164f,
0.6740059517812944f, 0.3239847771997537f, -0.5794684678643381f, 0.3239847771997537f,
0.5794684678643381f, -0.3239847771997537f, -0.3239847771997537f, -0.6740059517812944f,
0.5029860367700724f, -0.4004672082940195f, 0.15296486218853164f, -0.7504883828755602f,
0.5029860367700724f, 0.15296486218853164f, -0.4004672082940195f, -0.7504883828755602f,
0.4553054119602712f, 0.08164729285680945f, 0.08164729285680945f, -0.8828161875373585f,
0.8828161875373585f, -0.08164729285680945f, -0.08164729285680945f, -0.4553054119602712f,
0.7504883828755602f, -0.15296486218853164f, 0.4004672082940195f, -0.5029860367700724f,
0.7504883828755602f, 0.4004672082940195f, -0.15296486218853164f, -0.5029860367700724f,
0.6740059517812944f, 0.3239847771997537f, 0.3239847771997537f, -0.5794684678643381f,
0.03381941603233842f, 0.03381941603233842f, 0.03381941603233842f, 0.9982828964265062f,
-0.044802370851755174f, -0.044802370851755174f, 0.508629699630796f, 0.8586508742123365f,
-0.044802370851755174f, 0.508629699630796f, -0.044802370851755174f, 0.8586508742123365f,
-0.12128480194602098f, 0.4321472685365301f, 0.4321472685365301f, 0.7821684431180708f,
0.508629699630796f, -0.044802370851755174f, -0.044802370851755174f, 0.8586508742123365f,
0.4321472685365301f, -0.12128480194602098f, 0.4321472685365301f, 0.7821684431180708f,
0.4321472685365301f, 0.4321472685365301f, -0.12128480194602098f, 0.7821684431180708f,
0.37968289875261624f, 0.37968289875261624f, 0.37968289875261624f, 0.753341017856078f,
0.03381941603233842f, 0.03381941603233842f, 0.9982828964265062f, 0.03381941603233842f,
-0.044802370851755174f, 0.044802370851755174f, 0.8586508742123365f, 0.508629699630796f,
-0.044802370851755174f, 0.508629699630796f, 0.8586508742123365f, -0.044802370851755174f,
-0.12128480194602098f, 0.4321472685365301f, 0.7821684431180708f, 0.4321472685365301f,
0.508629699630796f, -0.044802370851755174f, 0.8586508742123365f, -0.044802370851755174f,
0.4321472685365301f, -0.12128480194602098f, 0.7821684431180708f, 0.4321472685365301f,
0.4321472685365301f, 0.4321472685365301f, 0.7821684431180708f, -0.12128480194602098f,
0.37968289875261624f, 0.37968289875261624f, 0.753341017856078f, 0.37968289875261624f,
0.03381941603233842f, 0.9982828964265062f, 0.03381941603233842f, 0.03381941603233842f,
-0.044802370851755174f, 0.8586508742123365f, -0.044802370851755174f, 0.508629699630796f,
-0.044802370851755174f, 0.8586508742123365f, 0.508629699630796f, -0.044802370851755174f,
-0.12128480194602098f, 0.7821684431180708f, 0.4321472685365301f, 0.4321472685365301f,
0.508629699630796f, 0.8586508742123365f, -0.044802370851755174f, -0.044802370851755174f,
0.4321472685365301f, 0.7821684431180708f, -0.12128480194602098f, 0.4321472685365301f,
0.4321472685365301f, 0.7821684431180708f, 0.4321472685365301f, -0.12128480194602098f,
0.37968289875261624f, 0.753341017856078f, 0.37968289875261624f, 0.37968289875261624f,
0.9982828964265062f, 0.03381941603233842f, 0.03381941603233842f, 0.03381941603233842f,
0.8586508742123365f, -0.044802370851755174f, -0.044802370851755174f, 0.508629699630796f,
0.8586508742123365f, -0.044802370851755174f, 0.508629699630796f, -0.044802370851755174f,
0.7821684431180708f, -0.12128480194602098f, 0.4321472685365301f, 0.4321472685365301f,
0.8586508742123365f, 0.508629699630796f, -0.044802370851755174f, -0.044802370851755174f,
0.7821684431180708f, 0.4321472685365301f, -0.12128480194602098f, 0.4321472685365301f,
0.7821684431180708f, 0.4321472685365301f, 0.4321472685365301f, -0.12128480194602098f,
0.753341017856078f, 0.37968289875261624f, 0.37968289875261624f, 0.37968289875261624f,
};
for (int i = 0; i < grad4.length; i++) {
grad4[i] = (float)(grad4[i] / NORMALIZER_4D);
}
for (int i = 0, j = 0; i < GRADIENTS_4D.length; i++, j++) {
if (j == grad4.length) j = 0;
GRADIENTS_4D[i] = grad4[j];
}
int[][] lookup4DVertexCodes = {
new int[] { 0x15, 0x45, 0x51, 0x54, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA },
new int[] { 0x15, 0x45, 0x51, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x6A, 0x95, 0x96, 0x9A, 0xA6, 0xAA },
new int[] { 0x01, 0x05, 0x11, 0x15, 0x41, 0x45, 0x51, 0x55, 0x56, 0x5A, 0x66, 0x6A, 0x96, 0x9A, 0xA6, 0xAA },
new int[] { 0x01, 0x15, 0x16, 0x45, 0x46, 0x51, 0x52, 0x55, 0x56, 0x5A, 0x66, 0x6A, 0x96, 0x9A, 0xA6, 0xAA, 0xAB },
new int[] { 0x15, 0x45, 0x54, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x69, 0x6A, 0x95, 0x99, 0x9A, 0xA9, 0xAA },
new int[] { 0x05, 0x15, 0x45, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xAA },
new int[] { 0x05, 0x15, 0x45, 0x55, 0x56, 0x59, 0x5A, 0x66, 0x6A, 0x96, 0x9A, 0xAA },
new int[] { 0x05, 0x15, 0x16, 0x45, 0x46, 0x55, 0x56, 0x59, 0x5A, 0x66, 0x6A, 0x96, 0x9A, 0xAA, 0xAB },
new int[] { 0x04, 0x05, 0x14, 0x15, 0x44, 0x45, 0x54, 0x55, 0x59, 0x5A, 0x69, 0x6A, 0x99, 0x9A, 0xA9, 0xAA },
new int[] { 0x05, 0x15, 0x45, 0x55, 0x56, 0x59, 0x5A, 0x69, 0x6A, 0x99, 0x9A, 0xAA },
new int[] { 0x05, 0x15, 0x45, 0x55, 0x56, 0x59, 0x5A, 0x6A, 0x9A, 0xAA },
new int[] { 0x05, 0x15, 0x16, 0x45, 0x46, 0x55, 0x56, 0x59, 0x5A, 0x5B, 0x6A, 0x9A, 0xAA, 0xAB },
new int[] { 0x04, 0x15, 0x19, 0x45, 0x49, 0x54, 0x55, 0x58, 0x59, 0x5A, 0x69, 0x6A, 0x99, 0x9A, 0xA9, 0xAA, 0xAE },
new int[] { 0x05, 0x15, 0x19, 0x45, 0x49, 0x55, 0x56, 0x59, 0x5A, 0x69, 0x6A, 0x99, 0x9A, 0xAA, 0xAE },
new int[] { 0x05, 0x15, 0x19, 0x45, 0x49, 0x55, 0x56, 0x59, 0x5A, 0x5E, 0x6A, 0x9A, 0xAA, 0xAE },
new int[] { 0x05, 0x15, 0x1A, 0x45, 0x4A, 0x55, 0x56, 0x59, 0x5A, 0x5B, 0x5E, 0x6A, 0x9A, 0xAA, 0xAB, 0xAE, 0xAF },
new int[] { 0x15, 0x51, 0x54, 0x55, 0x56, 0x59, 0x65, 0x66, 0x69, 0x6A, 0x95, 0xA5, 0xA6, 0xA9, 0xAA },
new int[] { 0x11, 0x15, 0x51, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0xA5, 0xA6, 0xAA },
new int[] { 0x11, 0x15, 0x51, 0x55, 0x56, 0x5A, 0x65, 0x66, 0x6A, 0x96, 0xA6, 0xAA },
new int[] { 0x11, 0x15, 0x16, 0x51, 0x52, 0x55, 0x56, 0x5A, 0x65, 0x66, 0x6A, 0x96, 0xA6, 0xAA, 0xAB },
new int[] { 0x14, 0x15, 0x54, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x99, 0xA5, 0xA9, 0xAA },
new int[] { 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x9A, 0xA6, 0xA9, 0xAA },
new int[] { 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x96, 0x9A, 0xA6, 0xAA, 0xAB },
new int[] { 0x15, 0x16, 0x55, 0x56, 0x5A, 0x66, 0x6A, 0x6B, 0x96, 0x9A, 0xA6, 0xAA, 0xAB },
new int[] { 0x14, 0x15, 0x54, 0x55, 0x59, 0x5A, 0x65, 0x69, 0x6A, 0x99, 0xA9, 0xAA },
new int[] { 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x99, 0x9A, 0xA9, 0xAA, 0xAE },
new int[] { 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x9A, 0xAA },
new int[] { 0x15, 0x16, 0x55, 0x56, 0x59, 0x5A, 0x66, 0x6A, 0x6B, 0x9A, 0xAA, 0xAB },
new int[] { 0x14, 0x15, 0x19, 0x54, 0x55, 0x58, 0x59, 0x5A, 0x65, 0x69, 0x6A, 0x99, 0xA9, 0xAA, 0xAE },
new int[] { 0x15, 0x19, 0x55, 0x59, 0x5A, 0x69, 0x6A, 0x6E, 0x99, 0x9A, 0xA9, 0xAA, 0xAE },
new int[] { 0x15, 0x19, 0x55, 0x56, 0x59, 0x5A, 0x69, 0x6A, 0x6E, 0x9A, 0xAA, 0xAE },
new int[] { 0x15, 0x1A, 0x55, 0x56, 0x59, 0x5A, 0x6A, 0x6B, 0x6E, 0x9A, 0xAA, 0xAB, 0xAE, 0xAF },
new int[] { 0x10, 0x11, 0x14, 0x15, 0x50, 0x51, 0x54, 0x55, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA6, 0xA9, 0xAA },
new int[] { 0x11, 0x15, 0x51, 0x55, 0x56, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA6, 0xAA },
new int[] { 0x11, 0x15, 0x51, 0x55, 0x56, 0x65, 0x66, 0x6A, 0xA6, 0xAA },
new int[] { 0x11, 0x15, 0x16, 0x51, 0x52, 0x55, 0x56, 0x65, 0x66, 0x67, 0x6A, 0xA6, 0xAA, 0xAB },
new int[] { 0x14, 0x15, 0x54, 0x55, 0x59, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA9, 0xAA },
new int[] { 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA },
new int[] { 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0xA6, 0xAA },
new int[] { 0x15, 0x16, 0x55, 0x56, 0x5A, 0x65, 0x66, 0x6A, 0x6B, 0xA6, 0xAA, 0xAB },
new int[] { 0x14, 0x15, 0x54, 0x55, 0x59, 0x65, 0x69, 0x6A, 0xA9, 0xAA },
new int[] { 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0xA9, 0xAA },
new int[] { 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0xAA },
new int[] { 0x15, 0x16, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x6B, 0xAA, 0xAB },
new int[] { 0x14, 0x15, 0x19, 0x54, 0x55, 0x58, 0x59, 0x65, 0x69, 0x6A, 0x6D, 0xA9, 0xAA, 0xAE },
new int[] { 0x15, 0x19, 0x55, 0x59, 0x5A, 0x65, 0x69, 0x6A, 0x6E, 0xA9, 0xAA, 0xAE },
new int[] { 0x15, 0x19, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x6E, 0xAA, 0xAE },
new int[] { 0x15, 0x55, 0x56, 0x59, 0x5A, 0x66, 0x69, 0x6A, 0x6B, 0x6E, 0x9A, 0xAA, 0xAB, 0xAE, 0xAF },
new int[] { 0x10, 0x15, 0x25, 0x51, 0x54, 0x55, 0x61, 0x64, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA },
new int[] { 0x11, 0x15, 0x25, 0x51, 0x55, 0x56, 0x61, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA6, 0xAA, 0xBA },
new int[] { 0x11, 0x15, 0x25, 0x51, 0x55, 0x56, 0x61, 0x65, 0x66, 0x6A, 0x76, 0xA6, 0xAA, 0xBA },
new int[] { 0x11, 0x15, 0x26, 0x51, 0x55, 0x56, 0x62, 0x65, 0x66, 0x67, 0x6A, 0x76, 0xA6, 0xAA, 0xAB, 0xBA, 0xBB },
new int[] { 0x14, 0x15, 0x25, 0x54, 0x55, 0x59, 0x64, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA9, 0xAA, 0xBA },
new int[] { 0x15, 0x25, 0x55, 0x65, 0x66, 0x69, 0x6A, 0x7A, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA },
new int[] { 0x15, 0x25, 0x55, 0x56, 0x65, 0x66, 0x69, 0x6A, 0x7A, 0xA6, 0xAA, 0xBA },
new int[] { 0x15, 0x26, 0x55, 0x56, 0x65, 0x66, 0x6A, 0x6B, 0x7A, 0xA6, 0xAA, 0xAB, 0xBA, 0xBB },
new int[] { 0x14, 0x15, 0x25, 0x54, 0x55, 0x59, 0x64, 0x65, 0x69, 0x6A, 0x79, 0xA9, 0xAA, 0xBA },
new int[] { 0x15, 0x25, 0x55, 0x59, 0x65, 0x66, 0x69, 0x6A, 0x7A, 0xA9, 0xAA, 0xBA },
new int[] { 0x15, 0x25, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x7A, 0xAA, 0xBA },
new int[] { 0x15, 0x55, 0x56, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x6B, 0x7A, 0xA6, 0xAA, 0xAB, 0xBA, 0xBB },
new int[] { 0x14, 0x15, 0x29, 0x54, 0x55, 0x59, 0x65, 0x68, 0x69, 0x6A, 0x6D, 0x79, 0xA9, 0xAA, 0xAE, 0xBA, 0xBE },
new int[] { 0x15, 0x29, 0x55, 0x59, 0x65, 0x69, 0x6A, 0x6E, 0x7A, 0xA9, 0xAA, 0xAE, 0xBA, 0xBE },
new int[] { 0x15, 0x55, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x6E, 0x7A, 0xA9, 0xAA, 0xAE, 0xBA, 0xBE },
new int[] { 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x6B, 0x6E, 0x7A, 0xAA, 0xAB, 0xAE, 0xBA, 0xBF },
new int[] { 0x45, 0x51, 0x54, 0x55, 0x56, 0x59, 0x65, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA },
new int[] { 0x41, 0x45, 0x51, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xAA },
new int[] { 0x41, 0x45, 0x51, 0x55, 0x56, 0x5A, 0x66, 0x95, 0x96, 0x9A, 0xA6, 0xAA },
new int[] { 0x41, 0x45, 0x46, 0x51, 0x52, 0x55, 0x56, 0x5A, 0x66, 0x95, 0x96, 0x9A, 0xA6, 0xAA, 0xAB },
new int[] { 0x44, 0x45, 0x54, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x69, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA9, 0xAA },
new int[] { 0x45, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA6, 0xA9, 0xAA },
new int[] { 0x45, 0x55, 0x56, 0x59, 0x5A, 0x66, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA6, 0xAA, 0xAB },
new int[] { 0x45, 0x46, 0x55, 0x56, 0x5A, 0x66, 0x6A, 0x96, 0x9A, 0x9B, 0xA6, 0xAA, 0xAB },
new int[] { 0x44, 0x45, 0x54, 0x55, 0x59, 0x5A, 0x69, 0x95, 0x99, 0x9A, 0xA9, 0xAA },
new int[] { 0x45, 0x55, 0x56, 0x59, 0x5A, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA9, 0xAA, 0xAE },
new int[] { 0x45, 0x55, 0x56, 0x59, 0x5A, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xAA },
new int[] { 0x45, 0x46, 0x55, 0x56, 0x59, 0x5A, 0x6A, 0x96, 0x9A, 0x9B, 0xAA, 0xAB },
new int[] { 0x44, 0x45, 0x49, 0x54, 0x55, 0x58, 0x59, 0x5A, 0x69, 0x95, 0x99, 0x9A, 0xA9, 0xAA, 0xAE },
new int[] { 0x45, 0x49, 0x55, 0x59, 0x5A, 0x69, 0x6A, 0x99, 0x9A, 0x9E, 0xA9, 0xAA, 0xAE },
new int[] { 0x45, 0x49, 0x55, 0x56, 0x59, 0x5A, 0x6A, 0x99, 0x9A, 0x9E, 0xAA, 0xAE },
new int[] { 0x45, 0x4A, 0x55, 0x56, 0x59, 0x5A, 0x6A, 0x9A, 0x9B, 0x9E, 0xAA, 0xAB, 0xAE, 0xAF },
new int[] { 0x50, 0x51, 0x54, 0x55, 0x56, 0x59, 0x65, 0x66, 0x69, 0x95, 0x96, 0x99, 0xA5, 0xA6, 0xA9, 0xAA },
new int[] { 0x51, 0x55, 0x56, 0x59, 0x65, 0x66, 0x6A, 0x95, 0x96, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA },
new int[] { 0x51, 0x55, 0x56, 0x5A, 0x65, 0x66, 0x6A, 0x95, 0x96, 0x9A, 0xA5, 0xA6, 0xAA, 0xAB },
new int[] { 0x51, 0x52, 0x55, 0x56, 0x5A, 0x66, 0x6A, 0x96, 0x9A, 0xA6, 0xA7, 0xAA, 0xAB },
new int[] { 0x54, 0x55, 0x56, 0x59, 0x65, 0x69, 0x6A, 0x95, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA },
new int[] { 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA },
new int[] { 0x15, 0x45, 0x51, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x6A, 0x95, 0x96, 0x9A, 0xA6, 0xAA, 0xAB },
new int[] { 0x55, 0x56, 0x5A, 0x66, 0x6A, 0x96, 0x9A, 0xA6, 0xAA, 0xAB },
new int[] { 0x54, 0x55, 0x59, 0x5A, 0x65, 0x69, 0x6A, 0x95, 0x99, 0x9A, 0xA5, 0xA9, 0xAA, 0xAE },
new int[] { 0x15, 0x45, 0x54, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x69, 0x6A, 0x95, 0x99, 0x9A, 0xA9, 0xAA, 0xAE },
new int[] { 0x15, 0x45, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA6, 0xA9, 0xAA, 0xAB, 0xAE },
new int[] { 0x55, 0x56, 0x59, 0x5A, 0x66, 0x6A, 0x96, 0x9A, 0xA6, 0xAA, 0xAB },
new int[] { 0x54, 0x55, 0x58, 0x59, 0x5A, 0x69, 0x6A, 0x99, 0x9A, 0xA9, 0xAA, 0xAD, 0xAE },
new int[] { 0x55, 0x59, 0x5A, 0x69, 0x6A, 0x99, 0x9A, 0xA9, 0xAA, 0xAE },
new int[] { 0x55, 0x56, 0x59, 0x5A, 0x69, 0x6A, 0x99, 0x9A, 0xA9, 0xAA, 0xAE },
new int[] { 0x55, 0x56, 0x59, 0x5A, 0x6A, 0x9A, 0xAA, 0xAB, 0xAE, 0xAF },
new int[] { 0x50, 0x51, 0x54, 0x55, 0x65, 0x66, 0x69, 0x95, 0xA5, 0xA6, 0xA9, 0xAA },
new int[] { 0x51, 0x55, 0x56, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA },
new int[] { 0x51, 0x55, 0x56, 0x65, 0x66, 0x6A, 0x95, 0x96, 0xA5, 0xA6, 0xAA },
new int[] { 0x51, 0x52, 0x55, 0x56, 0x65, 0x66, 0x6A, 0x96, 0xA6, 0xA7, 0xAA, 0xAB },
new int[] { 0x54, 0x55, 0x59, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x99, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA },
new int[] { 0x15, 0x51, 0x54, 0x55, 0x56, 0x59, 0x65, 0x66, 0x69, 0x6A, 0x95, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA },
new int[] { 0x15, 0x51, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xAB, 0xBA },
new int[] { 0x55, 0x56, 0x5A, 0x65, 0x66, 0x6A, 0x96, 0x9A, 0xA6, 0xAA, 0xAB },
new int[] { 0x54, 0x55, 0x59, 0x65, 0x69, 0x6A, 0x95, 0x99, 0xA5, 0xA9, 0xAA },
new int[] { 0x15, 0x54, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xAE, 0xBA },
new int[] { 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x9A, 0xA6, 0xA9, 0xAA },
new int[] { 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x96, 0x9A, 0xA6, 0xAA, 0xAB },
new int[] { 0x54, 0x55, 0x58, 0x59, 0x65, 0x69, 0x6A, 0x99, 0xA9, 0xAA, 0xAD, 0xAE },
new int[] { 0x55, 0x59, 0x5A, 0x65, 0x69, 0x6A, 0x99, 0x9A, 0xA9, 0xAA, 0xAE },
new int[] { 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x99, 0x9A, 0xA9, 0xAA, 0xAE },
new int[] { 0x15, 0x55, 0x56, 0x59, 0x5A, 0x66, 0x69, 0x6A, 0x9A, 0xAA, 0xAB, 0xAE, 0xAF },
new int[] { 0x50, 0x51, 0x54, 0x55, 0x61, 0x64, 0x65, 0x66, 0x69, 0x95, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA },
new int[] { 0x51, 0x55, 0x61, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA6, 0xA9, 0xAA, 0xB6, 0xBA },
new int[] { 0x51, 0x55, 0x56, 0x61, 0x65, 0x66, 0x6A, 0xA5, 0xA6, 0xAA, 0xB6, 0xBA },
new int[] { 0x51, 0x55, 0x56, 0x62, 0x65, 0x66, 0x6A, 0xA6, 0xA7, 0xAA, 0xAB, 0xB6, 0xBA, 0xBB },
new int[] { 0x54, 0x55, 0x64, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA6, 0xA9, 0xAA, 0xB9, 0xBA },
new int[] { 0x55, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA },
new int[] { 0x55, 0x56, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA },
new int[] { 0x55, 0x56, 0x65, 0x66, 0x6A, 0xA6, 0xAA, 0xAB, 0xBA, 0xBB },
new int[] { 0x54, 0x55, 0x59, 0x64, 0x65, 0x69, 0x6A, 0xA5, 0xA9, 0xAA, 0xB9, 0xBA },
new int[] { 0x55, 0x59, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA },
new int[] { 0x15, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA },
new int[] { 0x15, 0x55, 0x56, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0xA6, 0xAA, 0xAB, 0xBA, 0xBB },
new int[] { 0x54, 0x55, 0x59, 0x65, 0x68, 0x69, 0x6A, 0xA9, 0xAA, 0xAD, 0xAE, 0xB9, 0xBA, 0xBE },
new int[] { 0x55, 0x59, 0x65, 0x69, 0x6A, 0xA9, 0xAA, 0xAE, 0xBA, 0xBE },
new int[] { 0x15, 0x55, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0xA9, 0xAA, 0xAE, 0xBA, 0xBE },
new int[] { 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0xAA, 0xAB, 0xAE, 0xBA, 0xBF },
new int[] { 0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA },
new int[] { 0x41, 0x45, 0x51, 0x55, 0x56, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xAA },
new int[] { 0x41, 0x45, 0x51, 0x55, 0x56, 0x95, 0x96, 0x9A, 0xA6, 0xAA },
new int[] { 0x41, 0x45, 0x46, 0x51, 0x52, 0x55, 0x56, 0x95, 0x96, 0x97, 0x9A, 0xA6, 0xAA, 0xAB },
new int[] { 0x44, 0x45, 0x54, 0x55, 0x59, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA9, 0xAA },
new int[] { 0x45, 0x55, 0x56, 0x59, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA },
new int[] { 0x45, 0x55, 0x56, 0x59, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0xA6, 0xAA },
new int[] { 0x45, 0x46, 0x55, 0x56, 0x5A, 0x95, 0x96, 0x9A, 0x9B, 0xA6, 0xAA, 0xAB },
new int[] { 0x44, 0x45, 0x54, 0x55, 0x59, 0x95, 0x99, 0x9A, 0xA9, 0xAA },
new int[] { 0x45, 0x55, 0x56, 0x59, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0xA9, 0xAA },
new int[] { 0x45, 0x55, 0x56, 0x59, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0xAA },
new int[] { 0x45, 0x46, 0x55, 0x56, 0x59, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0x9B, 0xAA, 0xAB },
new int[] { 0x44, 0x45, 0x49, 0x54, 0x55, 0x58, 0x59, 0x95, 0x99, 0x9A, 0x9D, 0xA9, 0xAA, 0xAE },
new int[] { 0x45, 0x49, 0x55, 0x59, 0x5A, 0x95, 0x99, 0x9A, 0x9E, 0xA9, 0xAA, 0xAE },
new int[] { 0x45, 0x49, 0x55, 0x56, 0x59, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0x9E, 0xAA, 0xAE },
new int[] { 0x45, 0x55, 0x56, 0x59, 0x5A, 0x6A, 0x96, 0x99, 0x9A, 0x9B, 0x9E, 0xAA, 0xAB, 0xAE, 0xAF },
new int[] { 0x50, 0x51, 0x54, 0x55, 0x65, 0x95, 0x96, 0x99, 0xA5, 0xA6, 0xA9, 0xAA },
new int[] { 0x51, 0x55, 0x56, 0x65, 0x66, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA },
new int[] { 0x51, 0x55, 0x56, 0x65, 0x66, 0x95, 0x96, 0x9A, 0xA5, 0xA6, 0xAA },
new int[] { 0x51, 0x52, 0x55, 0x56, 0x66, 0x95, 0x96, 0x9A, 0xA6, 0xA7, 0xAA, 0xAB },
new int[] { 0x54, 0x55, 0x59, 0x65, 0x69, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA },
new int[] { 0x45, 0x51, 0x54, 0x55, 0x56, 0x59, 0x65, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA },
new int[] { 0x45, 0x51, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xAB, 0xEA },
new int[] { 0x55, 0x56, 0x5A, 0x66, 0x6A, 0x95, 0x96, 0x9A, 0xA6, 0xAA, 0xAB },
new int[] { 0x54, 0x55, 0x59, 0x65, 0x69, 0x95, 0x99, 0x9A, 0xA5, 0xA9, 0xAA },
new int[] { 0x45, 0x54, 0x55, 0x56, 0x59, 0x5A, 0x65, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xAE, 0xEA },
new int[] { 0x45, 0x55, 0x56, 0x59, 0x5A, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA6, 0xA9, 0xAA },
new int[] { 0x45, 0x55, 0x56, 0x59, 0x5A, 0x66, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA6, 0xAA, 0xAB },
new int[] { 0x54, 0x55, 0x58, 0x59, 0x69, 0x95, 0x99, 0x9A, 0xA9, 0xAA, 0xAD, 0xAE },
new int[] { 0x55, 0x59, 0x5A, 0x69, 0x6A, 0x95, 0x99, 0x9A, 0xA9, 0xAA, 0xAE },
new int[] { 0x45, 0x55, 0x56, 0x59, 0x5A, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA9, 0xAA, 0xAE },
new int[] { 0x45, 0x55, 0x56, 0x59, 0x5A, 0x6A, 0x96, 0x99, 0x9A, 0xAA, 0xAB, 0xAE, 0xAF },
new int[] { 0x50, 0x51, 0x54, 0x55, 0x65, 0x95, 0xA5, 0xA6, 0xA9, 0xAA },
new int[] { 0x51, 0x55, 0x56, 0x65, 0x66, 0x95, 0x96, 0xA5, 0xA6, 0xA9, 0xAA },
new int[] { 0x51, 0x55, 0x56, 0x65, 0x66, 0x95, 0x96, 0xA5, 0xA6, 0xAA },
new int[] { 0x51, 0x52, 0x55, 0x56, 0x65, 0x66, 0x95, 0x96, 0xA5, 0xA6, 0xA7, 0xAA, 0xAB },
new int[] { 0x54, 0x55, 0x59, 0x65, 0x69, 0x95, 0x99, 0xA5, 0xA6, 0xA9, 0xAA },
new int[] { 0x51, 0x54, 0x55, 0x56, 0x59, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA, 0xEA },
new int[] { 0x51, 0x55, 0x56, 0x65, 0x66, 0x6A, 0x95, 0x96, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA },
new int[] { 0x51, 0x55, 0x56, 0x5A, 0x65, 0x66, 0x6A, 0x95, 0x96, 0x9A, 0xA5, 0xA6, 0xAA, 0xAB },
new int[] { 0x54, 0x55, 0x59, 0x65, 0x69, 0x95, 0x99, 0xA5, 0xA9, 0xAA },
new int[] { 0x54, 0x55, 0x59, 0x65, 0x69, 0x6A, 0x95, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA },
new int[] { 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA },
new int[] { 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x6A, 0x95, 0x96, 0x9A, 0xA6, 0xA9, 0xAA, 0xAB },
new int[] { 0x54, 0x55, 0x58, 0x59, 0x65, 0x69, 0x95, 0x99, 0xA5, 0xA9, 0xAA, 0xAD, 0xAE },
new int[] { 0x54, 0x55, 0x59, 0x5A, 0x65, 0x69, 0x6A, 0x95, 0x99, 0x9A, 0xA5, 0xA9, 0xAA, 0xAE },
new int[] { 0x55, 0x56, 0x59, 0x5A, 0x65, 0x69, 0x6A, 0x95, 0x99, 0x9A, 0xA6, 0xA9, 0xAA, 0xAE },
new int[] { 0x55, 0x56, 0x59, 0x5A, 0x66, 0x69, 0x6A, 0x96, 0x99, 0x9A, 0xA6, 0xA9, 0xAA, 0xAB, 0xAE, 0xAF },
new int[] { 0x50, 0x51, 0x54, 0x55, 0x61, 0x64, 0x65, 0x95, 0xA5, 0xA6, 0xA9, 0xAA, 0xB5, 0xBA },
new int[] { 0x51, 0x55, 0x61, 0x65, 0x66, 0x95, 0xA5, 0xA6, 0xA9, 0xAA, 0xB6, 0xBA },
new int[] { 0x51, 0x55, 0x56, 0x61, 0x65, 0x66, 0x95, 0x96, 0xA5, 0xA6, 0xAA, 0xB6, 0xBA },
new int[] { 0x51, 0x55, 0x56, 0x65, 0x66, 0x6A, 0x96, 0xA5, 0xA6, 0xA7, 0xAA, 0xAB, 0xB6, 0xBA, 0xBB },
new int[] { 0x54, 0x55, 0x64, 0x65, 0x69, 0x95, 0xA5, 0xA6, 0xA9, 0xAA, 0xB9, 0xBA },
new int[] { 0x55, 0x65, 0x66, 0x69, 0x6A, 0x95, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA },
new int[] { 0x51, 0x55, 0x56, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA },
new int[] { 0x51, 0x55, 0x56, 0x65, 0x66, 0x6A, 0x96, 0xA5, 0xA6, 0xAA, 0xAB, 0xBA, 0xBB },
new int[] { 0x54, 0x55, 0x59, 0x64, 0x65, 0x69, 0x95, 0x99, 0xA5, 0xA9, 0xAA, 0xB9, 0xBA },
new int[] { 0x54, 0x55, 0x59, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x99, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA },
new int[] { 0x55, 0x56, 0x59, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA },
new int[] { 0x55, 0x56, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x96, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xAB, 0xBA, 0xBB },
new int[] { 0x54, 0x55, 0x59, 0x65, 0x69, 0x6A, 0x99, 0xA5, 0xA9, 0xAA, 0xAD, 0xAE, 0xB9, 0xBA, 0xBE },
new int[] { 0x54, 0x55, 0x59, 0x65, 0x69, 0x6A, 0x99, 0xA5, 0xA9, 0xAA, 0xAE, 0xBA, 0xBE },
new int[] { 0x55, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xAE, 0xBA, 0xBE },
new int[] { 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x9A, 0xA6, 0xA9, 0xAA, 0xAB, 0xAE, 0xBA },
new int[] { 0x40, 0x45, 0x51, 0x54, 0x55, 0x85, 0x91, 0x94, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA },
new int[] { 0x41, 0x45, 0x51, 0x55, 0x56, 0x85, 0x91, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xAA, 0xEA },
new int[] { 0x41, 0x45, 0x51, 0x55, 0x56, 0x85, 0x91, 0x95, 0x96, 0x9A, 0xA6, 0xAA, 0xD6, 0xEA },
new int[] { 0x41, 0x45, 0x51, 0x55, 0x56, 0x86, 0x92, 0x95, 0x96, 0x97, 0x9A, 0xA6, 0xAA, 0xAB, 0xD6, 0xEA, 0xEB },
new int[] { 0x44, 0x45, 0x54, 0x55, 0x59, 0x85, 0x94, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA9, 0xAA, 0xEA },
new int[] { 0x45, 0x55, 0x85, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xDA, 0xEA },
new int[] { 0x45, 0x55, 0x56, 0x85, 0x95, 0x96, 0x99, 0x9A, 0xA6, 0xAA, 0xDA, 0xEA },
new int[] { 0x45, 0x55, 0x56, 0x86, 0x95, 0x96, 0x9A, 0x9B, 0xA6, 0xAA, 0xAB, 0xDA, 0xEA, 0xEB },
new int[] { 0x44, 0x45, 0x54, 0x55, 0x59, 0x85, 0x94, 0x95, 0x99, 0x9A, 0xA9, 0xAA, 0xD9, 0xEA },
new int[] { 0x45, 0x55, 0x59, 0x85, 0x95, 0x96, 0x99, 0x9A, 0xA9, 0xAA, 0xDA, 0xEA },
new int[] { 0x45, 0x55, 0x56, 0x59, 0x5A, 0x85, 0x95, 0x96, 0x99, 0x9A, 0xAA, 0xDA, 0xEA },
new int[] { 0x45, 0x55, 0x56, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0x9B, 0xA6, 0xAA, 0xAB, 0xDA, 0xEA, 0xEB },
new int[] { 0x44, 0x45, 0x54, 0x55, 0x59, 0x89, 0x95, 0x98, 0x99, 0x9A, 0x9D, 0xA9, 0xAA, 0xAE, 0xD9, 0xEA, 0xEE },
new int[] { 0x45, 0x55, 0x59, 0x89, 0x95, 0x99, 0x9A, 0x9E, 0xA9, 0xAA, 0xAE, 0xDA, 0xEA, 0xEE },
new int[] { 0x45, 0x55, 0x59, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0x9E, 0xA9, 0xAA, 0xAE, 0xDA, 0xEA, 0xEE },
new int[] { 0x45, 0x55, 0x56, 0x59, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0x9B, 0x9E, 0xAA, 0xAB, 0xAE, 0xDA, 0xEA, 0xEF },
new int[] { 0x50, 0x51, 0x54, 0x55, 0x65, 0x91, 0x94, 0x95, 0x96, 0x99, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA },
new int[] { 0x51, 0x55, 0x91, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xE6, 0xEA },
new int[] { 0x51, 0x55, 0x56, 0x91, 0x95, 0x96, 0x9A, 0xA5, 0xA6, 0xAA, 0xE6, 0xEA },
new int[] { 0x51, 0x55, 0x56, 0x92, 0x95, 0x96, 0x9A, 0xA6, 0xA7, 0xAA, 0xAB, 0xE6, 0xEA, 0xEB },
new int[] { 0x54, 0x55, 0x94, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xE9, 0xEA },
new int[] { 0x55, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA },
new int[] { 0x55, 0x56, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA },
new int[] { 0x55, 0x56, 0x95, 0x96, 0x9A, 0xA6, 0xAA, 0xAB, 0xEA, 0xEB },
new int[] { 0x54, 0x55, 0x59, 0x94, 0x95, 0x99, 0x9A, 0xA5, 0xA9, 0xAA, 0xE9, 0xEA },
new int[] { 0x55, 0x59, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA },
new int[] { 0x45, 0x55, 0x56, 0x59, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA },
new int[] { 0x45, 0x55, 0x56, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0xA6, 0xAA, 0xAB, 0xEA, 0xEB },
new int[] { 0x54, 0x55, 0x59, 0x95, 0x98, 0x99, 0x9A, 0xA9, 0xAA, 0xAD, 0xAE, 0xE9, 0xEA, 0xEE },
new int[] { 0x55, 0x59, 0x95, 0x99, 0x9A, 0xA9, 0xAA, 0xAE, 0xEA, 0xEE },
new int[] { 0x45, 0x55, 0x59, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0xA9, 0xAA, 0xAE, 0xEA, 0xEE },
new int[] { 0x55, 0x56, 0x59, 0x5A, 0x95, 0x96, 0x99, 0x9A, 0xAA, 0xAB, 0xAE, 0xEA, 0xEF },
new int[] { 0x50, 0x51, 0x54, 0x55, 0x65, 0x91, 0x94, 0x95, 0xA5, 0xA6, 0xA9, 0xAA, 0xE5, 0xEA },
new int[] { 0x51, 0x55, 0x65, 0x91, 0x95, 0x96, 0xA5, 0xA6, 0xA9, 0xAA, 0xE6, 0xEA },
new int[] { 0x51, 0x55, 0x56, 0x65, 0x66, 0x91, 0x95, 0x96, 0xA5, 0xA6, 0xAA, 0xE6, 0xEA },
new int[] { 0x51, 0x55, 0x56, 0x66, 0x95, 0x96, 0x9A, 0xA5, 0xA6, 0xA7, 0xAA, 0xAB, 0xE6, 0xEA, 0xEB },
new int[] { 0x54, 0x55, 0x65, 0x94, 0x95, 0x99, 0xA5, 0xA6, 0xA9, 0xAA, 0xE9, 0xEA },
new int[] { 0x55, 0x65, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA },
new int[] { 0x51, 0x55, 0x56, 0x65, 0x66, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA },
new int[] { 0x51, 0x55, 0x56, 0x66, 0x95, 0x96, 0x9A, 0xA5, 0xA6, 0xAA, 0xAB, 0xEA, 0xEB },
new int[] { 0x54, 0x55, 0x59, 0x65, 0x69, 0x94, 0x95, 0x99, 0xA5, 0xA9, 0xAA, 0xE9, 0xEA },
new int[] { 0x54, 0x55, 0x59, 0x65, 0x69, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA },
new int[] { 0x55, 0x56, 0x59, 0x65, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xEA },
new int[] { 0x55, 0x56, 0x5A, 0x66, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xAB, 0xEA, 0xEB },
new int[] { 0x54, 0x55, 0x59, 0x69, 0x95, 0x99, 0x9A, 0xA5, 0xA9, 0xAA, 0xAD, 0xAE, 0xE9, 0xEA, 0xEE },
new int[] { 0x54, 0x55, 0x59, 0x69, 0x95, 0x99, 0x9A, 0xA5, 0xA9, 0xAA, 0xAE, 0xEA, 0xEE },
new int[] { 0x55, 0x59, 0x5A, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xAE, 0xEA, 0xEE },
new int[] { 0x55, 0x56, 0x59, 0x5A, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA6, 0xA9, 0xAA, 0xAB, 0xAE, 0xEA },
new int[] { 0x50, 0x51, 0x54, 0x55, 0x65, 0x95, 0xA1, 0xA4, 0xA5, 0xA6, 0xA9, 0xAA, 0xB5, 0xBA, 0xE5, 0xEA, 0xFA },
new int[] { 0x51, 0x55, 0x65, 0x95, 0xA1, 0xA5, 0xA6, 0xA9, 0xAA, 0xB6, 0xBA, 0xE6, 0xEA, 0xFA },
new int[] { 0x51, 0x55, 0x65, 0x66, 0x95, 0x96, 0xA5, 0xA6, 0xA9, 0xAA, 0xB6, 0xBA, 0xE6, 0xEA, 0xFA },
new int[] { 0x51, 0x55, 0x56, 0x65, 0x66, 0x95, 0x96, 0xA5, 0xA6, 0xA7, 0xAA, 0xAB, 0xB6, 0xBA, 0xE6, 0xEA, 0xFB },
new int[] { 0x54, 0x55, 0x65, 0x95, 0xA4, 0xA5, 0xA6, 0xA9, 0xAA, 0xB9, 0xBA, 0xE9, 0xEA, 0xFA },
new int[] { 0x55, 0x65, 0x95, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA, 0xEA, 0xFA },
new int[] { 0x51, 0x55, 0x65, 0x66, 0x95, 0x96, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA, 0xEA, 0xFA },
new int[] { 0x55, 0x56, 0x65, 0x66, 0x95, 0x96, 0xA5, 0xA6, 0xAA, 0xAB, 0xBA, 0xEA, 0xFB },
new int[] { 0x54, 0x55, 0x65, 0x69, 0x95, 0x99, 0xA5, 0xA6, 0xA9, 0xAA, 0xB9, 0xBA, 0xE9, 0xEA, 0xFA },
new int[] { 0x54, 0x55, 0x65, 0x69, 0x95, 0x99, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA, 0xEA, 0xFA },
new int[] { 0x55, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xBA, 0xEA, 0xFA },
new int[] { 0x55, 0x56, 0x65, 0x66, 0x6A, 0x95, 0x96, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xAB, 0xBA, 0xEA },
new int[] { 0x54, 0x55, 0x59, 0x65, 0x69, 0x95, 0x99, 0xA5, 0xA9, 0xAA, 0xAD, 0xAE, 0xB9, 0xBA, 0xE9, 0xEA, 0xFE },
new int[] { 0x55, 0x59, 0x65, 0x69, 0x95, 0x99, 0xA5, 0xA9, 0xAA, 0xAE, 0xBA, 0xEA, 0xFE },
new int[] { 0x55, 0x59, 0x65, 0x69, 0x6A, 0x95, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xAE, 0xBA, 0xEA },
new int[] { 0x55, 0x56, 0x59, 0x5A, 0x65, 0x66, 0x69, 0x6A, 0x95, 0x96, 0x99, 0x9A, 0xA5, 0xA6, 0xA9, 0xAA, 0xAB, 0xAE, 0xBA, 0xEA },
};
LatticeVertex4D[] latticeVerticesByCode = new LatticeVertex4D[256];
for (int i = 0; i < 256; i++) {
int cx = ((i >> 0) & 3) - 1;
int cy = ((i >> 2) & 3) - 1;
int cz = ((i >> 4) & 3) - 1;
int cw = ((i >> 6) & 3) - 1;
latticeVerticesByCode[i] = new LatticeVertex4D(cx, cy, cz, cw);
}
int nLatticeVerticesTotal = 0;
for (int i = 0; i < 256; i++) {
nLatticeVerticesTotal += lookup4DVertexCodes[i].length;
}
LOOKUP_4D_A = new int[256];
LOOKUP_4D_B = new LatticeVertex4D[nLatticeVerticesTotal];
for (int i = 0, j = 0; i < 256; i++) {
LOOKUP_4D_A[i] = j | ((j + lookup4DVertexCodes[i].length) << 16);
for (int k = 0; k < lookup4DVertexCodes[i].length; k++) {
LOOKUP_4D_B[j++] = latticeVerticesByCode[lookup4DVertexCodes[i][k]];
}
}
}
private static class LatticeVertex4D {
public final float dx, dy, dz, dw;
public final long xsvp, ysvp, zsvp, wsvp;
public LatticeVertex4D(int xsv, int ysv, int zsv, int wsv) {
this.xsvp = xsv * PRIME_X; this.ysvp = ysv * PRIME_Y;
this.zsvp = zsv * PRIME_Z; this.wsvp = wsv * PRIME_W;
float ssv = (xsv + ysv + zsv + wsv) * UNSKEW_4D;
this.dx = -xsv - ssv;
this.dy = -ysv - ssv;
this.dz = -zsv - ssv;
this.dw = -wsv - ssv;
}
}
}
/*
* OpenSimplex2S Noise sample class.
*/
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.io.*;
public class OpenSimplexDemo
{
private static final long SEED = 0;
private static final int WIDTH = 512;
private static final int HEIGHT = 512;
private static final double FREQUENCY = 1.0 / 24.0;
public static void main(String[] args)
throws IOException {
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < WIDTH; x++)
{
double value = OpenSimplex2S.noise3_ImproveXY(SEED, x * FREQUENCY, y * FREQUENCY, 0.0);
int rgb = 0x010101 * (int)((value + 1) * 127.5);
image.setRGB(x, y, rgb);
}
}
ImageIO.write(image, "png", new File("noise.png"));
}
}
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.
@ecumene
Copy link

ecumene commented Sep 23, 2014

Wow, great work!

@tliron
Copy link

tliron commented Oct 6, 2014

Any chance you can make periodic versions?

@oloflarsson
Copy link

I would like to see a 1 dimension implementation as well.
Also there is the common problem of getting the noise level for a certain chance.
http://stackoverflow.com/questions/11487759/perlin-noise-to-percentage
Maybe you could include a getNoiseForChance(double chance) method?

@oloflarsson
Copy link

Here is another example of someone struggling with the "chance" problem:
http://stackoverflow.com/questions/3696747/generation-of-uniformly-distributed-random-noise

Copy link

ghost commented Apr 27, 2015

This is fantastic. Thank you! I am deff going to give you credit in my work.

@afonsolage
Copy link

Awesome work! This was exactly what I was looking for. I'll add to my project and, of course, keep your name on it!!!

@Asmageddon
Copy link

Bloody hell, this is a freaking long source. Any chance of a shorter implementation, perhaps a GLSL one?

@tyronx
Copy link

tyronx commented Feb 16, 2016

Shouldn't it generate noise between -1 and 1? For the 2d implementation it seems to generate more like within an area of -0.87 to +0.87

I thing the norm constants haven't been chosen quite right.

@CreamyCookie
Copy link

@KdotJPG There seem to be few unused assignments: smcameron/open-simplex-noise-in-c#4

Any idea?

@ghandhikus
Copy link

// Iterations: 100000000
2DOpenSimplexNoise speed: 6498.520513ms // this
2DSimplexNoise speed: 5000.267634ms // http://staffwww.itn.liu.se/~stegu/simplexnoise/SimplexNoise.java

// Iterations: 1000000
2DOpenSimplexNoise speed: 111.175103ms
2DSimplexNoise speed: 73.051068ms

////////////////////////////////////////////////////////////////
// After adding final to both implementation like so "public final class Name"
// Also I've separated the tests to avoid hot and cold scenario

// Iterations: 100000000
2DOpenSimplexNoise speed: 5702.409891ms
2DOpenSimplexNoise speed: 5675.584907ms
2DOpenSimplexNoise speed: 5863.16953ms
2DSimplexNoise speed: 4633.812286ms
2DSimplexNoise speed: 4524.991414ms
2DSimplexNoise speed: 4492.767565ms
2DSimplexNoise speed: 4649.350849ms
2DSimplexNoise speed: 4455.254193ms
2DSimplexNoise speed: 4633.330702ms
2DSimplexNoise speed: 4550.094936ms

// Best scenarios in this test
//
// 2DOpenSimplexNoise - 5675.584907ms
// 2DSimplexNoise - 4455.254193ms

// Worst scenarios in this test
//
// 2DOpenSimplexNoise - 5863.16953ms
// 2DSimplexNoise - 4649.350849ms

////////////////////////////////////////////////////////////////
// After removing final
2DOpenSimplexNoise speed: 5724.589568ms
2DOpenSimplexNoise speed: 5842.842763ms
2DOpenSimplexNoise speed: 5804.29675ms
2DOpenSimplexNoise speed: 5665.408102ms
2DSimplexNoise speed: 4581.063116ms
2DSimplexNoise speed: 4530.74752ms
2DSimplexNoise speed: 4590.37899ms
2DSimplexNoise speed: 4504.37333ms

// final seems to make no difference in this code

// Best scenarios in this test
//
// 2DOpenSimplexNoise - 5665.408102ms
// 2DSimplexNoise - 4504.37333ms

// Worst scenarios in this test
//
// 2DOpenSimplexNoise - 5842.842763ms
// 2DSimplexNoise - 4590.37899ms
////////////////////////////////////////////////////////////////

code:

public class SimplexNoisePerformanceTests {

	private static int iterations = 100000000;
	private static double x = 0.5447734756785486781d;
	private static double y = 0.4923141242323442d;
	
	public @Test void simplexNoise() {
		final double[] result = new double[iterations];
		final long start = System.nanoTime();
		for (int i = 0; i < iterations; i++)
			result[i] = SimplexNoise.noise(i*x, i*y);
		long end = System.nanoTime() - start;
		System.out.println("2DSimplexNoise speed: "+(end/1000000d)+"ms");
	}
	
	public @Test void openSimplexNoise() {
		final double[] result = new double[iterations];
		final OpenSimplexNoise simplex = new OpenSimplexNoise();
		long start = System.nanoTime();
		for (int i = 0; i < iterations; i++)
			result[i] = simplex.eval(i*x, i*y);
		long end = System.nanoTime() - start;
		System.out.println("2DOpenSimplexNoise speed: "+(end/1000000d)+"ms");
	}
}

@Porama6400
Copy link

Look like it's never touch -1 or 1
it's around -0.8 to +0.8

@Chovanec
Copy link

Chovanec commented Jun 1, 2017

agree with Porama6400 interval should be betwwn -1 to 1, how to change code to get correct values?

@blah1
Copy link

blah1 commented Jun 26, 2017

https://eev.ee/blog/2016/05/29/perlin-noise/
Near the bottom, under "Some properties"

Contrary to popular belief — one espoused even by Ken Perlin! — the output range of Perlin noise is not -1 to 1. It’s ±½√n, where n is the number of dimensions. So a 1-D plane can never extend beyond -½ or ½ (which I bet you could prove if you thought about it), and the familiar 2-D noise is trapped within ±½√2 ≈ ±0.707 (which is also provable by extending the same thought a little further). If you’re using Perlin noise and expecting to span a specific range, make sure to take this into account.

I believe this should explain your issues with the range on OpenSimplex Noise; for 3D noise it would have a amplitude of ~0.866.

@thecjharries
Copy link

What's the reason for shifting seed by 31 while permuting (source)? It seems like, for positive or negative seed, it would just shift the input up by 31, which could be taken care of in the LCG. I spent a decent amount of time researching that, and I couldn't find anything. Does it provide an extra layer of randomness on the off-chance the LCG aligns perfectly with the denominator?

@jearmstrong21
Copy link

I am doing eval(x,y,z,0) (4d noise with w=0) and it gives a range of about:

-0.6512914, 0.6200971
-0.77198315, 0.7699929
-0.6705122, 0.68826705

This is in a sample range of 16x256x16x0, or at point (x,y,z) the noise is eval(x,y,z,0).

Shouldnt it be +-(1/2)sqrt(4) = +-(1/2)2 = +-1?

@s5bug
Copy link

s5bug commented Oct 7, 2018

@KdotJPG Please explain what all the different constants mean, how you got to them, and why this code can't be generalized to n dimensions instead of just 2, 3, and 4. I want to write my own implementation in pure scala but this code is just a huge monster to tackle I can't really do it without explanation of the algorithm.

@cjburkey01
Copy link

@KdotJPG Please explain what all the different constants mean, how you got to them, and why this code can't be generalized to n dimensions instead of just 2, 3, and 4. I want to write my own implementation in pure scala but this code is just a huge monster to tackle I can't really do it without explanation of the algorithm.

The actual paper is here, but it requires some higher level mathematics to understand: http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf

OpenSimplex Noise, according to This Wikipedia Page, is slightly different in its implementation, though, in that:

  • It uses a stretched simplectic honeycomb instead of a hypercubic honeycomb
  • OpenSimplex noise uses a larger kernel size than Simplex noise, which results in slightly lost performance.

@nonchip
Copy link

nonchip commented Mar 23, 2019

@cjburkey01

the paper you linked explains perlin vs simplex, not opensimplex.

@Manuel3115
Copy link

Very good code thanks ! Only 1 question : how do you decrease the amplitude of the noise ? I'm getting a lot of big spikes in the values. I'd rather have bigger clusters of similar values. Thank you !

@benlmyers
Copy link

This is amazing!

@FoxSamu
Copy link

FoxSamu commented Jun 16, 2020

Amazing! I use a modified version of this implementation in a small procedural terrain generator library: https://github.com/RedGalaxySW/Noise. Thanks a lot!

@MarcoCiaramella
Copy link

Thanks!
I made an Android library version from the latest revision
https://github.com/MarcoCiaramella/OpenSimplexNoise

@KdotJPG
Copy link
Author

KdotJPG commented Jul 28, 2020

@MarcoCiaramella Very cool! Out of curiosity, why not use the optimized version or even OpenSimplex2S? Either way I like that you continued with the public domain license.

@MarcoCiaramella
Copy link

@KdotJPG ok good thanks for your advice, I will do that!

@MarcoCiaramella
Copy link

@MarcoCiaramella
Copy link

@Pentagonist
Copy link

Thank you for this code!

@erik-alm
Copy link

agree with Porama6400 interval should be betwwn -1 to 1, how to change code to get correct values?

Normalization? (or even split normalization depending on above or below 0).

Isn't this supposed to be "random" from the seed? In that case it will never be -1 → 1 unless you normalize it to be that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment