mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-04-05 15:26:28 +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.iris.util.project.context.IrisContext;
|
||||
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.RNG;
|
||||
import art.arcane.iris.util.project.noise.CNG;
|
||||
@@ -83,6 +82,8 @@ public class IrisComplex implements DataProvider {
|
||||
private ProceduralStream<BlockData> fluidStream;
|
||||
private IrisBiome focusBiome;
|
||||
private IrisRegion focusRegion;
|
||||
private Map<IrisInterpolator, IdentityHashMap<IrisBiome, GeneratorBounds>> generatorBounds;
|
||||
private Set<IrisBiome> generatorBiomes;
|
||||
|
||||
public IrisComplex(Engine engine) {
|
||||
this(engine, false);
|
||||
@@ -97,6 +98,7 @@ public class IrisComplex implements DataProvider {
|
||||
double height = engine.getMaxHeight();
|
||||
fluidHeight = engine.getDimension().getFluidHeight();
|
||||
generators = new HashMap<>();
|
||||
generatorBiomes = Collections.newSetFromMap(new IdentityHashMap<>());
|
||||
focusBiome = engine.getFocus();
|
||||
focusRegion = engine.getFocusRegion();
|
||||
Map<InferredType, ProceduralStream<IrisBiome>> inferredStreams = new HashMap<>();
|
||||
@@ -116,9 +118,20 @@ public class IrisComplex implements DataProvider {
|
||||
.getAllBiomes(this)
|
||||
.forEach(this::registerGenerators));
|
||||
}
|
||||
generatorBounds = buildGeneratorBounds(engine);
|
||||
boolean legacy = engine.getDimension().isLegacyRarity();
|
||||
overlayStream = ProceduralStream.ofDouble((x, z) -> 0.0D).waste("Overlay Stream");
|
||||
engine.getDimension().getOverlayNoise().forEach(i -> overlayStream = overlayStream.add((x, z) -> i.get(rng, getData(), x, z)));
|
||||
KList<IrisShapedGeneratorStyle> overlayNoise = engine.getDimension().getOverlayNoise();
|
||||
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()
|
||||
.select(engine.getDimension().getRockPalette().getBlockData(data)).waste("Rock Stream");
|
||||
fluidStream = engine.getDimension().getFluidPalette().getLayerGenerator(rng.nextParallelRNG(78), data).stream()
|
||||
@@ -306,18 +319,27 @@ public class IrisComplex implements DataProvider {
|
||||
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) -> {
|
||||
try {
|
||||
IrisBiome bx = baseBiomeStream.get(xx, zz);
|
||||
cache.put(new NoiseKey(xx, zz), bx);
|
||||
double b = 0;
|
||||
|
||||
for (IrisGenerator gen : generators) {
|
||||
b += bx.getGenLinkMax(gen.getLoadKey(), engine);
|
||||
IrisBiome bx = sampleCache.get(xx, zz);
|
||||
if (bx == null) {
|
||||
bx = baseBiomeStream.get(xx, zz);
|
||||
sampleCache.put(xx, zz, bx);
|
||||
}
|
||||
|
||||
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) {
|
||||
Iris.reportError(e);
|
||||
e.printStackTrace();
|
||||
@@ -329,18 +351,22 @@ public class IrisComplex implements DataProvider {
|
||||
|
||||
double lo = interpolator.interpolate(x, z, (xx, zz) -> {
|
||||
try {
|
||||
IrisBiome bx = cache.get(new NoiseKey(xx, zz));
|
||||
IrisBiome bx = sampleCache.get(xx, zz);
|
||||
if (bx == null) {
|
||||
bx = baseBiomeStream.get(xx, zz);
|
||||
cache.put(new NoiseKey(xx, zz), bx);
|
||||
}
|
||||
double b = 0;
|
||||
|
||||
for (IrisGenerator gen : generators) {
|
||||
b += bx.getGenLinkMin(gen.getLoadKey(), engine);
|
||||
sampleCache.put(xx, zz, bx);
|
||||
}
|
||||
|
||||
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) {
|
||||
Iris.reportError(e);
|
||||
e.printStackTrace();
|
||||
@@ -362,8 +388,8 @@ public class IrisComplex implements DataProvider {
|
||||
private double getInterpolatedHeight(Engine engine, double x, double z, long seed) {
|
||||
double h = 0;
|
||||
|
||||
for (IrisInterpolator i : generators.keySet()) {
|
||||
h += interpolateGenerators(engine, i, generators.get(i), x, z, seed);
|
||||
for (Map.Entry<IrisInterpolator, Set<IrisGenerator>> entry : generators.entrySet()) {
|
||||
h += interpolateGenerators(engine, entry.getKey(), entry.getValue(), x, z, seed);
|
||||
}
|
||||
|
||||
return h;
|
||||
@@ -374,6 +400,7 @@ public class IrisComplex implements DataProvider {
|
||||
}
|
||||
|
||||
private void registerGenerators(IrisBiome biome) {
|
||||
generatorBiomes.add(biome);
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (b.getChildren().isEmpty()) {
|
||||
return b;
|
||||
@@ -406,6 +465,66 @@ public class IrisComplex implements DataProvider {
|
||||
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() {
|
||||
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Objects;
|
||||
|
||||
@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() {
|
||||
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) {
|
||||
String cacheKey = hash() + "";
|
||||
|
||||
CNG cng = null;
|
||||
long sourceStamp = 0L;
|
||||
if (getExpression() != null) {
|
||||
IrisExpression e = data.getExpressionLoader().load(getExpression());
|
||||
if (e != null) {
|
||||
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) {
|
||||
cng = new CNG(rng, new ImageNoise(data, getImageMap()), 1D, 1).bake();
|
||||
sourceStamp = Integer.toUnsignedLong(imageMapHash());
|
||||
} else if (getScript() != null) {
|
||||
Object result = data.getEnvironment().createNoise(getScript(), rng);
|
||||
if (result == null) Iris.warn("Failed to create noise from script: " + getScript());
|
||||
if (result instanceof NoiseGenerator generator) {
|
||||
cng = new CNG(rng, generator, 1D, 1).bake();
|
||||
sourceStamp = scriptStamp(data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +186,13 @@ public class IrisGeneratorStyle {
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -63,6 +63,14 @@ public class IrisShapedGeneratorStyle {
|
||||
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() {
|
||||
return min == max || getGenerator().isFlat();
|
||||
}
|
||||
|
||||
@@ -999,8 +999,8 @@ public class IrisInterpolation {
|
||||
}
|
||||
|
||||
public static double getNoise(InterpolationMethod method, int x, int z, double h, NoiseProvider noise) {
|
||||
HashMap<NoiseKey, Double> cache = new HashMap<>(64);
|
||||
NoiseProvider n = (x1, z1) -> cache.computeIfAbsent(new NoiseKey(x1 - x, z1 - z), k -> noise.noise(x1, z1));
|
||||
NoiseSampleCache2D cache = new NoiseSampleCache2D(64);
|
||||
NoiseProvider n = (x1, z1) -> cache.getOrSample(x1 - x, z1 - z, x1, z1, noise);
|
||||
|
||||
if (method.equals(InterpolationMethod.BILINEAR)) {
|
||||
return getBilinearNoise(x, z, h, n);
|
||||
@@ -1059,6 +1059,56 @@ public class IrisInterpolation {
|
||||
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) {
|
||||
return amin + ((amax - amin) * ((b - bmin) / (bmax - bmin)));
|
||||
}
|
||||
|
||||
@@ -425,6 +425,26 @@ public class CNG {
|
||||
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) {
|
||||
if (min == max) {
|
||||
return (int) Math.round(min);
|
||||
@@ -435,6 +455,26 @@ public class CNG {
|
||||
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) {
|
||||
if (min == max) {
|
||||
return min;
|
||||
@@ -445,6 +485,26 @@ public class CNG {
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (dim.length == 1) {
|
||||
return noise(-dim[0]);
|
||||
@@ -497,9 +593,69 @@ public class CNG {
|
||||
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) {
|
||||
if (cache != null && dim.length == 2) {
|
||||
return cache.get((int) dim[0], (int) dim[1]);
|
||||
if (dim.length == 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);
|
||||
@@ -519,6 +675,22 @@ public class CNG {
|
||||
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) {
|
||||
this.power = power;
|
||||
return this;
|
||||
|
||||
@@ -23,11 +23,12 @@ class ChunkedDataCache<T> private constructor(
|
||||
if (!cache) return
|
||||
|
||||
supervisorScope {
|
||||
for (i in 0 until 16) {
|
||||
for (j in 0 until 16) {
|
||||
launch(context) {
|
||||
val t = stream.get((x + i).toDouble(), (z + j).toDouble())
|
||||
data[(j * 16) + i] = t
|
||||
for (j in 0 until 16) {
|
||||
launch(context) {
|
||||
val rowOffset = j * 16
|
||||
val zz = (z + j).toDouble()
|
||||
for (i in 0 until 16) {
|
||||
data[rowOffset + i] = stream.get((x + i).toDouble(), zz)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user