Major refactor and organization, optimizations to chunk, world and renderer

This commit is contained in:
max
2026-03-24 22:31:40 +01:00
parent dbc546fd0e
commit eb6294c09e
25 changed files with 410 additions and 441 deletions

149
Graphics/Renderer.cs Normal file
View File

@@ -0,0 +1,149 @@
using OpenTK.Graphics.OpenGL4;
using OpenTK.Mathematics;
using Voxel.Core;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace Voxel.Graphics
{
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 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 = "Assets/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.SetVector3("cameraPosition", Camera.Position);
_shader.SetMatrix4("projection", Camera.projection);
if (_buffersDirty)
{
UpdateAllChunksBuffer();
_buffersDirty = false;
}
RenderWorld();
RenderUi();
}
public static void UpdateChunkBuffer(Chunk chunk)
{
if (_world == null || !_chunkBufferSizes.TryGetValue((chunk.X, chunk.Y), out int faceOffset))
return;
ChunkMesh chunkMesh = chunk.GetChunkMesh();
byte[] data = chunkMesh.GetPackedData();
int newByteSize = chunkMesh.Size * 4;
int currentAllocatedBytes = GetAllocatedSizeForChunk(chunk.X, chunk.Y);
if (newByteSize <= currentAllocatedBytes)
{
GL.BindBuffer(BufferTarget.ShaderStorageBuffer, _ssbo);
GL.BufferSubData(BufferTarget.ShaderStorageBuffer, (IntPtr)(faceOffset * 4), newByteSize, data);
}
else
{
MarkBuffersDirty();
}
}
private static int GetAllocatedSizeForChunk(int x, int y)
{
// todo, memory manager
return 0;
}
private static void UpdateAllChunksBuffer()
{
if (_world == null) return;
_chunkBufferSizes.Clear();
int faceOffset = 0;
foreach (Chunk chunk in _world.GetAllChunks())
{
ChunkMesh chunkMesh = chunk.GetChunkMesh();
_chunkBufferSizes[(chunk.X, chunk.Y)] = faceOffset;
byte[] data = chunkMesh.GetPackedData();
GL.BufferSubData(BufferTarget.ShaderStorageBuffer,
(IntPtr)(faceOffset * 4), // faceOffset * 4 = byte offset
chunkMesh.Size * 4,
data
);
faceOffset += chunkMesh.Size;
}
}
private static void RenderUi()
{
}
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;
}
}
}