mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-06-18 14:50:57 +00:00
p1
This commit is contained in:
@@ -27,7 +27,6 @@ import art.arcane.iris.engine.object.*;
|
|||||||
import art.arcane.volmlib.util.collection.KList;
|
import art.arcane.volmlib.util.collection.KList;
|
||||||
import art.arcane.iris.util.project.context.IrisContext;
|
import art.arcane.iris.util.project.context.IrisContext;
|
||||||
import art.arcane.iris.util.common.data.DataProvider;
|
import art.arcane.iris.util.common.data.DataProvider;
|
||||||
import art.arcane.iris.util.project.interpolation.IrisInterpolation.NoiseKey;
|
|
||||||
import art.arcane.volmlib.util.math.M;
|
import art.arcane.volmlib.util.math.M;
|
||||||
import art.arcane.volmlib.util.math.RNG;
|
import art.arcane.volmlib.util.math.RNG;
|
||||||
import art.arcane.iris.util.project.noise.CNG;
|
import art.arcane.iris.util.project.noise.CNG;
|
||||||
@@ -83,6 +82,8 @@ public class IrisComplex implements DataProvider {
|
|||||||
private ProceduralStream<BlockData> fluidStream;
|
private ProceduralStream<BlockData> fluidStream;
|
||||||
private IrisBiome focusBiome;
|
private IrisBiome focusBiome;
|
||||||
private IrisRegion focusRegion;
|
private IrisRegion focusRegion;
|
||||||
|
private Map<IrisInterpolator, IdentityHashMap<IrisBiome, GeneratorBounds>> generatorBounds;
|
||||||
|
private Set<IrisBiome> generatorBiomes;
|
||||||
|
|
||||||
public IrisComplex(Engine engine) {
|
public IrisComplex(Engine engine) {
|
||||||
this(engine, false);
|
this(engine, false);
|
||||||
@@ -97,6 +98,7 @@ public class IrisComplex implements DataProvider {
|
|||||||
double height = engine.getMaxHeight();
|
double height = engine.getMaxHeight();
|
||||||
fluidHeight = engine.getDimension().getFluidHeight();
|
fluidHeight = engine.getDimension().getFluidHeight();
|
||||||
generators = new HashMap<>();
|
generators = new HashMap<>();
|
||||||
|
generatorBiomes = Collections.newSetFromMap(new IdentityHashMap<>());
|
||||||
focusBiome = engine.getFocus();
|
focusBiome = engine.getFocus();
|
||||||
focusRegion = engine.getFocusRegion();
|
focusRegion = engine.getFocusRegion();
|
||||||
Map<InferredType, ProceduralStream<IrisBiome>> inferredStreams = new HashMap<>();
|
Map<InferredType, ProceduralStream<IrisBiome>> inferredStreams = new HashMap<>();
|
||||||
@@ -116,9 +118,20 @@ public class IrisComplex implements DataProvider {
|
|||||||
.getAllBiomes(this)
|
.getAllBiomes(this)
|
||||||
.forEach(this::registerGenerators));
|
.forEach(this::registerGenerators));
|
||||||
}
|
}
|
||||||
|
generatorBounds = buildGeneratorBounds(engine);
|
||||||
boolean legacy = engine.getDimension().isLegacyRarity();
|
boolean legacy = engine.getDimension().isLegacyRarity();
|
||||||
overlayStream = ProceduralStream.ofDouble((x, z) -> 0.0D).waste("Overlay Stream");
|
KList<IrisShapedGeneratorStyle> overlayNoise = engine.getDimension().getOverlayNoise();
|
||||||
engine.getDimension().getOverlayNoise().forEach(i -> overlayStream = overlayStream.add((x, z) -> i.get(rng, getData(), x, z)));
|
overlayStream = overlayNoise.isEmpty()
|
||||||
|
? ProceduralStream.ofDouble((x, z) -> 0.0D).waste("Overlay Stream")
|
||||||
|
: ProceduralStream.ofDouble((x, z) -> {
|
||||||
|
double value = 0D;
|
||||||
|
|
||||||
|
for (IrisShapedGeneratorStyle style : overlayNoise) {
|
||||||
|
value += style.get(rng, getData(), x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}).waste("Overlay Stream");
|
||||||
rockStream = engine.getDimension().getRockPalette().getLayerGenerator(rng.nextParallelRNG(45), data).stream()
|
rockStream = engine.getDimension().getRockPalette().getLayerGenerator(rng.nextParallelRNG(45), data).stream()
|
||||||
.select(engine.getDimension().getRockPalette().getBlockData(data)).waste("Rock Stream");
|
.select(engine.getDimension().getRockPalette().getBlockData(data)).waste("Rock Stream");
|
||||||
fluidStream = engine.getDimension().getFluidPalette().getLayerGenerator(rng.nextParallelRNG(78), data).stream()
|
fluidStream = engine.getDimension().getFluidPalette().getLayerGenerator(rng.nextParallelRNG(78), data).stream()
|
||||||
@@ -306,18 +319,27 @@ public class IrisComplex implements DataProvider {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
HashMap<NoiseKey, IrisBiome> cache = new HashMap<>(64);
|
CoordinateBiomeCache sampleCache = new CoordinateBiomeCache(64);
|
||||||
|
IdentityHashMap<IrisBiome, GeneratorBounds> cachedBounds = generatorBounds.get(interpolator);
|
||||||
|
IdentityHashMap<IrisBiome, GeneratorBounds> localBounds = new IdentityHashMap<>(8);
|
||||||
double hi = interpolator.interpolate(x, z, (xx, zz) -> {
|
double hi = interpolator.interpolate(x, z, (xx, zz) -> {
|
||||||
try {
|
try {
|
||||||
IrisBiome bx = baseBiomeStream.get(xx, zz);
|
IrisBiome bx = sampleCache.get(xx, zz);
|
||||||
cache.put(new NoiseKey(xx, zz), bx);
|
if (bx == null) {
|
||||||
double b = 0;
|
bx = baseBiomeStream.get(xx, zz);
|
||||||
|
sampleCache.put(xx, zz, bx);
|
||||||
for (IrisGenerator gen : generators) {
|
|
||||||
b += bx.getGenLinkMax(gen.getLoadKey(), engine);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return b;
|
GeneratorBounds bounds = cachedBounds == null ? null : cachedBounds.get(bx);
|
||||||
|
if (bounds == null) {
|
||||||
|
bounds = localBounds.get(bx);
|
||||||
|
if (bounds == null) {
|
||||||
|
bounds = computeGeneratorBounds(engine, generators, bx);
|
||||||
|
localBounds.put(bx, bounds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bounds.max;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -329,18 +351,22 @@ public class IrisComplex implements DataProvider {
|
|||||||
|
|
||||||
double lo = interpolator.interpolate(x, z, (xx, zz) -> {
|
double lo = interpolator.interpolate(x, z, (xx, zz) -> {
|
||||||
try {
|
try {
|
||||||
IrisBiome bx = cache.get(new NoiseKey(xx, zz));
|
IrisBiome bx = sampleCache.get(xx, zz);
|
||||||
if (bx == null) {
|
if (bx == null) {
|
||||||
bx = baseBiomeStream.get(xx, zz);
|
bx = baseBiomeStream.get(xx, zz);
|
||||||
cache.put(new NoiseKey(xx, zz), bx);
|
sampleCache.put(xx, zz, bx);
|
||||||
}
|
|
||||||
double b = 0;
|
|
||||||
|
|
||||||
for (IrisGenerator gen : generators) {
|
|
||||||
b += bx.getGenLinkMin(gen.getLoadKey(), engine);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return b;
|
GeneratorBounds bounds = cachedBounds == null ? null : cachedBounds.get(bx);
|
||||||
|
if (bounds == null) {
|
||||||
|
bounds = localBounds.get(bx);
|
||||||
|
if (bounds == null) {
|
||||||
|
bounds = computeGeneratorBounds(engine, generators, bx);
|
||||||
|
localBounds.put(bx, bounds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bounds.min;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -362,8 +388,8 @@ public class IrisComplex implements DataProvider {
|
|||||||
private double getInterpolatedHeight(Engine engine, double x, double z, long seed) {
|
private double getInterpolatedHeight(Engine engine, double x, double z, long seed) {
|
||||||
double h = 0;
|
double h = 0;
|
||||||
|
|
||||||
for (IrisInterpolator i : generators.keySet()) {
|
for (Map.Entry<IrisInterpolator, Set<IrisGenerator>> entry : generators.entrySet()) {
|
||||||
h += interpolateGenerators(engine, i, generators.get(i), x, z, seed);
|
h += interpolateGenerators(engine, entry.getKey(), entry.getValue(), x, z, seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
return h;
|
return h;
|
||||||
@@ -374,6 +400,7 @@ public class IrisComplex implements DataProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void registerGenerators(IrisBiome biome) {
|
private void registerGenerators(IrisBiome biome) {
|
||||||
|
generatorBiomes.add(biome);
|
||||||
biome.getGenerators().forEach(c -> registerGenerator(c.getCachedGenerator(this)));
|
biome.getGenerators().forEach(c -> registerGenerator(c.getCachedGenerator(this)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,6 +408,38 @@ public class IrisComplex implements DataProvider {
|
|||||||
generators.computeIfAbsent(cachedGenerator.getInterpolator(), (k) -> new HashSet<>()).add(cachedGenerator);
|
generators.computeIfAbsent(cachedGenerator.getInterpolator(), (k) -> new HashSet<>()).add(cachedGenerator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Map<IrisInterpolator, IdentityHashMap<IrisBiome, GeneratorBounds>> buildGeneratorBounds(Engine engine) {
|
||||||
|
Map<IrisInterpolator, IdentityHashMap<IrisBiome, GeneratorBounds>> bounds = new HashMap<>();
|
||||||
|
KList<IrisBiome> allBiomes = new KList<>(generatorBiomes);
|
||||||
|
|
||||||
|
if (focusBiome != null && !allBiomes.contains(focusBiome)) {
|
||||||
|
allBiomes.add(focusBiome);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<IrisInterpolator, Set<IrisGenerator>> entry : generators.entrySet()) {
|
||||||
|
IdentityHashMap<IrisBiome, GeneratorBounds> interpolatorBounds = new IdentityHashMap<>(Math.max(allBiomes.size(), 16));
|
||||||
|
for (IrisBiome biome : allBiomes) {
|
||||||
|
interpolatorBounds.put(biome, computeGeneratorBounds(engine, entry.getValue(), biome));
|
||||||
|
}
|
||||||
|
bounds.put(entry.getKey(), interpolatorBounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GeneratorBounds computeGeneratorBounds(Engine engine, Set<IrisGenerator> generators, IrisBiome biome) {
|
||||||
|
double min = 0D;
|
||||||
|
double max = 0D;
|
||||||
|
|
||||||
|
for (IrisGenerator gen : generators) {
|
||||||
|
String key = gen.getLoadKey();
|
||||||
|
max += biome.getGenLinkMax(key, engine);
|
||||||
|
min += biome.getGenLinkMin(key, engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new GeneratorBounds(min, max);
|
||||||
|
}
|
||||||
|
|
||||||
private IrisBiome implode(IrisBiome b, Double x, Double z) {
|
private IrisBiome implode(IrisBiome b, Double x, Double z) {
|
||||||
if (b.getChildren().isEmpty()) {
|
if (b.getChildren().isEmpty()) {
|
||||||
return b;
|
return b;
|
||||||
@@ -406,6 +465,66 @@ public class IrisComplex implements DataProvider {
|
|||||||
return implode(biome, x, z, max - 1);
|
return implode(biome, x, z, max - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class GeneratorBounds {
|
||||||
|
private final double min;
|
||||||
|
private final double max;
|
||||||
|
|
||||||
|
private GeneratorBounds(double min, double max) {
|
||||||
|
this.min = min;
|
||||||
|
this.max = max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class CoordinateBiomeCache {
|
||||||
|
private long[] xBits;
|
||||||
|
private long[] zBits;
|
||||||
|
private IrisBiome[] values;
|
||||||
|
private int size;
|
||||||
|
|
||||||
|
private CoordinateBiomeCache(int initialSize) {
|
||||||
|
xBits = new long[initialSize];
|
||||||
|
zBits = new long[initialSize];
|
||||||
|
values = new IrisBiome[initialSize];
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IrisBiome get(double x, double z) {
|
||||||
|
long xb = Double.doubleToLongBits(x);
|
||||||
|
long zb = Double.doubleToLongBits(z);
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
if (xBits[i] == xb && zBits[i] == zb) {
|
||||||
|
return values[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void put(double x, double z, IrisBiome biome) {
|
||||||
|
if (size >= xBits.length) {
|
||||||
|
grow();
|
||||||
|
}
|
||||||
|
|
||||||
|
xBits[size] = Double.doubleToLongBits(x);
|
||||||
|
zBits[size] = Double.doubleToLongBits(z);
|
||||||
|
values[size] = biome;
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void grow() {
|
||||||
|
int nextSize = xBits.length << 1;
|
||||||
|
long[] nx = new long[nextSize];
|
||||||
|
long[] nz = new long[nextSize];
|
||||||
|
IrisBiome[] nv = new IrisBiome[nextSize];
|
||||||
|
System.arraycopy(xBits, 0, nx, 0, size);
|
||||||
|
System.arraycopy(zBits, 0, nz, 0, size);
|
||||||
|
System.arraycopy(values, 0, nv, 0, size);
|
||||||
|
xBits = nx;
|
||||||
|
zBits = nz;
|
||||||
|
values = nv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import lombok.Data;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@Snippet("style")
|
@Snippet("style")
|
||||||
@@ -91,26 +92,85 @@ public class IrisGeneratorStyle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private int imageMapHash() {
|
||||||
|
if (imageMap == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Objects.hash(imageMap.getImage(),
|
||||||
|
imageMap.getCoordinateScale(),
|
||||||
|
imageMap.getInterpolationMethod(),
|
||||||
|
imageMap.getChannel(),
|
||||||
|
imageMap.isInverted(),
|
||||||
|
imageMap.isTiled(),
|
||||||
|
imageMap.isCentered());
|
||||||
|
}
|
||||||
|
|
||||||
private int hash() {
|
private int hash() {
|
||||||
return Objects.hash(expression, imageMap, multiplier, axialFracturing, fracture != null ? fracture.hash() : 0, exponent, cacheSize, zoom, cellularZoom, cellularFrequency, style);
|
return Objects.hash(expression, imageMapHash(), script, multiplier, axialFracturing, fracture != null ? fracture.hash() : 0, exponent, cacheSize, zoom, cellularZoom, cellularFrequency, style);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String cachePrefix(RNG rng) {
|
||||||
|
return "style-" + Integer.toUnsignedString(hash())
|
||||||
|
+ "-seed-" + Long.toUnsignedString(rng.getSeed())
|
||||||
|
+ "-src-";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String cacheKey(RNG rng, long sourceStamp) {
|
||||||
|
return cachePrefix(rng) + Long.toUnsignedString(sourceStamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private long scriptStamp(IrisData data) {
|
||||||
|
if (getScript() == null) {
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
File scriptFile = data.getScriptLoader().findFile(getScript());
|
||||||
|
if (scriptFile == null) {
|
||||||
|
return Integer.toUnsignedLong(getScript().hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Integer.toUnsignedLong(Objects.hash(getScript(), scriptFile.lastModified(), scriptFile.length()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearStaleCacheEntries(IrisData data, String prefix, String key) {
|
||||||
|
File cacheFolder = new File(data.getDataFolder(), ".cache");
|
||||||
|
File[] files = cacheFolder.listFiles((dir, name) -> name.endsWith(".cnm") && name.startsWith(prefix));
|
||||||
|
if (files == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String keepFile = key + ".cnm";
|
||||||
|
for (File file : files) {
|
||||||
|
if (keepFile.equals(file.getName())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file.delete()) {
|
||||||
|
Iris.debug("Unable to delete stale noise cache " + file.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public CNG createNoCache(RNG rng, IrisData data, boolean actuallyCached) {
|
public CNG createNoCache(RNG rng, IrisData data, boolean actuallyCached) {
|
||||||
String cacheKey = hash() + "";
|
|
||||||
|
|
||||||
CNG cng = null;
|
CNG cng = null;
|
||||||
|
long sourceStamp = 0L;
|
||||||
if (getExpression() != null) {
|
if (getExpression() != null) {
|
||||||
IrisExpression e = data.getExpressionLoader().load(getExpression());
|
IrisExpression e = data.getExpressionLoader().load(getExpression());
|
||||||
if (e != null) {
|
if (e != null) {
|
||||||
cng = new CNG(rng, new ExpressionNoise(rng, e), 1D, 1).bake();
|
cng = new CNG(rng, new ExpressionNoise(rng, e), 1D, 1).bake();
|
||||||
|
sourceStamp = Integer.toUnsignedLong(Objects.hash(getExpression(),
|
||||||
|
e.getLoadFile() == null ? 0L : e.getLoadFile().lastModified()));
|
||||||
}
|
}
|
||||||
} else if (getImageMap() != null) {
|
} else if (getImageMap() != null) {
|
||||||
cng = new CNG(rng, new ImageNoise(data, getImageMap()), 1D, 1).bake();
|
cng = new CNG(rng, new ImageNoise(data, getImageMap()), 1D, 1).bake();
|
||||||
|
sourceStamp = Integer.toUnsignedLong(imageMapHash());
|
||||||
} else if (getScript() != null) {
|
} else if (getScript() != null) {
|
||||||
Object result = data.getEnvironment().createNoise(getScript(), rng);
|
Object result = data.getEnvironment().createNoise(getScript(), rng);
|
||||||
if (result == null) Iris.warn("Failed to create noise from script: " + getScript());
|
if (result == null) Iris.warn("Failed to create noise from script: " + getScript());
|
||||||
if (result instanceof NoiseGenerator generator) {
|
if (result instanceof NoiseGenerator generator) {
|
||||||
cng = new CNG(rng, generator, 1D, 1).bake();
|
cng = new CNG(rng, generator, 1D, 1).bake();
|
||||||
|
sourceStamp = scriptStamp(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +186,13 @@ public class IrisGeneratorStyle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cellularFrequency > 0) {
|
if (cellularFrequency > 0) {
|
||||||
return cng.cellularize(rng.nextParallelRNG(884466), cellularFrequency).scale(1D / cellularZoom).bake();
|
cng = cng.cellularize(rng.nextParallelRNG(884466), cellularFrequency).scale(1D / cellularZoom).bake();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cacheSize > 0) {
|
||||||
|
String key = cacheKey(rng, sourceStamp);
|
||||||
|
clearStaleCacheEntries(data, cachePrefix(rng), key);
|
||||||
|
cng = cng.cached(cacheSize, key, data.getDataFolder());
|
||||||
}
|
}
|
||||||
|
|
||||||
return cng;
|
return cng;
|
||||||
|
|||||||
@@ -63,6 +63,14 @@ public class IrisShapedGeneratorStyle {
|
|||||||
return generator.create(rng, data).fitDouble(min, max, dim);
|
return generator.create(rng, data).fitDouble(min, max, dim);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double get(RNG rng, IrisData data, double x, double z) {
|
||||||
|
return generator.create(rng, data).fitDouble(min, max, x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double get(RNG rng, IrisData data, double x, double y, double z) {
|
||||||
|
return generator.create(rng, data).fitDouble(min, max, x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isFlat() {
|
public boolean isFlat() {
|
||||||
return min == max || getGenerator().isFlat();
|
return min == max || getGenerator().isFlat();
|
||||||
}
|
}
|
||||||
|
|||||||
+52
-2
@@ -999,8 +999,8 @@ public class IrisInterpolation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static double getNoise(InterpolationMethod method, int x, int z, double h, NoiseProvider noise) {
|
public static double getNoise(InterpolationMethod method, int x, int z, double h, NoiseProvider noise) {
|
||||||
HashMap<NoiseKey, Double> cache = new HashMap<>(64);
|
NoiseSampleCache2D cache = new NoiseSampleCache2D(64);
|
||||||
NoiseProvider n = (x1, z1) -> cache.computeIfAbsent(new NoiseKey(x1 - x, z1 - z), k -> noise.noise(x1, z1));
|
NoiseProvider n = (x1, z1) -> cache.getOrSample(x1 - x, z1 - z, x1, z1, noise);
|
||||||
|
|
||||||
if (method.equals(InterpolationMethod.BILINEAR)) {
|
if (method.equals(InterpolationMethod.BILINEAR)) {
|
||||||
return getBilinearNoise(x, z, h, n);
|
return getBilinearNoise(x, z, h, n);
|
||||||
@@ -1059,6 +1059,56 @@ public class IrisInterpolation {
|
|||||||
return n.noise(x, z);
|
return n.noise(x, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class NoiseSampleCache2D {
|
||||||
|
private long[] xBits;
|
||||||
|
private long[] zBits;
|
||||||
|
private double[] values;
|
||||||
|
private int size;
|
||||||
|
|
||||||
|
public NoiseSampleCache2D(int initialCapacity) {
|
||||||
|
xBits = new long[initialCapacity];
|
||||||
|
zBits = new long[initialCapacity];
|
||||||
|
values = new double[initialCapacity];
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getOrSample(double relativeX, double relativeZ, double sampleX, double sampleZ, NoiseProvider provider) {
|
||||||
|
long rx = Double.doubleToLongBits(relativeX);
|
||||||
|
long rz = Double.doubleToLongBits(relativeZ);
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
if (xBits[i] == rx && zBits[i] == rz) {
|
||||||
|
return values[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double value = provider.noise(sampleX, sampleZ);
|
||||||
|
if (size >= xBits.length) {
|
||||||
|
grow();
|
||||||
|
}
|
||||||
|
|
||||||
|
xBits[size] = rx;
|
||||||
|
zBits[size] = rz;
|
||||||
|
values[size] = value;
|
||||||
|
size++;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void grow() {
|
||||||
|
int nextLength = xBits.length << 1;
|
||||||
|
long[] nextXBits = new long[nextLength];
|
||||||
|
long[] nextZBits = new long[nextLength];
|
||||||
|
double[] nextValues = new double[nextLength];
|
||||||
|
System.arraycopy(xBits, 0, nextXBits, 0, size);
|
||||||
|
System.arraycopy(zBits, 0, nextZBits, 0, size);
|
||||||
|
System.arraycopy(values, 0, nextValues, 0, size);
|
||||||
|
xBits = nextXBits;
|
||||||
|
zBits = nextZBits;
|
||||||
|
values = nextValues;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static double rangeScale(double amin, double amax, double bmin, double bmax, double b) {
|
public static double rangeScale(double amin, double amax, double bmin, double bmax, double b) {
|
||||||
return amin + ((amax - amin) * ((b - bmin) / (bmax - bmin)));
|
return amin + ((amax - amin) * ((b - bmin) / (bmax - bmin)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -425,6 +425,26 @@ public class CNG {
|
|||||||
return (int) Math.round(IrisInterpolation.lerp(min, max, noise));
|
return (int) Math.round(IrisInterpolation.lerp(min, max, noise));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int fit(int min, int max, double x, double z) {
|
||||||
|
if (min == max) {
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
double noise = noise(x, z);
|
||||||
|
|
||||||
|
return (int) Math.round(IrisInterpolation.lerp(min, max, noise));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int fit(int min, int max, double x, double y, double z) {
|
||||||
|
if (min == max) {
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
double noise = noise(x, y, z);
|
||||||
|
|
||||||
|
return (int) Math.round(IrisInterpolation.lerp(min, max, noise));
|
||||||
|
}
|
||||||
|
|
||||||
public int fit(double min, double max, double... dim) {
|
public int fit(double min, double max, double... dim) {
|
||||||
if (min == max) {
|
if (min == max) {
|
||||||
return (int) Math.round(min);
|
return (int) Math.round(min);
|
||||||
@@ -435,6 +455,26 @@ public class CNG {
|
|||||||
return (int) Math.round(IrisInterpolation.lerp(min, max, noise));
|
return (int) Math.round(IrisInterpolation.lerp(min, max, noise));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int fit(double min, double max, double x, double z) {
|
||||||
|
if (min == max) {
|
||||||
|
return (int) Math.round(min);
|
||||||
|
}
|
||||||
|
|
||||||
|
double noise = noise(x, z);
|
||||||
|
|
||||||
|
return (int) Math.round(IrisInterpolation.lerp(min, max, noise));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int fit(double min, double max, double x, double y, double z) {
|
||||||
|
if (min == max) {
|
||||||
|
return (int) Math.round(min);
|
||||||
|
}
|
||||||
|
|
||||||
|
double noise = noise(x, y, z);
|
||||||
|
|
||||||
|
return (int) Math.round(IrisInterpolation.lerp(min, max, noise));
|
||||||
|
}
|
||||||
|
|
||||||
public double fitDouble(double min, double max, double... dim) {
|
public double fitDouble(double min, double max, double... dim) {
|
||||||
if (min == max) {
|
if (min == max) {
|
||||||
return min;
|
return min;
|
||||||
@@ -445,6 +485,26 @@ public class CNG {
|
|||||||
return IrisInterpolation.lerp(min, max, noise);
|
return IrisInterpolation.lerp(min, max, noise);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double fitDouble(double min, double max, double x, double z) {
|
||||||
|
if (min == max) {
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
double noise = noise(x, z);
|
||||||
|
|
||||||
|
return IrisInterpolation.lerp(min, max, noise);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double fitDouble(double min, double max, double x, double y, double z) {
|
||||||
|
if (min == max) {
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
double noise = noise(x, y, z);
|
||||||
|
|
||||||
|
return IrisInterpolation.lerp(min, max, noise);
|
||||||
|
}
|
||||||
|
|
||||||
private double getNoise(double... dim) {
|
private double getNoise(double... dim) {
|
||||||
double scale = noscale ? 1 : this.bakedScale * this.scale;
|
double scale = noscale ? 1 : this.bakedScale * this.scale;
|
||||||
|
|
||||||
@@ -481,6 +541,42 @@ public class CNG {
|
|||||||
return generator.noise(x * scale, y * scale, z * scale) * opacity;
|
return generator.noise(x * scale, y * scale, z * scale) * opacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private double getNoise(double x) {
|
||||||
|
double scl = noscale ? 1 : this.bakedScale * this.scale;
|
||||||
|
|
||||||
|
if (fracture == null || noscale) {
|
||||||
|
return generator.noise(x * scl, 0D, 0D) * opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
double fx = x + ((fracture.noise(x) - 0.5D) * fscale);
|
||||||
|
return generator.noise(fx * scl, 0D, 0D) * opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double getNoise(double x, double z) {
|
||||||
|
double scl = noscale ? 1 : this.bakedScale * this.scale;
|
||||||
|
|
||||||
|
if (fracture == null || noscale) {
|
||||||
|
return generator.noise(x * scl, z * scl, 0D) * opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
double fx = x + ((fracture.noise(x, z) - 0.5D) * fscale);
|
||||||
|
double fz = z + ((fracture.noise(z, x) - 0.5D) * fscale);
|
||||||
|
return generator.noise(fx * scl, fz * scl, 0D) * opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double getNoise(double x, double y, double z) {
|
||||||
|
double scl = noscale ? 1 : this.bakedScale * this.scale;
|
||||||
|
|
||||||
|
if (fracture == null || noscale) {
|
||||||
|
return generator.noise(x * scl, y * scl, z * scl) * opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
double fx = x + ((fracture.noise(x, y, z) - 0.5D) * fscale);
|
||||||
|
double fy = y + ((fracture.noise(y, x) - 0.5D) * fscale);
|
||||||
|
double fz = z + ((fracture.noise(z, x, y) - 0.5D) * fscale);
|
||||||
|
return generator.noise(fx * scl, fy * scl, fz * scl) * opacity;
|
||||||
|
}
|
||||||
|
|
||||||
public double invertNoise(double... dim) {
|
public double invertNoise(double... dim) {
|
||||||
if (dim.length == 1) {
|
if (dim.length == 1) {
|
||||||
return noise(-dim[0]);
|
return noise(-dim[0]);
|
||||||
@@ -497,9 +593,69 @@ public class CNG {
|
|||||||
return (noise(dim) * 2) - 1;
|
return (noise(dim) * 2) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isWholeCoordinate(double value) {
|
||||||
|
return value == Math.rint(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double applyPost(double n, double x) {
|
||||||
|
n = power != 1D ? (n < 0 ? -Math.pow(Math.abs(n), power) : Math.pow(n, power)) : n;
|
||||||
|
double m = 1;
|
||||||
|
hits += oct;
|
||||||
|
|
||||||
|
if (children != null) {
|
||||||
|
for (CNG i : children) {
|
||||||
|
double[] r = injector.combine(n, i.noise(x));
|
||||||
|
n = r[0];
|
||||||
|
m += r[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((n / m) - down + up) * patch;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double applyPost(double n, double x, double z) {
|
||||||
|
n = power != 1D ? (n < 0 ? -Math.pow(Math.abs(n), power) : Math.pow(n, power)) : n;
|
||||||
|
double m = 1;
|
||||||
|
hits += oct;
|
||||||
|
|
||||||
|
if (children != null) {
|
||||||
|
for (CNG i : children) {
|
||||||
|
double[] r = injector.combine(n, i.noise(x, z));
|
||||||
|
n = r[0];
|
||||||
|
m += r[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((n / m) - down + up) * patch;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double applyPost(double n, double x, double y, double z) {
|
||||||
|
n = power != 1D ? (n < 0 ? -Math.pow(Math.abs(n), power) : Math.pow(n, power)) : n;
|
||||||
|
double m = 1;
|
||||||
|
hits += oct;
|
||||||
|
|
||||||
|
if (children != null) {
|
||||||
|
for (CNG i : children) {
|
||||||
|
double[] r = injector.combine(n, i.noise(x, y, z));
|
||||||
|
n = r[0];
|
||||||
|
m += r[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((n / m) - down + up) * patch;
|
||||||
|
}
|
||||||
|
|
||||||
public double noise(double... dim) {
|
public double noise(double... dim) {
|
||||||
if (cache != null && dim.length == 2) {
|
if (dim.length == 1) {
|
||||||
return cache.get((int) dim[0], (int) dim[1]);
|
return noise(dim[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dim.length == 2) {
|
||||||
|
return noise(dim[0], dim[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dim.length == 3) {
|
||||||
|
return noise(dim[0], dim[1], dim[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
double n = getNoise(dim);
|
double n = getNoise(dim);
|
||||||
@@ -519,6 +675,22 @@ public class CNG {
|
|||||||
return ((n / m) - down + up) * patch;
|
return ((n / m) - down + up) * patch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double noise(double x) {
|
||||||
|
return applyPost(getNoise(x), x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double noise(double x, double z) {
|
||||||
|
if (cache != null && isWholeCoordinate(x) && isWholeCoordinate(z)) {
|
||||||
|
return cache.get((int) x, (int) z);
|
||||||
|
}
|
||||||
|
|
||||||
|
return applyPost(getNoise(x, z), x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double noise(double x, double y, double z) {
|
||||||
|
return applyPost(getNoise(x, y, z), x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
public CNG pow(double power) {
|
public CNG pow(double power) {
|
||||||
this.power = power;
|
this.power = power;
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -23,11 +23,12 @@ class ChunkedDataCache<T> private constructor(
|
|||||||
if (!cache) return
|
if (!cache) return
|
||||||
|
|
||||||
supervisorScope {
|
supervisorScope {
|
||||||
for (i in 0 until 16) {
|
for (j in 0 until 16) {
|
||||||
for (j in 0 until 16) {
|
launch(context) {
|
||||||
launch(context) {
|
val rowOffset = j * 16
|
||||||
val t = stream.get((x + i).toDouble(), (z + j).toDouble())
|
val zz = (z + j).toDouble()
|
||||||
data[(j * 16) + i] = t
|
for (i in 0 until 16) {
|
||||||
|
data[rowOffset + i] = stream.get((x + i).toDouble(), zz)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user