diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/NoiseChunkGenerator3DAddon.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/NoiseChunkGenerator3DAddon.java index 06450b613..ce1ec9650 100644 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/NoiseChunkGenerator3DAddon.java +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/NoiseChunkGenerator3DAddon.java @@ -11,9 +11,10 @@ import com.dfsek.terra.addons.chunkgenerator.config.NoiseChunkGeneratorPackConfi import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseConfigTemplate; import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseProperties; import com.dfsek.terra.addons.chunkgenerator.config.palette.BiomePaletteTemplate; -import com.dfsek.terra.addons.chunkgenerator.config.palette.PaletteInfo; -import com.dfsek.terra.addons.chunkgenerator.config.palette.SlantLayer; +import com.dfsek.terra.addons.chunkgenerator.config.palette.slant.SlantLayerTemplate; import com.dfsek.terra.addons.chunkgenerator.generation.NoiseChunkGenerator3D; +import com.dfsek.terra.addons.chunkgenerator.palette.BiomePaletteInfo; +import com.dfsek.terra.addons.chunkgenerator.palette.slant.SlantHolder; import com.dfsek.terra.addons.manifest.api.AddonInitializer; import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.addon.BaseAddon; @@ -36,15 +37,20 @@ public class NoiseChunkGenerator3DAddon implements AddonInitializer { @Override public void initialize() { - PropertyKey paletteInfoPropertyKey = Context.create(PaletteInfo.class); + PropertyKey paletteInfoPropertyKey = Context.create(BiomePaletteInfo.class); PropertyKey noisePropertiesPropertyKey = Context.create(BiomeNoiseProperties.class); platform.getEventManager() .getHandler(FunctionalEventHandler.class) .register(addon, ConfigPackPreLoadEvent.class) .priority(1000) .then(event -> { + + event.getPack().applyLoader(SlantHolder.CalculationMethod.class, + (type, o, loader, depthTracker) -> SlantHolder.CalculationMethod.valueOf((String) o)); + NoiseChunkGeneratorPackConfigTemplate config = event.loadTemplate(new NoiseChunkGeneratorPackConfigTemplate()); - + event.getPack().getContext().put(config); + event.getPack() .getOrCreateRegistry(ChunkGeneratorProvider.class) .register(addon.key("NOISE_3D"), @@ -53,7 +59,7 @@ public class NoiseChunkGenerator3DAddon implements AddonInitializer { config.getVerticalRes(), noisePropertiesPropertyKey, paletteInfoPropertyKey)); event.getPack() - .applyLoader(SlantLayer.class, SlantLayer::new); + .applyLoader(SlantHolder.Layer.class, SlantLayerTemplate::new); }) .failThrough(); @@ -62,8 +68,10 @@ public class NoiseChunkGenerator3DAddon implements AddonInitializer { .register(addon, ConfigurationLoadEvent.class) .then(event -> { if(event.is(Biome.class)) { + NoiseChunkGeneratorPackConfigTemplate config = event.getPack().getContext().get(NoiseChunkGeneratorPackConfigTemplate.class); + event.getLoadedObject(Biome.class).getContext().put(paletteInfoPropertyKey, - event.load(new BiomePaletteTemplate(platform)).get()); + event.load(new BiomePaletteTemplate(platform, config.getSlantCalculationMethod())).get()); event.getLoadedObject(Biome.class).getContext().put(noisePropertiesPropertyKey, event.load(new BiomeNoiseConfigTemplate()).get()); } diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/NoiseChunkGeneratorPackConfigTemplate.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/NoiseChunkGeneratorPackConfigTemplate.java index e636ae400..db9922980 100644 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/NoiseChunkGeneratorPackConfigTemplate.java +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/NoiseChunkGeneratorPackConfigTemplate.java @@ -4,10 +4,12 @@ import com.dfsek.tectonic.api.config.template.ConfigTemplate; import com.dfsek.tectonic.api.config.template.annotations.Default; import com.dfsek.tectonic.api.config.template.annotations.Value; +import com.dfsek.terra.addons.chunkgenerator.palette.slant.SlantHolder; import com.dfsek.terra.api.config.meta.Meta; +import com.dfsek.terra.api.properties.Properties; -public class NoiseChunkGeneratorPackConfigTemplate implements ConfigTemplate { +public class NoiseChunkGeneratorPackConfigTemplate implements ConfigTemplate, Properties { @Value("blend.terrain.elevation") @Default private @Meta int elevationBlend = 4; @@ -20,6 +22,10 @@ public class NoiseChunkGeneratorPackConfigTemplate implements ConfigTemplate { @Default private @Meta int verticalRes = 2; + @Value("slant.calculation-method") + @Default + private SlantHolder.@Meta CalculationMethod slantCalculationMethod = SlantHolder.CalculationMethod.Derivative; + public int getElevationBlend() { return elevationBlend; } @@ -31,4 +37,8 @@ public class NoiseChunkGeneratorPackConfigTemplate implements ConfigTemplate { public int getVerticalRes() { return verticalRes; } + + public SlantHolder.CalculationMethod getSlantCalculationMethod() { + return slantCalculationMethod; + } } diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/palette/BiomePaletteTemplate.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/palette/BiomePaletteTemplate.java index f1f0f804a..f872794c9 100644 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/palette/BiomePaletteTemplate.java +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/palette/BiomePaletteTemplate.java @@ -15,25 +15,23 @@ import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Map.Entry; -import java.util.TreeMap; import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder; -import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolderBuilder; -import com.dfsek.terra.addons.chunkgenerator.palette.SlantHolder; +import com.dfsek.terra.addons.chunkgenerator.palette.BiomePaletteInfo; +import com.dfsek.terra.addons.chunkgenerator.palette.slant.SlantHolder; import com.dfsek.terra.api.Platform; import com.dfsek.terra.api.block.state.BlockState; import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.world.chunk.generation.util.Palette; -public class BiomePaletteTemplate implements ObjectTemplate { +public class BiomePaletteTemplate implements ObjectTemplate { private final Platform platform; @Value("slant") @Default @Description("The slant palettes to use in this biome.") - private @Meta List<@Meta SlantLayer> slant = Collections.emptyList(); + private @Meta List slantLayers = Collections.emptyList(); @Value("slant-depth") @Default @@ -63,27 +61,16 @@ public class BiomePaletteTemplate implements ObjectTemplate { @Default private @Meta boolean updatePalette = false; - public BiomePaletteTemplate(Platform platform) { this.platform = platform; } + private final SlantHolder.CalculationMethod slantCalculationMethod; + + public BiomePaletteTemplate(Platform platform, SlantHolder.CalculationMethod slantCalculationMethod) { + this.platform = platform; + this.slantCalculationMethod = slantCalculationMethod; + } @Override - public PaletteInfo get() { - PaletteHolderBuilder builder = new PaletteHolderBuilder(); - for(Map layer : palettes) { - for(Entry entry : layer.entrySet()) { - builder.add(entry.getValue(), entry.getKey()); - } - } - - TreeMap slantLayers = new TreeMap<>(); - double minThreshold = Double.MAX_VALUE; - - for(SlantLayer layer : slant) { - double threshold = layer.getThreshold(); - if(threshold < minThreshold) minThreshold = threshold; - slantLayers.put(threshold, layer.getPalette()); - } - - return new PaletteInfo(builder.build(), SlantHolder.of(slantLayers, minThreshold), oceanPalette, seaLevel, slantDepth, - updatePalette); + public BiomePaletteInfo get() { + return new BiomePaletteInfo(PaletteHolder.of(palettes), SlantHolder.of(slantLayers, slantDepth, slantCalculationMethod), + oceanPalette, seaLevel, updatePalette); } } diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/palette/PaletteInfo.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/palette/PaletteInfo.java deleted file mode 100644 index caf3c4802..000000000 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/palette/PaletteInfo.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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.config.palette; - -import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder; -import com.dfsek.terra.addons.chunkgenerator.palette.SlantHolder; -import com.dfsek.terra.api.properties.Properties; -import com.dfsek.terra.api.world.chunk.generation.util.Palette; - - -public record PaletteInfo(PaletteHolder paletteHolder, - SlantHolder slantHolder, - Palette ocean, - int seaLevel, - int maxSlantDepth, - boolean updatePaletteWhenCarving) implements Properties { -} diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/palette/SlantLayer.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/palette/SlantLayer.java deleted file mode 100644 index d63cbbb46..000000000 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/palette/SlantLayer.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.dfsek.terra.addons.chunkgenerator.config.palette; - -import com.dfsek.tectonic.api.config.template.annotations.Value; -import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; - -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder; -import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolderBuilder; -import com.dfsek.terra.api.config.meta.Meta; -import com.dfsek.terra.api.world.chunk.generation.util.Palette; - - -public class SlantLayer implements ObjectTemplate { - @Value("threshold") - private @Meta double threshold; - - @Value("palette") - private @Meta List<@Meta Map<@Meta Palette, @Meta Integer>> palettes; - - @Override - public SlantLayer get() { - return this; - } - - public double getThreshold() { - return threshold; - } - - public PaletteHolder getPalette() { - PaletteHolderBuilder builder = new PaletteHolderBuilder(); - for(Map layer : palettes) { - for(Entry entry : layer.entrySet()) { - builder.add(entry.getValue(), entry.getKey()); - } - } - - return builder.build(); - } -} diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/palette/slant/SlantLayerTemplate.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/palette/slant/SlantLayerTemplate.java new file mode 100644 index 000000000..5a4fd646d --- /dev/null +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/config/palette/slant/SlantLayerTemplate.java @@ -0,0 +1,27 @@ +package com.dfsek.terra.addons.chunkgenerator.config.palette.slant; + +import com.dfsek.tectonic.api.config.template.annotations.Value; +import com.dfsek.tectonic.api.config.template.object.ObjectTemplate; + +import java.util.List; +import java.util.Map; + +import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder; +import com.dfsek.terra.addons.chunkgenerator.palette.slant.SlantHolder; +import com.dfsek.terra.api.config.meta.Meta; +import com.dfsek.terra.api.world.chunk.generation.util.Palette; + + +public class SlantLayerTemplate implements ObjectTemplate { + + @Value("threshold") + private @Meta double threshold; + + @Value("palette") + private @Meta List<@Meta Map<@Meta Palette, @Meta Integer>> palettes; + + @Override + public SlantHolder.Layer get() { + return new SlantHolder.Layer(PaletteHolder.of(palettes), threshold); + } +} diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/NoiseChunkGenerator3D.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/NoiseChunkGenerator3D.java index fcb8d3fe2..f0f6de8e3 100644 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/NoiseChunkGenerator3D.java +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/NoiseChunkGenerator3D.java @@ -12,7 +12,7 @@ import net.jafama.FastMath; import org.jetbrains.annotations.NotNull; import com.dfsek.terra.addons.chunkgenerator.config.noise.BiomeNoiseProperties; -import com.dfsek.terra.addons.chunkgenerator.config.palette.PaletteInfo; +import com.dfsek.terra.addons.chunkgenerator.palette.BiomePaletteInfo; import com.dfsek.terra.addons.chunkgenerator.generation.math.PaletteUtil; import com.dfsek.terra.addons.chunkgenerator.generation.math.interpolation.LazilyEvaluatedInterpolator; import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D; @@ -40,13 +40,13 @@ public class NoiseChunkGenerator3D implements ChunkGenerator { private final int carverHorizontalResolution; private final int carverVerticalResolution; - private final PropertyKey paletteInfoPropertyKey; + private final PropertyKey paletteInfoPropertyKey; private final PropertyKey noisePropertiesKey; public NoiseChunkGenerator3D(ConfigPack pack, Platform platform, int elevationBlend, int carverHorizontalResolution, int carverVerticalResolution, PropertyKey noisePropertiesKey, - PropertyKey paletteInfoPropertyKey) { + PropertyKey paletteInfoPropertyKey) { this.platform = platform; this.air = platform.getWorldHandle().air(); this.carverHorizontalResolution = carverHorizontalResolution; @@ -97,7 +97,7 @@ public class NoiseChunkGenerator3D implements ChunkGenerator { for(int y = world.getMaxHeight() - 1; y >= world.getMinHeight(); y--) { Biome biome = biomeColumn.get(y); - PaletteInfo paletteInfo = biome.getContext().get(paletteInfoPropertyKey); + BiomePaletteInfo paletteInfo = biome.getContext().get(paletteInfoPropertyKey); int sea = paletteInfo.seaLevel(); Palette seaPalette = paletteInfo.ocean(); @@ -131,7 +131,7 @@ public class NoiseChunkGenerator3D implements ChunkGenerator { Biome biome = biomeProvider.getBiome(x, y, z, world.getSeed()); Sampler3D sampler = samplerCache.get(x, z, world, biomeProvider); - PaletteInfo paletteInfo = biome.getContext().get(paletteInfoPropertyKey); + BiomePaletteInfo paletteInfo = biome.getContext().get(paletteInfoPropertyKey); int fdX = FastMath.floorMod(x, 16); int fdZ = FastMath.floorMod(z, 16); diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/PaletteUtil.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/PaletteUtil.java index d649cf4f2..ebeabaf23 100644 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/PaletteUtil.java +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/generation/math/PaletteUtil.java @@ -7,40 +7,23 @@ package com.dfsek.terra.addons.chunkgenerator.generation.math; -import com.dfsek.terra.addons.chunkgenerator.config.palette.PaletteInfo; +import com.dfsek.terra.addons.chunkgenerator.palette.BiomePaletteInfo; import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D; -import com.dfsek.terra.addons.chunkgenerator.palette.SlantHolder; +import com.dfsek.terra.addons.chunkgenerator.palette.slant.SlantHolder; import com.dfsek.terra.api.world.chunk.generation.util.Palette; public final class PaletteUtil { - /** - * Derivative constant. - */ - private static final double DERIVATIVE_DIST = 0.55; - public static Palette getPalette(int x, int y, int z, Sampler3D sampler, PaletteInfo paletteInfo, int depth) { - SlantHolder slant = paletteInfo.slantHolder(); - if(!slant.isEmpty() && depth <= paletteInfo.maxSlantDepth()) { - double slope = derivative(sampler, x, y, z); - if(slope > slant.getMinSlope()) { - return slant.getPalette(slope).getPalette(y); + public static Palette getPalette(int x, int y, int z, Sampler3D sampler, BiomePaletteInfo paletteInfo, int depth) { + SlantHolder slantHolder = paletteInfo.slantHolder(); + if(slantHolder.isAboveDepth(depth)) { + double slant = slantHolder.calculateSlant(sampler, x, y, z); + if(slantHolder.isInSlantThreshold(slant)) { + return slantHolder.getPalette(slant).getPalette(y); } } return paletteInfo.paletteHolder().getPalette(y); } - - public static double derivative(Sampler3D sampler, double x, double y, double z) { - double baseSample = sampler.sample(x, y, z); - - double xVal1 = (sampler.sample(x + DERIVATIVE_DIST, y, z) - baseSample) / DERIVATIVE_DIST; - double xVal2 = (sampler.sample(x - DERIVATIVE_DIST, y, z) - baseSample) / DERIVATIVE_DIST; - double zVal1 = (sampler.sample(x, y, z + DERIVATIVE_DIST) - baseSample) / DERIVATIVE_DIST; - double zVal2 = (sampler.sample(x, y, z - DERIVATIVE_DIST) - baseSample) / DERIVATIVE_DIST; - double yVal1 = (sampler.sample(x, y + DERIVATIVE_DIST, z) - baseSample) / DERIVATIVE_DIST; - double yVal2 = (sampler.sample(x, y - DERIVATIVE_DIST, z) - baseSample) / DERIVATIVE_DIST; - - return Math.sqrt(((xVal2 - xVal1) * (xVal2 - xVal1)) + ((zVal2 - zVal1) * (zVal2 - zVal1)) + ((yVal2 - yVal1) * (yVal2 - yVal1))); - } } \ No newline at end of file diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/BiomePaletteInfo.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/BiomePaletteInfo.java new file mode 100644 index 000000000..a75eeef5f --- /dev/null +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/BiomePaletteInfo.java @@ -0,0 +1,20 @@ +/* + * 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.addons.chunkgenerator.palette.slant.SlantHolder; +import com.dfsek.terra.api.properties.Properties; +import com.dfsek.terra.api.world.chunk.generation.util.Palette; + + +public record BiomePaletteInfo(PaletteHolder paletteHolder, + SlantHolder slantHolder, + Palette ocean, + int seaLevel, + boolean updatePaletteWhenCarving) implements Properties { +} diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/PaletteHolder.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/PaletteHolder.java index 2451d063c..fcd48f4a8 100644 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/PaletteHolder.java +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/PaletteHolder.java @@ -7,6 +7,13 @@ package com.dfsek.terra.addons.chunkgenerator.palette; +import net.jafama.FastMath; + +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; + import com.dfsek.terra.api.world.chunk.generation.util.Palette; @@ -27,4 +34,43 @@ public class PaletteHolder { : palettes[palettes.length - 1] : palettes[0]; } + + public static PaletteHolder of(List> palettes) { + PaletteHolderBuilder builder = new PaletteHolderBuilder(); + for(Map layer : palettes) { + for(Entry entry : layer.entrySet()) { + builder.add(entry.getValue(), entry.getKey()); + } + } + return builder.build(); + } + + private static class PaletteHolderBuilder { + private final TreeMap 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(Entry 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); + } + } } diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/PaletteHolderBuilder.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/PaletteHolderBuilder.java deleted file mode 100644 index 693939c75..000000000 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/PaletteHolderBuilder.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.chunk.generation.util.Palette; - - -public class PaletteHolderBuilder { - private final TreeMap 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 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); - } -} diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/SlantHolder.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/SlantHolder.java deleted file mode 100644 index 6ceacee24..000000000 --- a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/SlantHolder.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.Map.Entry; -import java.util.TreeMap; - - -public class SlantHolder { - private final TreeMap layers; - private final double minSlope; - - private SlantHolder(TreeMap layers, double minSlope) { - this.layers = layers; - this.minSlope = minSlope; - } - - public static SlantHolder of(TreeMap layers, double minSlope) { - if(layers.size() == 1) { - Entry firstEntry = layers.firstEntry(); - return new Single(firstEntry.getValue(), minSlope); - } - return new SlantHolder(layers, minSlope); - } - - public boolean isEmpty() { - return layers.isEmpty(); - } - - public PaletteHolder getPalette(double slope) { - return layers.floorEntry(slope).getValue(); - } - - public double getMinSlope() { - return minSlope; - } - - private static final class Single extends SlantHolder { - - private final PaletteHolder layers; - - public Single(PaletteHolder layers, double minSlope) { - super(of(minSlope, layers), minSlope); - this.layers = layers; - } - - private static TreeMap of(double v, PaletteHolder layer) { - TreeMap map = new TreeMap<>(); - map.put(v, layer); - return map; - } - - @Override - public PaletteHolder getPalette(double slope) { - return layers; - } - } -} diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/slant/MultipleSlantHolder.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/slant/MultipleSlantHolder.java new file mode 100644 index 000000000..928edb2c2 --- /dev/null +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/slant/MultipleSlantHolder.java @@ -0,0 +1,47 @@ +/* + * 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.slant; + + +import java.util.List; +import java.util.NavigableMap; +import java.util.TreeMap; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder; + + +public class MultipleSlantHolder extends SlantHolderImpl { + private final NavigableMap layers; + private final double slantThreshold; + + MultipleSlantHolder(List slant, int slantDepth, CalculationMethod calculationMethod) { + super(slantDepth, calculationMethod); + NavigableMap layers = new TreeMap<>(slant.stream().collect(Collectors.toMap(SlantHolder.Layer::threshold, SlantHolder.Layer::palette))); + Stream thresholds = layers.keySet().stream(); + double slantThreshold = floorToThreshold ? + thresholds.min(Double::compare).orElseThrow() : + thresholds.max(Double::compare).orElseThrow(); + this.layers = layers; + this.slantThreshold = slantThreshold; + } + + @Override + protected double getSlantThreshold() { + return slantThreshold; + } + + @Override + public PaletteHolder getPalette(double slant) { + return (floorToThreshold ? + layers.floorEntry(slant) : + layers.ceilingEntry(slant) + ).getValue(); + } +} diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/slant/SingleSlantHolder.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/slant/SingleSlantHolder.java new file mode 100644 index 000000000..fdc9b27cb --- /dev/null +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/slant/SingleSlantHolder.java @@ -0,0 +1,24 @@ +package com.dfsek.terra.addons.chunkgenerator.palette.slant; + +import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder; + + +final class SingleSlantHolder extends SlantHolderImpl { + + private final SlantHolder.Layer layer; + + public SingleSlantHolder(SlantHolder.Layer layer, int slantDepth, CalculationMethod calculationMethod) { + super(slantDepth, calculationMethod); + this.layer = layer; + } + + @Override + public PaletteHolder getPalette(double slant) { + return layer.palette(); + } + + @Override + protected double getSlantThreshold() { + return layer.threshold(); + } +} diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/slant/SlantHolder.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/slant/SlantHolder.java new file mode 100644 index 000000000..e70670977 --- /dev/null +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/slant/SlantHolder.java @@ -0,0 +1,116 @@ +package com.dfsek.terra.addons.chunkgenerator.palette.slant; + +import java.util.List; + +import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D; +import com.dfsek.terra.addons.chunkgenerator.palette.PaletteHolder; +import com.dfsek.terra.api.util.vector.Vector3; + + +public interface SlantHolder { + + static SlantHolder of(List layers, int slantDepth, CalculationMethod calculationMethod) { + if(layers.isEmpty()) { + return EMPTY; + } else if(layers.size() == 1) { + return new SingleSlantHolder(layers.get(0), slantDepth, calculationMethod); + } + return new MultipleSlantHolder(layers, slantDepth, calculationMethod); + } + + double calculateSlant(Sampler3D sampler, double x, double y, double z); + + boolean isAboveDepth(int depth); + + boolean isInSlantThreshold(double slant); + + PaletteHolder getPalette(double slant); + + record Layer(PaletteHolder palette, double threshold) { + } + + enum CalculationMethod { + DotProduct { + private static final Vector3 DOT_PRODUCT_DIRECTION = Vector3.of(0, 1, 0); + + private static final Vector3[] DOT_PRODUCT_SAMPLE_POINTS = { + Vector3.of(0, 0, -DERIVATIVE_DIST), + Vector3.of(0, 0, DERIVATIVE_DIST), + Vector3.of(0, -DERIVATIVE_DIST, 0), + Vector3.of(0, DERIVATIVE_DIST, 0), + Vector3.of(-DERIVATIVE_DIST, 0, 0), + Vector3.of(DERIVATIVE_DIST, 0, 0) + }; + + @Override + public double slant(Sampler3D sampler, double x, double y, double z) { + Vector3.Mutable normalApproximation = Vector3.Mutable.of(0, 0, 0); + for(Vector3 point : DOT_PRODUCT_SAMPLE_POINTS) { + var scalar = -sampler.sample(x+point.getX(), y+point.getY(), z+point.getZ()); + normalApproximation.add(point.mutable().multiply(scalar)); + } + return DOT_PRODUCT_DIRECTION.dot(normalApproximation.normalize()); + } + + @Override + public boolean floorToThreshold() { + return false; + } + }, + + Derivative { + @Override + public double slant(Sampler3D sampler, double x, double y, double z) { + double baseSample = sampler.sample(x, y, z); + + double xVal1 = (sampler.sample(x + DERIVATIVE_DIST, y, z) - baseSample) / DERIVATIVE_DIST; + double xVal2 = (sampler.sample(x - DERIVATIVE_DIST, y, z) - baseSample) / DERIVATIVE_DIST; + double zVal1 = (sampler.sample(x, y, z + DERIVATIVE_DIST) - baseSample) / DERIVATIVE_DIST; + double zVal2 = (sampler.sample(x, y, z - DERIVATIVE_DIST) - baseSample) / DERIVATIVE_DIST; + double yVal1 = (sampler.sample(x, y + DERIVATIVE_DIST, z) - baseSample) / DERIVATIVE_DIST; + double yVal2 = (sampler.sample(x, y - DERIVATIVE_DIST, z) - baseSample) / DERIVATIVE_DIST; + + return Math.sqrt(((xVal2 - xVal1) * (xVal2 - xVal1)) + ((zVal2 - zVal1) * (zVal2 - zVal1)) + ((yVal2 - yVal1) * (yVal2 - yVal1))); + } + + @Override + public boolean floorToThreshold() { + return true; + } + }; + + private static final double DERIVATIVE_DIST = 0.55; + + public abstract double slant(Sampler3D sampler, double x, double y, double z); + + /* + * Controls whether palettes should be applied before or after their respective thresholds. + * + * If true, slant values will map to the palette of the next floor threshold, otherwise they + * will map to the ceiling. + */ + public abstract boolean floorToThreshold(); + } + + SlantHolder EMPTY = new SlantHolder() { + @Override + public double calculateSlant(Sampler3D sampler, double x, double y, double z) { + throw new UnsupportedOperationException("Empty holder should not calculate slant"); + } + + @Override + public boolean isAboveDepth(int depth) { + return false; + } + + @Override + public boolean isInSlantThreshold(double slant) { + return false; + } + + @Override + public PaletteHolder getPalette(double slant) { + throw new UnsupportedOperationException("Empty holder cannot return a palette"); + } + }; +} diff --git a/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/slant/SlantHolderImpl.java b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/slant/SlantHolderImpl.java new file mode 100644 index 000000000..e7261b88e --- /dev/null +++ b/common/addons/chunk-generator-noise-3d/src/main/java/com/dfsek/terra/addons/chunkgenerator/palette/slant/SlantHolderImpl.java @@ -0,0 +1,38 @@ +package com.dfsek.terra.addons.chunkgenerator.palette.slant; + +import com.dfsek.terra.addons.chunkgenerator.generation.math.samplers.Sampler3D; + + +public abstract class SlantHolderImpl implements SlantHolder { + private final SlantHolder.CalculationMethod calculationMethod; + + private final int slantDepth; + + protected final boolean floorToThreshold; + + protected SlantHolderImpl(int slantDepth, CalculationMethod calculationMethod) { + this.floorToThreshold = calculationMethod.floorToThreshold(); + this.calculationMethod = calculationMethod; + this.slantDepth = slantDepth; + } + + protected abstract double getSlantThreshold(); + + @Override + public final double calculateSlant(Sampler3D sampler, double x, double y, double z) { + return calculationMethod.slant(sampler, x, y, z); + } + + @Override + public final boolean isAboveDepth(int depth) { + return depth <= slantDepth; + } + + @Override + public final boolean isInSlantThreshold(double slant) { + return (floorToThreshold ? + slant > getSlantThreshold() : + slant < getSlantThreshold() + ); + } +}