Compare commits
2 Commits
96c1faa626
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| e1778fb446 | |||
| a324ff0d16 |
26
.vscode/launch.json
vendored
Normal file
26
.vscode/launch.json
vendored
Normal file
@@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
41
.vscode/tasks.json
vendored
Normal file
41
.vscode/tasks.json
vendored
Normal file
@@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
Assets/ascii.png
Normal file
BIN
Assets/ascii.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
@@ -1,8 +1,10 @@
|
|||||||
using OpenTK.Graphics.OpenGL4;
|
using OpenTK.Graphics.OpenGL4;
|
||||||
|
using OpenTK.Mathematics;
|
||||||
using OpenTK.Windowing.Common;
|
using OpenTK.Windowing.Common;
|
||||||
using OpenTK.Windowing.Desktop;
|
using OpenTK.Windowing.Desktop;
|
||||||
using OpenTK.Windowing.GraphicsLibraryFramework;
|
using OpenTK.Windowing.GraphicsLibraryFramework;
|
||||||
using Voxel.Graphics;
|
using Voxel.Graphics;
|
||||||
|
using Voxel.UI;
|
||||||
|
|
||||||
namespace Voxel.Core
|
namespace Voxel.Core
|
||||||
{
|
{
|
||||||
@@ -16,6 +18,8 @@ namespace Voxel.Core
|
|||||||
public event Action<float, float> Update;
|
public event Action<float, float> Update;
|
||||||
public event Action Tick;
|
public event Action Tick;
|
||||||
|
|
||||||
|
private Label _fpsLabel = new Label("FPS: N/A", 16, 16, 24, Vector4.One);
|
||||||
|
|
||||||
private double _tickTime;
|
private double _tickTime;
|
||||||
public const double TICK_LENGTH = 1.0 / 20.0; // 20 TPS
|
public const double TICK_LENGTH = 1.0 / 20.0; // 20 TPS
|
||||||
|
|
||||||
@@ -55,15 +59,19 @@ namespace Voxel.Core
|
|||||||
timeElapsed += e.Time;
|
timeElapsed += e.Time;
|
||||||
float alpha = (float)(_tickTime / Window.TICK_LENGTH);
|
float alpha = (float)(_tickTime / Window.TICK_LENGTH);
|
||||||
float deltaTime = (float)e.Time;
|
float deltaTime = (float)e.Time;
|
||||||
|
|
||||||
if (timeElapsed >= 1)
|
if (timeElapsed >= 1)
|
||||||
{
|
{
|
||||||
Console.WriteLine("FPS: " + frames.ToString());
|
Console.WriteLine("FPS: " + frames.ToString());
|
||||||
|
_fpsLabel.Text = $"FPS: {frames}";
|
||||||
timeElapsed = 0;
|
timeElapsed = 0;
|
||||||
frames = 0;
|
frames = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Update.Invoke(deltaTime, alpha);
|
Update.Invoke(deltaTime, alpha);
|
||||||
|
|
||||||
|
Renderer.RenderLabel(_fpsLabel);
|
||||||
|
|
||||||
Renderer.Render();
|
Renderer.Render();
|
||||||
|
|
||||||
SwapBuffers();
|
SwapBuffers();
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
using OpenTK.Mathematics;
|
using System.Net.Sockets;
|
||||||
|
using OpenTK.Mathematics;
|
||||||
using OpenTK.Windowing.Common;
|
using OpenTK.Windowing.Common;
|
||||||
using OpenTK.Windowing.GraphicsLibraryFramework;
|
using OpenTK.Windowing.GraphicsLibraryFramework;
|
||||||
using Voxel.Core;
|
using Voxel.Core;
|
||||||
using Voxel.Graphics;
|
using Voxel.Graphics;
|
||||||
|
using Voxel.UI;
|
||||||
|
|
||||||
namespace Voxel.Entities
|
namespace Voxel.Entities
|
||||||
{
|
{
|
||||||
@@ -15,11 +17,14 @@ namespace Voxel.Entities
|
|||||||
private int _jumpTicks = 0;
|
private int _jumpTicks = 0;
|
||||||
|
|
||||||
private Blocks _selectedBlock = Blocks.OakPlanks;
|
private Blocks _selectedBlock = Blocks.OakPlanks;
|
||||||
private Vector3 previousPosition;
|
private Vector3 _previousPosition;
|
||||||
|
private Label _positionLabel = new Label("Position:", 16, 48, 24, Vector4.One);
|
||||||
|
private Label _blockLabel = new Label("Selected Block:", 16, 80, 24, Vector4.One);
|
||||||
|
|
||||||
public Player(Vector3 startPos, World world) : base(startPos, 0.5f, 1.8f, world)
|
public Player(Vector3 startPos, World world) : base(startPos, 0.5f, 1.8f, world)
|
||||||
{
|
{
|
||||||
Input.OnMouseWheel += SwitchBlock;
|
Input.OnMouseWheel += SwitchBlock;
|
||||||
|
_blockLabel.Text = $"Selected block: {_selectedBlock}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PlaceBlock()
|
public void PlaceBlock()
|
||||||
@@ -48,7 +53,7 @@ namespace Voxel.Entities
|
|||||||
|
|
||||||
_world.UpdateChunkLoading(Position);
|
_world.UpdateChunkLoading(Position);
|
||||||
|
|
||||||
previousPosition = Position;
|
_previousPosition = Position;
|
||||||
|
|
||||||
float forwards = 0;
|
float forwards = 0;
|
||||||
float sidewards = 0;
|
float sidewards = 0;
|
||||||
@@ -94,6 +99,8 @@ namespace Voxel.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else _jumpTicks = 0;
|
else _jumpTicks = 0;
|
||||||
|
|
||||||
|
_positionLabel.Text = $"Position: {Position.X:F2}, {Position.Y:F2}, {Position.Z:F2}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Jump()
|
public void Jump()
|
||||||
@@ -104,9 +111,12 @@ namespace Voxel.Entities
|
|||||||
|
|
||||||
public void Update(float deltaTime, float alpha)
|
public void Update(float deltaTime, float alpha)
|
||||||
{
|
{
|
||||||
Camera.Position = Vector3.Lerp(previousPosition, Position, alpha) + Vector3.UnitY * 1.62f;
|
Camera.Position = Vector3.Lerp(_previousPosition, Position, alpha) + Vector3.UnitY * 1.62f;
|
||||||
Rotation = Camera.Yaw;
|
Rotation = Camera.Yaw;
|
||||||
|
|
||||||
|
Renderer.RenderLabel(_positionLabel);
|
||||||
|
Renderer.RenderLabel(_blockLabel);
|
||||||
|
|
||||||
if (lastClick > 0)
|
if (lastClick > 0)
|
||||||
{
|
{
|
||||||
lastClick -= deltaTime;
|
lastClick -= deltaTime;
|
||||||
@@ -159,7 +169,7 @@ namespace Voxel.Entities
|
|||||||
|
|
||||||
_blockIndex = (_blockIndex + direction + count) % count;
|
_blockIndex = (_blockIndex + direction + count) % count;
|
||||||
_selectedBlock = BlockDefinitions.CreativeInventory[_blockIndex];
|
_selectedBlock = BlockDefinitions.CreativeInventory[_blockIndex];
|
||||||
|
_blockLabel.Text = $"Selected block: {_selectedBlock}";
|
||||||
Console.WriteLine(_selectedBlock);
|
Console.WriteLine(_selectedBlock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ namespace Voxel.Graphics
|
|||||||
public static float Speed = 5f;
|
public static float Speed = 5f;
|
||||||
public static float ShiftSpeed = 20f;
|
public static float ShiftSpeed = 20f;
|
||||||
|
|
||||||
private static int _width;
|
public static int Width;
|
||||||
private static int _height;
|
public static int Height;
|
||||||
|
|
||||||
public static Matrix4 view =>
|
public static Matrix4 view =>
|
||||||
Matrix4.LookAt(Position, Position + Front, Vector3.UnitY);
|
Matrix4.LookAt(Position, Position + Front, Vector3.UnitY);
|
||||||
@@ -47,7 +47,7 @@ namespace Voxel.Graphics
|
|||||||
public static void UpdateProjection()
|
public static void UpdateProjection()
|
||||||
{
|
{
|
||||||
float fov = MathHelper.DegreesToRadians(FOV);
|
float fov = MathHelper.DegreesToRadians(FOV);
|
||||||
float aspectRatio = _width / (float)_height;
|
float aspectRatio = Width / (float)Height;
|
||||||
float near = 0.1f;
|
float near = 0.1f;
|
||||||
float far = 1000f;
|
float far = 1000f;
|
||||||
|
|
||||||
@@ -56,8 +56,8 @@ namespace Voxel.Graphics
|
|||||||
|
|
||||||
public static void UpdateSize(int width, int height)
|
public static void UpdateSize(int width, int height)
|
||||||
{
|
{
|
||||||
_width = width;
|
Width = width;
|
||||||
_height = height;
|
Height = height;
|
||||||
UpdateProjection();
|
UpdateProjection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using OpenTK.Graphics.OpenGL4;
|
using OpenTK.Graphics.OpenGL4;
|
||||||
|
using OpenTK.Mathematics;
|
||||||
using Voxel.Core;
|
using Voxel.Core;
|
||||||
|
using Voxel.UI;
|
||||||
|
|
||||||
namespace Voxel.Graphics
|
namespace Voxel.Graphics
|
||||||
{
|
{
|
||||||
@@ -11,17 +13,25 @@ namespace Voxel.Graphics
|
|||||||
|
|
||||||
private static Dictionary<(int, int), int> _chunkBufferSizes = new Dictionary<(int, int), int>();
|
private static Dictionary<(int, int), int> _chunkBufferSizes = new Dictionary<(int, int), int>();
|
||||||
private static Shader _shader;
|
private static Shader _shader;
|
||||||
|
private static Shader _uiShader;
|
||||||
|
private static GuiBatcher _guiBatcher;
|
||||||
private static readonly Texture _texture;
|
private static readonly Texture _texture;
|
||||||
|
private static readonly Texture _uiTexture;
|
||||||
private static World? _world;
|
private static World? _world;
|
||||||
|
|
||||||
|
public static int WindowHeight = 1080;
|
||||||
|
public static int WindowWidth = 1920;
|
||||||
|
|
||||||
static Renderer()
|
static Renderer()
|
||||||
{
|
{
|
||||||
string vertexPath = "Shaders/shader.vert";
|
string vertexPath = "Shaders/shader.vert";
|
||||||
string fragmentPath = "Shaders/shader.frag";
|
string fragmentPath = "Shaders/shader.frag";
|
||||||
string texturePath = "Assets/atlas.png";
|
string texturePath = "Assets/atlas.png";
|
||||||
|
string uiTexturePath = "Assets/ascii.png";
|
||||||
|
|
||||||
_shader = new Shader(vertexPath, fragmentPath);
|
_shader = new Shader(vertexPath, fragmentPath);
|
||||||
_texture = new Texture(texturePath);
|
_texture = new Texture(texturePath);
|
||||||
|
_uiTexture = new Texture(uiTexturePath);
|
||||||
|
|
||||||
_shader.SetInt("uTexture", 0);
|
_shader.SetInt("uTexture", 0);
|
||||||
|
|
||||||
@@ -33,6 +43,10 @@ namespace Voxel.Graphics
|
|||||||
|
|
||||||
GL.BufferData(BufferTarget.ShaderStorageBuffer, 1024 * 1024 * 128, IntPtr.Zero, BufferUsageHint.DynamicDraw);
|
GL.BufferData(BufferTarget.ShaderStorageBuffer, 1024 * 1024 * 128, IntPtr.Zero, BufferUsageHint.DynamicDraw);
|
||||||
GL.BindBufferBase(BufferRangeTarget.ShaderStorageBuffer, 0, _ssbo);
|
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()
|
public static void Render()
|
||||||
@@ -44,6 +58,7 @@ namespace Voxel.Graphics
|
|||||||
_shader.SetMatrix4("view", Camera.view);
|
_shader.SetMatrix4("view", Camera.view);
|
||||||
_shader.SetVector3("cameraPosition", Camera.Position);
|
_shader.SetVector3("cameraPosition", Camera.Position);
|
||||||
_shader.SetMatrix4("projection", Camera.projection);
|
_shader.SetMatrix4("projection", Camera.projection);
|
||||||
|
_texture.Bind(TextureUnit.Texture0);
|
||||||
|
|
||||||
if (_buffersDirty)
|
if (_buffersDirty)
|
||||||
{
|
{
|
||||||
@@ -110,7 +125,24 @@ namespace Voxel.Graphics
|
|||||||
|
|
||||||
private static void RenderUi()
|
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, Camera.Width, Camera.Height, 0, -1, 1);
|
||||||
|
_uiShader.SetMatrix4("projection", projection);
|
||||||
|
|
||||||
|
_uiTexture.Bind(TextureUnit.Texture0);
|
||||||
|
_guiBatcher.DrawString("Voxel Engine v0.1", 16, 112, 24, Vector4.One);
|
||||||
|
|
||||||
|
_guiBatcher.Render();
|
||||||
|
|
||||||
|
GL.Disable(EnableCap.Blend);
|
||||||
|
GL.Enable(EnableCap.DepthTest);
|
||||||
|
GL.Enable(EnableCap.CullFace);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RenderWorld()
|
private static void RenderWorld()
|
||||||
@@ -143,5 +175,11 @@ namespace Voxel.Graphics
|
|||||||
{
|
{
|
||||||
_buffersDirty = true;
|
_buffersDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//temp
|
||||||
|
public static void RenderLabel(Label label)
|
||||||
|
{
|
||||||
|
_guiBatcher.DrawString(label.Text, label.X, label.Y, label.Size, label.Color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
Shaders/ui.frag
Normal file
16
Shaders/ui.frag
Normal file
@@ -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;
|
||||||
|
}
|
||||||
18
Shaders/ui.vert
Normal file
18
Shaders/ui.vert
Normal file
@@ -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;
|
||||||
|
}
|
||||||
47
UI/CharData.cs
Normal file
47
UI/CharData.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
public static class CharWidth
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<char, float> CharWidths = new Dictionary<char, float>();
|
||||||
|
|
||||||
|
static CharWidth()
|
||||||
|
{
|
||||||
|
// Default for all ASCII
|
||||||
|
for (char c = (char)32; c <= (char)126; c++)
|
||||||
|
CharWidths[c] = 5.0f;
|
||||||
|
|
||||||
|
// Override exceptions
|
||||||
|
CharWidths[' '] = 3.0f;
|
||||||
|
CharWidths['!'] = 1.0f;
|
||||||
|
CharWidths['"'] = 3.0f;
|
||||||
|
CharWidths['\''] = 1.0f;
|
||||||
|
CharWidths['('] = 3.0f;
|
||||||
|
CharWidths[')'] = 3.0f;
|
||||||
|
CharWidths['*'] = 3.0f;
|
||||||
|
CharWidths[','] = 1.0f;
|
||||||
|
CharWidths['.'] = 1.0f;
|
||||||
|
CharWidths[':'] = 1.0f;
|
||||||
|
CharWidths[';'] = 1.0f;
|
||||||
|
CharWidths['<'] = 4.0f;
|
||||||
|
CharWidths['>'] = 4.0f;
|
||||||
|
CharWidths['@'] = 6.0f;
|
||||||
|
CharWidths['I'] = 3.0f;
|
||||||
|
CharWidths['['] = 3.0f;
|
||||||
|
CharWidths[']'] = 3.0f;
|
||||||
|
CharWidths['`'] = 2.0f;
|
||||||
|
CharWidths['f'] = 4.0f;
|
||||||
|
CharWidths['i'] = 1.0f;
|
||||||
|
CharWidths['k'] = 4.0f;
|
||||||
|
CharWidths['l'] = 2.0f;
|
||||||
|
CharWidths['t'] = 3.0f;
|
||||||
|
CharWidths['{'] = 3.0f;
|
||||||
|
CharWidths['|'] = 1.0f;
|
||||||
|
CharWidths['}'] = 3.0f;
|
||||||
|
CharWidths['~'] = 6.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float GetWidth(char c)
|
||||||
|
{
|
||||||
|
if (CharWidths.TryGetValue(c, out float width))
|
||||||
|
return width;
|
||||||
|
return 5.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
86
UI/GuiBatcher.cs
Normal file
86
UI/GuiBatcher.cs
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
using OpenTK.Graphics.OpenGL4;
|
||||||
|
using OpenTK.Mathematics;
|
||||||
|
|
||||||
|
public class GuiBatcher
|
||||||
|
{
|
||||||
|
private List<UiVertex> _vertices = new List<UiVertex>();
|
||||||
|
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);
|
||||||
|
|
||||||
|
float charWidthPixels = (CharWidth.GetWidth(c) + 1) / 8;
|
||||||
|
float charWidthWorldUnits = size * charWidthPixels;
|
||||||
|
currentX += charWidthWorldUnits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
UI/Label.cs
Normal file
21
UI/Label.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using OpenTK.Mathematics;
|
||||||
|
|
||||||
|
namespace Voxel.UI {
|
||||||
|
public class Label
|
||||||
|
{
|
||||||
|
public string Text;
|
||||||
|
public float X;
|
||||||
|
public float Y;
|
||||||
|
public float Size;
|
||||||
|
public Vector4 Color;
|
||||||
|
|
||||||
|
public Label(string text, float x, float y, float size, Vector4 color)
|
||||||
|
{
|
||||||
|
Text = text;
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
Size = size;
|
||||||
|
Color = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
// wip
|
|
||||||
|
|
||||||
public class UIElement
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
15
UI/UiVertex.cs
Normal file
15
UI/UiVertex.cs
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using OpenTK.Mathematics;
|
using OpenTK.Mathematics;
|
||||||
using Voxel.Graphics;
|
using Voxel.Graphics;
|
||||||
using Voxel.Physics;
|
using Voxel.Physics;
|
||||||
|
using Voxel.UI;
|
||||||
|
|
||||||
namespace Voxel.Core
|
namespace Voxel.Core
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user