-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathterrain_map.go
92 lines (81 loc) · 2.65 KB
/
terrain_map.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
package gen
import (
"github.com/df-mc/dragonfly/server/world"
"github.com/df-mc/dragonfly/server/world/chunk"
"math"
)
// terrainColumn is a column part of a terrainMap. It holds information on the Biome in that column and the height
// produced by that biome.
type terrainColumn struct {
height float64
biome Biome
}
// terrainMap holds terrain information about an area of the world in the form of columns with heights and biomes.
type terrainMap []terrainColumn
// calculateTerrainMap calculates a terrainMap at a specific world.ChunkPos. The r value passed specifies how much space
// around the chunk's bounds is also calculated to prepare for smoothing the terrain map.
func calculateTerrainMap(r int, pos world.ChunkPos, g *Generator, chunk *chunk.Chunk) terrainMap {
d := triangulate(pos, 20, 0.06)
cells := voronoiCells(d)
g.displayDiagram(d, 128, chunk)
baseX, baseY := int(pos[0]<<4), int(pos[1]<<4)
dx := 2*r + 16
m := make(terrainMap, dx*dx)
for x := -r; x < 16+r; x++ {
for y := -r; y < 16+r; y++ {
biome := g.biome(int32(baseX), int32(baseY), int32(x+baseX), int32(y+baseY), cells)
m[(x+r)+(y+r)*dx] = terrainColumn{
height: biome.Height(float64(baseX+x), float64(baseY+y)) * 128,
biome: biome,
}
}
}
return m
}
// smooth smooths the terrainMap where r specifies the radius of the circle around a column that influences the final
// height of a block. The curve passed has an influence on the weight of another height around a column at a specific
// distance.
func (m terrainMap) smooth(r int, c curve) terrainMap {
var (
rf = float64(r)
curveStepSize = float64(len(c)) / rf
dx = 16
smooth = make(terrainMap, dx*dx)
norm, height float64
biome Biome
)
for x := 0; x < dx; x++ {
for y := 0; y < dx; y++ {
norm, height = 0, 0
thisCol := m[(x+r)+(y+r)*(dx+r*2)]
thisHeight := thisCol.height
biome = thisCol.biome
for xx := -r; xx <= r; xx++ {
for yy := -r; yy <= r; yy++ {
if xx == 0 && yy == 0 {
continue
}
dist := math.Sqrt(float64(xx*xx) + float64(yy*yy))
if dist > rf {
// The block fell outside of the circle so we don't need to check this. These blocks have a relatively
// small radius and ignoring them makes for an improvement in performance without losing accuracy.
continue
}
weight := c.at(int(math.Floor(curveStepSize * dist)))
norm += weight
col := m[(x+xx+r)+(y+yy+r)*(dx+r*2)]
h := col.height
if col.biome == biome {
h = thisHeight
}
height += weight * h
}
}
smooth[x+y*dx] = terrainColumn{
height: height / norm,
biome: biome,
}
}
}
return smooth
}