private bool IsNeighborEmpty( ChunkPaletteStorage <Block>[,,] storages, int x, int y, int z, BlockFacing facing) { var cx = 1; var cy = 1; var cz = 1; switch (facing) { case BlockFacing.East: x += 1; if (x >= 16) { cx += 1; } break; case BlockFacing.West: x -= 1; if (x < 0) { cx -= 1; } break; case BlockFacing.Up: y += 1; if (y >= 16) { cy += 1; } break; case BlockFacing.Down: y -= 1; if (y < 0) { cy -= 1; } break; case BlockFacing.South: z += 1; if (z >= 16) { cz += 1; } break; case BlockFacing.North: z -= 1; if (z < 0) { cz -= 1; } break; } return(storages[cx, cy, cz]?[x & 0b1111, y & 0b1111, z & 0b1111].Prototype.IsNone ?? true);
public Mesh?Generate(ChunkPos chunkPos) { var storages = new ChunkPaletteStorage <Block> [3, 3, 3]; foreach (var(x, y, z) in Neighbors.ALL.Prepend(Neighbor.None)) { if (_chunkStore.TryGetEntityID(chunkPos.Add(x, y, z), out var neighborID)) { if (_storageStore.TryGet(neighborID, out var storage)) { storages[x + 1, y + 1, z + 1] = storage; } } } var centerStorage = storages[1, 1, 1]; var indexCount = 0; var vertexCount = 0; for (var x = 0; x < 16; x++) { for (var y = 0; y < 16; y++) { for (var z = 0; z < 16; z++) { var block = centerStorage[x, y, z]; if (block.Prototype.IsNone) { continue; } var blockVertex = new Vector3(x, y, z); var textureCell = _textureCellStore.Get(block.Prototype.ID); foreach (var facing in BlockFacings.ALL) { if (!IsNeighborEmpty(storages, x, y, z, facing)) { continue; } if (_indices.Length <= indexCount + 6) { Array.Resize(ref _indices, _indices.Length << 1); } if (_vertices.Length <= vertexCount + 4) { Array.Resize(ref _vertices, _vertices.Length << 1); Array.Resize(ref _normals, _vertices.Length << 1); Array.Resize(ref _uvs, _vertices.Length << 1); } for (var i = 0; i < TRIANGLE_INDICES.Length; i++) { _indices[indexCount++] = (ushort)(vertexCount + TRIANGLE_INDICES[i]); } var normal = facing.ToVector3(); for (var i = 0; i < 4; i++) { var offset = OFFSET_PER_FACING[(int)facing][i]; _vertices[vertexCount] = blockVertex + offset; _normals[vertexCount] = normal; _uvs[vertexCount] = i switch { 0 => textureCell.TopLeft, 1 => textureCell.BottomLeft, 2 => textureCell.BottomRight, 3 => textureCell.TopRight, _ => throw new InvalidOperationException() }; vertexCount++; } } } } } return((indexCount > 0) ? _meshManager.Create( _indices.AsSpan(0, indexCount), _vertices.AsSpan(0, vertexCount), _normals.AsSpan(0, vertexCount), _uvs.AsSpan(0, vertexCount)) : (Mesh?)null); }
protected override void OnLoad() { base.OnLoad(); var(mainCamera, _) = GetAll <Camera>().First(); Set(mainCamera, (Transform)Matrix4x4.CreateTranslation(0, 26, 0)); var meshManager = Processors.GetOrThrow <MeshManager>(); var heartMesh = meshManager.Load(this, "heart.glb"); var swordMesh = meshManager.Load(this, "sword.glb"); for (var x = -12; x <= 12; x++) { for (var z = -12; z <= 12; z++) { var entity = Entities.New(); var position = Matrix4x4.CreateTranslation(x * 2, 24, z * 2); var rotation = Matrix4x4.CreateRotationY(RND.NextFloat(MathF.PI * 2)); Set(entity, (Transform)(rotation * position)); Set(entity, RND.Pick(heartMesh, swordMesh)); } } var textureManager = Processors.GetOrThrow <TextureManager>(); var texture = textureManager.Load(this, "terrain.png"); var stone = Entities.New(); var dirt = Entities.New(); var grass = Entities.New(); Set(stone, TextureCoords4.FromGrid(4, 4, 1, 0)); Set(dirt, TextureCoords4.FromGrid(4, 4, 2, 0)); Set(grass, TextureCoords4.FromGrid(4, 4, 3, 0)); void CreateChunk(ChunkPos pos) { var chunk = Entities.New(); var storage = new ChunkPaletteStorage <Block>(default(Block)); for (var x = 0; x < 16; x++) { for (var y = 0; y < 16; y++) { for (var z = 0; z < 16; z++) { var yy = (pos.Y << 4) | y; if (RND.NextBool(0.5 - yy / 48.0)) { storage[x, y, z] = new Block((yy > 16) ? grass : (yy > -16) ? dirt : stone); } } } } Set(chunk, new Chunk(pos)); Set(chunk, (Transform)Matrix4x4.CreateTranslation(pos.GetOrigin())); Set(chunk, storage); } var chunkMeshGenerator = new ChunkMeshGenerator(this); var chunkStore = (LookupDictionaryStore <ChunkPos, Chunk>)Components.GetStore <Chunk>(); void GenerateChunkMesh(ChunkPos pos) { var chunk = Entities.GetByID(chunkStore.GetEntityID(pos)) !.Value; var chunkMesh = chunkMeshGenerator.Generate(pos); if (chunkMesh == null) { return; } Set(chunk, chunkMesh.Value); Set(chunk, texture); } for (var x = -6; x < 6; x++) { for (var y = -2; y < 2; y++) { for (var z = -6; z < 6; z++) { CreateChunk(new ChunkPos(x, y, z)); } } } for (var x = -6; x < 6; x++) { for (var y = -2; y < 2; y++) { for (var z = -6; z < 6; z++) { GenerateChunkMesh(new ChunkPos(x, y, z)); } } } }