basic noise carver implementation

This commit is contained in:
dfsek
2021-01-24 21:14:21 -07:00
parent bd4812ef2b
commit dca0891e00
13 changed files with 181 additions and 78 deletions
@@ -1,5 +1,8 @@
package com.dfsek.terra.api.math.noise.samplers; package com.dfsek.terra.api.math.noise.samplers;
/**
* Sampler implementation that returns a constant.
*/
public class ConstantSampler implements NoiseSampler { public class ConstantSampler implements NoiseSampler {
private final double constant; private final double constant;
@@ -1351,6 +1351,8 @@ public class FastNoiseLite implements NoiseSampler {
double distance0 = Double.MAX_VALUE; double distance0 = Double.MAX_VALUE;
double distance1 = Double.MAX_VALUE; double distance1 = Double.MAX_VALUE;
double distance2 = Double.MAX_VALUE;
int closestHash = 0; int closestHash = 0;
double cellularJitter = 0.43701595 * mCellularJitterModifier; double cellularJitter = 0.43701595 * mCellularJitterModifier;
@@ -1382,6 +1384,11 @@ public class FastNoiseLite implements NoiseSampler {
closestHash = hash; closestHash = hash;
center.setX((xi + RAND_VECS_2D[idx] * cellularJitter) / mFrequency); center.setX((xi + RAND_VECS_2D[idx] * cellularJitter) / mFrequency);
center.setZ((yi + RAND_VECS_2D[idx | 1] * cellularJitter) / mFrequency); center.setZ((yi + RAND_VECS_2D[idx | 1] * cellularJitter) / mFrequency);
} else if(newDistance < distance1) {
distance2 = distance1;
distance1 = newDistance;
} else if(newDistance < distance2) {
distance2 = newDistance;
} }
yPrimed += PRIME_Y; yPrimed += PRIME_Y;
} }
@@ -1407,6 +1414,11 @@ public class FastNoiseLite implements NoiseSampler {
closestHash = hash; closestHash = hash;
center.setX((xi + RAND_VECS_2D[idx] * cellularJitter) / mFrequency); center.setX((xi + RAND_VECS_2D[idx] * cellularJitter) / mFrequency);
center.setZ((yi + RAND_VECS_2D[idx | 1] * cellularJitter) / mFrequency); center.setZ((yi + RAND_VECS_2D[idx | 1] * cellularJitter) / mFrequency);
} else if(newDistance < distance1) {
distance2 = distance1;
distance1 = newDistance;
} else if(newDistance < distance2) {
distance2 = newDistance;
} }
yPrimed += PRIME_Y; yPrimed += PRIME_Y;
} }
@@ -1432,6 +1444,11 @@ public class FastNoiseLite implements NoiseSampler {
closestHash = hash; closestHash = hash;
center.setX((xi + RAND_VECS_2D[idx] * cellularJitter) / mFrequency); center.setX((xi + RAND_VECS_2D[idx] * cellularJitter) / mFrequency);
center.setZ((yi + RAND_VECS_2D[idx | 1] * cellularJitter) / mFrequency); center.setZ((yi + RAND_VECS_2D[idx | 1] * cellularJitter) / mFrequency);
} else if(newDistance < distance1) {
distance2 = distance1;
distance1 = newDistance;
} else if(newDistance < distance2) {
distance2 = newDistance;
} }
yPrimed += PRIME_Y; yPrimed += PRIME_Y;
} }
@@ -1464,6 +1481,8 @@ public class FastNoiseLite implements NoiseSampler {
return distance0 / distance1 - 1; return distance0 / distance1 - 1;
case NoiseLookup: case NoiseLookup:
return cellularNoiseLookup.getNoise(center.getX(), center.getZ()); return cellularNoiseLookup.getNoise(center.getX(), center.getZ());
case Distance3Div:
return distance0 / distance2 - 1;
default: default:
return 0; return 0;
} }
@@ -1477,6 +1496,7 @@ public class FastNoiseLite implements NoiseSampler {
double distance0 = Double.MAX_VALUE; double distance0 = Double.MAX_VALUE;
double distance1 = Double.MAX_VALUE; double distance1 = Double.MAX_VALUE;
double distance2 = Double.MAX_VALUE;
int closestHash = 0; int closestHash = 0;
double cellularJitter = 0.39614353 * mCellularJitterModifier; double cellularJitter = 0.39614353 * mCellularJitterModifier;
@@ -1506,13 +1526,17 @@ public class FastNoiseLite implements NoiseSampler {
double newDistance = vecX * vecX + vecY * vecY + vecZ * vecZ; double newDistance = vecX * vecX + vecY * vecY + vecZ * vecZ;
distance1 = fastMax(fastMin(distance1, newDistance), distance0);
if(newDistance < distance0) { if(newDistance < distance0) {
distance0 = newDistance; distance0 = newDistance;
closestHash = hash; closestHash = hash;
center.setX((xi + RAND_VECS_3D[idx] * cellularJitter) / mFrequency); center.setX((xi + RAND_VECS_3D[idx] * cellularJitter) / mFrequency);
center.setY((yi + RAND_VECS_3D[idx | 1] * cellularJitter) / mFrequency); center.setY((yi + RAND_VECS_3D[idx | 1] * cellularJitter) / mFrequency);
center.setZ((zi + RAND_VECS_3D[idx | 2] * cellularJitter) / mFrequency); center.setZ((zi + RAND_VECS_3D[idx | 2] * cellularJitter) / mFrequency);
} else if(newDistance < distance1) {
distance2 = distance1;
distance1 = newDistance;
} else if(newDistance < distance2) {
distance2 = newDistance;
} }
zPrimed += PRIME_Z; zPrimed += PRIME_Z;
} }
@@ -1538,13 +1562,17 @@ public class FastNoiseLite implements NoiseSampler {
double newDistance = fastAbs(vecX) + fastAbs(vecY) + fastAbs(vecZ); double newDistance = fastAbs(vecX) + fastAbs(vecY) + fastAbs(vecZ);
distance1 = fastMax(fastMin(distance1, newDistance), distance0);
if(newDistance < distance0) { if(newDistance < distance0) {
distance0 = newDistance; distance0 = newDistance;
closestHash = hash; closestHash = hash;
center.setX((xi + RAND_VECS_3D[idx] * cellularJitter) / mFrequency); center.setX((xi + RAND_VECS_3D[idx] * cellularJitter) / mFrequency);
center.setY((yi + RAND_VECS_3D[idx | 1] * cellularJitter) / mFrequency); center.setY((yi + RAND_VECS_3D[idx | 1] * cellularJitter) / mFrequency);
center.setZ((zi + RAND_VECS_3D[idx | 2] * cellularJitter) / mFrequency); center.setZ((zi + RAND_VECS_3D[idx | 2] * cellularJitter) / mFrequency);
} else if(newDistance < distance1) {
distance2 = distance1;
distance1 = newDistance;
} else if(newDistance < distance2) {
distance2 = newDistance;
} }
zPrimed += PRIME_Z; zPrimed += PRIME_Z;
} }
@@ -1578,6 +1606,11 @@ public class FastNoiseLite implements NoiseSampler {
center.setX((xi + RAND_VECS_3D[idx] * cellularJitter) / mFrequency); center.setX((xi + RAND_VECS_3D[idx] * cellularJitter) / mFrequency);
center.setY((yi + RAND_VECS_3D[idx | 1] * cellularJitter) / mFrequency); center.setY((yi + RAND_VECS_3D[idx | 1] * cellularJitter) / mFrequency);
center.setZ((zi + RAND_VECS_3D[idx | 2] * cellularJitter) / mFrequency); center.setZ((zi + RAND_VECS_3D[idx | 2] * cellularJitter) / mFrequency);
} else if(newDistance < distance1) {
distance2 = distance1;
distance1 = newDistance;
} else if(newDistance < distance2) {
distance2 = newDistance;
} }
zPrimed += PRIME_Z; zPrimed += PRIME_Z;
} }
@@ -1614,6 +1647,8 @@ public class FastNoiseLite implements NoiseSampler {
return distance0 / distance1 - 1; return distance0 / distance1 - 1;
case NoiseLookup: case NoiseLookup:
return cellularNoiseLookup.getNoise(center.getX(), center.getY(), center.getZ()); return cellularNoiseLookup.getNoise(center.getX(), center.getY(), center.getZ());
case Distance3Div:
return distance0 / distance2 - 1;
default: default:
return 0; return 0;
} }
@@ -2603,7 +2638,8 @@ public class FastNoiseLite implements NoiseSampler {
Distance2Sub, Distance2Sub,
Distance2Mul, Distance2Mul,
Distance2Div, Distance2Div,
NoiseLookup NoiseLookup,
Distance3Div
} }
@@ -6,16 +6,25 @@ import com.dfsek.terra.api.world.palette.Palette;
public interface Generator { public interface Generator {
/** /**
* Gets the 3D noise at a pair of coordinates using the provided FastNoiseLite instance. * Gets the noise sampler instance to use for base terrain.
* *
* @param x - The x coordinate. * @return NoiseSampler for terrain
* @param y - The y coordinate.
* @param z - The z coordinate.
* @return double - Noise value at the specified coordinates.
*/ */
double getNoise(double x, double y, double z); NoiseSampler getBaseSampler();
double getElevation(int x, int z); /**
* Gets the noise sampler to use for elevation
*
* @return NoiseSampler for elevation.
*/
NoiseSampler getElevationSampler();
/**
* Gets the noise sampler to use for carving.
*
* @return NoiseSampler for carving.
*/
NoiseSampler getCarver();
int getBlendDistance(); int getBlendDistance();
@@ -1,7 +1,8 @@
package com.dfsek.terra.carving; package com.dfsek.terra.carving;
import com.dfsek.terra.api.platform.world.ChunkAccess; import com.dfsek.terra.api.platform.world.ChunkAccess;
import com.dfsek.terra.api.platform.world.World;
public interface Carver { public interface Carver {
void carve(int chunkX, int chunkZ, ChunkAccess chunk); void carve(World world, int chunkX, int chunkZ, ChunkAccess chunk);
} }
@@ -20,6 +20,8 @@ public class GeneratorBuilder {
private String elevationEquation; private String elevationEquation;
private String carvingEquation;
private Scope varScope; private Scope varScope;
private Map<String, NoiseBuilder> noiseBuilderMap; private Map<String, NoiseBuilder> noiseBuilderMap;
@@ -51,13 +53,15 @@ public class GeneratorBuilder {
return gens.computeIfAbsent(seed, k -> { return gens.computeIfAbsent(seed, k -> {
NoiseSampler noise; NoiseSampler noise;
NoiseSampler elevation; NoiseSampler elevation;
NoiseSampler carving;
try { try {
noise = new ExpressionSampler(noiseEquation, varScope, seed, noiseBuilderMap); noise = new ExpressionSampler(noiseEquation, varScope, seed, noiseBuilderMap);
elevation = elevationEquation == null ? new ConstantSampler(0) : new ExpressionSampler(elevationEquation, varScope, seed, noiseBuilderMap); elevation = elevationEquation == null ? new ConstantSampler(0) : new ExpressionSampler(elevationEquation, varScope, seed, noiseBuilderMap);
carving = new ExpressionSampler(carvingEquation, varScope, seed, noiseBuilderMap);
} catch(ParseException e) { } catch(ParseException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
return new WorldGenerator(palettes, slantPalettes, noise, elevation, noise2d, base, biomeNoise.build((int) seed), elevationWeight, blendDistance, blendStep, blendWeight); return new WorldGenerator(palettes, slantPalettes, noise, elevation, carving, noise2d, base, biomeNoise.build((int) seed), elevationWeight, blendDistance, blendStep, blendWeight);
}); });
} }
} }
@@ -114,6 +118,10 @@ public class GeneratorBuilder {
this.elevationEquation = elevationEquation; this.elevationEquation = elevationEquation;
} }
public void setCarvingEquation(String carvingEquation) {
this.carvingEquation = carvingEquation;
}
public Scope getVarScope() { public Scope getVarScope() {
return varScope; return varScope;
} }
@@ -19,6 +19,7 @@ public class BiomeFactory implements TerraFactory<BiomeTemplate, TerraBiome> {
GeneratorBuilder generatorBuilder = new GeneratorBuilder(); GeneratorBuilder generatorBuilder = new GeneratorBuilder();
generatorBuilder.setElevationEquation(template.getElevationEquation()); generatorBuilder.setElevationEquation(template.getElevationEquation());
generatorBuilder.setNoiseEquation(template.getNoiseEquation()); generatorBuilder.setNoiseEquation(template.getNoiseEquation());
generatorBuilder.setCarvingEquation(template.getCarvingEquation());
generatorBuilder.setNoiseBuilderMap(template.getPack().getTemplate().getNoiseBuilderMap()); generatorBuilder.setNoiseBuilderMap(template.getPack().getTemplate().getNoiseBuilderMap());
generatorBuilder.setPalettes(template.getPalette()); generatorBuilder.setPalettes(template.getPalette());
generatorBuilder.setSlantPalettes(template.getSlantPalette()); generatorBuilder.setSlantPalettes(template.getSlantPalette());
@@ -42,6 +42,11 @@ public class BiomeTemplate extends AbstractableTemplate implements ValidatedConf
@Default @Default
private String extend = null; private String extend = null;
@Value("carving.equation")
@Abstractable
@Default
private String carvingEquation = "0";
@Value("noise-2d.enable") @Value("noise-2d.enable")
@Default @Default
@Abstractable @Abstractable
@@ -235,6 +240,10 @@ public class BiomeTemplate extends AbstractableTemplate implements ValidatedConf
return elevationEquation; return elevationEquation;
} }
public String getCarvingEquation() {
return carvingEquation;
}
public ConfigPack getPack() { public ConfigPack getPack() {
return pack; return pack;
} }
@@ -317,6 +326,12 @@ public class BiomeTemplate extends AbstractableTemplate implements ValidatedConf
throw new ValidationException("Invalid noise equation: ", e); throw new ValidationException("Invalid noise equation: ", e);
} }
try {
tester.parse(carvingEquation, testScope);
} catch(ParseException e) {
throw new ValidationException("Invalid carving equation: ", e);
}
try { try {
if(elevationEquation != null) tester.parse(elevationEquation, testScope); if(elevationEquation != null) tester.parse(elevationEquation, testScope);
} catch(ParseException e) { } catch(ParseException e) {
@@ -1,6 +1,7 @@
package com.dfsek.terra.generation; package com.dfsek.terra.generation;
import com.dfsek.terra.TerraWorld; import com.dfsek.terra.TerraWorld;
import com.dfsek.terra.api.math.Range;
import com.dfsek.terra.api.math.vector.Vector3; import com.dfsek.terra.api.math.vector.Vector3;
import com.dfsek.terra.api.platform.TerraPlugin; import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.platform.block.BlockData; import com.dfsek.terra.api.platform.block.BlockData;
@@ -19,10 +20,12 @@ import com.dfsek.terra.api.world.palette.Palette;
import com.dfsek.terra.biome.BiomeProvider; import com.dfsek.terra.biome.BiomeProvider;
import com.dfsek.terra.biome.UserDefinedBiome; import com.dfsek.terra.biome.UserDefinedBiome;
import com.dfsek.terra.biome.palette.SinglePalette; import com.dfsek.terra.biome.palette.SinglePalette;
import com.dfsek.terra.carving.Carver;
import com.dfsek.terra.config.base.ConfigPack; import com.dfsek.terra.config.base.ConfigPack;
import com.dfsek.terra.config.templates.BiomeTemplate; import com.dfsek.terra.config.templates.BiomeTemplate;
import com.dfsek.terra.generation.math.Sampler; import com.dfsek.terra.generation.math.Sampler;
import com.dfsek.terra.generation.math.SamplerCache; import com.dfsek.terra.generation.math.SamplerCache;
import com.dfsek.terra.population.items.carving.NoiseCarver;
import com.dfsek.terra.profiler.ProfileFuture; import com.dfsek.terra.profiler.ProfileFuture;
import com.dfsek.terra.util.PaletteUtil; import com.dfsek.terra.util.PaletteUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -38,12 +41,15 @@ public class MasterChunkGenerator implements TerraChunkGenerator {
private final MaterialData water; private final MaterialData water;
private final SinglePalette<BlockData> blank; private final SinglePalette<BlockData> blank;
private final Carver carver;
private final SamplerCache cache; private final SamplerCache cache;
public MasterChunkGenerator(ConfigPack c, TerraPlugin main, SamplerCache cache) { public MasterChunkGenerator(ConfigPack c, TerraPlugin main, SamplerCache cache) {
this.configPack = c; this.configPack = c;
this.main = main; this.main = main;
carver = new NoiseCarver(new Range(0, 255), main.getWorldHandle().createBlockData("minecraft:air"), main);
water = main.getWorldHandle().createMaterialData("minecraft:water"); water = main.getWorldHandle().createMaterialData("minecraft:water");
blank = new SinglePalette<>(main.getWorldHandle().createBlockData("minecraft:air")); blank = new SinglePalette<>(main.getWorldHandle().createBlockData("minecraft:air"));
this.cache = cache; this.cache = cache;
@@ -90,54 +96,55 @@ public class MasterChunkGenerator implements TerraChunkGenerator {
TerraWorld tw = main.getWorld(world); TerraWorld tw = main.getWorld(world);
BiomeProvider grid = tw.getBiomeProvider(); BiomeProvider grid = tw.getBiomeProvider();
try(ProfileFuture ignore = tw.getProfiler().measure("TotalChunkGenTime")) { try(ProfileFuture ignore = tw.getProfiler().measure("TotalChunkGenTime")) {
if(!tw.isSafe()) return chunk; if(!tw.isSafe()) return chunk;
int xOrig = (chunkX << 4); int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4); int zOrig = (chunkZ << 4);
Sampler sampler = cache.getChunk(world, chunkX, chunkZ); Sampler sampler = cache.getChunk(world, chunkX, chunkZ);
for(byte x = 0; x < 16; x++) { for(byte x = 0; x < 16; x++) {
for(byte z = 0; z < 16; z++) { for(byte z = 0; z < 16; z++) {
int paletteLevel = 0; int paletteLevel = 0;
int cx = xOrig + x; int cx = xOrig + x;
int cz = zOrig + z; int cz = zOrig + z;
TerraBiome b = grid.getBiome(xOrig + x, zOrig + z); TerraBiome b = grid.getBiome(xOrig + x, zOrig + z);
BiomeTemplate c = ((UserDefinedBiome) b).getConfig(); BiomeTemplate c = ((UserDefinedBiome) b).getConfig();
int sea = c.getSeaLevel(); int sea = c.getSeaLevel();
Palette<BlockData> seaPalette = c.getOceanPalette(); Palette<BlockData> seaPalette = c.getOceanPalette();
boolean justSet = false; boolean justSet = false;
BlockData data = null; BlockData data = null;
for(int y = world.getMaxHeight() - 1; y >= 0; y--) { for(int y = world.getMaxHeight() - 1; y >= 0; y--) {
if(sampler.sample(x, y, z) > 0) { if(sampler.sample(x, y, z) > 0) {
justSet = true; justSet = true;
data = PaletteUtil.getPalette(x, y, z, c, sampler).get(paletteLevel, cx, y, cz); data = PaletteUtil.getPalette(x, y, z, c, sampler).get(paletteLevel, cx, y, cz);
chunk.setBlock(x, y, z, data); chunk.setBlock(x, y, z, data);
if(paletteLevel == 0 && c.doSlabs() && y < 255) { if(paletteLevel == 0 && c.doSlabs() && y < 255) {
prepareBlockPartFloor(data, chunk.getBlockData(x, y + 1, z), chunk, new Vector3(x, y + 1, z), c.getSlabPalettes(), prepareBlockPartFloor(data, chunk.getBlockData(x, y + 1, z), chunk, new Vector3(x, y + 1, z), c.getSlabPalettes(),
c.getStairPalettes(), c.getSlabThreshold(), sampler); c.getStairPalettes(), c.getSlabThreshold(), sampler);
}
paletteLevel++;
} else if(y <= sea) {
chunk.setBlock(x, y, z, seaPalette.get(sea - y, x + xOrig, y, z + zOrig));
if(justSet && c.doSlabs()) {
prepareBlockPartCeiling(data, chunk.getBlockData(x, y, z), chunk, new Vector3(x, y, z), c.getSlabPalettes(), c.getStairPalettes(), c.getSlabThreshold(), sampler);
}
justSet = false;
paletteLevel = 0;
} else {
if(justSet && c.doSlabs()) {
prepareBlockPartCeiling(data, chunk.getBlockData(x, y, z), chunk, new Vector3(x, y, z), c.getSlabPalettes(), c.getStairPalettes(), c.getSlabThreshold(), sampler);
}
justSet = false;
paletteLevel = 0;
} }
paletteLevel++;
} else if(y <= sea) {
chunk.setBlock(x, y, z, seaPalette.get(sea - y, x + xOrig, y, z + zOrig));
if(justSet && c.doSlabs()) {
prepareBlockPartCeiling(data, chunk.getBlockData(x, y, z), chunk, new Vector3(x, y, z), c.getSlabPalettes(), c.getStairPalettes(), c.getSlabThreshold(), sampler);
}
justSet = false;
paletteLevel = 0;
} else {
if(justSet && c.doSlabs()) {
prepareBlockPartCeiling(data, chunk.getBlockData(x, y, z), chunk, new Vector3(x, y, z), c.getSlabPalettes(), c.getStairPalettes(), c.getSlabThreshold(), sampler);
}
justSet = false;
paletteLevel = 0;
} }
} }
} }
}
carver.carve(world, chunkX, chunkZ, chunk);
return chunk; return chunk;
} }
} }
@@ -14,6 +14,7 @@ public class WorldGenerator implements Generator {
private final NoiseSampler noise; private final NoiseSampler noise;
private final NoiseSampler elevation; private final NoiseSampler elevation;
private final NoiseSampler carving;
private final boolean noise2d; private final boolean noise2d;
private final double base; private final double base;
@@ -23,11 +24,12 @@ public class WorldGenerator implements Generator {
private final int blendStep; private final int blendStep;
private final double blendWeight; private final double blendWeight;
public WorldGenerator(PaletteHolder palettes, PaletteHolder slantPalettes, NoiseSampler noise, NoiseSampler elevation, boolean noise2d, double base, NoiseSampler biomeNoise, double elevationWeight, int blendDistance, int blendStep, double blendWeight) { public WorldGenerator(PaletteHolder palettes, PaletteHolder slantPalettes, NoiseSampler noise, NoiseSampler elevation, NoiseSampler carving, boolean noise2d, double base, NoiseSampler biomeNoise, double elevationWeight, int blendDistance, int blendStep, double blendWeight) {
this.palettes = palettes; this.palettes = palettes;
this.slantPalettes = slantPalettes; this.slantPalettes = slantPalettes;
this.noise = noise; this.noise = noise;
this.elevation = elevation; this.elevation = elevation;
this.carving = carving;
this.noise2d = noise2d; this.noise2d = noise2d;
this.base = base; this.base = base;
@@ -39,8 +41,18 @@ public class WorldGenerator implements Generator {
} }
@Override @Override
public synchronized double getElevation(int x, int z) { public NoiseSampler getBaseSampler() {
return elevation.getNoise(x, z); return noise;
}
@Override
public NoiseSampler getElevationSampler() {
return elevation;
}
@Override
public NoiseSampler getCarver() {
return carving;
} }
@Override @Override
@@ -53,11 +65,6 @@ public class WorldGenerator implements Generator {
return blendWeight; return blendWeight;
} }
@Override
public synchronized double getNoise(double x, double y, double z) {
return noise.getNoise(x, y, z);
}
/** /**
* Gets the BlockPalette to generate the biome with. * Gets the BlockPalette to generate the biome with.
* *
@@ -11,11 +11,19 @@ public class Sampler {
private final ElevationInterpolator elevationInterpolator; private final ElevationInterpolator elevationInterpolator;
public Sampler(int x, int z, BiomeProvider provider, World world, int elevationSmooth) { public Sampler(int x, int z, BiomeProvider provider, World world, int elevationSmooth) {
this.interpolator = new BiomeChunkInterpolator(world, x, z, provider); this.interpolator = new BiomeChunkInterpolator(world, x, z, provider, (generator, coord) -> {
if(generator.is2d())
return generator.getBaseSampler().getNoise(coord.getX(), 0, coord.getZ()) + noise2dExtrude(coord.getY(), generator.get2dBase());
else return generator.getBaseSampler().getNoise(coord);
});
this.elevationInterpolator = new ElevationInterpolator(world, x, z, provider, elevationSmooth); this.elevationInterpolator = new ElevationInterpolator(world, x, z, provider, elevationSmooth);
} }
public double sample(double x, double y, double z) { public double sample(double x, double y, double z) {
return interpolator.getNoise(x, y, z) + elevationInterpolator.getElevation(FastMath.roundToInt(x), FastMath.roundToInt(z)); return interpolator.getNoise(x, y, z) + elevationInterpolator.getElevation(FastMath.roundToInt(x), FastMath.roundToInt(z));
} }
public static double noise2dExtrude(double y, double base) {
return ((-FastMath.pow2((y / base))) + 1);
}
} }
@@ -1,5 +1,6 @@
package com.dfsek.terra.generation.math.interpolation; package com.dfsek.terra.generation.math.interpolation;
import com.dfsek.terra.api.math.vector.Vector3;
import com.dfsek.terra.api.platform.world.World; import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.api.util.mutable.MutableInteger; import com.dfsek.terra.api.util.mutable.MutableInteger;
import com.dfsek.terra.api.world.biome.Generator; import com.dfsek.terra.api.world.biome.Generator;
@@ -8,6 +9,7 @@ import net.jafama.FastMath;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.BiFunction;
/** /**
* Class to abstract away the Interpolators needed to generate a chunk.<br> * Class to abstract away the Interpolators needed to generate a chunk.<br>
@@ -15,6 +17,7 @@ import java.util.Map;
*/ */
public class BiomeChunkInterpolator implements ChunkInterpolator { public class BiomeChunkInterpolator implements ChunkInterpolator {
private final Interpolator3[][][] interpGrid = new Interpolator3[4][64][4]; private final Interpolator3[][][] interpGrid = new Interpolator3[4][64][4];
private final BiFunction<Generator, Vector3, Double> noiseGetter;
/** /**
* Instantiates a 3D BiomeChunkInterpolator at a pair of chunk coordinates. * Instantiates a 3D BiomeChunkInterpolator at a pair of chunk coordinates.
@@ -23,7 +26,8 @@ public class BiomeChunkInterpolator implements ChunkInterpolator {
* @param chunkZ Z coordinate of the chunk. * @param chunkZ Z coordinate of the chunk.
* @param provider Biome Provider to use for biome fetching. * @param provider Biome Provider to use for biome fetching.
*/ */
public BiomeChunkInterpolator(World w, int chunkX, int chunkZ, BiomeProvider provider) { public BiomeChunkInterpolator(World w, int chunkX, int chunkZ, BiomeProvider provider, BiFunction<Generator, Vector3, Double> noiseGetter) {
this.noiseGetter = noiseGetter;
int xOrigin = chunkX << 4; int xOrigin = chunkX << 4;
int zOrigin = chunkZ << 4; int zOrigin = chunkZ << 4;
@@ -66,7 +70,7 @@ public class BiomeChunkInterpolator implements ChunkInterpolator {
} }
} }
private static double computeNoise(Map<Generator, MutableInteger> gens, double x, double y, double z) { private double computeNoise(Map<Generator, MutableInteger> gens, double x, double y, double z) {
double n = 0; double n = 0;
double div = 0; double div = 0;
for(Map.Entry<Generator, MutableInteger> entry : gens.entrySet()) { for(Map.Entry<Generator, MutableInteger> entry : gens.entrySet()) {
@@ -80,19 +84,14 @@ public class BiomeChunkInterpolator implements ChunkInterpolator {
return n / div; return n / div;
} }
private static double computeNoise(Generator generator, double x, double y, double z) { private double computeNoise(Generator generator, double x, double y, double z) {
if(generator.is2d()) return generator.getNoise(x, 0, z) + noise2dExtrude(y, generator.get2dBase()); return noiseGetter.apply(generator, new Vector3(x, y, z));
else return generator.getNoise(x, y, z);
} }
private static int reRange(int value, int high) { private static int reRange(int value, int high) {
return FastMath.max(FastMath.min(value, high), 0); return FastMath.max(FastMath.min(value, high), 0);
} }
private static double noise2dExtrude(double y, double base) {
return ((-FastMath.pow2((y / base))) + 1);
}
/** /**
* Gets the noise at a pair of internal chunk coordinates. * Gets the noise at a pair of internal chunk coordinates.
* *
@@ -28,7 +28,7 @@ public class ElevationInterpolator {
for(int xi = -smooth; xi <= smooth; xi++) { for(int xi = -smooth; xi <= smooth; xi++) {
for(int zi = -smooth; zi <= smooth; zi++) { for(int zi = -smooth; zi <= smooth; zi++) {
Generator gen = gens[x + 1 + smooth + xi][z + 1 + smooth + zi]; Generator gen = gens[x + 1 + smooth + xi][z + 1 + smooth + zi];
noise += gen.getElevation(xOrigin + x, zOrigin + z) * gen.getElevationWeight(); noise += gen.getElevationSampler().getNoise(xOrigin + x, zOrigin + z) * gen.getElevationWeight();
div += gen.getElevationWeight(); div += gen.getElevationWeight();
} }
} }
@@ -1,26 +1,35 @@
package com.dfsek.terra.population.items.carving; package com.dfsek.terra.population.items.carving;
import com.dfsek.terra.api.math.Range; import com.dfsek.terra.api.math.Range;
import com.dfsek.terra.api.math.noise.samplers.NoiseSampler; import com.dfsek.terra.api.platform.TerraPlugin;
import com.dfsek.terra.api.platform.block.BlockData;
import com.dfsek.terra.api.platform.world.ChunkAccess; import com.dfsek.terra.api.platform.world.ChunkAccess;
import com.dfsek.terra.api.platform.world.World;
import com.dfsek.terra.carving.Carver; import com.dfsek.terra.carving.Carver;
import com.dfsek.terra.generation.math.interpolation.NoiseChunkInterpolator; import com.dfsek.terra.generation.math.interpolation.BiomeChunkInterpolator;
import com.dfsek.terra.generation.math.interpolation.ChunkInterpolator;
public class NoiseCarver implements Carver { public class NoiseCarver implements Carver {
private final NoiseSampler noise;
private final Range range; private final Range range;
private final BlockData data;
private final TerraPlugin main;
public NoiseCarver(NoiseSampler noise, Range range) { public NoiseCarver(Range range, BlockData data, TerraPlugin main) {
this.noise = noise;
this.range = range; this.range = range;
this.data = data;
this.main = main;
} }
@Override @Override
public void carve(int chunkX, int chunkZ, ChunkAccess chunk) { public void carve(World world, int chunkX, int chunkZ, ChunkAccess chunk) {
NoiseChunkInterpolator chunkInterpolator = new NoiseChunkInterpolator(chunkX, chunkZ, noise); ChunkInterpolator interpolator = new BiomeChunkInterpolator(world, chunkX, chunkZ, main.getWorld(world).getBiomeProvider(), (gen, coord) -> gen.getCarver().getNoise(coord));
for(int y : range) { for(int y : range) {
for(int x = 0; x < 16; x++) {
for(int z = 0; z < 16; z++) {
double n = interpolator.getNoise(x, y, z);
if(n > 0) chunk.setBlock(x, y, z, data);
}
}
} }
} }
} }