diff --git a/noise/lookup.v b/noise/lookup.v new file mode 100644 index 000000000..23f8458c5 --- /dev/null +++ b/noise/lookup.v @@ -0,0 +1,516 @@ +module noise + +const permutations = [ + 151, + 160, + 137, + 91, + 90, + 15, + 131, + 13, + 201, + 95, + 96, + 53, + 194, + 233, + 7, + 225, + 140, + 36, + 103, + 30, + 69, + 142, + 8, + 99, + 37, + 240, + 21, + 10, + 23, + 190, + 6, + 148, + 247, + 120, + 234, + 75, + 0, + 26, + 197, + 62, + 94, + 252, + 219, + 203, + 117, + 35, + 11, + 32, + 57, + 177, + 33, + 88, + 237, + 149, + 56, + 87, + 174, + 20, + 125, + 136, + 171, + 168, + 68, + 175, + 74, + 165, + 71, + 134, + 139, + 48, + 27, + 166, + 77, + 146, + 158, + 231, + 83, + 111, + 229, + 122, + 60, + 211, + 133, + 230, + 220, + 105, + 92, + 41, + 55, + 46, + 245, + 40, + 244, + 102, + 143, + 54, + 65, + 25, + 63, + 161, + 1, + 216, + 80, + 73, + 209, + 76, + 132, + 187, + 208, + 89, + 18, + 169, + 200, + 196, + 135, + 130, + 116, + 188, + 159, + 86, + 164, + 100, + 109, + 198, + 173, + 186, + 3, + 64, + 52, + 217, + 226, + 250, + 124, + 123, + 5, + 202, + 38, + 147, + 118, + 126, + 255, + 82, + 85, + 212, + 207, + 206, + 59, + 227, + 47, + 16, + 58, + 17, + 182, + 189, + 28, + 42, + 223, + 183, + 170, + 213, + 119, + 248, + 152, + 2, + 44, + 154, + 163, + 70, + 221, + 153, + 101, + 155, + 167, + 43, + 172, + 9, + 129, + 22, + 39, + 253, + 19, + 98, + 108, + 110, + 79, + 113, + 224, + 232, + 178, + 185, + 112, + 104, + 218, + 246, + 97, + 228, + 251, + 34, + 242, + 193, + 238, + 210, + 144, + 12, + 191, + 179, + 162, + 241, + 81, + 51, + 145, + 235, + 249, + 14, + 239, + 107, + 49, + 192, + 214, + 31, + 181, + 199, + 106, + 157, + 184, + 84, + 204, + 176, + 115, + 121, + 50, + 45, + 127, + 4, + 150, + 254, + 138, + 236, + 205, + 93, + 222, + 114, + 67, + 29, + 24, + 72, + 243, + 141, + 128, + 195, + 78, + 66, + 215, + 61, + 156, + 180, + 151, + 160, + 137, + 91, + 90, + 15, + 131, + 13, + 201, + 95, + 96, + 53, + 194, + 233, + 7, + 225, + 140, + 36, + 103, + 30, + 69, + 142, + 8, + 99, + 37, + 240, + 21, + 10, + 23, + 190, + 6, + 148, + 247, + 120, + 234, + 75, + 0, + 26, + 197, + 62, + 94, + 252, + 219, + 203, + 117, + 35, + 11, + 32, + 57, + 177, + 33, + 88, + 237, + 149, + 56, + 87, + 174, + 20, + 125, + 136, + 171, + 168, + 68, + 175, + 74, + 165, + 71, + 134, + 139, + 48, + 27, + 166, + 77, + 146, + 158, + 231, + 83, + 111, + 229, + 122, + 60, + 211, + 133, + 230, + 220, + 105, + 92, + 41, + 55, + 46, + 245, + 40, + 244, + 102, + 143, + 54, + 65, + 25, + 63, + 161, + 1, + 216, + 80, + 73, + 209, + 76, + 132, + 187, + 208, + 89, + 18, + 169, + 200, + 196, + 135, + 130, + 116, + 188, + 159, + 86, + 164, + 100, + 109, + 198, + 173, + 186, + 3, + 64, + 52, + 217, + 226, + 250, + 124, + 123, + 5, + 202, + 38, + 147, + 118, + 126, + 255, + 82, + 85, + 212, + 207, + 206, + 59, + 227, + 47, + 16, + 58, + 17, + 182, + 189, + 28, + 42, + 223, + 183, + 170, + 213, + 119, + 248, + 152, + 2, + 44, + 154, + 163, + 70, + 221, + 153, + 101, + 155, + 167, + 43, + 172, + 9, + 129, + 22, + 39, + 253, + 19, + 98, + 108, + 110, + 79, + 113, + 224, + 232, + 178, + 185, + 112, + 104, + 218, + 246, + 97, + 228, + 251, + 34, + 242, + 193, + 238, + 210, + 144, + 12, + 191, + 179, + 162, + 241, + 81, + 51, + 145, + 235, + 249, + 14, + 239, + 107, + 49, + 192, + 214, + 31, + 181, + 199, + 106, + 157, + 184, + 84, + 204, + 176, + 115, + 121, + 50, + 45, + 127, + 4, + 150, + 254, + 138, + 236, + 205, + 93, + 222, + 114, + 67, + 29, + 24, + 72, + 243, + 141, + 128, + 195, + 78, + 66, + 215, + 61, + 156, + 180, +] diff --git a/noise/perlin.v b/noise/perlin.v deleted file mode 100644 index 6d37b2fa1..000000000 --- a/noise/perlin.v +++ /dev/null @@ -1,56 +0,0 @@ -module noise - -import math -import rand - -@[inline] -fn random_gradient() !(f32, f32) { - nr := rand.f32_in_range(0.0, math.pi * 2) or { return err } - return math.cosf(nr), math.sinf(nr) -} - -@[inline] -fn interpolate(a f32, b f32, w f32) f32 { - return ((a - b) * w) + a -} - -@[inline] -fn dot(ix int, iy int, x f32, y f32) !f32 { - vec_x, vec_y := random_gradient()! - dx := x - f32(ix) - dy := y - f32(iy) - return dx * vec_x + dy * vec_y -} - -// perlin2d is a function that returns a perlin noise value for a given x and y coordinate -pub fn perlin2d(x f32, y f32) !f32 { - x1 := int(math.floor(x)) - y1 := int(math.floor(y)) - x2 := x1 + 1 - y2 := y1 + 1 - - sx := x - f32(x1) - sy := y - f32(y2) - - n0 := dot(x1, y1, x, y)! - n1 := dot(x2, y1, x, y)! - first := interpolate(n0, n1, sx) - - n2 := dot(x1, y2, x, y)! - n3 := dot(x2, y2, x, y)! - second := interpolate(n2, n3, sx) - - return interpolate(first, second, sy) -} - -// perlin2d_space is a function that returns a 2d array of perlin noise values for a given width and height -pub fn perlin2d_space(w int, h int) ![][]f32 { - mut res := [][]f32{len: h, init: []f32{len: w}} - for i, a in res { - for j, _ in a { - val := perlin2d(j, i)! - res[i][j] = val - } - } - return res -} diff --git a/noise/perlin2d.v b/noise/perlin2d.v new file mode 100644 index 000000000..a65a553cf --- /dev/null +++ b/noise/perlin2d.v @@ -0,0 +1,69 @@ +module noise + +import rand + +pub struct Perlin { +mut: + perm []int = rand.shuffle_clone(permutations) or { panic(err) } +} + +// randomize is a function that shuffle the permutation set inside the Perlin struct +// will not shuffle if rand.seed is not changed +pub fn (mut perlin Perlin) randomize() { + perlin.perm = rand.shuffle_clone(permutations) or { panic(err) } +} + +// perlin2d is a function that return a single value of perlin noise for a given 2d position +pub fn (perlin Perlin) perlin2d(x f64, y f64) f64 { + xi := int(x) & 0xFF + yi := int(y) & 0xFF + + xf := x - int(x) + yf := y - int(y) + + u := fade(xf) + v := fade(yf) + + pxi := perlin.perm[xi] + pxi1 := perlin.perm[xi + 1] + + aa := perlin.perm[pxi + yi] + ab := perlin.perm[pxi + yi + 1] + ba := perlin.perm[pxi1 + yi] + bb := perlin.perm[pxi1 + yi + 1] + + x1 := lerp(grad2d(aa, xf, yf), grad2d(ba, xf - 1, yf), u) + x2 := lerp(grad2d(ab, xf, yf - 1), grad2d(bb, xf - 1, yf - 1), u) + + return (lerp(x1, x2, v) + 1) / 2 +} + +fn fade(t f64) f64 { + return t * t * t * (t * (t * 6.0 - 15.0) + 10.0) +} + +fn grad2d(hash int, x f64, y f64) f64 { + match hash & 0xF { + 0x0 { return x + y } + 0x1 { return -x + y } + 0x2 { return x - y } + 0x3 { return -x - y } + 0x4 { return x } + 0x5 { return -x } + 0x6 { return x } + 0x7 { return -x } + 0x8 { return y } + 0x9 { return -y } + 0xA { return y } + 0xB { return -y } + 0xC { return y + x } + 0xD { return -y } + 0xE { return y - x } + 0xF { return -y } + else { return 0 } + } +} + +fn lerp(a f64, b f64, x f64) f64 { + return a + x * (b - a) +} diff --git a/noise/perlin2d_test.v b/noise/perlin2d_test.v new file mode 100644 index 000000000..1b4ef4c88 --- /dev/null +++ b/noise/perlin2d_test.v @@ -0,0 +1,14 @@ +module noise + +import math { abs } +import rand + +const single_perlin = f64(0.4948387311305851) + +fn test_perlin2d() { + rand.seed([u32(3155200429), u32(3208395956)]) + mut gen := Perlin{} + gen.randomize() + + assert abs(gen.perlin2d(0.125, 0.125) - noise.single_perlin) < 1.0e-6 +} diff --git a/noise/perlin3d.v b/noise/perlin3d.v new file mode 100644 index 000000000..a0ebdcd06 --- /dev/null +++ b/noise/perlin3d.v @@ -0,0 +1,61 @@ +module noise + +// perlin3d is a function that return a single value of perlin noise for a given 3d position +pub fn (perlin Perlin) perlin3d(x f64, y f64, z f64) f64 { + xi := int(x) & 0xFF + yi := int(y) & 0xFF + zi := int(z) & 0xFF + xf := x - int(x) + yf := y - int(y) + zf := z - int(z) + u := fade(xf) + v := fade(yf) + w := fade(zf) + + pxi := perlin.perm[xi] + pxi_yi := perlin.perm[pxi + yi] + pxi_yi1 := perlin.perm[pxi + yi + 1] + pxi1 := perlin.perm[xi + 1] + pxi1_yi := perlin.perm[pxi1 + yi] + pxi1_yi1 := perlin.perm[pxi1 + yi + 1] + + aaa := perlin.perm[pxi_yi + zi] + aba := perlin.perm[pxi_yi1 + zi] + aab := perlin.perm[pxi_yi + zi + 1] + abb := perlin.perm[pxi_yi1 + zi + 1] + baa := perlin.perm[pxi1_yi + zi] + bba := perlin.perm[pxi1_yi1 + zi] + bab := perlin.perm[pxi1_yi + zi + 1] + bbb := perlin.perm[pxi1_yi1 + zi + 1] + + mut x1 := lerp(grad3d(aaa, xf, yf, zf), grad3d(baa, xf - 1, yf, zf), u) + mut x2 := lerp(grad3d(aba, xf, yf - 1, zf), grad3d(bba, xf - 1, yf - 1, zf), u) + y1 := lerp(x1, x2, v) + x1 = lerp(grad3d(aab, xf, yf, zf - 1), grad3d(bab, xf - 1, yf, zf - 1), u) + x2 = lerp(grad3d(abb, xf, yf - 1, zf - 1), grad3d(bbb, xf - 1, yf - 1, zf - 1), u) + y2 := lerp(x1, x2, v) + + return (lerp(y1, y2, w) + 1) / 2 +} + +fn grad3d(hash int, x f64, y f64, z f64) f64 { + match hash & 0xF { + 0x0 { return x + y } + 0x1 { return -x + y } + 0x2 { return x - y } + 0x3 { return -x - y } + 0x4 { return x + z } + 0x5 { return -x + z } + 0x6 { return x - z } + 0x7 { return -x - z } + 0x8 { return y + z } + 0x9 { return -y + z } + 0xA { return y - z } + 0xB { return -y - z } + 0xC { return y + x } + 0xD { return -y + z } + 0xE { return y - x } + 0xF { return -y - z } + else { return 0 } + } +} diff --git a/noise/perlin3d_test.v b/noise/perlin3d_test.v new file mode 100644 index 000000000..6a34998a7 --- /dev/null +++ b/noise/perlin3d_test.v @@ -0,0 +1,14 @@ +module noise + +import math { abs } +import rand + +const single_perlin_3d = f64(0.3713334855776509) + +fn test_perlin3d() { + rand.seed([u32(3155200429), u32(3208395956)]) + mut gen := Perlin{} + gen.randomize() + + assert abs(gen.perlin3d(0.125, 0.125, 0.125) - noise.single_perlin_3d) < 1.0e-6 +} diff --git a/noise/perlin_test.v b/noise/perlin_test.v deleted file mode 100644 index 6a3049a12..000000000 --- a/noise/perlin_test.v +++ /dev/null @@ -1,31 +0,0 @@ -module noise - -import math { abs } -import rand - -const single_perlin = f32(0.9920886) - -const square_perlin = [ - [f32(0.9920886), -0.9148169], - [f32(0.4479326), 0.7049548], -] - -fn test_perlin2d() { - rand.seed([u32(114764230), 293925637]) - - x := perlin2d(0.0, 0.0)! - println(' x is ${x:11.9}') - assert abs(x - noise.single_perlin) < 1.0e-6 -} - -fn test_perlin2d_space() { - rand.seed([u32(114764230), 293925637]) - y := perlin2d_space(2, 2)! - - println(' y is ${y:13.11}') - for i, _ in y { - for j, _ in y[i] { - assert y[i][j] - noise.square_perlin[i][j] < 1.0e-6 - } - } -}