205 lines
7.7 KiB
Go
205 lines
7.7 KiB
Go
|
package world
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"os"
|
||
|
"unsafe"
|
||
|
|
||
|
"github.com/Edgaru089/gl01/internal/asset"
|
||
|
"github.com/Edgaru089/gl01/internal/util/itype"
|
||
|
"github.com/go-gl/gl/all-core/gl"
|
||
|
)
|
||
|
|
||
|
// Vertex represents a rendering vertex in the global coordinate system.
|
||
|
type Vertex struct {
|
||
|
World itype.Vec3f // World vertex coordinate
|
||
|
Normal itype.Vec3f // Surface normal vector (normalized)
|
||
|
Texture itype.Vec2f // World Texture Atlas vertex coordinate
|
||
|
Light float32 // Light level of the block (0 ~ 15=blocklight, 16=sunlight)
|
||
|
}
|
||
|
|
||
|
func (c *Chunk) InitRender() {
|
||
|
gl.GenVertexArrays(1, &c.vao)
|
||
|
gl.GenBuffers(1, &c.vbo)
|
||
|
|
||
|
c.renderChanged = true
|
||
|
}
|
||
|
|
||
|
func (c *Chunk) FreeRender() {
|
||
|
gl.DeleteVertexArrays(1, &c.vao)
|
||
|
gl.DeleteBuffers(1, &c.vbo)
|
||
|
}
|
||
|
|
||
|
// Bind calls glBindVertexArray(vao) and glBindBuffer(vbo).
|
||
|
func (c *Chunk) Bind() {
|
||
|
gl.BindVertexArray(c.vao)
|
||
|
gl.BindBuffer(gl.ARRAY_BUFFER, c.vbo)
|
||
|
}
|
||
|
|
||
|
// EnableVertexArrayAttrib calls glEnableVertexArrayAttrib(vao, attribId).
|
||
|
func (c *Chunk) EnableVertexArrayAttrib(attribId uint32) {
|
||
|
c.Bind()
|
||
|
gl.EnableVertexAttribArray(attribId)
|
||
|
}
|
||
|
|
||
|
// a global vertex array for VBO updates
|
||
|
//var vertex []Vertex
|
||
|
|
||
|
// updateRender should be called with gl.BindBuffer(c.vbo).
|
||
|
func (c *Chunk) updateRender() {
|
||
|
if c.renderChanged {
|
||
|
c.vertex = c.AppendVertex(c.vertex[0:0])
|
||
|
log.Printf("Chunk [%d,%d]: UpdateRender: vertex len of %d*%d = %d", c.X, c.Z, unsafe.Sizeof(Vertex{}), len(c.vertex), int(unsafe.Sizeof(Vertex{}))*len(c.vertex))
|
||
|
|
||
|
f, _ := os.Create("vertex.txt")
|
||
|
fmt.Fprint(f, c.vertex)
|
||
|
f.Close()
|
||
|
|
||
|
gl.BufferData(gl.ARRAY_BUFFER, int(unsafe.Sizeof(Vertex{}))*len(c.vertex), gl.Ptr(c.vertex), gl.DYNAMIC_DRAW)
|
||
|
c.vbolen = len(c.vertex)
|
||
|
|
||
|
c.renderChanged = false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (c *Chunk) Render() {
|
||
|
gl.BindVertexArray(c.vao)
|
||
|
gl.BindBuffer(gl.ARRAY_BUFFER, c.vbo)
|
||
|
c.updateRender()
|
||
|
gl.DrawArrays(gl.TRIANGLES, 0, int32(c.vbolen))
|
||
|
}
|
||
|
|
||
|
// ChunkRenderAppend appends the chunk's global vertex into the array.
|
||
|
func (c *Chunk) AppendVertex(arr []Vertex) []Vertex {
|
||
|
off := itype.Vec3i{
|
||
|
c.X * ChunkSizeX,
|
||
|
0,
|
||
|
c.Z * ChunkSizeZ,
|
||
|
}
|
||
|
|
||
|
for i := 0; i < ChunkSizeX; i++ {
|
||
|
for j := 0; j < ChunkSizeY; j++ {
|
||
|
for k := 0; k < ChunkSizeZ; k++ {
|
||
|
if c.Id[i][j][k] == 0 {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
app := GetBlockAppearance(off.Addv(i, j, k), int(c.Id[i][j][k]), int(c.Aux[i][j][k]), nil)
|
||
|
switch app.RenderType {
|
||
|
case OneTexture:
|
||
|
arr = c.appendFace(itype.XPlus, itype.Vec3i{i, j, k}, app.Name+".png", arr)
|
||
|
arr = c.appendFace(itype.XMinus, itype.Vec3i{i, j, k}, app.Name+".png", arr)
|
||
|
arr = c.appendFace(itype.YPlus, itype.Vec3i{i, j, k}, app.Name+".png", arr)
|
||
|
arr = c.appendFace(itype.YMinus, itype.Vec3i{i, j, k}, app.Name+".png", arr)
|
||
|
arr = c.appendFace(itype.ZPlus, itype.Vec3i{i, j, k}, app.Name+".png", arr)
|
||
|
arr = c.appendFace(itype.ZMinus, itype.Vec3i{i, j, k}, app.Name+".png", arr)
|
||
|
case ThreeTexture:
|
||
|
arr = c.appendFace(itype.XPlus, itype.Vec3i{i, j, k}, app.Name+"_side.png", arr)
|
||
|
arr = c.appendFace(itype.XMinus, itype.Vec3i{i, j, k}, app.Name+"_side.png", arr)
|
||
|
arr = c.appendFace(itype.YPlus, itype.Vec3i{i, j, k}, app.Name+"_top.png", arr)
|
||
|
arr = c.appendFace(itype.YMinus, itype.Vec3i{i, j, k}, app.Name+"_bot.png", arr)
|
||
|
arr = c.appendFace(itype.ZPlus, itype.Vec3i{i, j, k}, app.Name+"_side.png", arr)
|
||
|
arr = c.appendFace(itype.ZMinus, itype.Vec3i{i, j, k}, app.Name+"_side.png", arr)
|
||
|
case SixTexture:
|
||
|
arr = c.appendFace(itype.XPlus, itype.Vec3i{i, j, k}, app.Name+"_x+.png", arr)
|
||
|
arr = c.appendFace(itype.XMinus, itype.Vec3i{i, j, k}, app.Name+"_x-.png", arr)
|
||
|
arr = c.appendFace(itype.YPlus, itype.Vec3i{i, j, k}, app.Name+"_y+.png", arr)
|
||
|
arr = c.appendFace(itype.YMinus, itype.Vec3i{i, j, k}, app.Name+"_y-.png", arr)
|
||
|
arr = c.appendFace(itype.ZPlus, itype.Vec3i{i, j, k}, app.Name+"_z+.png", arr)
|
||
|
arr = c.appendFace(itype.ZMinus, itype.Vec3i{i, j, k}, app.Name+"_z-.png", arr)
|
||
|
case CustomRendering:
|
||
|
arr = app.CustomRenderAppend(off.Addv(i, j, k), int(c.Aux[i][j][k]), nil, arr)
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return arr
|
||
|
}
|
||
|
|
||
|
func (c *Chunk) appendFace(face itype.Direction, pos itype.Vec3i, texname string, arr []Vertex) []Vertex {
|
||
|
|
||
|
off := pos.Addv(c.X*ChunkSizeX, 0, c.Z*ChunkSizeZ).ToFloat32()
|
||
|
|
||
|
// check if we can skip this face
|
||
|
next := pos.Add(itype.DirectionVeci[face])
|
||
|
if next[0] >= 0 && next[1] >= 0 && next[2] >= 0 && next[0] < ChunkSizeX && next[1] < ChunkSizeY && next[2] < ChunkSizeZ &&
|
||
|
c.Id[next[0]][next[1]][next[2]] != 0 &&
|
||
|
!GetBlockAppearance(
|
||
|
next.Addv(c.X*ChunkSizeX, 0, c.Z*ChunkSizeZ),
|
||
|
int(c.Id[next[0]][next[1]][next[2]]),
|
||
|
int(c.Aux[next[0]][next[1]][next[2]]),
|
||
|
nil,
|
||
|
).Transparent { // face next to a solid block
|
||
|
return arr // skip!
|
||
|
}
|
||
|
|
||
|
switch face {
|
||
|
case itype.XPlus: // X+
|
||
|
arr = append(arr,
|
||
|
// Vertex Position Normal Vector(normalized) Texture Coord Light
|
||
|
Vertex{off.Addv(1, 0, 0), itype.Vec3f{1, 0, 0}, itype.Vec2f{1, 1}, 0.7},
|
||
|
Vertex{off.Addv(1, 1, 0), itype.Vec3f{1, 0, 0}, itype.Vec2f{1, 0}, 0.7},
|
||
|
Vertex{off.Addv(1, 1, 1), itype.Vec3f{1, 0, 0}, itype.Vec2f{0, 0}, 0.7},
|
||
|
Vertex{off.Addv(1, 0, 0), itype.Vec3f{1, 0, 0}, itype.Vec2f{1, 1}, 0.7},
|
||
|
Vertex{off.Addv(1, 1, 1), itype.Vec3f{1, 0, 0}, itype.Vec2f{0, 0}, 0.7},
|
||
|
Vertex{off.Addv(1, 0, 1), itype.Vec3f{1, 0, 0}, itype.Vec2f{0, 1}, 0.7},
|
||
|
)
|
||
|
case itype.XMinus: // X-
|
||
|
arr = append(arr,
|
||
|
Vertex{off.Addv(0, 0, 0), itype.Vec3f{-1, 0, 0}, itype.Vec2f{0, 1}, 0.95},
|
||
|
Vertex{off.Addv(0, 1, 1), itype.Vec3f{-1, 0, 0}, itype.Vec2f{1, 0}, 0.95},
|
||
|
Vertex{off.Addv(0, 1, 0), itype.Vec3f{-1, 0, 0}, itype.Vec2f{0, 0}, 0.95},
|
||
|
Vertex{off.Addv(0, 0, 0), itype.Vec3f{-1, 0, 0}, itype.Vec2f{0, 1}, 0.95},
|
||
|
Vertex{off.Addv(0, 0, 1), itype.Vec3f{-1, 0, 0}, itype.Vec2f{1, 1}, 0.95},
|
||
|
Vertex{off.Addv(0, 1, 1), itype.Vec3f{-1, 0, 0}, itype.Vec2f{1, 0}, 0.95},
|
||
|
)
|
||
|
case itype.YPlus: // Y+
|
||
|
arr = append(arr,
|
||
|
Vertex{off.Addv(0, 1, 0), itype.Vec3f{0, 1, 0}, itype.Vec2f{0, 0}, 1},
|
||
|
Vertex{off.Addv(0, 1, 1), itype.Vec3f{0, 1, 0}, itype.Vec2f{0, 1}, 1},
|
||
|
Vertex{off.Addv(1, 1, 0), itype.Vec3f{0, 1, 0}, itype.Vec2f{1, 0}, 1},
|
||
|
Vertex{off.Addv(0, 1, 1), itype.Vec3f{0, 1, 0}, itype.Vec2f{0, 1}, 1},
|
||
|
Vertex{off.Addv(1, 1, 1), itype.Vec3f{0, 1, 0}, itype.Vec2f{1, 1}, 1},
|
||
|
Vertex{off.Addv(1, 1, 0), itype.Vec3f{0, 1, 0}, itype.Vec2f{1, 0}, 1},
|
||
|
)
|
||
|
case itype.YMinus: // Y-
|
||
|
arr = append(arr,
|
||
|
Vertex{off.Addv(0, 0, 0), itype.Vec3f{0, -1, 0}, itype.Vec2f{1, 0}, 0.6},
|
||
|
Vertex{off.Addv(1, 0, 0), itype.Vec3f{0, -1, 0}, itype.Vec2f{0, 0}, 0.6},
|
||
|
Vertex{off.Addv(1, 0, 1), itype.Vec3f{0, -1, 0}, itype.Vec2f{0, 1}, 0.6},
|
||
|
Vertex{off.Addv(0, 0, 0), itype.Vec3f{0, -1, 0}, itype.Vec2f{1, 0}, 0.6},
|
||
|
Vertex{off.Addv(1, 0, 1), itype.Vec3f{0, -1, 0}, itype.Vec2f{0, 1}, 0.6},
|
||
|
Vertex{off.Addv(0, 0, 1), itype.Vec3f{0, -1, 0}, itype.Vec2f{1, 1}, 0.6},
|
||
|
)
|
||
|
case itype.ZPlus: // Z+
|
||
|
arr = append(arr,
|
||
|
Vertex{off.Addv(0, 0, 1), itype.Vec2f{0, 1}, 0.85},
|
||
|
Vertex{off.Addv(1, 0, 1), itype.Vec2f{1, 1}, 0.85},
|
||
|
Vertex{off.Addv(0, 1, 1), itype.Vec2f{0, 0}, 0.85},
|
||
|
Vertex{off.Addv(1, 1, 1), itype.Vec2f{1, 0}, 0.85},
|
||
|
Vertex{off.Addv(0, 1, 1), itype.Vec2f{0, 0}, 0.85},
|
||
|
Vertex{off.Addv(1, 0, 1), itype.Vec2f{1, 1}, 0.85},
|
||
|
)
|
||
|
case itype.ZMinus: // Z-
|
||
|
arr = append(arr,
|
||
|
Vertex{off.Addv(0, 0, 0), itype.Vec2f{1, 1}, 0.85},
|
||
|
Vertex{off.Addv(0, 1, 0), itype.Vec2f{1, 0}, 0.85},
|
||
|
Vertex{off.Addv(1, 1, 0), itype.Vec2f{0, 0}, 0.85},
|
||
|
Vertex{off.Addv(0, 0, 0), itype.Vec2f{1, 1}, 0.85},
|
||
|
Vertex{off.Addv(1, 1, 0), itype.Vec2f{0, 0}, 0.85},
|
||
|
Vertex{off.Addv(1, 0, 0), itype.Vec2f{0, 1}, 0.85},
|
||
|
)
|
||
|
}
|
||
|
|
||
|
texrect := asset.WorldTextureAtlas.RectNormalized(texname)
|
||
|
for i := len(arr) - 6; i < len(arr); i++ {
|
||
|
arr[i].Texture[0] = texrect.Left + arr[i].Texture[0]*texrect.Width
|
||
|
arr[i].Texture[1] = texrect.Top + arr[i].Texture[1]*texrect.Height
|
||
|
}
|
||
|
|
||
|
return arr
|
||
|
}
|