Add a World that stores chunks in a Dictionary keyed by chunk coordinate, with floor-division world<->chunk coordinate mapping (correct for negative coords). The mesher takes an optional neighbor sampler so faces at chunk borders are culled against adjacent chunks instead of always meshing the shell. Render one ChunkRenderer per chunk, placed via the model matrix. Reorganize the World layer into Blocks/ and Chunk/ sub-namespaces.
62 lines
1.8 KiB
C#
62 lines
1.8 KiB
C#
using VoxelEngine.World;
|
|
using VoxelEngine.World.Blocks;
|
|
using VoxelEngine.World.Chunk;
|
|
using Xunit;
|
|
|
|
namespace VoxelEngine.Tests;
|
|
|
|
public class ChunkMesherTests
|
|
{
|
|
private const int FloatsPerVertex = 6; // pos.xyz, uv, shade
|
|
private const int VerticesPerFace = 6; // quad = 2 triangles
|
|
private const int FloatsPerFace = FloatsPerVertex * VerticesPerFace; // 36
|
|
|
|
private static int FaceCount(float[] mesh) => mesh.Length / FloatsPerFace;
|
|
|
|
[Fact]
|
|
public void EmptyChunk_ProducesNoFaces()
|
|
{
|
|
var mesh = new ChunkMesher().Build(new Chunk(), new BlockRegistry());
|
|
Assert.Empty(mesh);
|
|
}
|
|
|
|
[Fact]
|
|
public void SingleBlockSurroundedByAir_Produces6Faces()
|
|
{
|
|
var chunk = new Chunk();
|
|
chunk[8, 8, 8] = 1; // stone
|
|
|
|
var mesh = new ChunkMesher().Build(chunk, new BlockRegistry());
|
|
|
|
Assert.Equal(6, FaceCount(mesh));
|
|
}
|
|
|
|
[Fact]
|
|
public void FullySolidChunk_ProducesOnlyOuterShell()
|
|
{
|
|
var chunk = new Chunk();
|
|
for (int x = 0; x < Chunk.Size; x++)
|
|
for (int y = 0; y < Chunk.Size; y++)
|
|
for (int z = 0; z < Chunk.Size; z++)
|
|
chunk[x, y, z] = 1; // stone
|
|
|
|
var mesh = new ChunkMesher().Build(chunk, new BlockRegistry());
|
|
|
|
// 6 sides * 16 * 16 visible faces
|
|
Assert.Equal(6 * Chunk.Size * Chunk.Size, FaceCount(mesh));
|
|
}
|
|
|
|
[Fact]
|
|
public void SingleBlock_EmitsExactInterleavedFloatCount()
|
|
{
|
|
var chunk = new Chunk();
|
|
chunk[0, 0, 0] = 1; // corner block: all 6 neighbors are air/out-of-bounds -> 6 faces
|
|
|
|
var mesh = new ChunkMesher().Build(chunk, new BlockRegistry());
|
|
|
|
// Pins the layout: 6 faces * 6 vertices/face * 6 floats/vertex.
|
|
Assert.Equal(6 * VerticesPerFace * FloatsPerVertex, mesh.Length);
|
|
Assert.Equal(0, mesh.Length % FloatsPerVertex);
|
|
}
|
|
}
|