Map block
This commit is contained in:
parent
4de4de419c
commit
52ed93aa0f
@ -1,5 +1,5 @@
|
||||
import { Mesh } from '../mesh'
|
||||
import { MeshInstance } from '../components'
|
||||
import { Node, MeshInstance } from '../components'
|
||||
import { addv3 } from '../utility'
|
||||
|
||||
const FACE_VERTEX = [
|
||||
@ -74,8 +74,9 @@ const AIR_VOXEL = new Voxel(0)
|
||||
const GROUND_VOXEL = new Voxel(1)
|
||||
|
||||
class VoxelChunk extends MeshInstance {
|
||||
constructor (pos, size = 16) {
|
||||
super(null, pos)
|
||||
constructor (origin, pos, size = 16) {
|
||||
super(null, [origin[0] + pos[0] * size, origin[1] + pos[1] * size, origin[2] + pos[2] * size])
|
||||
this.relativePos = pos
|
||||
this.size = size
|
||||
this.mesh = null
|
||||
|
||||
@ -90,24 +91,77 @@ class VoxelChunk extends MeshInstance {
|
||||
}
|
||||
|
||||
getVoxel (x, y, z) {
|
||||
if (x < 0 || x >= this.size || y < 0 || y >= this.size || z < 0 || z >= this.size) return AIR_VOXEL
|
||||
return this.data[x][y][z]
|
||||
if (this.parent) {
|
||||
let neighbor
|
||||
if (x < 0) {
|
||||
neighbor = this.parent.getChunk(this.relativePos[0] - 1, this.relativePos[1], this.relativePos[2])
|
||||
if (neighbor) {
|
||||
return neighbor.getVoxel(this.size + x, y, z)
|
||||
}
|
||||
return AIR_VOXEL
|
||||
} else if (x >= this.size) {
|
||||
neighbor = this.parent.getChunk(this.relativePos[0] + 1, this.relativePos[1], this.relativePos[2])
|
||||
if (neighbor) {
|
||||
return neighbor.getVoxel(x - this.size, y, z)
|
||||
}
|
||||
return AIR_VOXEL
|
||||
} else if (y < 0) {
|
||||
neighbor = this.parent.getChunk(this.relativePos[0], this.relativePos[1] - 1, this.relativePos[2])
|
||||
if (neighbor) {
|
||||
return neighbor.getVoxel(x, this.size + y, z)
|
||||
}
|
||||
return AIR_VOXEL
|
||||
} else if (y >= this.size) {
|
||||
neighbor = this.parent.getChunk(this.relativePos[0], this.relativePos[1] + 1, this.relativePos[2])
|
||||
if (neighbor) {
|
||||
return neighbor.getVoxel(x, y - this.size, z)
|
||||
}
|
||||
return AIR_VOXEL
|
||||
} else if (z < 0) {
|
||||
neighbor = this.parent.getChunk(this.relativePos[0], this.relativePos[1], this.relativePos[2] - 1)
|
||||
if (neighbor) {
|
||||
return neighbor.getVoxel(x, y, this.size + z)
|
||||
}
|
||||
return AIR_VOXEL
|
||||
} else if (z >= this.size) {
|
||||
neighbor = this.parent.getChunk(this.relativePos[0], this.relativePos[1], this.relativePos[2] + 1)
|
||||
if (neighbor) {
|
||||
return neighbor.getVoxel(x, y, z - this.size)
|
||||
}
|
||||
return AIR_VOXEL
|
||||
}
|
||||
}
|
||||
|
||||
return this.data[x][z][y]
|
||||
}
|
||||
|
||||
getVoxelv (v) {
|
||||
return this.getVoxel(v[0], v[1], v[2])
|
||||
}
|
||||
|
||||
generate (generator) {
|
||||
this.data = {}
|
||||
for (let x = 0; x < this.size; x++) {
|
||||
if (!this.data[x]) this.data[x] = {}
|
||||
for (let y = 0; y < this.size; y++) {
|
||||
if (!this.data[x][y]) this.data[x][y] = {}
|
||||
for (let z = 0; z < this.size; z++) {
|
||||
if (!this.data[x][y][z]) this.data[x][y][z] = {}
|
||||
let solid = y < (generator.getHeight(x + this.pos[0], z + this.pos[2]) + 10)
|
||||
this.data[x][y][z] = solid ? GROUND_VOXEL : AIR_VOXEL
|
||||
if (!this.data[x][z]) this.data[x][z] = {}
|
||||
let columnHeight = generator.getHeight(x + this.pos[0], z + this.pos[2])
|
||||
for (let y = 0; y < this.size; y++) {
|
||||
let solid = this.pos[1] + y < columnHeight
|
||||
this.data[x][z][y] = solid ? GROUND_VOXEL : AIR_VOXEL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.generated = true
|
||||
|
||||
// Make sure the parent knows that we have generated everything
|
||||
if (this.parent) {
|
||||
this.parent.chunksLeft--
|
||||
if (this.parent.chunksLeft <= 0) {
|
||||
this.parent.generated = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Programmatically generate a voxel face
|
||||
@ -138,7 +192,7 @@ class VoxelChunk extends MeshInstance {
|
||||
this.dirty = false
|
||||
|
||||
// If there is no generated chunk, we have nothing to base a mesh off of
|
||||
if (!this.generated) return
|
||||
if (!this.generated) return false
|
||||
|
||||
// If there already exists a mesh, dispose of it
|
||||
if (this.mesh) {
|
||||
@ -184,7 +238,7 @@ class VoxelChunk extends MeshInstance {
|
||||
|
||||
// Do not create a mesh when there are no faces in this chunk
|
||||
if (points.length === 0) {
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
// Flatten the points array to three separate arrays
|
||||
@ -206,13 +260,108 @@ class VoxelChunk extends MeshInstance {
|
||||
// Create a new mesh without an element array buffer (TODO maybe?)
|
||||
this.mesh = Mesh.construct(gl, vertices, null, uvs, normals)
|
||||
|
||||
// TODO: Temporary..
|
||||
if (this.material) this.mesh.material = this.material
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
update (gl, dt) {
|
||||
if (this.dirty) return this.createMesh(gl)
|
||||
return false
|
||||
}
|
||||
|
||||
destroy (gl) {
|
||||
this.generated = false
|
||||
this.mesh && this.mesh.dispose(gl)
|
||||
this.data = {}
|
||||
}
|
||||
}
|
||||
|
||||
export { Voxel, VoxelChunk }
|
||||
class VoxelMapBlock extends Node {
|
||||
constructor (pos, chunkSize = 16, size = 8) {
|
||||
super(pos)
|
||||
this.chunkSize = chunkSize
|
||||
this.size = size
|
||||
this.chunks = {}
|
||||
this.generated = false
|
||||
this.chunksLeft = size * size * size
|
||||
}
|
||||
|
||||
getChunk (x, y, z) {
|
||||
if (x < 0 || x >= this.size || y < 0 || y >= this.size || z < 0 || z >= this.size) return null
|
||||
return this.chunks[x][z][y]
|
||||
}
|
||||
|
||||
getChunkv (v) {
|
||||
return this.getChunk(v[0], v[1], v[2])
|
||||
}
|
||||
|
||||
generate (generator) {
|
||||
this.chunks = {}
|
||||
for (let x = 0; x < this.size; x++) {
|
||||
if (!this.chunks[x]) this.chunks[x] = {}
|
||||
for (let z = 0; z < this.size; z++) {
|
||||
if (!this.chunks[x][z]) this.chunks[x][z] = {}
|
||||
for (let y = 0; y < this.size; y++) {
|
||||
if (this.chunks[x][z][y]) continue
|
||||
let chunk = new VoxelChunk(this.pos, [x, y, z], this.chunkSize)
|
||||
this.chunks[x][z][y] = chunk
|
||||
this.addChild(chunk)
|
||||
generator.pushChunk(chunk)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
destroy (gl) {
|
||||
this.generated = false
|
||||
for (let i in this.children) {
|
||||
let ch = this.children[i]
|
||||
if (!(ch instanceof VoxelChunk)) continue
|
||||
ch.destroy(gl)
|
||||
}
|
||||
this.children = []
|
||||
this.chunks = {}
|
||||
}
|
||||
|
||||
update (gl, dt) {
|
||||
if (!this.generated) return
|
||||
for (let i in this.children) {
|
||||
let ch = this.children[i]
|
||||
if (!(ch instanceof VoxelChunk)) continue
|
||||
if (ch.update(gl, dt)) break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class VoxelGenerator {
|
||||
constructor (noise, material, groundHeight = 64) {
|
||||
this.material = material
|
||||
this.noise = noise
|
||||
this.groundHeight = groundHeight
|
||||
this.generateQueue = []
|
||||
}
|
||||
|
||||
// Push a chunk into the generation queue
|
||||
pushChunk (chunk) {
|
||||
this.generateQueue.push(chunk)
|
||||
}
|
||||
|
||||
// Get chunk height
|
||||
getHeight (x, z) {
|
||||
return this.noise.getHeight(x, z) + this.groundHeight
|
||||
}
|
||||
|
||||
// Generate chunks in the queue
|
||||
update (dt) {
|
||||
for (let i in this.generateQueue) {
|
||||
let chunk = this.generateQueue[i]
|
||||
if (chunk.generated) continue
|
||||
|
||||
chunk.material = this.material
|
||||
chunk.generate(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { VoxelGenerator, Voxel, VoxelChunk, VoxelMapBlock }
|
||||
|
13
src/index.js
13
src/index.js
@ -13,7 +13,7 @@ import { SimplexHeightMap } from './engine/components/terrain/heightmap'
|
||||
import { Material, Texture } from './engine/mesh/material'
|
||||
import { GUIRenderer, GUIImage, Dim4 } from './engine/gui'
|
||||
import { FontRenderer, GUIText, Font } from './engine/gui/font'
|
||||
import { VoxelChunk } from './engine/voxel'
|
||||
import { VoxelMapBlock, VoxelGenerator } from './engine/voxel'
|
||||
|
||||
let game = Engine
|
||||
let env = new Environment()
|
||||
@ -87,9 +87,9 @@ async function pipeline () {
|
||||
await skybox.initialize(game.gl)
|
||||
|
||||
// Voxel test
|
||||
let chunk = new VoxelChunk([0.0, 0.0, 0.0])
|
||||
chunk.generate(hmap)
|
||||
chunk.material = material
|
||||
let voxgen = new VoxelGenerator(hmap, material)
|
||||
let block = new VoxelMapBlock([0.0, 0.0, 0.0])
|
||||
block.generate(voxgen)
|
||||
|
||||
// Update function for camera and terrain
|
||||
let fpsTimer = 0
|
||||
@ -132,7 +132,8 @@ async function pipeline () {
|
||||
// waterRenderer.update(dt)
|
||||
|
||||
// Update voxel chunk
|
||||
chunk.update(game.gl, dt)
|
||||
voxgen.update(dt)
|
||||
block.update(game.gl, dt)
|
||||
|
||||
// Set text to FPS
|
||||
fpsTimer++
|
||||
@ -160,7 +161,7 @@ async function pipeline () {
|
||||
|
||||
// entity.draw(gl, terrainShader)
|
||||
|
||||
chunk.draw(gl, terrainShader)
|
||||
block.draw(gl, terrainShader)
|
||||
}
|
||||
|
||||
// Render function for the triangle
|
||||
|
Loading…
Reference in New Issue
Block a user