minecraft-src/net/minecraft/world/level/levelgen/synth/PerlinSimplexNoise.java
2025-07-04 01:41:11 +03:00

83 lines
2.7 KiB
Java

package net.minecraft.world.level.levelgen.synth;
import it.unimi.dsi.fastutil.ints.IntRBTreeSet;
import it.unimi.dsi.fastutil.ints.IntSortedSet;
import java.util.List;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.levelgen.LegacyRandomSource;
import net.minecraft.world.level.levelgen.WorldgenRandom;
/**
* This class generates multiple octaves of simplex noise. Each individual octave is an instance of {@link net.minecraft.world.level.levelgen.synth.SimplexNoise}.
* Mojang uses the term 'Perlin' to describe octaves or fBm (Fractal Brownian Motion) noise and this class does not actually generate Perlin noise.
*/
public class PerlinSimplexNoise {
private final SimplexNoise[] noiseLevels;
private final double highestFreqValueFactor;
private final double highestFreqInputFactor;
public PerlinSimplexNoise(RandomSource random, List<Integer> octaves) {
this(random, new IntRBTreeSet(octaves));
}
private PerlinSimplexNoise(RandomSource random, IntSortedSet octaves) {
if (octaves.isEmpty()) {
throw new IllegalArgumentException("Need some octaves!");
} else {
int i = -octaves.firstInt();
int j = octaves.lastInt();
int k = i + j + 1;
if (k < 1) {
throw new IllegalArgumentException("Total number of octaves needs to be >= 1");
} else {
SimplexNoise simplexNoise = new SimplexNoise(random);
int l = j;
this.noiseLevels = new SimplexNoise[k];
if (j >= 0 && j < k && octaves.contains(0)) {
this.noiseLevels[j] = simplexNoise;
}
for (int m = j + 1; m < k; m++) {
if (m >= 0 && octaves.contains(l - m)) {
this.noiseLevels[m] = new SimplexNoise(random);
} else {
random.consumeCount(262);
}
}
if (j > 0) {
long n = (long)(simplexNoise.getValue(simplexNoise.xo, simplexNoise.yo, simplexNoise.zo) * 9.223372E18F);
RandomSource randomSource = new WorldgenRandom(new LegacyRandomSource(n));
for (int o = l - 1; o >= 0; o--) {
if (o < k && octaves.contains(l - o)) {
this.noiseLevels[o] = new SimplexNoise(randomSource);
} else {
randomSource.consumeCount(262);
}
}
}
this.highestFreqInputFactor = Math.pow(2.0, j);
this.highestFreqValueFactor = 1.0 / (Math.pow(2.0, k) - 1.0);
}
}
}
public double getValue(double x, double y, boolean useNoiseOffsets) {
double d = 0.0;
double e = this.highestFreqInputFactor;
double f = this.highestFreqValueFactor;
for (SimplexNoise simplexNoise : this.noiseLevels) {
if (simplexNoise != null) {
d += simplexNoise.getValue(x * e + (useNoiseOffsets ? simplexNoise.xo : 0.0), y * e + (useNoiseOffsets ? simplexNoise.yo : 0.0)) * f;
}
e /= 2.0;
f *= 2.0;
}
return d;
}
}