using OpenTK.Graphics.OpenGL4; using static System.Runtime.InteropServices.JavaScript.JSType; namespace Voxel { static class Renderer { private static int _ssbo; private static int _vao; private static bool _buffersDirty; private static Dictionary<(int, int), int> _chunkBufferSizes = new Dictionary<(int, int), int>(); private static List _chunkMeshes = new List(); private static Shader _shader; private static readonly Texture _texture; private static World? _world; static Renderer() { string vertexPath = "Shaders/shader.vert"; string fragmentPath = "Shaders/shader.frag"; string texturePath = "atlas.png"; _shader = new Shader(vertexPath, fragmentPath); _texture = new Texture(texturePath); _shader.SetInt("uTexture", 0); _ssbo = GL.GenBuffer(); _vao = GL.GenVertexArray(); GL.BindVertexArray(_vao); GL.BindBuffer(BufferTarget.ShaderStorageBuffer, _ssbo); GL.BufferData(BufferTarget.ShaderStorageBuffer, 1024 * 1024 * 128, IntPtr.Zero, BufferUsageHint.DynamicDraw); GL.BindBufferBase(BufferRangeTarget.ShaderStorageBuffer, 0, _ssbo); } public static void Render() { GL.BindVertexArray(_vao); GL.BindBuffer(BufferTarget.ShaderStorageBuffer, _ssbo); _shader.Use(); _shader.SetMatrix4("view", Camera.view); _shader.SetMatrix4("projection", Camera.projection); if (_buffersDirty) { UpdateAllChunksBuffer(); _buffersDirty = false; } RenderWorld(); } private static void UpdateAllChunksBuffer() { if (_world == null) return; int offset = 0; foreach (Chunk chunk in _world.GetAllChunks()) { ChunkMesh chunkMesh = chunk.GetChunkMesh(); if (chunkMesh.NeedsUpdate) { byte[] data = chunkMesh.GetPackedData(); GL.BufferSubData(BufferTarget.ShaderStorageBuffer, (IntPtr)offset * 8, chunkMesh.Size * 8, data); } _chunkBufferSizes[(chunk.X, chunk.Y)] = offset; offset += chunkMesh.Size * 8; } } private static void RenderWorld() { if (_world == null) return; foreach (Chunk chunk in _world.GetAllChunks()) { ChunkMesh chunkMesh = chunk.GetChunkMesh(); if (chunkMesh.Size == 0) continue; if (!_chunkBufferSizes.TryGetValue((chunk.X, chunk.Y), out int offset)) continue; _shader.SetInt("chunkX", chunk.X); _shader.SetInt("chunkY", chunk.Y); //GL.MemoryBarrier(MemoryBarrierFlags.ShaderStorageBarrierBit); GL.DrawArrays(PrimitiveType.Triangles, offset * 6, chunkMesh.Size * 6); } } public static void SetWorld(World world) { _world = world; _buffersDirty = true; } public static void MarkBuffersDirty() { _buffersDirty = true; } } }