-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathblocks.go
148 lines (134 loc) · 2.87 KB
/
blocks.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package texture
import "math/rand"
type BlockNoise struct {
Name string
Domain []float64
Rows int
Cols int
Seed int64
Samps int
UseMax bool
CellW float64
CellH float64
CLen int
cache map[int][][]float64
}
func NewBlockNoise(w, h float64, r, c int, d float64) *BlockNoise {
dom := []float64{w, h}
seed := rand.Int63()
cw, ch := w/float64(c), h/float64(r)
samps := 4 * int(ch*d)
return &BlockNoise{"BlockNoise", dom, r, c, seed, samps, false, cw, ch, 3 * c, make(map[int][][]float64)}
}
// Eval2 implements the Field interface.
func (bn *BlockNoise) Eval2(x, y float64) float64 {
// Wrap x, y
_, x = MapValueToLambda(x, bn.Domain[0])
_, y = MapValueToLambda(y, bn.Domain[1])
fr, fc := y/bn.CellH, x/bn.CellW
r, c := int(fr), int(fc)
x -= bn.CellW * float64(c)
y -= bn.CellH * float64(r)
lw := bn.CellW
lh := 1.0
// Run through #samps to see if we get a hit
var v float64
hit := false
bb := bn.cbCache(r, c, bn.Samps, lw, lh)
if bn.UseMax {
hit, v = testBBH(x, y, bb)
} else {
hit, v = testBB(x, y, bb)
}
if hit {
return v
}
// Need to check the preceding cell (to the left)
c -= 1
if c < 0 {
c = bn.Cols - 1
}
x += bn.CellW
// Run through #samps to see if we get a hit
bb = bn.cbCache(r, c, bn.Samps, lw, lh)
if bn.UseMax {
hit, v = testBBH(x, y, bb)
} else {
hit, v = testBB(x, y, bb)
}
if hit {
return v
}
// Need to check the cell above
c += 1
if c == bn.Cols {
c = 0
}
x -= bn.CellW
r -= 1
if r < 0 {
r = bn.Rows - 1
}
y += bn.CellH
// Run through #samps to see if we get a hit
bb = bn.cbCache(r, c, bn.Samps, lw, lh)
if bn.UseMax {
_, v = testBBH(x, y, bb)
} else {
_, v = testBB(x, y, bb)
}
return v
}
// first hit wins
func testBB(x, y float64, bbs [][]float64) (bool, float64) {
v := -1.0
hit := false
for _, bb := range bbs {
if x < bb[0] || x > bb[2] || y < bb[1] || y > bb[3] {
continue
}
hit = true
v = bb[4]
break
}
return hit, v
}
// largest v wins
func testBBH(x, y float64, bbs [][]float64) (bool, float64) {
v := -1.0
hit := false
for _, bb := range bbs {
if x < bb[0] || x > bb[2] || y < bb[1] || y > bb[3] {
continue
}
hit = true
if v < bb[4] {
v = bb[4]
}
}
return hit, v
}
func (bn *BlockNoise) cbCache(r, c, samps int, w, h float64) [][]float64 {
cind := r*bn.Cols + c
res := bn.cache[cind]
if res != nil {
return res
}
if len(bn.cache) == bn.CLen {
bn.cache = make(map[int][][]float64)
}
res = bn.cellBlocks(r, c, samps, w, h)
bn.cache[cind] = res
return res
}
func (bn *BlockNoise) cellBlocks(r, c, samps int, w, h float64) [][]float64 {
lr := rand.New(rand.NewSource(bn.Seed + int64(r*bn.Cols+c)))
res := make([][]float64, samps)
for i := 0; i < samps; i++ {
ox, oy := lr.Float64()*bn.CellW, lr.Float64()*bn.CellH
dx, dy := lr.Float64()*w, lr.Float64()*h
v := lr.Float64()*2 - 1
res[i] = []float64{ox, oy, ox + dx, oy + dy, v}
}
return res
}