Here is a version I ported from C code (only 1D and 2D). I added the NoiseSize variables to set where the pattern repeats.
Strict
Import brl.random
' Perlin Noise
Type TPerlin
Field NoiseSizeX: Int
Field NoiseSizeY: Int
Field NoiseSizeZ: Int
Const BN = $100
Const BM = $FF
Const N = $1000
Const NP = 12 ' 2^N
Const NM = $FFF
Field p: Int[BN + BN + 2]
Field g1: Double[BN + BN + 2]
Field g2: Double[BN + BN + 2, 2]
Const DEFAULT_NOISE_SIZE = $10000
Method Init (XS: Int = 0, YS: Int = 0, ZS: Int = 0)
Local i: Int, j: Int, k: Int
Local s: Double
If XS <= 0 Then XS = DEFAULT_NOISE_SIZE
If YS <= 0 Then YS = DEFAULT_NOISE_SIZE
If ZS <= 0 Then ZS = DEFAULT_NOISE_SIZE
NoiseSizeX = XS
NoiseSizeY = YS
NoiseSizeZ = ZS
For i = 0 To BN - 1
p[i] = i
g1[i] = Double (Rand (0, BN + BN - 1) - BN) / BN
For j = 0 To 1
g2[i, j] = Double (Rand (0, BN + BN - 1) - BN) / BN
Next
s = Sqr (g2[i, 0] * g2[i, 0] + g2[i, 1] * g2[i, 1])
g2[i, 0] = g2[i, 0] / s
g2[i, 1] = g2[i, 1] / s
Next
For i = BN - 1 To 0 Step -1
k = p[i]
j = Rand (0, BN - 1)
p[i] = p[j]
p[j] = k
Next
For i = 0 To BN + 1
p[BN + i] = p[i]
g1[BN + i] = g1[i]
For j = 0 To 1
g2[BN + i, j] = g2[i, j]
Next
Next
End Method
Method S_Curve: Double (t: Double)
Return t * t * (3.0 - 2.0 * t)
End Method
Method Lerp: Double (t: Double, a: Double, b: Double)
Return a + t * (b - a)
End Method
Method Noise1: Double (x: Double)
Local t: Double = x + N
Local bx0: Int = Int (Floor (t) Mod NoiseSizeX) & BM
Local bx1: Int = Int ((bx0 + 1) Mod NoiseSizeX) & BM
Local rx0: Double = t - (Floor (t))
Local rx1: Double = rx0 - 1.0
Local sx: Double = s_curve (rx0)
Local u: Double = rx0 * g1[p[bx0]]
Local v: Double = rx1 * g1[p[bx1]]
Local c: Double = 0.5 + Lerp (sx, u, v)
If c < 0.0 Then c = 0.0 Else If c > 0.99999999 Then c = 0.99999999
Return c
End Method
Method Noise2: Double (x: Double, y: Double)
Local t: Double = Double (x + N)
Local bx0: Int = Int (Floor (t) Mod NoiseSizeX) & BM
Local bx1: Int = Int ((bx0 + 1) Mod NoiseSizeX) & BM
Local rx0: Double = t - (Floor (t))
Local rx1: Double = rx0 - 1.0
t = y + N
Local by0: Int = Int (Floor (t) Mod NoiseSizeY) & BM
Local by1: Int = Int ((by0 + 1) Mod NoiseSizeY) & BM
Local ry0: Double = t - (Floor (t))
Local ry1: Double = ry0 - 1.0
Local i: Int = p[bx0]
Local j: Int = p[bx1]
Local b00: Int = p[i + by0]
Local b10: Int = p[j + by0]
Local b01: Int = p[i + by1]
Local b11: Int = p[j + by1]
Local sx: Double = s_curve (rx0)
Local sy: Double = s_curve (ry0)
Local u: Double = rx0 * g2[b00, 0] + ry0 * g2[b00, 1]
Local v: Double = rx1 * g2[b10, 0] + ry0 * g2[b10, 1]
Local a: Double = lerp (sx, u, v)
u = rx0 * g2[b01, 0] + ry1 * g2[b01, 1]
v = rx1 * g2[b11, 0] + ry1 * g2[b11, 1]
Local b: Double = Lerp (sx, u, v)
Local c: Double = 0.5 + Lerp (sy, a, b)
If c < 0.0 Then c = 0.0 Else If c > 0.99999999 Then c = 0.99999999
Return c
End Method
End Type
And here is a small example:
Strict
Import brl.random
Import "Perlin.bmx"
Const SCREEN_WIDTH = 320
Const SCREEN_HEIGHT = 240
Local i: Int, j: Int
Local r: Int, g: Int, b: Int
Local f: Double
Local x: Double, y: Double
Local u: Double, v: Double
Local Perlin: TPerlin = New TPerlin
Perlin.Init (10, 10, 10)
x = 0.0
y = 0.0
Graphics SCREEN_WIDTH, SCREEN_HEIGHT
Repeat
For j = 0 To SCREEN_HEIGHT - 1
For i = 0 To SCREEN_WIDTH - 1
u = Float (i) / 100.0
v = Float (j) / 100.0
f = Perlin.Noise2 (x + u, y + v)
r = f * 128.0
g = 128 - f * 128.0
b = f * 255.0
SetColor r, g, b
DrawRect (i, j, 1, 1)
Next
Next
Flip ()
x :+ 0.1
y :+ 0.1
Until AppTerminate () Or KeyHit (KEY_ESCAPE)
EndGraphics
|