diff --git a/Sandbox/src/VoxelFun/Block.bf b/Sandbox/src/VoxelFun/Block.bf new file mode 100644 index 0000000..745bd83 --- /dev/null +++ b/Sandbox/src/VoxelFun/Block.bf @@ -0,0 +1,20 @@ +using GlitchyEngine.Math; +namespace Sandbox.VoxelFun +{ + class Block + { + private uint16 _blockID; + + public uint16 ID => _blockID; + + public Color Color {get;} + + public BlockFace VisibleNeighbors {get;} + + public this(Color color, BlockFace visibleNeighbors = .None) + { + Color = color; + VisibleNeighbors = visibleNeighbors; + } + } +} diff --git a/Sandbox/src/VoxelFun/Blocks.bf b/Sandbox/src/VoxelFun/Blocks.bf new file mode 100644 index 0000000..ab290b8 --- /dev/null +++ b/Sandbox/src/VoxelFun/Blocks.bf @@ -0,0 +1,29 @@ +using System; +using System.Collections; +namespace Sandbox.VoxelFun +{ + static class Blocks + { + static uint16 _sLastId; + static List _blocks = new List() ~ DeleteContainerAndItems!(_); + + /// Air is a special Block. It defines the absence of a block. + public static Block Air = RegisterBlock(.. new Block(.White, .All)); + + public static Block Stone = RegisterBlock(.. new Block(.Gray)); + public static Block Grass = RegisterBlock(.. new Block(.Green)); + public static Block Dirt = RegisterBlock(.. new Block(.Brown)); + + private static void RegisterBlock(Block block) + { + block.[Friend]_blockID = _sLastId; + _sLastId++; + _blocks.Add(block); + } + + public static Block GetFromId(int id) + { + return _blocks[id]; + } + } +} diff --git a/Sandbox/src/VoxelFun/ChunkManager.bf b/Sandbox/src/VoxelFun/ChunkManager.bf index 4c58ff1..e0a9747 100644 --- a/Sandbox/src/VoxelFun/ChunkManager.bf +++ b/Sandbox/src/VoxelFun/ChunkManager.bf @@ -34,7 +34,7 @@ namespace Sandbox.VoxelFun set => _isGeometryDirty = value; } - public void SetBlock(Int32_3 coordinate, uint8 blockId) + public void SetBlock(Int32_3 coordinate, Block blockId) { Log.EngineLogger.AssertDebug(coordinate.X >= 0 && coordinate.Y >= 0 && coordinate.Z >= 0 && coordinate.X < VoxelChunk.Size.X && coordinate.Y < VoxelChunk.Size.Y && coordinate.Z < VoxelChunk.Size.Z, "Specified coordinate is out of range."); @@ -45,7 +45,7 @@ namespace Sandbox.VoxelFun ChunkManager.[Friend]chunkPosLock.Exit(); } - public uint8 GetBlock(Int32_3 coordinate) + public Block GetBlock(Int32_3 coordinate) { Log.EngineLogger.AssertDebug(coordinate.X >= 0 && coordinate.Y >= 0 && coordinate.Z >= 0 && coordinate.X < VoxelChunk.Size.X && coordinate.Y < VoxelChunk.Size.Y && coordinate.Z < VoxelChunk.Size.Z, "Specified coordinate is out of range."); @@ -54,7 +54,15 @@ namespace Sandbox.VoxelFun public void Serialize(Stream stream) { - stream.Write(Data); + uint16[VoxelChunk.SizeX][VoxelChunk.SizeY][VoxelChunk.SizeZ] rawData = ?; + + for(int x = 0; x < VoxelChunk.SizeX; x++) + for(int y = 0; y < VoxelChunk.SizeY; y++) + for(int z = 0; z < VoxelChunk.SizeZ; z++) + { + rawData[x][y][z] = Data.Data[x][y][z].ID; + } + stream.Write(rawData); _isDirty = false; } } @@ -361,15 +369,24 @@ namespace Sandbox.VoxelFun if(!File.Exists(chunkFileName)) return .Err; + + uint16[VoxelChunk.SizeX][VoxelChunk.SizeY][VoxelChunk.SizeZ] rawData; FileStream fs = scope FileStream(); fs.Open(chunkFileName, .Read, .Read); - outChunk.Data = fs.Read(); + rawData = fs.Read(); fs.Close(); + for(int x = 0; x < VoxelChunk.SizeX; x++) + for(int y = 0; y < VoxelChunk.SizeY; y++) + for(int z = 0; z < VoxelChunk.SizeZ; z++) + { + outChunk.Data.Data[x][y][z] = Blocks.GetFromId(rawData[x][y][z]); + } + return .Ok; } @@ -377,7 +394,7 @@ namespace Sandbox.VoxelFun { String chunkFileName = scope String(_chunkBasePath); chunkFileName.AppendF($"{chunk.Coordinate.X}_{chunk.Coordinate.Y}_{chunk.Coordinate.Z}.cdata"); - + FileStream fs = scope FileStream(); fs.Open(chunkFileName, FileMode.Create, .Write); @@ -433,8 +450,9 @@ namespace Sandbox.VoxelFun float gradientValue = cy / (float)(settings.TerrainFloorHeight * 2 - 1); // determine whether or not gradient value is air - uint8 stepValue = gradientValue < 0.5f ? 1 : 0; + Block stepValue = gradientValue < 0.5f ? Blocks.Stone : Blocks.Air; + // Note these objects will be invalid chunk.Data.Data[x][y][z] = stepValue; } @@ -448,7 +466,7 @@ namespace Sandbox.VoxelFun struct GroundLayer { public int Depth; - public uint8 BlockType; + public Block BlockType; } void GroundLayers(Chunk chunk) @@ -457,17 +475,17 @@ namespace Sandbox.VoxelFun layers[0] = .() { Depth = 1, - BlockType = 3 + BlockType = Blocks.Grass }; layers[1] = .() { Depth = 4, - BlockType = 2 + BlockType = Blocks.Dirt }; layers[2] = .() { Depth = 0, - BlockType = 1 + BlockType = Blocks.Stone }; for(int x < VoxelChunk.SizeX) @@ -478,7 +496,7 @@ namespace Sandbox.VoxelFun for(int y = VoxelChunk.SizeY - 1; y > 0; y--) { - if(chunk.Data.Data[x][y][z] == 0) + if(chunk.Data.Data[x][y][z] == Blocks.Air) { currentDepth--; diff --git a/Sandbox/src/VoxelFun/VoxelChunk.bf b/Sandbox/src/VoxelFun/VoxelChunk.bf index ef784ff..a34f57c 100644 --- a/Sandbox/src/VoxelFun/VoxelChunk.bf +++ b/Sandbox/src/VoxelFun/VoxelChunk.bf @@ -11,6 +11,6 @@ namespace Sandbox.VoxelFun public const Int32_3 Size = .(SizeX, SizeY, SizeZ); public const Vector3 VectorSize = .(SizeX, SizeY, SizeZ); - public uint8[SizeX][SizeY][SizeZ] Data; + public Block[SizeX][SizeY][SizeZ] Data; } } diff --git a/Sandbox/src/VoxelFun/VoxelGeometryGenerator.bf b/Sandbox/src/VoxelFun/VoxelGeometryGenerator.bf index bc7a5e1..bd5e904 100644 --- a/Sandbox/src/VoxelFun/VoxelGeometryGenerator.bf +++ b/Sandbox/src/VoxelFun/VoxelGeometryGenerator.bf @@ -47,52 +47,23 @@ namespace Sandbox.VoxelFun public GraphicsContext Context; public VertexLayout Layout; - [Inline] - Color HtoRGB(float h) - { - var h; - h = h % 360.0f; - - float x = (1 - Math.Abs((h / 60.0f) % 2 - 1)); - - Vector3 cStrich; - - if(h < 60) - cStrich = .(1, x, 0); - else if(h < 120) - cStrich = .(x, 1, 0); - else if(h < 180) - cStrich = .(0, 1, x); - else if(h < 240) - cStrich = .(0, x, 1); - else if(h < 300) - cStrich = .(x, 0, 1); - else - cStrich = .(1, 0, x); - - cStrich *= 255.0f; - - return .((uint8)cStrich.X, (uint8)cStrich.Y, (uint8)cStrich.Z); - } - - //[/Inline] BlockFace GetVisibleFaces(VoxelChunk chunk, int x, int y, int z) { BlockFace visibleFaces = .None; - if(z == 0 || chunk.Data[x][y][z - 1] == 0) + 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] == 0) + if(z == VoxelChunk.SizeZ - 1 || chunk.Data[x][y][z + 1].VisibleNeighbors.HasFlag(.Back)) visibleFaces |= .Front; - if(x == 0 || chunk.Data[x - 1][y][z] == 0) + if(x == 0 || chunk.Data[x - 1][y][z].VisibleNeighbors.HasFlag(.Right)) visibleFaces |= .Left; - if(x == VoxelChunk.SizeX - 1 || chunk.Data[x + 1][y][z] == 0) + if(x == VoxelChunk.SizeX - 1 || chunk.Data[x + 1][y][z].VisibleNeighbors.HasFlag(.Left)) visibleFaces |= .Right; - if(y == 0 || chunk.Data[x][y - 1][z] == 0) + 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] == 0) + if(y == VoxelChunk.SizeY - 1 || chunk.Data[x][y + 1][z].VisibleNeighbors.HasFlag(.Bottom)) visibleFaces |= .Top; return visibleFaces; @@ -110,16 +81,16 @@ namespace Sandbox.VoxelFun for(int y < VoxelChunk.SizeY) for(int z < VoxelChunk.SizeZ) { - uint16 blockIndex = chunk.Data[x][y][z]; + Block block = chunk.Data[x][y][z]; Vector3 blockPos = .(x, y, z); - if(blockIndex != 0) + if(block != Blocks.Air) { BlockFace visibleFaces = GetVisibleFaces(chunk, x, y, z); if(visibleFaces != .None) - GenerateBlockModel(blockIndex, blockPos, visibleFaces, vertices, indices, ref lastIndex); + GenerateBlockModel(block, blockPos, visibleFaces, vertices, indices, ref lastIndex); } } @@ -149,7 +120,7 @@ namespace Sandbox.VoxelFun sw.Stop(); - Debug.WriteLine($"Generation: {sw.ElapsedMilliseconds}"); + Debug.WriteLine($"Geometry Generation: {sw.ElapsedMilliseconds}"); delete sw; @@ -159,23 +130,9 @@ namespace Sandbox.VoxelFun Random r = new Random(1337) ~ delete _; float f = 0.0f; - public static void GenerateBlockModel(uint16 blockIndex, Vector3 blockPosition, BlockFace visibleFaces, List vertices, List indices, ref uint32 lastIndex) + public static void GenerateBlockModel(Block block, Vector3 blockPosition, BlockFace visibleFaces, List vertices, List indices, ref uint32 lastIndex) { - Color c = .Pink; - - if(blockIndex == 1) - c = .Gray; - else if(blockIndex == 2) - c = .SaddleBrown; - else if(blockIndex == 3) - c = .Green; - - //Color c = .(blockIndex, blockIndex, blockIndex); - - //c = HtoRGB(f += r.Next(0, 0xBEEF)); - - if(blockPosition.Y == 63) - c = .Red; + Color c = block.Color; if(visibleFaces.HasFlag(.Back)) { diff --git a/Sandbox/src/VoxelFun/VoxelTestLayer.bf b/Sandbox/src/VoxelFun/VoxelTestLayer.bf index 1872acd..d9c6d2e 100644 --- a/Sandbox/src/VoxelFun/VoxelTestLayer.bf +++ b/Sandbox/src/VoxelFun/VoxelTestLayer.bf @@ -63,6 +63,8 @@ namespace Sandbox.VoxelFun RasterizerState _rasterizerState ~ delete _; + EffectLibrary _effectLibrary ~ delete _; + Effect _effect ~ _?.ReleaseRef(); Effect _textureEffect ~ _?.ReleaseRef(); @@ -88,11 +90,13 @@ namespace Sandbox.VoxelFun { _context = Application.Get().Window.Context..AddRef(); + _effectLibrary = new EffectLibrary(_context); + _depthStencilTarget = new DepthStencilTarget(_context, _context.SwapChain.Width, _context.SwapChain.Height); - _effect = new Effect(_context, "content\\Shaders\\basicShader.hlsl"); + _effect = _effectLibrary.Load("content\\Shaders\\basicShader.hlsl"); - _textureEffect = new Effect(_context, "content\\Shaders\\textureShader.hlsl"); + _textureEffect = _effectLibrary.Load("content\\Shaders\\textureShader.hlsl"); // Create Input Layout @@ -174,7 +178,7 @@ namespace Sandbox.VoxelFun uint32 i = 0; - VoxelGeometryGenerator.GenerateBlockModel(0, .Zero, .All, vertices, indices, ref i); + VoxelGeometryGenerator.GenerateBlockModel(Blocks.Stone, .Zero, .All, vertices, indices, ref i); let qvb = new VertexBuffer(_context, typeof(VertexColorTexture), (.)vertices.Count, .Immutable); qvb.SetData(vertices); @@ -402,7 +406,7 @@ namespace Sandbox.VoxelFun { if(Input.IsMouseButtonPressing(.LeftButton)) { - _world.SetBlock(intersectInfo.Coordinate, 0); + _world.SetBlock(intersectInfo.Coordinate, Blocks.Air); } else if(Input.IsMouseButtonPressing(.RightButton)) { @@ -426,7 +430,7 @@ namespace Sandbox.VoxelFun Log.ClientLogger.Error("Unknown block face."); } - _world.SetBlock(newBlockCoord, 1); + _world.SetBlock(newBlockCoord, Blocks.Stone); } } diff --git a/Sandbox/src/VoxelFun/World.bf b/Sandbox/src/VoxelFun/World.bf index 8bd8307..87ec82d 100644 --- a/Sandbox/src/VoxelFun/World.bf +++ b/Sandbox/src/VoxelFun/World.bf @@ -181,6 +181,12 @@ namespace Sandbox.VoxelFun return Vector3.Floor(chunkPosition); } + /* + public struct BlockIntersection + { + Int32_3 BlockCoordinate; + } + */ public Int32_3 RaycastBlock(Ray ray, float maxDistance, GeometryBinding geo, Effect effect, out Vector3 intersectionPosition, out BlockFace intersectionFace) { Vector3 start = ray.Start; @@ -280,9 +286,9 @@ namespace Sandbox.VoxelFun } } - uint8 blockData = [Inline]GetBlock(walker); + Block blockData = [Inline]GetBlock(walker); - if(blockData != 0) + if(blockData != Blocks.Air) { intersectionPosition = start + distance * dir; @@ -299,7 +305,7 @@ namespace Sandbox.VoxelFun * Gets the block at the specified coordinate. * @remarks If the blocks chunk is not loaded it will be loaded from the disk. */ - public void SetBlock(Int32_3 blockCoordinate, uint8 blockId) + public void SetBlock(Int32_3 blockCoordinate, Block block) { Int32_3 chunkCoordinate = ChunkCoordFromBlockCoord(blockCoordinate); @@ -307,14 +313,14 @@ namespace Sandbox.VoxelFun Int32_3 coordInChunk = BlockCoordInChunk(blockCoordinate); - chunk.SetBlock(coordInChunk, blockId); + chunk.SetBlock(coordInChunk, block); } /** * Gets the block at the specified coordinate. * @remarks If the blocks chunk is not loaded it will be loaded from the disk. */ - public uint8 GetBlock(Int32_3 blockCoordinate) + public Block GetBlock(Int32_3 blockCoordinate) { Int32_3 chunkCoordinate = ChunkCoordFromBlockCoord(blockCoordinate);