package common.rng;

class SimplexGen {
	private static final int[][] DIRS = new int[][] { { 1, 1, 0 }, { -1, 1, 0 }, { 1, -1, 0 }, { -1, -1, 0 }, { 1, 0, 1 }, { -1, 0, 1 }, { 1, 0, -1 },
			{ -1, 0, -1 }, { 0, 1, 1 }, { 0, -1, 1 }, { 0, 1, -1 }, { 0, -1, -1 } };
	private static final double SQ3 = Math.sqrt(3.0D);
	private static final double SQ3NORM = 0.5D * (SQ3 - 1.0D);
	private static final double SQ3INV = (3.0D - SQ3) / 6.0D;

	private final int[] bitfield;
	private final double xVar;
	private final double zVar;
	private final double unused1;

	protected SimplexGen(Random random) {
		this.bitfield = new int[512];
		this.xVar = random.doublev() * 256.0D;
		this.zVar = random.doublev() * 256.0D;
		this.unused1 = random.doublev() * 256.0D;

		for(int n = 0; n < 256; this.bitfield[n] = n++) {
			;
		}

		for(int n = 0; n < 256; ++n) {
			int pos = random.zrange(256 - n) + n;
			int value = this.bitfield[n];
			this.bitfield[n] = this.bitfield[pos];
			this.bitfield[pos] = value;
			this.bitfield[n + 256] = this.bitfield[n];
		}
	}

	private static int floorClamp(double d) {
		return d > 0.0D ? (int)d : (int)d - 1;
	}

	private static double multPair(int[] n, double xm, double zm) {
		return (double)n[0] * xm + (double)n[1] * zm;
	}

	public double generate(double x, double z) {
		double d3 = 0.5D * (SQ3 - 1.0D);
		double d4 = (x + z) * d3;
		int i = floorClamp(x + d4);
		int j = floorClamp(z + d4);
		double d5 = (3.0D - SQ3) / 6.0D;
		double d6 = (double)(i + j) * d5;
		double d7 = (double)i - d6;
		double d8 = (double)j - d6;
		double d9 = x - d7;
		double d10 = z - d8;
		int k;
		int l;

		if(d9 > d10) {
			k = 1;
			l = 0;
		}
		else {
			k = 0;
			l = 1;
		}

		double d11 = d9 - (double)k + d5;
		double d12 = d10 - (double)l + d5;
		double d13 = d9 - 1.0D + 2.0D * d5;
		double d14 = d10 - 1.0D + 2.0D * d5;
		int i1 = i & 255;
		int j1 = j & 255;
		int k1 = this.bitfield[i1 + this.bitfield[j1]] % 12;
		int l1 = this.bitfield[i1 + k + this.bitfield[j1 + l]] % 12;
		int i2 = this.bitfield[i1 + 1 + this.bitfield[j1 + 1]] % 12;
		double d15 = 0.5D - d9 * d9 - d10 * d10;
		double d0;

		if(d15 < 0.0D) {
			d0 = 0.0D;
		}
		else {
			d15 = d15 * d15;
			d0 = d15 * d15 * multPair(DIRS[k1], d9, d10);
		}

		double d16 = 0.5D - d11 * d11 - d12 * d12;
		double d1;

		if(d16 < 0.0D) {
			d1 = 0.0D;
		}
		else {
			d16 = d16 * d16;
			d1 = d16 * d16 * multPair(DIRS[l1], d11, d12);
		}

		double d17 = 0.5D - d13 * d13 - d14 * d14;
		double d2;

		if(d17 < 0.0D) {
			d2 = 0.0D;
		}
		else {
			d17 = d17 * d17;
			d2 = d17 * d17 * multPair(DIRS[i2], d13, d14);
		}

		return 70.0D * (d0 + d1 + d2);
	}

	public void generate(double[] noise, double xoff, double zoff, int xsize, int zsize, double xscale, double zscale, double amp) {
		int o = 0;

		for(int n1 = 0; n1 < zsize; ++n1) {
			double zv = (zoff + (double)n1) * zscale + this.zVar;

			for(int n2 = 0; n2 < xsize; ++n2) {
				double xv = (xoff + (double)n2) * xscale + this.xVar;
				double d5 = (xv + zv) * SQ3NORM;
				int l = floorClamp(xv + d5);
				int i1 = floorClamp(zv + d5);
				double d6 = (double)(l + i1) * SQ3INV;
				double d7 = (double)l - d6;
				double d8 = (double)i1 - d6;
				double d9 = xv - d7;
				double d10 = zv - d8;
				int j1;
				int k1;

				if(d9 > d10) {
					j1 = 1;
					k1 = 0;
				}
				else {
					j1 = 0;
					k1 = 1;
				}

				double d11 = d9 - (double)j1 + SQ3INV;
				double d12 = d10 - (double)k1 + SQ3INV;
				double d13 = d9 - 1.0D + 2.0D * SQ3INV;
				double d14 = d10 - 1.0D + 2.0D * SQ3INV;
				int l1 = l & 255;
				int i2 = i1 & 255;
				int j2 = this.bitfield[l1 + this.bitfield[i2]] % 12;
				int k2 = this.bitfield[l1 + j1 + this.bitfield[i2 + k1]] % 12;
				int l2 = this.bitfield[l1 + 1 + this.bitfield[i2 + 1]] % 12;
				double d15 = 0.5D - d9 * d9 - d10 * d10;
				double d2;

				if(d15 < 0.0D) {
					d2 = 0.0D;
				}
				else {
					d15 = d15 * d15;
					d2 = d15 * d15 * multPair(DIRS[j2], d9, d10);
				}

				double d16 = 0.5D - d11 * d11 - d12 * d12;
				double d3;

				if(d16 < 0.0D) {
					d3 = 0.0D;
				}
				else {
					d16 = d16 * d16;
					d3 = d16 * d16 * multPair(DIRS[k2], d11, d12);
				}

				double d17 = 0.5D - d13 * d13 - d14 * d14;
				double d4;

				if(d17 < 0.0D) {
					d4 = 0.0D;
				}
				else {
					d17 = d17 * d17;
					d4 = d17 * d17 * multPair(DIRS[l2], d13, d14);
				}

				int pos = o++;
				noise[pos] += 70.0D * (d2 + d3 + d4) * amp;
			}
		}
	}
}
