diff --git a/assets/Data/game/biomes.json b/assets/Data/game/biomes.json new file mode 100644 index 00000000..ab93f97f --- /dev/null +++ b/assets/Data/game/biomes.json @@ -0,0 +1,45 @@ +{ + "biomes": [ + { + "id": "sky", + "displayName": "Sky", + "isAerial": true, + "isSurface": false, + "isSubterranean": false, + "regions": [ + { + "frequency": 1.0, + "baseFloorVoxel": 0, + "floorVariants": [], + "foliageDescription": [] + } + ] + }, + { + "id": "plains", + "displayName": "Plains", + "isAerial": false, + "isSurface": true, + "isSubterranean": false, + "regions": [ + { + "frequency": 1.0, + "baseFloorVoxel": 1, + "floorVariants": [ + { + "voxelId": 2, + "frequency": 1.0, + "dispersion": 1.0, + "priority": 1.0 + } + ], + "foliageDescription": [ + ] + } + ] + } + ], + "files": [ + + ] +} \ No newline at end of file diff --git a/docs/src/architecture/architectureindex.md b/docs/src/architecture/architectureindex.md index b723a330..dde27d0b 100644 --- a/docs/src/architecture/architectureindex.md +++ b/docs/src/architecture/architectureindex.md @@ -19,6 +19,7 @@ - @subpage server - @subpage indexrendering - @subpage entitytypesindex +- @subpage worldgenerationindex # What is this section diff --git a/docs/src/architecture/generation/biomeselection.md b/docs/src/architecture/generation/biomeselection.md new file mode 100644 index 00000000..8d86bc94 --- /dev/null +++ b/docs/src/architecture/generation/biomeselection.md @@ -0,0 +1,19 @@ +@page biomeselection Biome Selection + + +Details on how biome selection works + +The world is segmented into "zones" via voronoi partitioning + +These zones have themes attached to them + +The themes filter the biomes that can be picked from the overall biome pool + +The biomes are also filtered by terrain attributes (elevation, moisture, temperature, magic count, etc) + +The biome pool is then mapped to regions which are indexed into based on noise functions + +Once the biome is selected, a fine grain surface value is calculated + +All other generation proceeds based on the specific biome selected from the pool via noise + diff --git a/docs/src/architecture/generation/worldgenerationindex.md b/docs/src/architecture/generation/worldgenerationindex.md new file mode 100644 index 00000000..10a1b39f --- /dev/null +++ b/docs/src/architecture/generation/worldgenerationindex.md @@ -0,0 +1,4 @@ +@page worldgenerationindex World Generation + +[TOC] +- @subpage biomeselection \ No newline at end of file diff --git a/docs/src/architecture/worldstorage/macroWorldPartitioning.md b/docs/src/architecture/worldstorage/macroWorldPartitioning.md index a157bbea..d6a9de7f 100644 --- a/docs/src/architecture/worldstorage/macroWorldPartitioning.md +++ b/docs/src/architecture/worldstorage/macroWorldPartitioning.md @@ -7,9 +7,9 @@ Different terrain levels: -Sky 1: 12000m - 14000m +Sky 3: 12000m - 14000m -Sky 1: 10000m - 12000m +Sky 2: 10000m - 12000m Sky 1: 8000m - 10000m diff --git a/docs/src/architecture/worldstorage/worldstorage.md b/docs/src/architecture/worldstorage/worldstorage.md index d359709d..cc7f17ba 100644 --- a/docs/src/architecture/worldstorage/worldstorage.md +++ b/docs/src/architecture/worldstorage/worldstorage.md @@ -21,5 +21,10 @@ Types of data we need: - magic (?) +Also stored to disk is the zone map +This is stored in the format of a pixel map that maps pixels to zone IDs +These IDs map to a list of zone definitions + + # In Memory diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index d2685c0c..9d055429 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1011,6 +1011,9 @@ Bug fixes Debug - Draw all bones with orientations +Biome description enhancements + - Weather description + Would be nice to be able to cut clients that stream their logs to my server Refactor render flags diff --git a/src/main/java/electrosphere/game/data/Config.java b/src/main/java/electrosphere/game/data/Config.java index 46c776b4..fd0e9089 100644 --- a/src/main/java/electrosphere/game/data/Config.java +++ b/src/main/java/electrosphere/game/data/Config.java @@ -4,6 +4,7 @@ import java.util.LinkedList; import java.util.List; import electrosphere.game.data.audio.SurfaceAudioCollection; +import electrosphere.game.data.biome.BiomeTypeMap; import electrosphere.game.data.common.CommonEntityLoader; import electrosphere.game.data.common.CommonEntityMap; import electrosphere.game.data.common.CommonEntityType; @@ -56,6 +57,11 @@ public class Config { * The crafting recipe map */ RecipeDataMap recipeMap; + + /** + * The biome map + */ + BiomeTypeMap biomeMap; /** * Loads the default data @@ -76,6 +82,7 @@ public class Config { config.projectileTypeHolder.init(); config.unitLoader = UnitLoader.create(FileUtils.loadObjectFromAssetPath("Data/game/units/units.json", UnitDefinitionFile.class)); config.recipeMap = RecipeDataMap.loadRecipeFiles("Data/game/recipes.json"); + config.biomeMap = BiomeTypeMap.loadBiomeFile("Data/game/biomes.json"); //validate ConfigValidator.valdiate(config); @@ -260,5 +267,13 @@ public class Config { public RecipeDataMap getRecipeMap(){ return recipeMap; } + + /** + * Gets the biome map + * @return The biome map + */ + public BiomeTypeMap getBiomeMap(){ + return biomeMap; + } } diff --git a/src/main/java/electrosphere/game/data/biome/BiomeData.java b/src/main/java/electrosphere/game/data/biome/BiomeData.java new file mode 100644 index 00000000..4eb5d50a --- /dev/null +++ b/src/main/java/electrosphere/game/data/biome/BiomeData.java @@ -0,0 +1,90 @@ +package electrosphere.game.data.biome; + +import java.util.List; + +/** + * Data about a given biome + */ +public class BiomeData { + + /** + * The id of the biome + */ + String id; + + /** + * The display name of the biome + */ + String displayName; + + /** + * The regions available to the biome + */ + List regions; + + /** + * True if this region applies above the surface + */ + Boolean isAerial; + + /** + * True if this region applies to the surface + */ + Boolean isSurface; + + /** + * True if this region applies below the surface + */ + Boolean isSubterranean; + + + + /** + * Gets the id of the biome + * @return The id of the biome + */ + public String getId() { + return id; + } + + /** + * Gets the display name of the biome + * @return The display name + */ + public String getDisplayName() { + return displayName; + } + + /** + * Gets the regions of the biome + * @return The regions + */ + public List getRegions(){ + return regions; + } + + /** + * Gets whether the biome is a surface biome or not + * @return true if is a surface biome, false otherwise + */ + public Boolean isSurface(){ + return isSurface; + } + + /** + * Gets whether the biome is an aerial biome or not + * @return true if is an aerial biome, false otherwise + */ + public Boolean isAerial(){ + return isAerial; + } + + /** + * Gets whether the biome is a subterreanean biome or not + * @return true if is a subterreanean biome, false otherwise + */ + public Boolean isSubterranean(){ + return isSubterranean; + } + +} diff --git a/src/main/java/electrosphere/game/data/biome/BiomeDataFile.java b/src/main/java/electrosphere/game/data/biome/BiomeDataFile.java new file mode 100644 index 00000000..9c3db840 --- /dev/null +++ b/src/main/java/electrosphere/game/data/biome/BiomeDataFile.java @@ -0,0 +1,52 @@ +package electrosphere.game.data.biome; + +import java.util.List; + +/** + * The data file containing all biome data + */ +public class BiomeDataFile { + + /** + * The biome data in this file + */ + List biomes; + + /** + * All child files of this one + */ + List files; + + /** + * Gets the biome data in this file + * @return The biome data in this file + */ + public List getBiomes() { + return biomes; + } + + /** + * Sets the biome data in this file + * @param biomes The biome data in this file + */ + public void setBiomes(List biomes) { + this.biomes = biomes; + } + + /** + * Gets all child files of this one + * @return All child files of this one + */ + public List getFiles() { + return files; + } + + /** + * Sets all child files of this one + * @param files All child files of this one + */ + public void setFiles(List files) { + this.files = files; + } + +} diff --git a/src/main/java/electrosphere/game/data/biome/BiomeFloorElement.java b/src/main/java/electrosphere/game/data/biome/BiomeFloorElement.java new file mode 100644 index 00000000..d34faa4c --- /dev/null +++ b/src/main/java/electrosphere/game/data/biome/BiomeFloorElement.java @@ -0,0 +1,28 @@ +package electrosphere.game.data.biome; + +/** + * Describes how a given voxel type may be used to populate the floor of the biome + */ +public class BiomeFloorElement { + + /** + * The id of the voxel type for this element in particular + */ + int voxelId; + + /** + * The frequency of this element in particular + */ + Double frequency; + + /** + * The scale of the noise used to generate this element + */ + Double dispersion; + + /** + * The priority of this floor element in particular + */ + Double priority; + +} diff --git a/src/main/java/electrosphere/game/data/biome/BiomeFoliageDescription.java b/src/main/java/electrosphere/game/data/biome/BiomeFoliageDescription.java new file mode 100644 index 00000000..9d043a9a --- /dev/null +++ b/src/main/java/electrosphere/game/data/biome/BiomeFoliageDescription.java @@ -0,0 +1,30 @@ +package electrosphere.game.data.biome; + +import java.util.List; + +/** + * Describes behavior for spawning a specific type of foliage in the biome + */ +public class BiomeFoliageDescription { + + /** + * The liust of entity IDs of this foliage type in particular + */ + List entityIDs; + + /** + * The frequency of this element in particular + */ + Double frequency; + + /** + * The scale of the noise used to generate this element + */ + Double dispersion; + + /** + * The priority of this floor element in particular + */ + Double priority; + +} diff --git a/src/main/java/electrosphere/game/data/biome/BiomeRegion.java b/src/main/java/electrosphere/game/data/biome/BiomeRegion.java new file mode 100644 index 00000000..0ef2b982 --- /dev/null +++ b/src/main/java/electrosphere/game/data/biome/BiomeRegion.java @@ -0,0 +1,43 @@ +package electrosphere.game.data.biome; + +import java.util.List; + +/** + * A region type that can generate inside a biome + * Examples: + * A field + * A natural trail + * A grove of trees + * A field of stalactites + * + * The idea of having regions is to allow spatially isolating different generation components within a larger biome. + * The prime example of this is generating a large tree within a larger forest biome. + * You might want to spatially separate the tree so that you can apply special generation rules around it in particular. + * IE, generate roots, but only around the tree. + */ +public class BiomeRegion { + + /** + * The frequency of this region within the biome + */ + Double frequency; + + /** + * The base floor voxel + * This is populated by default, then overridden if any of the floor variants trigger/supercede it + */ + Integer baseFloorVoxel; + + /** + * The different floor elements + */ + List floorVariants; + + /** + * The list of foliage descriptions available to this biome type + */ + List foliageDescriptions; + + + +} diff --git a/src/main/java/electrosphere/game/data/biome/BiomeTypeMap.java b/src/main/java/electrosphere/game/data/biome/BiomeTypeMap.java new file mode 100644 index 00000000..283ac246 --- /dev/null +++ b/src/main/java/electrosphere/game/data/biome/BiomeTypeMap.java @@ -0,0 +1,141 @@ +package electrosphere.game.data.biome; + +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import electrosphere.util.FileUtils; + +/** + * Structure for efficiently accessing biome data + */ +public class BiomeTypeMap { + + /** + * The map of biome id -> biome data + */ + Map idBiomeMap = new HashMap(); + + /** + * The list of surface biomes + */ + List surfaceBiomes = new LinkedList(); + + /** + * The list of sky biomes + */ + List skyBiomes = new LinkedList(); + + /** + * The list of subterranean biomes + */ + List subterraneanBiomes = new LinkedList(); + + + /** + * Adds biome data to the loader + * @param name The id of the biome + * @param type The biome data + */ + public void putBiome(String id, BiomeData biome){ + idBiomeMap.put(id,biome); + if(biome.isSurface()){ + this.surfaceBiomes.add(biome); + } + if(biome.isAerial()){ + this.skyBiomes.add(biome); + } + if(biome.isSubterranean()){ + this.subterraneanBiomes.add(biome); + } + } + + /** + * Gets biome data from the id of the biome + * @param id The id of the biome + * @return The biome data if it exists, null otherwise + */ + public BiomeData getType(String id){ + return idBiomeMap.get(id); + } + + /** + * Gets the collection of all biome data + * @return the collection of all biome data + */ + public Collection getTypes(){ + return idBiomeMap.values(); + } + + /** + * Gets the set of all biome data id's stored in the loader + * @return the set of all biome data ids + */ + public Set getTypeIds(){ + return idBiomeMap.keySet(); + } + + /** + * Reads a child biome defintion file + * @param filename The filename + * @return The list of biomes in the file + */ + static List recursiveReadBiomeLoader(String filename){ + List typeList = new LinkedList(); + BiomeDataFile loaderFile = FileUtils.loadObjectFromAssetPath(filename, BiomeDataFile.class); + //push the types from this file + for(BiomeData type : loaderFile.getBiomes()){ + typeList.add(type); + } + //push types from any other files + for(String filepath : loaderFile.getFiles()){ + List parsedTypeList = recursiveReadBiomeLoader(filepath); + for(BiomeData type : parsedTypeList){ + typeList.add(type); + } + } + return typeList; + } + + /** + * Loads all biome definition files recursively + * @param initialPath The initial path to recurse from + * @return The biome defintion interface + */ + public static BiomeTypeMap loadBiomeFile(String initialPath) { + BiomeTypeMap rVal = new BiomeTypeMap(); + List typeList = recursiveReadBiomeLoader(initialPath); + for(BiomeData biome : typeList){ + rVal.putBiome(biome.getId(), biome); + } + return rVal; + } + + /** + * Gets the list of surface biomes + * @return The list of surface biomes + */ + public List getSurfaceBiomes(){ + return this.surfaceBiomes; + } + + /** + * Gets the list of sky biomes + * @return The list of sky biomes + */ + public List getSkyBiomes(){ + return this.skyBiomes; + } + + /** + * Gets the list of subterranean biomes + * @return The list of subterranean biomes + */ + public List getSubterraneanBiomes(){ + return this.subterraneanBiomes; + } + +} diff --git a/src/main/java/electrosphere/server/terrain/models/TerrainModel.java b/src/main/java/electrosphere/server/terrain/models/TerrainModel.java index fc2889a8..60bf3715 100644 --- a/src/main/java/electrosphere/server/terrain/models/TerrainModel.java +++ b/src/main/java/electrosphere/server/terrain/models/TerrainModel.java @@ -3,6 +3,8 @@ package electrosphere.server.terrain.models; import java.util.HashMap; import java.util.Map; +import electrosphere.engine.Globals; +import electrosphere.game.data.biome.BiomeData; import electrosphere.util.annotation.Exclude; /** @@ -456,5 +458,16 @@ public class TerrainModel { public void setElevationArray(float[][] elevation){ this.elevation = elevation; } + + /** + * Gets the biome for a given world position + * @param worldX The world X + * @param worldY The world Y + * @param worldZ The world Z + * @return The biome + */ + public BiomeData getBiome(int worldX, int worldY, int worldZ){ + return Globals.gameConfigCurrent.getBiomeMap().getTypes().iterator().next(); + } } diff --git a/src/main/java/electrosphere/util/noise/OpenSimplex2S.java b/src/main/java/electrosphere/util/noise/OpenSimplex2S.java new file mode 100644 index 00000000..dc7c113a --- /dev/null +++ b/src/main/java/electrosphere/util/noise/OpenSimplex2S.java @@ -0,0 +1,1147 @@ +package electrosphere.util.noise; + +/** + * 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; + } + } +}