diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..7466f32 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,26 @@ +{ + "version": "0.2.0", + "configurations": [ + { + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/bin/Debug/net8.0/Voxel.dll", + "args": [], + "cwd": "${workspaceFolder}", + // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console + "console": "internalConsole", + "stopAtEntry": false + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..095f25b --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,41 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/Voxel.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary;ForceNoAlign" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/Voxel.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary;ForceNoAlign" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "--project", + "${workspaceFolder}/Voxel.csproj" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/Assets/ascii.png b/Assets/ascii.png new file mode 100644 index 0000000..2cb9ecb Binary files /dev/null and b/Assets/ascii.png differ diff --git a/Graphics/Renderer.cs b/Graphics/Renderer.cs index 67cc33f..bd25413 100644 --- a/Graphics/Renderer.cs +++ b/Graphics/Renderer.cs @@ -1,4 +1,5 @@ using OpenTK.Graphics.OpenGL4; +using OpenTK.Mathematics; using Voxel.Core; namespace Voxel.Graphics @@ -11,17 +12,25 @@ namespace Voxel.Graphics private static Dictionary<(int, int), int> _chunkBufferSizes = new Dictionary<(int, int), int>(); private static Shader _shader; + private static Shader _uiShader; + private static GuiBatcher _guiBatcher; private static readonly Texture _texture; + private static readonly Texture _uiTexture; private static World? _world; + public static int WindowHeight = 1080; + public static int WindowWidth = 1920; + static Renderer() { string vertexPath = "Shaders/shader.vert"; string fragmentPath = "Shaders/shader.frag"; string texturePath = "Assets/atlas.png"; + string uiTexturePath = "Assets/ascii.png"; _shader = new Shader(vertexPath, fragmentPath); _texture = new Texture(texturePath); + _uiTexture = new Texture(uiTexturePath); _shader.SetInt("uTexture", 0); @@ -33,6 +42,10 @@ namespace Voxel.Graphics GL.BufferData(BufferTarget.ShaderStorageBuffer, 1024 * 1024 * 128, IntPtr.Zero, BufferUsageHint.DynamicDraw); GL.BindBufferBase(BufferRangeTarget.ShaderStorageBuffer, 0, _ssbo); + + _guiBatcher = new GuiBatcher(); + _uiShader = new Shader("Shaders/ui.vert", "Shaders/ui.frag"); + _uiShader.SetInt("uTexture", 1); } public static void Render() @@ -44,6 +57,7 @@ namespace Voxel.Graphics _shader.SetMatrix4("view", Camera.view); _shader.SetVector3("cameraPosition", Camera.Position); _shader.SetMatrix4("projection", Camera.projection); + _texture.Bind(TextureUnit.Texture0); if (_buffersDirty) { @@ -110,7 +124,24 @@ namespace Voxel.Graphics private static void RenderUi() { + GL.Disable(EnableCap.CullFace); + GL.Disable(EnableCap.DepthTest); + GL.Enable(EnableCap.Blend); + GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); + _uiShader.Use(); + + Matrix4 projection = Matrix4.CreateOrthographicOffCenter(0, WindowWidth, WindowHeight, 0, -1, 1); + _uiShader.SetMatrix4("projection", projection); + + _uiTexture.Bind(TextureUnit.Texture0); + _guiBatcher.DrawString("Voxel Engine v0.1", 15, 70, 20, Vector4.One); + + _guiBatcher.Render(); + + GL.Disable(EnableCap.Blend); + GL.Enable(EnableCap.DepthTest); + GL.Enable(EnableCap.CullFace); } private static void RenderWorld() diff --git a/Shaders/ui.frag b/Shaders/ui.frag new file mode 100644 index 0000000..83043a0 --- /dev/null +++ b/Shaders/ui.frag @@ -0,0 +1,16 @@ +#version 440 core + +in vec2 TexCoord; +in vec4 Color; + +out vec4 FragColor; + +uniform sampler2D uTexture; // Ensure this name matches C# exactly + +void main() +{ + vec4 texColor = texture(uTexture, TexCoord); + + // If you don't use texColor, uTexture gets deleted by the compiler + FragColor = texColor * Color; +} \ No newline at end of file diff --git a/Shaders/ui.vert b/Shaders/ui.vert new file mode 100644 index 0000000..59770e6 --- /dev/null +++ b/Shaders/ui.vert @@ -0,0 +1,18 @@ +#version 440 core + +layout (location = 0) in vec2 aPos; +layout (location = 1) in vec2 aTexCoord; +layout (location = 2) in vec4 aColor; + +out vec2 TexCoord; +out vec4 Color; + +uniform mat4 projection; // Ensure this name matches C# exactly + +void main() +{ + // If you don't multiply by projection, the compiler deletes the uniform + gl_Position = projection * vec4(aPos, 0.0, 1.0); + TexCoord = aTexCoord; + Color = aColor; +} \ No newline at end of file diff --git a/UI/GuiBatcher.cs b/UI/GuiBatcher.cs new file mode 100644 index 0000000..5aba069 --- /dev/null +++ b/UI/GuiBatcher.cs @@ -0,0 +1,83 @@ +using OpenTK.Graphics.OpenGL4; +using OpenTK.Mathematics; + +public class GuiBatcher +{ + private List _vertices = new List(); + private int _vbo; + private int _vao; + + public GuiBatcher() + { + _vao = GL.GenVertexArray(); + _vbo = GL.GenBuffer(); + + GL.BindVertexArray(_vao); + GL.BindBuffer(BufferTarget.ArrayBuffer, _vbo); + + // Position (2 floats) + GL.EnableVertexAttribArray(0); + GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 8 * sizeof(float), 0); + // TexCoord (2 floats) + GL.EnableVertexAttribArray(1); + GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 8 * sizeof(float), 2 * sizeof(float)); + // Color (4 floats) + GL.EnableVertexAttribArray(2); + GL.VertexAttribPointer(2, 4, VertexAttribPointerType.Float, false, 8 * sizeof(float), 4 * sizeof(float)); + } + + public void DrawQuad(float x, float y, float w, float h, Vector4 uv, Vector4 color) + { + // Two triangles (Standard Minecraft Blit) + _vertices.Add(new UiVertex(x, y, uv.X, uv.Y, color)); // TL + _vertices.Add(new UiVertex(x + w, y, uv.Z, uv.Y, color)); // TR + _vertices.Add(new UiVertex(x, y + h, uv.X, uv.W, color)); // BL + + _vertices.Add(new UiVertex(x + w, y, uv.Z, uv.Y, color)); // TR + _vertices.Add(new UiVertex(x + w, y + h, uv.Z, uv.W, color)); // BR + _vertices.Add(new UiVertex(x, y + h, uv.X, uv.W, color)); // BL + } + + public void Render() + { + if (_vertices.Count == 0) return; + + GL.BindVertexArray(_vao); + GL.BindBuffer(BufferTarget.ArrayBuffer, _vbo); + + var data = _vertices.ToArray(); + GL.BufferData(BufferTarget.ArrayBuffer, data.Length * 8 * sizeof(float), data, BufferUsageHint.StreamDraw); + + GL.DrawArrays(PrimitiveType.Triangles, 0, _vertices.Count); + _vertices.Clear(); // Reset for next frame + } + + public void DrawString(string text, float x, float y, float size, Vector4 color) + { + float charStep = 1.0f / 16.0f; + float currentX = x; + + foreach (char c in text) + { + int ascii = (int)c; + int row = ascii / 16; + int col = ascii % 16; + + float uStart = col * charStep; + float uEnd = uStart + charStep; + + float vStart = 1.0f - (row * charStep); + float vEnd = vStart - charStep; + + Vector4 uv = new Vector4( + uStart, // U start + vStart, // V start + uEnd, // U end + vEnd // V end + ); + + DrawQuad(currentX, y, size, size, uv, color); + currentX += size * 0.8f; // Tighten horizontal spacing + } + } +} \ No newline at end of file diff --git a/UI/UIElement.cs b/UI/UIElement.cs deleted file mode 100644 index 2be6585..0000000 --- a/UI/UIElement.cs +++ /dev/null @@ -1,6 +0,0 @@ -// wip - -public class UIElement -{ - -} \ No newline at end of file diff --git a/UI/UiVertex.cs b/UI/UiVertex.cs new file mode 100644 index 0000000..a4afad7 --- /dev/null +++ b/UI/UiVertex.cs @@ -0,0 +1,15 @@ +using OpenTK.Mathematics; + +struct UiVertex +{ + public Vector2 Position; + public Vector2 TexCoord; + public Vector4 Color; + + public UiVertex(float x, float y, float u, float v, Vector4 color) + { + Position = new Vector2(x, y); + TexCoord = new Vector2(u, v); + Color = color; + } +} \ No newline at end of file