Skip to content

Instantly share code, notes, and snippets.

@sixthgear
Created June 3, 2013 22:31
Show Gist options
  • Save sixthgear/5702034 to your computer and use it in GitHub Desktop.
Save sixthgear/5702034 to your computer and use it in GitHub Desktop.
package main
import "math"
import "github.com/sixthgear/noise"
import "github.com/go-gl/gl"
type Vertex struct {
x, y, z float32
}
var colorMap [][3]float32 = [][3]float32{
{0.0, 0.0, 0.7},
{0.2, 0.5, 1.0},
{0.5, 0.5, 0.4},
{1.0, 1.0, 0.9},
{0.1, 0.4, 0.1},
{0.1, 0.4, 0.1},
{0.2, 0.2, 0.2},
{0.3, 0.3, 0.3},
{0.3, 0.3, 0.3},
{0.3, 0.3, 0.3},
{0.3, 0.3, 0.3},
{0.3, 0.3, 0.3},
{0.3, 0.3, 0.3},
{0.3, 0.3, 0.3},
{0.3, 0.3, 0.3},
{0.3, 0.3, 0.3},
{0.3, 0.3, 0.3},
{0.3, 0.3, 0.3},
{0.3, 0.3, 0.3},
{1.0, 1.0, 1.0},
}
const (
RIGHT = iota
LEFT
)
type Map struct {
width, depth int
heightMap []float32
vertices []float32
normals []float32
colors []float32
texcoords []float32
texture gl.Texture
gridSize int
minHeight float64
maxHeight float64
}
func Cross(v1 Vertex, v2 Vertex) Vertex {
n := Vertex{}
n.x = v1.y*v2.z - v1.z*v2.y
n.y = v1.z*v2.x - v1.x*v2.z
n.z = v1.x*v2.y - v1.y*v2.x
return n
}
func GenerateMap(width, depth int, gridSize int) *Map {
m := new(Map)
m.width = width
m.depth = depth
m.gridSize = gridSize
m.minHeight = 1000000
m.maxHeight = 0
diag := math.Hypot(float64(m.width/2), float64(m.depth/2))
for z := 0; z < depth; z++ {
for x := 0; x < width; x++ {
fx := float64(x) + float64(z%2)*0.5
fz := float64(z)
d := math.Hypot(float64(m.width/2)-fx, float64(m.depth/2)-fz)
d = 1.0 - d/diag
h := noise.OctaveNoise2d(fx, fz, 4, 0.25, 1.0/30)
h = (h + 1.0) * 0.5
h = math.Sqrt(h) * 1024 * (math.Pow(d, 2.2))
h = math.Max(h, 120)
m.heightMap = append(m.heightMap, float32(h))
m.minHeight = math.Min(m.minHeight, h)
m.maxHeight = math.Max(m.maxHeight, h)
}
}
return m
}
func (m *Map) getColorForVertex(v Vertex) [3]float32 {
n := (float64(v.y) - m.minHeight) / (m.maxHeight - m.minHeight) * float64(len(colorMap)-1)
i0 := int(math.Floor(n))
i1 := int(math.Ceil(n))
f := n - math.Floor(n)
if f < 0.01 {
i1 = i0
}
c0 := colorMap[i0]
c1 := colorMap[i1]
color := [3]float32{}
for i := 0; i < 3; i++ {
color[i] = c0[i] + (c1[i]-c0[i])*float32(f)
if n > 2 {
color[i] += float32(noise.OctaveNoise2d(float64(v.x), float64(v.z), 1, 1, 1)) * 0.04
}
}
return color
}
func (m *Map) PlaceVertex(x, z int) Vertex {
s := m.gridSize
xOffset := float32(z % 2 * s / 2)
vx := xOffset + float32(x*s)
vy := m.heightMap[z*m.width+x]
vz := float32(z * s)
return Vertex{vx, vy, vz}
}
func (m *Map) BuildVertices() {
for i := 0; i < (m.depth-1)*(m.width); i++ {
x := i % (m.width)
z := i / (m.width)
num := 2
dir := z % 2
if dir == LEFT {
x = (m.width - 1) - x
}
if dir == RIGHT && x == 0 && z > 0 {
num = 1
}
if dir == LEFT && x == m.width-1 {
num = 1
}
for j := 2 - num; j <= 1; j++ {
v := m.PlaceVertex(x, z+j)
n := m.GetNormal(v, x, z+j)
c := m.getColorForVertex(v)
m.vertices = append(m.vertices, v.x, v.y, v.z)
m.normals = append(m.normals, n.x, n.y, n.z)
m.colors = append(m.colors, c[0], c[1], c[2])
}
}
}
func (m *Map) GetNormal(v Vertex, x, z int) (normal Vertex) {
var neighbors []Vertex
var sum Vertex
if x > 0 {
neighbors = append(neighbors, m.PlaceVertex(x-1, z))
}
if z > 0 {
neighbors = append(neighbors, m.PlaceVertex(x, z-1))
}
if x < m.width-1 {
neighbors = append(neighbors, m.PlaceVertex(x+1, z))
}
if z < m.depth-1 {
neighbors = append(neighbors, m.PlaceVertex(x, z+1))
}
if z%2 == 0 && x > 0 && z > 0 {
neighbors = append(neighbors, m.PlaceVertex(x-1, z-1))
}
if z%2 == 0 && x > 0 && z < m.depth-1 {
neighbors = append(neighbors, m.PlaceVertex(x-1, z+1))
}
if z%2 != 0 && x < m.width-1 && z > 0 {
neighbors = append(neighbors, m.PlaceVertex(x+1, z-1))
}
if z%2 != 0 && x < m.width-1 && z < m.depth-1 {
neighbors = append(neighbors, m.PlaceVertex(x+1, z+1))
}
for i, n1 := range neighbors {
n2 := neighbors[(i+1)%len(neighbors)]
d1 := Vertex{n1.x - v.x, n1.y - v.y, n1.z - v.z}
d2 := Vertex{n2.x - v.x, n2.y - v.y, n2.z - v.z}
cross := Cross(d1, d2)
sum.x += cross.x
sum.y += cross.y
sum.z += cross.z
}
num := float32(len(neighbors))
sum.x /= num
sum.y /= num
sum.z /= num
length := float32(math.Sqrt(float64(sum.x*sum.x + sum.y*sum.y + sum.z*sum.z)))
if length > 0 {
normal.x = sum.x / length
normal.y = sum.y / length
normal.z = sum.z / length
}
if normal.y < 0 {
normal.y *= -1
}
return normal
}
func (m *Map) Draw() {
gl.PushMatrix()
gl.PushAttrib(gl.CURRENT_BIT | gl.ENABLE_BIT | gl.LIGHTING_BIT | gl.POLYGON_BIT | gl.LINE_BIT)
gl.EnableClientState(gl.VERTEX_ARRAY)
gl.VertexPointer(3, gl.FLOAT, 0, m.vertices)
gl.EnableClientState(gl.NORMAL_ARRAY)
gl.NormalPointer(gl.FLOAT, 0, m.normals)
// gl.EnableClientState(gl.TEXTURE_COORD_ARRAY)
// gl.TexCoordPointer(2, gl.FLOAT, 0, m.texcoords)
gl.EnableClientState(gl.COLOR_ARRAY)
gl.ColorPointer(3, gl.FLOAT, 0, m.colors)
// draw solids
gl.Enable(gl.COLOR_MATERIAL)
gl.PolygonMode(gl.FRONT_AND_BACK, gl.LINE)
gl.LineWidth(1.0)
gl.DrawArrays(gl.TRIANGLE_STRIP, 0, len(m.vertices)/3)
gl.PopAttrib()
gl.PopMatrix()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment