From 18d7408f53b9b45e1bc48eb42cd24774c3b4ba6a Mon Sep 17 00:00:00 2001 From: dfsek Date: Mon, 11 Jan 2021 13:31:19 -0700 Subject: [PATCH 1/7] customizable palette noise --- .../terra/api/math/ProbabilityCollection.java | 15 ++++---- .../math/noise/samplers/FastNoiseLite.java | 33 ++++++++++------- ...{SimplexPalette.java => NoisePalette.java} | 4 +-- .../api/world/tree/fractal/TreeGeometry.java | 30 ++++++++-------- .../api/world/tree/fractal/trees/OakTree.java | 4 +-- .../tree/fractal/trees/ShatteredTree.java | 4 +-- .../fractal/trees/SmallShatteredTree.java | 4 +-- .../world/tree/fractal/trees/SpruceTree.java | 8 ++--- .../config/factories/PaletteFactory.java | 13 ++----- .../config/templates/PaletteTemplate.java | 36 +++++++------------ .../terra/generation/config/NoiseBuilder.java | 8 ++++- 11 files changed, 75 insertions(+), 84 deletions(-) rename common/src/main/java/com/dfsek/terra/api/world/palette/{SimplexPalette.java => NoisePalette.java} (84%) diff --git a/common/src/main/java/com/dfsek/terra/api/math/ProbabilityCollection.java b/common/src/main/java/com/dfsek/terra/api/math/ProbabilityCollection.java index 829acf7d6..2e6f76af9 100644 --- a/common/src/main/java/com/dfsek/terra/api/math/ProbabilityCollection.java +++ b/common/src/main/java/com/dfsek/terra/api/math/ProbabilityCollection.java @@ -1,12 +1,11 @@ package com.dfsek.terra.api.math; import com.dfsek.terra.api.math.noise.samplers.NoiseSampler; -import com.dfsek.terra.api.world.biome.NormalizationUtil; +import net.jafama.FastMath; import java.util.HashSet; import java.util.Random; import java.util.Set; -import java.util.concurrent.ThreadLocalRandom; @SuppressWarnings("unchecked") public class ProbabilityCollection { @@ -25,19 +24,19 @@ public class ProbabilityCollection { return this; } - public E get() { - if(array.length == 0) return null; - return (E) array[ThreadLocalRandom.current().nextInt(array.length)]; - } - public E get(Random r) { if(array.length == 0) return null; return (E) array[r.nextInt(array.length)]; } + private static double getNoise(double x, double z, NoiseSampler sampler) { + double n = sampler.getNoise(x, z); + return FastMath.min(FastMath.max(n, -1), 1); + } + public E get(NoiseSampler n, double x, double z) { if(array.length == 0) return null; - return (E) array[NormalizationUtil.normalize(n.getNoise(x, z), array.length, 1)]; + return (E) array[FastMath.min(FastMath.floorToInt(((getNoise(x, z, n) + 1D) / 2D) * array.length), array.length - 1)]; } public int getTotalProbability() { diff --git a/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/FastNoiseLite.java b/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/FastNoiseLite.java index 3b125cf05..5baefd7e2 100644 --- a/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/FastNoiseLite.java +++ b/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/FastNoiseLite.java @@ -1615,25 +1615,32 @@ public class FastNoiseLite implements NoiseSampler { return lerp(xf0, xf1, ys) * 1.4247691104677813f; } - private int doubleCast2Int(double f) { - int i = Float.floatToRawIntBits((float) f); - - return i ^ (i >> 16); + private static long hash(long in) { + in = (in + 0x7ed55d16) + (in << 12); + in = (in ^ 0xc761c23c) ^ (in >> 19); + in = (in + 0x165667b1) + (in << 5); + in = (in + 0xd3a2646c) ^ (in << 9); + in = (in + 0xfd7046c5) + (in << 3); + in = (in ^ 0xb55a4f09) ^ (in >> 16); + return in; } private double singleWhiteNoise(int seed, double x, double y, double z) { - int xi = doubleCast2Int(x); - int yi = doubleCast2Int(y); - int zi = doubleCast2Int(z); - - return valCoord(seed, xi, yi, zi); + long hashX = hash(Double.doubleToRawLongBits(x) ^ seed); + long hashZ = hash(Double.doubleToRawLongBits(y) ^ seed); + long hash = (((hashX ^ (hashX >>> 32)) + ((hashZ ^ (hashZ >>> 32)) << 32)) ^ seed) + Double.doubleToRawLongBits(z); + long base = ((hash(hash)) & 0x000fffffffffffffL) + + (0b01111111111L << 52); // Sign and exponent + return (Double.longBitsToDouble(base) - 1.5) * 2; } private double singleWhiteNoise(int seed, double x, double y) { - int xi = doubleCast2Int(x); - int yi = doubleCast2Int(y); - - return valCoord(seed, xi, yi); + long hashX = hash(Double.doubleToRawLongBits(x) ^ seed); + long hashZ = hash(Double.doubleToRawLongBits(y) ^ seed); + long hash = ((hashX ^ (hashX >>> 32)) + ((hashZ ^ (hashZ >>> 32)) << 32)) ^ seed; + long base = (hash(hash) & 0x000fffffffffffffL) + + (0b01111111111L << 52); // Sign and exponent + return (Double.longBitsToDouble(base) - 1.5) * 2; } // Simplex/OpenSimplex2 Noise diff --git a/common/src/main/java/com/dfsek/terra/api/world/palette/SimplexPalette.java b/common/src/main/java/com/dfsek/terra/api/world/palette/NoisePalette.java similarity index 84% rename from common/src/main/java/com/dfsek/terra/api/world/palette/SimplexPalette.java rename to common/src/main/java/com/dfsek/terra/api/world/palette/NoisePalette.java index 6ac97f88b..4709ad755 100644 --- a/common/src/main/java/com/dfsek/terra/api/world/palette/SimplexPalette.java +++ b/common/src/main/java/com/dfsek/terra/api/world/palette/NoisePalette.java @@ -4,10 +4,10 @@ import com.dfsek.terra.api.math.noise.samplers.NoiseSampler; import java.util.List; -public class SimplexPalette extends Palette { +public class NoisePalette extends Palette { private final NoiseSampler r; - public SimplexPalette(NoiseSampler r) { + public NoisePalette(NoiseSampler r) { this.r = r; } diff --git a/common/src/main/java/com/dfsek/terra/api/world/tree/fractal/TreeGeometry.java b/common/src/main/java/com/dfsek/terra/api/world/tree/fractal/TreeGeometry.java index bd9ac089b..7ec3ee28c 100644 --- a/common/src/main/java/com/dfsek/terra/api/world/tree/fractal/TreeGeometry.java +++ b/common/src/main/java/com/dfsek/terra/api/world/tree/fractal/TreeGeometry.java @@ -15,28 +15,28 @@ public class TreeGeometry { } public static Vector3 getPerpendicular(Vector3 v) { - return v.getZ() < v.getX() ? new Vector3(v.getY(), - v.getX(), 0) : new Vector3(0, - v.getZ(), v.getY()); + return v.getZ() < v.getX() ? new Vector3(v.getY(), -v.getX(), 0) : new Vector3(0, -v.getZ(), v.getY()); } public FractalTree getTree() { return tree; } - public void generateSphere(Location l, BlockData m, int radius, boolean overwrite) { - generateSphere(l, new ProbabilityCollection().add(m, 1), radius, overwrite); + public void generateSphere(Location l, BlockData m, int radius, boolean overwrite, Random r) { + generateSphere(l, new ProbabilityCollection().add(m, 1), radius, overwrite, r); } - public void generateCylinder(Location l, BlockData m, int radius, int height, boolean overwrite) { - generateCylinder(l, new ProbabilityCollection().add(m, 1), radius, height, overwrite); + public void generateCylinder(Location l, BlockData m, int radius, int height, boolean overwrite, Random r) { + generateCylinder(l, new ProbabilityCollection().add(m, 1), radius, height, overwrite, r); } - public void generateSphere(Location l, ProbabilityCollection m, int radius, boolean overwrite) { - for(int x = - radius; x <= radius; x++) { - for(int y = - radius; y <= radius; y++) { - for(int z = - radius; z <= radius; z++) { + public void generateSphere(Location l, ProbabilityCollection m, int radius, boolean overwrite, Random r) { + for(int x = -radius; x <= radius; x++) { + for(int y = -radius; y <= radius; y++) { + for(int z = -radius; z <= radius; z++) { Vector3 position = l.toVector().clone().add(new Vector3(x, y, z)); if(l.toVector().distance(position) <= radius + 0.5 && (overwrite || position.toLocation(l.getWorld()).getBlock().isEmpty())) - tree.setBlock(position.toLocation(l.getWorld()), m.get()); + tree.setBlock(position.toLocation(l.getWorld()), m.get(r)); } } } @@ -48,19 +48,19 @@ public class TreeGeometry { for(int z = -radius; z <= radius; z++) { Vector3 position = l.toVector().clone().add(new Vector3(x, y, z)); if(r.nextInt(100) < sponginess && l.toVector().distance(position) <= radius + 0.5 && (overwrite || position.toLocation(l.getWorld()).getBlock().isEmpty())) - tree.setBlock(position.toLocation(l.getWorld()), m.get()); + tree.setBlock(position.toLocation(l.getWorld()), m.get(r)); } } } } - public void generateCylinder(Location l, ProbabilityCollection m, int radius, int height, boolean overwrite) { - for(int x = - radius; x <= radius; x++) { + public void generateCylinder(Location l, ProbabilityCollection m, int radius, int height, boolean overwrite, Random r) { + for(int x = -radius; x <= radius; x++) { for(int y = 0; y <= height; y++) { - for(int z = - radius; z <= radius; z++) { + for(int z = -radius; z <= radius; z++) { Vector3 position = l.toVector().clone().add(new Vector3(x, 0, z)); if(l.toVector().distance(position) <= radius + 0.5 && (overwrite || position.toLocation(l.getWorld()).getBlock().isEmpty())) - tree.setBlock(position.toLocation(l.getWorld()), m.get()); + tree.setBlock(position.toLocation(l.getWorld()), m.get(r)); } } } diff --git a/common/src/main/java/com/dfsek/terra/api/world/tree/fractal/trees/OakTree.java b/common/src/main/java/com/dfsek/terra/api/world/tree/fractal/trees/OakTree.java index 4a24b7a90..d4fdee054 100644 --- a/common/src/main/java/com/dfsek/terra/api/world/tree/fractal/trees/OakTree.java +++ b/common/src/main/java/com/dfsek/terra/api/world/tree/fractal/trees/OakTree.java @@ -41,13 +41,13 @@ public class OakTree extends FractalTree { BlockData wood = getMain().getWorldHandle().createBlockData("minecraft:oak_wood"); BlockData leaves = getMain().getWorldHandle().createBlockData("minecraft:oak_leave"); if(recursions > 1) { - geo.generateSphere(l1, leaves, 1 + r.nextInt(2) + (3 - recursions), false); + geo.generateSphere(l1, leaves, 1 + r.nextInt(2) + (3 - recursions), false, r); if(recursions > 2) return; } if(diff.getY() < 0) diff.rotateAroundAxis(TreeGeometry.getPerpendicular(diff.clone()).normalize(), FastMath.PI); int d = (int) diff.length(); for(int i = 0; i < d; i++) { - geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), wood, FastMath.max((int) d1, 0), true); + geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), wood, FastMath.max((int) d1, 0), true, r); } double runningAngle = (double) 45 / (recursions + 1); growBranch(l1.clone().add(diff), diff.clone().multiply(0.75).rotateAroundX(FastMath.toRadians(runningAngle + getNoise(r))).rotateAroundZ(FastMath.toRadians(getNoise(r))), diff --git a/common/src/main/java/com/dfsek/terra/api/world/tree/fractal/trees/ShatteredTree.java b/common/src/main/java/com/dfsek/terra/api/world/tree/fractal/trees/ShatteredTree.java index 50839b746..58a06585e 100644 --- a/common/src/main/java/com/dfsek/terra/api/world/tree/fractal/trees/ShatteredTree.java +++ b/common/src/main/java/com/dfsek/terra/api/world/tree/fractal/trees/ShatteredTree.java @@ -50,13 +50,13 @@ public class ShatteredTree extends FractalTree { private void growBranch(Location l1, Vector3 diff, double d1, int recursions, Random r) { if(recursions > 2) { - geo.generateSphere(l1, leaves, 1 + r.nextInt(2), false); + geo.generateSphere(l1, leaves, 1 + r.nextInt(2), false, r); return; } if(diff.getY() < 0) diff.rotateAroundAxis(TreeGeometry.getPerpendicular(diff.clone()).normalize(), FastMath.PI); int d = (int) diff.length(); for(int i = 0; i < d; i++) { - geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), bark, FastMath.max((int) d1, 0), true); + geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), bark, FastMath.max((int) d1, 0), true, r); } double runningAngle = (double) 45 / (recursions + 1); growBranch(l1.clone().add(diff), diff.clone().multiply(0.9).rotateAroundX(FastMath.toRadians(runningAngle + getNoise(r))).rotateAroundZ(FastMath.toRadians(getNoise(r))), diff --git a/common/src/main/java/com/dfsek/terra/api/world/tree/fractal/trees/SmallShatteredTree.java b/common/src/main/java/com/dfsek/terra/api/world/tree/fractal/trees/SmallShatteredTree.java index 50e681870..16aec9d4f 100644 --- a/common/src/main/java/com/dfsek/terra/api/world/tree/fractal/trees/SmallShatteredTree.java +++ b/common/src/main/java/com/dfsek/terra/api/world/tree/fractal/trees/SmallShatteredTree.java @@ -50,13 +50,13 @@ public class SmallShatteredTree extends FractalTree { private void growBranch(Location l1, Vector3 diff, double d1, int recursions, Random r) { if(recursions > 2) { - geo.generateSphere(l1, leaves, 1 + r.nextInt(2) + (3 - recursions), false); + geo.generateSphere(l1, leaves, 1 + r.nextInt(2) + (3 - recursions), false, r); return; } if(diff.getY() < 0) diff.rotateAroundAxis(TreeGeometry.getPerpendicular(diff.clone()).normalize(), FastMath.PI); int d = (int) diff.length(); for(int i = 0; i < d; i++) { - geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), bark, FastMath.max((int) d1, 0), true); + geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), bark, FastMath.max((int) d1, 0), true, r); } double runningAngle = (double) 45 / (recursions + 1); growBranch(l1.clone().add(diff), diff.clone().multiply(0.7).rotateAroundX(FastMath.toRadians(runningAngle + getNoise(r))).rotateAroundZ(FastMath.toRadians(getNoise(r))), diff --git a/common/src/main/java/com/dfsek/terra/api/world/tree/fractal/trees/SpruceTree.java b/common/src/main/java/com/dfsek/terra/api/world/tree/fractal/trees/SpruceTree.java index 640cd6177..139e77a49 100644 --- a/common/src/main/java/com/dfsek/terra/api/world/tree/fractal/trees/SpruceTree.java +++ b/common/src/main/java/com/dfsek/terra/api/world/tree/fractal/trees/SpruceTree.java @@ -33,19 +33,19 @@ public class SpruceTree extends FractalTree { */ @Override public void grow(Location origin, Random random) { - growTrunk(origin.clone(), new Vector3(0, 16 + random.nextInt(5), 0)); + growTrunk(origin.clone(), new Vector3(0, 16 + random.nextInt(5), 0), random); } - private void growTrunk(Location l1, Vector3 diff) { + private void growTrunk(Location l1, Vector3 diff, Random r) { if(diff.getY() < 0) diff.rotateAroundAxis(TreeGeometry.getPerpendicular(diff.clone()).normalize(), FastMath.PI); int d = (int) diff.length(); int rad = 7; BlockData wood = getMain().getWorldHandle().createBlockData("minecraft:spruce_wood"); BlockData leaves = getMain().getWorldHandle().createBlockData("minecraft:spruce_leave"); for(int i = 0; i < d; i++) { - geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), wood, (int) ((i > d * 0.65) ? 0.5 : 1.5), true); + geo.generateSphere(l1.clone().add(diff.clone().multiply((double) i / d)), wood, (int) ((i > d * 0.65) ? 0.5 : 1.5), true, r); if(i > 3) - geo.generateCylinder(l1.clone().add(diff.clone().multiply((double) i / d)), leaves, (int) (((6 - (i % 4))) * (1.25 - ((double) i / d))), 1, false); + geo.generateCylinder(l1.clone().add(diff.clone().multiply((double) i / d)), leaves, (int) (((6 - (i % 4))) * (1.25 - ((double) i / d))), 1, false, r); } setBlock(l1.clone().add(diff), leaves); setBlock(l1.clone().add(diff).add(0, 1, 0), leaves); diff --git a/common/src/main/java/com/dfsek/terra/config/factories/PaletteFactory.java b/common/src/main/java/com/dfsek/terra/config/factories/PaletteFactory.java index 137ab4dbd..dedd6a8f3 100644 --- a/common/src/main/java/com/dfsek/terra/config/factories/PaletteFactory.java +++ b/common/src/main/java/com/dfsek/terra/config/factories/PaletteFactory.java @@ -1,25 +1,16 @@ package com.dfsek.terra.config.factories; -import com.dfsek.terra.api.math.noise.samplers.FastNoiseLite; import com.dfsek.terra.api.platform.TerraPlugin; import com.dfsek.terra.api.platform.block.BlockData; -import com.dfsek.terra.api.util.FastRandom; +import com.dfsek.terra.api.world.palette.NoisePalette; import com.dfsek.terra.api.world.palette.Palette; -import com.dfsek.terra.api.world.palette.RandomPalette; -import com.dfsek.terra.api.world.palette.SimplexPalette; import com.dfsek.terra.biome.palette.PaletteLayer; import com.dfsek.terra.config.templates.PaletteTemplate; public class PaletteFactory implements TerraFactory> { @Override public Palette build(PaletteTemplate config, TerraPlugin main) { - Palette palette; - if(config.isSimplex()) { - FastNoiseLite noise = new FastNoiseLite((int) config.getSeed()); - noise.setFrequency(config.getFrequency()); - palette = new SimplexPalette<>(noise); - } else palette = new RandomPalette<>(new FastRandom(config.getSeed())); - + Palette palette = new NoisePalette<>(config.getNoise().build(2403)); for(PaletteLayer layer : config.getPalette()) { palette.add(layer.getLayer(), layer.getSize()); } diff --git a/common/src/main/java/com/dfsek/terra/config/templates/PaletteTemplate.java b/common/src/main/java/com/dfsek/terra/config/templates/PaletteTemplate.java index 443bc9bab..fae810e95 100644 --- a/common/src/main/java/com/dfsek/terra/config/templates/PaletteTemplate.java +++ b/common/src/main/java/com/dfsek/terra/config/templates/PaletteTemplate.java @@ -3,12 +3,19 @@ package com.dfsek.terra.config.templates; import com.dfsek.tectonic.annotations.Abstractable; import com.dfsek.tectonic.annotations.Default; import com.dfsek.tectonic.annotations.Value; +import com.dfsek.terra.api.math.noise.samplers.FastNoiseLite; import com.dfsek.terra.biome.palette.PaletteLayer; +import com.dfsek.terra.generation.config.NoiseBuilder; import java.util.List; @SuppressWarnings({"FieldMayBeFinal", "unused"}) public class PaletteTemplate extends AbstractableTemplate { + @Value("noise") + @Abstractable + @Default + private NoiseBuilder noise = new NoiseBuilder(); + @Value("id") private String id; @@ -16,38 +23,19 @@ public class PaletteTemplate extends AbstractableTemplate { @Abstractable private List palette; - @Value("simplex") - @Abstractable - @Default - private boolean simplex = false; - - @Value("frequency") - @Abstractable - @Default - private double frequency = 0.02D; - - @Value("seed") - @Abstractable - @Default - private long seed = 0; + public PaletteTemplate() { + noise.setType(FastNoiseLite.NoiseType.WhiteNoise); + } public String getID() { return id; } - public double getFrequency() { - return frequency; - } - - public long getSeed() { - return seed; - } - public List getPalette() { return palette; } - public boolean isSimplex() { - return simplex; + public NoiseBuilder getNoise() { + return noise; } } diff --git a/common/src/main/java/com/dfsek/terra/generation/config/NoiseBuilder.java b/common/src/main/java/com/dfsek/terra/generation/config/NoiseBuilder.java index b86a6d764..c9212a195 100644 --- a/common/src/main/java/com/dfsek/terra/generation/config/NoiseBuilder.java +++ b/common/src/main/java/com/dfsek/terra/generation/config/NoiseBuilder.java @@ -6,6 +6,7 @@ import com.dfsek.tectonic.config.ConfigTemplate; import com.dfsek.terra.api.math.noise.samplers.FastNoiseLite; import com.dfsek.terra.api.math.noise.samplers.NoiseSampler; +@SuppressWarnings("FieldMayBeFinal") public class NoiseBuilder implements ConfigTemplate { @Value("type") @Default @@ -39,7 +40,7 @@ public class NoiseBuilder implements ConfigTemplate { @Default private double weightedStrength = 0.0D; - @Value("offset") + @Value("salt") @Default private int seedOffset = 0; @@ -71,6 +72,10 @@ public class NoiseBuilder implements ConfigTemplate { @Default private int dimensions = 2; + @Value("cellular.lookup") + @Default + private NoiseBuilder lookup = new NoiseBuilder(); + public NoiseSampler build(int seed) { FastNoiseLite noise = new FastNoiseLite(seed + seedOffset); if(!fractalType.equals(FastNoiseLite.FractalType.None)) { @@ -85,6 +90,7 @@ public class NoiseBuilder implements ConfigTemplate { noise.setCellularDistanceFunction(cellularDistanceFunction); noise.setCellularReturnType(cellularReturnType); noise.setCellularJitter(cellularJitter); + noise.setCellularNoiseLookup(lookup.build(seed)); } noise.setNoiseType(type); From 623a4dea4f223b3e647db5401fc28d355ecdeb6a Mon Sep 17 00:00:00 2001 From: dfsek Date: Mon, 11 Jan 2021 13:34:53 -0700 Subject: [PATCH 2/7] allow configuration of cellular lookup function --- .../java/com/dfsek/terra/generation/config/NoiseBuilder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/com/dfsek/terra/generation/config/NoiseBuilder.java b/common/src/main/java/com/dfsek/terra/generation/config/NoiseBuilder.java index c9212a195..0382f01d8 100644 --- a/common/src/main/java/com/dfsek/terra/generation/config/NoiseBuilder.java +++ b/common/src/main/java/com/dfsek/terra/generation/config/NoiseBuilder.java @@ -74,7 +74,7 @@ public class NoiseBuilder implements ConfigTemplate { @Value("cellular.lookup") @Default - private NoiseBuilder lookup = new NoiseBuilder(); + private NoiseBuilder lookup; public NoiseSampler build(int seed) { FastNoiseLite noise = new FastNoiseLite(seed + seedOffset); @@ -90,7 +90,7 @@ public class NoiseBuilder implements ConfigTemplate { noise.setCellularDistanceFunction(cellularDistanceFunction); noise.setCellularReturnType(cellularReturnType); noise.setCellularJitter(cellularJitter); - noise.setCellularNoiseLookup(lookup.build(seed)); + if(lookup != null) noise.setCellularNoiseLookup(lookup.build(seed)); } noise.setNoiseType(type); From 8a10a9807d19ee707060a1f97c431a6c0c67a4c9 Mon Sep 17 00:00:00 2001 From: dfsek Date: Mon, 11 Jan 2021 14:37:56 -0700 Subject: [PATCH 3/7] allow configuration of 2d/3d noise in palettes --- .../terra/api/math/ProbabilityCollection.java | 10 ++++++++ .../terra/api/world/palette/NoisePalette.java | 12 ++++++---- .../terra/api/world/palette/Palette.java | 7 +++--- .../api/world/palette/RandomPalette.java | 2 +- .../terra/biome/palette/SinglePalette.java | 2 +- .../config/factories/PaletteFactory.java | 2 +- .../config/templates/PaletteTemplate.java | 1 + .../generation/MasterChunkGenerator.java | 24 +++++++++---------- .../population/items/flora/TerraFlora.java | 2 +- 9 files changed, 38 insertions(+), 24 deletions(-) diff --git a/common/src/main/java/com/dfsek/terra/api/math/ProbabilityCollection.java b/common/src/main/java/com/dfsek/terra/api/math/ProbabilityCollection.java index 2e6f76af9..ed488656e 100644 --- a/common/src/main/java/com/dfsek/terra/api/math/ProbabilityCollection.java +++ b/common/src/main/java/com/dfsek/terra/api/math/ProbabilityCollection.java @@ -29,11 +29,21 @@ public class ProbabilityCollection { return (E) array[r.nextInt(array.length)]; } + private static double getNoise(double x, double y, double z, NoiseSampler sampler) { + double n = sampler.getNoise(x, y, z); + return FastMath.min(FastMath.max(n, -1), 1); + } + private static double getNoise(double x, double z, NoiseSampler sampler) { double n = sampler.getNoise(x, z); return FastMath.min(FastMath.max(n, -1), 1); } + public E get(NoiseSampler n, double x, double y, double z) { + if(array.length == 0) return null; + return (E) array[FastMath.min(FastMath.floorToInt(((getNoise(x, y, z, n) + 1D) / 2D) * array.length), array.length - 1)]; + } + public E get(NoiseSampler n, double x, double z) { if(array.length == 0) return null; return (E) array[FastMath.min(FastMath.floorToInt(((getNoise(x, z, n) + 1D) / 2D) * array.length), array.length - 1)]; diff --git a/common/src/main/java/com/dfsek/terra/api/world/palette/NoisePalette.java b/common/src/main/java/com/dfsek/terra/api/world/palette/NoisePalette.java index 4709ad755..d2b314dc8 100644 --- a/common/src/main/java/com/dfsek/terra/api/world/palette/NoisePalette.java +++ b/common/src/main/java/com/dfsek/terra/api/world/palette/NoisePalette.java @@ -6,16 +6,18 @@ import java.util.List; public class NoisePalette extends Palette { private final NoiseSampler r; + private final boolean is2D; - public NoisePalette(NoiseSampler r) { + public NoisePalette(NoiseSampler r, boolean is2D) { this.r = r; + this.is2D = is2D; } @Override - public E get(int layer, int x, int z) { - if(layer > this.getSize()) return this.getLayers().get(this.getLayers().size() - 1).get(r, x, z); + public E get(int layer, double x, double y, double z) { + if(layer > this.getSize()) return this.getLayers().get(this.getLayers().size() - 1).get(r, x, y, z, is2D); List> pl = getLayers(); - if(layer >= pl.size()) return pl.get(pl.size() - 1).get(r, x, z); - return pl.get(layer).get(r, x, z); + if(layer >= pl.size()) return pl.get(pl.size() - 1).get(r, x, y, z, is2D); + return pl.get(layer).get(r, x, y, z, is2D); } } diff --git a/common/src/main/java/com/dfsek/terra/api/world/palette/Palette.java b/common/src/main/java/com/dfsek/terra/api/world/palette/Palette.java index f10ecfbf8..618427041 100644 --- a/common/src/main/java/com/dfsek/terra/api/world/palette/Palette.java +++ b/common/src/main/java/com/dfsek/terra/api/world/palette/Palette.java @@ -55,7 +55,7 @@ public abstract class Palette { * @param layer - The layer at which to fetch the material. * @return BlockData - The material fetched. */ - public abstract E get(int layer, int x, int z); + public abstract E get(int layer, double x, double y, double z); public int getSize() { @@ -104,8 +104,9 @@ public abstract class Palette { return m; } - public E get(NoiseSampler random, int x, int z) { - if(col) return this.collection.get(random, x, z); + public E get(NoiseSampler random, double x, double y, double z, boolean is2D) { + if(col && is2D) return this.collection.get(random, x, z); + else if(col) return this.collection.get(random, x, y, z); return m; } diff --git a/common/src/main/java/com/dfsek/terra/api/world/palette/RandomPalette.java b/common/src/main/java/com/dfsek/terra/api/world/palette/RandomPalette.java index 88452d953..3fff52cbc 100644 --- a/common/src/main/java/com/dfsek/terra/api/world/palette/RandomPalette.java +++ b/common/src/main/java/com/dfsek/terra/api/world/palette/RandomPalette.java @@ -11,7 +11,7 @@ public class RandomPalette extends Palette { } @Override - public E get(int layer, int x, int z) { + public E get(int layer, double x, double y, double z) { if(layer > this.getSize()) return this.getLayers().get(this.getLayers().size() - 1).get(r); List> pl = getLayers(); if(layer >= pl.size()) return pl.get(pl.size() - 1).get(r); diff --git a/common/src/main/java/com/dfsek/terra/biome/palette/SinglePalette.java b/common/src/main/java/com/dfsek/terra/biome/palette/SinglePalette.java index 76e01281e..5a71a8a6b 100644 --- a/common/src/main/java/com/dfsek/terra/biome/palette/SinglePalette.java +++ b/common/src/main/java/com/dfsek/terra/biome/palette/SinglePalette.java @@ -10,7 +10,7 @@ public class SinglePalette extends Palette { } @Override - public E get(int i, int i1, int i2) { + public E get(int layer, double x, double y, double z) { return item; } } diff --git a/common/src/main/java/com/dfsek/terra/config/factories/PaletteFactory.java b/common/src/main/java/com/dfsek/terra/config/factories/PaletteFactory.java index dedd6a8f3..47804fef3 100644 --- a/common/src/main/java/com/dfsek/terra/config/factories/PaletteFactory.java +++ b/common/src/main/java/com/dfsek/terra/config/factories/PaletteFactory.java @@ -10,7 +10,7 @@ import com.dfsek.terra.config.templates.PaletteTemplate; public class PaletteFactory implements TerraFactory> { @Override public Palette build(PaletteTemplate config, TerraPlugin main) { - Palette palette = new NoisePalette<>(config.getNoise().build(2403)); + Palette palette = new NoisePalette<>(config.getNoise().build(2403), config.getNoise().getDimensions() == 2); for(PaletteLayer layer : config.getPalette()) { palette.add(layer.getLayer(), layer.getSize()); } diff --git a/common/src/main/java/com/dfsek/terra/config/templates/PaletteTemplate.java b/common/src/main/java/com/dfsek/terra/config/templates/PaletteTemplate.java index fae810e95..84dc949e5 100644 --- a/common/src/main/java/com/dfsek/terra/config/templates/PaletteTemplate.java +++ b/common/src/main/java/com/dfsek/terra/config/templates/PaletteTemplate.java @@ -25,6 +25,7 @@ public class PaletteTemplate extends AbstractableTemplate { public PaletteTemplate() { noise.setType(FastNoiseLite.NoiseType.WhiteNoise); + noise.setDimensions(3); } public String getID() { diff --git a/common/src/main/java/com/dfsek/terra/generation/MasterChunkGenerator.java b/common/src/main/java/com/dfsek/terra/generation/MasterChunkGenerator.java index a2265b5a2..db019b04f 100644 --- a/common/src/main/java/com/dfsek/terra/generation/MasterChunkGenerator.java +++ b/common/src/main/java/com/dfsek/terra/generation/MasterChunkGenerator.java @@ -114,7 +114,7 @@ public class MasterChunkGenerator implements TerraChunkGenerator { for(int y = world.getMaxHeight() - 1; y >= 0; y--) { if(sampler.sample(x, y, z) > 0) { justSet = true; - data = PaletteUtil.getPalette(x, y, z, c, sampler).get(paletteLevel, cx, cz); + data = PaletteUtil.getPalette(x, y, z, c, sampler).get(paletteLevel, cx, y, cz); chunk.setBlock(x, y, z, data); if(paletteLevel == 0 && c.doSlabs() && y < 255) { prepareBlockPartFloor(data, chunk.getBlockData(x, y + 1, z), chunk, new Vector3(x, y + 1, z), c.getSlabPalettes(), @@ -122,7 +122,7 @@ public class MasterChunkGenerator implements TerraChunkGenerator { } paletteLevel++; } else if(y <= sea) { - chunk.setBlock(x, y, z, seaPalette.get(sea - y, x + xOrig, z + zOrig)); + 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); } @@ -144,18 +144,18 @@ public class MasterChunkGenerator implements TerraChunkGenerator { private void prepareBlockPartFloor(BlockData down, BlockData orig, ChunkGenerator.ChunkData chunk, Vector3 block, Map> slabs, Map> stairs, double thresh, Sampler sampler) { - if(sampler.sample(block.getBlockX(), block.getBlockY() - 0.4, block.getBlockZ()) > thresh) { + if(sampler.sample(block.getX(), block.getY() - 0.4, block.getZ()) > thresh) { if(stairs != null) { Palette stairPalette = stairs.get(down.getMaterial()); if(stairPalette != null) { - BlockData stair = stairPalette.get(0, block.getBlockX(), block.getBlockZ()).clone(); + BlockData stair = stairPalette.get(0, block.getX(), block.getY(), block.getZ()).clone(); if(stair instanceof Stairs) { Stairs stairNew = (Stairs) stair; if(placeStair(orig, chunk, block, thresh, sampler, stairNew)) return; // Successfully placed part. } } } - BlockData slab = slabs.getOrDefault(down.getMaterial(), blank).get(0, block.getBlockX(), block.getBlockZ()); + BlockData slab = slabs.getOrDefault(down.getMaterial(), blank).get(0, block.getX(), block.getY(), block.getZ()); if(slab instanceof Waterlogged) { ((Waterlogged) slab).setWaterlogged(orig.matches(water)); } else if(orig.matches(water)) return; @@ -165,11 +165,11 @@ public class MasterChunkGenerator implements TerraChunkGenerator { private void prepareBlockPartCeiling(BlockData up, BlockData orig, ChunkGenerator.ChunkData chunk, Vector3 block, Map> slabs, Map> stairs, double thresh, Sampler sampler) { - if(sampler.sample(block.getBlockX(), block.getBlockY() + 0.4, block.getBlockZ()) > thresh) { + if(sampler.sample(block.getX(), block.getY() + 0.4, block.getZ()) > thresh) { if(stairs != null) { Palette stairPalette = stairs.get(up.getMaterial()); if(stairPalette != null) { - BlockData stair = stairPalette.get(0, block.getBlockX(), block.getBlockZ()).clone(); + BlockData stair = stairPalette.get(0, block.getX(), block.getY(), block.getZ()).clone(); if(stair instanceof Stairs) { Stairs stairNew = (Stairs) stair.clone(); stairNew.setHalf(Bisected.Half.TOP); @@ -177,7 +177,7 @@ public class MasterChunkGenerator implements TerraChunkGenerator { } } } - BlockData slab = slabs.getOrDefault(up.getMaterial(), blank).get(0, block.getBlockX(), block.getBlockZ()).clone(); + BlockData slab = slabs.getOrDefault(up.getMaterial(), blank).get(0, block.getX(), block.getY(), block.getZ()).clone(); if(slab instanceof Bisected) ((Bisected) slab).setHalf(Bisected.Half.TOP); if(slab instanceof Slab) ((Slab) slab).setType(Slab.Type.TOP); if(slab instanceof Waterlogged) { @@ -189,14 +189,14 @@ public class MasterChunkGenerator implements TerraChunkGenerator { private boolean placeStair(BlockData orig, ChunkGenerator.ChunkData chunk, Vector3 block, double thresh, Sampler sampler, Stairs stairNew) { - if(sampler.sample(block.getBlockX() - 0.55, block.getBlockY(), block.getBlockZ()) > thresh) { + if(sampler.sample(block.getBlockX() - 0.55, block.getY(), block.getZ()) > thresh) { stairNew.setFacing(BlockFace.WEST); - } else if(sampler.sample(block.getBlockX(), block.getBlockY(), block.getBlockZ() - 0.55) > thresh) { + } else if(sampler.sample(block.getBlockX(), block.getY(), block.getZ() - 0.55) > thresh) { stairNew.setFacing(BlockFace.NORTH); - } else if(sampler.sample(block.getBlockX(), block.getBlockY(), block.getBlockZ() + 0.55) > thresh) { + } else if(sampler.sample(block.getBlockX(), block.getY(), block.getZ() + 0.55) > thresh) { stairNew.setFacing(BlockFace.SOUTH); - } else if(sampler.sample(block.getBlockX() + 0.55, block.getBlockY(), block.getBlockZ()) > thresh) { + } else if(sampler.sample(block.getX() + 0.55, block.getY(), block.getZ()) > thresh) { stairNew.setFacing(BlockFace.EAST); } else stairNew = null; if(stairNew != null) { diff --git a/common/src/main/java/com/dfsek/terra/population/items/flora/TerraFlora.java b/common/src/main/java/com/dfsek/terra/population/items/flora/TerraFlora.java index 34b2b974a..28e892bde 100644 --- a/common/src/main/java/com/dfsek/terra/population/items/flora/TerraFlora.java +++ b/common/src/main/java/com/dfsek/terra/population/items/flora/TerraFlora.java @@ -106,7 +106,7 @@ public class TerraFlora implements Flora { for(int i = 0; FastMath.abs(i) < size; i += c) { // Down if ceiling, up if floor int lvl = (FastMath.abs(i)); - BlockData data = floraPalette.get((ceiling ? lvl : size - lvl - 1), location.getBlockX(), location.getBlockZ()).clone(); + BlockData data = floraPalette.get((ceiling ? lvl : size - lvl - 1), location.getX(), location.getY(), location.getZ()).clone(); if(doRotation) { if(data instanceof Directional) { ((Directional) data).setFacing(oneFace); From c59ab5d9178bf9591572dfff9e6153c7325678af Mon Sep 17 00:00:00 2001 From: dfsek Date: Mon, 11 Jan 2021 16:28:53 -0700 Subject: [PATCH 4/7] fix lookup issue --- .../dfsek/terra/config/loaders/config/NoiseBuilderLoader.java | 1 + 1 file changed, 1 insertion(+) diff --git a/common/src/main/java/com/dfsek/terra/config/loaders/config/NoiseBuilderLoader.java b/common/src/main/java/com/dfsek/terra/config/loaders/config/NoiseBuilderLoader.java index e83a8dd8a..f133c12b6 100644 --- a/common/src/main/java/com/dfsek/terra/config/loaders/config/NoiseBuilderLoader.java +++ b/common/src/main/java/com/dfsek/terra/config/loaders/config/NoiseBuilderLoader.java @@ -22,6 +22,7 @@ public class NoiseBuilderLoader implements TypeLoader { LOADER.registerLoader(FastNoiseLite.RotationType3D.class, (t, object, cf) -> FastNoiseLite.RotationType3D.valueOf((String) object)); LOADER.registerLoader(FastNoiseLite.CellularReturnType.class, (t, object, cf) -> FastNoiseLite.CellularReturnType.valueOf((String) object)); LOADER.registerLoader(FastNoiseLite.CellularDistanceFunction.class, (t, object, cf) -> FastNoiseLite.CellularDistanceFunction.valueOf((String) object)); + LOADER.registerLoader(NoiseBuilder.class, new NoiseBuilderLoader()); } @Override From 5c469ed37860ff465e662bd38a2cb45ce612316e Mon Sep 17 00:00:00 2001 From: dfsek Date: Mon, 11 Jan 2021 17:07:25 -0700 Subject: [PATCH 5/7] noise function flora and tree dist --- .../loaders/config/FloraLayerLoader.java | 19 +++++++++++---- .../loaders/config/TreeLayerLoader.java | 24 ++++++++++++------- .../terra/population/FloraPopulator.java | 2 +- .../dfsek/terra/population/TreePopulator.java | 2 +- .../population/items/PlaceableLayer.java | 4 +--- .../population/items/flora/FloraLayer.java | 6 ++--- .../population/items/tree/TreeLayer.java | 9 ++++--- 7 files changed, 38 insertions(+), 28 deletions(-) diff --git a/common/src/main/java/com/dfsek/terra/config/loaders/config/FloraLayerLoader.java b/common/src/main/java/com/dfsek/terra/config/loaders/config/FloraLayerLoader.java index 72990fd61..6939a9777 100644 --- a/common/src/main/java/com/dfsek/terra/config/loaders/config/FloraLayerLoader.java +++ b/common/src/main/java/com/dfsek/terra/config/loaders/config/FloraLayerLoader.java @@ -1,5 +1,6 @@ package com.dfsek.terra.config.loaders.config; +import com.dfsek.tectonic.exception.ConfigException; import com.dfsek.tectonic.exception.LoadException; import com.dfsek.tectonic.loading.ConfigLoader; import com.dfsek.tectonic.loading.TypeLoader; @@ -8,6 +9,7 @@ import com.dfsek.terra.api.math.Range; import com.dfsek.terra.api.math.noise.samplers.FastNoiseLite; import com.dfsek.terra.api.world.flora.Flora; import com.dfsek.terra.config.loaders.Types; +import com.dfsek.terra.generation.config.NoiseBuilder; import com.dfsek.terra.population.items.flora.FloraLayer; import java.lang.reflect.Type; @@ -23,12 +25,19 @@ public class FloraLayerLoader implements TypeLoader { if(range == null) throw new LoadException("Flora range unspecified"); ProbabilityCollection items = (ProbabilityCollection) configLoader.loadType(Types.FLORA_PROBABILITY_COLLECTION_TYPE, map.get("items")); - if(map.containsKey("simplex-frequency")) { - FastNoiseLite noiseLite = new FastNoiseLite(); - noiseLite.setFrequency((Double) map.get("simplex-frequency")); - return new FloraLayer(density, range, items, noiseLite); + NoiseBuilder sampler; + if(map.containsKey("distribution")) { + try { + sampler = new NoiseBuilderLoader().load(NoiseBuilder.class, map.get("distribution"), configLoader); + } catch(ConfigException e) { + throw new LoadException("Unable to load noise", e); + } + return new FloraLayer(density, range, items, sampler.build(2403)); } + sampler = new NoiseBuilder(); + sampler.setType(FastNoiseLite.NoiseType.WhiteNoise); + sampler.setDimensions(3); - return new FloraLayer(density, range, items, null); + return new FloraLayer(density, range, items, sampler.build(2403)); } } diff --git a/common/src/main/java/com/dfsek/terra/config/loaders/config/TreeLayerLoader.java b/common/src/main/java/com/dfsek/terra/config/loaders/config/TreeLayerLoader.java index 123718bf0..39237229d 100644 --- a/common/src/main/java/com/dfsek/terra/config/loaders/config/TreeLayerLoader.java +++ b/common/src/main/java/com/dfsek/terra/config/loaders/config/TreeLayerLoader.java @@ -1,5 +1,7 @@ package com.dfsek.terra.config.loaders.config; +import com.dfsek.tectonic.config.Configuration; +import com.dfsek.tectonic.exception.ConfigException; import com.dfsek.tectonic.exception.LoadException; import com.dfsek.tectonic.loading.ConfigLoader; import com.dfsek.tectonic.loading.TypeLoader; @@ -8,6 +10,7 @@ import com.dfsek.terra.api.math.Range; import com.dfsek.terra.api.math.noise.samplers.FastNoiseLite; import com.dfsek.terra.api.world.tree.Tree; import com.dfsek.terra.config.loaders.Types; +import com.dfsek.terra.generation.config.NoiseBuilder; import com.dfsek.terra.population.items.tree.TreeLayer; import java.lang.reflect.Type; @@ -15,10 +18,6 @@ import java.util.Map; @SuppressWarnings("unchecked") public class TreeLayerLoader implements TypeLoader { - - public TreeLayerLoader() { - } - @Override public TreeLayer load(Type type, Object o, ConfigLoader configLoader) throws LoadException { Map map = (Map) o; @@ -27,12 +26,19 @@ public class TreeLayerLoader implements TypeLoader { if(range == null) throw new LoadException("Tree range unspecified"); ProbabilityCollection items = (ProbabilityCollection) configLoader.loadType(Types.TREE_PROBABILITY_COLLECTION_TYPE, map.get("items")); - if(map.containsKey("simplex-frequency")) { - FastNoiseLite noiseLite = new FastNoiseLite(); - noiseLite.setFrequency((Double) map.get("simplex-frequency")); - return new TreeLayer(density, range, items, noiseLite); + NoiseBuilder sampler = new NoiseBuilder(); + if(map.containsKey("distribution")) { + try { + configLoader.load(sampler, new Configuration((Map) map.get("distribution"))); + } catch(ConfigException e) { + throw new LoadException("Unable to load noise", e); + } + return new TreeLayer(density, range, items, sampler.build(2403)); } - return new TreeLayer(density, range, items, null); + sampler.setType(FastNoiseLite.NoiseType.WhiteNoise); + sampler.setDimensions(3); + + return new TreeLayer(density, range, items, sampler.build(2403)); } } diff --git a/common/src/main/java/com/dfsek/terra/population/FloraPopulator.java b/common/src/main/java/com/dfsek/terra/population/FloraPopulator.java index 09aeca00e..bd41d9851 100644 --- a/common/src/main/java/com/dfsek/terra/population/FloraPopulator.java +++ b/common/src/main/java/com/dfsek/terra/population/FloraPopulator.java @@ -55,7 +55,7 @@ public class FloraPopulator implements TerraBlockPopulator { if(entry.getValue().size() <= iter) continue; finished = false; FloraLayer layer = entry.getValue().get(iter); - if(layer.getDensity() >= random.nextDouble() * 100D) layer.place(chunk, entry.getKey(), random); + if(layer.getDensity() >= random.nextDouble() * 100D) layer.place(chunk, entry.getKey()); } iter++; } diff --git a/common/src/main/java/com/dfsek/terra/population/TreePopulator.java b/common/src/main/java/com/dfsek/terra/population/TreePopulator.java index 2d3c4d212..70bf9164b 100644 --- a/common/src/main/java/com/dfsek/terra/population/TreePopulator.java +++ b/common/src/main/java/com/dfsek/terra/population/TreePopulator.java @@ -42,7 +42,7 @@ public class TreePopulator implements TerraBlockPopulator { UserDefinedBiome biome = (UserDefinedBiome) grid.getBiome((chunk.getX() << 4) + x, (chunk.getZ() << 4) + z, GenerationPhase.POPULATE); for(TreeLayer layer : biome.getConfig().getTrees()) { if(layer.getDensity() >= random.nextDouble() * 100) - layer.place(chunk, new Vector2(offset(random, x), offset(random, z)), random); + layer.place(chunk, new Vector2(offset(random, x), offset(random, z))); } } } diff --git a/common/src/main/java/com/dfsek/terra/population/items/PlaceableLayer.java b/common/src/main/java/com/dfsek/terra/population/items/PlaceableLayer.java index 1f68c579a..479610d2e 100644 --- a/common/src/main/java/com/dfsek/terra/population/items/PlaceableLayer.java +++ b/common/src/main/java/com/dfsek/terra/population/items/PlaceableLayer.java @@ -6,8 +6,6 @@ import com.dfsek.terra.api.math.noise.samplers.NoiseSampler; import com.dfsek.terra.api.math.vector.Vector2; import com.dfsek.terra.api.platform.world.Chunk; -import java.util.Random; - public abstract class PlaceableLayer { protected final double density; protected final Range level; @@ -37,5 +35,5 @@ public abstract class PlaceableLayer { return layer; } - public abstract void place(Chunk chunk, Vector2 coords, Random random); + public abstract void place(Chunk chunk, Vector2 coords); } diff --git a/common/src/main/java/com/dfsek/terra/population/items/flora/FloraLayer.java b/common/src/main/java/com/dfsek/terra/population/items/flora/FloraLayer.java index 66799f357..48e39c35f 100644 --- a/common/src/main/java/com/dfsek/terra/population/items/flora/FloraLayer.java +++ b/common/src/main/java/com/dfsek/terra/population/items/flora/FloraLayer.java @@ -8,8 +8,6 @@ import com.dfsek.terra.api.platform.world.Chunk; import com.dfsek.terra.api.world.flora.Flora; import com.dfsek.terra.population.items.PlaceableLayer; -import java.util.Random; - public class FloraLayer extends PlaceableLayer { public FloraLayer(double density, Range level, ProbabilityCollection layer, NoiseSampler noise) { @@ -21,8 +19,8 @@ public class FloraLayer extends PlaceableLayer { } @Override - public void place(Chunk chunk, Vector2 coords, Random random) { - Flora item = noise == null ? layer.get(random) : layer.get(noise, (chunk.getX() << 4) + coords.getX(), (chunk.getZ() << 4) + coords.getZ()); + public void place(Chunk chunk, Vector2 coords) { + Flora item = layer.get(noise, (chunk.getX() << 4) + coords.getX(), (chunk.getZ() << 4) + coords.getZ()); item.getValidSpawnsAt(chunk, (int) coords.getX(), (int) coords.getZ(), level).forEach(block -> item.plant(block.getLocation())); } } diff --git a/common/src/main/java/com/dfsek/terra/population/items/tree/TreeLayer.java b/common/src/main/java/com/dfsek/terra/population/items/tree/TreeLayer.java index c30ecda71..88276dc96 100644 --- a/common/src/main/java/com/dfsek/terra/population/items/tree/TreeLayer.java +++ b/common/src/main/java/com/dfsek/terra/population/items/tree/TreeLayer.java @@ -9,8 +9,7 @@ import com.dfsek.terra.api.platform.block.BlockFace; import com.dfsek.terra.api.platform.world.Chunk; import com.dfsek.terra.api.world.tree.Tree; import com.dfsek.terra.population.items.PlaceableLayer; - -import java.util.Random; +import com.dfsek.terra.util.PopulationUtil; public class TreeLayer extends PlaceableLayer { @@ -19,13 +18,13 @@ public class TreeLayer extends PlaceableLayer { } @Override - public void place(Chunk chunk, Vector2 coords, Random random) { - Tree item = layer.get(random); + public void place(Chunk chunk, Vector2 coords) { + Tree item = layer.get(noise, coords.getX(), coords.getZ()); Block current = chunk.getBlock((int) coords.getX(), level.getMax(), (int) coords.getZ()); for(int ignored : level) { current = current.getRelative(BlockFace.DOWN); if(item.getSpawnable().contains(current.getType())) { - item.plant(current.getLocation().add(0, 1, 0), random); + item.plant(current.getLocation().add(0, 1, 0), PopulationUtil.getRandom(chunk)); } } } From 462b0af2259d458f8f23681c6aef4dee7fc0832c Mon Sep 17 00:00:00 2001 From: dfsek Date: Mon, 11 Jan 2021 20:23:41 -0700 Subject: [PATCH 6/7] normalization options --- .../com/dfsek/terra/api/GenericLoaders.java | 12 +++++++----- .../math/noise/samplers/LinearNormalizer.java | 17 +++++++++++++++++ .../api/math/noise/samplers/Normalizer.java | 6 +++++- .../loaders/config/NoiseBuilderLoader.java | 16 +++++++++------- .../terra/generation/config/NoiseBuilder.java | 15 +++++++++++++++ 5 files changed, 53 insertions(+), 13 deletions(-) create mode 100644 common/src/main/java/com/dfsek/terra/api/math/noise/samplers/LinearNormalizer.java diff --git a/common/src/main/java/com/dfsek/terra/api/GenericLoaders.java b/common/src/main/java/com/dfsek/terra/api/GenericLoaders.java index a3ec9ab35..72e886ab7 100644 --- a/common/src/main/java/com/dfsek/terra/api/GenericLoaders.java +++ b/common/src/main/java/com/dfsek/terra/api/GenericLoaders.java @@ -4,6 +4,7 @@ import com.dfsek.tectonic.loading.TypeRegistry; import com.dfsek.terra.api.math.GridSpawn; import com.dfsek.terra.api.math.ProbabilityCollection; import com.dfsek.terra.api.math.Range; +import com.dfsek.terra.api.math.noise.samplers.Normalizer; import com.dfsek.terra.api.platform.TerraPlugin; import com.dfsek.terra.biome.grid.master.TerraBiomeGrid; import com.dfsek.terra.biome.palette.PaletteHolder; @@ -48,16 +49,17 @@ public class GenericLoaders implements LoaderRegistrar { .registerLoader(PaletteHolder.class, new PaletteHolderLoader()) .registerLoader(PaletteLayer.class, new PaletteLayerLoader()) .registerLoader(FloraLayer.class, new FloraLayerLoader()) - .registerLoader(Ore.Type.class, (t, o, l) -> Ore.Type.valueOf((String) o)) + .registerLoader(Ore.Type.class, (t, o, l) -> Ore.Type.valueOf(o.toString())) .registerLoader(OreConfig.class, new OreConfigLoader()) .registerLoader(NoiseBuilder.class, new NoiseBuilderLoader()) .registerLoader(TreeLayer.class, new TreeLayerLoader()) .registerLoader(MaterialSet.class, new MaterialSetLoader()) .registerLoader(OreHolder.class, new OreHolderLoader()) .registerLoader(ImageLoader.class, new ImageLoaderLoader()) - .registerLoader(TerraBiomeGrid.Type.class, (t, o, l) -> TerraBiomeGrid.Type.valueOf((String) o)) - .registerLoader(ImageLoader.Channel.class, (t, o, l) -> ImageLoader.Channel.valueOf((String) o)) - .registerLoader(ImageLoader.Align.class, (t, o, l) -> ImageLoader.Align.valueOf((String) o)) - .registerLoader(TerraFlora.Search.class, (t, o, l) -> TerraFlora.Search.valueOf((String) o)); + .registerLoader(TerraBiomeGrid.Type.class, (t, o, l) -> TerraBiomeGrid.Type.valueOf(o.toString())) + .registerLoader(ImageLoader.Channel.class, (t, o, l) -> ImageLoader.Channel.valueOf(o.toString())) + .registerLoader(ImageLoader.Align.class, (t, o, l) -> ImageLoader.Align.valueOf(o.toString())) + .registerLoader(TerraFlora.Search.class, (t, o, l) -> TerraFlora.Search.valueOf(o.toString())) + .registerLoader(Normalizer.NormalType.class, (t, o, l) -> Normalizer.NormalType.valueOf(o.toString().toUpperCase())); } } diff --git a/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/LinearNormalizer.java b/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/LinearNormalizer.java new file mode 100644 index 000000000..bd56d7fac --- /dev/null +++ b/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/LinearNormalizer.java @@ -0,0 +1,17 @@ +package com.dfsek.terra.api.math.noise.samplers; + +public class LinearNormalizer extends Normalizer { + private final double min; + private final double max; + + public LinearNormalizer(NoiseSampler sampler, double min, double max) { + super(sampler); + this.min = min; + this.max = max; + } + + @Override + public double normalize(double in) { + return (in - min) * (2 / (max - min)) - 1; + } +} diff --git a/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/Normalizer.java b/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/Normalizer.java index 2d24939c7..ef18519e2 100644 --- a/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/Normalizer.java +++ b/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/Normalizer.java @@ -3,7 +3,7 @@ package com.dfsek.terra.api.math.noise.samplers; public abstract class Normalizer implements NoiseSampler { private final NoiseSampler sampler; - protected Normalizer(NoiseSampler sampler) { + public Normalizer(NoiseSampler sampler) { this.sampler = sampler; } @@ -18,4 +18,8 @@ public abstract class Normalizer implements NoiseSampler { public double getNoise(double x, double y, double z) { return normalize(sampler.getNoise(x, y, z)); } + + public enum NormalType { + LINEAR, NONE + } } diff --git a/common/src/main/java/com/dfsek/terra/config/loaders/config/NoiseBuilderLoader.java b/common/src/main/java/com/dfsek/terra/config/loaders/config/NoiseBuilderLoader.java index f133c12b6..2381a981e 100644 --- a/common/src/main/java/com/dfsek/terra/config/loaders/config/NoiseBuilderLoader.java +++ b/common/src/main/java/com/dfsek/terra/config/loaders/config/NoiseBuilderLoader.java @@ -6,6 +6,7 @@ import com.dfsek.tectonic.exception.LoadException; import com.dfsek.tectonic.loading.ConfigLoader; import com.dfsek.tectonic.loading.TypeLoader; import com.dfsek.terra.api.math.noise.samplers.FastNoiseLite; +import com.dfsek.terra.api.math.noise.samplers.Normalizer; import com.dfsek.terra.generation.config.NoiseBuilder; import java.lang.reflect.Type; @@ -16,13 +17,14 @@ public class NoiseBuilderLoader implements TypeLoader { private static final ConfigLoader LOADER = new ConfigLoader(); static { - LOADER.registerLoader(FastNoiseLite.NoiseType.class, (t, object, cf) -> FastNoiseLite.NoiseType.valueOf((String) object)); - LOADER.registerLoader(FastNoiseLite.FractalType.class, (t, object, cf) -> FastNoiseLite.FractalType.valueOf((String) object)); - LOADER.registerLoader(FastNoiseLite.DomainWarpType.class, (t, object, cf) -> FastNoiseLite.DomainWarpType.valueOf((String) object)); - LOADER.registerLoader(FastNoiseLite.RotationType3D.class, (t, object, cf) -> FastNoiseLite.RotationType3D.valueOf((String) object)); - LOADER.registerLoader(FastNoiseLite.CellularReturnType.class, (t, object, cf) -> FastNoiseLite.CellularReturnType.valueOf((String) object)); - LOADER.registerLoader(FastNoiseLite.CellularDistanceFunction.class, (t, object, cf) -> FastNoiseLite.CellularDistanceFunction.valueOf((String) object)); - LOADER.registerLoader(NoiseBuilder.class, new NoiseBuilderLoader()); + LOADER.registerLoader(FastNoiseLite.NoiseType.class, (t, object, cf) -> FastNoiseLite.NoiseType.valueOf((String) object)) + .registerLoader(FastNoiseLite.FractalType.class, (t, object, cf) -> FastNoiseLite.FractalType.valueOf((String) object)) + .registerLoader(FastNoiseLite.DomainWarpType.class, (t, object, cf) -> FastNoiseLite.DomainWarpType.valueOf((String) object)) + .registerLoader(FastNoiseLite.RotationType3D.class, (t, object, cf) -> FastNoiseLite.RotationType3D.valueOf((String) object)) + .registerLoader(FastNoiseLite.CellularReturnType.class, (t, object, cf) -> FastNoiseLite.CellularReturnType.valueOf((String) object)) + .registerLoader(FastNoiseLite.CellularDistanceFunction.class, (t, object, cf) -> FastNoiseLite.CellularDistanceFunction.valueOf((String) object)) + .registerLoader(NoiseBuilder.class, new NoiseBuilderLoader()) + .registerLoader(Normalizer.NormalType.class, (t, o, l) -> Normalizer.NormalType.valueOf(o.toString().toUpperCase())); } @Override diff --git a/common/src/main/java/com/dfsek/terra/generation/config/NoiseBuilder.java b/common/src/main/java/com/dfsek/terra/generation/config/NoiseBuilder.java index 0382f01d8..f2a33c226 100644 --- a/common/src/main/java/com/dfsek/terra/generation/config/NoiseBuilder.java +++ b/common/src/main/java/com/dfsek/terra/generation/config/NoiseBuilder.java @@ -4,7 +4,9 @@ import com.dfsek.tectonic.annotations.Default; import com.dfsek.tectonic.annotations.Value; import com.dfsek.tectonic.config.ConfigTemplate; import com.dfsek.terra.api.math.noise.samplers.FastNoiseLite; +import com.dfsek.terra.api.math.noise.samplers.LinearNormalizer; import com.dfsek.terra.api.math.noise.samplers.NoiseSampler; +import com.dfsek.terra.api.math.noise.samplers.Normalizer; @SuppressWarnings("FieldMayBeFinal") public class NoiseBuilder implements ConfigTemplate { @@ -76,6 +78,18 @@ public class NoiseBuilder implements ConfigTemplate { @Default private NoiseBuilder lookup; + @Value("normalize.type") + @Default + private Normalizer.NormalType normalType = Normalizer.NormalType.NONE; + + @Value("normalize.linear.min") + @Default + private double linearMin = -1D; + + @Value("normalize.linear.max") + @Default + private double linearMax = 1D; + public NoiseSampler build(int seed) { FastNoiseLite noise = new FastNoiseLite(seed + seedOffset); if(!fractalType.equals(FastNoiseLite.FractalType.None)) { @@ -101,6 +115,7 @@ public class NoiseBuilder implements ConfigTemplate { noise.setRotationType3D(rotationType3D); noise.setFrequency(frequency); + if(!normalType.equals(Normalizer.NormalType.NONE)) return new LinearNormalizer(noise, linearMin, linearMax); return noise; } From 5df511a940a4f6a9426e8da673c439b69dd9d48b Mon Sep 17 00:00:00 2001 From: dfsek Date: Mon, 11 Jan 2021 22:00:10 -0700 Subject: [PATCH 7/7] white noise micro opt --- .../api/math/noise/samplers/FastNoiseLite.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/FastNoiseLite.java b/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/FastNoiseLite.java index 5baefd7e2..e6b1dd67b 100644 --- a/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/FastNoiseLite.java +++ b/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/FastNoiseLite.java @@ -278,6 +278,7 @@ public class FastNoiseLite implements NoiseSampler { private static final int PRIME_Y = 1136930381; private static final int PRIME_Z = 1720413743; private static final NoiseSampler CELLULAR_LOOKUP_DEFAULT = new FastNoiseLite(); + private static final long POSITIVE_POW1 = 0b01111111111L << 52; // Bits that when applied to the exponent/sign section of a double, produce a positive number with a power of 1. private int mSeed = 1337; private double mFrequency = 0.01f; private NoiseType mNoiseType = NoiseType.OpenSimplex2; @@ -288,7 +289,7 @@ public class FastNoiseLite implements NoiseSampler { private double mLacunarity = 2.0f; private double mGain = 0.5f; private double mWeightedStrength = 0.0f; - private double mPingPongStength = 2.0f; + private double mPingPongStrength = 2.0f; private double mFractalBounding = 1 / 1.75f; private CellularDistanceFunction mCellularDistanceFunction = CellularDistanceFunction.EuclideanSq; private CellularReturnType mCellularReturnType = CellularReturnType.Distance; @@ -569,7 +570,7 @@ public class FastNoiseLite implements NoiseSampler { * Default: 2.0 */ public void setFractalPingPongStrength(double pingPongStrength) { - mPingPongStength = pingPongStrength; + mPingPongStrength = pingPongStrength; } /** @@ -886,7 +887,7 @@ public class FastNoiseLite implements NoiseSampler { double amp = mFractalBounding; for(int i = 0; i < mOctaves; i++) { - double noise = pingPong((genNoiseSingle(seed++, x, y) + 1) * mPingPongStength); + double noise = pingPong((genNoiseSingle(seed++, x, y) + 1) * mPingPongStrength); sum += (noise - 0.5f) * 2 * amp; amp *= lerp(1.0f, noise, mWeightedStrength); @@ -905,7 +906,7 @@ public class FastNoiseLite implements NoiseSampler { double amp = mFractalBounding; for(int i = 0; i < mOctaves; i++) { - double noise = pingPong((genNoiseSingle(seed++, x, y, z) + 1) * mPingPongStength); + double noise = pingPong((genNoiseSingle(seed++, x, y, z) + 1) * mPingPongStrength); sum += (noise - 0.5f) * 2 * amp; amp *= lerp(1.0f, noise, mWeightedStrength); @@ -1630,7 +1631,7 @@ public class FastNoiseLite implements NoiseSampler { long hashZ = hash(Double.doubleToRawLongBits(y) ^ seed); long hash = (((hashX ^ (hashX >>> 32)) + ((hashZ ^ (hashZ >>> 32)) << 32)) ^ seed) + Double.doubleToRawLongBits(z); long base = ((hash(hash)) & 0x000fffffffffffffL) - + (0b01111111111L << 52); // Sign and exponent + + POSITIVE_POW1; // Sign and exponent return (Double.longBitsToDouble(base) - 1.5) * 2; } @@ -1639,7 +1640,7 @@ public class FastNoiseLite implements NoiseSampler { long hashZ = hash(Double.doubleToRawLongBits(y) ^ seed); long hash = ((hashX ^ (hashX >>> 32)) + ((hashZ ^ (hashZ >>> 32)) << 32)) ^ seed; long base = (hash(hash) & 0x000fffffffffffffL) - + (0b01111111111L << 52); // Sign and exponent + + POSITIVE_POW1; // Sign and exponent return (Double.longBitsToDouble(base) - 1.5) * 2; }