mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Decoupled Chunk data loading/generation and geometry generation
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
using GlitchyEngine.Math;
|
|
||||||
using GlitchyEngine;
|
using GlitchyEngine;
|
||||||
|
using GlitchyEngine.Math;
|
||||||
|
|
||||||
namespace Sandbox.VoxelFun
|
namespace Sandbox.VoxelFun
|
||||||
{
|
{
|
||||||
class Block
|
class Block
|
||||||
@@ -34,7 +35,7 @@ namespace Sandbox.VoxelFun
|
|||||||
*/
|
*/
|
||||||
public virtual void OnPlacing(Int32_3 blockCoordinate)
|
public virtual void OnPlacing(Int32_3 blockCoordinate)
|
||||||
{
|
{
|
||||||
Log.ClientLogger.Info($"I broke. {{{blockCoordinate}}}");
|
Log.ClientLogger.Info($"I live! {{{blockCoordinate}}}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ namespace Sandbox.VoxelFun
|
|||||||
private bool _isDirty;
|
private bool _isDirty;
|
||||||
private bool _isGeometryDirty;
|
private bool _isGeometryDirty;
|
||||||
|
|
||||||
|
/// Neighbors that will trigger a regeneration of this chunks geometry
|
||||||
|
public BlockFace _reqiredNeighbors;
|
||||||
|
|
||||||
public bool IsDirty => _isDirty;
|
public bool IsDirty => _isDirty;
|
||||||
|
|
||||||
public bool IsGeometryDirty
|
public bool IsGeometryDirty
|
||||||
@@ -196,7 +199,7 @@ namespace Sandbox.VoxelFun
|
|||||||
SaveChunkToFile(chunk);
|
SaveChunkToFile(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
GenChunkGeo(chunk);
|
chunk.IsGeometryDirty = true;
|
||||||
|
|
||||||
using(chunkListLock.Enter())
|
using(chunkListLock.Enter())
|
||||||
{
|
{
|
||||||
@@ -212,10 +215,7 @@ namespace Sandbox.VoxelFun
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Raise chunk loaded event (this will wake up all calls of LoadChunk waiting for our chunk)
|
// Raise chunk loaded event (this will wake up all calls of LoadChunk waiting for our chunk)
|
||||||
using(_chunkLoadedLock.Enter())
|
OnChunkLoaded(chunkCoordinate);
|
||||||
{
|
|
||||||
_chunkLoaded.Invoke(chunkCoordinate);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if(!noBlocking)
|
else if(!noBlocking)
|
||||||
{
|
{
|
||||||
@@ -256,6 +256,59 @@ namespace Sandbox.VoxelFun
|
|||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OnChunkLoaded(Int32_3 chunkCoordinate)
|
||||||
|
{
|
||||||
|
// Raise chunk loaded event (this will wake up all calls of LoadChunk waiting for our chunk)
|
||||||
|
using(_chunkLoadedLock.Enter())
|
||||||
|
{
|
||||||
|
_chunkLoaded.Invoke(chunkCoordinate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Left
|
||||||
|
{
|
||||||
|
var chunkCoordinate;
|
||||||
|
|
||||||
|
chunkCoordinate.X--;
|
||||||
|
Chunk neighbor = GetChunk(chunkCoordinate);
|
||||||
|
|
||||||
|
if(neighbor != null && neighbor._reqiredNeighbors.HasFlag(.Right))
|
||||||
|
neighbor.IsGeometryDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right
|
||||||
|
{
|
||||||
|
var chunkCoordinate;
|
||||||
|
|
||||||
|
chunkCoordinate.X++;
|
||||||
|
Chunk neighbor = GetChunk(chunkCoordinate);
|
||||||
|
|
||||||
|
if(neighbor != null && neighbor._reqiredNeighbors.HasFlag(.Left))
|
||||||
|
neighbor.IsGeometryDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Back
|
||||||
|
{
|
||||||
|
var chunkCoordinate;
|
||||||
|
|
||||||
|
chunkCoordinate.Z--;
|
||||||
|
Chunk neighbor = GetChunk(chunkCoordinate);
|
||||||
|
|
||||||
|
if(neighbor != null && neighbor._reqiredNeighbors.HasFlag(.Front))
|
||||||
|
neighbor.IsGeometryDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Front
|
||||||
|
{
|
||||||
|
var chunkCoordinate;
|
||||||
|
|
||||||
|
chunkCoordinate.Z++;
|
||||||
|
Chunk neighbor = GetChunk(chunkCoordinate);
|
||||||
|
|
||||||
|
if(neighbor != null && neighbor._reqiredNeighbors.HasFlag(.Back))
|
||||||
|
neighbor.IsGeometryDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SetChunkPos(Int32_3 chunkPos)
|
void SetChunkPos(Int32_3 chunkPos)
|
||||||
{
|
{
|
||||||
chunkPosLock.Enter();
|
chunkPosLock.Enter();
|
||||||
@@ -543,7 +596,7 @@ namespace Sandbox.VoxelFun
|
|||||||
{
|
{
|
||||||
var oldGeometry = chunk.Geometry;
|
var oldGeometry = chunk.Geometry;
|
||||||
|
|
||||||
var newGeometry = voxelGeoGen.GenerateGeometry(chunk.Data);
|
var newGeometry = voxelGeoGen.GenerateGeometry(chunk);
|
||||||
|
|
||||||
Interlocked.Store(ref chunk.Geometry, newGeometry);
|
Interlocked.Store(ref chunk.Geometry, newGeometry);
|
||||||
chunk.IsGeometryDirty = false;
|
chunk.IsGeometryDirty = false;
|
||||||
@@ -559,11 +612,12 @@ namespace Sandbox.VoxelFun
|
|||||||
Chunk chunk = pair.value;
|
Chunk chunk = pair.value;
|
||||||
|
|
||||||
GeometryBinding chunkGeo = Interlocked.Load(ref chunk.Geometry);
|
GeometryBinding chunkGeo = Interlocked.Load(ref chunk.Geometry);
|
||||||
chunkGeo.AddRef();
|
|
||||||
|
|
||||||
if(chunkGeo == null)
|
if(chunkGeo == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
chunkGeo.AddRef();
|
||||||
|
|
||||||
Texture.Bind();
|
Texture.Bind();
|
||||||
|
|
||||||
Renderer.Submit(chunk.Geometry, TextureEffect, chunk.Transform);
|
Renderer.Submit(chunk.Geometry, TextureEffect, chunk.Transform);
|
||||||
|
|||||||
@@ -47,15 +47,69 @@ namespace Sandbox.VoxelFun
|
|||||||
public GraphicsContext Context;
|
public GraphicsContext Context;
|
||||||
public VertexLayout Layout;
|
public VertexLayout Layout;
|
||||||
|
|
||||||
BlockFace GetVisibleFaces(VoxelChunk chunk, int x, int y, int z)
|
BlockFace GetVisibleFaces(VoxelChunk chunk, int x, int y, int z, Chunk[3][3] chunks)
|
||||||
{
|
{
|
||||||
BlockFace visibleFaces = .None;
|
BlockFace visibleFaces = .None;
|
||||||
|
|
||||||
if(z == 0 || chunk.Data[x][y][z - 1].VisibleNeighbors.HasFlag(.Front))
|
|
||||||
visibleFaces |= .Back;
|
|
||||||
if(z == VoxelChunk.SizeZ - 1 || chunk.Data[x][y][z + 1].VisibleNeighbors.HasFlag(.Back))
|
|
||||||
visibleFaces |= .Front;
|
|
||||||
|
|
||||||
|
// Back
|
||||||
|
int idx = z;
|
||||||
|
Chunk readChunk = chunks[1][1];
|
||||||
|
|
||||||
|
if(idx == 0)
|
||||||
|
{
|
||||||
|
readChunk = chunks[1][0];
|
||||||
|
idx = VoxelChunk.Size.Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(readChunk == null || readChunk.Data.Data[x][y][idx - 1].VisibleNeighbors.HasFlag(.Front))
|
||||||
|
visibleFaces |= .Back;
|
||||||
|
|
||||||
|
// Front
|
||||||
|
idx = z + 1;
|
||||||
|
readChunk = chunks[1][1];
|
||||||
|
|
||||||
|
if(idx == VoxelChunk.Size.Z)
|
||||||
|
{
|
||||||
|
readChunk = chunks[1][2];
|
||||||
|
idx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(readChunk == null || readChunk.Data.Data[x][y][idx].VisibleNeighbors.HasFlag(.Back))
|
||||||
|
visibleFaces |= .Front;
|
||||||
|
|
||||||
|
// Left
|
||||||
|
idx = x;
|
||||||
|
readChunk = chunks[1][1];
|
||||||
|
|
||||||
|
if(idx == 0)
|
||||||
|
{
|
||||||
|
readChunk = chunks[0][1];
|
||||||
|
idx = VoxelChunk.Size.X;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(readChunk == null || readChunk.Data.Data[idx - 1][y][z].VisibleNeighbors.HasFlag(.Right))
|
||||||
|
visibleFaces |= .Left;
|
||||||
|
|
||||||
|
// Right
|
||||||
|
idx = x + 1;
|
||||||
|
readChunk = chunks[1][1];
|
||||||
|
|
||||||
|
if(idx == VoxelChunk.Size.X)
|
||||||
|
{
|
||||||
|
readChunk = chunks[2][1];
|
||||||
|
idx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(readChunk == null || readChunk.Data.Data[idx][y][z].VisibleNeighbors.HasFlag(.Left))
|
||||||
|
visibleFaces |= .Right;
|
||||||
|
|
||||||
|
// TODO: implement for top and bottom as we have 3D chunks
|
||||||
|
if(y == 0 || chunk.Data[x][y - 1][z].VisibleNeighbors.HasFlag(.Top))
|
||||||
|
visibleFaces |= .Bottom;
|
||||||
|
if(y == VoxelChunk.SizeY - 1 || chunk.Data[x][y + 1][z].VisibleNeighbors.HasFlag(.Bottom))
|
||||||
|
visibleFaces |= .Top;
|
||||||
|
|
||||||
|
/*
|
||||||
if(x == 0 || chunk.Data[x - 1][y][z].VisibleNeighbors.HasFlag(.Right))
|
if(x == 0 || chunk.Data[x - 1][y][z].VisibleNeighbors.HasFlag(.Right))
|
||||||
visibleFaces |= .Left;
|
visibleFaces |= .Left;
|
||||||
if(x == VoxelChunk.SizeX - 1 || chunk.Data[x + 1][y][z].VisibleNeighbors.HasFlag(.Left))
|
if(x == VoxelChunk.SizeX - 1 || chunk.Data[x + 1][y][z].VisibleNeighbors.HasFlag(.Left))
|
||||||
@@ -65,11 +119,11 @@ namespace Sandbox.VoxelFun
|
|||||||
visibleFaces |= .Bottom;
|
visibleFaces |= .Bottom;
|
||||||
if(y == VoxelChunk.SizeY - 1 || chunk.Data[x][y + 1][z].VisibleNeighbors.HasFlag(.Bottom))
|
if(y == VoxelChunk.SizeY - 1 || chunk.Data[x][y + 1][z].VisibleNeighbors.HasFlag(.Bottom))
|
||||||
visibleFaces |= .Top;
|
visibleFaces |= .Top;
|
||||||
|
*/
|
||||||
return visibleFaces;
|
return visibleFaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GeometryBinding GenerateGeometry(VoxelChunk chunk)
|
public GeometryBinding GenerateGeometry(Chunk chunk)
|
||||||
{
|
{
|
||||||
List<VertexColorTexture> vertices = scope List<VertexColorTexture>();
|
List<VertexColorTexture> vertices = scope List<VertexColorTexture>();
|
||||||
List<uint32> indices = scope List<uint32>();
|
List<uint32> indices = scope List<uint32>();
|
||||||
@@ -77,17 +131,64 @@ namespace Sandbox.VoxelFun
|
|||||||
|
|
||||||
Stopwatch sw = .StartNew();
|
Stopwatch sw = .StartNew();
|
||||||
|
|
||||||
for(int x < VoxelChunk.SizeX)
|
var chunkData = chunk.Data.Data;
|
||||||
|
|
||||||
|
Chunk[3][3] chunks;
|
||||||
|
|
||||||
|
var coord = chunk.Coordinate;
|
||||||
|
|
||||||
|
// left
|
||||||
|
coord.X -= 1;
|
||||||
|
chunks[0][1] = chunk.ChunkManager.GetChunk(coord);
|
||||||
|
if(chunks[0][1] == null)
|
||||||
|
{
|
||||||
|
// TODO: register reload when neighbor generated
|
||||||
|
chunk._reqiredNeighbors |= .Left;
|
||||||
|
}
|
||||||
|
|
||||||
|
// back
|
||||||
|
coord.X += 1;
|
||||||
|
coord.Z -= 1;
|
||||||
|
chunks[1][0] = chunk.ChunkManager.GetChunk(coord);
|
||||||
|
if(chunks[1][0] == null)
|
||||||
|
{
|
||||||
|
// TODO: register reload when neighbor generated
|
||||||
|
chunk._reqiredNeighbors |= .Back;
|
||||||
|
}
|
||||||
|
|
||||||
|
// center
|
||||||
|
chunks[1][1] = chunk;
|
||||||
|
|
||||||
|
// front
|
||||||
|
coord.Z += 2;
|
||||||
|
chunks[1][2] = chunk.ChunkManager.GetChunk(coord);
|
||||||
|
if(chunks[1][2] == null)
|
||||||
|
{
|
||||||
|
// TODO: register reload when neighbor generated
|
||||||
|
chunk._reqiredNeighbors |= .Front;
|
||||||
|
}
|
||||||
|
|
||||||
|
// right
|
||||||
|
coord.X += 1;
|
||||||
|
coord.Z -= 1;
|
||||||
|
chunks[2][1] = chunk.ChunkManager.GetChunk(coord);
|
||||||
|
if(chunks[2][1] == null)
|
||||||
|
{
|
||||||
|
// TODO: register reload when neighbor generated
|
||||||
|
chunk._reqiredNeighbors |= .Right;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int x < VoxelChunk.SizeX)
|
||||||
for(int y < VoxelChunk.SizeY)
|
for(int y < VoxelChunk.SizeY)
|
||||||
for(int z < VoxelChunk.SizeZ)
|
for(int z < VoxelChunk.SizeZ)
|
||||||
{
|
{
|
||||||
Block block = chunk.Data[x][y][z];
|
Block block = chunkData[x][y][z];
|
||||||
|
|
||||||
Vector3 blockPos = .(x, y, z);
|
Vector3 blockPos = .(x, y, z);
|
||||||
|
|
||||||
if(block != Blocks.Air)
|
if(block != Blocks.Air)
|
||||||
{
|
{
|
||||||
BlockFace visibleFaces = GetVisibleFaces(chunk, x, y, z);
|
BlockFace visibleFaces = GetVisibleFaces(chunk.Data, x, y, z, chunks);
|
||||||
|
|
||||||
if(visibleFaces != .None)
|
if(visibleFaces != .None)
|
||||||
block.Model.GenerateGeometry(block, blockPos, visibleFaces, vertices, indices, ref lastIndex);
|
block.Model.GenerateGeometry(block, blockPos, visibleFaces, vertices, indices, ref lastIndex);
|
||||||
|
|||||||
@@ -408,6 +408,9 @@ namespace Sandbox.VoxelFun
|
|||||||
|
|
||||||
if(intersectInfo.Face != .None)
|
if(intersectInfo.Face != .None)
|
||||||
{
|
{
|
||||||
|
if(rightHandBlock == null)
|
||||||
|
rightHandBlock = Blocks.Stone;
|
||||||
|
|
||||||
if(Input.IsMouseButtonPressing(.LeftButton))
|
if(Input.IsMouseButtonPressing(.LeftButton))
|
||||||
{
|
{
|
||||||
_world.BreakBlock(intersectInfo.Coordinate);
|
_world.BreakBlock(intersectInfo.Coordinate);
|
||||||
@@ -427,7 +430,7 @@ namespace Sandbox.VoxelFun
|
|||||||
Renderer.EndScene();
|
Renderer.EndScene();
|
||||||
}
|
}
|
||||||
|
|
||||||
Block rightHandBlock = Blocks.Stone;
|
Block rightHandBlock;
|
||||||
|
|
||||||
struct IntersectionInfo
|
struct IntersectionInfo
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -317,6 +317,8 @@ namespace Sandbox.VoxelFun
|
|||||||
block.OnBreaking(blockCoordinate);
|
block.OnBreaking(blockCoordinate);
|
||||||
|
|
||||||
chunk.SetBlock(coordInChunk, Blocks.Air);
|
chunk.SetBlock(coordInChunk, Blocks.Air);
|
||||||
|
|
||||||
|
MarkNeighborGeometryDirty(chunkCoordinate, coordInChunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -336,6 +338,8 @@ namespace Sandbox.VoxelFun
|
|||||||
block.OnPlacing(blockCoordinate);
|
block.OnPlacing(blockCoordinate);
|
||||||
|
|
||||||
chunk.SetBlock(coordInChunk, block);
|
chunk.SetBlock(coordInChunk, block);
|
||||||
|
|
||||||
|
MarkNeighborGeometryDirty(chunkCoordinate, coordInChunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -379,6 +383,43 @@ namespace Sandbox.VoxelFun
|
|||||||
Int32_3 coordInChunk = BlockCoordInChunk(blockCoordinate);
|
Int32_3 coordInChunk = BlockCoordInChunk(blockCoordinate);
|
||||||
|
|
||||||
chunk.SetBlock(coordInChunk, block);
|
chunk.SetBlock(coordInChunk, block);
|
||||||
|
|
||||||
|
MarkNeighborGeometryDirty(chunkCoordinate, coordInChunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MarkNeighborGeometryDirty(Int32_3 chunkCoordinate, Int32_3 coordInChunk)
|
||||||
|
{
|
||||||
|
var chunkCoordinate;
|
||||||
|
|
||||||
|
Chunk chunk;
|
||||||
|
|
||||||
|
// if we are on a chunk border mark the neighbor as dirty
|
||||||
|
|
||||||
|
if(coordInChunk.X == 0)
|
||||||
|
{
|
||||||
|
chunkCoordinate.X--;
|
||||||
|
chunk = _chunkManager.GetChunk(chunkCoordinate);
|
||||||
|
chunk?.IsGeometryDirty = true;
|
||||||
|
}
|
||||||
|
else if(coordInChunk.X == VoxelChunk.Size.X - 1)
|
||||||
|
{
|
||||||
|
chunkCoordinate.X++;
|
||||||
|
chunk = _chunkManager.GetChunk(chunkCoordinate);
|
||||||
|
chunk?.IsGeometryDirty = true;
|
||||||
|
}
|
||||||
|
// TODO: implement Y
|
||||||
|
else if(coordInChunk.Z == 0)
|
||||||
|
{
|
||||||
|
chunkCoordinate.Z--;
|
||||||
|
chunk = _chunkManager.GetChunk(chunkCoordinate);
|
||||||
|
chunk?.IsGeometryDirty = true;
|
||||||
|
}
|
||||||
|
else if(coordInChunk.Z == VoxelChunk.Size.Z - 1)
|
||||||
|
{
|
||||||
|
chunkCoordinate.Z++;
|
||||||
|
chunk = _chunkManager.GetChunk(chunkCoordinate);
|
||||||
|
chunk?.IsGeometryDirty = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user