From e306a0fd09e39f1ea17457dc0ff5252b097e3856 Mon Sep 17 00:00:00 2001 From: dfsek Date: Fri, 29 Jan 2021 10:09:19 -0700 Subject: [PATCH] ImageSampler implementation --- .../noise/samplers/DomainWarpedSampler.java | 36 ++++++++++ .../math/noise/samplers/FastNoiseLite.java | 19 +---- .../api/math/noise/samplers/ImageSampler.java | 69 +++++++++++++++++++ .../dfsek/terra/config/GenericLoaders.java | 5 +- .../sampler/NoiseSamplerBuilderLoader.java | 30 ++++++++ .../dfsek/terra/config/pack/ConfigPack.java | 5 +- .../world/generation/config/NoiseBuilder.java | 34 --------- common/src/test/java/noise/NoiseTool.java | 8 ++- 8 files changed, 148 insertions(+), 58 deletions(-) create mode 100644 common/src/main/java/com/dfsek/terra/api/math/noise/samplers/DomainWarpedSampler.java create mode 100644 common/src/main/java/com/dfsek/terra/api/math/noise/samplers/ImageSampler.java diff --git a/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/DomainWarpedSampler.java b/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/DomainWarpedSampler.java new file mode 100644 index 000000000..4f50254d1 --- /dev/null +++ b/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/DomainWarpedSampler.java @@ -0,0 +1,36 @@ +package com.dfsek.terra.api.math.noise.samplers; + +public class DomainWarpedSampler implements NoiseSampler { + private final NoiseSampler function; + private final NoiseSampler warp; + private final int seed; + + public DomainWarpedSampler(NoiseSampler function, NoiseSampler warp, int seed) { + this.function = function; + this.warp = warp; + this.seed = seed; + } + + @Override + public double getNoise(double x, double y) { + return function.getNoise( + x + warp.getNoiseSeeded(seed, x, y), + y + warp.getNoiseSeeded(seed + 1, x, y) + ); + } + + @Override + public double getNoise(double x, double y, double z) { + return 0; + } + + @Override + public double getNoiseSeeded(int seed, double x, double y) { + return 0; + } + + @Override + public double getNoiseSeeded(int seed, double x, double y, double z) { + return 0; + } +} 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 81257f964..add05ac0f 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 @@ -295,7 +295,7 @@ public class FastNoiseLite implements NoiseSampler { private CellularDistanceFunction mCellularDistanceFunction = CellularDistanceFunction.EuclideanSq; private CellularReturnType mCellularReturnType = CellularReturnType.Distance; private double mCellularJitterModifier = 1.0; - private DomainWarpType mDomainWarpType = DomainWarpType.None; + private DomainWarpType mDomainWarpType = DomainWarpType.OpenSimplex2; private TransformType3D mWarpTransformType3D = TransformType3D.DefaultOpenSimplex2; private double mDomainWarpAmp = 1.0; private NoiseSampler cellularNoiseLookup = CELLULAR_LOOKUP_DEFAULT; @@ -652,12 +652,6 @@ public class FastNoiseLite implements NoiseSampler { @Override public double getNoiseSeeded(int seed, double x, double y) { - if(!mDomainWarpType.equals(DomainWarpType.None)) { - Vector2 dWarp = new Vector2(x, y); - domainWarp(dWarp); - x = dWarp.getX(); - y = dWarp.getZ(); - } x *= mFrequency; y *= mFrequency; @@ -691,14 +685,6 @@ public class FastNoiseLite implements NoiseSampler { @Override public double getNoiseSeeded(int seed, double x, double y, double z) { - if(!mDomainWarpType.equals(DomainWarpType.None)) { - Vector3 dWarp = new Vector3(x, y, z); - domainWarp(dWarp); - x = dWarp.getX(); - y = dWarp.getY(); - z = dWarp.getZ(); - } - x *= mFrequency; y *= mFrequency; z *= mFrequency; @@ -2658,8 +2644,7 @@ public class FastNoiseLite implements NoiseSampler { OpenSimplex2, OpenSimplex2Reduced, BasicGrid, - Function, - None + Function } diff --git a/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/ImageSampler.java b/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/ImageSampler.java new file mode 100644 index 000000000..4fc8d1ece --- /dev/null +++ b/common/src/main/java/com/dfsek/terra/api/math/noise/samplers/ImageSampler.java @@ -0,0 +1,69 @@ +package com.dfsek.terra.api.math.noise.samplers; + +import net.jafama.FastMath; + +import java.awt.image.BufferedImage; + +public class ImageSampler implements NoiseSampler { + private final BufferedImage image; + private final Channel channel; + + private final double frequency; + + public ImageSampler(BufferedImage image, Channel channel, double frequency) { + this.image = image; + this.channel = channel; + this.frequency = frequency; + } + + @Override + public double getNoise(double x, double y) { + return ((channel.getChannel(image.getRGB(FastMath.floorMod(FastMath.floorToInt(x * frequency), image.getWidth()), FastMath.floorMod(FastMath.floorToInt(y * frequency), image.getHeight()))) / 255D) - 0.5) * 2; + } + + @Override + public double getNoise(double x, double y, double z) { + return getNoise(x, y); + } + + @Override + public double getNoiseSeeded(int seed, double x, double y) { + return getNoise(x, y); + } + + @Override + public double getNoiseSeeded(int seed, double x, double y, double z) { + return getNoise(x, y, z); + } + + public enum Channel { + RED { + @Override + public int getChannel(int mashed) { + return (mashed >> 16) & 0xff; + } + }, GREEN { + @Override + public int getChannel(int mashed) { + return (mashed >> 8) & 0xff; + } + }, BLUE { + @Override + public int getChannel(int mashed) { + return mashed & 0xff; + } + }, GRAYSCALE { + @Override + public int getChannel(int mashed) { + return (RED.getChannel(mashed) + GREEN.getChannel(mashed) + BLUE.getChannel(mashed)) / 3; + } + }, ALPHA { + @Override + public int getChannel(int mashed) { + return (mashed >> 24) & 0xff; + } + }; + + public abstract int getChannel(int mashed); + } +} diff --git a/common/src/main/java/com/dfsek/terra/config/GenericLoaders.java b/common/src/main/java/com/dfsek/terra/config/GenericLoaders.java index 329857af6..c2999609d 100644 --- a/common/src/main/java/com/dfsek/terra/config/GenericLoaders.java +++ b/common/src/main/java/com/dfsek/terra/config/GenericLoaders.java @@ -8,7 +8,6 @@ import com.dfsek.terra.api.math.ProbabilityCollection; import com.dfsek.terra.api.math.Range; import com.dfsek.terra.api.math.noise.normalizer.Normalizer; import com.dfsek.terra.api.math.noise.samplers.FastNoiseLite; -import com.dfsek.terra.api.util.seeded.NoiseSeeded; import com.dfsek.terra.api.world.palette.holder.PaletteHolder; import com.dfsek.terra.api.world.palette.holder.PaletteLayerHolder; import com.dfsek.terra.config.loaders.MaterialSetLoader; @@ -19,7 +18,6 @@ import com.dfsek.terra.config.loaders.config.GridSpawnLoader; import com.dfsek.terra.config.loaders.config.OreConfigLoader; import com.dfsek.terra.config.loaders.config.OreHolderLoader; import com.dfsek.terra.config.loaders.config.TreeLayerLoader; -import com.dfsek.terra.config.loaders.config.sampler.NoiseSamplerBuilderLoader; import com.dfsek.terra.config.loaders.palette.PaletteHolderLoader; import com.dfsek.terra.config.loaders.palette.PaletteLayerLoader; import com.dfsek.terra.util.MaterialSet; @@ -58,7 +56,6 @@ public class GenericLoaders implements LoaderRegistrar { .registerLoader(FastNoiseLite.CellularDistanceFunction.class, (t, object, cf) -> FastNoiseLite.CellularDistanceFunction.valueOf((String) object)) .registerLoader(Normalizer.NormalType.class, (t, o, l) -> Normalizer.NormalType.valueOf(o.toString().toUpperCase())) .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())) - .registerLoader(NoiseSeeded.class, new NoiseSamplerBuilderLoader()); + .registerLoader(Normalizer.NormalType.class, (t, o, l) -> Normalizer.NormalType.valueOf(o.toString().toUpperCase())); } } diff --git a/common/src/main/java/com/dfsek/terra/config/loaders/config/sampler/NoiseSamplerBuilderLoader.java b/common/src/main/java/com/dfsek/terra/config/loaders/config/sampler/NoiseSamplerBuilderLoader.java index 5f646d06f..c750b8775 100644 --- a/common/src/main/java/com/dfsek/terra/config/loaders/config/sampler/NoiseSamplerBuilderLoader.java +++ b/common/src/main/java/com/dfsek/terra/config/loaders/config/sampler/NoiseSamplerBuilderLoader.java @@ -8,15 +8,26 @@ import com.dfsek.tectonic.loading.TypeLoader; import com.dfsek.terra.api.math.noise.normalizer.LinearNormalizer; import com.dfsek.terra.api.math.noise.normalizer.NormalNormalizer; import com.dfsek.terra.api.math.noise.normalizer.Normalizer; +import com.dfsek.terra.api.math.noise.samplers.ImageSampler; import com.dfsek.terra.api.math.noise.samplers.NoiseSampler; import com.dfsek.terra.api.util.seeded.NoiseSeeded; +import com.dfsek.terra.config.fileloaders.Loader; import com.dfsek.terra.world.generation.config.NoiseBuilder; +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.IOException; import java.lang.reflect.Type; import java.util.Map; @SuppressWarnings("unchecked") public class NoiseSamplerBuilderLoader implements TypeLoader { + private final Loader fileAccess; + + public NoiseSamplerBuilderLoader(Loader fileAccess) { + this.fileAccess = fileAccess; + } + @Override public NoiseSeeded load(Type t, Object c, ConfigLoader loader) throws LoadException { Map map = (Map) c; @@ -100,6 +111,25 @@ public class NoiseSamplerBuilderLoader implements TypeLoader { }; } } + } else if(samplerType.equals("IMAGE")) { + try { + BufferedImage image = ImageIO.read(fileAccess.get(map.get("image").toString())); + ImageSampler.Channel channel = ImageSampler.Channel.valueOf(map.get("channel").toString()); + double frequency = Double.parseDouble(map.get("frequency").toString()); + return new NoiseSeeded() { + @Override + public NoiseSampler apply(Long seed) { + return new ImageSampler(image, channel, frequency); + } + + @Override + public int getDimensions() { + return dimensions; + } + }; + } catch(IOException | NullPointerException e) { + throw new LoadException("Failed to load image", e); + } } throw new LoadException("No such noise sampler type \"" + samplerType + "\""); diff --git a/common/src/main/java/com/dfsek/terra/config/pack/ConfigPack.java b/common/src/main/java/com/dfsek/terra/config/pack/ConfigPack.java index 9ca57ae16..ff4f5d4fc 100644 --- a/common/src/main/java/com/dfsek/terra/config/pack/ConfigPack.java +++ b/common/src/main/java/com/dfsek/terra/config/pack/ConfigPack.java @@ -9,6 +9,7 @@ import com.dfsek.terra.api.LoaderRegistrar; import com.dfsek.terra.api.core.TerraPlugin; import com.dfsek.terra.api.structures.loot.LootTable; import com.dfsek.terra.api.structures.script.StructureScript; +import com.dfsek.terra.api.util.seeded.NoiseSeeded; import com.dfsek.terra.api.world.flora.Flora; import com.dfsek.terra.api.world.palette.Palette; import com.dfsek.terra.api.world.tree.Tree; @@ -27,6 +28,7 @@ import com.dfsek.terra.config.fileloaders.Loader; import com.dfsek.terra.config.fileloaders.ZIPLoader; import com.dfsek.terra.config.lang.LangUtil; import com.dfsek.terra.config.loaders.config.biome.BiomeProviderBuilderLoader; +import com.dfsek.terra.config.loaders.config.sampler.NoiseSamplerBuilderLoader; import com.dfsek.terra.config.templates.AbstractableTemplate; import com.dfsek.terra.config.templates.BiomeTemplate; import com.dfsek.terra.config.templates.FloraTemplate; @@ -238,7 +240,8 @@ public class ConfigPack implements LoaderRegistrar { .registerLoader(StructureScript.class, scriptRegistry) .registerLoader(TerraStructure.class, structureRegistry) .registerLoader(LootTable.class, lootRegistry) - .registerLoader(BiomeProvider.BiomeProviderBuilder.class, new BiomeProviderBuilderLoader(main, biomeRegistry, loader)); + .registerLoader(BiomeProvider.BiomeProviderBuilder.class, new BiomeProviderBuilderLoader(main, biomeRegistry, loader)) + .registerLoader(NoiseSeeded.class, new NoiseSamplerBuilderLoader(loader)); } public ScriptRegistry getScriptRegistry() { diff --git a/common/src/main/java/com/dfsek/terra/world/generation/config/NoiseBuilder.java b/common/src/main/java/com/dfsek/terra/world/generation/config/NoiseBuilder.java index fe3130bb9..33cd79676 100644 --- a/common/src/main/java/com/dfsek/terra/world/generation/config/NoiseBuilder.java +++ b/common/src/main/java/com/dfsek/terra/world/generation/config/NoiseBuilder.java @@ -57,18 +57,6 @@ public class NoiseBuilder implements ConfigTemplate { @Default private double cellularJitter = 1.0D; - @Value("domain-warp.type") - @Default - private FastNoiseLite.DomainWarpType domainWarpType = FastNoiseLite.DomainWarpType.None; - - @Value("domain-warp.amplitude") - @Default - private double domainWarpAmp = 1.0D; - - @Value("domain-warp.function") - @Default - private NoiseSeeded domainWarp; - @Value("rotation-type") @Default private FastNoiseLite.RotationType3D rotationType3D = FastNoiseLite.RotationType3D.None; @@ -101,10 +89,6 @@ public class NoiseBuilder implements ConfigTemplate { noise.setNoiseType(type); - noise.setDomainWarpType(domainWarpType); - noise.setDomainWarpAmp(domainWarpAmp); - if(domainWarp != null) noise.setDomainWarpFunction(domainWarp.apply(seed)); - noise.setRotationType3D(rotationType3D); noise.setFrequency(frequency); @@ -146,15 +130,6 @@ public class NoiseBuilder implements ConfigTemplate { return this; } - public FastNoiseLite.DomainWarpType getDomainWarpType() { - return domainWarpType; - } - - public NoiseBuilder setDomainWarpType(FastNoiseLite.DomainWarpType domainWarpType) { - this.domainWarpType = domainWarpType; - return this; - } - public double getCellularJitter() { return cellularJitter; } @@ -164,15 +139,6 @@ public class NoiseBuilder implements ConfigTemplate { return this; } - public double getDomainWarpAmp() { - return domainWarpAmp; - } - - public NoiseBuilder setDomainWarpAmp(double domainWarpAmp) { - this.domainWarpAmp = domainWarpAmp; - return this; - } - public double getFractalGain() { return fractalGain; } diff --git a/common/src/test/java/noise/NoiseTool.java b/common/src/test/java/noise/NoiseTool.java index 9f268936b..7ad825786 100644 --- a/common/src/test/java/noise/NoiseTool.java +++ b/common/src/test/java/noise/NoiseTool.java @@ -6,6 +6,7 @@ import com.dfsek.terra.api.math.ProbabilityCollection; import com.dfsek.terra.api.math.noise.samplers.NoiseSampler; import com.dfsek.terra.api.util.seeded.NoiseSeeded; import com.dfsek.terra.config.GenericLoaders; +import com.dfsek.terra.config.fileloaders.FolderLoader; import com.dfsek.terra.config.loaders.ProbabilityCollectionLoader; import com.dfsek.terra.config.loaders.config.sampler.NoiseSamplerBuilderLoader; import org.apache.commons.io.FileUtils; @@ -18,6 +19,7 @@ import java.awt.image.BufferedImage; import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.nio.file.Paths; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicInteger; @@ -90,10 +92,12 @@ public class NoiseTool { private static BufferedImage load(int seed, boolean distribution, boolean chunk) throws ConfigException, IOException { long s = System.nanoTime(); + FolderLoader folderLoader = new FolderLoader(Paths.get("./")); + ConfigLoader loader = new ConfigLoader(); - loader.registerLoader(NoiseSeeded.class, new NoiseSamplerBuilderLoader()) + loader.registerLoader(NoiseSeeded.class, new NoiseSamplerBuilderLoader(folderLoader)) .registerLoader(ProbabilityCollection.class, new ProbabilityCollectionLoader()); - + new GenericLoaders(null).register(loader); NoiseConfigTemplate template = new NoiseConfigTemplate();