From 56f2f02afe2a138e3af41804a9ba7643bcf6be82 Mon Sep 17 00:00:00 2001 From: Edgaru089 Date: Fri, 19 Dec 2025 13:08:51 +0800 Subject: [PATCH] cleanup --- internal/entity/entities/player.go | 32 -- internal/entity/entity.go | 135 ------ internal/entity/manager.go | 1 - internal/entity/physics.go | 202 --------- internal/entity/physics.go.new | 233 ---------- internal/game/game.go | 32 +- internal/game/imgui.go | 86 ---- internal/game/logic.go | 193 +-------- internal/game/render.go | 469 --------------------- internal/game/render_debuginfo.go | 116 ----- internal/io/io.go | 4 - internal/world/block.go | 212 ---------- internal/world/block.go.new | 160 ------- internal/world/blocks/default.go | 57 --- internal/world/blocks/helper_appendface.go | 186 -------- internal/world/blocks/slab.go | 100 ----- internal/world/blocks/water.go | 38 -- internal/world/chunk.go | 103 ----- internal/world/render.go | 289 ------------- internal/world/render.go.old | 204 --------- internal/world/viewray.go | 55 --- internal/world/world.go | 167 -------- internal/world/worldgen/worldgen.go | 105 ----- main.cfg.json | 6 +- 24 files changed, 6 insertions(+), 3179 deletions(-) delete mode 100644 internal/entity/entities/player.go delete mode 100644 internal/entity/entity.go delete mode 100644 internal/entity/manager.go delete mode 100644 internal/entity/physics.go delete mode 100644 internal/entity/physics.go.new delete mode 100644 internal/game/render_debuginfo.go delete mode 100644 internal/world/block.go delete mode 100644 internal/world/block.go.new delete mode 100644 internal/world/blocks/default.go delete mode 100644 internal/world/blocks/helper_appendface.go delete mode 100644 internal/world/blocks/slab.go delete mode 100644 internal/world/blocks/water.go delete mode 100644 internal/world/chunk.go delete mode 100644 internal/world/render.go delete mode 100644 internal/world/render.go.old delete mode 100644 internal/world/viewray.go delete mode 100644 internal/world/world.go delete mode 100644 internal/world/worldgen/worldgen.go diff --git a/internal/entity/entities/player.go b/internal/entity/entities/player.go deleted file mode 100644 index 07640a2..0000000 --- a/internal/entity/entities/player.go +++ /dev/null @@ -1,32 +0,0 @@ -package entities - -import ( - "time" - - "edgaru089.ink/go/gl01/internal/entity" - "edgaru089.ink/go/gl01/internal/util/itype" - "edgaru089.ink/go/gl01/internal/world" -) - -type PlayerBehaviour struct{} - -func init() { - entity.RegisterEntityBehaviour(PlayerBehaviour{}) -} - -func (PlayerBehaviour) Name() string { return "player" } - -func (PlayerBehaviour) Hitbox(pos itype.Vec3d, dataset itype.Dataset) []itype.Boxd { - return []itype.Boxd{{ - OffX: -0.3, OffY: 0, OffZ: -0.3, - SizeX: 0.6, SizeY: 1.8, SizeZ: 0.6, - }} -} - -func (PlayerBehaviour) EyeHeight(pos itype.Vec3d, dataset itype.Dataset) float64 { - return 1.65 -} - -func (PlayerBehaviour) Update(pos itype.Vec3d, dataset itype.Dataset, world *world.World, deltaTime time.Duration) { - -} diff --git a/internal/entity/entity.go b/internal/entity/entity.go deleted file mode 100644 index bb5bba4..0000000 --- a/internal/entity/entity.go +++ /dev/null @@ -1,135 +0,0 @@ -package entity - -import ( - "time" - - "edgaru089.ink/go/gl01/internal/util/itype" - "edgaru089.ink/go/gl01/internal/world" -) - -// EntityBehaviour describes the behaviour of a type of entity with the same Name. -// It should hold no data of its own. -type EntityBehaviour interface { - // Name returns the type Name of the behaviour. - Name() string - - // Hitbox gets the hitbox(s) of the entity. - // - // The hitbox is in entity-local coordinates, originating from the position. - Hitbox(pos itype.Vec3d, dataset itype.Dataset) []itype.Boxd - - // EyeHeight gets the height of the eye of the entity. - EyeHeight(pos itype.Vec3d, dataset itype.Dataset) float64 - - // Update is called on every frame. - // It should be used to update the behaviour of the entity. - Update(pos itype.Vec3d, dataset itype.Dataset, world *world.World, deltaTime time.Duration) -} - -var behaviour = make(map[string]EntityBehaviour) - -// RegisterEntityBehaviour registers behaviour with the name of b.Name(). -// -// If the name is already taken, false is returned and nothing is done. -// Otherwise, true is returned and the entity is registered. -func RegisterEntityBehaviour(b EntityBehaviour) bool { - if _, ok := behaviour[b.Name()]; ok { - return false - } - - behaviour[b.Name()] = b - return true -} - -// Entity is a struct holding a Behaviour, a Position and a Speed. -type Entity struct { - b EntityBehaviour - pos, speed itype.Vec3d // pos should have a origin of the **center of the bottom** of the hitbox - ds itype.Dataset - - name string // a shortcut to b.Name(), the typename - - // physics stuff - onGround bool - worldbox []itype.Boxd -} - -func NewEntity(typename string, pos itype.Vec3d) *Entity { - var b EntityBehaviour - var ok bool - if b, ok = behaviour[typename]; !ok { - return nil - } - return &Entity{ - b: b, - pos: pos, - name: typename, - ds: make(itype.Dataset), - } -} - -func (e *Entity) Position() itype.Vec3d { - return e.pos -} - -func (e *Entity) SetPosition(pos itype.Vec3d) { - e.pos = pos -} - -func (e *Entity) Speed() itype.Vec3d { - return e.speed -} - -func (e *Entity) SetSpeed(speed itype.Vec3d) { - e.speed = speed -} - -func (e *Entity) Hitbox() []itype.Boxd { - return e.b.Hitbox(e.pos, e.ds) -} - -func (e *Entity) Accelerate(x, y, z float64) { - e.speed[0] += x - e.speed[1] += y - e.speed[2] += z - /*vec := itype.Vec3d{x, y, z} - e.speed = util.BunnyhopAccelerate(vec, e.speed, vec.Length(), 8)*/ -} - -func (e *Entity) OnGround() bool { - return e.onGround -} - -func (e *Entity) EyeHeight() float64 { - return e.b.EyeHeight(e.pos, e.ds) -} - -func (e *Entity) EyePosition() itype.Vec3d { - return e.pos.Addv(0, e.EyeHeight(), 0) -} - -func (e *Entity) DatasetI(name string) int64 { - return e.ds[name].(int64) -} -func (e *Entity) DatasetF(name string) float64 { - return e.ds[name].(float64) -} -func (e *Entity) DatasetS(name string) string { - return e.ds[name].(string) -} -func (e *Entity) DatasetB(name string) bool { - return e.ds[name].(bool) -} - -func (e *Entity) SetDatasetI(name string, val int64) { - e.ds[name] = val -} -func (e *Entity) SetDatasetF(name string, val float64) { - e.ds[name] = val -} -func (e *Entity) SetDatasetS(name string, val string) { - e.ds[name] = val -} -func (e *Entity) SetDatasetB(name string, val bool) { - e.ds[name] = val -} diff --git a/internal/entity/manager.go b/internal/entity/manager.go deleted file mode 100644 index bc3d304..0000000 --- a/internal/entity/manager.go +++ /dev/null @@ -1 +0,0 @@ -package entity diff --git a/internal/entity/physics.go b/internal/entity/physics.go deleted file mode 100644 index b8ddb88..0000000 --- a/internal/entity/physics.go +++ /dev/null @@ -1,202 +0,0 @@ -package entity - -import ( - "math" - "time" - - "edgaru089.ink/go/gl01/internal/util" - "edgaru089.ink/go/gl01/internal/util/itype" - "edgaru089.ink/go/gl01/internal/world" -) - -// WorldHitbox returns the hitboxes of the entity, in world coordinates. -func (e *Entity) WorldHitbox() []itype.Boxd { - boxes := e.Hitbox() - for i := range boxes { - boxes[i] = boxes[i].Offset(e.pos) - } - return boxes -} - -// MoveEps is a small value used to indicate a tiny amount more than zero. -const MoveEps = 1e-7 - -// move attempts to move the entity by delta in the world. -// It does not change anything in e. -func (e *Entity) move(delta itype.Vec3d, w *world.World) (finDelta itype.Vec3d, finVelocity itype.Vec3d, onGround bool) { - - // Truncate the delta to [0, 1] - for i := 0; i < len(delta); i++ { - if math.Abs(delta[i]) > 1 { - delta[i] /= math.Abs(delta[i]) - } - } - - // Get the hitboxes and the blocks region covering it - hb := e.WorldHitbox() - hbmin, hbmax := itype.Vec3d{1000000000, 1000000000, 1000000000}, itype.Vec3d{-1000000000, -1000000000, -1000000000} - for _, b := range hb { - bmin, bmax := b.MinPoint(), b.MaxPoint() - hbmin[0] = util.Mind(hbmin[0], bmin[0]) - hbmin[1] = util.Mind(hbmin[1], bmin[1]) - hbmin[2] = util.Mind(hbmin[2], bmin[2]) - hbmax[0] = util.Maxd(hbmax[0], bmax[0]) - hbmax[1] = util.Maxd(hbmax[1], bmax[1]) - hbmax[2] = util.Maxd(hbmax[2], bmax[2]) - } - - // So this is the region of blocks we should calculate - imin, imax := hbmin.Floor().Addv(-1, -1, -1), hbmax.Ceiling().Addv(1, 1, 1) - - finDelta = delta - finVelocity = e.speed - for x := imin[0]; x <= imax[0]; x++ { - for y := imin[1]; y <= imax[1]; y++ { - for z := imin[2]; z <= imax[2]; z++ { - blockDelta, blockVelocity, blockOnGround := e.moveBlock(hb, delta, itype.Vec3i{x, y, z}, w) - finDelta[0] = util.AbsMind(finDelta[0], blockDelta[0]) - finDelta[1] = util.AbsMind(finDelta[1], blockDelta[1]) - finDelta[2] = util.AbsMind(finDelta[2], blockDelta[2]) - finVelocity[0] = util.AbsMind(finVelocity[0], blockVelocity[0]) - finVelocity[1] = util.AbsMind(finVelocity[1], blockVelocity[1]) - finVelocity[2] = util.AbsMind(finVelocity[2], blockVelocity[2]) - onGround = onGround || blockOnGround - } - } - } - - // Y- - if delta[1] < 0 { - onGround = onGround || e.onGround - } else { - onGround = false - } - - return -} - -// moveBlock simulates moving the entity by delta, and tests collision with the block hibbox. -func (e *Entity) moveBlock(worldHitbox []itype.Boxd, delta itype.Vec3d, blockCoord itype.Vec3i, w *world.World) (blockDelta itype.Vec3d, finVelocity itype.Vec3d, onGround bool) { - blockDelta = delta - finVelocity = e.speed - onGround = false - - var blockHitbox []itype.Boxd - if block := w.Block(blockCoord); block.Id != 0 { - blocka := block.Appearance(blockCoord) - if !blocka.NotSolid { - blockHitbox = w.Block(blockCoord).Appearance(blockCoord).Hitbox - for i := range blockHitbox { - blockHitbox[i] = blockHitbox[i].Offset(blockCoord.ToFloat64()) - } - } - } - - if len(blockHitbox) == 0 { - return - } - - for _, eb := range worldHitbox { - for _, bb := range blockHitbox { - // Already intersecting: return - if ok, _ := eb.Intersect(bb); ok { - continue - } - - // X - if ok, _ := eb.Offsetv(blockDelta[0], 0, 0).Intersect(bb); ok { - if blockDelta[0] > 0 { - blockDelta[0] = bb.OffX - (eb.OffX + eb.SizeX) - MoveEps - //log.Printf("Hit(X+): On (X%d,Y%d,Z%d), delta=%v\n", blockCoord[0], blockCoord[1], blockCoord[2], blockDelta) - } else { - blockDelta[0] = (bb.OffX + bb.SizeX) - eb.OffX + MoveEps - //log.Printf("Hit(X-): On (X%d,Y%d,Z%d), delta=%v\n", blockCoord[0], blockCoord[1], blockCoord[2], blockDelta) - } - finVelocity[0] = 0 - } - - // Y - if ok, _ := eb.Offsetv(0, blockDelta[1], 0).Intersect(bb); ok { - if blockDelta[1] > 0 { - blockDelta[1] = bb.OffY - (eb.OffY + eb.SizeY) - MoveEps - //log.Printf("Hit(Y+): On (X%d,Y%d,Z%d), delta=%v\n", blockCoord[0], blockCoord[1], blockCoord[2], blockDelta) - } else { - onGround = true - blockDelta[1] = (bb.OffY + bb.SizeY) - eb.OffY + MoveEps - //log.Printf("Hit(Y-): On (X%d,Y%d,Z%d), delta=%v\n", blockCoord[0], blockCoord[1], blockCoord[2], blockDelta) - } - finVelocity[1] = 0 - } - - // Z - if ok, _ := eb.Offsetv(0, 0, blockDelta[2]).Intersect(bb); ok { - if blockDelta[2] > 0 { - blockDelta[2] = bb.OffZ - (eb.OffZ + eb.SizeZ) - MoveEps - //log.Printf("Hit(Z+): On (X%d,Y%d,Z%d), delta=%v\n", blockCoord[0], blockCoord[1], blockCoord[2], blockDelta) - } else { - blockDelta[2] = (bb.OffZ + bb.SizeZ) - eb.OffZ + MoveEps - //log.Printf("Hit(Z-): On (X%d,Y%d,Z%d), delta=%v\n", blockCoord[0], blockCoord[1], blockCoord[2], blockDelta) - } - finVelocity[2] = 0 - } - } - } - - return -} - -const gravity = 26 -const deaclc = 28 -const maxspeed = 8 - -func (e *Entity) Update(world *world.World, deltaTime time.Duration) { - - /* - delta, vec, onGround := e.move(itype.Vec3d{e.speed[0] * deltaTime.Seconds()}, world) - e.pos = e.pos.Add(delta) - e.speed = vec - delta, vec, onGround = e.move(e.speed.Multiply(deltaTime.Seconds()), world) - e.pos = e.pos.Add(delta) - e.speed = vec - delta, vec, onGround = e.move(e.speed.Multiply(deltaTime.Seconds()), world) - e.pos = e.pos.Add(delta) - e.speed = vec - - e.onGround = onGround - */ - - var deltaSpeed itype.Vec3d - if e.onGround { - speed := math.Sqrt(e.speed[0]*e.speed[0] + e.speed[2]*e.speed[2]) - if speed > MoveEps { - decrease := deaclc * deltaTime.Seconds() - factor := util.Maxd(util.Mind(speed-decrease, 6), 0) / speed - - deltaSpeed[0] = -e.speed[0] * (1 - factor) - deltaSpeed[2] = -e.speed[2] * (1 - factor) - } else { - e.speed[0] = 0 - e.speed[2] = 0 - } - } - deltaSpeed[1] = -gravity * deltaTime.Seconds() - - delta := e.speed.Multiply(deltaTime.Seconds()).Add(deltaSpeed.Multiply(deltaTime.Seconds() / 2)) - e.speed = e.speed.Add(deltaSpeed) - - findelta, vec, onGround := e.move(delta, world) - e.pos = e.pos.Add(findelta) - e.speed = vec - e.onGround = onGround - - if !e.onGround { - vecXZ := itype.Vec2d{e.speed[0], e.speed[2]} - if vecXZ.Length() > maxspeed { - vecXZ = vecXZ.Normalize().Multiply(maxspeed) - } - e.speed[0] = vecXZ[0] - e.speed[2] = vecXZ[1] - } - - e.b.Update(e.pos, e.ds, world, deltaTime) -} diff --git a/internal/entity/physics.go.new b/internal/entity/physics.go.new deleted file mode 100644 index 46b89bf..0000000 --- a/internal/entity/physics.go.new +++ /dev/null @@ -1,233 +0,0 @@ -package entity - -import ( - "log" - "math" - "time" - - "github.com/Edgaru089/gl01/internal/util" - "github.com/Edgaru089/gl01/internal/util/itype" - "github.com/Edgaru089/gl01/internal/world" -) - -func (e *Entity) worldHitbox(hitbox itype.Vec3d) itype.Boxd { - return itype.Boxd{ - OffX: e.pos[0] - hitbox[0]/2, - OffY: e.pos[1], - OffZ: e.pos[2] - hitbox[2]/2, - SizeX: hitbox[0], - SizeY: hitbox[1], - SizeZ: hitbox[2], - } -} - -// WorldHitbox returns the hitbox of the entity, in world coordinates. -func (e *Entity) WorldHitbox() itype.Boxd { - return e.worldHitbox(e.b.Hitbox(e.pos, e.ds)) -} - -// MoveEps is a small value used to indicate a tiny amount more than zero. -const MoveEps = 1e-7 - -// the move series functions should be called with e.hp already filled - -func (e *Entity) moveX(delta float64, hitbox itype.Boxd, w *world.World) { - if math.Abs(delta) < MoveEps*10 { - return - } - - var hit bool = false - var deltaMin float64 = 10000 - - if delta > 1-MoveEps { - delta = 1 - MoveEps - } - if delta < -1+MoveEps { - delta = -1 + MoveEps - } - - // X+ / X- - if pointStuck(p, w) { - continue - } - - dest := hitbox.Offsetv(delta, 0, 0) - blockid := dest.Floor() - block := w.Block(blockid) - - var deltaDone float64 - if block.Id == 0 { - deltaDone = delta - } else { // block.Id!=0 - app := world.GetBlockAppearance(blockid, block.Id, block.Aux, block.Dataset) - blockBox := app.Hitbox.Offset(blockid.ToFloat64()) - if !app.NotSolid && blockBox.Contains(dest) { // Hit! - hit = true - if delta > 0 { // moving X+, hit on the X- face - deltaDone = blockBox.OffX - (e.pos[0] + hitbox.SizeX/2) - MoveEps - //log.Print("Hit X+: On Block ", blockid, ", delta=", delta, ", coord=", e.pos, ", p=", p, ", dest=", dest, ", deltaDone=", deltaDone) - } else { // moving X-, hit on the X+ face - deltaDone = blockBox.OffX + blockBox.SizeX - (e.pos[0] - hitbox.SizeX/2) + MoveEps - //log.Print("Hit X-: On Block ", blockid, ", delta=", delta, ", coord=", e.pos, ", p=", p, ", dest=", dest, ", deltaDone=", deltaDone) - } - } else { - deltaDone = delta - } - } - - deltaMin = util.AbsMind(deltaMin, deltaDone) - - if hit { - e.speed[0] = 0 - } - e.pos[0] += deltaMin -} -func (e *Entity) moveY(delta float64, hitbox itype.Boxd, w *world.World) { - if math.Abs(delta) < MoveEps*10 { - return - } - - var hit bool = false - var deltaMin float64 = 10000 - - if delta > 1-MoveEps { - delta = 1 - MoveEps - } - if delta < -1+MoveEps { - delta = -1 + MoveEps - } - - // Y+ / Y- - for _, p := range e.hp { - if pointStuck(p, w) { - continue - } - - dest := p.Addv(0, delta, 0) - blockid := dest.Floor() - block := w.Block(blockid) - - var deltaDone float64 - if block.Id == 0 { - deltaDone = delta - } else { // block.Id!=0 - app := world.GetBlockAppearance(blockid, block.Id, block.Aux, block.Dataset) - blockBox := app.Hitbox.Offset(blockid.ToFloat64()) - if !app.NotSolid && blockBox.Contains(dest) { // Hit! - hit = true - if delta > 0 { // moving Y+, hit on the Y- face - deltaDone = blockBox.OffY - (e.pos[1] + hitbox.SizeY) - MoveEps - //log.Print("Hit Y+: On Block ", blockid, ", delta=", delta, ", coord=", e.pos, ", p=", p, ", dest=", dest,", deltaDone=",deltaDone) - } else { // moving Y-, hit on the Y+ face (on the ground) - deltaDone = blockBox.OffY + blockBox.SizeY - e.pos[1] + MoveEps - //log.Print("Hit Y-: On Block ", blockid, ", delta=", delta, ", coord=", e.pos, ", p=", p, ", dest=", dest,", deltaDone=",deltaDone) - if !e.onGround { - log.Print("onGround = true") - } - e.onGround = true - } - } else { - deltaDone = delta - } - } - - deltaMin = util.AbsMind(deltaMin, deltaDone) - } - - if hit { - e.speed[1] = 0 - } - - if math.Abs(deltaMin) > MoveEps*10 { - if e.onGround { - log.Print("onGround = false") - } - e.onGround = false - } - e.pos[1] += deltaMin -} -func (e *Entity) moveZ(delta float64, hitbox itype.Boxd, w *world.World) { - if math.Abs(delta) < MoveEps*10 { - return - } - - var hit bool = false - var deltaMin float64 = 10000 - - if delta > 1-MoveEps { - delta = 1 - MoveEps - } - if delta < -1+MoveEps { - delta = -1 + MoveEps - } - - // Z+ / Z- - for _, p := range e.hp { - if pointStuck(p, w) { - continue - } - - dest := p.Addv(0, 0, delta) - blockid := dest.Floor() - block := w.Block(blockid) - - var deltaDone float64 - if block.Id == 0 { - deltaDone = delta - } else { // block.Id!=0 - app := world.GetBlockAppearance(blockid, block.Id, block.Aux, block.Dataset) - blockBox := app.Hitbox.Offset(blockid.ToFloat64()) - if !app.NotSolid && blockBox.Contains(dest) { // Hit! - hit = true - if delta > 0 { // moving Z+, hit on the Z- face - deltaDone = util.Maxd(blockBox.OffZ-(e.pos[2]+hitbox.SizeZ/2)-MoveEps, 0) - //log.Print("Hit Z+: On Block ", blockid, ", delta=", delta, ", coord=", e.pos, ", p=", p, ", dest=", dest, ", deltaDone=", deltaDone) - } else { // moving Z-, hit on the Z+ face - deltaDone = util.Mind(blockBox.OffZ+blockBox.SizeZ-(e.pos[2]-hitbox.SizeZ/2)+MoveEps, 0) - //log.Print("Hit Z-: On Block ", blockid, ", delta=", delta, ", coord=", e.pos, ", p=", p, ", dest=", dest, ", deltaDone=", deltaDone) - } - } else { - deltaDone = delta - } - } - - deltaMin = util.AbsMind(deltaMin, deltaDone) - } - - if hit { - e.speed[2] = 0 - } - e.pos[2] += deltaMin -} - -const gravity float64 = 26 -const deaclc float64 = 28 - -func (e *Entity) Update(world *world.World, deltaTime time.Duration) { - - hitbox := e.b.Hitbox(e.pos, e.ds) - box := e.worldHitbox(hitbox) - - e.hp = e.hp[0:0] - e.hp = e.boxHitpoints(e.hp, box) - - e.moveX(e.speed[0]*deltaTime.Seconds(), box, world) - e.moveY(e.speed[1]*deltaTime.Seconds(), box, world) - e.moveZ(e.speed[2]*deltaTime.Seconds(), box, world) - - speed := math.Sqrt(e.speed[0]*e.speed[0] + e.speed[2]*e.speed[2]) - if speed > MoveEps { - decrease := deaclc * deltaTime.Seconds() - if !e.onGround { - decrease /= 10 - } - factor := util.Maxd(util.Mind(speed-decrease, 9), 0) / speed - - e.speed[0] *= factor - e.speed[2] *= factor - } - - e.speed[1] -= gravity * deltaTime.Seconds() - - e.b.Update(e.pos, e.ds, world, deltaTime) -} diff --git a/internal/game/game.go b/internal/game/game.go index b062f87..8b8ab12 100644 --- a/internal/game/game.go +++ b/internal/game/game.go @@ -3,30 +3,12 @@ package game import ( "time" - "edgaru089.ink/go/gl01/internal/entity" - "edgaru089.ink/go/gl01/internal/render" "edgaru089.ink/go/gl01/internal/util/itype" - "edgaru089.ink/go/gl01/internal/world" "github.com/inkyblackness/imgui-go/v4" - - _ "edgaru089.ink/go/gl01/internal/entity/entities" ) // Game holds a game scene. type Game struct { - world *world.World - - player *entity.Entity - - view *render.View - render renderData - - prevCursorPos itype.Vec2d - cameraPos itype.Vec3d - rotY itype.Angle - rotZ float32 // Degrees in range (-90, 90) - - fbSize itype.Vec2i fullscreen bool lastPos, lastSize itype.Vec2i // Window size before entering fullscreen @@ -39,17 +21,5 @@ type Game struct { // NewGame creates a new, empty Game. func NewGame() (g *Game) { - return &Game{ - world: world.NewWorld(), - player: entity.NewEntity("player", itype.Vec3d{18, 80, 18}), - cameraPos: itype.Vec3d{18, 80, 18}, - rotY: 0, - rotZ: 0, - } -} - -// LoadGameFromPath loads a saved game from a filesystem folder in a read-write fashion. -func LoadGameFromPath(path string) (g *Game, err error) { - - return + return &Game{} } diff --git a/internal/game/imgui.go b/internal/game/imgui.go index 5629219..2531872 100644 --- a/internal/game/imgui.go +++ b/internal/game/imgui.go @@ -3,8 +3,6 @@ package game import ( "image/color" "log" - "math" - "os" "runtime" "edgaru089.ink/go/gl01/internal/asset" @@ -12,8 +10,6 @@ import ( "edgaru089.ink/go/gl01/internal/igwrap/backend" "edgaru089.ink/go/gl01/internal/io" "edgaru089.ink/go/gl01/internal/util" - "edgaru089.ink/go/gl01/internal/util/itype" - "edgaru089.ink/go/gl01/internal/world" "github.com/go-gl/glfw/v3.3/glfw" "github.com/inkyblackness/imgui-go/v4" ) @@ -73,13 +69,6 @@ func (g *Game) imgui() { igwrap.TextBackground("CgoCalls:%d (%d lastframe), Goroutines:%d", g.gui.lastframeCgoCalls, io.Diagnostics.CgoCalls, runtime.NumGoroutine()) igwrap.TextBlank() - pos := g.player.Position() - igwrap.TextBackground("Player: (%.3f, %.5f, %.3f) (Y%.2f, Z%.2f)", pos[0], pos[1], pos[2], g.rotY.Degrees(), g.rotZ) - - if ok, bc, face, _, _ := g.world.CastViewRay(io.ViewPos, io.ViewDir.Normalize(), 10); ok { - igwrap.TextBackground("Looking At: (%d %d %d) facing %s", bc[0], bc[1], bc[2], itype.DirectionName[face]) - } - imgui.End() } } @@ -87,14 +76,6 @@ func (g *Game) imgui() { if g.paused { imgui.ShowDemoWindow(nil) - if imgui.BeginV("Player", nil, imgui.WindowFlagsAlwaysAutoResize) { - pos := g.player.Position() - vel := g.player.Speed() - igwrap.Text("Pos: (%.5f, %.5f, %.5f), Vel: (%.5f, %.5f, %.5f)", pos[0], pos[1], pos[2], vel[0], vel[1], vel[2]) - igwrap.Text("VelXZ=%.5f, VelXYZ=%.5f", math.Sqrt(vel[0]*vel[0]+vel[2]*vel[2]), vel.Length()) - } - imgui.End() - if igwrap.Begin("Logs", &g.gui.showLog, imgui.WindowFlagsMenuBar) { if imgui.BeginMenuBar() { if imgui.Button("Clear") { @@ -118,76 +99,9 @@ func (g *Game) imgui() { imgui.End() } - if imgui.Begin("Actions") { - - imgui.Text("Chunks") - imgui.Separator() - imgui.InputText("Load Filename", &g.gui.loadChunkFile) - imgui.SliderInt2("Load ID", &g.gui.loadChunkID, -10, 10) - if imgui.ButtonV("Load", imgui.Vec2{X: -2, Y: 0}) { - c := &world.Chunk{} - f, err := os.Open(g.gui.loadChunkFile) - if err != nil { - log.Print("LoadChunk: ", err) - } else { - c.LoadFromGobIndexed(f, int(g.gui.loadChunkID[0]), int(g.gui.loadChunkID[1])) - g.world.SetChunk(int(g.gui.loadChunkID[0]), int(g.gui.loadChunkID[1]), c) - } - } - imgui.Separator() - imgui.InputText("Save Filename", &g.gui.saveChunkFile) - imgui.SliderInt2("Save ID", &g.gui.saveChunkID, -10, 10) - if imgui.ButtonV("Save", imgui.Vec2{X: -2, Y: 0}) { - c := g.world.Chunks[itype.Vec2i{int(g.gui.saveChunkID[0]), int(g.gui.saveChunkID[1])}] - f, _ := os.Create(g.gui.saveChunkFile) - c.WriteToGob(f) - f.Close() - } - imgui.Separator() - - } - imgui.End() } imgui.BackgroundDrawList().AddRectFilledV(imgui.Vec2{X: float32(io.DisplaySize[0]/2 - 12), Y: float32(io.DisplaySize[1]/2 - 1)}, imgui.Vec2{X: float32(io.DisplaySize[0]/2 + 12), Y: float32(io.DisplaySize[1]/2 + 1)}, imgui.Packed(color.White), 0, 0) imgui.BackgroundDrawList().AddRectFilledV(imgui.Vec2{X: float32(io.DisplaySize[0]/2 - 1), Y: float32(io.DisplaySize[1]/2 - 12)}, imgui.Vec2{X: float32(io.DisplaySize[0]/2 + 1), Y: float32(io.DisplaySize[1]/2 + 12)}, imgui.Packed(color.White), 0, 0) - imgui.SetNextWindowPosV(imgui.Vec2{float32(io.DisplaySize[0] / 2), float32(io.DisplaySize[1]) + 1}, imgui.ConditionAlways, imgui.Vec2{0.5, 1}) - if igwrap.Begin("InventoryBar", nil, imgui.WindowFlagsAlwaysAutoResize|imgui.WindowFlagsNoNavFocus|imgui.WindowFlagsNoNavInputs|imgui.WindowFlagsNoDecoration|imgui.WindowFlagsNoBringToFrontOnFocus|imgui.WindowFlagsNoSavedSettings|imgui.WindowFlagsNoFocusOnAppearing) { - - imgui.PushStyleColor(imgui.StyleColorBorder, imgui.Vec4{0.8, 0.8, 0.8, 1}) - for i, id := range placeId { - if i != 0 { - imgui.SameLineV(0, 1) - } - - if i == placei { - imgui.PushStyleVarFloat(imgui.StyleVarFrameBorderSize, 2) - } - - app := world.GetBlockBehaviour(id).Appearance(itype.Vec3i{}, 0, nil, g.world) - var name string - switch app.RenderType { - case world.OneTexture: - name = app.Name + ".png" - case world.ThreeTexture: - name = app.Name + "_top.png" - case world.SixTexture: - name = app.Name + "_y+.png" - } - igwrap.ImageButtonV( - g.render.texture.Handle(), - itype.Vec2f{32, 32}, - asset.WorldTextureAtlas.RectNormalized(name), - 0, itype.Vec4f{}, itype.Vec4f{1, 1, 1, 1}, - ) - - if i == placei { - imgui.PopStyleVar() - } - } - imgui.PopStyleColor() - - imgui.End() - } } diff --git a/internal/game/logic.go b/internal/game/logic.go index ccc639f..dbba3a6 100644 --- a/internal/game/logic.go +++ b/internal/game/logic.go @@ -1,21 +1,15 @@ package game import ( - "image/color" "log" "os" "time" "edgaru089.ink/go/gl01/internal/igwrap/backend" "edgaru089.ink/go/gl01/internal/io" - "edgaru089.ink/go/gl01/internal/render" "edgaru089.ink/go/gl01/internal/util" "edgaru089.ink/go/gl01/internal/util/itype" - "edgaru089.ink/go/gl01/internal/world" - "edgaru089.ink/go/gl01/internal/world/blocks" - "edgaru089.ink/go/gl01/internal/world/worldgen" "github.com/go-gl/glfw/v3.3/glfw" - "github.com/go-gl/mathgl/mgl64" ) const ( @@ -23,10 +17,6 @@ const ( PlayerPlaceCooldown = 200 * time.Millisecond ) -var placeId = [10]int{blocks.Stone, blocks.Slab, blocks.Grass, blocks.LogOak, blocks.PlanksOak, blocks.LeavesOak, blocks.Glass, blocks.DebugDir, blocks.Bedrock, blocks.Water} -var placeAux = [10]int{0, blocks.PlanksOak, 0, 0, 0, 0, 0, 0, 0, 0} -var placei = 0 - var logs string type logger struct{} @@ -44,51 +34,14 @@ func init() { // Init initializes the game. func (g *Game) Init(win *glfw.Window) { - g.world = world.NewWorld() - g.view = &render.View{} - - err := g.initRender() - if err != nil { - panic(err) - } - - g.player.SetDatasetI("LastBreak", 0) - g.player.SetDatasetI("LastPlace", 0) - - var seed int64 = time.Now().Unix() - gensync := make(chan struct{}) - gensynccnt := 0 - for i := -4; i <= 4; i++ { - for j := -4; j <= 4; j++ { - c := &world.Chunk{} - g.world.SetChunk(i, j, c) - go func() { - worldgen.Chunk(c, g.world, seed) - gensync <- struct{}{} - }() - gensynccnt++ - } - } - - for i := 0; i < gensynccnt; i++ { - <-gensync - } - width, height := win.GetSize() - g.view.Aspect(float32(width)/float32(height)).FovY(itype.Degrees(60)).LookAt(g.cameraPos.ToFloat32(), g.rotY, itype.Degrees(g.rotZ)) io.DisplaySize[0], io.DisplaySize[1] = win.GetFramebufferSize() win.SetSizeCallback(func(w *glfw.Window, width, height int) { //win.SetCursorPos(float64(width)/2, float64(height)/2) - g.view.Aspect(float32(width) / float32(height)) io.DisplaySize = itype.Vec2i{width, height} }) - err = render.Framewire.Init() - if err != nil { - panic(err) - } - g.initImgui(win) win.SetCursorPos(float64(width)/2, float64(height)/2) @@ -102,15 +55,8 @@ func (g *Game) Init(win *glfw.Window) { width, height := w.GetSize() centerX, centerY := float64(width)/2, float64(height)/2 - deltaX, deltaY := xpos-centerX, ypos-centerY - g.rotY -= itype.Degrees(float32(deltaX) / 10) - g.rotZ -= float32(deltaY) / 10 - if g.rotZ > 89.99 { - g.rotZ = 89.99 - } - if g.rotZ < -89.99 { - g.rotZ = -89.99 - } + //deltaX, deltaY := xpos-centerX, ypos-centerY + _, _ = xpos-centerX, ypos-centerY win.SetCursorPos(centerX, centerY) }) @@ -125,21 +71,6 @@ func (g *Game) Init(win *glfw.Window) { backend.KeyCallback(key, action) } if action == glfw.Press { - if g.paused { - if key == glfw.KeyEscape && !g.io.WantCaptureKeyboard() { - g.paused = false - win.SetInputMode(glfw.CursorMode, glfw.CursorDisabled) - width, height := w.GetSize() - win.SetCursorPos(float64(width)/2, float64(height)/2) - } - } else { - if key == glfw.KeyEscape { - g.paused = true - win.SetInputMode(glfw.CursorMode, glfw.CursorNormal) - width, height := w.GetSize() - win.SetCursorPos(float64(width)/2, float64(height)/2) - } - } if key == glfw.KeyF11 { if g.fullscreen { @@ -175,18 +106,6 @@ func (g *Game) Init(win *glfw.Window) { win.SetScrollCallback(func(w *glfw.Window, xpos, ypos float64) { if g.paused { backend.MouseScrollCallback(xpos, ypos) - } else { - if ypos > 0 { - placei-- - } else if ypos < 0 { - placei++ - } - if placei < 0 { - placei += len(placeId) - } - if placei >= len(placeId) { - placei -= len(placeId) - } } }) @@ -201,114 +120,6 @@ func (g *Game) Update(win *glfw.Window, delta time.Duration) { clock := util.NewClock() - if !g.paused { - - if win.GetKey(glfw.KeyLeft) == glfw.Press { - g.rotY += itype.Degrees(float32(delta.Seconds()) * 100) - } - if win.GetKey(glfw.KeyRight) == glfw.Press { - g.rotY -= itype.Degrees(float32(delta.Seconds()) * 100) - } - if win.GetKey(glfw.KeyUp) == glfw.Press { - g.rotZ += float32(delta.Seconds()) * 100 - if g.rotZ > 89.99 { - g.rotZ = 89.99 - } - } - if win.GetKey(glfw.KeyDown) == glfw.Press { - g.rotZ -= float32(delta.Seconds()) * 100 - if g.rotZ < -89.99 { - g.rotZ = -89.99 - } - } - - //forward := itype.Vec3f(mgl32.Rotate3DY(mgl32.DegToRad(g.rotY)).Mul3(mgl32.Rotate3DZ(mgl32.DegToRad(g.rotZ))).Mul3x1(mgl32.Vec3{1, 0, 0})).ToFloat64().Multiply(delta.Seconds()*8) - var walkaccel float64 - if g.player.OnGround() { - walkaccel = 48 - } else { - walkaccel = 16 - } - - forward := itype.Vec3d(mgl64.Rotate3DY(float64(g.rotY.Radians())).Mul3x1(mgl64.Vec3{1, 0, 0})) - right := forward.Cross(itype.Vec3d{0, 1, 0}) - accel := itype.Vec3d{0, 0, 0} - if win.GetKey(glfw.KeyW) == glfw.Press { - accel = accel.Add(forward.Multiply(walkaccel * delta.Seconds())) - } - if win.GetKey(glfw.KeyS) == glfw.Press { - accel = accel.Add(forward.Multiply(walkaccel * delta.Seconds()).Negative()) - } - if win.GetKey(glfw.KeyD) == glfw.Press { - accel = accel.Add(right.Multiply(walkaccel * delta.Seconds())) - } - if win.GetKey(glfw.KeyA) == glfw.Press { - accel = accel.Add(right.Multiply(walkaccel * delta.Seconds()).Negative()) - } - - if win.GetKey(glfw.KeySpace) == glfw.Press && g.player.OnGround() { - //log.Print("Jump!") - accel = accel.Addv(0, 8, 0) - } - - g.player.Accelerate(accel[0], accel[1], accel[2]) - } - - g.player.Update(g.world, delta) - - g.view.LookAt(g.player.EyePosition().ToFloat32(), g.rotY, itype.Degrees(g.rotZ)) - io.ViewPos = g.player.EyePosition() - io.ViewDir = itype.Vec3d(mgl64.Rotate3DY(float64(g.rotY.Radians())).Mul3(mgl64.Rotate3DZ(float64(itype.Degrees(g.rotZ)))).Mul3x1(mgl64.Vec3{1, 0, 0})) - - render.Framewire.PushBox(g.player.WorldHitbox()[0].ToFloat32(), color.White) - - if g.player.Position()[1] < -100 { - g.player.SetPosition(itype.Vec3d{18, 80, 18}) - g.player.SetSpeed(itype.Vec3d{}) - } - - if ok, bc, dir, _, _ := g.world.CastViewRay(io.ViewPos, io.ViewDir.Normalize(), 6); ok { - ba := g.world.Block(bc).Appearance(bc) - for _, r := range ba.Lookbox { - render.Framewire.PushBox(r.GrowEven(itype.Vec3d{0.03125, 0.03125, 0.03125}).Offset(bc.ToFloat64()).ToFloat32(), color.White) - } - - if !g.paused { - // Break/Place block - if win.GetMouseButton(glfw.MouseButtonLeft) == glfw.Press && g.runtime-time.Duration(g.player.DatasetI("LastBreak")) >= PlayerBreakCooldown { - // Break - g.world.Break(bc) - g.player.SetDatasetI("LastBreak", int64(g.runtime)) - } else if win.GetMouseButton(glfw.MouseButtonRight) == glfw.Press && g.runtime-time.Duration(g.player.DatasetI("LastPlace")) >= PlayerBreakCooldown { - // Place - // Check hitbox - tobehit := world.GetBlockBehaviour(placeId[placei]).Appearance(bc.Add(itype.DirectionVeci[dir]), 0, nil, g.world).Hitbox - if len(tobehit) == 0 { - tobehit = []itype.Boxd{{OffX: 0, OffY: 0, OffZ: 0, SizeX: 1, SizeY: 1, SizeZ: 1}} - } - canplace := true - outer: - for _, pb := range g.player.WorldHitbox() { - for _, b := range tobehit { - if ok, _ := b.Offset(bc.Add(itype.DirectionVeci[dir]).ToFloat64()).Intersect(pb); ok { - canplace = false - break outer - } - } - } - - if canplace { - aux := placeAux[placei] - if win.GetKey(glfw.KeyLeftShift) == glfw.Press { - aux = -aux - } - g.world.SetBlock(bc.Add(itype.DirectionVeci[dir]), placeId[placei], aux, nil) - g.player.SetDatasetI("LastPlace", int64(g.runtime)) - } - } - } - } - io.Diagnostics.Times.Logic = clock.Restart() g.imgui() diff --git a/internal/game/render.go b/internal/game/render.go index 309d7ac..4adb9ed 100644 --- a/internal/game/render.go +++ b/internal/game/render.go @@ -1,488 +1,19 @@ package game import ( - "errors" - "math/rand" - "time" - "unsafe" - - "edgaru089.ink/go/gl01/internal/asset" - "edgaru089.ink/go/gl01/internal/igwrap" "edgaru089.ink/go/gl01/internal/igwrap/backend" - "edgaru089.ink/go/gl01/internal/io" - "edgaru089.ink/go/gl01/internal/render" - "edgaru089.ink/go/gl01/internal/util" "edgaru089.ink/go/gl01/internal/util/itype" - "github.com/go-gl/gl/all-core/gl" "github.com/go-gl/glfw/v3.3/glfw" - "github.com/go-gl/mathgl/mgl32" - "github.com/inkyblackness/imgui-go/v4" ) -const ( - SSAOSampleCount = 32 // Number of samples in the SSAO pass. Must stay the same with ssao.frag -) - -var ( - ShadowmapSize = itype.Vec2i{6144, 6144} // Size of the shadow mapping - RandomSize = itype.Vec2i{32, 32} // Size of the random mapping -) - -// renderData holds OpenGL state used by the game renderer. -type renderData struct { - lastDisplaySize itype.Vec2i - startTime time.Time - - texRand uint32 // random texture mapping, RGBA8 (0~1) - - // Depth mapping pass - depthmap struct { - fbo, tex uint32 // Framebuffer Object and Texture. - shader *render.Shader // Shader. - } - - // Geometry pass - gbuffer struct { - fbo uint32 // The Framebuffer object. - - // Textures. Position/Depth(View Space); Normal/Lightspace Depth; Diffuse Color/Specular Intensity. - pos, norm, color uint32 - depth uint32 // Depth renderbuffer. - shader *render.Shader // Geometry pass shaders. - } - - // Screen-Space Ambient Occlusion (SSAO) pass - ssao struct { - fbo uint32 // Framebuffer - ambient uint32 // Ambient strength output texture [0,1] (Red channel) - uboSamples uint32 // Uniform Buffer Object pointing to the array of samples - shader *render.Shader // SSAO pass shader - - // SSAO blur pass - blur struct { - fbo uint32 - output uint32 - shader *render.Shader - } - } - - // Deferred lighting pass - lighting struct { - shader *render.Shader // Deferred lighting pass shaders - } - - // Semi-transparent pass - water struct { - shader *render.Shader - } - - // Output pass - output struct { - fbo uint32 // Output framebuffer object, rendering to the output texture. - tex uint32 // Output texture, rendered to the back buffer at the end. - //depth uint32 // Output depth renderbuffer, use gbuffer.depth - shader *render.Shader // Shader used to copy output.tex to back buffer. - } - - texture *render.Texture // World texture atlas -} - -func (g *Game) initRender() (err error) { - r := &g.render - - r.depthmap.shader, err = render.NewShader(asset.WorldShaderShadowmapVert, asset.WorldShaderShadowmapFrag) - if err != nil { - return errors.New("depthmap: " + err.Error()) - } - r.gbuffer.shader, err = render.NewShader(asset.WorldShaderGeometryVert, asset.WorldShaderGeometryFrag) - if err != nil { - return errors.New("gbuffer: " + err.Error()) - } - r.ssao.shader, err = render.NewShader(asset.WorldShaderSSAOVert, asset.WorldShaderSSAOFrag) - if err != nil { - return errors.New("ssao: " + err.Error()) - } - r.ssao.blur.shader, err = render.NewShader(asset.WorldShaderSSAOBlurVert, asset.WorldShaderSSAOBlurFrag) - if err != nil { - return errors.New("ssao_blur: " + err.Error()) - } - r.lighting.shader, err = render.NewShader(asset.WorldShaderLightingVert, asset.WorldShaderLightingFrag) - if err != nil { - return errors.New("lighting: " + err.Error()) - } - r.water.shader, err = render.NewShader(asset.WorldShaderWaterVert, asset.WorldShaderWaterFrag) - if err != nil { - return errors.New("water: " + err.Error()) - } - r.output.shader, err = render.NewShader(asset.WorldShaderOutputVert, asset.WorldShaderOutputFrag) - if err != nil { - return errors.New("output: " + err.Error()) - } - - // get the maximum anisotropic filtering level - var maxaf float32 - gl.GetFloatv(gl.MAX_TEXTURE_MAX_ANISOTROPY, &maxaf) - - asset.InitWorldTextureAtlas() - r.texture = render.NewTexture() - r.texture.UpdatesRGB(asset.WorldTextureAtlas.Image) - r.texture.GenerateMipMap() - gl.BindTexture(gl.TEXTURE_2D, r.texture.Handle()) - gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAX_ANISOTROPY, maxaf) - r.depthmap.shader.SetUniformTexture("tex", r.texture) - r.gbuffer.shader.SetUniformTexture("tex", r.texture) - r.water.shader.SetUniformTexture("tex", r.texture) - igwrap.SetTextureFlag(r.texture.Handle(), igwrap.TextureFlag_Linear, igwrap.TextureFlag_FlipY) - - r.depthmap.shader.SetUniformMat4("model", mgl32.Ident4()) - r.gbuffer.shader.SetUniformMat4("model", mgl32.Ident4()) - r.water.shader.SetUniformMat4("model", mgl32.Ident4()) - // and view and projection uniforms not yet set - gl.BindFragDataLocation(r.lighting.shader.Handle(), 0, gl.Str("outputColor\x00")) - gl.BindFragDataLocation(r.water.shader.Handle(), 0, gl.Str("outputColor\x00")) - gl.BindFragDataLocation(r.output.shader.Handle(), 0, gl.Str("outputColor\x00")) - - // generate random mapping - { - data := make([]uint32, RandomSize[0]*RandomSize[1]) - for i := range data { - data[i] = rand.Uint32() - } - gl.GenTextures(1, &r.texRand) - gl.BindTexture(gl.TEXTURE_2D, r.texRand) - gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int32(RandomSize[0]), int32(RandomSize[1]), 0, gl.RGBA, gl.UNSIGNED_BYTE, util.Ptr(data)) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT) - } - r.ssao.shader.SetUniformTextureHandle("rand", r.texRand) - r.ssao.shader.SetUniformVec2f("randSize", RandomSize.ToFloat32()) - - // generate the depthmap and depthmap FBO - gl.GenFramebuffers(1, &r.depthmap.fbo) - gl.GenTextures(1, &r.depthmap.tex) - gl.BindTexture(gl.TEXTURE_2D, r.depthmap.tex) - gl.TexImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, int32(ShadowmapSize[0]), int32(ShadowmapSize[1]), 0, gl.DEPTH_COMPONENT, gl.FLOAT, nil) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_BORDER) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_BORDER) - borderColor := []float32{1, 1, 1, 1} - gl.TexParameterfv(gl.TEXTURE_2D, gl.TEXTURE_BORDER_COLOR, &borderColor[0]) - // attach depth texture as FBO's depth buffer - gl.BindFramebuffer(gl.FRAMEBUFFER, r.depthmap.fbo) - gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, r.depthmap.tex, 0) - gl.DrawBuffer(gl.NONE) - gl.ReadBuffer(gl.NONE) - // attach the shadowmap to the shader - r.lighting.shader.SetUniformTextureHandle("shadowmap", r.depthmap.tex) - r.water.shader.SetUniformTextureHandle("shadowmap", r.depthmap.tex) - - // generate G-buffer and friends - gl.GenFramebuffers(1, &r.gbuffer.fbo) - gl.BindFramebuffer(gl.FRAMEBUFFER, r.gbuffer.fbo) - // position - gl.GenTextures(1, &r.gbuffer.pos) - gl.BindTexture(gl.TEXTURE_2D, r.gbuffer.pos) - gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA32F, int32(io.DisplaySize[0]), int32(io.DisplaySize[1]), 0, gl.RGBA, gl.FLOAT, nil) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_BORDER) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_BORDER) - borderColor = []float32{1, 1, 1, 1} - gl.TexParameterfv(gl.TEXTURE_2D, gl.TEXTURE_BORDER_COLOR, &borderColor[0]) - gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, r.gbuffer.pos, 0) - // normal - gl.GenTextures(1, &r.gbuffer.norm) - gl.BindTexture(gl.TEXTURE_2D, r.gbuffer.norm) - gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA16F, int32(io.DisplaySize[0]), int32(io.DisplaySize[1]), 0, gl.RGBA, gl.FLOAT, nil) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) - gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_2D, r.gbuffer.norm, 0) - // diffuse color - gl.GenTextures(1, &r.gbuffer.color) - gl.BindTexture(gl.TEXTURE_2D, r.gbuffer.color) - gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int32(io.DisplaySize[0]), int32(io.DisplaySize[1]), 0, gl.RGBA, gl.UNSIGNED_BYTE, nil) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) - gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT2, gl.TEXTURE_2D, r.gbuffer.color, 0) - // depth - gl.GenRenderbuffers(1, &r.gbuffer.depth) - gl.BindRenderbuffer(gl.RENDERBUFFER, r.gbuffer.depth) - gl.RenderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, int32(io.DisplaySize[0]), int32(io.DisplaySize[1])) - gl.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, r.gbuffer.depth) - // tell OpenGL which color attachments we'll use (of this framebuffer) - attachments := [...]uint32{gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2} - gl.DrawBuffers(int32(len(attachments)), &attachments[0]) - // attach the textures - r.lighting.shader.SetUniformTextureHandle("gPos", r.gbuffer.pos) - r.lighting.shader.SetUniformTextureHandle("gNorm", r.gbuffer.norm) - r.lighting.shader.SetUniformTextureHandle("gColor", r.gbuffer.color) - r.ssao.shader.SetUniformTextureHandle("gPos", r.gbuffer.pos) - r.ssao.shader.SetUniformTextureHandle("gNorm", r.gbuffer.norm) - r.water.shader.SetUniformTextureHandle("gPos", r.gbuffer.pos) - - // generate SSAO friends - gl.GenFramebuffers(1, &r.ssao.fbo) - gl.BindFramebuffer(gl.FRAMEBUFFER, r.ssao.fbo) - // ambient strength texture - gl.GenTextures(1, &r.ssao.ambient) - gl.BindTexture(gl.TEXTURE_2D, r.ssao.ambient) - gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RED, int32(io.DisplaySize[0]), int32(io.DisplaySize[1]), 0, gl.RED, gl.UNSIGNED_BYTE, nil) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) - gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, r.ssao.ambient, 0) - r.ssao.blur.shader.SetUniformTextureHandle("tex", r.ssao.ambient) - // uniform buffer object for samples - ssaoSamples := make([]itype.Vec4f, SSAOSampleCount) - for i := range ssaoSamples { - sample := itype.Vec3d{rand.Float64()*2 - 1, rand.Float64()*2 - 1, rand.Float64() + 0.05} - sample = sample.Normalize().Multiply(rand.Float64()).Multiply(rand.Float64()) - ssaoSamples[i] = itype.Vec4f{ - float32(sample[0]), - float32(sample[1]), - float32(sample[2]), - 0, - } - } - gl.GenBuffers(1, &r.ssao.uboSamples) - gl.BindBuffer(gl.UNIFORM_BUFFER, r.ssao.uboSamples) - gl.BufferData(gl.UNIFORM_BUFFER, int(unsafe.Sizeof(float32(0))*4*SSAOSampleCount), util.Ptr(ssaoSamples), gl.STATIC_DRAW) - // bind UBO (onto binding 0 for now) - gl.BindBufferBase(gl.UNIFORM_BUFFER, 0, r.ssao.uboSamples) - gl.UniformBlockBinding(r.ssao.shader.Handle(), gl.GetUniformBlockIndex(r.ssao.shader.Handle(), gl.Str("uboSamples\x00")), 0) - // SSAO blur pass - gl.GenFramebuffers(1, &r.ssao.blur.fbo) - gl.BindFramebuffer(gl.FRAMEBUFFER, r.ssao.blur.fbo) - gl.GenTextures(1, &r.ssao.blur.output) - gl.BindTexture(gl.TEXTURE_2D, r.ssao.blur.output) - gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RED, int32(io.DisplaySize[0]), int32(io.DisplaySize[1]), 0, gl.RED, gl.UNSIGNED_BYTE, nil) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) - gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, r.ssao.blur.output, 0) - r.lighting.shader.SetUniformTextureHandle("ssaoAmbient", r.ssao.blur.output) - - // generate the output texture and friends - gl.GenFramebuffers(1, &r.output.fbo) - gl.BindFramebuffer(gl.FRAMEBUFFER, r.output.fbo) - // output - gl.GenTextures(1, &r.output.tex) - gl.BindTexture(gl.TEXTURE_2D, r.output.tex) - gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA16F, int32(io.DisplaySize[0]), int32(io.DisplaySize[1]), 0, gl.RGBA, gl.FLOAT, nil) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) - gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, r.output.tex, 0) - // depth - gl.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, r.gbuffer.depth) - // attach textures - r.output.shader.SetUniformTextureHandle("tex", r.output.tex) - - // set the texture flags for ImGUI - igwrap.SetTextureFlag(r.gbuffer.color, igwrap.TextureFlag_Linear) - igwrap.SetTextureFlag(r.ssao.ambient, igwrap.TextureFlag_Red) - - gl.BindFramebuffer(gl.FRAMEBUFFER, 0) - r.lastDisplaySize = io.DisplaySize - r.startTime = time.Now() - - return nil -} - // ResizeDisplay resizes the size of the internal buffers dependent on the window size. // It is called automatically most of the time. func (g *Game) ResizeDisplay(newSize itype.Vec2i) { - gl.BindTexture(gl.TEXTURE_2D, g.render.gbuffer.pos) // G-Buffer, Position - gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA32F, int32(io.DisplaySize[0]), int32(io.DisplaySize[1]), 0, gl.RGBA, gl.FLOAT, nil) - gl.BindTexture(gl.TEXTURE_2D, g.render.gbuffer.norm) // G-Buffer, Normal - gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA16F, int32(io.DisplaySize[0]), int32(io.DisplaySize[1]), 0, gl.RGBA, gl.FLOAT, nil) - gl.BindTexture(gl.TEXTURE_2D, g.render.gbuffer.color) // G-Buffer, Albedo Color - gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int32(io.DisplaySize[0]), int32(io.DisplaySize[1]), 0, gl.RGBA, gl.UNSIGNED_BYTE, nil) - gl.BindRenderbuffer(gl.RENDERBUFFER, g.render.gbuffer.depth) // G-Buffer, Depth (Renderbuffer) - gl.RenderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, int32(io.DisplaySize[0]), int32(io.DisplaySize[1])) - gl.BindTexture(gl.TEXTURE_2D, g.render.ssao.ambient) // SSAO Output Ambient Strength - gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RED, int32(io.DisplaySize[0]), int32(io.DisplaySize[1]), 0, gl.RED, gl.UNSIGNED_BYTE, nil) - gl.BindTexture(gl.TEXTURE_2D, g.render.ssao.blur.output) // SSAO Blurred Output - gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RED, int32(io.DisplaySize[0]), int32(io.DisplaySize[1]), 0, gl.RED, gl.UNSIGNED_BYTE, nil) - gl.BindTexture(gl.TEXTURE_2D, g.render.output.tex) // Output Texture - gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int32(io.DisplaySize[0]), int32(io.DisplaySize[1]), 0, gl.RGBA, gl.UNSIGNED_BYTE, nil) - g.render.lastDisplaySize = newSize } -var ( - sun = [3]float32{0.2, 0.4, 0.3} - alpha = float32(0.55) - gamma = float32(2.2) - exposure = float32(1) - atlasScale = float32(1) -) - // Render, called with a OpenGL context, renders the game. func (g *Game) Render(win *glfw.Window) { - gl.Viewport(0, 0, int32(io.DisplaySize[0]), int32(io.DisplaySize[1])) - matv, matp := g.view.View(), g.view.Perspective() - matvp := matp.Mul4(matv) - - allclock := util.NewClock() - lastclock := util.NewClock() - - io.RenderPos = io.ViewPos - io.RenderDir = io.ViewDir - - // re-generate the G-buffers if the display size changed - if g.render.lastDisplaySize != io.DisplaySize { - g.ResizeDisplay(io.DisplaySize) - } - - if g.paused { - imgui.SliderFloat3("Sun", &sun, -1, 1) - imgui.SliderFloat("Water Alpha", &alpha, 0, 1) - imgui.SliderFloat("Gamma", &gamma, 1.6, 2.8) - imgui.SliderFloat("Exposure", &exposure, 0, 2) - } - normalSun := itype.Vec3f(sun).Normalize() - - gl.Enable(gl.CULL_FACE) - gl.Enable(gl.DEPTH_TEST) - gl.DepthFunc(gl.LESS) - - lastclock.Restart() - - // 1. Render to depth map - gl.Viewport(0, 0, int32(ShadowmapSize[0]), int32(ShadowmapSize[1])) - gl.BindFramebuffer(gl.FRAMEBUFFER, g.render.depthmap.fbo) - gl.Clear(gl.DEPTH_BUFFER_BIT) - gl.Disable(gl.CULL_FACE) - - lightPos := g.view.EyePos.Add(normalSun.Multiply(50)) - lightView := mgl32.LookAt(lightPos[0], lightPos[1], lightPos[2], g.view.EyePos[0], g.view.EyePos[1], g.view.EyePos[2], 0, 1, 0) - lightProjection := mgl32.Ortho(-50, 50, -50, 50, 1, 100) - lightspace := lightProjection.Mul4(lightView) - - io.RenderPos = lightPos.ToFloat64() - io.RenderDir = g.view.EyePos.Add(lightPos.Negative()).ToFloat64() - - g.render.depthmap.shader.UseProgram() - g.render.depthmap.shader.BindTextures() - g.render.depthmap.shader.SetUniformMat4("lightspace", lightspace) - - g.world.Render() - g.world.RenderWater() - - gl.Flush() - io.Diagnostics.Times.RenderPasses.Depthmap = lastclock.Restart() - - // 2. Geometry pass, render to G-buffer - io.RenderPos = io.ViewPos - io.RenderDir = io.ViewDir - - gl.Viewport(0, 0, int32(g.render.lastDisplaySize[0]), int32(g.render.lastDisplaySize[1])) - gl.BindFramebuffer(gl.FRAMEBUFFER, g.render.gbuffer.fbo) - gl.ClearColor(0, 0, 0, 1) - gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) - gl.Enable(gl.CULL_FACE) - gl.Disable(gl.BLEND) - - g.render.gbuffer.shader.UseProgram() - g.render.gbuffer.shader.BindTextures() - g.render.gbuffer.shader.SetUniformMat4("lightspace", lightspace) - g.render.gbuffer.shader.SetUniformMat4("view", matv) - g.render.gbuffer.shader.SetUniformMat4("projection", matp) - g.render.gbuffer.shader.SetUniformMat4("mvp", matvp) - g.render.gbuffer.shader.SetUniformVec3f("viewPos", g.view.EyePos) - - g.world.Render() - - gl.Flush() - io.Diagnostics.Times.RenderPasses.Geometry = lastclock.Restart() - - // 3/1. SSAO pass - gl.BindFramebuffer(gl.FRAMEBUFFER, g.render.ssao.fbo) - gl.ClearColor(1, 1, 1, 1) - gl.Clear(gl.COLOR_BUFFER_BIT) - - g.render.ssao.shader.UseProgram() - g.render.ssao.shader.BindTextures() - g.render.ssao.shader.SetUniformMat4("view", matv) - g.render.ssao.shader.SetUniformMat4("projection", matp) - g.render.ssao.shader.SetUniformVec3f("viewPos", g.view.EyePos) - - render.DrawScreenQuad() - - // 3/2. SSAO blur pass - gl.BindFramebuffer(gl.FRAMEBUFFER, g.render.ssao.blur.fbo) - g.render.ssao.blur.shader.UseProgram() - g.render.ssao.blur.shader.BindTextures() - g.render.ssao.blur.shader.SetUniformVec2f("screenSize", g.render.lastDisplaySize.ToFloat32()) - - render.DrawScreenQuad() - - gl.Flush() - io.Diagnostics.Times.RenderPasses.SSAO = lastclock.Restart() - - // 4. Render the actual output with deferred lighting - gl.BindFramebuffer(gl.FRAMEBUFFER, g.render.output.fbo) - gl.ClearColor(0, 0, 0, 0) - gl.Clear(gl.COLOR_BUFFER_BIT) - gl.Disable(gl.DEPTH_TEST) - g.render.lighting.shader.UseProgram() - g.render.lighting.shader.BindTextures() - g.render.lighting.shader.SetUniformMat4("lightspace", lightspace) - g.render.lighting.shader.SetUniformVec3f("viewPos", g.view.EyePos) - g.render.lighting.shader.SetUniformVec4f("fogColor", io.FogColor) - g.render.lighting.shader.SetUniformVec3f("sun", normalSun) - - render.DrawScreenQuad() - - gl.Flush() - io.Diagnostics.Times.RenderPasses.Lighting = lastclock.Restart() - - // 5. Render water - gl.Enable(gl.DEPTH_TEST) - gl.DepthFunc(gl.LESS) - gl.Enable(gl.CULL_FACE) - gl.Enable(gl.BLEND) - gl.BlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA) - gl.BlendEquation(gl.FUNC_ADD) - g.render.water.shader.UseProgram() - g.render.water.shader.BindTextures() - - g.render.water.shader.SetUniformMat4("lightspace", lightspace) - g.render.water.shader.SetUniformMat4("view", matv) - g.render.water.shader.SetUniformMat4("projection", matp) - g.render.water.shader.SetUniformVec3f("viewPos", g.view.EyePos) - g.render.water.shader.SetUniformVec4f("fogColor", io.FogColor) - g.render.water.shader.SetUniformVec3f("sun", normalSun) - g.render.water.shader.SetUniformFloat("alpha", alpha) - g.render.water.shader.SetUniformVec2f("screenSize", g.render.lastDisplaySize.ToFloat32()) - - g.world.RenderWater() - - // And render framewires - render.Framewire.Render(g.view) - - // Finally. Copy the output texture to the back buffer - gl.BindFramebuffer(gl.FRAMEBUFFER, 0) - gl.ClearColor(io.ClearColor[0], io.ClearColor[1], io.ClearColor[2], io.ClearColor[3]) - gl.Clear(gl.COLOR_BUFFER_BIT) - gl.Disable(gl.DEPTH_TEST) - gl.Disable(gl.BLEND) - g.render.output.shader.UseProgram() - g.render.output.shader.BindTextures() - g.render.output.shader.SetUniformFloat("gamma", gamma) - g.render.output.shader.SetUniformFloat("exposure", exposure) - - render.DrawScreenQuad() - - gl.Flush() - io.Diagnostics.Times.RenderPasses.Postfx = lastclock.Restart() - io.Diagnostics.Times.Render = allclock.Elapsed() - - // Show Information? - if io.ShowDebugInfo { - g.renderDebugInfo() - } backend.Render(win) diff --git a/internal/game/render_debuginfo.go b/internal/game/render_debuginfo.go deleted file mode 100644 index a100893..0000000 --- a/internal/game/render_debuginfo.go +++ /dev/null @@ -1,116 +0,0 @@ -package game - -import ( - "math" - "time" - - "edgaru089.ink/go/gl01/internal/asset" - "edgaru089.ink/go/gl01/internal/igwrap" - "edgaru089.ink/go/gl01/internal/io" - "edgaru089.ink/go/gl01/internal/util" - "edgaru089.ink/go/gl01/internal/util/itype" - "github.com/inkyblackness/imgui-go/v4" -) - -const ( - timebarN = 700 -) - -var ( - colorset = [...]imgui.PackedColor{4289753676, 4283598045, 4285048917, 4283584196, 4289950337, 4284512403, 4291005402, 4287401100, 4285839820, 4291671396} - timebars [timebarN][]int // height of each bar set - timebari int - timebarScale int = 64 -) - -func (g *Game) renderDebugInfo() { - // Render information - if igwrap.Begin("F3", nil, 0) { - igwrap.TextBlank() - - igwrap.TextBackground("WorldRender: lastframe %.3fms", float64(io.Diagnostics.Times.Render.Nanoseconds())/float64(time.Millisecond)) - igwrap.TextBackground("TimeBars:") - pad := igwrap.Vec2f(imgui.CurrentStyle().ItemSpacing()) - imgui.SameLine() - igwrap.TextBackgroundV(colorset[0], pad, "Depthmap") - imgui.SameLine() - igwrap.TextBackgroundV(colorset[1], pad, "Geometry") - imgui.SameLine() - igwrap.TextBackgroundV(colorset[2], pad, "SSAO") - imgui.SameLine() - igwrap.TextBackgroundV(colorset[3], pad, "Lighting") - imgui.SameLine() - igwrap.TextBackgroundV(colorset[4], pad, "Postfx") - imgui.SameLine() - igwrap.TextBackground("[Hover]") - if imgui.IsItemHoveredV(imgui.HoveredFlagsAllowWhenDisabled) { - _, wheely := imgui.CurrentIO().MouseWheel() - if math.Abs(float64(wheely)) > 1e-3 { - if wheely > 0 { - timebarScale = util.Mini(timebarScale*2, 128) - } else { // < 0 - timebarScale = util.Maxi(timebarScale/2, 1) - } - } - } - - isize := asset.WorldTextureAtlas.ImageSize - igwrap.TextBackground("Texture Atlas Size: (%dx%d)", isize[0], isize[1]) - imgui.SameLine() - igwrap.TextBackground("[Scroll]") - if imgui.IsItemHoveredV(imgui.HoveredFlagsAllowWhenDisabled) { - _, wheely := imgui.CurrentIO().MouseWheel() - if math.Abs(float64(wheely)) > 1e-3 { - atlasScale = util.Maxf(1, atlasScale+wheely) - } - imgui.BeginTooltip() - igwrap.Image(g.render.texture.Handle(), isize.ToFloat32().Multiply(atlasScale), itype.Rectf{0, 0, 1, 1}) - imgui.EndTooltip() - } - - imgui.End() - } - - // Draw Textures - imgui.SetNextWindowPosV(imgui.Vec2{X: float32(g.render.lastDisplaySize[0]), Y: 0}, imgui.ConditionAlways, imgui.Vec2{X: 1, Y: 0}) - if igwrap.Begin("Renderer Textures/Outputs", nil, igwrap.WindowFlagsOverlay) { - imgui.PushStyleVarVec2(imgui.StyleVarItemSpacing, imgui.Vec2{}) - - imageSize := g.render.lastDisplaySize.ToFloat32().Multiply(0.25) - imageSize[1] -= imgui.CurrentStyle().WindowPadding().Y / 2 - imageSize[0] = imageSize[1] / float32(g.render.lastDisplaySize[1]) * float32(g.render.lastDisplaySize[0]) - - igwrap.Image(g.render.gbuffer.pos, imageSize, itype.Rectf{0, 0, 1, 1}) - igwrap.Image(g.render.gbuffer.norm, imageSize, itype.Rectf{0, 0, 1, 1}) - igwrap.Image(g.render.gbuffer.color, imageSize, itype.Rectf{0, 0, 1, 1}) - igwrap.Image(g.render.ssao.ambient, imageSize, itype.Rectf{0, 0, 1, 1}) - - imgui.PopStyleVar() - imgui.End() - } - - // Push the next bar - timebars[timebari] = []int{ - int(io.Diagnostics.Times.RenderPasses.Depthmap.Nanoseconds()), - int(io.Diagnostics.Times.RenderPasses.Geometry.Nanoseconds()), - int(io.Diagnostics.Times.RenderPasses.SSAO.Nanoseconds()), - int(io.Diagnostics.Times.RenderPasses.Lighting.Nanoseconds()), - int(io.Diagnostics.Times.RenderPasses.Postfx.Nanoseconds()), - } - timebari++ - if timebari >= len(timebars) { - timebari = 0 - } - - // Draw time bars - size := g.render.lastDisplaySize - dl := imgui.BackgroundDrawList() - for i, l := range timebars { - ex := 0 - for j, d := range l { - d = d * timebarScale / 1024 / 1024 - dl.AddLine(imgui.Vec2{X: float32(i), Y: float32(size[1] - ex)}, imgui.Vec2{X: float32(i), Y: float32(size[1] - ex - d)}, colorset[j]) - ex += d - } - } -} diff --git a/internal/io/io.go b/internal/io/io.go index 32bfe83..da63c2f 100644 --- a/internal/io/io.go +++ b/internal/io/io.go @@ -12,10 +12,6 @@ var ( ClearColor itype.Vec4f // Clear color of the renderer. FogColor itype.Vec4f // Color of the fog. Changes if the player is e.g. under water - // Directions are not always normalized. - ViewPos, ViewDir itype.Vec3d // Position and Direction of the player view. - RenderPos, RenderDir itype.Vec3d // Position and Direction of view for the current render pass. Might be different for e.g. lighting passes - ShowDebugInfo bool // Show debug info (F3 screen)? // Per-Frame Diagnostics information diff --git a/internal/world/block.go b/internal/world/block.go deleted file mode 100644 index e84b31d..0000000 --- a/internal/world/block.go +++ /dev/null @@ -1,212 +0,0 @@ -package world - -import ( - "fmt" - - "edgaru089.ink/go/gl01/internal/util/itype" -) - -// BlockRenderType is an enum describing the rendering process of a block -type BlockRenderType int - -const ( - OneTexture BlockRenderType = iota // Render with one texture of the same on all faces, "Name.png" - ThreeTexture // Render with one texture on the top, one around the sides, and one on the bottom, "Name_top/side/bot.png," - SixTexture // Render with six different textures on six faces, "Name_x+/x-/y+/y-/z+/z-.png" - CustomRendering // Rendering calls BlockAppearance.CustomRenderAppend() -) - -// BlockAppearance describes basic appearance of a kind of block. -type BlockAppearance struct { - Name string // A short name, like "stone" or "dirt", used for texture lookups - Transparent bool // Is block transparent, i.e., does not block nearby blocks in rendering? - NotSolid bool // Is block not solid, i.e., has no hitbox at all? (this makes the zero value reasonable) - Light int // The light level it emits, 0 is none - - Hitbox []itype.Boxd // Hitbox, in block-local coordinates; empty slice means a default hitbox of 1x1x1 - Lookbox []itype.Boxd // Selection hitbox, hit only by the view ray; empty means Hitbox[] - - RenderType BlockRenderType // Rendering type, defaults to OneTexture (zero value) - - // Called on render if RenderType == CustomRendering. - // - // Be sure to return vertexArray at the end of the function (in case it got reallocated)!!!! - CustomRenderAppend func( - position itype.Vec3i, - aux int, - data itype.Dataset, - world *World, - vertexArray []Vertex, - vertexArrayWater []Vertex, - ) (verts []Vertex, waters []Vertex) -} - -// BlockBehaviour describes a kind of block of the same Major ID. -type BlockBehaviour interface { - - // Static returns if the Behaviour is "static", i.e., the Appearance does not - // change with position, Minor ID or Dataset. Static Behaviours are cached - // by the renderer and only generated once. - // - // Static implies RequireDataset = false and RequireBlockUpdate = false. - Static() bool - - // RequireDataset returns if the type of block requires a Dataset attached. - RequireDataset() bool - - // RequireBlockUpdate return if BlockUpdate should be called if a neighboring - // block has changed. Blocks not requiring BlockUpdate does not change at all. - RequireBlockUpdate() bool - - // Appearance returns the Appearance of the block at global position Position, - // with Minor ID aux, and Dataset data. - // - // If RequireDataset if false, data is nil. - Appearance(position itype.Vec3i, aux int, data itype.Dataset, world *World) BlockAppearance - - // BlockUpdate is called when RequireBlockUpdate is true and the block at - // global position Position, with Minor ID aux, and Dataset data has a neighbor - // that changed state. A block will only be updated once in a tick. - // - // If RequireDataset if false, data is nil. - // - // Return true if this block also changed state, false otherwise. - BlockUpdate(position itype.Vec3i, aux int, data itype.Dataset, world *World) bool - - // Break is called when the block is broken by natural means. - Break(position itype.Vec3i, aux int, data itype.Dataset, world *World) -} - -type blockBehaviourStatic struct { - app BlockAppearance -} - -func (blockBehaviourStatic) Static() bool { return true } -func (blockBehaviourStatic) RequireDataset() bool { return false } -func (blockBehaviourStatic) RequireBlockUpdate() bool { return false } -func (b blockBehaviourStatic) Appearance(position itype.Vec3i, aux int, data itype.Dataset, world *World) BlockAppearance { - return b.app -} -func (blockBehaviourStatic) BlockUpdate(position itype.Vec3i, aux int, data itype.Dataset, world *World) bool { - return false -} -func (blockBehaviourStatic) Break(position itype.Vec3i, aux int, data itype.Dataset, world *World) {} - -// BlockBehaviourStatic returns a Static BlockBehaviour that has the given BlockAppearance. -func BlockBehaviourStatic(app BlockAppearance) BlockBehaviour { - return blockBehaviourStatic{app: app} -} - -var behaviour map[int]BlockBehaviour = make(map[int]BlockBehaviour) -var appearance map[int]BlockAppearance = make(map[int]BlockAppearance) -var behaviourDoneRegister bool - -// RegisterBlockBehaviour registers behaviour with the given id. -// -// If the id is already taken, or id == 0, false is returned and nothing is done. -// Otherwise, true is returned and the block is registered. -func RegisterBlockBehaviour(id int, b BlockBehaviour) bool { - if _, ok := behaviour[id]; behaviourDoneRegister || id == 0 || ok { - return false - } - - behaviour[id] = b - return true -} - -// DoneRegisteringBlockBehaviour is to be called after Registering BlockBehaviour, -// i.e., in Post-Init() initializations. -func DoneRegisteringBlockBehaviour() { - for id, b := range behaviour { - if b.Static() { - appearance[id] = b.Appearance(itype.Vec3i{}, 0, nil, nil) - } - } - - behaviourDoneRegister = true -} - -// GetBlockAppearance gets the block appearance of the given block in the fastest way possible. -func GetBlockAppearance(position itype.Vec3i, id, aux int, data itype.Dataset, world *World) BlockAppearance { - if app, ok := appearance[id]; ok { // Cache - if len(app.Hitbox) == 0 { - app.Hitbox = []itype.Boxd{{ - OffX: 0, OffY: 0, OffZ: 0, - SizeX: 1, SizeY: 1, SizeZ: 1, - }} - } - if len(app.Lookbox) == 0 { - app.Lookbox = app.Hitbox - } - return app - } - - // Slow way - b, ok := behaviour[id] - if !ok { - panic(fmt.Sprint("invalid block type ", id)) - } - - app := b.Appearance(position, aux, data, world) - if len(app.Hitbox) == 0 { - app.Hitbox = []itype.Boxd{{ - OffX: 0, OffY: 0, OffZ: 0, - SizeX: 1, SizeY: 1, SizeZ: 1, - }} - } - if len(app.Lookbox) == 0 { - app.Lookbox = app.Hitbox - } - return app -} - -// GetBlockBehaviour gets the block behaviour of the given id, or nil if not present. -func GetBlockBehaviour(id int) BlockBehaviour { - return behaviour[id] -} - -// Block is a structure to store and pass Blocks around. -type Block struct { - Id, Aux int - Dataset itype.Dataset - Behaviour BlockBehaviour - World *World -} - -// Appearance is a shortcut for Behaviour.Appearance(). -// It returns the Appearance of the block with the given parameters. -func (b Block) Appearance(position itype.Vec3i) BlockAppearance { - if b.Behaviour == nil { - return BlockAppearance{} - } - app := b.Behaviour.Appearance(position, b.Aux, b.Dataset, b.World) - if !app.NotSolid && len(app.Hitbox) == 0 { - app.Hitbox = []itype.Boxd{{ - OffX: 0, OffY: 0, OffZ: 0, - SizeX: 1, SizeY: 1, SizeZ: 1, - }} - } - if len(app.Lookbox) == 0 { - if len(app.Hitbox) == 0 { - app.Lookbox = []itype.Boxd{{ - OffX: 0, OffY: 0, OffZ: 0, - SizeX: 1, SizeY: 1, SizeZ: 1, - }} - } else { - app.Lookbox = app.Hitbox - } - } - return app -} - -// BlockUpdate is a shortcut for Behaviour.BlockUpdate(). -// It is called when RequireBlockUpdate is true and the block at -// global position Position, with Minor ID aux, and Dataset data has a neighbor -// that changed state. A block will only be updated once in a tick. -// -// If RequireDataset if false, data is nil. -// -// Return true if this block also changed state, false otherwise. -func (b Block) BlockUpdate(position itype.Vec3i) bool { - return b.Behaviour.BlockUpdate(position, b.Aux, b.Dataset, b.World) -} diff --git a/internal/world/block.go.new b/internal/world/block.go.new deleted file mode 100644 index 1144c96..0000000 --- a/internal/world/block.go.new +++ /dev/null @@ -1,160 +0,0 @@ -package world - -import ( - "fmt" - - "github.com/Edgaru089/gl01/internal/util/itype" -) - -// BlockRenderType is an enum describing the rendering process of a block -type BlockRenderType int - -const ( - OneTexture BlockRenderType = iota // Render with one texture of the same on all faces, "Name.png" - ThreeTexture // Render with one texture on the top, one around the sides, and one on the bottom, "Name_top/side/bot.png," - SixTexture // Render with six different textures on six faces, "Name_x+/x-/y+/y-/z+/z-.png" - CustomRendering // Rendering calls BlockAppearance.CustomRenderAppend() -) - -// BlockAppearance describes basic appearance of a kind of block. -type BlockAppearance struct { - Name string // A short name, like "stone" or "dirt", used for texture lookups - Transparent bool // Is block transparent? - NotSolid bool // Is block not solid, i.e., has no solid hitbox? (this makes the zero value reasonable) - Light int // The light level it emits, 0 is none - - Hitbox []itype.Boxd // Hitbox, in block-local coordinates; empty slice means a default hitbox of 1x1x1 - - RenderType BlockRenderType // Rendering type, defaults to OneTexture (zero value) - - // Called on render if RenderType == CustomRendering. - // - // Be sure to return vertexArray at the end of the function (in case it got reallocated)!!!! - CustomRenderAppend func( - position itype.Vec3i, - aux int, - data itype.Dataset, - vertexArray []Vertex, - ) []Vertex -} - -// BlockBehaviour describes a kind of block of the same Major ID. -type BlockBehaviour interface { - - // Static returns if the Behaviour is "static", i.e., the Appearance does not - // change with position, Minor ID or Dataset. Static Behaviours are cached - // by the renderer and only generated once. - // - // Static implies RequireDataset = false and RequireBlockUpdate = false. - Static() bool - - // RequireDataset returns if the type of block requires a Dataset attached. - RequireDataset() bool - - // RequireBlockUpdate return if BlockUpdate should be called if a neighboring - // block has changed. Blocks not requiring BlockUpdate does not change at all. - RequireBlockUpdate() bool - - // Appearance returns the Appearance of the block at global position Position, - // with Minor ID aux, and Dataset data. - // - // If RequireDataset if false, data is nil. - Appearance(position itype.Vec3i, aux int, data itype.Dataset) BlockAppearance - - // BlockUpdate is called when RequireBlockUpdate is true and the block at - // global position Position, with Minor ID aux, and Dataset data has a neighbor - // that changed state. A block will only be updated once in a tick. - // - // If RequireDataset if false, data is nil. - // - // Return true if this block also changed state, false otherwise. - BlockUpdate(position itype.Vec3i, aux int, data itype.Dataset) bool -} - -type blockBehaviourStatic struct { - app BlockAppearance -} - -func (blockBehaviourStatic) Static() bool { return true } -func (blockBehaviourStatic) RequireDataset() bool { return false } -func (blockBehaviourStatic) RequireBlockUpdate() bool { return false } -func (b blockBehaviourStatic) Appearance(position itype.Vec3i, aux int, data itype.Dataset) BlockAppearance { - return b.app -} -func (blockBehaviourStatic) BlockUpdate(position itype.Vec3i, aux int, data itype.Dataset) bool { - return false -} - -// BlockBehaviourStatic returns a Static BlockBehaviour that has the given BlockAppearance. -func BlockBehaviourStatic(app BlockAppearance) BlockBehaviour { - return blockBehaviourStatic{app: app} -} - -var behaviour map[int]BlockBehaviour = make(map[int]BlockBehaviour) -var appearance map[int]BlockAppearance = make(map[int]BlockAppearance) -var behaviourDoneRegister bool - -// RegisterBlockBehaviour registers behaviour with the given id. -// -// If the id is already taken, or id == 0, false is returned and nothing is done. -// Otherwise, true is returned and the block is registered. -func RegisterBlockBehaviour(id int, b BlockBehaviour) bool { - if _, ok := behaviour[id]; behaviourDoneRegister || id == 0 || ok { - return false - } - - behaviour[id] = b - return true -} - -// DoneRegisteringBlockBehaviour is to be called after Registering BlockBehaviour, -// i.e., in Post-Init() initializations. -func DoneRegisteringBlockBehaviour() { - for id, b := range behaviour { - if b.Static() { - appearance[id] = b.Appearance(itype.Vec3i{}, 0, nil) - } - } - - behaviourDoneRegister = true -} - -// GetBlockAppearance gets the block appearance of the given block in the fastest way possible. -func GetBlockAppearance(position itype.Vec3i, id, aux int, data itype.Dataset) BlockAppearance { - if app, ok := appearance[id]; ok { // Cache - if len(app.Hitbox) == 0 { - app.Hitbox = []itype.Boxd{{ - OffX: 0, OffY: 0, OffZ: 0, - SizeX: 1, SizeY: 1, SizeZ: 1, - }} - } - return app - } - - // Slow way - b, ok := behaviour[id] - if !ok { - panic(fmt.Sprint("invalid block type ", id)) - } - - app := b.Appearance(position, aux, data) - if len(app.Hitbox) == 0 { - app.Hitbox = []itype.Boxd{{ - OffX: 0, OffY: 0, OffZ: 0, - SizeX: 1, SizeY: 1, SizeZ: 1, - }} - } - return app -} - -// GetBlockBehaviour gets the block behaviour of the given id, or nil if not present. -func GetBlockBehaviour(id int) BlockBehaviour { - return behaviour[id] -} - -// Block is a structure to store and pass Blocks around. -type Block struct { - Id, Aux int - Dataset itype.Dataset - Behaviour BlockBehaviour -} diff --git a/internal/world/blocks/default.go b/internal/world/blocks/default.go deleted file mode 100644 index 85e36df..0000000 --- a/internal/world/blocks/default.go +++ /dev/null @@ -1,57 +0,0 @@ -package blocks - -import "edgaru089.ink/go/gl01/internal/world" - -const ( - Nil = iota - - Debug - DebugDir - DebugNonexist - - Stone - Dirt - Grass - Bedrock - Sand - LogOak - LeavesOak - PlanksOak - - Water - - Glass - - Slab - - Count -) - -func init() { - - world.RegisterBlockBehaviour(1, world.BlockBehaviourStatic(world.BlockAppearance{Name: "debug"})) - world.RegisterBlockBehaviour(2, world.BlockBehaviourStatic(world.BlockAppearance{Name: "debug_dir", RenderType: world.SixTexture})) - world.RegisterBlockBehaviour(3, world.BlockBehaviourStatic(world.BlockAppearance{Name: "debug_nonexist"})) - - world.RegisterBlockBehaviour(4, world.BlockBehaviourStatic(world.BlockAppearance{Name: "stone"})) - world.RegisterBlockBehaviour(5, world.BlockBehaviourStatic(world.BlockAppearance{Name: "dirt"})) - world.RegisterBlockBehaviour(6, world.BlockBehaviourStatic(world.BlockAppearance{Name: "grass", RenderType: world.ThreeTexture})) - world.RegisterBlockBehaviour(7, world.BlockBehaviourStatic(world.BlockAppearance{Name: "bedrock"})) - world.RegisterBlockBehaviour(8, world.BlockBehaviourStatic(world.BlockAppearance{Name: "sand"})) - world.RegisterBlockBehaviour(9, world.BlockBehaviourStatic(world.BlockAppearance{Name: "log_oak", RenderType: world.ThreeTexture})) - world.RegisterBlockBehaviour(10, world.BlockBehaviourStatic(world.BlockAppearance{Name: "leaves_oak", Transparent: true})) - - world.RegisterBlockBehaviour(11, world.BlockBehaviourStatic(world.BlockAppearance{Name: "planks_oak"})) - - world.RegisterBlockBehaviour(12, WaterBehaviour{}) - - world.RegisterBlockBehaviour(13, world.BlockBehaviourStatic(world.BlockAppearance{Name: "glass", Transparent: true})) - - world.RegisterBlockBehaviour(14, SlabBehaviour{}) - - if Count != 15 { - panic("world.DefaultBlocks: block count not correct (check for block numbering in default_blocks.go)") - } - - world.DoneRegisteringBlockBehaviour() -} diff --git a/internal/world/blocks/helper_appendface.go b/internal/world/blocks/helper_appendface.go deleted file mode 100644 index 9510624..0000000 --- a/internal/world/blocks/helper_appendface.go +++ /dev/null @@ -1,186 +0,0 @@ -package blocks - -import ( - "edgaru089.ink/go/gl01/internal/asset" - "edgaru089.ink/go/gl01/internal/util/itype" - "edgaru089.ink/go/gl01/internal/world" -) - -// texname is the full filename of the texture file (with .png) -// faceOffset is added to each vertex -func appendFace(face itype.Direction, pos itype.Vec3i, texname string, faceOffset itype.Vec3f, arr []world.Vertex) []world.Vertex { - - switch face { - case itype.XPlus: // X+ - arr = append(arr, - // Vertex Position Normal Vector(normalized) Texture Coord Light - world.Vertex{pos.Addv(1, 0, 0).ToFloat32().Add(faceOffset), itype.Vec3f{1, 0, 0}, itype.Vec2f{1, 1}, 16}, - world.Vertex{pos.Addv(1, 1, 0).ToFloat32().Add(faceOffset), itype.Vec3f{1, 0, 0}, itype.Vec2f{1, 0}, 16}, - world.Vertex{pos.Addv(1, 1, 1).ToFloat32().Add(faceOffset), itype.Vec3f{1, 0, 0}, itype.Vec2f{0, 0}, 16}, - world.Vertex{pos.Addv(1, 0, 0).ToFloat32().Add(faceOffset), itype.Vec3f{1, 0, 0}, itype.Vec2f{1, 1}, 16}, - world.Vertex{pos.Addv(1, 1, 1).ToFloat32().Add(faceOffset), itype.Vec3f{1, 0, 0}, itype.Vec2f{0, 0}, 16}, - world.Vertex{pos.Addv(1, 0, 1).ToFloat32().Add(faceOffset), itype.Vec3f{1, 0, 0}, itype.Vec2f{0, 1}, 16}, - ) - case itype.XMinus: // X- - arr = append(arr, - world.Vertex{pos.Addv(0, 0, 0).ToFloat32().Add(faceOffset), itype.Vec3f{-1, 0, 0}, itype.Vec2f{0, 1}, 16}, - world.Vertex{pos.Addv(0, 1, 1).ToFloat32().Add(faceOffset), itype.Vec3f{-1, 0, 0}, itype.Vec2f{1, 0}, 16}, - world.Vertex{pos.Addv(0, 1, 0).ToFloat32().Add(faceOffset), itype.Vec3f{-1, 0, 0}, itype.Vec2f{0, 0}, 16}, - world.Vertex{pos.Addv(0, 0, 0).ToFloat32().Add(faceOffset), itype.Vec3f{-1, 0, 0}, itype.Vec2f{0, 1}, 16}, - world.Vertex{pos.Addv(0, 0, 1).ToFloat32().Add(faceOffset), itype.Vec3f{-1, 0, 0}, itype.Vec2f{1, 1}, 16}, - world.Vertex{pos.Addv(0, 1, 1).ToFloat32().Add(faceOffset), itype.Vec3f{-1, 0, 0}, itype.Vec2f{1, 0}, 16}, - ) - case itype.YPlus: // Y+ - arr = append(arr, - world.Vertex{pos.Addv(0, 1, 0).ToFloat32().Add(faceOffset), itype.Vec3f{0, 1, 0}, itype.Vec2f{0, 0}, 16}, - world.Vertex{pos.Addv(0, 1, 1).ToFloat32().Add(faceOffset), itype.Vec3f{0, 1, 0}, itype.Vec2f{0, 1}, 16}, - world.Vertex{pos.Addv(1, 1, 0).ToFloat32().Add(faceOffset), itype.Vec3f{0, 1, 0}, itype.Vec2f{1, 0}, 16}, - world.Vertex{pos.Addv(0, 1, 1).ToFloat32().Add(faceOffset), itype.Vec3f{0, 1, 0}, itype.Vec2f{0, 1}, 16}, - world.Vertex{pos.Addv(1, 1, 1).ToFloat32().Add(faceOffset), itype.Vec3f{0, 1, 0}, itype.Vec2f{1, 1}, 16}, - world.Vertex{pos.Addv(1, 1, 0).ToFloat32().Add(faceOffset), itype.Vec3f{0, 1, 0}, itype.Vec2f{1, 0}, 16}, - ) - case itype.YMinus: // Y- - arr = append(arr, - world.Vertex{pos.Addv(0, 0, 0).ToFloat32().Add(faceOffset), itype.Vec3f{0, -1, 0}, itype.Vec2f{1, 0}, 16}, - world.Vertex{pos.Addv(1, 0, 0).ToFloat32().Add(faceOffset), itype.Vec3f{0, -1, 0}, itype.Vec2f{0, 0}, 16}, - world.Vertex{pos.Addv(1, 0, 1).ToFloat32().Add(faceOffset), itype.Vec3f{0, -1, 0}, itype.Vec2f{0, 1}, 16}, - world.Vertex{pos.Addv(0, 0, 0).ToFloat32().Add(faceOffset), itype.Vec3f{0, -1, 0}, itype.Vec2f{1, 0}, 16}, - world.Vertex{pos.Addv(1, 0, 1).ToFloat32().Add(faceOffset), itype.Vec3f{0, -1, 0}, itype.Vec2f{0, 1}, 16}, - world.Vertex{pos.Addv(0, 0, 1).ToFloat32().Add(faceOffset), itype.Vec3f{0, -1, 0}, itype.Vec2f{1, 1}, 16}, - ) - case itype.ZPlus: // Z+ - arr = append(arr, - world.Vertex{pos.Addv(0, 0, 1).ToFloat32().Add(faceOffset), itype.Vec3f{0, 0, 1}, itype.Vec2f{0, 1}, 16}, - world.Vertex{pos.Addv(1, 0, 1).ToFloat32().Add(faceOffset), itype.Vec3f{0, 0, 1}, itype.Vec2f{1, 1}, 16}, - world.Vertex{pos.Addv(0, 1, 1).ToFloat32().Add(faceOffset), itype.Vec3f{0, 0, 1}, itype.Vec2f{0, 0}, 16}, - world.Vertex{pos.Addv(1, 1, 1).ToFloat32().Add(faceOffset), itype.Vec3f{0, 0, 1}, itype.Vec2f{1, 0}, 16}, - world.Vertex{pos.Addv(0, 1, 1).ToFloat32().Add(faceOffset), itype.Vec3f{0, 0, 1}, itype.Vec2f{0, 0}, 16}, - world.Vertex{pos.Addv(1, 0, 1).ToFloat32().Add(faceOffset), itype.Vec3f{0, 0, 1}, itype.Vec2f{1, 1}, 16}, - ) - case itype.ZMinus: // Z- - arr = append(arr, - world.Vertex{pos.Addv(0, 0, 0).ToFloat32().Add(faceOffset), itype.Vec3f{0, 0, -1}, itype.Vec2f{1, 1}, 16}, - world.Vertex{pos.Addv(0, 1, 0).ToFloat32().Add(faceOffset), itype.Vec3f{0, 0, -1}, itype.Vec2f{1, 0}, 16}, - world.Vertex{pos.Addv(1, 1, 0).ToFloat32().Add(faceOffset), itype.Vec3f{0, 0, -1}, itype.Vec2f{0, 0}, 16}, - world.Vertex{pos.Addv(0, 0, 0).ToFloat32().Add(faceOffset), itype.Vec3f{0, 0, -1}, itype.Vec2f{1, 1}, 16}, - world.Vertex{pos.Addv(1, 1, 0).ToFloat32().Add(faceOffset), itype.Vec3f{0, 0, -1}, itype.Vec2f{0, 0}, 16}, - world.Vertex{pos.Addv(1, 0, 0).ToFloat32().Add(faceOffset), 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 -} - -// same as appendFace -// faceSize is in [0, 1] -// textureSubrect is normalized, also in [0, 1]; coords start from the left-top -func appendFaceSized(face itype.Direction, pos itype.Vec3i, texname string, faceSize itype.Vec3f, faceOffset itype.Vec3f, textureSubrect itype.Rectf, arr []world.Vertex) []world.Vertex { - - switch face { - case itype.XPlus: // X+ - arr = append(arr, - // Vertex Position Normal Vector(normalized) Texture Coord Light - world.Vertex{pos.ToFloat32().Addv(1, 0, 0). - Add(faceOffset), itype.Vec3f{1, 0, 0}, itype.Vec2f{1, 1}, 16}, - world.Vertex{pos.ToFloat32().Addv(1, faceSize[1], 0). - Add(faceOffset), itype.Vec3f{1, 0, 0}, itype.Vec2f{1, 0}, 16}, - world.Vertex{pos.ToFloat32().Addv(1, faceSize[1], faceSize[2]). - Add(faceOffset), itype.Vec3f{1, 0, 0}, itype.Vec2f{0, 0}, 16}, - world.Vertex{pos.ToFloat32().Addv(1, 0, 0). - Add(faceOffset), itype.Vec3f{1, 0, 0}, itype.Vec2f{1, 1}, 16}, - world.Vertex{pos.ToFloat32().Addv(1, faceSize[1], faceSize[2]). - Add(faceOffset), itype.Vec3f{1, 0, 0}, itype.Vec2f{0, 0}, 16}, - world.Vertex{pos.ToFloat32().Addv(1, 0, faceSize[2]). - Add(faceOffset), itype.Vec3f{1, 0, 0}, itype.Vec2f{0, 1}, 16}, - ) - case itype.XMinus: // X- - arr = append(arr, - world.Vertex{pos.ToFloat32().Addv(0, 0, 0). - Add(faceOffset), itype.Vec3f{-1, 0, 0}, itype.Vec2f{0, 1}, 16}, - world.Vertex{pos.ToFloat32().Addv(0, faceSize[1], faceSize[2]). - Add(faceOffset), itype.Vec3f{-1, 0, 0}, itype.Vec2f{1, 0}, 16}, - world.Vertex{pos.ToFloat32().Addv(0, faceSize[1], 0). - Add(faceOffset), itype.Vec3f{-1, 0, 0}, itype.Vec2f{0, 0}, 16}, - world.Vertex{pos.ToFloat32().Addv(0, 0, 0). - Add(faceOffset), itype.Vec3f{-1, 0, 0}, itype.Vec2f{0, 1}, 16}, - world.Vertex{pos.ToFloat32().Addv(0, 0, faceSize[2]). - Add(faceOffset), itype.Vec3f{-1, 0, 0}, itype.Vec2f{1, 1}, 16}, - world.Vertex{pos.ToFloat32().Addv(0, faceSize[1], faceSize[2]). - Add(faceOffset), itype.Vec3f{-1, 0, 0}, itype.Vec2f{1, 0}, 16}, - ) - case itype.YPlus: // Y+ - arr = append(arr, - world.Vertex{pos.ToFloat32().Addv(0, 1, 0). - Add(faceOffset), itype.Vec3f{0, 1, 0}, itype.Vec2f{0, 0}, 16}, - world.Vertex{pos.ToFloat32().Addv(0, 1, faceSize[2]). - Add(faceOffset), itype.Vec3f{0, 1, 0}, itype.Vec2f{0, 1}, 16}, - world.Vertex{pos.ToFloat32().Addv(faceSize[0], 1, 0). - Add(faceOffset), itype.Vec3f{0, 1, 0}, itype.Vec2f{1, 0}, 16}, - world.Vertex{pos.ToFloat32().Addv(0, 1, faceSize[2]). - Add(faceOffset), itype.Vec3f{0, 1, 0}, itype.Vec2f{0, 1}, 16}, - world.Vertex{pos.ToFloat32().Addv(faceSize[0], 1, faceSize[2]). - Add(faceOffset), itype.Vec3f{0, 1, 0}, itype.Vec2f{1, 1}, 16}, - world.Vertex{pos.ToFloat32().Addv(faceSize[0], 1, 0). - Add(faceOffset), itype.Vec3f{0, 1, 0}, itype.Vec2f{1, 0}, 16}, - ) - case itype.YMinus: // Y- - arr = append(arr, - world.Vertex{pos.ToFloat32().Addv(0, 0, 0). - Add(faceOffset), itype.Vec3f{0, -1, 0}, itype.Vec2f{1, 0}, 16}, - world.Vertex{pos.ToFloat32().Addv(faceSize[0], 0, 0). - Add(faceOffset), itype.Vec3f{0, -1, 0}, itype.Vec2f{0, 0}, 16}, - world.Vertex{pos.ToFloat32().Addv(faceSize[0], 0, faceSize[2]). - Add(faceOffset), itype.Vec3f{0, -1, 0}, itype.Vec2f{0, 1}, 16}, - world.Vertex{pos.ToFloat32().Addv(0, 0, 0). - Add(faceOffset), itype.Vec3f{0, -1, 0}, itype.Vec2f{1, 0}, 16}, - world.Vertex{pos.ToFloat32().Addv(faceSize[0], 0, faceSize[2]). - Add(faceOffset), itype.Vec3f{0, -1, 0}, itype.Vec2f{0, 1}, 16}, - world.Vertex{pos.ToFloat32().Addv(0, 0, faceSize[2]). - Add(faceOffset), itype.Vec3f{0, -1, 0}, itype.Vec2f{1, 1}, 16}, - ) - case itype.ZPlus: // Z+ - arr = append(arr, - world.Vertex{pos.ToFloat32().Addv(0, 0, 1). - Add(faceOffset), itype.Vec3f{0, 0, 1}, itype.Vec2f{0, 1}, 16}, - world.Vertex{pos.ToFloat32().Addv(faceSize[0], 0, 1). - Add(faceOffset), itype.Vec3f{0, 0, 1}, itype.Vec2f{1, 1}, 16}, - world.Vertex{pos.ToFloat32().Addv(0, faceSize[1], 1). - Add(faceOffset), itype.Vec3f{0, 0, 1}, itype.Vec2f{0, 0}, 16}, - world.Vertex{pos.ToFloat32().Addv(faceSize[0], faceSize[1], 1). - Add(faceOffset), itype.Vec3f{0, 0, 1}, itype.Vec2f{1, 0}, 16}, - world.Vertex{pos.ToFloat32().Addv(0, faceSize[1], 1). - Add(faceOffset), itype.Vec3f{0, 0, 1}, itype.Vec2f{0, 0}, 16}, - world.Vertex{pos.ToFloat32().Addv(faceSize[0], 0, 1). - Add(faceOffset), itype.Vec3f{0, 0, 1}, itype.Vec2f{1, 1}, 16}, - ) - case itype.ZMinus: // Z- - arr = append(arr, - world.Vertex{pos.ToFloat32().Addv(0, 0, 0). - Add(faceOffset), itype.Vec3f{0, 0, -1}, itype.Vec2f{1, 1}, 16}, - world.Vertex{pos.ToFloat32().Addv(0, faceSize[1], 0). - Add(faceOffset), itype.Vec3f{0, 0, -1}, itype.Vec2f{1, 0}, 16}, - world.Vertex{pos.ToFloat32().Addv(faceSize[0], faceSize[1], 0). - Add(faceOffset), itype.Vec3f{0, 0, -1}, itype.Vec2f{0, 0}, 16}, - world.Vertex{pos.ToFloat32().Addv(0, 0, 0). - Add(faceOffset), itype.Vec3f{0, 0, -1}, itype.Vec2f{1, 1}, 16}, - world.Vertex{pos.ToFloat32().Addv(faceSize[0], faceSize[1], 0). - Add(faceOffset), itype.Vec3f{0, 0, -1}, itype.Vec2f{0, 0}, 16}, - world.Vertex{pos.ToFloat32().Addv(faceSize[0], 0, 0). - Add(faceOffset), 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 + (textureSubrect.Left+textureSubrect.Width*arr[i].Texture[0])*texrect.Width - arr[i].Texture[1] = texrect.Top + (textureSubrect.Top+textureSubrect.Height*arr[i].Texture[1])*texrect.Height - } - - return arr -} diff --git a/internal/world/blocks/slab.go b/internal/world/blocks/slab.go deleted file mode 100644 index d497ebd..0000000 --- a/internal/world/blocks/slab.go +++ /dev/null @@ -1,100 +0,0 @@ -package blocks - -import ( - "edgaru089.ink/go/gl01/internal/util/itype" - "edgaru089.ink/go/gl01/internal/world" -) - -type SlabBehaviour struct{} - -func (SlabBehaviour) Static() bool { return true } -func (SlabBehaviour) RequireDataset() bool { return false } -func (SlabBehaviour) RequireBlockUpdate() bool { return false } -func (SlabBehaviour) Appearance(position itype.Vec3i, aux int, data itype.Dataset, w *world.World) world.BlockAppearance { - - var hitbox itype.Boxd - if aux > 0 { // Bottom slab - hitbox = itype.Boxd{0, 0, 0, 1, 0.5, 1} - } else { // Top slab - hitbox = itype.Boxd{0, 0.5, 0, 1, 0.5, 1} - } - - return world.BlockAppearance{ - Name: "", - Transparent: true, - NotSolid: false, - Hitbox: []itype.Boxd{hitbox}, - Lookbox: []itype.Boxd{hitbox}, - - RenderType: world.CustomRendering, - CustomRenderAppend: func( - position itype.Vec3i, - aux int, - data itype.Dataset, - w *world.World, - vertexArray []world.Vertex, vertsWater []world.Vertex) (verts, waters []world.Vertex) { - - var offset itype.Vec3f - if aux < 0 { - offset = itype.Vec3f{0, 0.5, 0} - aux = -aux - } - - var name string - switch aux { - case Stone: - name = "stone" - case Sand: - name = "sand" - case PlanksOak: - name = "planks_oak" - } - - vertexArray = appendFace(itype.YMinus, position, name+".png", itype.Vec3f{0, 0, 0}.Add(offset), vertexArray) - vertexArray = appendFace(itype.YPlus, position, name+".png", itype.Vec3f{0, -0.5, 0}.Add(offset), vertexArray) - - vertexArray = appendFaceSized( - itype.XPlus, - position, - name+".png", - itype.Vec3f{1, 0.5, 1}, - itype.Vec3f{0, 0, 0}.Add(offset), - itype.Rectf{0, 0, 1, 0.5}, - vertexArray, - ) - vertexArray = appendFaceSized( - itype.XMinus, - position, - name+".png", - itype.Vec3f{1, 0.5, 1}, - itype.Vec3f{0, 0, 0}.Add(offset), - itype.Rectf{0, 0, 1, 0.5}, - vertexArray, - ) - vertexArray = appendFaceSized( - itype.ZPlus, - position, - name+".png", - itype.Vec3f{1, 0.5, 1}, - itype.Vec3f{0, 0, 0}.Add(offset), - itype.Rectf{0, 0, 1, 0.5}, - vertexArray, - ) - vertexArray = appendFaceSized( - itype.ZMinus, - position, - name+".png", - itype.Vec3f{1, 0.5, 1}, - itype.Vec3f{0, 0, 0}.Add(offset), - itype.Rectf{0, 0, 1, 0.5}, - vertexArray, - ) - - return vertexArray, vertsWater - }, - } -} -func (SlabBehaviour) BlockUpdate(position itype.Vec3i, aux int, data itype.Dataset, w *world.World) bool { - return false -} -func (SlabBehaviour) Break(position itype.Vec3i, aux int, data itype.Dataset, w *world.World) {} diff --git a/internal/world/blocks/water.go b/internal/world/blocks/water.go deleted file mode 100644 index 263f53e..0000000 --- a/internal/world/blocks/water.go +++ /dev/null @@ -1,38 +0,0 @@ -package blocks - -import ( - "edgaru089.ink/go/gl01/internal/util/itype" - "edgaru089.ink/go/gl01/internal/world" -) - -type WaterBehaviour struct{} - -func (WaterBehaviour) Static() bool { return false } -func (WaterBehaviour) RequireDataset() bool { return false } -func (WaterBehaviour) RequireBlockUpdate() bool { return false } -func (WaterBehaviour) Appearance(position itype.Vec3i, aux int, data itype.Dataset, w *world.World) world.BlockAppearance { - return world.BlockAppearance{ - Name: "water", - Transparent: true, - NotSolid: true, - - RenderType: world.CustomRendering, - CustomRenderAppend: func( - position itype.Vec3i, - aux int, - data itype.Dataset, - w *world.World, - vertexArray []world.Vertex, vertsWater []world.Vertex) (verts, waters []world.Vertex) { - - if block := w.Block(position.Addv(0, 1, 0)); block.Id != Water { - return vertexArray, appendFace(itype.YPlus, position, "water.png", itype.Vec3f{0, -0.125, 0}, vertsWater) - } - - return vertexArray, vertsWater - }, - } -} -func (WaterBehaviour) BlockUpdate(position itype.Vec3i, aux int, data itype.Dataset, w *world.World) bool { - return false -} -func (WaterBehaviour) Break(position itype.Vec3i, aux int, data itype.Dataset, w *world.World) {} diff --git a/internal/world/chunk.go b/internal/world/chunk.go deleted file mode 100644 index 96f57cf..0000000 --- a/internal/world/chunk.go +++ /dev/null @@ -1,103 +0,0 @@ -package world - -import ( - "encoding/gob" - "io" - "log" - - "edgaru089.ink/go/gl01/internal/util/itype" -) - -const ( - ChunkSizeX = 16 - ChunkSizeY = 128 - ChunkSizeZ = 16 -) - -type Chunk struct { - X, Z int // Chunk coordinate in global coordinate (y is always zero) - - Id [ChunkSizeX][ChunkSizeY][ChunkSizeZ]uint16 - Aux [ChunkSizeX][ChunkSizeY][ChunkSizeZ]int16 - - // render data kept unexported (therefore excluded from gob encoding) - renderChanged bool - vao, vbo uint32 - vbolen int - water struct { - vao, vbo uint32 - vbolen int - } - vertUpdate chan [2][]Vertex - - world *World -} - -func (c *Chunk) SetChunkID(x, z int) { - c.X = x - c.Z = z - c.renderChanged = true -} - -func (c *Chunk) SetBlock(x, y, z int, id, aux int) { - c.Id[x][y][z] = uint16(id) - c.Aux[x][y][z] = int16(aux) - c.renderChanged = true - - switch x { - case 0: - if cb, ok := c.world.Chunks[itype.Vec2i{c.X - 1, c.Z}]; ok { - cb.InvalidateRender() - } - case ChunkSizeX - 1: - if cb, ok := c.world.Chunks[itype.Vec2i{c.X + 1, c.Z}]; ok { - cb.InvalidateRender() - } - } - switch z { - case 0: - if cb, ok := c.world.Chunks[itype.Vec2i{c.X, c.Z - 1}]; ok { - cb.InvalidateRender() - } - case ChunkSizeZ - 1: - if cb, ok := c.world.Chunks[itype.Vec2i{c.X, c.Z + 1}]; ok { - cb.InvalidateRender() - } - } -} - -// InvalidateRender should be called if a block inside the chunk has changed -// and the chunk needs to re-rendered. -func (c *Chunk) InvalidateRender() { - c.renderChanged = true -} - -// LoadFromGob loads the chunk from a gob-encoded file. -func (c *Chunk) LoadFromGob(file io.Reader) { - d := gob.NewDecoder(file) - err := d.Decode(c) - if err != nil { - log.Print("LoadFromGob Error: ", err) - } -} - -// LoadFromGobIndexed loads the chunk from a gob-encoded file, with the -// chunk Index overwritten. -func (c *Chunk) LoadFromGobIndexed(file io.Reader, x, z int) { - d := gob.NewDecoder(file) - err := d.Decode(c) - if err != nil { - log.Printf("LoadFromGobIndexed(x=%d, z=%d) Error: %s", x, z, err) - } - c.X = x - c.Z = z -} - -// WriteToGob writes the chunk to a gob-encoded file. -func (c *Chunk) WriteToGob(file io.Writer) { - e := gob.NewEncoder(file) - err := e.Encode(c) - if err != nil { - log.Printf("WriteToGob(x=%d, z=%d) Error: %s", c.X, c.Z, err) - } -} diff --git a/internal/world/render.go b/internal/world/render.go deleted file mode 100644 index 60a83af..0000000 --- a/internal/world/render.go +++ /dev/null @@ -1,289 +0,0 @@ -package world - -import ( - "log" - "time" - "unsafe" - - "edgaru089.ink/go/gl01/internal/asset" - "edgaru089.ink/go/gl01/internal/io" - "edgaru089.ink/go/gl01/internal/util" - "edgaru089.ink/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) - - 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) - - c.renderChanged = true -} - -func (c *Chunk) FreeRender() { - gl.DeleteVertexArrays(1, &c.vao) - gl.DeleteBuffers(1, &c.vbo) - gl.DeleteVertexArrays(1, &c.water.vao) - gl.DeleteBuffers(1, &c.water.vbo) - 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) -} - -// 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) -} - -// 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() - vert, vertWater := c.appendVertex([]Vertex{}, []Vertex{}) - 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()) - c.vertUpdate <- [2][]Vertex{vert, vertWater} - }() - c.renderChanged = false - } - - select { - case vert := <-c.vertUpdate: - gl.BindBuffer(gl.ARRAY_BUFFER, c.vbo) - gl.BufferData(gl.ARRAY_BUFFER, int(unsafe.Sizeof(Vertex{}))*len(vert[0]), util.Ptr(vert[0]), gl.DYNAMIC_DRAW) - gl.BindBuffer(gl.ARRAY_BUFFER, c.water.vbo) - gl.BufferData(gl.ARRAY_BUFFER, int(unsafe.Sizeof(Vertex{}))*len(vert[1]), util.Ptr(vert[1]), gl.DYNAMIC_DRAW) - c.vbolen = len(vert[0]) - c.water.vbolen = len(vert[1]) - default: // do nothing - } -} - -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 -} - -func (c *Chunk) Render() { - if !c.checkView(io.ViewPos, io.ViewDir) || !c.checkView(io.RenderPos, io.RenderDir) { - return - } - - c.updateRender() - c.Bind() - gl.DrawArrays(gl.TRIANGLES, 0, int32(c.vbolen)) -} - -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) { - 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, c.world) - 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, arrwater = app.CustomRenderAppend(off.Addv(i, j, k), int(c.Aux[i][j][k]), nil, c.world, arr, arrwater) - } - - } - } - } - - return arr, arrwater -} - -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, c.world, - ).Transparent { // face next to a solid block - return arr // skip! - } - - 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! - } - - 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 -} diff --git a/internal/world/render.go.old b/internal/world/render.go.old deleted file mode 100644 index 71167d4..0000000 --- a/internal/world/render.go.old +++ /dev/null @@ -1,204 +0,0 @@ -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 -} diff --git a/internal/world/viewray.go b/internal/world/viewray.go deleted file mode 100644 index bb55747..0000000 --- a/internal/world/viewray.go +++ /dev/null @@ -1,55 +0,0 @@ -package world - -import ( - "edgaru089.ink/go/gl01/internal/util/itype" -) - -func (w *World) castworker(from, dir itype.Vec3d, maxlen float64, current itype.Vec3i, skipdir itype.Direction) (ok bool, blockcoord itype.Vec3i, face itype.Direction, where itype.Vec3d, dist float64) { - - // Length test - if current.ToFloat64().Addv(0.5, 0.5, 0.5).Add(from.Negative()).Length() > maxlen+1 { - return - } - - // Loose intersect test - if ok, _, _, _ = (itype.Boxd{ - OffX: float64(current[0]), - OffY: float64(current[1]), - OffZ: float64(current[2]), - SizeX: 1, SizeY: 1, SizeZ: 1, - }).IntersectRay(from, dir, maxlen); !ok { - return - } - - // Go through the bounding boxes - ba := w.Block(current).Appearance(current) - if !ba.NotSolid { - for _, b := range ba.Lookbox { - if ok, face, where, dist = b.Offset(current.ToFloat64()).IntersectRay(from, dir, maxlen); ok { - blockcoord = current - return - } - } - } - - // Test the directions - for i := itype.Direction(0); i < 6; i++ { - if i == skipdir { - continue - } - - ok, blockcoord, face, where, dist = w.castworker(from, dir, maxlen, current.Add(itype.DirectionVeci[i]), i.Opposite()) - if ok { - return - } - } - - ok = false - return -} - -// CastViewRay -func (w *World) CastViewRay(from, dir itype.Vec3d, maxlen float64) (ok bool, blockcoord itype.Vec3i, face itype.Direction, where itype.Vec3d, dist float64) { - - return w.castworker(from, dir, maxlen, from.Floor(), -1) -} diff --git a/internal/world/world.go b/internal/world/world.go deleted file mode 100644 index 0778866..0000000 --- a/internal/world/world.go +++ /dev/null @@ -1,167 +0,0 @@ -package world - -import ( - "fmt" - "io" - - "edgaru089.ink/go/gl01/internal/util/itype" -) - -// World holds a number of Chunks and Entities. -type World struct { - Chunks map[itype.Vec2i]*Chunk - Seed int32 -} - -// NewWorld creates a new, empty, world with no chunks. -func NewWorld() *World { - var w World - w.Chunks = make(map[itype.Vec2i]*Chunk) - - return &w -} - -// The default World. -var DefaultWorld World - -func init() { - DefaultWorld.Chunks = make(map[itype.Vec2i]*Chunk) -} - -// Chunk returns the chunk at [x, z], or nil if nonexistent. -func (w *World) Chunk(x, z int) *Chunk { - return w.Chunks[itype.Vec2i{x, z}] -} - -// SetChunk sets the chunk [x, z] to c. -func (w *World) SetChunk(x, z int, c *Chunk) { - if old, ok := w.Chunks[itype.Vec2i{x, z}]; ok { - old.FreeRender() - } - - c.X = x - c.Z = z - c.renderChanged = true - c.world = w - w.Chunks[itype.Vec2i{x, z}] = c - c.InitRender() -} - -func BlockPosToChunk(blockpos itype.Vec3i) (x, z int) { - if blockpos[0] >= 0 { - x = blockpos[0] / ChunkSizeX - } else { - x = (blockpos[0]+1)/ChunkSizeX - 1 - } - - if blockpos[2] >= 0 { - z = blockpos[2] / ChunkSizeZ - } else { - z = (blockpos[2]+1)/ChunkSizeZ - 1 - } - - return -} - -func BlockPosToInChunk(blockpos itype.Vec3i) (x, y, z int) { - if blockpos[0] >= 0 { - x = blockpos[0] % ChunkSizeX - } else { - x = ChunkSizeX + (blockpos[0] % ChunkSizeX) - if x == ChunkSizeX { - x = 0 - } - } - y = blockpos[1] - if blockpos[2] >= 0 { - z = blockpos[2] % ChunkSizeZ - } else { - z = ChunkSizeZ + (blockpos[2] % ChunkSizeZ) - if z == ChunkSizeZ { - z = 0 - } - } - return -} - -// Break breaks the block. -func (w *World) Break(pos itype.Vec3i) { - cx, cz := BlockPosToChunk(pos) - cix, ciy, ciz := BlockPosToInChunk(pos) - c, ok := w.Chunks[itype.Vec2i{cx, cz}] - if !ok || ciy < 0 || ciy >= ChunkSizeY { - return - } - - c.SetBlock(cix, ciy, ciz, 0, 0) -} - -// Block returns the block at the position [pos], or an empty Block{} if it does not exist. -func (w *World) Block(pos itype.Vec3i) Block { - cx, cz := BlockPosToChunk(pos) - cix, ciy, ciz := BlockPosToInChunk(pos) - c, ok := w.Chunks[itype.Vec2i{cx, cz}] - if !ok || ciy < 0 || ciy >= ChunkSizeY { - return Block{} - } - return Block{ - Id: int(c.Id[cix][ciy][ciz]), - Aux: int(c.Aux[cix][ciy][ciz]), - Dataset: nil, - Behaviour: GetBlockBehaviour(int(c.Id[cix][ciy][ciz])), - } -} - -// SetBlock sets the block at the given position, returning its Block. -// -// It fails if the chunk is not loaded, and an empty Block{} is returned. -func (w *World) SetBlock(pos itype.Vec3i, id, aux int, dataset itype.Dataset) Block { - cx, cz := BlockPosToChunk(pos) - cix, ciy, ciz := BlockPosToInChunk(pos) - c, ok := w.Chunks[itype.Vec2i{cx, cz}] - if !ok || ciy < 0 || ciy >= ChunkSizeY { - return Block{} - } - - c.SetBlock(cix, ciy, ciz, id, aux) - return Block{ - Id: int(c.Id[cix][ciy][ciz]), - Aux: int(c.Aux[cix][ciy][ciz]), - Dataset: nil, - Behaviour: GetBlockBehaviour(int(c.Id[cix][ciy][ciz])), - } -} - -// LoadChunkFromGob loads (or overwrites) chunk [id.x, id.z] from the Gob-encoding file. -func (w *World) LoadChunkFromGob(id itype.Vec2i, file io.Reader) (err error) { - c := &Chunk{} - if err != nil { - return fmt.Errorf("World: load chunk (%d,%d) from gob file: %s", id[0], id[1], err) - } - - if old, ok := w.Chunks[id]; ok { - old.FreeRender() - } - - c.LoadFromGobIndexed(file, id[0], id[1]) - w.Chunks[id] = c - c.InitRender() - - return nil -} - -// Render should be called from WorldRenderer, setting shader and texture context -// for the Render function, which merely calls BindVertexArray and DrawArrays. -func (w *World) Render() { - for _, c := range w.Chunks { - c.Render() - } -} - -// RenderWater calls DrawArrays drawing the semi-transparant layer of the world. -func (w *World) RenderWater() { - for _, c := range w.Chunks { - c.RenderWater() - } - -} diff --git a/internal/world/worldgen/worldgen.go b/internal/world/worldgen/worldgen.go deleted file mode 100644 index e214890..0000000 --- a/internal/world/worldgen/worldgen.go +++ /dev/null @@ -1,105 +0,0 @@ -package worldgen - -import ( - "sync" - - packworld "edgaru089.ink/go/gl01/internal/world" - "edgaru089.ink/go/gl01/internal/world/blocks" - "github.com/aquilax/go-perlin" -) - -const ( - Alpha = 5 // Weight forming the noise sum - Beta = 2 // harmonic scaling/spacing - N = 3 // iterations - - AltitudeDensity = 20 // Density of the noise in altitude - - Sealevel = 63 // Space with Y=63 and lower should be the sea - Highest = 74 // Highest part of the terrain - Lowest = 54 // Lowest part of the terrain -) - -var perlins map[int64]*perlin.Perlin -var perlinsLock sync.RWMutex - -func init() { - perlins = make(map[int64]*perlin.Perlin) -} - -func fractal(p *perlin.Perlin, x, y float64, levels int) float64 { - ans := 0.0 - amp := 1.0 - for i := 0; i < levels; i++ { - ans += amp * p.Noise2D(x, y) - amp /= 3 - x *= 2 - y *= 2 - } - return ans -} - -// Chunk generates the chunk (must with chunkID set!!) with seed. -func Chunk(chunk *packworld.Chunk, world *packworld.World, seed int64) { - - perlinsLock.RLock() - p, ok := perlins[seed] - if !ok { - perlinsLock.RUnlock() - perlinsLock.Lock() - p = perlin.NewPerlin(Alpha, Beta, N, seed) - perlins[seed] = p - perlinsLock.Unlock() - } else { - perlinsLock.RUnlock() - } - - //log.Printf("noise=%.5f", p.Noise2D(0.1, 0.1)) - - offX := packworld.ChunkSizeX * chunk.X - offZ := packworld.ChunkSizeZ * chunk.Z - - for x := 0; x < packworld.ChunkSizeX; x++ { - for z := 0; z < packworld.ChunkSizeZ; z++ { - - height := Lowest + int(float64(Highest-Lowest)*(fractal( - p, - float64(offX+x)/AltitudeDensity, - float64(offZ+z)/AltitudeDensity, 6)/2+0.5)) - //log.Printf("height = %d (noise=%.5f)", height, p.Noise2D(float64(offX+x)/AltitudeDensity, float64(offZ+z)/AltitudeDensity)/2+0.5) - - // water - for y := Sealevel; y > height; y-- { - chunk.Id[x][y][z] = blocks.Water - } - - // covering dirt - if height >= Sealevel { - chunk.Id[x][height][z] = blocks.Grass - } else { - chunk.Id[x][height][z] = blocks.Dirt - } - //chunk.Id[x][height][z] = blocks.DebugDir - chunk.Id[x][height-1][z] = blocks.Dirt - chunk.Id[x][height-2][z] = blocks.Dirt - chunk.Id[x][height-3][z] = blocks.Dirt - height -= 4 - - // stone in the middle - for y := height; y >= 1; y-- { - chunk.Id[x][y][z] = blocks.Stone - } - - // bedrock at the bottom - chunk.Id[x][0][z] = blocks.Bedrock - - // plant trees - if height >= 50 && height <= 70 { - if p.Noise2D(float64(offX+x), float64(offZ+z)) > 0.9 { - } - } - } - } - - chunk.InvalidateRender() -} diff --git a/main.cfg.json b/main.cfg.json index 1c07991..cb51509 100644 --- a/main.cfg.json +++ b/main.cfg.json @@ -1,7 +1,7 @@ { - "WindowWidth": 800, - "WindowHeight": 600, + "WindowWidth": 1024, + "WindowHeight": 768, - "FramerateLimit": 0 + "FramerateLimit": 100 }