Merge submodule contents for common/addons/chunk-generator-noise-3d/master

This commit is contained in:
dfsek 2021-11-21 21:10:07 -07:00
commit eb34d30b00
20 changed files with 968 additions and 0 deletions

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020-2021 Polyhedral Development
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,4 @@
# chunk-generator-noise-3d
Registers the `NOISE_3D` chunk generator, a chunk generator which uses biomes'
samplers in 3D to generate chunk data.

View File

@ -0,0 +1,3 @@
dependencies {
"shadedApi"(project(":common:addons:manifest-addon-loader"))
}

View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.chunkgenerator;
import com.dfsek.tectonic.annotations.Default;
import com.dfsek.tectonic.annotations.Value;
import com.dfsek.tectonic.loading.object.ObjectTemplate;
import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder;
import com.dfsek.terra.addons.chunkgenerator.palette.PaletteInfo;
import com.dfsek.terra.addons.chunkgenerator.palette.SlantHolder;
import com.dfsek.terra.api.config.meta.Meta;
import com.dfsek.terra.api.world.generator.Palette;
public class BiomePaletteTemplate implements ObjectTemplate<PaletteInfo> {
@Value("slant")
@Default
private @Meta SlantHolder slant;
@Value("palette")
private @Meta PaletteHolder palette;
@Value("ocean.level")
private @Meta int seaLevel;
@Value("ocean.palette")
private @Meta Palette oceanPalette;
@Override
public PaletteInfo get() {
return new PaletteInfo(palette, slant, oceanPalette, seaLevel);
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.chunkgenerator;
import com.dfsek.terra.addons.chunkgenerator.generation.generators.NoiseChunkGenerator3D;
import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder;
import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolderLoader;
import com.dfsek.terra.addons.chunkgenerator.palette.SlantHolder;
import com.dfsek.terra.addons.chunkgenerator.palette.SlantHolderLoader;
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
import com.dfsek.terra.api.inject.annotations.Inject;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.generator.ChunkGeneratorProvider;
public class NoiseChunkGenerator3DAddon implements AddonInitializer {
@Inject
private Platform platform;
@Inject
private BaseAddon addon;
@Override
public void initialize() {
platform.getEventManager()
.getHandler(FunctionalEventHandler.class)
.register(addon, ConfigPackPreLoadEvent.class)
.then(event -> {
event.getPack().getOrCreateRegistry(ChunkGeneratorProvider.class).register("NOISE_3D",
pack -> new NoiseChunkGenerator3D(pack,
platform));
event.getPack()
.applyLoader(SlantHolder.class, new SlantHolderLoader())
.applyLoader(PaletteHolder.class, new PaletteHolderLoader());
})
.failThrough();
platform.getEventManager()
.getHandler(FunctionalEventHandler.class)
.register(addon, ConfigurationLoadEvent.class)
.then(event -> {
if(event.is(TerraBiome.class)) {
event.getLoadedObject(TerraBiome.class).getContext().put(event.load(new BiomePaletteTemplate()).get());
}
})
.failThrough();
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.chunkgenerator;
import com.dfsek.terra.addons.chunkgenerator.palette.PaletteInfo;
import com.dfsek.terra.addons.chunkgenerator.palette.SlantHolder;
import com.dfsek.terra.api.util.MathUtil;
import com.dfsek.terra.api.util.math.Sampler;
import com.dfsek.terra.api.world.biome.GenerationSettings;
import com.dfsek.terra.api.world.generator.Palette;
public final class PaletteUtil {
public static Palette getPalette(int x, int y, int z, GenerationSettings c, Sampler sampler, PaletteInfo paletteInfo) {
SlantHolder slant = paletteInfo.getSlantHolder();
if(slant != null) {
double slope = MathUtil.derivative(sampler, x, y, z);
if(slope > slant.getMinSlope()) {
return slant.getPalette(slope).getPalette(y);
}
}
return paletteInfo.getPaletteHolder().getPalette(y);
}
}

View File

@ -0,0 +1,169 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.chunkgenerator.generation.generators;
import net.jafama.FastMath;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import com.dfsek.terra.addons.chunkgenerator.PaletteUtil;
import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D;
import com.dfsek.terra.addons.chunkgenerator.palette.PaletteInfo;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.block.state.properties.base.Properties;
import com.dfsek.terra.api.block.state.properties.enums.Direction;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.profiler.ProfileFrame;
import com.dfsek.terra.api.util.math.Sampler;
import com.dfsek.terra.api.util.vector.Vector3;
import com.dfsek.terra.api.world.BiomeGrid;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.GenerationSettings;
import com.dfsek.terra.api.world.biome.TerraBiome;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.generator.ChunkData;
import com.dfsek.terra.api.world.generator.ChunkGenerator;
import com.dfsek.terra.api.world.generator.GenerationStage;
import com.dfsek.terra.api.world.generator.Palette;
public class NoiseChunkGenerator3D implements ChunkGenerator {
private final ConfigPack configPack;
private final Platform platform;
private final List<GenerationStage> generationStages = new ArrayList<>();
private final BlockState air;
public NoiseChunkGenerator3D(ConfigPack c, Platform platform) {
this.configPack = c;
this.platform = platform;
this.air = platform.getWorldHandle().air();
c.getStages().forEach(stage -> generationStages.add(stage.newInstance(c)));
}
@SuppressWarnings("try")
static void biomes(@NotNull World world, int chunkX, int chunkZ, @NotNull BiomeGrid biome, Platform platform) {
try(ProfileFrame ignore = platform.getProfiler().profile("biomes")) {
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);
long seed = world.getSeed();
BiomeProvider grid = world.getBiomeProvider();
for(int x = 0; x < 4; x++) {
for(int z = 0; z < 4; z++) {
int cx = xOrig + (x << 2);
int cz = zOrig + (z << 2);
TerraBiome b = grid.getBiome(cx, cz, seed);
biome.setBiome(cx, cz, b.getVanillaBiomes().get(b.getGenerator().getBiomeNoise(), cx, 0, cz, world.getSeed()));
}
}
}
}
@Override
@SuppressWarnings("try")
public ChunkData generateChunkData(@NotNull World world, Random random, int chunkX, int chunkZ, ChunkData chunk) {
try(ProfileFrame ignore = platform.getProfiler().profile("chunk_base_3d")) {
BiomeProvider grid = world.getBiomeProvider();
int xOrig = (chunkX << 4);
int zOrig = (chunkZ << 4);
Sampler sampler = world.getConfig().getSamplerCache().getChunk(chunkX, chunkZ);
long seed = world.getSeed();
for(int x = 0; x < 16; x++) {
for(int z = 0; z < 16; z++) {
int paletteLevel = 0;
int cx = xOrig + x;
int cz = zOrig + z;
TerraBiome biome = grid.getBiome(cx, cz, seed);
PaletteInfo paletteInfo = biome.getContext().get(PaletteInfo.class);
GenerationSettings generationSettings = biome.getGenerator();
int sea = paletteInfo.getSeaLevel();
Palette seaPalette = paletteInfo.getOcean();
BlockState data;
for(int y = world.getMaxHeight() - 1; y >= world.getMinHeight(); y--) {
if(sampler.sample(x, y, z) > 0) {
data = PaletteUtil.getPalette(x, y, z, generationSettings, sampler, paletteInfo).get(paletteLevel, cx, y, cz,
seed);
chunk.setBlock(x, y, z, data);
paletteLevel++;
} else if(y <= sea) {
chunk.setBlock(x, y, z, seaPalette.get(sea - y, x + xOrig, y, z + zOrig, seed));
paletteLevel = 0;
} else {
paletteLevel = 0;
}
}
}
}
return chunk;
}
}
@Override
public void generateBiomes(@NotNull World world, @NotNull Random random, int chunkX, int chunkZ, @NotNull BiomeGrid biome) {
biomes(world, chunkX, chunkZ, biome, platform);
}
@Override
public Sampler createSampler(int chunkX, int chunkZ, BiomeProvider provider, World world, int elevationSmooth) {
return new Sampler3D(chunkX, chunkZ, provider, world, elevationSmooth);
}
@Override
public ConfigPack getConfigPack() {
return configPack;
}
@Override
public Platform getPlatform() {
return platform;
}
@Override
public List<GenerationStage> getGenerationStages() {
return generationStages;
}
@Override
public BlockState getBlock(World world, int x, int y, int z) {
BiomeProvider provider = world.getBiomeProvider();
TerraBiome biome = provider.getBiome(x, z, world.getSeed());
Sampler sampler = world.getConfig().getSamplerCache().get(x, z);
PaletteInfo paletteInfo = biome.getContext().get(PaletteInfo.class);
Palette palette = PaletteUtil.getPalette(x, y, z, biome.getGenerator(), sampler, paletteInfo);
int fdX = FastMath.floorMod(x, 16);
int fdZ = FastMath.floorMod(z, 16);
double noise = sampler.sample(fdX, y, fdZ);
if(noise > 0) {
int level = 0;
for(int yi = world.getMaxHeight() - 1; yi > y; yi--) {
if(sampler.sample(fdX, yi, fdZ) > 0) level++;
else level = 0;
}
return palette.get(level, x, y, z, world.getSeed());
} else if(y <= paletteInfo.getSeaLevel()) {
return paletteInfo.getOcean().get(paletteInfo.getSeaLevel() - y, x, y, z, world.getSeed());
} else return air;
}
}

View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation;
import net.jafama.FastMath;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
import com.dfsek.terra.api.util.mutable.MutableInteger;
import com.dfsek.terra.api.util.vector.Vector3;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.GenerationSettings;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.generator.ChunkInterpolator;
/**
* Class to abstract away the Interpolators needed to generate a chunk.<br>
* Contains method to get interpolated noise at a coordinate within the chunk.
*/
public class ChunkInterpolator2D implements ChunkInterpolator {
private final Interpolator[][] interpGrid = new Interpolator[4][4];
private final BiFunction<GenerationSettings, Vector3, Double> noiseGetter;
/**
* Instantiates a 3D ChunkInterpolator3D at a pair of chunk coordinates.
*
* @param chunkX X coordinate of the chunk.
* @param chunkZ Z coordinate of the chunk.
* @param provider Biome Provider to use for biome fetching.
*/
public ChunkInterpolator2D(World w, int chunkX, int chunkZ, BiomeProvider provider,
BiFunction<GenerationSettings, Vector3, Double> noiseGetter) {
this.noiseGetter = noiseGetter;
int xOrigin = chunkX << 4;
int zOrigin = chunkZ << 4;
long seed = w.getSeed();
double[][] noiseStorage = new double[5][5];
for(int x = 0; x < 5; x++) {
for(int z = 0; z < 5; z++) {
GenerationSettings generationSettings = provider.getBiome(xOrigin + (x << 2), zOrigin + (z << 2), seed).getGenerator();
Map<GenerationSettings, MutableInteger> genMap = new HashMap<>();
int step = generationSettings.getBlendStep();
int blend = generationSettings.getBlendDistance();
for(int xi = -blend; xi <= blend; xi++) {
for(int zi = -blend; zi <= blend; zi++) {
genMap.computeIfAbsent(
provider.getBiome(xOrigin + (x << 2) + (xi * step), zOrigin + (z << 2) + (zi * step), seed).getGenerator(),
g -> new MutableInteger(0)).increment(); // Increment by 1
}
}
noiseStorage[x][z] = computeNoise(genMap, (x << 2) + xOrigin, 0, (z << 2) + zOrigin);
}
}
for(int x = 0; x < 4; x++) {
for(int z = 0; z < 4; z++) {
interpGrid[x][z] = new Interpolator(
noiseStorage[x][z],
noiseStorage[x + 1][z],
noiseStorage[x][z + 1],
noiseStorage[x + 1][z + 1]);
}
}
}
private static int reRange(int value, int high) {
return FastMath.max(FastMath.min(value, high), 0);
}
public double computeNoise(GenerationSettings generationSettings, double x, double y, double z) {
return noiseGetter.apply(generationSettings, new Vector3(x, y, z));
}
/**
* Gets the noise at a pair of internal chunk coordinates.
*
* @param x The internal X coordinate (0-15).
* @param z The internal Z coordinate (0-15).
*
* @return double - The interpolated noise at the coordinates.
*/
@Override
public double getNoise(double x, double y, double z) {
return interpGrid[reRange(((int) x) / 4, 3)][reRange(((int) z) / 4, 3)].bilerp((x % 4) / 4, (z % 4) / 4);
}
public double getNoise(int x, int y, int z) {
return interpGrid[x / 4][z / 4].bilerp((double) (x % 4) / 4, (double) (z % 4) / 4);
}
}

View File

@ -0,0 +1,125 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation;
import net.jafama.FastMath;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
import com.dfsek.terra.api.util.mutable.MutableInteger;
import com.dfsek.terra.api.util.vector.Vector3;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.GenerationSettings;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.generator.ChunkInterpolator;
/**
* Class to abstract away the Interpolators needed to generate a chunk.<br>
* Contains method to get interpolated noise at a coordinate within the chunk.
*/
public class ChunkInterpolator3D implements ChunkInterpolator {
private final Interpolator3[][][] interpGrid;
private final BiFunction<GenerationSettings, Vector3, Double> noiseGetter;
private final int min;
private final int max;
/**
* Instantiates a 3D ChunkInterpolator3D at a pair of chunk coordinates.
*
* @param chunkX X coordinate of the chunk.
* @param chunkZ Z coordinate of the chunk.
* @param provider Biome Provider to use for biome fetching.
*/
public ChunkInterpolator3D(World w, int chunkX, int chunkZ, BiomeProvider provider,
BiFunction<GenerationSettings, Vector3, Double> noiseGetter) {
this.noiseGetter = noiseGetter;
int xOrigin = chunkX << 4;
int zOrigin = chunkZ << 4;
this.max = w.getMaxHeight();
this.min = w.getMinHeight();
int range = max - min + 1;
int size = range >> 2;
interpGrid = new Interpolator3[4][size][4];
double[][][] noiseStorage = new double[5][5][size + 1];
long seed = w.getSeed();
for(int x = 0; x < 5; x++) {
for(int z = 0; z < 5; z++) {
GenerationSettings generationSettings = provider.getBiome(xOrigin + (x << 2), zOrigin + (z << 2), seed).getGenerator();
Map<GenerationSettings, MutableInteger> genMap = new HashMap<>();
int step = generationSettings.getBlendStep();
int blend = generationSettings.getBlendDistance();
for(int xi = -blend; xi <= blend; xi++) {
for(int zi = -blend; zi <= blend; zi++) {
genMap.computeIfAbsent(
provider.getBiome(xOrigin + (x << 2) + (xi * step), zOrigin + (z << 2) + (zi * step), seed).getGenerator(),
g -> new MutableInteger(0)).increment(); // Increment by 1
}
}
for(int y = 0; y < size + 1; y++) {
noiseStorage[x][z][y] = computeNoise(genMap, (x << 2) + xOrigin, (y << 2) + min, (z << 2) + zOrigin);
}
}
}
for(int x = 0; x < 4; x++) {
for(int z = 0; z < 4; z++) {
for(int y = 0; y < size; y++) {
interpGrid[x][y][z] = new Interpolator3(
noiseStorage[x][z][y],
noiseStorage[x + 1][z][y],
noiseStorage[x][z][y + 1],
noiseStorage[x + 1][z][y + 1],
noiseStorage[x][z + 1][y],
noiseStorage[x + 1][z + 1][y],
noiseStorage[x][z + 1][y + 1],
noiseStorage[x + 1][z + 1][y + 1]);
}
}
}
}
private static int reRange(int value, int high) {
return FastMath.max(FastMath.min(value, high), 0);
}
public double computeNoise(GenerationSettings generationSettings, double x, double y, double z) {
return noiseGetter.apply(generationSettings, new Vector3(x, y, z));
}
/**
* Gets the noise at a pair of internal chunk coordinates.
*
* @param x The internal X coordinate (0-15).
* @param z The internal Z coordinate (0-15).
*
* @return double - The interpolated noise at the coordinates.
*/
@Override
public double getNoise(double x, double y, double z) {
return interpGrid[reRange(((int) x) / 4, 3)][(FastMath.max(FastMath.min(((int) y), max), min) - min) / 4][reRange(((int) z) / 4,
3)].trilerp(
(x % 4) / 4, (y % 4) / 4, (z % 4) / 4);
}
public double getNoise(int x, int y, int z) {
return interpGrid[x / 4][(y - min) / 4][z / 4].trilerp((double) (x % 4) / 4, (double) (y % 4) / 4, (double) (z % 4) / 4);
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.GenerationSettings;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class ElevationInterpolator {
private final double[][] values = new double[18][18];
public ElevationInterpolator(World world, int chunkX, int chunkZ, BiomeProvider provider, int smooth) {
int xOrigin = chunkX << 4;
int zOrigin = chunkZ << 4;
long seed = world.getSeed();
GenerationSettings[][] gens = new GenerationSettings[18 + 2 * smooth][18 + 2 * smooth];
// Precompute generators.
for(int x = -1 - smooth; x <= 16 + smooth; x++) {
for(int z = -1 - smooth; z <= 16 + smooth; z++) {
gens[x + 1 + smooth][z + 1 + smooth] = provider.getBiome(xOrigin + x, zOrigin + z, seed).getGenerator();
}
}
for(int x = -1; x <= 16; x++) {
for(int z = -1; z <= 16; z++) {
double noise = 0;
double div = 0;
for(int xi = -smooth; xi <= smooth; xi++) {
for(int zi = -smooth; zi <= smooth; zi++) {
GenerationSettings gen = gens[x + 1 + smooth + xi][z + 1 + smooth + zi];
noise += gen.getElevationSampler().getNoiseSeeded(seed, xOrigin + x, zOrigin + z) * gen.getElevationWeight();
div += gen.getElevationWeight();
}
}
values[x + 1][z + 1] = noise / div;
}
}
}
public double getElevation(int x, int z) {
return values[x + 1][z + 1];
}
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation;
/**
* Class for bilinear interpolation of values arranged on a unit square.
*/
public class Interpolator {
private final double v0, v1, v2, v3;
/**
* Constructs an interpolator with given values as vertices of a unit square.
*
* @param v0 - (0,0)
* @param v1 - (1,0)
* @param v2 - (0,1)
* @param v3 - (1,1)
*/
public Interpolator(double v0, double v1, double v2, double v3) {
this.v0 = v0;
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
}
/**
* 1D Linear interpolation between 2 points 1 unit apart.
*
* @param t - Distance from v0. Total distance between v0 and v1 is 1 unit.
* @param v0 - Value at v0.
* @param v1 - Value at v1.
*
* @return double - The interpolated value.
*/
public static double lerp(double t, double v0, double v1) {
return v0 + t * (v1 - v0);
}
/**
* 2D Bilinear interpolation between 4 points on a unit square.
*
* @param s - X value
* @param t - Z value
*
* @return double - The interpolated value.
*/
public double bilerp(double s, double t) {
double v01 = lerp(s, v0, v1);
double v23 = lerp(s, v2, v3);
return lerp(t, v01, v23);
}
}

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation;
/**
* Class for bilinear interpolation of values arranged on a unit square.
*/
public class Interpolator3 {
private final Interpolator bottom;
private final Interpolator top;
/**
* Constructs an interpolator with given values as vertices of a unit cube.
* * @param _000 The value at <code>(t, u, v) = (0, 0, 0)</code>.
* * @param _100 The value at <code>(t, u, v) = (1, 0, 0)</code>.
* * @param _010 The value at <code>(t, u, v) = (0, 1, 0)</code>.
* * @param _110 The value at <code>(t, u, v) = (1, 1, 0)</code>.
* * @param _001 The value at <code>(t, u, v) = (0, 0, 1)</code>.
* * @param _101 The value at <code>(t, u, v) = (1, 0, 1)</code>.
* * @param _011 The value at <code>(t, u, v) = (0, 1, 1)</code>.
* * @param _111 The value at <code>(t, u, v) = (1, 1, 1)</code>.
*/
public Interpolator3(double _000, double _100,
double _010, double _110,
double _001, double _101,
double _011, double _111) {
this.top = new Interpolator(_000, _010, _001, _011);
this.bottom = new Interpolator(_100, _110, _101, _111);
}
public double trilerp(double x, double y, double z) {
return Interpolator.lerp(x, top.bilerp(y, z), bottom.bilerp(y, z));
}
}

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.chunkgenerator.generation.math.samplers;
import net.jafama.FastMath;
import com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation.ChunkInterpolator3D;
import com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation.ElevationInterpolator;
import com.dfsek.terra.api.util.math.Sampler;
import com.dfsek.terra.api.world.World;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class Sampler3D implements Sampler {
private final ChunkInterpolator3D interpolator;
private final ElevationInterpolator elevationInterpolator;
public Sampler3D(int x, int z, BiomeProvider provider, World world, int elevationSmooth) {
this.interpolator = new ChunkInterpolator3D(world, x, z, provider, (generator, coord) -> generator.getBaseSampler()
.getNoiseSeeded(coord,
world.getSeed()));
this.elevationInterpolator = new ElevationInterpolator(world, x, z, provider, elevationSmooth);
}
@Override
public double sample(double x, double y, double z) {
return interpolator.getNoise(x, y, z) + elevationInterpolator.getElevation(FastMath.roundToInt(x), FastMath.roundToInt(z));
}
@Override
public double sample(int x, int y, int z) {
return interpolator.getNoise(x, y, z) + elevationInterpolator.getElevation(FastMath.roundToInt(x), FastMath.roundToInt(z));
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.chunkgenerator.palette;
import com.dfsek.terra.api.world.generator.Palette;
public class PaletteHolder {
private final Palette[] palettes;
private final int offset;
protected PaletteHolder(Palette[] palettes, int offset) {
this.palettes = palettes;
this.offset = offset;
}
public Palette getPalette(int y) {
int index = y + offset;
return index >= 0
? index < palettes.length
? palettes[index]
: palettes[palettes.length - 1]
: palettes[0];
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.chunkgenerator.palette;
import net.jafama.FastMath;
import java.util.Map;
import java.util.TreeMap;
import com.dfsek.terra.api.world.generator.Palette;
public class PaletteHolderBuilder {
private final TreeMap<Integer, Palette> paletteMap = new TreeMap<>();
public PaletteHolderBuilder add(int y, Palette palette) {
paletteMap.put(y, palette);
return this;
}
public PaletteHolder build() {
int min = FastMath.min(paletteMap.keySet().stream().min(Integer::compareTo).orElse(0), 0);
int max = FastMath.max(paletteMap.keySet().stream().max(Integer::compareTo).orElse(255), 255);
Palette[] palettes = new Palette[paletteMap.lastKey() + 1 - min];
for(int y = min; y <= FastMath.max(paletteMap.lastKey(), max); y++) {
Palette d = null;
for(Map.Entry<Integer, Palette> e : paletteMap.entrySet()) {
if(e.getKey() >= y) {
d = e.getValue();
break;
}
}
if(d == null) throw new IllegalArgumentException("No palette for Y=" + y);
palettes[y - min] = d;
}
return new PaletteHolder(palettes, -min);
}
}

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.chunkgenerator.palette;
import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.ConfigLoader;
import com.dfsek.tectonic.loading.TypeLoader;
import java.lang.reflect.AnnotatedType;
import java.util.List;
import java.util.Map;
import com.dfsek.terra.api.world.generator.Palette;
public class PaletteHolderLoader implements TypeLoader<PaletteHolder> {
@SuppressWarnings("unchecked")
@Override
public PaletteHolder load(AnnotatedType type, Object o, ConfigLoader configLoader) throws LoadException {
List<Map<String, Integer>> palette = (List<Map<String, Integer>>) o;
PaletteHolderBuilder builder = new PaletteHolderBuilder();
for(Map<String, Integer> layer : palette) {
for(Map.Entry<String, Integer> entry : layer.entrySet()) {
builder.add(entry.getValue(), configLoader.loadType(Palette.class, entry.getKey()));
}
}
return builder.build();
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.chunkgenerator.palette;
import com.dfsek.terra.api.properties.Properties;
import com.dfsek.terra.api.world.generator.Palette;
public class PaletteInfo implements Properties {
private final PaletteHolder paletteHolder;
private final SlantHolder slantHolder;
private final Palette ocean;
private final int seaLevel;
public PaletteInfo(PaletteHolder paletteHolder, SlantHolder slantHolder, Palette ocean, int seaLevel) {
this.paletteHolder = paletteHolder;
this.slantHolder = slantHolder;
this.ocean = ocean;
this.seaLevel = seaLevel;
}
public Palette getOcean() {
return ocean;
}
public PaletteHolder getPaletteHolder() {
return paletteHolder;
}
public SlantHolder getSlantHolder() {
return slantHolder;
}
public int getSeaLevel() {
return seaLevel;
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.chunkgenerator.palette;
import java.util.TreeMap;
public class SlantHolder {
private final TreeMap<Double, PaletteHolder> layers;
private final double minSlope;
public SlantHolder(TreeMap<Double, PaletteHolder> layers, double minSlope) {
this.layers = layers;
this.minSlope = minSlope;
}
public PaletteHolder getPalette(double slope) {
return layers.floorEntry(slope).getValue();
}
public double getMinSlope() {
return minSlope;
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.chunkgenerator.palette;
import com.dfsek.tectonic.exception.LoadException;
import com.dfsek.tectonic.loading.ConfigLoader;
import com.dfsek.tectonic.loading.TypeLoader;
import java.lang.reflect.AnnotatedType;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
@SuppressWarnings("unchecked")
public class SlantHolderLoader implements TypeLoader<SlantHolder> {
@Override
public SlantHolder load(AnnotatedType type, Object o, ConfigLoader configLoader) throws LoadException {
List<Map<Object, Object>> layers = (List<Map<Object, Object>>) o;
TreeMap<Double, PaletteHolder> slantLayers = new TreeMap<>();
double minThreshold = Double.MAX_VALUE;
for(Map<Object, Object> layer : layers) {
double threshold = ((Number) layer.get("threshold")).doubleValue();
if(threshold < minThreshold) minThreshold = threshold;
slantLayers.put(threshold, configLoader.loadType(PaletteHolder.class, layer.get("palette")));
}
return new SlantHolder(slantLayers, minThreshold);
}
}

View File

@ -0,0 +1,12 @@
schema-version: 1
contributors:
- Terra contributors
id: chunk-generator-noise-3d
version: 0.1.0
entrypoints:
- "com.dfsek.terra.addons.chunkgenerator.NoiseChunkGenerator3DAddon"
website:
issues: https://github.com/PolyhedralDev/Terra-chunk-generator-noise-3d/issues
source: https://github.com/PolyhedralDev/Terra-chunk-generator-noise-3d
docs: https://github.com/PolyhedralDev/Terra/wiki
license: GNU LGPL v3.0