From ee88f153bb2d592a778cea34163c8321765ededc Mon Sep 17 00:00:00 2001 From: gnembon Date: Fri, 24 Jan 2020 02:17:01 -0400 Subject: [PATCH] noise gen --- src/main/java/carpet/script/Expression.java | 46 +++++ .../script/utils/PerlinNoiseSampler.java | 170 ++++++++++++++++++ .../script/utils/SimplexNoiseSampler.java | 67 +++++++ 3 files changed, 283 insertions(+) create mode 100644 src/main/java/carpet/script/utils/PerlinNoiseSampler.java create mode 100644 src/main/java/carpet/script/utils/SimplexNoiseSampler.java diff --git a/src/main/java/carpet/script/Expression.java b/src/main/java/carpet/script/Expression.java index eeed2959..e1008165 100644 --- a/src/main/java/carpet/script/Expression.java +++ b/src/main/java/carpet/script/Expression.java @@ -20,6 +20,8 @@ import carpet.script.exception.InternalExpressionException; import carpet.script.exception.ResolvedException; import carpet.script.exception.ReturnStatement; import carpet.script.exception.ThrowStatement; +import carpet.script.utils.PerlinNoiseSampler; +import carpet.script.utils.SimplexNoiseSampler; import carpet.script.value.AbstractListValue; import carpet.script.value.ContainerValueInterface; import carpet.script.value.FunctionSignatureValue; @@ -29,6 +31,7 @@ import carpet.script.value.LContainerValue; import carpet.script.value.LazyListValue; import carpet.script.value.ListValue; import carpet.script.value.MapValue; +import carpet.script.value.NullValue; import carpet.script.value.NumericValue; import carpet.script.value.StringValue; import carpet.script.value.ThreadValue; @@ -2972,6 +2975,49 @@ public class Expression return (cc, tt) -> retval; }); + addLazyFunction("perlin", 3, (c, t, lv) -> { + // add seed cache + Value ret; + Value x = lv.get(0).evalValue(c); + Value y = lv.get(1).evalValue(c); + Value z = lv.get(2).evalValue(c); + + if (z instanceof NullValue) + { + if (y instanceof NullValue) + { + ret = new NumericValue(PerlinNoiseSampler.instance.sample1d( + NumericValue.asNumber(x).getDouble() + )); + } + else + { + ret = new NumericValue(PerlinNoiseSampler.instance.sample2d( + NumericValue.asNumber(x).getDouble(), + NumericValue.asNumber(y).getDouble() + )); + } + } + else + { + ret = new NumericValue(PerlinNoiseSampler.instance.sample3d( + NumericValue.asNumber(x).getDouble(), + NumericValue.asNumber(y).getDouble(), + NumericValue.asNumber(z).getDouble() + )); + } + return (cc, tt) -> ret; + }); + + addLazyFunction("simplex", 2, (c, t, lv) -> { + // add seed cache + double x = NumericValue.asNumber(lv.get(0).evalValue(c)).getDouble(); + double y = NumericValue.asNumber(lv.get(1).evalValue(c)).getDouble(); + //double z = NumericValue.asNumber(lv.get(2).evalValue(c)).getDouble(); + Value value = new NumericValue(SimplexNoiseSampler.instance.sample(x,y)); + return (cc, tt) -> value; + }); + addUnaryFunction("print", (v) -> { System.out.println(v.getString()); diff --git a/src/main/java/carpet/script/utils/PerlinNoiseSampler.java b/src/main/java/carpet/script/utils/PerlinNoiseSampler.java new file mode 100644 index 00000000..300df75c --- /dev/null +++ b/src/main/java/carpet/script/utils/PerlinNoiseSampler.java @@ -0,0 +1,170 @@ +package carpet.script.utils; + +import java.util.Random; + +public class PerlinNoiseSampler { + protected static final int[][] gradients3d = 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}, + {1, 1, 0}, {0, -1, 1}, {-1, 1, 0}, {0, -1, -1} + }; + protected static final int[][] gradients2d = new int[][]{{1, 1}, {-1, 1}, {1, -1}, {-1, -1}}; + + + private final byte[] permutations; + public final double originX; + public final double originY; + public final double originZ; + public static PerlinNoiseSampler instance = new PerlinNoiseSampler(new Random(0)); + + public PerlinNoiseSampler(Random random) { + this.originX = random.nextDouble() * 256.0D; + this.originY = random.nextDouble() * 256.0D; + this.originZ = random.nextDouble() * 256.0D; + this.permutations = new byte[256]; + + int j; + for(j = 0; j < 256; ++j) { + this.permutations[j] = (byte)j; + } + + for(j = 0; j < 256; ++j) { + int k = random.nextInt(256 - j); + byte b = this.permutations[j]; + this.permutations[j] = this.permutations[j + k]; + this.permutations[j + k] = b; + } + + } + + //3D + public double sample3d(double x, double y, double z) {//, double d, double e) { + double f = x + this.originX; + double g = y + this.originY; + double h = z + this.originZ; + int i = floor(f); + int j = floor(g); + int k = floor(h); + double l = f - (double)i; + double m = g - (double)j; + double n = h - (double)k; + double o = perlinFade(l); + double p = perlinFade(m); + double q = perlinFade(n); + //double t; + /* + if (d != 0.0D) { + double r = Math.min(e, m); + t = (double)floor(r / d) * d; + } else { + t = 0.0D; + }*/ + //return this.sample(i, j, k, l, m - t, n, o, p, q); + return this.sample3d(i, j, k, l, m, n, o, p, q); + } + + private double sample3d(int sectionX, int sectionY, int sectionZ, double localX, double localY, double localZ, double fadeLocalX, double fadeLocalY, double fadeLocalZ) { + int i = this.getGradient(sectionX) + sectionY; + int j = this.getGradient(i) + sectionZ; + int k = this.getGradient(i + 1) + sectionZ; + int l = this.getGradient(sectionX + 1) + sectionY; + int m = this.getGradient(l) + sectionZ; + int n = this.getGradient(l + 1) + sectionZ; + double d = grad3d(this.getGradient(j), localX, localY, localZ); + double e = grad3d(this.getGradient(m), localX - 1.0D, localY, localZ); + double f = grad3d(this.getGradient(k), localX, localY - 1.0D, localZ); + double g = grad3d(this.getGradient(n), localX - 1.0D, localY - 1.0D, localZ); + double h = grad3d(this.getGradient(j + 1), localX, localY, localZ - 1.0D); + double o = grad3d(this.getGradient(m + 1), localX - 1.0D, localY, localZ - 1.0D); + double p = grad3d(this.getGradient(k + 1), localX, localY - 1.0D, localZ - 1.0D); + double q = grad3d(this.getGradient(n + 1), localX - 1.0D, localY - 1.0D, localZ - 1.0D); + return lerp3(fadeLocalX, fadeLocalY, fadeLocalZ, d, e, f, g, h, o, p, q); + } + + private static double grad3d(int hash, double x, double y, double z) { + int i = hash & 15; + return dot3d(gradients3d[i], x, y, z); + } + + protected static double dot3d(int[] gArr, double x, double y, double z) { + return (double)gArr[0] * x + (double)gArr[1] * y + (double)gArr[2] * z; + } + + public static double lerp3(double deltaX, double deltaY, double deltaZ, double d, double e, double f, double g, double h, double i, double j, double k) { + return lerp(deltaZ, lerp2(deltaX, deltaY, d, e, f, g), lerp2(deltaX, deltaY, h, i, j, k)); + } + + //2D + public double sample2d(double x, double y) {//, double d, double e) { + double f = x + this.originX; + double g = y + this.originY; + int i = floor(f); + int j = floor(g); + double l = f - (double)i; + double m = g - (double)j; + double o = perlinFade(l); + double p = perlinFade(m); + return this.sample2d(i, j, l, m, o, p); + } + + private double sample2d(int sectionX, int sectionY, double localX, double localY, double fadeLocalX, double fadeLocalY) { + int j = this.getGradient(sectionX) + sectionY; + int m = this.getGradient(sectionX + 1) + sectionY; + double d = grad2d(this.getGradient(j), localX, localY); + double e = grad2d(this.getGradient(m), localX - 1.0D, localY); + double f = grad2d(this.getGradient(j+1), localX, localY - 1.0D); + double g = grad2d(this.getGradient(m+1), localX - 1.0D, localY - 1.0D); + + return lerp2(fadeLocalX, fadeLocalY, d, e, f, g); + } + + private static double grad2d(int hash, double x, double y) { + int i = hash & 3; + return dot2d(gradients2d[i], x, y); + } + + protected static double dot2d(int[] gArr, double x, double y) { + return (double)gArr[0] * x + (double)gArr[1] * y; + } + + public static double lerp2(double deltaX, double deltaY, double d, double e, double f, double g) { + return lerp(deltaY, lerp(deltaX, d, e), lerp(deltaX, f, g)); + } + + // 1D + public double sample1d(double x) {//, double d, double e) { + double f = x + this.originX; + int i = floor(f); + double l = f - (double)i; + double o = perlinFade(l); + return this.sample1d(i, l, o); + } + private double sample1d(int sectionX, double localX, double fadeLocalX) { + double d = grad1d(this.getGradient(sectionX), localX); + double e = grad1d(this.getGradient(sectionX+1), localX - 1.0D); + return lerp(fadeLocalX, d, e); + } + + private static double grad1d(int hash, double x) { + return ((hash & 1) == 0)? x:-x; + } + + public static double lerp(double delta, double first, double second) { + return first + delta * (second - first); + } + + // shared + public int getGradient(int hash) { + return this.permutations[hash & 255] & 255; + } + + public static double perlinFade(double d) { + return d * d * d * (d * (d * 6.0D - 15.0D) + 10.0D); + } + + public static int floor(double d) { + int i = (int)d; + return d < (double)i ? i - 1 : i; + } +} \ No newline at end of file diff --git a/src/main/java/carpet/script/utils/SimplexNoiseSampler.java b/src/main/java/carpet/script/utils/SimplexNoiseSampler.java new file mode 100644 index 00000000..06c5b71b --- /dev/null +++ b/src/main/java/carpet/script/utils/SimplexNoiseSampler.java @@ -0,0 +1,67 @@ +package carpet.script.utils; + +import java.util.Random; + +public class SimplexNoiseSampler extends PerlinNoiseSampler { + private static final double sqrt3 = Math.sqrt(3.0D); + private static final double SKEW_FACTOR_2D; + private static final double UNSKEW_FACTOR_2D; + + public static SimplexNoiseSampler instance = new SimplexNoiseSampler(new Random(0)); + + public SimplexNoiseSampler(Random random) { + super(random); + } + + private double grad(int hash, double x, double y, double z, double d) { + double e = d - x * x - y * y - z * z; + double g; + if (e < 0.0D) { + g = 0.0D; + } else { + e *= e; + g = e * e * PerlinNoiseSampler.dot3d(PerlinNoiseSampler.gradients3d[hash], x, y, z); + } + + return g; + } + + public double sample(double x, double y) { + double d = (x + y) * SKEW_FACTOR_2D; + int i = PerlinNoiseSampler.floor(x + d); + int j = PerlinNoiseSampler.floor(y + d); + double e = (double)(i + j) * UNSKEW_FACTOR_2D; + double f = (double)i - e; + double g = (double)j - e; + double h = x - f; + double k = y - g; + byte n; + byte o; + if (h > k) { + n = 1; + o = 0; + } else { + n = 0; + o = 1; + } + + double p = h - (double)n + UNSKEW_FACTOR_2D; + double q = k - (double)o + UNSKEW_FACTOR_2D; + double r = h - 1.0D + 2.0D * UNSKEW_FACTOR_2D; + double s = k - 1.0D + 2.0D * UNSKEW_FACTOR_2D; + int t = i & 255; + int u = j & 255; + int v = this.getGradient(t + this.getGradient(u)) % 12; + int w = this.getGradient(t + n + this.getGradient(u + o)) % 12; + int z = this.getGradient(t + 1 + this.getGradient(u + 1)) % 12; + double aa = this.grad(v, h, k, 0.0D, 0.5D); + double ab = this.grad(w, p, q, 0.0D, 0.5D); + double ac = this.grad(z, r, s, 0.0D, 0.5D); + return 70.0D * (aa + ab + ac); + } + + static { + SKEW_FACTOR_2D = 0.5D * (sqrt3 - 1.0D); + UNSKEW_FACTOR_2D = (3.0D - sqrt3) / 6.0D; + } +} \ No newline at end of file