/
terrain.go
103 lines (92 loc) · 2.38 KB
/
terrain.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
package world
import (
"encoding/binary"
"log"
"math"
"os"
"github.com/eaglesight/eaglesight-server/mathutils"
)
// Terrain ...
type Terrain struct {
width uint
depth uint
distance float64
points []uint16
}
// LoadTerrain loads the terrain
func LoadTerrain(filePath string) (*Terrain, error) {
reader, err := os.Open(filePath)
if err != nil {
log.Fatal(err)
}
defer reader.Close()
t := Terrain{
width: 0,
depth: 0,
distance: 0.0,
}
// We read the header
header := make([]byte, 2+2+2+4)
_, err = reader.Read(header[:])
if err != nil {
return &t, err
}
// Load the width
t.width = uint(binary.LittleEndian.Uint16(header[0:2]))
// Load the depth
t.depth = uint(binary.LittleEndian.Uint16(header[2:4]))
// Load the distance
t.distance = float64(math.Float32frombits(binary.LittleEndian.Uint32(header[6:10])))
// Here comes the me
t.points = make([]uint16, t.width*t.depth)
data := make([]byte, t.width*t.depth*2)
_, err = reader.Read(data)
for i := 0; i < len(t.points); i++ {
if err != nil {
return &t, err
}
t.points[i] = binary.LittleEndian.Uint16(data[i*2 : i*2+2])
}
return &t, nil
}
// OverredTriangle find the triangle that is overred by the vector pos. Return a triangle made of 3 Vector3D
func (t *Terrain) OverredTriangle(pos mathutils.Vector3D) (s [3]mathutils.Vector3D) {
// 0 1
// 2 3
col := uint(math.Ceil(pos.X / t.distance)) // X
row := uint(math.Ceil(pos.Z / t.distance)) // Z
// We check if we are out of bound
if col < 0 || col >= t.width-1 || row < 0 || row >= t.depth-1 {
s[0].X = math.NaN()
return s // s[0] == NaN if out of bound
}
// UP LEFT
index0 := row*t.width + col
s[0].X = float64(index0%t.width) * t.distance
s[0].Y = float64(t.points[index0])
s[0].Z = math.Ceil(float64(index0/t.width)) * t.distance
if math.Mod(pos.X, t.distance) > math.Mod(pos.Z, t.distance) {
// DOWN RIGHT
index1 := index0 + 1 + t.width
s[1].X = s[0].X + t.distance
s[1].Y = float64(t.points[index1])
s[1].Z = s[0].Z + t.distance
// UP RIGHT
index2 := index0 + 1
s[2].X = s[1].X
s[2].Y = float64(t.points[index2])
s[2].Z = s[0].Z
} else {
// DOWN LEFT
index1 := index0 + t.width
s[1].X = s[0].X
s[1].Y = float64(t.points[index1])
s[1].Z = s[0].Z + t.distance
// DOWN RIGHT
index2 := index0 + 1 + t.width
s[2].X = s[0].X + t.distance
s[2].Y = float64(t.points[index2])
s[2].Z = s[1].Z
}
return s
}