statping-ng/utils/perlin.go

119 lines
1.8 KiB
Go

package utils
import (
"math"
"math/rand"
)
const (
B = 0x100
N = 0x1000
BM = 0xff
)
func NewPerlin(alpha, beta float64, n int, seed int64) *Perlin {
return NewPerlinRandSource(alpha, beta, n, rand.NewSource(seed))
}
// Perlin is the noise generator
type Perlin struct {
alpha float64
beta float64
n int
p [B + B + 2]int
g3 [B + B + 2][3]float64
g2 [B + B + 2][2]float64
g1 [B + B + 2]float64
}
func NewPerlinRandSource(alpha, beta float64, n int, source rand.Source) *Perlin {
var p Perlin
var i int
p.alpha = alpha
p.beta = beta
p.n = n
r := rand.New(source)
for i = 0; i < B; i++ {
p.p[i] = i
p.g1[i] = float64((r.Int()%(B+B))-B) / B
for j := 0; j < 2; j++ {
p.g2[i][j] = float64((r.Int()%(B+B))-B) / B
}
normalize2(&p.g2[i])
}
for ; i > 0; i-- {
k := p.p[i]
j := r.Int() % B
p.p[i] = p.p[j]
p.p[j] = k
}
for i := 0; i < B+2; i++ {
p.p[B+i] = p.p[i]
p.g1[B+i] = p.g1[i]
for j := 0; j < 2; j++ {
p.g2[B+i][j] = p.g2[i][j]
}
for j := 0; j < 3; j++ {
p.g3[B+i][j] = p.g3[i][j]
}
}
return &p
}
func normalize2(v *[2]float64) {
s := math.Sqrt(v[0]*v[0] + v[1]*v[1])
v[0] = v[0] / s
v[1] = v[1] / s
}
func (p *Perlin) Noise1D(x float64) float64 {
var scale float64 = 1
var sum float64
px := x
for i := 0; i < p.n; i++ {
val := p.noise1(px)
sum += val / scale
scale *= p.alpha
px *= p.beta
}
if sum < 0 {
sum = sum * -1
}
return sum
}
func (p *Perlin) noise1(arg float64) float64 {
var vec [1]float64
vec[0] = arg
t := vec[0] + N
bx0 := int(t) & BM
bx1 := (bx0 + 1) & BM
rx0 := t - float64(int(t))
rx1 := rx0 - 1.
sx := sCurve(rx0)
u := rx0 * p.g1[p.p[bx0]]
v := rx1 * p.g1[p.p[bx1]]
return lerp(sx, u, v)
}
func sCurve(t float64) float64 {
return t * t * (3. - 2.*t)
}
func lerp(t, a, b float64) float64 {
return a + t*(b-a)
}