added input system and perspective camera
This commit is contained in:
@ -1,3 +1,8 @@
|
||||
# EngineSharp
|
||||
|
||||
A second attempt at creating an engine using Silk.Net
|
||||
|
||||
|
||||
|
||||
Using a Left-Handed Y-Up coordinate system
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EngineSharp.Core", "EngineSharp.Core\EngineSharp.Core.csproj", "{A617B903-6114-448A-864F-17B157C58C53}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EngineSharp", "..\EngineSharp\EngineSharp.csproj", "{1D984FEE-1A61-4E35-9D00-0264D92A31F4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -12,5 +14,9 @@ Global
|
||||
{A617B903-6114-448A-864F-17B157C58C53}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A617B903-6114-448A-864F-17B157C58C53}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A617B903-6114-448A-864F-17B157C58C53}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1D984FEE-1A61-4E35-9D00-0264D92A31F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1D984FEE-1A61-4E35-9D00-0264D92A31F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1D984FEE-1A61-4E35-9D00-0264D92A31F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1D984FEE-1A61-4E35-9D00-0264D92A31F4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
@ -0,0 +1,7 @@
|
||||
namespace EngineSharp.Core;
|
||||
|
||||
public static class NumberExtensions
|
||||
{
|
||||
public static float ToRadians(this float degrees) => degrees * MathF.PI / 180.0f;
|
||||
public static double ToRadians(this double degrees) => degrees * Math.PI / 180.0;
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
using Silk.NET.Maths;
|
||||
|
||||
namespace EngineSharp.Core;
|
||||
|
||||
// TODO: Pretty useless currently as I am extending instances and not the class sadly
|
||||
public static class VectorExtensions
|
||||
{
|
||||
public static Vector3D<T> Up<T>(this Vector3D<T> _) where T : unmanaged, IFormattable, IEquatable<T>, IComparable<T> => Vector3D<T>.UnitY;
|
||||
public static Vector3D<T> Down<T>(this Vector3D<T> _) where T : unmanaged, IFormattable, IEquatable<T>, IComparable<T> => -Vector3D<T>.UnitY;
|
||||
public static Vector3D<T> Left<T>(this Vector3D<T> _) where T : unmanaged, IFormattable, IEquatable<T>, IComparable<T> => Vector3D<T>.UnitX;
|
||||
public static Vector3D<T> Right<T>(this Vector3D<T> _) where T : unmanaged, IFormattable, IEquatable<T>, IComparable<T> => -Vector3D<T>.UnitX;
|
||||
public static Vector3D<T> Front<T>(this Vector3D<T> _) where T : unmanaged, IFormattable, IEquatable<T>, IComparable<T> => -Vector3D<T>.UnitZ;
|
||||
public static Vector3D<T> Back<T>(this Vector3D<T> _) where T : unmanaged, IFormattable, IEquatable<T>, IComparable<T> => -Vector3D<T>.UnitZ;
|
||||
|
||||
// Thanks to: https://stackoverflow.com/a/67920029
|
||||
// public static Vector3D<T> Slerp<T>(this Vector3D<T> start, Vector3D<T> end, float percent)
|
||||
// where T : unmanaged, IFormattable, IEquatable<T>, IComparable<T>
|
||||
// {
|
||||
// // the cosine of the angle between 2 vectors.
|
||||
// var dot = Vector3D.Dot(start, end);
|
||||
//
|
||||
// // Clamp it to be in the range of Acos()
|
||||
// // This may be unnecessary, but floating point precision can be a fickle mistress.
|
||||
// Math.Clamp(dot, -1, 1);
|
||||
//
|
||||
// // Acos(dot) returns the angle between start and end,
|
||||
// // And multiplying that by percent returns the angle between start and the final result.
|
||||
// var theta = Math.Acos(dot) * percent;
|
||||
// var relativeVec = end - start * dot;
|
||||
// relativeVec = Vector3D.Normalize(relativeVec);
|
||||
//
|
||||
// // Orthonormal basis
|
||||
// // The final result.
|
||||
// return ((start * Math.Cos(theta)) + (relativeVec * Math.Sin(theta)));
|
||||
// }
|
||||
}
|
28
src/EngineSharp.Core/EngineSharp.Core/IEngine.cs
Normal file
28
src/EngineSharp.Core/EngineSharp.Core/IEngine.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using Silk.NET.Windowing;
|
||||
|
||||
namespace EngineSharp.Core;
|
||||
|
||||
public interface IEngine
|
||||
{
|
||||
void Start();
|
||||
void Stop();
|
||||
}
|
||||
|
||||
public enum GraphicsAPI
|
||||
{
|
||||
OpenGL,
|
||||
Vulkan,
|
||||
}
|
||||
|
||||
public static class EngineFactory
|
||||
{
|
||||
public static IEngine Create(GraphicsAPI api, WindowOptions windowOptions)
|
||||
{
|
||||
return api switch
|
||||
{
|
||||
GraphicsAPI.OpenGL => new OpenGLEngine(windowOptions),
|
||||
GraphicsAPI.Vulkan => throw new NotSupportedException($"The graphics API {api} is not currently supported"),
|
||||
_ => throw new ArgumentException($"The graphics API {api} is unknown.", nameof(api))
|
||||
};
|
||||
}
|
||||
}
|
52
src/EngineSharp.Core/EngineSharp.Core/Input.cs
Normal file
52
src/EngineSharp.Core/EngineSharp.Core/Input.cs
Normal file
@ -0,0 +1,52 @@
|
||||
using Silk.NET.Input;
|
||||
|
||||
namespace EngineSharp.Core;
|
||||
|
||||
public class Input
|
||||
{
|
||||
private readonly IInputContext _context;
|
||||
private readonly IDictionary<IKeyboard, HashSet<Key>> _pressedKeys = new Dictionary<IKeyboard, HashSet<Key>>();
|
||||
|
||||
// TODO: Add mouse
|
||||
internal Input(IInputContext inputContext)
|
||||
{
|
||||
_context = inputContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the given key has been pressed on any keyboard.
|
||||
/// </summary>
|
||||
public bool IsKeyPressed(Key key) => _pressedKeys.Values.Any(k => k.Contains(key));
|
||||
/// <summary>
|
||||
/// Returns true if the given key is pressed on the given keyboard.
|
||||
/// </summary>
|
||||
public bool IsKeyPressed(IKeyboard keyboard, Key key)
|
||||
{
|
||||
if (_pressedKeys.TryGetValue(keyboard, out var pressedKeys))
|
||||
{
|
||||
return pressedKeys.Contains(key);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnKeyDown(IKeyboard keyboard, Key key, int keyCode)
|
||||
{
|
||||
if (_pressedKeys.TryGetValue(keyboard, out var existingSet))
|
||||
{
|
||||
existingSet.Add(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
var set = new HashSet<Key> { key };
|
||||
_pressedKeys.Add(keyboard, set);
|
||||
}
|
||||
}
|
||||
private void OnKeyUp(IKeyboard keyboard, Key key, int keyCode)
|
||||
{
|
||||
if (_pressedKeys.TryGetValue(keyboard, out var existingSet))
|
||||
{
|
||||
existingSet.Remove(key);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +1,16 @@
|
||||
using Silk.NET.Windowing;
|
||||
using System.Drawing;
|
||||
using Silk.NET.Input;
|
||||
using Silk.NET.Maths;
|
||||
using Silk.NET.OpenGL;
|
||||
using Silk.NET.Windowing;
|
||||
|
||||
namespace EngineSharp.Core;
|
||||
|
||||
public interface IEngine
|
||||
{
|
||||
void Start();
|
||||
}
|
||||
|
||||
public class OpenGLEngine : IEngine
|
||||
internal class OpenGLEngine : IEngine
|
||||
{
|
||||
private readonly IWindow _window;
|
||||
private GL _gl = null!; // because between constructing the engine and OnLoad being called nothing should be able to happen, we do this to get rid of warnings
|
||||
private Input _input = null!;
|
||||
|
||||
public OpenGLEngine(WindowOptions windowOptions)
|
||||
{
|
||||
@ -17,6 +18,7 @@ public class OpenGLEngine : IEngine
|
||||
_window.Load += OnLoad;
|
||||
_window.Update += OnUpdate;
|
||||
_window.Render += OnRender;
|
||||
_window.Resize += OnResize;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
@ -24,9 +26,18 @@ public class OpenGLEngine : IEngine
|
||||
_window.Run();
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
_window.Close();
|
||||
}
|
||||
|
||||
private void OnLoad()
|
||||
{
|
||||
// TODO: Create openGL context etc.
|
||||
_gl = _window.CreateOpenGL();
|
||||
_input = new Input(_window.CreateInput());
|
||||
|
||||
_gl.ClearColor(Color.Black);
|
||||
_gl.Enable(EnableCap.DepthTest);
|
||||
}
|
||||
|
||||
private void OnUpdate(double deltaTime)
|
||||
@ -38,4 +49,9 @@ public class OpenGLEngine : IEngine
|
||||
{
|
||||
// TODO: Here render all meshes etc.
|
||||
}
|
||||
|
||||
private void OnResize(Vector2D<int> obj)
|
||||
{
|
||||
// TODO: update aspect of camera; on entity component system the camera should probably read the aspect ratio from some location rather than the engine updating the aspect on the camera
|
||||
}
|
||||
}
|
54
src/EngineSharp.Core/EngineSharp.Core/PerspectiveCamera.cs
Normal file
54
src/EngineSharp.Core/EngineSharp.Core/PerspectiveCamera.cs
Normal file
@ -0,0 +1,54 @@
|
||||
// using System.Numerics;
|
||||
using Silk.NET.Maths;
|
||||
|
||||
namespace EngineSharp.Core;
|
||||
|
||||
public class PerspectiveCamera
|
||||
{
|
||||
private readonly Vector3D<float> _position;
|
||||
private readonly Vector3D<float> _worldUp;
|
||||
private Matrix3X3<float> _intrinsicCoordinates; // right | up | front
|
||||
private float _yaw;
|
||||
private float _pitch;
|
||||
private float _fov;
|
||||
private float _nearClippingPlane;
|
||||
private float _farClippingPlane;
|
||||
|
||||
public Matrix4X4<float> ViewMatrix => Matrix4X4.CreateLookAt(_position, _position + _intrinsicCoordinates.Column3, _worldUp); // TODO: I hope this is Left-Handed. If not I need to update the readme
|
||||
public Matrix4X4<float> ProjectionMatrix => Matrix4X4.CreatePerspectiveFieldOfView(_fov, , _nearClippingPlane, _farClippingPlane);
|
||||
|
||||
public PerspectiveCamera(Vector3D<float> position, float yaw = -90.0f, float pitch = 0, float fov = 45.0f, float nearClippingPlane = 0.1f, float farClippingPlane = 100.0f)
|
||||
{
|
||||
_position = position;
|
||||
_yaw = yaw;
|
||||
_pitch = pitch;
|
||||
_fov = fov;
|
||||
_nearClippingPlane = nearClippingPlane;
|
||||
_farClippingPlane = farClippingPlane;
|
||||
_worldUp = Vector3D<float>.UnitY;
|
||||
|
||||
UpdateCameraVectors();
|
||||
}
|
||||
|
||||
internal void UpdateAspect()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void UpdateCameraVectors()
|
||||
{
|
||||
var front = Vector3D.Normalize(new Vector3D<float>(
|
||||
MathF.Cos(_yaw.ToRadians()) * MathF.Cos(_pitch.ToRadians()),
|
||||
MathF.Sin(_pitch.ToRadians()),
|
||||
MathF.Sin(_yaw.ToRadians()) * MathF.Cos(_pitch.ToRadians())
|
||||
));
|
||||
var right = Vector3D.Normalize(Vector3D.Cross(front, _worldUp));
|
||||
var up = Vector3D.Normalize(Vector3D.Cross(right, front));
|
||||
|
||||
_intrinsicCoordinates = new Matrix3X3<float>(
|
||||
right.X, up.X, front.X,
|
||||
right.Y, up.Y, front.Y,
|
||||
right.Z, up.Z, front.Z
|
||||
);
|
||||
}
|
||||
}
|
18
src/EngineSharp/EngineSharp.csproj
Normal file
18
src/EngineSharp/EngineSharp.csproj
Normal file
@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\EngineSharp.Core\EngineSharp.Core\EngineSharp.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Silk.NET.Windowing" Version="2.22.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
21
src/EngineSharp/Program.cs
Normal file
21
src/EngineSharp/Program.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using EngineSharp.Core;
|
||||
using Silk.NET.Maths;
|
||||
using Silk.NET.Windowing;
|
||||
using GraphicsAPI = EngineSharp.Core.GraphicsAPI;
|
||||
|
||||
namespace EngineSharp;
|
||||
|
||||
static class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
var options = WindowOptions.Default with
|
||||
{
|
||||
Title = "EngineSharp Engine",
|
||||
Size = new Vector2D<int>(800, 600),
|
||||
};
|
||||
|
||||
var engine = EngineFactory.Create(GraphicsAPI.OpenGL, options);
|
||||
engine.Start();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user