package com.hypixel.hytale.builtin.hytalegenerator.fields.noise;
import java.util.Random;
import javax.annotation.Nonnull;
public class SimplexNoiseField extends NoiseField {
private final long seed;
@Nonnull
private final double[] offsetX;
@Nonnull
private final double[] offsetY;
@Nonnull
private final double[] offsetZ;
@Nonnull
private final double[] offsetW;
private final int numberOfOctaves;
@Nonnull
private final double[] octaveFrequency;
@Nonnull
private final double[] octaveAmplitude;
private final double normalizer;
public SimplexNoiseField(long seed, double octaveAmplitudeMultiplier, double octaveFrequencyMultiplier, int numberOfOctaves) {
if (numberOfOctaves <= 0) {
throw new IllegalArgumentException("octaves can't be smaller than 1");
} else {
this.seed = seed;
this.numberOfOctaves = numberOfOctaves;
Random rand = new Random(seed);
this.offsetX = new double[numberOfOctaves];
this.offsetY = new double[numberOfOctaves];
this.offsetZ = new double[numberOfOctaves];
this.offsetW = new double[numberOfOctaves];
for(int i = 0; i < numberOfOctaves; ++i) {
this.offsetX[i] = rand.nextDouble() * 256.0;
this.offsetY[i] = rand.nextDouble() * 256.0;
this.offsetZ[i] = rand.nextDouble() * 256.0;
this.offsetW[i] = rand.nextDouble() * 256.0;
}
this.octaveAmplitude = new double[numberOfOctaves];
this.octaveFrequency = new double[numberOfOctaves];
double frequency = 1.0;
double amplitude = 1.0;
double maxAmplitude = 0.0;
for(int i = 0; i < numberOfOctaves; ++i) {
this.octaveAmplitude[i] = amplitude;
this.octaveFrequency[i] = frequency;
maxAmplitude += amplitude;
amplitude *= octaveAmplitudeMultiplier;
frequency *= octaveFrequencyMultiplier;
}
this.normalizer = 1.0 / maxAmplitude;
}
}
@Nonnull
public static Builder builder() {
return new Builder();
}
public double valueAt(double x, double y, double z, double w) {
x /= this.scaleX;
y /= this.scaleY;
z /= this.scaleZ;
w /= this.scaleW;
double octaveX = 0.0;
double octaveY = 0.0;
double octaveZ = 0.0;
double octaveW = 0.0;
double value = 0.0;
for(int i = 0; i < this.numberOfOctaves; ++i) {
octaveX = x + this.offsetX[i];
octaveY = y + this.offsetY[i];
octaveZ = z + this.offsetZ[i];
octaveW = w + this.offsetW[i];
value += Simplex.noise(octaveX * this.octaveFrequency[i], octaveY * this.octaveFrequency[i], octaveZ * this.octaveFrequency[i], octaveW * this.octaveFrequency[i]) * this.octaveAmplitude[i];
}
value *= this.normalizer;
return value;
}
public double valueAt(double x, double y, double z) {
x /= this.scaleX;
y /= this.scaleY;
z /= this.scaleZ;
double octaveX = 0.0;
double octaveY = 0.0;
double octaveZ = 0.0;
double value = 0.0;
for(int i = 0; i < this.numberOfOctaves; ++i) {
octaveX = x + this.offsetX[i];
octaveY = y + this.offsetY[i];
octaveZ = z + this.offsetZ[i];
value += Simplex.noise(octaveX * this.octaveFrequency[i], octaveY * this.octaveFrequency[i], octaveZ * this.octaveFrequency[i]) * this.octaveAmplitude[i];
}
value *= this.normalizer;
return value;
}
public double valueAt(double x, double y) {
x /= this.scaleX;
y /= this.scaleY;
double octaveX = 0.0;
double octaveY = 0.0;
double value = 0.0;
for(int i = 0; i < this.numberOfOctaves; ++i) {
octaveX = x + this.offsetX[i];
octaveY = y + this.offsetY[i];
value += Simplex.noise(octaveX * this.octaveFrequency[i], octaveY * this.octaveFrequency[i]) * this.octaveAmplitude[i];
}
value *= this.normalizer;
return value;
}
public double valueAt(double x) {
x /= this.scaleX;
double octaveX = 0.0;
double value = 0.0;
for(int i = 0; i < this.numberOfOctaves; ++i) {
octaveX = x + this.offsetX[i];
value += Simplex.noise(octaveX * this.octaveFrequency[i], 0.0) * this.octaveAmplitude[i];
}
value *= this.normalizer;
return value;
}
public long getSeed() {
return this.seed;
}
public static class Builder {
private long seed = 1L;
private double octaveAmplitudeMultiplier = 0.5;
private double octaveFrequencyMultiplier = 2.0;
private int numberOfOctaves = 4;
private double scaleX;
private double scaleY;
private double scaleZ;
private double scaleW;
private Builder() {
}
@Nonnull
public SimplexNoiseField build() {
SimplexNoiseField g = new SimplexNoiseField(this.seed, this.octaveAmplitudeMultiplier, this.octaveFrequencyMultiplier, this.numberOfOctaves);
g.setScale(this.scaleX, this.scaleY, this.scaleZ, this.scaleW);
return g;
}
@Nonnull
public Builder withScale(double s) {
this.scaleX = s;
this.scaleY = s;
this.scaleZ = s;
this.scaleW = s;
return this;
}
@Nonnull
public Builder withScale(double x, double y, double z, double w) {
this.scaleX = x;
this.scaleY = y;
this.scaleZ = z;
this.scaleW = w;
return this;
}
@Nonnull
public Builder withNumberOfOctaves(int n) {
if (n <= 0) {
throw new IllegalArgumentException("invalid number");
} else {
this.numberOfOctaves = n;
return this;
}
}
@Nonnull
public Builder withFrequencyMultiplier(double f) {
this.octaveFrequencyMultiplier = f;
return this;
}
@Nonnull
public Builder withAmplitudeMultiplier(double a) {
this.octaveAmplitudeMultiplier = a;
return this;
}
@Nonnull
public Builder withSeed(long s) {
this.seed = s;
return this;
}
}
}