From cbfbd449ffec16362dc811a56ea8b7303e55ed47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20L=C3=BCbe=C3=9F?= Date: Fri, 26 Feb 2021 10:58:11 +0100 Subject: [PATCH] Start of block raycasting --- GlitchyEngine/src/Math/Ray.bf | 16 ++++ Sandbox/src/VoxelFun/ChunkManager.bf | 93 ++++++++++++++----- Sandbox/src/VoxelFun/VoxelChunk.bf | 2 + .../src/VoxelFun/VoxelGeometryGenerator.bf | 4 +- Sandbox/src/VoxelFun/VoxelTestLayer.bf | 59 +++++++++--- Sandbox/src/VoxelFun/World.bf | 74 +++++++++++++++ 6 files changed, 210 insertions(+), 38 deletions(-) create mode 100644 GlitchyEngine/src/Math/Ray.bf diff --git a/GlitchyEngine/src/Math/Ray.bf b/GlitchyEngine/src/Math/Ray.bf new file mode 100644 index 0000000..d0869e0 --- /dev/null +++ b/GlitchyEngine/src/Math/Ray.bf @@ -0,0 +1,16 @@ +namespace GlitchyEngine.Math +{ + struct Ray + { + public Vector3 Start; + public Vector3 Direction; + + public this() => this = default; + + public this(Vector3 start, Vector3 direction) + { + Start = start; + Direction = direction; + } + } +} diff --git a/Sandbox/src/VoxelFun/ChunkManager.bf b/Sandbox/src/VoxelFun/ChunkManager.bf index 9b8b2a3..b9cc4b3 100644 --- a/Sandbox/src/VoxelFun/ChunkManager.bf +++ b/Sandbox/src/VoxelFun/ChunkManager.bf @@ -23,6 +23,8 @@ namespace Sandbox.VoxelFun { public int X, Y, Z; + public this() => this = default; + public this(int x, int y, int z) { X = x; @@ -47,6 +49,8 @@ namespace Sandbox.VoxelFun public static Point3 operator +(Point3 left, Point3 right) => .(left.X + right.X, left.Y + right.Y, left.Z + right.Z); public static Point3 operator -(Point3 left, Point3 right) => .(left.X - right.X, left.Y - right.Y, left.Z - right.Z); public static Point3 operator *(Point3 left, Point3 right) => .(left.X * right.X, left.Y * right.Y, left.Z * right.Z); + public static Point3 operator /(Point3 left, Point3 right) => .(left.X / right.X, left.Y / right.Y, left.Z / right.Z); + public static Point3 operator %(Point3 left, Point3 right) => .(left.X % right.X, left.Y % right.Y, left.Z % right.Z); public Point3 Abs() { @@ -70,7 +74,7 @@ namespace Sandbox.VoxelFun private String _chunkBasePath ~ delete _; - Dictionary chunks = new .() ~ DeleteDictionaryAndValues!(_); + Dictionary _chunks = new .() ~ DeleteDictionaryAndValues!(_); public Texture2D Texture ~ _?.ReleaseRef(); public Effect TextureEffect ~ _?.ReleaseRef(); @@ -105,7 +109,7 @@ namespace Sandbox.VoxelFun voxelGeoGen.Context = _context; voxelGeoGen.Layout = vertexLayout; - chunkLoader = new Thread(new => ChunkLoaderThread); + chunkLoader = new Thread(new => ChunkLoaderThread_Entry); chunkLoader.Start(); } @@ -116,9 +120,64 @@ namespace Sandbox.VoxelFun chunkLoader.Join(); } + /** + * Returns whether or not the chunk with the given coordinate is currently loaded. + */ + [Inline] + public bool IsChunkLoaded(Point3 chunkCoordinate) + { + using(chunkListLock.Enter()) + { + return _chunks.ContainsKey(chunkCoordinate); + } + } + + /** + * Returns the chunk with the given chunk coordinate or null if the chunk isn't loaded. + */ + [Inline] + public Chunk GetChunk(Point3 chunkCoordinate) + { + using(chunkListLock.Enter()) + { + return _chunks.TryGetValue(chunkCoordinate, let chunk) ? chunk : null; + } + } + + /** + * Loads and returns the chunk with the given coordinate. If the chunk doesn't exist it will be generated. + */ + public Chunk LoadChunk(Point3 chunkCoordinate) + { + Chunk chunk = GetChunk(chunkCoordinate); + + if(chunk == null) + { + chunk = new Chunk(); + chunk.Position = chunkCoordinate * .(VoxelChunk.SizeX, VoxelChunk.SizeY, VoxelChunk.SizeZ); + chunk.Transform = .Translation(chunk.Position.X, chunk.Position.Y, chunk.Position.Z); + + if(LoadChunkFromFile(chunkCoordinate, chunk) case .Err) + { + GenTestChunk(chunk); + SaveChunkToFile(chunkCoordinate, chunk); + } + + GenChunkGeo(chunk); + + using(chunkListLock.Enter()) + { + _chunks.Add(chunkCoordinate, chunk); + } + } + + return chunk; + } + void SetChunkPos(Point3 chunkPos) { chunkPosLock.Enter(); + chunkPosition = chunkPos; if(oldChunkPosition != chunkPosition) @@ -137,7 +196,10 @@ namespace Sandbox.VoxelFun SetChunkPos(p); } - void ChunkLoaderThread() + /** + * Entrypoint for the chunk loader thread. + */ + void ChunkLoaderThread_Entry() { Point3 curChunkPosition = .(0, 0, 0); Point3 oldChunkPosition = .(Int.MaxValue, Int.MaxValue, Int.MaxValue); @@ -163,7 +225,7 @@ namespace Sandbox.VoxelFun public void GenerateChunks(Point3 chunkPos) { - for(var chunk in chunks) + for(var chunk in _chunks) { Point3 dist = (chunk.key - chunkPos).Abs(); @@ -171,7 +233,7 @@ namespace Sandbox.VoxelFun { chunkListLock.Enter(); delete chunk.value; - chunks.Remove(chunk.key); + _chunks.Remove(chunk.key); chunkListLock.Exit(); } } @@ -183,24 +245,7 @@ namespace Sandbox.VoxelFun int y = 0; Point3 chunkCoordinate = (Point3)chunkPos + .(x, y, z); - if(!chunks.ContainsKey(chunkCoordinate)) - { - var chunk = new Chunk(); - chunk.Position = chunkCoordinate * .(VoxelChunk.SizeX, VoxelChunk.SizeY, VoxelChunk.SizeZ); - chunk.Transform = .Translation(chunk.Position.X, chunk.Position.Y, chunk.Position.Z); - - if(LoadChunkFromFile(chunkCoordinate, chunk) case .Err) - { - GenTestChunk(chunk); - SaveChunkToFile(chunkCoordinate, chunk); - } - - GenChunkGeo(chunk); - - chunkListLock.Enter(); - chunks.Add(chunkCoordinate, chunk); - chunkListLock.Exit(); - } + LoadChunk(chunkCoordinate); } } @@ -380,7 +425,7 @@ namespace Sandbox.VoxelFun public void Draw() { chunkListLock.Enter(); - for(let pair in chunks) + for(let pair in _chunks) { Chunk chunk = pair.value; diff --git a/Sandbox/src/VoxelFun/VoxelChunk.bf b/Sandbox/src/VoxelFun/VoxelChunk.bf index 477e115..de924bd 100644 --- a/Sandbox/src/VoxelFun/VoxelChunk.bf +++ b/Sandbox/src/VoxelFun/VoxelChunk.bf @@ -6,6 +6,8 @@ namespace Sandbox.VoxelFun public const int SizeY = 256; public const int SizeZ = 16; + public const Point3 Size = .(SizeX, SizeY, SizeZ); + public uint8[SizeX][SizeY][SizeZ] Data; } } diff --git a/Sandbox/src/VoxelFun/VoxelGeometryGenerator.bf b/Sandbox/src/VoxelFun/VoxelGeometryGenerator.bf index 3f99ca7..bc7a5e1 100644 --- a/Sandbox/src/VoxelFun/VoxelGeometryGenerator.bf +++ b/Sandbox/src/VoxelFun/VoxelGeometryGenerator.bf @@ -159,7 +159,7 @@ namespace Sandbox.VoxelFun Random r = new Random(1337) ~ delete _; float f = 0.0f; - void GenerateBlockModel(uint16 blockIndex, Vector3 blockPosition, BlockFace visibleFaces, List vertices, List indices, ref uint32 lastIndex) + public static void GenerateBlockModel(uint16 blockIndex, Vector3 blockPosition, BlockFace visibleFaces, List vertices, List indices, ref uint32 lastIndex) { Color c = .Pink; @@ -238,7 +238,7 @@ namespace Sandbox.VoxelFun } } - void AddQuadIndices(ref uint32 lastIndex, List indices) + static void AddQuadIndices(ref uint32 lastIndex, List indices) { uint32[6] inds; inds[0] = lastIndex; diff --git a/Sandbox/src/VoxelFun/VoxelTestLayer.bf b/Sandbox/src/VoxelFun/VoxelTestLayer.bf index 1ff3bd2..8bafa6e 100644 --- a/Sandbox/src/VoxelFun/VoxelTestLayer.bf +++ b/Sandbox/src/VoxelFun/VoxelTestLayer.bf @@ -6,6 +6,7 @@ using ImGui; using GlitchyEngine.ImGui; using GlitchyEngine.Events; using System.Diagnostics; +using System.Collections; namespace Sandbox.VoxelFun { @@ -52,7 +53,7 @@ namespace Sandbox.VoxelFun VertexLayout _vertexLayout ~ delete _; - GeometryBinding _chunkGeoBinding ~ _?.ReleaseRef(); + GeometryBinding _cubeGeo ~ _?.ReleaseRef(); GeometryBinding _geometryBinding ~ _?.ReleaseRef(); @@ -73,8 +74,6 @@ namespace Sandbox.VoxelFun DepthStencilTarget _depthStencilTarget ~ _?.ReleaseRef(); - ChunkManager _chunkManager ~ delete _; - World _world ~ delete _; private Vector3 CircleCoord(float angle) @@ -160,6 +159,32 @@ namespace Sandbox.VoxelFun qib.ReleaseRef(); } + // Create Cube + { + _cubeGeo = new GeometryBinding(_context); + _cubeGeo.SetPrimitiveTopology(.TriangleList); + _cubeGeo.SetVertexLayout(_vertexLayout); + + List vertices = new List(); + defer delete vertices; + List indices = new List(); + defer delete indices; + + uint32 i = 0; + + VoxelGeometryGenerator.GenerateBlockModel(0, .Zero, .All, vertices, indices, ref i); + + let qvb = new VertexBuffer(_context, typeof(VertexColorTexture), (.)vertices.Count, .Immutable); + qvb.SetData(vertices); + _cubeGeo.SetVertexBufferSlot(qvb, 0); + qvb.ReleaseRef(); + + let qib = new IndexBuffer(_context, (.)indices.Count, .Immutable, .None, .Index32Bit); + qib.SetData(indices); + _cubeGeo.SetIndexBuffer(qib); + qib.ReleaseRef(); + } + // Create rasterizer state GlitchyEngine.Renderer.RasterizerStateDescription rsDesc = .(.Solid, .Back, true); rsDesc.DepthClipEnabled = true; @@ -196,10 +221,10 @@ namespace Sandbox.VoxelFun { World.LoadWorld("test", _world); } - - _chunkManager = new ChunkManager(_context, _vertexLayout, _world); - _chunkManager.Texture = _texture..AddRef(); - _chunkManager.TextureEffect = _textureEffect..AddRef(); + + _world.ChunkManager = new ChunkManager(_context, _vertexLayout, _world); + _world.ChunkManager.Texture = _texture..AddRef(); + _world.ChunkManager.TextureEffect = _textureEffect..AddRef(); } /* void GenerateTerrain(ref VoxelChunk vc) @@ -508,7 +533,7 @@ namespace Sandbox.VoxelFun { UpdateCamera(gameTime); - _chunkManager.Update(_camera.Position); + _world.ChunkManager.Update(_camera.Position); //RenderCommand.Clear(null, .(0.2f, 0.2f, 0.2f)); RenderCommand.Clear(null, .CornflowerBlue); @@ -549,10 +574,16 @@ namespace Sandbox.VoxelFun _ge_logo.Bind(); Renderer.Submit(_quadGeometryBinding, _textureEffect, .Scaling(1.5f)); - _chunkManager.Draw(); + Ray ray = .(_camera.Position, _camera.Transform.Forward); - //_texture.Bind(); - //Renderer.Submit(_chunkGeoBinding, _textureEffect, .Identity); + Point3 lookedAtBlock = _world.RaycastBlock(ray, 10); + + _effect.Variables["BaseColor"].SetData(.Red); + + _texture.Bind(); + Renderer.Submit(_cubeGeo, _textureEffect, .Translation((Vector3)lookedAtBlock)); + + _world.ChunkManager.Draw(); Renderer.EndScene(); } @@ -579,13 +610,17 @@ namespace Sandbox.VoxelFun private bool OnImGuiRender(ImGuiRenderEvent e) { - _chunkManager.OnImGuiRender(); + _world.ChunkManager.OnImGuiRender(); ImGui.Begin("Test"); ImGui.DragFloat("Slow Speed", &movementSpeed, 1.0f, 0.01f, 100.0f); ImGui.DragFloat("Fast Speed", &movementSpeedFast, 1.0f, 1f, 10000.0f); + Vector3 fwd = _camera.Transform.Forward; + + ImGui.DragFloat3("Forward", *(float[3]*)(void*)&fwd, 1.0f, float.NegativeInfinity, float.PositiveInfinity); + Vector3 camPos = _camera.Position; ImGui.DragFloat3("Position", *(float[3]*)(void*)&camPos, 1.0f, float.NegativeInfinity, float.PositiveInfinity); diff --git a/Sandbox/src/VoxelFun/World.bf b/Sandbox/src/VoxelFun/World.bf index bb47db2..e3ce1e3 100644 --- a/Sandbox/src/VoxelFun/World.bf +++ b/Sandbox/src/VoxelFun/World.bf @@ -1,6 +1,8 @@ using System; using System.IO; using System.Collections; +using GlitchyEngine.Math; +using GlitchyEngine; namespace Sandbox.VoxelFun { @@ -22,10 +24,18 @@ namespace Sandbox.VoxelFun private String _name ~ delete _; private String _directory ~ delete _; + private ChunkManager _chunkManager ~ delete _; + public int64 Seed => _seed; public String Name => _name; public String Directory => _directory; + public ChunkManager ChunkManager + { + get => _chunkManager; + set => _chunkManager = value; + } + const String WorldsDirectory = "worlds"; const String WorldFileName = "world.info"; @@ -84,5 +94,69 @@ namespace Sandbox.VoxelFun return .Ok; } + + /* + public Point3 GetChunkCoordinate(Vector3 blockPosition) + { + Vector3 v = blockPosition / (Vector3)VoxelChunk.Size; + + Point3 p = .(); + p.X = (int)Math.Round(v.X); + p.Y = (int)Math.Round(v.Y); + p.Z = (int)Math.Round(v.Z); + + p.Y = 0; + + return p; + } + */ + + public Point3 GetChunkCoordinate(Point3 blockCoordinate) + { + Point3 p = blockCoordinate; + if(p.X < 0) + p.X -= VoxelChunk.Size.X; + if(p.Y < 0) + p.Y -= VoxelChunk.Size.Y; + if(p.Z < 0) + p.Z -= VoxelChunk.Size.Z; + + return .(p.X / VoxelChunk.Size.X, 0, p.Z / VoxelChunk.Size.Z);//p.Y / VoxelChunk.Size.Y + } + + public Point3 RaycastBlock(Ray ray, float maxDistance) + { + Vector3 rayWalker = ray.Start; + Vector3 direction = ray.Direction.Normalized(); + + for(float walkedLength = 0; walkedLength < maxDistance; rayWalker += direction, walkedLength++) + { + Point3 blockCoordinate = (.)rayWalker; + + Point3 chunkCoordinate = GetChunkCoordinate(blockCoordinate); + + Chunk chunk = _chunkManager.LoadChunk(chunkCoordinate); + + Point3 coordInChunk = blockCoordinate - chunkCoordinate * VoxelChunk.Size; + + int blockData = chunk.Data.Data[coordInChunk.X][coordInChunk.Y][coordInChunk.Z]; + + if(blockData != 0) + return blockCoordinate; + + //Point3 chunkCoordinate = GetChunkCoordinate(rayWalker); + + //Chunk chunk = _chunkManager.LoadChunk(chunkCoordinate); + + //Point3 blockIndex = (Point3)rayWalker - chunkCoordinate * VoxelChunk.Size; + + //int blockData = chunk.Data.Data[blockIndex.X][blockIndex.Y][blockIndex.Z]; + + //if(blockData != 0) + // return blockIndex; + } + + return .(int.MaxValue, int.MaxValue, int.MaxValue); + } } }