From 8320689d3e64b037f8e9382d2b0a51f07b2ccf35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20L=C3=BCbe=C3=9F?= Date: Thu, 18 Mar 2021 17:22:41 +0100 Subject: [PATCH] Geometry Generation now in Block --- .../src/Math/SwizzleVectorAttribute.bf | 7 +- Sandbox/src/VoxelFun/Block.bf | 26 +++- Sandbox/src/VoxelFun/BlockModel.bf | 98 +++++++++++++++ Sandbox/src/VoxelFun/Blocks.bf | 16 ++- Sandbox/src/VoxelFun/Models.bf | 27 +++++ .../src/VoxelFun/VoxelGeometryGenerator.bf | 85 +------------ Sandbox/src/VoxelFun/VoxelTestLayer.bf | 35 ++---- Sandbox/src/VoxelFun/World.bf | 112 ++++++++++++++++-- 8 files changed, 280 insertions(+), 126 deletions(-) create mode 100644 Sandbox/src/VoxelFun/BlockModel.bf create mode 100644 Sandbox/src/VoxelFun/Models.bf diff --git a/GlitchyEngine/src/Math/SwizzleVectorAttribute.bf b/GlitchyEngine/src/Math/SwizzleVectorAttribute.bf index 7be1d26..f55ffa9 100644 --- a/GlitchyEngine/src/Math/SwizzleVectorAttribute.bf +++ b/GlitchyEngine/src/Math/SwizzleVectorAttribute.bf @@ -33,8 +33,7 @@ namespace GlitchyEngine.Math [Comptime] public void ApplyToType(Type type) { - // TODO: report bug... sized array not working - String[] componentNames = scope String[]("X", "Y", "Z", "W"); + String[4] componentNames = .("X", "Y", "Z", "W"); for(int swizzleCount = 2; swizzleCount <= 4; swizzleCount++) { @@ -50,7 +49,7 @@ namespace GlitchyEngine.Math { String swizzleName = scope String(swizzleCount); String swizzleConstructor = scope String(swizzleCount * 3); - String setter = scope String(128); + String setter = scope String(); bool setterInvalid = invalidSetter(cmp, swizzleCount); @@ -64,7 +63,7 @@ namespace GlitchyEngine.Math } swizzleConstructor.Append(componentNames[cmp[c]]); - if(!setterInvalid && c < _vectorSize) // + if(!setterInvalid && c < _vectorSize) { setter.AppendF($"\n\t\t{componentNames[cmp[c]]} = value.{componentNames[c]};"); } diff --git a/Sandbox/src/VoxelFun/Block.bf b/Sandbox/src/VoxelFun/Block.bf index 745bd83..9318010 100644 --- a/Sandbox/src/VoxelFun/Block.bf +++ b/Sandbox/src/VoxelFun/Block.bf @@ -1,20 +1,40 @@ using GlitchyEngine.Math; +using GlitchyEngine; namespace Sandbox.VoxelFun { class Block { + private Model _model; + private uint16 _blockID; public uint16 ID => _blockID; - public Color Color {get;} + public Model Model => _model; public BlockFace VisibleNeighbors {get;} - public this(Color color, BlockFace visibleNeighbors = .None) + public this(BlockFace visibleNeighbors = .None) { - Color = color; VisibleNeighbors = visibleNeighbors; } + + /** + * This method will be called when the block is being destroyed by the player. + * @param blockCoordinate The coordinate the block is at. + */ + public virtual void OnBreaking(Int32_3 blockCoordinate) + { + Log.ClientLogger.Info($"I broke. {{{blockCoordinate}}}"); + } + + /** + * This method will be called when the block is being placed by the player. + * @param blockCoordinate The coordinate the block is at. + */ + public virtual void OnPlacing(Int32_3 blockCoordinate) + { + Log.ClientLogger.Info($"I broke. {{{blockCoordinate}}}"); + } } } diff --git a/Sandbox/src/VoxelFun/BlockModel.bf b/Sandbox/src/VoxelFun/BlockModel.bf new file mode 100644 index 0000000..4920205 --- /dev/null +++ b/Sandbox/src/VoxelFun/BlockModel.bf @@ -0,0 +1,98 @@ +using System.Collections; +using GlitchyEngine.Math; +using static Sandbox.VoxelFun.VoxelTestLayer; +namespace Sandbox.VoxelFun +{ + abstract class Model + { + public abstract void GenerateGeometry(Block block, Vector3 blockPosition, BlockFace visibleFaces, List vertices, List indices, ref uint32 lastIndex); + + protected static void AddQuadIndices(ref uint32 lastIndex, List indices) + { + uint32[6] inds; + inds[0] = lastIndex; + inds[1] = lastIndex + 1; + inds[2] = lastIndex + 2; + + inds[3] = lastIndex + 2; + inds[4] = lastIndex + 3; + inds[5] = lastIndex; + + indices.AddRange(inds); + lastIndex += 4; + } + } + + class BlockModel : Model + { + Color _color; + + public this(Color color) + { + _color = color; + } + + public override void GenerateGeometry(Block block, Vector3 blockPosition, BlockFace visibleFaces, List vertices, List indices, ref uint32 lastIndex) + { + if(visibleFaces.HasFlag(.Back)) + { + vertices.Add(VertexColorTexture(blockPosition + .(0, 0, 0), _color, .UnitY)); + vertices.Add(VertexColorTexture(blockPosition + .(1, 0, 0), _color, .One)); + vertices.Add(VertexColorTexture(blockPosition + .(1, 1, 0), _color, .UnitX)); + vertices.Add(VertexColorTexture(blockPosition + .(0, 1, 0), _color, .Zero)); + + AddQuadIndices(ref lastIndex, indices); + } + + if(visibleFaces.HasFlag(.Top)) + { + vertices.Add(VertexColorTexture(blockPosition + .(0, 1, 0), _color, .UnitY)); + vertices.Add(VertexColorTexture(blockPosition + .(1, 1, 0), _color, .One)); + vertices.Add(VertexColorTexture(blockPosition + .(1, 1, 1), _color, .UnitX)); + vertices.Add(VertexColorTexture(blockPosition + .(0, 1, 1), _color, .Zero)); + + AddQuadIndices(ref lastIndex, indices); + } + + if(visibleFaces.HasFlag(.Bottom)) + { + vertices.Add(VertexColorTexture(blockPosition + .(0, 0, 1), _color, .UnitY)); + vertices.Add(VertexColorTexture(blockPosition + .(1, 0, 1), _color, .One)); + vertices.Add(VertexColorTexture(blockPosition + .(1, 0, 0), _color, .UnitX)); + vertices.Add(VertexColorTexture(blockPosition + .(0, 0, 0), _color, .Zero)); + + AddQuadIndices(ref lastIndex, indices); + } + + if(visibleFaces.HasFlag(.Front)) + { + vertices.Add(VertexColorTexture(blockPosition + .(1, 0, 1), _color, .UnitY)); + vertices.Add(VertexColorTexture(blockPosition + .(0, 0, 1), _color, .One)); + vertices.Add(VertexColorTexture(blockPosition + .(0, 1, 1), _color, .UnitX)); + vertices.Add(VertexColorTexture(blockPosition + .(1, 1, 1), _color, .Zero)); + + AddQuadIndices(ref lastIndex, indices); + } + + if(visibleFaces.HasFlag(.Right)) + { + vertices.Add(VertexColorTexture(blockPosition + .(1, 0, 0), _color, .UnitY)); + vertices.Add(VertexColorTexture(blockPosition + .(1, 0, 1), _color, .One)); + vertices.Add(VertexColorTexture(blockPosition + .(1, 1, 1), _color, .UnitX)); + vertices.Add(VertexColorTexture(blockPosition + .(1, 1, 0), _color, .Zero)); + + AddQuadIndices(ref lastIndex, indices); + } + + if(visibleFaces.HasFlag(.Left)) + { + vertices.Add(VertexColorTexture(blockPosition + .(0, 0, 1), _color, .UnitY)); + vertices.Add(VertexColorTexture(blockPosition + .(0, 0, 0), _color, .One)); + vertices.Add(VertexColorTexture(blockPosition + .(0, 1, 0), _color, .UnitX)); + vertices.Add(VertexColorTexture(blockPosition + .(0, 1, 1), _color, .Zero)); + + AddQuadIndices(ref lastIndex, indices); + } + } + } +} diff --git a/Sandbox/src/VoxelFun/Blocks.bf b/Sandbox/src/VoxelFun/Blocks.bf index ab290b8..b9fb06e 100644 --- a/Sandbox/src/VoxelFun/Blocks.bf +++ b/Sandbox/src/VoxelFun/Blocks.bf @@ -8,11 +8,19 @@ namespace Sandbox.VoxelFun 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 Air; - public static Block Stone = RegisterBlock(.. new Block(.Gray)); - public static Block Grass = RegisterBlock(.. new Block(.Green)); - public static Block Dirt = RegisterBlock(.. new Block(.Brown)); + public static Block Stone; + public static Block Grass; + public static Block Dirt; + + public static void Init() + { + Air = RegisterBlock(.. new Block(.All)); + Stone = RegisterBlock(.. new Block()); + Grass = RegisterBlock(.. new Block()); + Dirt = RegisterBlock(.. new Block()); + } private static void RegisterBlock(Block block) { diff --git a/Sandbox/src/VoxelFun/Models.bf b/Sandbox/src/VoxelFun/Models.bf new file mode 100644 index 0000000..b9a36f8 --- /dev/null +++ b/Sandbox/src/VoxelFun/Models.bf @@ -0,0 +1,27 @@ +using System; +using System.Collections; + +namespace Sandbox.VoxelFun +{ + static class Models + { + static List _models = new List() ~ DeleteContainerAndItems!(_); + + public static Model Stone; + public static Model Grass; + public static Model Dirt; + + public static void Init() + { + Stone = RegisterModel(Blocks.Stone, .. new BlockModel(.Gray)); + Grass = RegisterModel(Blocks.Grass, .. new BlockModel(.Green)); + Dirt = RegisterModel(Blocks.Dirt, .. new BlockModel(.Brown)); + } + + public static void RegisterModel(Block block, Model model) + { + _models.Add(model); + block.[Friend]_model = model; + } + } +} diff --git a/Sandbox/src/VoxelFun/VoxelGeometryGenerator.bf b/Sandbox/src/VoxelFun/VoxelGeometryGenerator.bf index bd5e904..adbccb1 100644 --- a/Sandbox/src/VoxelFun/VoxelGeometryGenerator.bf +++ b/Sandbox/src/VoxelFun/VoxelGeometryGenerator.bf @@ -90,7 +90,7 @@ namespace Sandbox.VoxelFun BlockFace visibleFaces = GetVisibleFaces(chunk, x, y, z); if(visibleFaces != .None) - GenerateBlockModel(block, blockPos, visibleFaces, vertices, indices, ref lastIndex); + block.Model.GenerateGeometry(block, blockPos, visibleFaces, vertices, indices, ref lastIndex); } } @@ -126,88 +126,5 @@ namespace Sandbox.VoxelFun return gb; } - - Random r = new Random(1337) ~ delete _; - float f = 0.0f; - - public static void GenerateBlockModel(Block block, Vector3 blockPosition, BlockFace visibleFaces, List vertices, List indices, ref uint32 lastIndex) - { - Color c = block.Color; - - if(visibleFaces.HasFlag(.Back)) - { - vertices.Add(VertexColorTexture(blockPosition + .(0, 0, 0), c, .UnitY)); - vertices.Add(VertexColorTexture(blockPosition + .(1, 0, 0), c, .One)); - vertices.Add(VertexColorTexture(blockPosition + .(1, 1, 0), c, .UnitX)); - vertices.Add(VertexColorTexture(blockPosition + .(0, 1, 0), c, .Zero)); - - AddQuadIndices(ref lastIndex, indices); - } - - if(visibleFaces.HasFlag(.Top)) - { - vertices.Add(VertexColorTexture(blockPosition + .(0, 1, 0), c, .UnitY)); - vertices.Add(VertexColorTexture(blockPosition + .(1, 1, 0), c, .One)); - vertices.Add(VertexColorTexture(blockPosition + .(1, 1, 1), c, .UnitX)); - vertices.Add(VertexColorTexture(blockPosition + .(0, 1, 1), c, .Zero)); - - AddQuadIndices(ref lastIndex, indices); - } - - if(visibleFaces.HasFlag(.Bottom)) - { - vertices.Add(VertexColorTexture(blockPosition + .(0, 0, 1), c, .UnitY)); - vertices.Add(VertexColorTexture(blockPosition + .(1, 0, 1), c, .One)); - vertices.Add(VertexColorTexture(blockPosition + .(1, 0, 0), c, .UnitX)); - vertices.Add(VertexColorTexture(blockPosition + .(0, 0, 0), c, .Zero)); - - AddQuadIndices(ref lastIndex, indices); - } - - if(visibleFaces.HasFlag(.Front)) - { - vertices.Add(VertexColorTexture(blockPosition + .(1, 0, 1), c, .UnitY)); - vertices.Add(VertexColorTexture(blockPosition + .(0, 0, 1), c, .One)); - vertices.Add(VertexColorTexture(blockPosition + .(0, 1, 1), c, .UnitX)); - vertices.Add(VertexColorTexture(blockPosition + .(1, 1, 1), c, .Zero)); - - AddQuadIndices(ref lastIndex, indices); - } - - if(visibleFaces.HasFlag(.Right)) - { - vertices.Add(VertexColorTexture(blockPosition + .(1, 0, 0), c, .UnitY)); - vertices.Add(VertexColorTexture(blockPosition + .(1, 0, 1), c, .One)); - vertices.Add(VertexColorTexture(blockPosition + .(1, 1, 1), c, .UnitX)); - vertices.Add(VertexColorTexture(blockPosition + .(1, 1, 0), c, .Zero)); - - AddQuadIndices(ref lastIndex, indices); - } - - if(visibleFaces.HasFlag(.Left)) - { - vertices.Add(VertexColorTexture(blockPosition + .(0, 0, 1), c, .UnitY)); - vertices.Add(VertexColorTexture(blockPosition + .(0, 0, 0), c, .One)); - vertices.Add(VertexColorTexture(blockPosition + .(0, 1, 0), c, .UnitX)); - vertices.Add(VertexColorTexture(blockPosition + .(0, 1, 1), c, .Zero)); - - AddQuadIndices(ref lastIndex, indices); - } - } - - static void AddQuadIndices(ref uint32 lastIndex, List indices) - { - uint32[6] inds; - inds[0] = lastIndex; - inds[1] = lastIndex + 1; - inds[2] = lastIndex + 2; - - inds[3] = lastIndex + 2; - inds[4] = lastIndex + 3; - inds[5] = lastIndex; - - indices.AddRange(inds); - lastIndex += 4; - } } } diff --git a/Sandbox/src/VoxelFun/VoxelTestLayer.bf b/Sandbox/src/VoxelFun/VoxelTestLayer.bf index d9c6d2e..f4e5ce2 100644 --- a/Sandbox/src/VoxelFun/VoxelTestLayer.bf +++ b/Sandbox/src/VoxelFun/VoxelTestLayer.bf @@ -88,6 +88,9 @@ namespace Sandbox.VoxelFun [AllowAppend] public this() : base("VoxelTest") { + Blocks.Init(); + Models.Init(); + _context = Application.Get().Window.Context..AddRef(); _effectLibrary = new EffectLibrary(_context); @@ -178,7 +181,7 @@ namespace Sandbox.VoxelFun uint32 i = 0; - VoxelGeometryGenerator.GenerateBlockModel(Blocks.Stone, .Zero, .All, vertices, indices, ref i); + (scope BlockModel(.HotPink)).GenerateGeometry(Blocks.Air, .Zero, .All, vertices, indices, ref i); let qvb = new VertexBuffer(_context, typeof(VertexColorTexture), (.)vertices.Count, .Immutable); qvb.SetData(vertices); @@ -406,31 +409,15 @@ namespace Sandbox.VoxelFun { if(Input.IsMouseButtonPressing(.LeftButton)) { - _world.SetBlock(intersectInfo.Coordinate, Blocks.Air); + _world.BreakBlock(intersectInfo.Coordinate); } else if(Input.IsMouseButtonPressing(.RightButton)) { - var newBlockCoord = intersectInfo.Coordinate; - - switch(intersectInfo.Face) - { - case .Front: - newBlockCoord.Z--; - case .Back: - newBlockCoord.Z++; - case .Left: - newBlockCoord.X--; - case .Right: - newBlockCoord.X++; - case .Bottom: - newBlockCoord.Y--; - case .Top: - newBlockCoord.Y++; - default: - Log.ClientLogger.Error("Unknown block face."); - } - - _world.SetBlock(newBlockCoord, Blocks.Stone); + _world.PlaceBlock(intersectInfo.Coordinate, rightHandBlock, intersectInfo.Face); + } + else if(Input.IsMouseButtonPressing(.MiddleButton)) + { + rightHandBlock = _world.GetBlock(intersectInfo.Coordinate); } } @@ -439,6 +426,8 @@ namespace Sandbox.VoxelFun Renderer.EndScene(); } + Block rightHandBlock = Blocks.Stone; + struct IntersectionInfo { public Int32_3 Coordinate; diff --git a/Sandbox/src/VoxelFun/World.bf b/Sandbox/src/VoxelFun/World.bf index 87ec82d..e1d32e1 100644 --- a/Sandbox/src/VoxelFun/World.bf +++ b/Sandbox/src/VoxelFun/World.bf @@ -115,7 +115,7 @@ namespace Sandbox.VoxelFun /** * Returs the coordinate of the chunk that contains the given coordinate. */ - public Vector3 GetChunkCoordinate(Vector3 blockCoordinate) + public static Vector3 GetChunkCoordinate(Vector3 blockCoordinate) { Vector3 chunkPosition = blockCoordinate / VoxelChunk.VectorSize; @@ -125,18 +125,18 @@ namespace Sandbox.VoxelFun /** * Calculates the coordinate of the chunk that contains the given block coordinate. */ - public Int32_3 ChunkCoordFromBlockCoord(Int32_3 blockCoordinate) + public static Int32_3 ChunkCoordFromBlockCoord(Int32_3 blockCoordinate) { Int32_3 coordinate = blockCoordinate; if(coordinate.X < 0) - coordinate.X -= VoxelChunk.Size.X; + coordinate.X -= VoxelChunk.Size.X - 1; if(coordinate.Y < 0) - coordinate.Y -= VoxelChunk.Size.Y; + coordinate.Y -= VoxelChunk.Size.Y - 1; if(coordinate.Z < 0) - coordinate.Z -= VoxelChunk.Size.Z; + coordinate.Z -= VoxelChunk.Size.Z - 1; return coordinate / VoxelChunk.Size; } @@ -146,7 +146,7 @@ namespace Sandbox.VoxelFun * For Example: Consider the block at the global location of (25, 17, -12) * The coordinate of this block inside its chunk would be (9, 17, 4) because the chunk starts at (16, 0, -16) */ - public Int32_3 BlockCoordInChunk(Int32_3 blockCoordinate) + public static Int32_3 BlockCoordInChunk(Int32_3 blockCoordinate) { Int32_3 chunkPosition = blockCoordinate % VoxelChunk.Size; @@ -165,7 +165,7 @@ namespace Sandbox.VoxelFun /** * Returs the coordinate of the block relative to the chunk. */ - public Vector3 GetPositionInChunk(Vector3 position) + public static Vector3 GetPositionInChunk(Vector3 position) { Vector3 chunkPosition = position % VoxelChunk.VectorSize; @@ -300,7 +300,72 @@ namespace Sandbox.VoxelFun intersectionPosition = .(float.NaN); return .(int32.MaxValue, int32.MaxValue, int32.MaxValue); } - + + /** + * Breaks the block at the given coordinates. + */ + public void BreakBlock(Int32_3 blockCoordinate) + { + Int32_3 chunkCoordinate = ChunkCoordFromBlockCoord(blockCoordinate); + + Chunk chunk = _chunkManager.LoadChunk(chunkCoordinate); + + Int32_3 coordInChunk = BlockCoordInChunk(blockCoordinate); + + Block block = chunk.GetBlock(coordInChunk); + + block.OnBreaking(blockCoordinate); + + chunk.SetBlock(coordInChunk, Blocks.Air); + } + + /** + * Places a block at the given coordinates. + */ + public void PlaceBlock(Int32_3 blockCoordinate, Block block) + { + Int32_3 chunkCoordinate = ChunkCoordFromBlockCoord(blockCoordinate); + + Chunk chunk = _chunkManager.LoadChunk(chunkCoordinate); + + Int32_3 coordInChunk = BlockCoordInChunk(blockCoordinate); + + // Todo: we will also be able to place block in fluids and some other blocks. + Log.ClientLogger.AssertDebug(chunk.GetBlock(coordInChunk) == Blocks.Air, "A block can only be placed in air (atm)"); + + block.OnPlacing(blockCoordinate); + + chunk.SetBlock(coordInChunk, block); + } + + /** + * Places a block on the given face of the block at the specified coordinates. + */ + public void PlaceBlock(Int32_3 blockCoordinate, Block block, BlockFace face) + { + var blockCoordinate; + + switch(face) + { + case .Front: + blockCoordinate.Z--; + case .Back: + blockCoordinate.Z++; + case .Left: + blockCoordinate.X--; + case .Right: + blockCoordinate.X++; + case .Bottom: + blockCoordinate.Y--; + case .Top: + blockCoordinate.Y++; + default: + Log.ClientLogger.AssertDebug(false, "Unexpected block face."); + } + + PlaceBlock(blockCoordinate, block); + } + /** * Gets the block at the specified coordinate. * @remarks If the blocks chunk is not loaded it will be loaded from the disk. @@ -330,5 +395,36 @@ namespace Sandbox.VoxelFun return chunk.GetBlock(coordInChunk); } + + [Test] + static void TestWorld() + { + // ChunkCoordFromBlockCoord + { + Int32_3 block = .(0, 0, 0); + Int32_3 expectedChunk = .(0, 0, 0); + Test.Assert(expectedChunk == ChunkCoordFromBlockCoord(block)); + + block = .(5, 0, 0); + expectedChunk = .(0, 0, 0); + Test.Assert(expectedChunk == ChunkCoordFromBlockCoord(block)); + + block = .(45, 80, 12); + expectedChunk = .(2, 0, 0); + Test.Assert(expectedChunk == ChunkCoordFromBlockCoord(block)); + + block = .(0, 0, -1); + expectedChunk = .(0, 0, -1); + Test.Assert(expectedChunk == ChunkCoordFromBlockCoord(block)); + + block = .(0, 0, -16); + expectedChunk = .(0, 0, -1); + Test.Assert(expectedChunk == ChunkCoordFromBlockCoord(block)); + + block = .(0, 0, -17); + expectedChunk = .(0, 0, -2); + Test.Assert(expectedChunk == ChunkCoordFromBlockCoord(block)); + } + } } }