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) }