Files
VoxelEngine/Core/Game.cs

115 lines
4.0 KiB
C#

using OpenTK.Graphics.OpenGL4;
using OpenTK.Mathematics;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.Desktop;
using OpenTK.Windowing.GraphicsLibraryFramework;
using VoxelEngine.Rendering;
using VoxelEngine.World;
namespace VoxelEngine.Core;
public sealed class Game : GameWindow
{
private const float MoveSpeed = 8f; // units per second
private const float Sensitivity = 0.15f; // degrees per pixel
private readonly BlockRegistry _registry = new();
private Shader _shader = null!;
private Texture _texture = null!;
private ChunkRenderer _renderer = null!;
private Camera _camera = null!;
public Game(GameWindowSettings gameSettings, NativeWindowSettings nativeSettings)
: base(gameSettings, nativeSettings) { }
protected override void OnLoad()
{
base.OnLoad();
GL.ClearColor(0.45f, 0.65f, 0.95f, 1.0f);
GL.Enable(EnableCap.DepthTest);
GL.Enable(EnableCap.CullFace);
this._shader = new Shader("Assets/shaders/chunk.vert", "Assets/shaders/chunk.frag");
this._texture = new Texture("Assets/textures/atlas.png");
Chunk chunk = this.BuildChunk();
float[] mesh = new ChunkMesher().Build(chunk, this._registry);
this._renderer = new ChunkRenderer(mesh);
this._camera = new Camera(new Vector3(8f, 20f, 40f), this.ClientSize.X / (float)this.ClientSize.Y);
this.CursorState = CursorState.Grabbed;
}
private Chunk BuildChunk()
{
Chunk chunk = new();
for (int x = 0; x < Chunk.Size; x++)
for (int z = 0; z < Chunk.Size; z++)
for (int y = 0; y < Chunk.Size; y++)
{
chunk[x, y, z] = y switch
{
Chunk.Size - 1 => this._registry.Grass.Id,
>= Chunk.Size - 4 => this._registry.Dirt.Id,
_ => this._registry.Stone.Id
};
}
return chunk;
}
protected override void OnUpdateFrame(FrameEventArgs args)
{
base.OnUpdateFrame(args);
if (!this.IsFocused) return;
if (this.KeyboardState.IsKeyDown(Keys.Escape)) {
this.Close(); return; }
float distance = Game.MoveSpeed * (float)args.Time;
if (this.KeyboardState.IsKeyDown(Keys.W)) this._camera.Move(this._camera.Front * distance);
if (this.KeyboardState.IsKeyDown(Keys.S)) this._camera.Move(-this._camera.Front * distance);
if (this.KeyboardState.IsKeyDown(Keys.A)) this._camera.Move(-this._camera.Right * distance);
if (this.KeyboardState.IsKeyDown(Keys.D)) this._camera.Move(this._camera.Right * distance);
if (this.KeyboardState.IsKeyDown(Keys.Space)) this._camera.Move(Vector3.UnitY * distance);
if (this.KeyboardState.IsKeyDown(Keys.LeftShift)) this._camera.Move(-Vector3.UnitY * distance);
Vector2 delta = this.MouseState.Delta;
this._camera.AddRotation(delta.X * Game.Sensitivity, -delta.Y * Game.Sensitivity);
}
protected override void OnRenderFrame(FrameEventArgs args)
{
base.OnRenderFrame(args);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
this._shader.Use();
this._shader.SetMatrix4("model", Matrix4.Identity);
this._shader.SetMatrix4("view", this._camera.GetViewMatrix());
this._shader.SetMatrix4("projection", this._camera.GetProjectionMatrix());
this._shader.SetInt("atlas", 0);
this._texture.Use(TextureUnit.Texture0);
this._renderer.Draw();
this.SwapBuffers();
}
protected override void OnResize(ResizeEventArgs e)
{
base.OnResize(e);
GL.Viewport(0, 0, e.Width, e.Height);
// OnResize can fire before OnLoad (where _camera is created), so guard against it.
if (this._camera is not null) this._camera.AspectRatio = e.Width / (float)e.Height;
}
protected override void OnUnload()
{
this._renderer.Dispose();
this._texture.Dispose();
this._shader.Dispose();
base.OnUnload();
}
}