2022-01-20 21:58:50 +08:00
package world
import (
"log"
"time"
"unsafe"
"edgaru089.ml/go/gl01/internal/asset"
2022-01-27 01:09:45 +08:00
"edgaru089.ml/go/gl01/internal/io"
2022-02-02 01:52:02 +08:00
"edgaru089.ml/go/gl01/internal/util"
2022-01-20 21:58:50 +08:00
"edgaru089.ml/go/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 . BindVertexArray ( c . vao )
gl . GenBuffers ( 1 , & c . vbo )
gl . BindBuffer ( gl . ARRAY_BUFFER , c . vbo )
gl . VertexAttribPointer ( 0 , 3 , gl . FLOAT , false , int32 ( unsafe . Sizeof ( Vertex { } ) ) , gl . PtrOffset ( int ( unsafe . Offsetof ( Vertex { } . World ) ) ) )
gl . VertexAttribPointer ( 1 , 3 , gl . FLOAT , false , int32 ( unsafe . Sizeof ( Vertex { } ) ) , gl . PtrOffset ( int ( unsafe . Offsetof ( Vertex { } . Normal ) ) ) )
gl . VertexAttribPointer ( 2 , 2 , gl . FLOAT , false , int32 ( unsafe . Sizeof ( Vertex { } ) ) , gl . PtrOffset ( int ( unsafe . Offsetof ( Vertex { } . Texture ) ) ) )
gl . VertexAttribPointer ( 3 , 1 , gl . FLOAT , false , int32 ( unsafe . Sizeof ( Vertex { } ) ) , gl . PtrOffset ( int ( unsafe . Offsetof ( Vertex { } . Light ) ) ) )
gl . EnableVertexAttribArray ( 0 )
gl . EnableVertexAttribArray ( 1 )
gl . EnableVertexAttribArray ( 2 )
gl . EnableVertexAttribArray ( 3 )
2022-01-29 00:43:11 +08:00
gl . GenVertexArrays ( 1 , & c . water . vao )
gl . BindVertexArray ( c . water . vao )
gl . GenBuffers ( 1 , & c . water . vbo )
gl . BindBuffer ( gl . ARRAY_BUFFER , c . water . vbo )
gl . VertexAttribPointer ( 0 , 3 , gl . FLOAT , false , int32 ( unsafe . Sizeof ( Vertex { } ) ) , gl . PtrOffset ( int ( unsafe . Offsetof ( Vertex { } . World ) ) ) )
gl . VertexAttribPointer ( 1 , 3 , gl . FLOAT , false , int32 ( unsafe . Sizeof ( Vertex { } ) ) , gl . PtrOffset ( int ( unsafe . Offsetof ( Vertex { } . Normal ) ) ) )
gl . VertexAttribPointer ( 2 , 2 , gl . FLOAT , false , int32 ( unsafe . Sizeof ( Vertex { } ) ) , gl . PtrOffset ( int ( unsafe . Offsetof ( Vertex { } . Texture ) ) ) )
gl . VertexAttribPointer ( 3 , 1 , gl . FLOAT , false , int32 ( unsafe . Sizeof ( Vertex { } ) ) , gl . PtrOffset ( int ( unsafe . Offsetof ( Vertex { } . Light ) ) ) )
gl . EnableVertexAttribArray ( 0 )
gl . EnableVertexAttribArray ( 1 )
gl . EnableVertexAttribArray ( 2 )
gl . EnableVertexAttribArray ( 3 )
c . vertUpdate = make ( chan [ 2 ] [ ] Vertex , 2 )
2022-01-20 21:58:50 +08:00
c . renderChanged = true
}
func ( c * Chunk ) FreeRender ( ) {
gl . DeleteVertexArrays ( 1 , & c . vao )
gl . DeleteBuffers ( 1 , & c . vbo )
2022-01-29 00:43:11 +08:00
gl . DeleteVertexArrays ( 1 , & c . water . vao )
gl . DeleteBuffers ( 1 , & c . water . vbo )
2022-01-20 21:58:50 +08:00
close ( c . vertUpdate )
}
// Bind calls glBindVertexArray(vao) and glBindBuffer(vbo).
func ( c * Chunk ) Bind ( ) {
gl . BindVertexArray ( c . vao )
gl . BindBuffer ( gl . ARRAY_BUFFER , c . vbo )
}
2022-01-29 00:43:11 +08:00
// BindWater binds the semi-transparant layer of the renderer.
func ( c * Chunk ) BindWater ( ) {
gl . BindVertexArray ( c . water . vao )
gl . BindBuffer ( gl . ARRAY_BUFFER , c . water . vbo )
}
2022-01-20 21:58:50 +08:00
// 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 {
go func ( ) {
t := time . Now ( )
2022-01-29 00:43:11 +08:00
vert , vertWater := c . appendVertex ( [ ] Vertex { } , [ ] Vertex { } )
2022-01-20 21:58:50 +08:00
log . Printf ( "Chunk [%d,%d]: UpdateRender: vertex len of %d*%d = %d in %dms" , c . X , c . Z , unsafe . Sizeof ( Vertex { } ) , len ( vert ) , int ( unsafe . Sizeof ( Vertex { } ) ) * len ( vert ) , time . Since ( t ) . Milliseconds ( ) )
2022-01-29 00:43:11 +08:00
c . vertUpdate <- [ 2 ] [ ] Vertex { vert , vertWater }
2022-01-20 21:58:50 +08:00
} ( )
c . renderChanged = false
}
select {
case vert := <- c . vertUpdate :
2022-01-29 00:43:11 +08:00
gl . BindBuffer ( gl . ARRAY_BUFFER , c . vbo )
2022-02-02 01:52:02 +08:00
gl . BufferData ( gl . ARRAY_BUFFER , int ( unsafe . Sizeof ( Vertex { } ) ) * len ( vert [ 0 ] ) , util . Ptr ( vert [ 0 ] ) , gl . DYNAMIC_DRAW )
2022-01-29 00:43:11 +08:00
gl . BindBuffer ( gl . ARRAY_BUFFER , c . water . vbo )
2022-02-02 01:52:02 +08:00
gl . BufferData ( gl . ARRAY_BUFFER , int ( unsafe . Sizeof ( Vertex { } ) ) * len ( vert [ 1 ] ) , util . Ptr ( vert [ 1 ] ) , gl . DYNAMIC_DRAW )
2022-01-29 00:43:11 +08:00
c . vbolen = len ( vert [ 0 ] )
c . water . vbolen = len ( vert [ 1 ] )
2022-01-20 21:58:50 +08:00
default : // do nothing
}
}
2022-01-27 01:09:45 +08:00
var checkViewOffset = [ ] itype . Vec3d {
{ 0 , 0 , 0 } ,
{ ChunkSizeX , 0 , 0 } ,
{ 0 , 0 , ChunkSizeZ } ,
{ ChunkSizeX , 0 , ChunkSizeZ } ,
{ 0 , ChunkSizeY , 0 } ,
{ ChunkSizeX , ChunkSizeY , 0 } ,
{ 0 , ChunkSizeY , ChunkSizeZ } ,
{ ChunkSizeX , ChunkSizeY , ChunkSizeZ } ,
}
// checkView checks if the chunk is in the front-facing direction of the view.
func ( c * Chunk ) checkView ( from , facing itype . Vec3d ) bool {
off := itype . Vec3d {
float64 ( c . X * ChunkSizeX ) ,
0 ,
float64 ( c . Z * ChunkSizeZ ) ,
}
for _ , check := range checkViewOffset {
ok := off . Add ( check ) . Add ( from . Negative ( ) ) . Dot ( facing ) > 0
if ok {
return true
}
}
return false
}
2022-01-20 21:58:50 +08:00
func ( c * Chunk ) Render ( ) {
2022-01-27 01:09:45 +08:00
if ! c . checkView ( io . ViewPos , io . ViewDir ) || ! c . checkView ( io . RenderPos , io . RenderDir ) {
return
}
2022-01-20 21:58:50 +08:00
c . updateRender ( )
2022-01-29 00:43:11 +08:00
c . Bind ( )
2022-01-20 21:58:50 +08:00
gl . DrawArrays ( gl . TRIANGLES , 0 , int32 ( c . vbolen ) )
}
2022-01-29 00:43:11 +08:00
func ( c * Chunk ) RenderWater ( ) {
if ! c . checkView ( io . ViewPos , io . ViewDir ) || ! c . checkView ( io . RenderPos , io . RenderDir ) {
return
}
c . updateRender ( )
c . BindWater ( )
gl . DrawArrays ( gl . TRIANGLES , 0 , int32 ( c . water . vbolen ) )
}
// appendVertex appends the chunk's global vertex into the array.
func ( c * Chunk ) appendVertex ( arr , arrwater [ ] Vertex ) ( fin , finwater [ ] Vertex ) {
2022-01-20 21:58:50 +08:00
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
}
2022-01-28 15:24:03 +08:00
app := GetBlockAppearance ( off . Addv ( i , j , k ) , int ( c . Id [ i ] [ j ] [ k ] ) , int ( c . Aux [ i ] [ j ] [ k ] ) , nil , c . world )
2022-01-20 21:58:50 +08:00
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 :
2022-01-29 00:43:11 +08:00
arr , arrwater = app . CustomRenderAppend ( off . Addv ( i , j , k ) , int ( c . Aux [ i ] [ j ] [ k ] ) , nil , c . world , arr , arrwater )
2022-01-20 21:58:50 +08:00
}
}
}
}
2022-01-29 00:43:11 +08:00
return arr , arrwater
2022-01-20 21:58:50 +08:00
}
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 ] ] ) ,
2022-01-28 15:24:03 +08:00
nil , c . world ,
2022-01-20 21:58:50 +08:00
) . Transparent { // face next to a solid block
return arr // skip!
}
2022-01-28 15:24:03 +08:00
worldnext := pos . Add ( itype . DirectionVeci [ face ] ) . Addv ( c . X * ChunkSizeX , 0 , c . Z * ChunkSizeZ )
if block := c . world . Block ( worldnext ) ; block . Id != 0 && ! block . Appearance ( worldnext ) . Transparent {
return arr // skip!
}
2022-01-20 21:58:50 +08:00
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 } , 16 } ,
Vertex { off . Addv ( 1 , 1 , 0 ) , itype . Vec3f { 1 , 0 , 0 } , itype . Vec2f { 1 , 0 } , 16 } ,
Vertex { off . Addv ( 1 , 1 , 1 ) , itype . Vec3f { 1 , 0 , 0 } , itype . Vec2f { 0 , 0 } , 16 } ,
Vertex { off . Addv ( 1 , 0 , 0 ) , itype . Vec3f { 1 , 0 , 0 } , itype . Vec2f { 1 , 1 } , 16 } ,
Vertex { off . Addv ( 1 , 1 , 1 ) , itype . Vec3f { 1 , 0 , 0 } , itype . Vec2f { 0 , 0 } , 16 } ,
Vertex { off . Addv ( 1 , 0 , 1 ) , itype . Vec3f { 1 , 0 , 0 } , itype . Vec2f { 0 , 1 } , 16 } ,
)
case itype . XMinus : // X-
arr = append ( arr ,
Vertex { off . Addv ( 0 , 0 , 0 ) , itype . Vec3f { - 1 , 0 , 0 } , itype . Vec2f { 0 , 1 } , 16 } ,
Vertex { off . Addv ( 0 , 1 , 1 ) , itype . Vec3f { - 1 , 0 , 0 } , itype . Vec2f { 1 , 0 } , 16 } ,
Vertex { off . Addv ( 0 , 1 , 0 ) , itype . Vec3f { - 1 , 0 , 0 } , itype . Vec2f { 0 , 0 } , 16 } ,
Vertex { off . Addv ( 0 , 0 , 0 ) , itype . Vec3f { - 1 , 0 , 0 } , itype . Vec2f { 0 , 1 } , 16 } ,
Vertex { off . Addv ( 0 , 0 , 1 ) , itype . Vec3f { - 1 , 0 , 0 } , itype . Vec2f { 1 , 1 } , 16 } ,
Vertex { off . Addv ( 0 , 1 , 1 ) , itype . Vec3f { - 1 , 0 , 0 } , itype . Vec2f { 1 , 0 } , 16 } ,
)
case itype . YPlus : // Y+
arr = append ( arr ,
Vertex { off . Addv ( 0 , 1 , 0 ) , itype . Vec3f { 0 , 1 , 0 } , itype . Vec2f { 0 , 0 } , 16 } ,
Vertex { off . Addv ( 0 , 1 , 1 ) , itype . Vec3f { 0 , 1 , 0 } , itype . Vec2f { 0 , 1 } , 16 } ,
Vertex { off . Addv ( 1 , 1 , 0 ) , itype . Vec3f { 0 , 1 , 0 } , itype . Vec2f { 1 , 0 } , 16 } ,
Vertex { off . Addv ( 0 , 1 , 1 ) , itype . Vec3f { 0 , 1 , 0 } , itype . Vec2f { 0 , 1 } , 16 } ,
Vertex { off . Addv ( 1 , 1 , 1 ) , itype . Vec3f { 0 , 1 , 0 } , itype . Vec2f { 1 , 1 } , 16 } ,
Vertex { off . Addv ( 1 , 1 , 0 ) , itype . Vec3f { 0 , 1 , 0 } , itype . Vec2f { 1 , 0 } , 16 } ,
)
case itype . YMinus : // Y-
arr = append ( arr ,
Vertex { off . Addv ( 0 , 0 , 0 ) , itype . Vec3f { 0 , - 1 , 0 } , itype . Vec2f { 1 , 0 } , 16 } ,
Vertex { off . Addv ( 1 , 0 , 0 ) , itype . Vec3f { 0 , - 1 , 0 } , itype . Vec2f { 0 , 0 } , 16 } ,
Vertex { off . Addv ( 1 , 0 , 1 ) , itype . Vec3f { 0 , - 1 , 0 } , itype . Vec2f { 0 , 1 } , 16 } ,
Vertex { off . Addv ( 0 , 0 , 0 ) , itype . Vec3f { 0 , - 1 , 0 } , itype . Vec2f { 1 , 0 } , 16 } ,
Vertex { off . Addv ( 1 , 0 , 1 ) , itype . Vec3f { 0 , - 1 , 0 } , itype . Vec2f { 0 , 1 } , 16 } ,
Vertex { off . Addv ( 0 , 0 , 1 ) , itype . Vec3f { 0 , - 1 , 0 } , itype . Vec2f { 1 , 1 } , 16 } ,
)
case itype . ZPlus : // Z+
arr = append ( arr ,
Vertex { off . Addv ( 0 , 0 , 1 ) , itype . Vec3f { 0 , 0 , 1 } , itype . Vec2f { 0 , 1 } , 16 } ,
Vertex { off . Addv ( 1 , 0 , 1 ) , itype . Vec3f { 0 , 0 , 1 } , itype . Vec2f { 1 , 1 } , 16 } ,
Vertex { off . Addv ( 0 , 1 , 1 ) , itype . Vec3f { 0 , 0 , 1 } , itype . Vec2f { 0 , 0 } , 16 } ,
Vertex { off . Addv ( 1 , 1 , 1 ) , itype . Vec3f { 0 , 0 , 1 } , itype . Vec2f { 1 , 0 } , 16 } ,
Vertex { off . Addv ( 0 , 1 , 1 ) , itype . Vec3f { 0 , 0 , 1 } , itype . Vec2f { 0 , 0 } , 16 } ,
Vertex { off . Addv ( 1 , 0 , 1 ) , itype . Vec3f { 0 , 0 , 1 } , itype . Vec2f { 1 , 1 } , 16 } ,
)
case itype . ZMinus : // Z-
arr = append ( arr ,
Vertex { off . Addv ( 0 , 0 , 0 ) , itype . Vec3f { 0 , 0 , - 1 } , itype . Vec2f { 1 , 1 } , 16 } ,
Vertex { off . Addv ( 0 , 1 , 0 ) , itype . Vec3f { 0 , 0 , - 1 } , itype . Vec2f { 1 , 0 } , 16 } ,
Vertex { off . Addv ( 1 , 1 , 0 ) , itype . Vec3f { 0 , 0 , - 1 } , itype . Vec2f { 0 , 0 } , 16 } ,
Vertex { off . Addv ( 0 , 0 , 0 ) , itype . Vec3f { 0 , 0 , - 1 } , itype . Vec2f { 1 , 1 } , 16 } ,
Vertex { off . Addv ( 1 , 1 , 0 ) , itype . Vec3f { 0 , 0 , - 1 } , itype . Vec2f { 0 , 0 } , 16 } ,
Vertex { off . Addv ( 1 , 0 , 0 ) , itype . Vec3f { 0 , 0 , - 1 } , itype . Vec2f { 0 , 1 } , 16 } ,
)
}
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
}