diff --git a/common/src/main/java/com/dfsek/terra/api/math/MathUtil.java b/common/src/main/java/com/dfsek/terra/api/math/MathUtil.java index b2313758b..b1a5aa687 100644 --- a/common/src/main/java/com/dfsek/terra/api/math/MathUtil.java +++ b/common/src/main/java/com/dfsek/terra/api/math/MathUtil.java @@ -55,4 +55,31 @@ public class MathUtil { } return hash; } + + /** + * Compute binary logarithm + * + * @param bits Input + * @return Binary logarithm + */ + public static int binlog(int bits) { + int log = 0; + if((bits & 0xffff0000) != 0) { + bits >>>= 16; + log = 16; + } + if(bits >= 256) { + bits >>>= 8; + log += 8; + } + if(bits >= 16) { + bits >>>= 4; + log += 4; + } + if(bits >= 4) { + bits >>>= 2; + log += 2; + } + return log + (bits >>> 1); + } } diff --git a/common/src/main/java/com/dfsek/terra/api/math/interpolation/ChunkInterpolator3.java b/common/src/main/java/com/dfsek/terra/api/math/interpolation/ChunkInterpolator3.java index 048e61c64..171c54fa9 100644 --- a/common/src/main/java/com/dfsek/terra/api/math/interpolation/ChunkInterpolator3.java +++ b/common/src/main/java/com/dfsek/terra/api/math/interpolation/ChunkInterpolator3.java @@ -15,6 +15,7 @@ public class ChunkInterpolator3 { private final Generator[][] gens = new Generator[7][7]; private final boolean[][] needsBiomeInterp = new boolean[5][5]; private final double[][][] noiseStorage = new double[7][7][65]; + private final int smooth; /** * Instantiates a 3D ChunkInterpolator at a pair of chunk coordinates, with a BiomeGrid and FastNoiseLite instance. @@ -23,14 +24,15 @@ public class ChunkInterpolator3 { * @param chunkZ Z coordinate of the chunk. * @param grid BiomeGrid to use for noise fetching. */ - public ChunkInterpolator3(World w, int chunkX, int chunkZ, BiomeGrid grid) { + public ChunkInterpolator3(World w, int chunkX, int chunkZ, BiomeGrid grid, int smooth) { int xOrigin = chunkX << 4; int zOrigin = chunkZ << 4; + this.smooth = smooth; for(int x = -1; x < 6; x++) { for(int z = -1; z < 6; z++) { - gens[x + 1][z + 1] = grid.getBiome(xOrigin + (x << 2), zOrigin + (z << 2), GenerationPhase.BASE).getGenerator(); + gens[x + 1][z + 1] = grid.getBiome(xOrigin + (x * smooth), zOrigin + (z * smooth), GenerationPhase.BASE).getGenerator(); } } for(int x = 0; x < 5; x++) { @@ -42,7 +44,7 @@ public class ChunkInterpolator3 { for(byte x = -1; x < 6; x++) { for(byte z = -1; z < 6; z++) { for(int y = 0; y < 65; y++) { - noiseStorage[x + 1][z + 1][y] = gens[x + 1][z + 1].getNoise(w, (x << 2) + xOrigin, y << 2, (z << 2) + zOrigin); + noiseStorage[x + 1][z + 1][y] = gens[x + 1][z + 1].getNoise(w, (x * smooth) + xOrigin, y << 2, (z * smooth) + zOrigin); } } } @@ -64,43 +66,40 @@ public class ChunkInterpolator3 { } } + private static int reRange(int value, int high) { + return FastMath.max(FastMath.min(value, high), 0); + } + private boolean compareGens(int x, int z) { Generator comp = gens[x][z]; - if(!comp.equals(gens[x+1][z])) return true; + if(!comp.equals(gens[x + 1][z])) return true; - if(!comp.equals(gens[x][z+1])) return true; + if(!comp.equals(gens[x][z + 1])) return true; - if(!comp.equals(gens[x-1][z])) return true; + if(!comp.equals(gens[x - 1][z])) return true; - if(!comp.equals(gens[x][z-1])) return true; + if(!comp.equals(gens[x][z - 1])) return true; - if(!comp.equals(gens[x+1][z+1])) return true; + if(!comp.equals(gens[x + 1][z + 1])) return true; - if(!comp.equals(gens[x-1][z-1])) return true; + if(!comp.equals(gens[x - 1][z - 1])) return true; - if(!comp.equals(gens[x+1][z-1])) return true; + if(!comp.equals(gens[x + 1][z - 1])) return true; return !comp.equals(gens[x - 1][z + 1]); } private double biomeAvg(int x, int y, int z) { - if(needsBiomeInterp[x][z]) return (noiseStorage[x + 2][z + 1][y] - + noiseStorage[x][z + 1][y] - + noiseStorage[x + 1][z + 2][y] - + noiseStorage[x + 1][z][y] - + noiseStorage[x][z][y] - + noiseStorage[x + 2][z + 2][y] - + noiseStorage[x + 2][z][y] - + noiseStorage[x][z + 2][y] - + noiseStorage[x + 1][z + 1][y] - ) / 9D; - else { - if(gens[x+1][z+1].useMinimalInterpolation()) return noiseStorage[x+1][z+1][y]; - else return (noiseStorage[x + 2][z + 1][y] - + noiseStorage[x][z + 1][y] - + noiseStorage[x + 1][z + 2][y] - + noiseStorage[x + 1][z][y] - + noiseStorage[x+1][z+1][y]) / 5D; + if(needsBiomeInterp[x][z]) { + double t = 0d; + for(int xi = 0; xi <= 2; xi++) { + for(int zi = 0; zi <= 2; zi++) { + t += noiseStorage[x + xi][z + zi][y]; + } + } + return t / 9d; + } else { + return noiseStorage[x + 1][z + 1][y]; } } @@ -112,10 +111,6 @@ public class ChunkInterpolator3 { * @return double - The interpolated noise at the coordinates. */ public double getNoise(double x, double y, double z) { - return interpGrid[reRange(((int) x) / 4, 3)][reRange(((int) y) / 4, 63)][reRange(((int) z) / 4, 3)].trilerp((x % 4) / 4, (y % 4) / 4, (z % 4) / 4); - } - - private static int reRange(int value, int high) { - return FastMath.max(FastMath.min(value, high), 0); + return interpGrid[reRange(((int) x) / smooth, 3)][reRange(((int) y) / 4, 63)][reRange(((int) z) / smooth, 3)].trilerp((x % smooth) / smooth, (y % 4) / 4, (z % smooth) / smooth); } } diff --git a/common/src/main/java/com/dfsek/terra/api/world/biome/Generator.java b/common/src/main/java/com/dfsek/terra/api/world/biome/Generator.java index 5f3336348..6c844d7a0 100644 --- a/common/src/main/java/com/dfsek/terra/api/world/biome/Generator.java +++ b/common/src/main/java/com/dfsek/terra/api/world/biome/Generator.java @@ -22,10 +22,4 @@ public interface Generator { */ Palette getPalette(int y); - /** - * Returns true if the biome should be interpolated just once, false to use advanced interpolation + blending. - * - * @return Whether biome should use minimal interpolation - */ - boolean useMinimalInterpolation(); } diff --git a/common/src/main/java/com/dfsek/terra/config/builder/GeneratorBuilder.java b/common/src/main/java/com/dfsek/terra/config/builder/GeneratorBuilder.java index d63460942..42cf84ac6 100644 --- a/common/src/main/java/com/dfsek/terra/config/builder/GeneratorBuilder.java +++ b/common/src/main/java/com/dfsek/terra/config/builder/GeneratorBuilder.java @@ -27,8 +27,9 @@ public class GeneratorBuilder { private boolean interpolateElevation; + public WorldGenerator build(long seed) { - return gens.computeIfAbsent(seed, k -> new WorldGenerator(seed, noiseEquation, elevationEquation, varScope, noiseBuilderMap, palettes, slantPalettes, preventInterpolation, interpolateElevation)); + return gens.computeIfAbsent(seed, k -> new WorldGenerator(seed, noiseEquation, elevationEquation, varScope, noiseBuilderMap, palettes, slantPalettes, interpolateElevation)); } public String getNoiseEquation() { diff --git a/common/src/main/java/com/dfsek/terra/generation/ElevationInterpolator.java b/common/src/main/java/com/dfsek/terra/generation/ElevationInterpolator.java index ef66f17dd..2de0df41a 100644 --- a/common/src/main/java/com/dfsek/terra/generation/ElevationInterpolator.java +++ b/common/src/main/java/com/dfsek/terra/generation/ElevationInterpolator.java @@ -4,6 +4,7 @@ import com.dfsek.terra.api.math.interpolation.Interpolator; import com.dfsek.terra.api.world.generation.GenerationPhase; import com.dfsek.terra.biome.grid.master.TerraBiomeGrid; import com.dfsek.terra.generation.config.WorldGenerator; +import net.jafama.FastMath; public class ElevationInterpolator { private final WorldGenerator[][] gens; @@ -12,17 +13,20 @@ public class ElevationInterpolator { private final int zOrigin; private final TerraBiomeGrid grid; private final int smooth; + private final int pow; public ElevationInterpolator(int chunkX, int chunkZ, TerraBiomeGrid grid, int smooth) { this.xOrigin = chunkX << 4; this.zOrigin = chunkZ << 4; this.grid = grid; this.smooth = smooth; - this.gens = new WorldGenerator[10][10]; + this.pow = FastMath.log2(smooth); + this.gens = new WorldGenerator[6 + 2 * pow][6 + 2 * pow]; - for(int x = -2; x < 8; x++) { - for(int z = -2; z < 8; z++) { - gens[x + 2][z + 2] = (WorldGenerator) grid.getBiome(xOrigin + (x * smooth), zOrigin + (z * smooth), GenerationPhase.BASE).getGenerator(); + + for(int x = -pow; x < 6 + pow; x++) { + for(int z = -pow; z < 6 + pow; z++) { + gens[x + pow][z + pow] = (WorldGenerator) grid.getBiome(xOrigin + (x * smooth), zOrigin + (z * smooth), GenerationPhase.BASE).getGenerator(); } } @@ -45,12 +49,12 @@ public class ElevationInterpolator { } private WorldGenerator getStoredGen(int x, int z) { - return gens[x + 2][z + 2]; + return gens[x + pow][z + pow]; } private boolean compareGens(int x, int z, WorldGenerator comp) { - for(int xi = x - 2; xi <= x + 2; xi++) { - for(int zi = z - 2; zi <= z + 2; zi++) { + for(int xi = x - pow; xi <= x + pow; xi++) { + for(int zi = z - pow; zi <= z + pow; zi++) { if(!comp.equals(getStoredGen(xi, zi))) return true; } } diff --git a/common/src/main/java/com/dfsek/terra/generation/MasterChunkGenerator.java b/common/src/main/java/com/dfsek/terra/generation/MasterChunkGenerator.java index fe1bb641a..7365a5571 100644 --- a/common/src/main/java/com/dfsek/terra/generation/MasterChunkGenerator.java +++ b/common/src/main/java/com/dfsek/terra/generation/MasterChunkGenerator.java @@ -88,7 +88,7 @@ public class MasterChunkGenerator implements TerraChunkGenerator { try(ProfileFuture ignore = tw.getProfiler().measure("TotalChunkGenTime")) { ChunkInterpolator3 interp; try(ProfileFuture ignored = tw.getProfiler().measure("ChunkBaseGenTime")) { - interp = new ChunkInterpolator3(world, chunkX, chunkZ, tw.getGrid()); + interp = new ChunkInterpolator3(world, chunkX, chunkZ, tw.getGrid(), 16); if(!tw.isSafe()) return chunk; int xOrig = (chunkX << 4); @@ -96,7 +96,7 @@ public class MasterChunkGenerator implements TerraChunkGenerator { ElevationInterpolator elevationInterpolator; try(ProfileFuture ignored1 = tw.getProfiler().measure("ElevationTime")) { - elevationInterpolator = new ElevationInterpolator(chunkX, chunkZ, tw.getGrid(), 8); + elevationInterpolator = new ElevationInterpolator(chunkX, chunkZ, tw.getGrid(), 4); } Sampler sampler = new Sampler(interp, elevationInterpolator); diff --git a/common/src/main/java/com/dfsek/terra/generation/config/WorldGenerator.java b/common/src/main/java/com/dfsek/terra/generation/config/WorldGenerator.java index 5c99c61d0..05f5f331a 100644 --- a/common/src/main/java/com/dfsek/terra/generation/config/WorldGenerator.java +++ b/common/src/main/java/com/dfsek/terra/generation/config/WorldGenerator.java @@ -22,7 +22,6 @@ public class WorldGenerator implements Generator { @SuppressWarnings({"unchecked", "rawtypes", "RedundantSuppression"}) private final PaletteHolder slantPalettes; - private final boolean preventSmooth; private final Expression noiseExp; private final Expression elevationExp; private final Variable xVar; @@ -32,7 +31,7 @@ public class WorldGenerator implements Generator { private final Variable elevationZVar; private final boolean elevationInterpolation; - public WorldGenerator(long seed, String equation, String elevateEquation, Scope vScope, Map noiseBuilders, PaletteHolder palettes, PaletteHolder slantPalettes, boolean preventSmooth, boolean elevationInterpolation) { + public WorldGenerator(long seed, String equation, String elevateEquation, Scope vScope, Map noiseBuilders, PaletteHolder palettes, PaletteHolder slantPalettes, boolean elevationInterpolation) { Parser p = new Parser(); p.registerFunction("rand", new RandomFunction()); Parser ep = new Parser(); @@ -44,8 +43,6 @@ public class WorldGenerator implements Generator { zVar = s.create("z"); s.create("seed").setValue(seed); - this.preventSmooth = preventSmooth; - this.palettes = palettes; this.slantPalettes = slantPalettes; @@ -110,11 +107,6 @@ public class WorldGenerator implements Generator { } - @Override - public boolean useMinimalInterpolation() { - return preventSmooth; - } - public boolean interpolateElevation() { return elevationInterpolation; }