diff --git a/.idea/.idea.Hypercube/.idea/indexLayout.xml b/.idea/.idea.Hypercube/.idea/indexLayout.xml index 7b08163..2a75c2c 100644 --- a/.idea/.idea.Hypercube/.idea/indexLayout.xml +++ b/.idea/.idea.Hypercube/.idea/indexLayout.xml @@ -1,7 +1,9 @@ - + + Resources + diff --git a/Hypercube.Client/Dependencies.cs b/Hypercube.Client/Dependencies.cs index 2e75cf9..29e4fc1 100644 --- a/Hypercube.Client/Dependencies.cs +++ b/Hypercube.Client/Dependencies.cs @@ -1,6 +1,7 @@ using Hypercube.Client.Graphics; using Hypercube.Client.Graphics.Rendering; using Hypercube.Client.Graphics.Texturing; +using Hypercube.Client.Graphics.Viewports; using Hypercube.Client.Input.Handler; using Hypercube.Client.Input.Manager; using Hypercube.Client.Runtimes; @@ -38,6 +39,9 @@ public static void Register(DependenciesContainer rootContainer) // Texturing rootContainer.Register(); + // Camera + rootContainer.Register(); + // Rendering rootContainer.Register(); diff --git a/Hypercube.Client/Graphics/Rendering/Renderer.Render.cs b/Hypercube.Client/Graphics/Rendering/Renderer.Render.cs index 215ada9..dc5a1c6 100644 --- a/Hypercube.Client/Graphics/Rendering/Renderer.Render.cs +++ b/Hypercube.Client/Graphics/Rendering/Renderer.Render.cs @@ -3,6 +3,8 @@ using Hypercube.Client.Graphics.Viewports; using Hypercube.Shared.Math; using Hypercube.Shared.Math.Box; +using Hypercube.Shared.Math.Matrix; +using Hypercube.Shared.Math.Vector; using Hypercube.Shared.Runtimes.Loop.Event; using OpenToolkit.Graphics.OpenGL4; @@ -40,6 +42,8 @@ private void OnLoad() _baseTexture = _textureManager.CreateHandler("/icon.png"); _baseTexture.Bind(); + _cameraManager.SetMainCamera(_cameraManager.CreateCamera2D(MainWindow.Size)); + _vbo = new BufferObject(BufferTarget.ArrayBuffer); _ebo = new BufferObject(BufferTarget.ElementArrayBuffer); _vao = new ArrayObject(); @@ -64,9 +68,10 @@ private void OnLoad() private void OnFrameUpdate(UpdateFrameEvent args) { #if DEBUG - _windowManager.WindowSetTitle(MainWindow, $"FPS: {_timing.Fps} | RealTime: {_timing.RealTime}"); + _windowManager.WindowSetTitle(MainWindow, $"FPS: {_timing.Fps} | RealTime: {_timing.RealTime} | cPos: {_cameraManager.MainCamera?.Position ?? null} | cRot: {_cameraManager.MainCamera?.Rotation ?? null}"); #endif _windowManager.PollEvents(); + _cameraManager.UpdateInput(_cameraManager.MainCamera, args.DeltaSeconds); } private void OnFrameRender(RenderFrameEvent args) @@ -83,14 +88,20 @@ private void OnFrameRender(RenderFrameEvent args) var colorG = new Color(0f, sin, 0f); var colorB = new Color(0f, 0f, sin); - DrawTexture(_baseTexture, new Box2(-1.0f, 1.0f, 0.0f, 0.0f), new Box2(0.0f, 1.0f, 1.0f, 0.0f), Color.White); - DrawTexture(_baseTexture, new Box2(0.0f, 1.0f, 1.0f, 0.0f), new Box2(0.0f, 1.0f, 1.0f, 0.0f), colorR); - DrawTexture(_baseTexture, new Box2(-1.0f, 0.0f, 0.0f, -1.0f), new Box2(0.0f, 1.0f, 1.0f, 0.0f), colorG); - DrawTexture(_baseTexture, new Box2(0.0f, 0.0f, 1.0f, -1.0f), new Box2(0.0f, 1.0f, 1.0f, 0.0f), colorB); + DrawTexture(_baseTexture, _baseTexture.Texture.QuadCrateTranslated(-Vector2.UnitY * 60f), new Box2(0.0f, 1.0f, 1.0f, 0.0f), Color.White); + DrawTexture(_baseTexture, _baseTexture.Texture.QuadCrateTranslated(Vector2.UnitX * 60f), new Box2(0.0f, 1.0f, 1.0f, 0.0f), colorR); + DrawTexture(_baseTexture, _baseTexture.Texture.QuadCrateTranslated(-Vector2.UnitX * 60f), new Box2(0.0f, 1.0f, 1.0f, 0.0f), colorG); + DrawTexture(_baseTexture, _baseTexture.Texture.QuadCrateTranslated(Vector2.UnitY * 60f), new Box2(0.0f, 1.0f, 1.0f, 0.0f), colorB); BatchUpdate(); + + var model = Matrix4X4.CreateTranslation(Vector2.Zero) * Matrix4X4.CreateRotationZ(0) * Matrix4X4.CreateScale(Vector2.One); + var view = Matrix4X4.CreateTranslation(0.0f, 0.0f, -3.0f); _baseShader.Use(); + _baseShader.SetUniform("model", model); + _baseShader.SetUniform("view", view); + _baseShader.SetUniform("projection", _cameraManager.Projection); _vao.Bind(); GL.DrawElements(BeginMode.Triangles, (int) _batchIndexIndex, DrawElementsType.UnsignedInt, 0); diff --git a/Hypercube.Client/Graphics/Rendering/Renderer.cs b/Hypercube.Client/Graphics/Rendering/Renderer.cs index 3e58e29..a350fa7 100644 --- a/Hypercube.Client/Graphics/Rendering/Renderer.cs +++ b/Hypercube.Client/Graphics/Rendering/Renderer.cs @@ -1,7 +1,7 @@ -using System.Collections.Frozen; -using Hypercube.Client.Graphics.Event; +using System.Collections.Frozen; using Hypercube.Client.Graphics.OpenGL; using Hypercube.Client.Graphics.Texturing; +using Hypercube.Client.Graphics.Viewports; using Hypercube.Client.Graphics.Windows; using Hypercube.Client.Graphics.Windows.Manager; using Hypercube.Shared.Dependency; @@ -22,6 +22,7 @@ public sealed partial class Renderer : IRenderer, IPostInject [Dependency] private readonly IEventBus _eventBus = default!; [Dependency] private readonly ITextureManager _textureManager = default!; [Dependency] private readonly ITiming _timing = default!; + [Dependency] private readonly ICameraManager _cameraManager = default!; [Dependency] private readonly IResourceManager _resourceManager = default!; private readonly ILogger _logger = LoggingManager.GetLogger("renderer"); diff --git a/Hypercube.Client/Graphics/Shading/IShader.cs b/Hypercube.Client/Graphics/Shading/IShader.cs index 4838e90..8881364 100644 --- a/Hypercube.Client/Graphics/Shading/IShader.cs +++ b/Hypercube.Client/Graphics/Shading/IShader.cs @@ -1,7 +1,12 @@ -namespace Hypercube.Client.Graphics.Shading; +using Hypercube.Shared.Math.Matrix; + +namespace Hypercube.Client.Graphics.Shading; public interface IShader { void Use(); + int GetUniformLocation(string name); void SetUniform(string name, int value); + void SetUniform(string name, Matrix4X4 value, bool transpose = false); + void SetUniform(int index, Matrix4X4 value, bool transpose = false); } \ No newline at end of file diff --git a/Hypercube.Client/Graphics/Shading/Shader.cs b/Hypercube.Client/Graphics/Shading/Shader.cs index 9ed479c..7e77782 100644 --- a/Hypercube.Client/Graphics/Shading/Shader.cs +++ b/Hypercube.Client/Graphics/Shading/Shader.cs @@ -1,8 +1,8 @@ -using Hypercube.Shared.Math.Vector; +using Hypercube.Shared.Math.Matrix; +using Hypercube.Shared.Math.Vector; using Hypercube.Shared.Resources; using Hypercube.Shared.Resources.Manager; using OpenToolkit.Graphics.OpenGL4; -using Vector2 = Hypercube.Shared.Math.Vector.Vector2; namespace Hypercube.Client.Graphics.Shading; @@ -57,12 +57,17 @@ public void Use() GL.UseProgram(_handle); } + public int GetUniformLocation(string name) + { + return GL.GetUniformLocation(_handle, name); + } + public void SetUniform(string name, int value) { GL.UseProgram(_handle); GL.Uniform1(_uniformLocations[name], value); } - + public void SetUniform(string name, Vector2Int value) { GL.UseProgram(_handle); @@ -80,6 +85,18 @@ public void SetUniform(string name, Vector2 value) GL.UseProgram(_handle); GL.Uniform2(_uniformLocations[name], value.X, value.Y); } + + public void SetUniform(string name, Matrix4X4 value, bool transpose = false) + { + SetUniform(GL.GetUniformLocation(_handle, name), value, transpose); + } + + public void SetUniform(int index, Matrix4X4 value, bool transpose = false) + { + var matrix = transpose ? Matrix4X4.Transpose(value) : new Matrix4X4(value); + GL.UseProgram(_handle); + GL.UniformMatrix4(index, 1, false, matrix.ToArray()); + } private int CreateShader(string source, ShaderType type) { diff --git a/Hypercube.Client/Graphics/Vertex.cs b/Hypercube.Client/Graphics/Vertex.cs index 62523b4..9ba010f 100644 --- a/Hypercube.Client/Graphics/Vertex.cs +++ b/Hypercube.Client/Graphics/Vertex.cs @@ -12,8 +12,8 @@ public readonly struct Vertex private static readonly Color DefaultColor = Color.White; public readonly Vector3 Position; - public readonly Vector2 UVCoords; public readonly Color Color; + public readonly Vector2 UVCoords; public Vertex(Vector3 position, Vector2 uvCoords, Color color) { diff --git a/Hypercube.Client/Graphics/Viewports/Camera2D.cs b/Hypercube.Client/Graphics/Viewports/Camera2D.cs index 11689cc..fde8ce8 100644 --- a/Hypercube.Client/Graphics/Viewports/Camera2D.cs +++ b/Hypercube.Client/Graphics/Viewports/Camera2D.cs @@ -1,37 +1,64 @@ -using Hypercube.Shared.Math.Box; -using Hypercube.Shared.Math.Matrix; +using Hypercube.Shared.Math.Matrix; using Hypercube.Shared.Math.Vector; namespace Hypercube.Client.Graphics.Viewports; public class Camera2D : ICamera { - public float ZFar { get; private set; } - public float ZNear { get; private set; } - public Vector2 Position { get; private set; } - public float Zoom { get; private set; } + public Vector3 Position { get; private set; } + public Vector3 Rotation { get; private set; } + public Vector3 Scale { get; private set; } = Vector3.One; + + private readonly float _zFar; + private readonly float _zNear; + private Vector2Int Size { get; set; } - public Matrix4X4 Projection; + + private Vector2 HalfSize => Size / 2f; + public Matrix4X4 Projection { get; private set; } - public void SetPosition(Vector2 position) + public Camera2D(Vector2Int size, Vector2 position, float zNear, float zFar) + { + Size = size; + Position = new Vector3(position); + _zNear = zNear; + _zFar = zFar; + + UpdateProjection(); + } + + public void SetSize(Vector2Int size) + { + Size = size; + UpdateProjection(); + } + + public void SetPosition(Vector3 position) { Position = position; UpdateProjection(); } - public void SetZoom(float zoom) + public void SetRotation(Vector3 rotation) + { + Rotation = Rotation.WithZ(rotation.Z); + UpdateProjection(); + } + + public void SetScale(Vector3 scale) { - Zoom = zoom; + Scale = scale; UpdateProjection(); } private void UpdateProjection() { - var size = new Box2(); + var projection = Matrix4X4.CreateOrthographic(Size, _zNear, _zFar); - var projection = Matrix4X4.CreateOrthographic(size, ZNear, ZFar); - var scale = Matrix4X4.CreateScale(Zoom); - - Projection = projection * scale; + var translate = Matrix4X4.CreateTranslation(Position); + var rotation = Matrix4X4.CreateRotationZ(Rotation.Z); + var scale = Matrix4X4.CreateScale(Scale); + + Projection = projection * translate * rotation * scale; } } \ No newline at end of file diff --git a/Hypercube.Client/Graphics/Viewports/CameraManager.cs b/Hypercube.Client/Graphics/Viewports/CameraManager.cs index 0213d02..6b8cdba 100644 --- a/Hypercube.Client/Graphics/Viewports/CameraManager.cs +++ b/Hypercube.Client/Graphics/Viewports/CameraManager.cs @@ -1,20 +1,71 @@ -using Hypercube.Shared.Dependency; -using Hypercube.Shared.EventBus; -using Hypercube.Shared.Runtimes.Loop.Event; +using Hypercube.Client.Input; +using Hypercube.Client.Input.Handler; +using Hypercube.Shared.Dependency; +using Hypercube.Shared.Math.Matrix; +using Hypercube.Shared.Math.Vector; namespace Hypercube.Client.Graphics.Viewports; -public class CameraManager : ICameraManager, IPostInject +public class CameraManager : ICameraManager { - [Dependency] private readonly IEventBus _eventBus = default!; + [Dependency] private readonly IInputHandler _inputHandler = default!; - public void PostInject() + public ICamera? MainCamera { get; private set; } + public Matrix4X4 Projection => MainCamera?.Projection ?? Matrix4X4.Identity; + + public void UpdateInput(ICamera? camera, float delta) { - _eventBus.Subscribe(OnUpdate); + if (camera is null) + return; + + // Debug camera controls + var position = camera.Position; + var rotation = camera.Rotation; + var scale = camera.Scale; + + var speed = 20f; + + if (_inputHandler.IsKeyDown(Key.W)) + position -= Vector3.UnitY * speed * delta; + + if (_inputHandler.IsKeyDown(Key.S)) + position += Vector3.UnitY * speed * delta; + + if (_inputHandler.IsKeyDown(Key.A)) + position += Vector3.UnitX * speed * delta; + + if (_inputHandler.IsKeyDown(Key.D)) + position -= Vector3.UnitX * speed * delta; + + if (_inputHandler.IsKeyDown(Key.Q)) + rotation -= Vector3.UnitZ * delta; + + if (_inputHandler.IsKeyDown(Key.E)) + rotation += Vector3.UnitZ * delta; + + if (_inputHandler.IsKeyDown(Key.T)) + scale -= Vector3.One * delta; + + if (_inputHandler.IsKeyDown(Key.Y)) + scale += Vector3.One * delta; + + camera.SetPosition(position); + camera.SetRotation(rotation); + camera.SetScale(scale); } - private void OnUpdate(UpdateFrameEvent args) + public void SetMainCamera(ICamera camera) { - + MainCamera = camera; + } + + public ICamera CreateCamera2D(Vector2Int size) + { + return CreateCamera2D(size, Vector2.Zero); + } + + public ICamera CreateCamera2D(Vector2Int size, Vector2 position, float zNear = 0.1f, float zFar = 100f) + { + return new Camera2D(size, position, zNear, zFar); } } \ No newline at end of file diff --git a/Hypercube.Client/Graphics/Viewports/ICamera.cs b/Hypercube.Client/Graphics/Viewports/ICamera.cs index 0c26f15..fd8d030 100644 --- a/Hypercube.Client/Graphics/Viewports/ICamera.cs +++ b/Hypercube.Client/Graphics/Viewports/ICamera.cs @@ -1,6 +1,17 @@ -namespace Hypercube.Client.Graphics.Viewports; +using Hypercube.Shared.Math.Matrix; +using Hypercube.Shared.Math.Vector; + +namespace Hypercube.Client.Graphics.Viewports; public interface ICamera { + Matrix4X4 Projection { get; } + + Vector3 Position { get; } + Vector3 Rotation { get; } + Vector3 Scale { get; } + void SetPosition(Vector3 position); + void SetRotation(Vector3 rotation); + void SetScale(Vector3 scale); } \ No newline at end of file diff --git a/Hypercube.Client/Graphics/Viewports/ICameraManager.cs b/Hypercube.Client/Graphics/Viewports/ICameraManager.cs index 88db334..035fc39 100644 --- a/Hypercube.Client/Graphics/Viewports/ICameraManager.cs +++ b/Hypercube.Client/Graphics/Viewports/ICameraManager.cs @@ -1,6 +1,13 @@ -namespace Hypercube.Client.Graphics.Viewports; +using Hypercube.Shared.Math.Matrix; +using Hypercube.Shared.Math.Vector; + +namespace Hypercube.Client.Graphics.Viewports; public interface ICameraManager { - + ICamera? MainCamera { get; } + Matrix4X4 Projection { get; } + void SetMainCamera(ICamera camera); + ICamera CreateCamera2D(Vector2Int size); + void UpdateInput(ICamera? camera, float delta); } \ No newline at end of file diff --git a/Hypercube.Client/Graphics/Windows/Manager/GlfwWindowManager.Callbacks.cs b/Hypercube.Client/Graphics/Windows/Manager/GlfwWindowManager.Callbacks.cs index 3eb4225..22e20f1 100644 --- a/Hypercube.Client/Graphics/Windows/Manager/GlfwWindowManager.Callbacks.cs +++ b/Hypercube.Client/Graphics/Windows/Manager/GlfwWindowManager.Callbacks.cs @@ -1,22 +1,43 @@ -using Hypercube.Client.Graphics.Event; -using Hypercube.Client.Input; +using Hypercube.Client.Input; using Hypercube.Client.Utilities; using OpenTK.Windowing.GraphicsLibraryFramework; using GlfwKeyModifiers = OpenTK.Windowing.GraphicsLibraryFramework.KeyModifiers; using KeyModifiers = Hypercube.Client.Input.KeyModifiers; +using static OpenTK.Windowing.GraphicsLibraryFramework.GLFWCallbacks; namespace Hypercube.Client.Graphics.Windows.Manager; public sealed unsafe partial class GlfwWindowManager { - private void OnWindowClosed(Window* window) + private ErrorCallback? _errorCallback; + + private KeyCallback? _keyCallback; + + private WindowCloseCallback? _windowCloseCallback; + private WindowSizeCallback? _windowSizeCallback; + private WindowFocusCallback? _windowFocusCallback; + + /// + /// GC doesn't think our callbacks are stored anywhere, + /// so it cleans them up, + /// we need to indicate that there is a link to them so they don't get lost. + /// + private void HandleCallbacks() { - if (!TryGetWindow(window, out var registration)) - return; + _errorCallback = OnErrorHandled; + + _keyCallback = OnWindowKeyHandled; - _renderer.CloseWindow(registration); + _windowCloseCallback = OnWindowClosed; + _windowSizeCallback = OnWindowResized; + _windowFocusCallback = OnWindowFocusChanged; } - + + private void OnErrorHandled(ErrorCode error, string description) + { + _logger.Error(GLFWHelper.FormatError(error, description)); + } + private void OnWindowKeyHandled(Window* window, Keys glfwKey, int scanCode, InputAction action, GlfwKeyModifiers mods) { var key = (Key)glfwKey; @@ -49,6 +70,14 @@ private void OnWindowKeyHandled(Window* window, Keys glfwKey, int scanCode, Inpu (KeyModifiers)mods, scanCode)); } + + private void OnWindowClosed(Window* window) + { + if (!TryGetWindow(window, out var registration)) + return; + + _renderer.CloseWindow(registration); + } private void OnWindowResized(Window* window, int width, int height) { diff --git a/Hypercube.Client/Graphics/Windows/Manager/GlfwWindowManager.Init.cs b/Hypercube.Client/Graphics/Windows/Manager/GlfwWindowManager.Init.cs index 6509d6c..46c21fc 100644 --- a/Hypercube.Client/Graphics/Windows/Manager/GlfwWindowManager.Init.cs +++ b/Hypercube.Client/Graphics/Windows/Manager/GlfwWindowManager.Init.cs @@ -14,7 +14,7 @@ private bool GlfwInit() } // Set callback to handle errors - GLFW.SetErrorCallback(OnErrorHandled); + GLFW.SetErrorCallback(_errorCallback); _initialized = true; @@ -22,9 +22,4 @@ private bool GlfwInit() _logger.EngineInfo($"Initialize, version: {version}"); return true; } - - private void OnErrorHandled(ErrorCode error, string description) - { - _logger.Error(GLFWHelper.FormatError(error, description)); - } } \ No newline at end of file diff --git a/Hypercube.Client/Graphics/Windows/Manager/GlfwWindowManager.Window.cs b/Hypercube.Client/Graphics/Windows/Manager/GlfwWindowManager.Window.cs index 5215b72..a7df78a 100644 --- a/Hypercube.Client/Graphics/Windows/Manager/GlfwWindowManager.Window.cs +++ b/Hypercube.Client/Graphics/Windows/Manager/GlfwWindowManager.Window.cs @@ -120,7 +120,7 @@ private GlfwWindowRegistration WindowSetup(Window* window, WindowCreateSettings Pointer = window, Id = new WindowId(_nextWindowId++), - Ratio = framebufferSize.Ratio, + Ratio = framebufferSize.AspectRatio, Size = size, FramebufferSize = framebufferSize }; @@ -132,10 +132,10 @@ private GlfwWindowRegistration WindowSetup(Window* window, WindowCreateSettings SetWindowIcons(registration, settings.WindowImages.ToList()); // Setting callbacks - GLFW.SetKeyCallback(window, OnWindowKeyHandled); - GLFW.SetWindowCloseCallback(window, OnWindowClosed); - GLFW.SetWindowSizeCallback(window, OnWindowResized); - GLFW.SetWindowFocusCallback(window, OnWindowFocusChanged); + GLFW.SetKeyCallback(window, _keyCallback); + GLFW.SetWindowCloseCallback(window, _windowCloseCallback); + GLFW.SetWindowSizeCallback(window, _windowSizeCallback); + GLFW.SetWindowFocusCallback(window, _windowFocusCallback); return registration; } diff --git a/Hypercube.Client/Graphics/Windows/Manager/GlfwWindowManager.cs b/Hypercube.Client/Graphics/Windows/Manager/GlfwWindowManager.cs index 8f38686..65d3a4e 100644 --- a/Hypercube.Client/Graphics/Windows/Manager/GlfwWindowManager.cs +++ b/Hypercube.Client/Graphics/Windows/Manager/GlfwWindowManager.cs @@ -26,6 +26,9 @@ public bool Init() { DependencyManager.Inject(this); + // We don't let GC take our callbacks + HandleCallbacks(); + if (!GlfwInit()) return false; diff --git a/Hypercube.Client/Input/Handler/IInputHandler.cs b/Hypercube.Client/Input/Handler/IInputHandler.cs index 635e552..f0ff620 100644 --- a/Hypercube.Client/Input/Handler/IInputHandler.cs +++ b/Hypercube.Client/Input/Handler/IInputHandler.cs @@ -13,4 +13,5 @@ public interface IInputHandler // TODO: Create Analyzer to allow access only for IWindowManager implementation void SendKeyState(KeyStateChangedArgs changedArgs); + bool IsKeyDown(Key key); } \ No newline at end of file diff --git a/Hypercube.Client/Input/Handler/InputHandler.cs b/Hypercube.Client/Input/Handler/InputHandler.cs index f2666fc..a11d733 100644 --- a/Hypercube.Client/Input/Handler/InputHandler.cs +++ b/Hypercube.Client/Input/Handler/InputHandler.cs @@ -6,7 +6,8 @@ public sealed class InputHandler : IInputHandler { public event Action? KeyUp; public event Action? KeyDown; - + + private readonly HashSet _keysDown = new(); private readonly ILogger _logger = LoggingManager.GetLogger("input_handler"); public void SendKeyState(KeyStateChangedArgs changedArgs) @@ -23,10 +24,17 @@ public void SendKeyState(KeyStateChangedArgs changedArgs) if (changedArgs.Pressed) { - KeyUp?.Invoke(changedArgs); + KeyDown?.Invoke(changedArgs); + _keysDown.Add(changedArgs.Key); return; } - KeyDown?.Invoke(changedArgs); + _keysDown.Remove(changedArgs.Key); + KeyUp?.Invoke(changedArgs); + } + + public bool IsKeyDown(Key key) + { + return _keysDown.Contains(key); } } \ No newline at end of file diff --git a/Hypercube.Shared.Math/Angle.cs b/Hypercube.Shared.Math/Angle.cs index 47f6552..e52a056 100644 --- a/Hypercube.Shared.Math/Angle.cs +++ b/Hypercube.Shared.Math/Angle.cs @@ -1,8 +1,16 @@ -namespace Hypercube.Shared.Math; +using System.Runtime.CompilerServices; + +namespace Hypercube.Shared.Math; public readonly struct Angle(double theta) { public static readonly Angle Zero = new(0); public readonly double Theta = theta; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator float(Angle angle) + { + return (float)angle.Theta; + } } \ No newline at end of file diff --git a/Hypercube.Shared.Math/Color.cs b/Hypercube.Shared.Math/Color.cs index a926016..6ecd9ee 100644 --- a/Hypercube.Shared.Math/Color.cs +++ b/Hypercube.Shared.Math/Color.cs @@ -1,8 +1,10 @@ using System.Globalization; +using System.Runtime.InteropServices; using Hypercube.Shared.Math.Vector; namespace Hypercube.Shared.Math; +[StructLayout(LayoutKind.Sequential)] public readonly struct Color { public static readonly Color White = new(1f, 1f, 1f); diff --git a/Hypercube.Shared.Math/Hypercube.Shared.Math.csproj b/Hypercube.Shared.Math/Hypercube.Shared.Math.csproj index 8f59722..b60e9ec 100644 --- a/Hypercube.Shared.Math/Hypercube.Shared.Math.csproj +++ b/Hypercube.Shared.Math/Hypercube.Shared.Math.csproj @@ -9,6 +9,7 @@ + diff --git a/Hypercube.Shared.Math/Matrix/Matrix3X3.Compatibility.cs b/Hypercube.Shared.Math/Matrix/Matrix3X3.Compatibility.cs new file mode 100644 index 0000000..1d6affa --- /dev/null +++ b/Hypercube.Shared.Math/Matrix/Matrix3X3.Compatibility.cs @@ -0,0 +1,39 @@ +using System.Runtime.CompilerServices; +using OpenTK.Mathematics; + +namespace Hypercube.Shared.Math.Matrix; + +public partial struct Matrix3X3 +{ + /* + * OpenTK Compatibility + */ + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Matrix3(Matrix3X3 matrix3) + { + return new Matrix3(matrix3.Row0, matrix3.Row1, matrix3.Row2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Matrix3X3(Matrix3 matrix3) + { + return new Matrix3X3(matrix3.Row0, matrix3.Row1, matrix3.Row2); + } + + /* + * OpenToolkit Compatibility + */ + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator OpenToolkit.Mathematics.Matrix3(Matrix3X3 matrix3) + { + return new OpenToolkit.Mathematics.Matrix3(matrix3.Row0, matrix3.Row1, matrix3.Row2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Matrix3X3(OpenToolkit.Mathematics.Matrix3 matrix3) + { + return new Matrix3X3(matrix3.Row0, matrix3.Row1, matrix3.Row2); + } +} \ No newline at end of file diff --git a/Hypercube.Shared.Math/Matrix/Matrix3X3.cs b/Hypercube.Shared.Math/Matrix/Matrix3X3.cs index f5b1394..ddf205f 100644 --- a/Hypercube.Shared.Math/Matrix/Matrix3X3.cs +++ b/Hypercube.Shared.Math/Matrix/Matrix3X3.cs @@ -1,25 +1,28 @@ using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using Hypercube.Shared.Math.Vector; namespace Hypercube.Shared.Math.Matrix; -public struct Matrix3X3(Vector3 x, Vector3 y, Vector3 z) +// TODO: May be it's can be immutable, and also layout broken +[StructLayout(LayoutKind.Sequential)] +public partial struct Matrix3X3 { - private const int IndexRaw0 = 0; - private const int IndexRaw1 = 1; - private const int IndexRaw2 = 2; + private const int IndexRow0 = 0; + private const int IndexRow1 = 1; + private const int IndexRow2 = 2; - private const int IndexColum0 = 0; - private const int IndexColum1 = 1; - private const int IndexColum2 = 2; + private const int IndexColumn0 = 0; + private const int IndexColumn1 = 1; + private const int IndexColumn2 = 2; public static Matrix3X3 Zero => new(Vector3.Zero); public static Matrix3X3 One => new(Vector3.One); - public static Matrix3X3 Identity => new(Vector3.Right, Vector3.Up, Vector3.Forward); + public static Matrix3X3 Identity => new(Vector3.UnitX, Vector3.UnitY, Vector3.UnitZ); - public Vector3 Raw0 = x; - public Vector3 Raw1 = y; - public Vector3 Raw2 = z; + public Vector3 Row0; + public Vector3 Row1; + public Vector3 Row2; /// /// Matrix x: 0, y: 0 element. @@ -27,9 +30,9 @@ public struct Matrix3X3(Vector3 x, Vector3 y, Vector3 z) public float M00 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw0.X; + get => Row0.X; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw0 = Raw0.WithX(value); + set => Row0 = Row0.WithX(value); } /// @@ -38,9 +41,9 @@ public float M00 public float M01 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw0.Y; + get => Row0.Y; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw0 = Raw0.WithY(value); + set => Row0 = Row0.WithY(value); } /// @@ -49,9 +52,9 @@ public float M01 public float M02 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw0.Z; + get => Row0.Z; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw0 = Raw0.WithZ(value); + set => Row0 = Row0.WithZ(value); } /// @@ -60,9 +63,9 @@ public float M02 public float M10 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw1.X; + get => Row1.X; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw1 = Raw1.WithX(value); + set => Row1 = Row1.WithX(value); } /// @@ -71,9 +74,9 @@ public float M10 public float M11 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw1.Y; + get => Row1.Y; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw1 = Raw1.WithY(value); + set => Row1 = Row1.WithY(value); } /// @@ -82,9 +85,9 @@ public float M11 public float M12 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw1.Z; + get => Row1.Z; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw1 = Raw1.WithZ(value); + set => Row1 = Row1.WithZ(value); } /// @@ -93,9 +96,9 @@ public float M12 public float M20 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw2.X; + get => Row2.X; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw2 = Raw2.WithX(value); + set => Row2 = Row2.WithX(value); } /// @@ -104,9 +107,9 @@ public float M20 public float M21 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw2.Y; + get => Row2.Y; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw2 = Raw2.WithY(value); + set => Row2 = Row2.WithY(value); } /// @@ -115,34 +118,34 @@ public float M21 public float M22 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw2.Z; + get => Row2.Z; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw2 = Raw2.WithZ(value); + set => Row2 = Row2.WithZ(value); } public float this[int raw, int colum] { get => raw switch { - IndexRaw0 => colum switch + IndexRow0 => colum switch { - IndexColum0 => M00, - IndexColum1 => M01, - IndexColum2 => M02, + IndexColumn0 => M00, + IndexColumn1 => M01, + IndexColumn2 => M02, _ => throw new ArgumentOutOfRangeException(nameof(colum), colum, null) }, - IndexRaw1 => colum switch + IndexRow1 => colum switch { - IndexColum0 => M10, - IndexColum1 => M11, - IndexColum2 => M12, + IndexColumn0 => M10, + IndexColumn1 => M11, + IndexColumn2 => M12, _ => throw new ArgumentOutOfRangeException(nameof(colum), colum, null) }, - IndexRaw2 => colum switch + IndexRow2 => colum switch { - IndexColum0 => M20, - IndexColum1 => M21, - IndexColum2 => M22, + IndexColumn0 => M20, + IndexColumn1 => M21, + IndexColumn2 => M22, _ => throw new ArgumentOutOfRangeException(nameof(colum), colum, null) }, _ => throw new ArgumentOutOfRangeException(nameof(raw), raw, null) @@ -151,18 +154,18 @@ public float M22 { switch (raw) { - case IndexRaw0: + case IndexRow0: switch (colum) { - case IndexColum0: + case IndexColumn0: M00 = value; break; - case IndexColum1: + case IndexColumn1: M01 = value; break; - case IndexColum2: + case IndexColumn2: M02 = value; break; @@ -171,18 +174,18 @@ public float M22 } break; - case IndexRaw1: + case IndexRow1: switch (colum) { - case IndexColum0: + case IndexColumn0: M10 = value; break; - case IndexColum1: + case IndexColumn1: M11 = value; break; - case IndexColum2: + case IndexColumn2: M12 = value; break; @@ -191,18 +194,18 @@ public float M22 } break; - case IndexRaw2: + case IndexRow2: switch (colum) { - case IndexColum0: + case IndexColumn0: M20 = value; break; - case IndexColum1: + case IndexColumn1: M21 = value; break; - case IndexColum2: + case IndexColumn2: M22 = value; break; @@ -216,11 +219,33 @@ public float M22 } } } + /// + /// Creates 3x3 matrix + /// + /// x.X | x.Y | x.Z + /// y.X | y.Y | y.Z + /// z.X | z.Y | z.Z + /// + /// + public Matrix3X3(Vector3 x, Vector3 y, Vector3 z) + { + Row0 = x; + Row1 = y; + Row2 = z; + } public Matrix3X3(Vector3 value) : this(value, value, value) { } + /// + /// Creates 3x3 matrix + /// + /// m00 | m01 | m02 + /// m10 | m11 | m12 + /// m20 | m21 | m22 + /// + /// public Matrix3X3(float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21, float m22) : this(new Vector3(m00, m01, m02), @@ -377,6 +402,6 @@ public static Matrix3X3 CreateTransform(Vector2 position, Angle angle, Vector2 s public static Vector3 operator *(Matrix3X3 a, Vector3 b) { - return a.Raw0 * b.X + a.Raw1 * b.Y + a.Raw2 * b.Z; + return a.Row0 * b.X + a.Row1 * b.Y + a.Row2 * b.Z; } } \ No newline at end of file diff --git a/Hypercube.Shared.Math/Matrix/Matrix4X4.Compatibility.cs b/Hypercube.Shared.Math/Matrix/Matrix4X4.Compatibility.cs new file mode 100644 index 0000000..d626311 --- /dev/null +++ b/Hypercube.Shared.Math/Matrix/Matrix4X4.Compatibility.cs @@ -0,0 +1,38 @@ +using System.Runtime.CompilerServices; +using OpenTK.Mathematics; + +namespace Hypercube.Shared.Math.Matrix; + +public partial struct Matrix4X4 +{ + /* + * OpenTK Compatibility + */ + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator OpenTK.Mathematics.Matrix4(Matrix4X4 matrix4X4) + { + return new OpenTK.Mathematics.Matrix4(matrix4X4.Row0, matrix4X4.Row1, matrix4X4.Row2, matrix4X4.Row3); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Matrix4X4(Matrix4 matrix4) + { + return new Matrix4X4(matrix4.Row0, matrix4.Row1, matrix4.Row2, matrix4.Row3); + } + + /* + * Open Toolkit Compatibility + */ + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator OpenToolkit.Mathematics.Matrix4(Matrix4X4 matrix4X4) + { + return new OpenToolkit.Mathematics.Matrix4(matrix4X4.Row0, matrix4X4.Row1, matrix4X4.Row2, matrix4X4.Row3); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Matrix4X4(OpenToolkit.Mathematics.Matrix4 matrix4) + { + return new Matrix4X4(matrix4.Row0, matrix4.Row1, matrix4.Row2, matrix4.Row3); + } +} \ No newline at end of file diff --git a/Hypercube.Shared.Math/Matrix/Matrix4X4.cs b/Hypercube.Shared.Math/Matrix/Matrix4X4.cs index b2d466b..17cef3d 100644 --- a/Hypercube.Shared.Math/Matrix/Matrix4X4.cs +++ b/Hypercube.Shared.Math/Matrix/Matrix4X4.cs @@ -1,49 +1,47 @@ using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using Hypercube.Shared.Math.Box; using Hypercube.Shared.Math.Vector; namespace Hypercube.Shared.Math.Matrix; -public struct Matrix4X4(Vector4 x, Vector4 y, Vector4 z, Vector4 w) : IEquatable +[StructLayout(LayoutKind.Sequential)] +public partial struct Matrix4X4 : IEquatable { public static Matrix4X4 Zero => new(Vector4.Zero); public static Matrix4X4 One => new(Vector4.One); - public static Matrix4X4 Identity => new( - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1); - - public Vector4 Raw0 = x; - public Vector4 Raw1 = y; - public Vector4 Raw2 = z; - public Vector4 Raw3 = w; - - public Vector4 Colum0 => new(M00, M10, M20, M30); - public Vector4 Colum1 => new(M01, M11, M21, M31); - public Vector4 Colum2 => new(M02, M12, M22, M32); - public Vector4 Colum3 => new(M03, M13, M23, M33); - + public static Matrix4X4 Identity => new(Vector4.UnitX, Vector4.UnitY, Vector4.UnitZ, Vector4.UnitW); + + public Vector4 Row0; + public Vector4 Row1; + public Vector4 Row2; + public Vector4 Row3; + + public Vector4 Column0 => new(M00, M10, M20, M30); + public Vector4 Column1 => new(M01, M11, M21, M31); + public Vector4 Column2 => new(M02, M12, M22, M32); + public Vector4 Column3 => new(M03, M13, M23, M33); + /// /// Matrix x: 0, y: 0 element. /// public float M00 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw0.X; + get => Row0.X; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw0 = Raw0.WithX(value); + set => Row0 = Row0.WithX(value); } - + /// /// Matrix x: 1, y: 0 element. /// public float M01 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw0.Y; + get => Row0.Y; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw0 = Raw0.WithY(value); + set => Row0 = Row0.WithY(value); } /// @@ -52,9 +50,9 @@ public float M01 public float M02 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw0.Z; + get => Row0.Z; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw0 = Raw0.WithZ(value); + set => Row0 = Row0.WithZ(value); } /// @@ -63,147 +61,170 @@ public float M02 public float M03 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw0.W; + get => Row0.W; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw0 = Raw0.WithW(value); + set => Row0 = Row0.WithW(value); } - + /// /// Matrix x: 0, y: 1 element. /// public float M10 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw1.X; + get => Row1.X; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw1 = Raw1.WithX(value); + set => Row1 = Row1.WithX(value); } - + /// /// Matrix x: 1, y: 1 element. /// public float M11 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw1.Y; + get => Row1.Y; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw1 = Raw1.WithY(value); + set => Row1 = Row1.WithY(value); } - + /// /// Matrix x: 2, y: 1 element. /// public float M12 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw1.Z; + get => Row1.Z; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw1 = Raw1.WithZ(value); + set => Row1 = Row1.WithZ(value); } - + /// /// Matrix x: 3, y: 1 element. /// public float M13 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw1.W; + get => Row1.W; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw1 = Raw1.WithW(value); + set => Row1 = Row1.WithW(value); } - + /// /// Matrix x: 0, y: 2 element. /// public float M20 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw2.X; + get => Row2.X; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw2 = Raw2.WithX(value); + set => Row2 = Row2.WithX(value); } - + /// /// Matrix x: 1, y: 2 element. /// public float M21 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw2.Y; + get => Row2.Y; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw2 = Raw2.WithY(value); + set => Row2 = Row2.WithY(value); } - + /// /// Matrix x: 2, y: 2 element. /// public float M22 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw2.Z; + get => Row2.Z; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw2 = Raw2.WithZ(value); + set => Row2 = Row2.WithZ(value); } - + /// /// Matrix x: 3, y: 2 element. /// public float M23 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw2.W; + get => Row2.W; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw2 = Raw2.WithW(value); + set => Row2 = Row2.WithW(value); } - + /// /// Matrix x: 0, y: 3 element. /// public float M30 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw3.X; + get => Row3.X; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw3 = Raw3.WithX(value); + set => Row3 = Row3.WithX(value); } - + /// /// Matrix x: 1, y: 3 element. /// public float M31 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw3.Y; + get => Row3.Y; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw3 = Raw3.WithY(value); + set => Row3 = Row3.WithY(value); } - + /// /// Matrix x: 2, y: 3 element. /// - public float M32 + public float M32 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw3.Z; + get => Row3.Z; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw3 = Raw3.WithZ(value); + set => Row3 = Row3.WithZ(value); } - + /// /// Matrix x: 3, y: 3 element. /// public float M33 { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Raw3.W; + get => Row3.W; [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Raw3 = Raw3.WithW(value); + set => Row3 = Row3.WithW(value); } - + /// + /// Creates new matrix 4x4 + /// + /// Row0.X | Row0.Y | Row0.Z | Row0.W + /// Row1.X | Row1.Y | Row1.Z | Row1.W + /// Row2.X | Row2.Y | Row2.Z | Row2.W + /// Row2.X | Row2.Y | Row2.Z | Row2.W + /// + /// + /// Row 0 + /// Row 1 + /// Row 2 + /// Row 3 + public Matrix4X4(Vector4 x, Vector4 y, Vector4 z, Vector4 w) + { + Row0 = x; + Row1 = y; + Row2 = z; + Row3 = w; + } + /// + /// Creates new matrix with all rows is "" + /// + /// Vector4 to make rows out of public Matrix4X4(Vector4 value) : this(value, value, value, value) { } - + /// /// Creating matrix /// @@ -223,16 +244,27 @@ public Matrix4X4(float m00, float m01, float m02, float m03, { } - public Matrix4X4(Matrix4X4 matrix4X4) : this(matrix4X4.Raw0, matrix4X4.Raw1, matrix4X4.Raw2, matrix4X4.Raw3) + public Matrix4X4(Matrix4X4 matrix4X4) : this(matrix4X4.Row0, matrix4X4.Row1, matrix4X4.Row2, matrix4X4.Row3) { } - + public bool Equals(Matrix4X4 other) { - return Raw0.Equals(other.Raw0) && - Raw1.Equals(other.Raw1) && - Raw2.Equals(other.Raw2) && - Raw3.Equals(other.Raw3); + return Row0.Equals(other.Row0) && + Row1.Equals(other.Row1) && + Row2.Equals(other.Row2) && + Row3.Equals(other.Row3); + } + + public float[] ToArray() + { + return new float[] + { + M00, M01, M02, M03, + M10, M11, M12, M13, + M20, M21, M22, M23, + M30, M31, M32, M33 + }; } public override bool Equals(object? obj) @@ -242,48 +274,48 @@ public override bool Equals(object? obj) public override int GetHashCode() { - return HashCode.Combine(Raw0, Raw1, Raw2, Raw3); + return HashCode.Combine(Row0, Row1, Row2, Row3); } - + public override string ToString() { - return $"{Raw0}\n{Raw1}\n{Raw2}\n{Raw3}"; + return $"{Row0}\n{Row1}\n{Row2}\n{Row3}"; } public static Matrix4X4 operator *(Matrix4X4 a, Matrix4X4 b) { var result = Zero; - result.M00 = (a.Raw0 * b.Colum0).Sum(); - result.M01 = (a.Raw0 * b.Colum1).Sum(); - result.M02 = (a.Raw0 * b.Colum2).Sum(); - result.M03 = (a.Raw0 * b.Colum3).Sum(); + result.M00 = (a.Row0 * b.Column0).Sum(); + result.M01 = (a.Row0 * b.Column1).Sum(); + result.M02 = (a.Row0 * b.Column2).Sum(); + result.M03 = (a.Row0 * b.Column3).Sum(); + + result.M10 = (a.Row1 * b.Column0).Sum(); + result.M11 = (a.Row1 * b.Column1).Sum(); + result.M12 = (a.Row1 * b.Column2).Sum(); + result.M13 = (a.Row1 * b.Column3).Sum(); + + result.M20 = (a.Row2 * b.Column0).Sum(); + result.M21 = (a.Row2 * b.Column1).Sum(); + result.M22 = (a.Row2 * b.Column2).Sum(); + result.M23 = (a.Row2 * b.Column3).Sum(); + + result.M30 = (a.Row3 * b.Column0).Sum(); + result.M31 = (a.Row3 * b.Column1).Sum(); + result.M32 = (a.Row3 * b.Column2).Sum(); + result.M33 = (a.Row3 * b.Column3).Sum(); - result.M10 = (a.Raw1 * b.Colum0).Sum(); - result.M11 = (a.Raw1 * b.Colum1).Sum(); - result.M12 = (a.Raw1 * b.Colum2).Sum(); - result.M13 = (a.Raw1 * b.Colum3).Sum(); - - result.M20 = (a.Raw2 * b.Colum0).Sum(); - result.M21 = (a.Raw2 * b.Colum1).Sum(); - result.M22 = (a.Raw2 * b.Colum2).Sum(); - result.M23 = (a.Raw2 * b.Colum3).Sum(); - - result.M30 = (a.Raw3 * b.Colum0).Sum(); - result.M31 = (a.Raw3 * b.Colum1).Sum(); - result.M32 = (a.Raw3 * b.Colum2).Sum(); - result.M33 = (a.Raw3 * b.Colum3).Sum(); - return result; } - + public static Vector4 operator *(Matrix4X4 a, Vector4 b) { return new Vector4( - (a.Raw0 * b).Sum(), - (a.Raw1 * b).Sum(), - (a.Raw2 * b).Sum(), - (a.Raw3 * b).Sum()); + (a.Row0 * b).Sum(), + (a.Row1 * b).Sum(), + (a.Row2 * b).Sum(), + (a.Row3 * b).Sum()); } public static bool operator ==(Matrix4X4 a, Matrix4X4 b) @@ -296,20 +328,26 @@ public override string ToString() return !a.Equals(b); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Matrix4X4 Transpose(Matrix4X4 matrix4X4) + { + return new Matrix4X4(matrix4X4.Column0, matrix4X4.Column1, matrix4X4.Column2, matrix4X4.Column3); + } + /// /// Creating scale matrix /// /// v | 0 | 0 | 0 /// 0 | v | 0 | 0 /// 0 | 0 | v | 0 - /// 0 | 0 | 0 | v + /// 0 | 0 | 0 | 1 /// /// public static Matrix4X4 CreateScale(float value) { - return CreateScale(value, value, value, value); + return CreateScale(value, value, value); } - + /// /// Creating scale matrix /// @@ -321,9 +359,9 @@ public static Matrix4X4 CreateScale(float value) /// public static Matrix4X4 CreateScale(Vector2 scale) { - return CreateScale(scale.X, scale.Y, 1f, 1f); + return CreateScale(scale.X, scale.Y, 1f); } - + /// /// Creating scale matrix /// @@ -335,9 +373,9 @@ public static Matrix4X4 CreateScale(Vector2 scale) /// public static Matrix4X4 CreateScale(Vector3 scale) { - return CreateScale(scale.X, scale.Y, scale.Z, 1f); + return CreateScale(scale.X, scale.Y, scale.Z); } - + /// /// Creating scale matrix /// @@ -347,42 +385,200 @@ public static Matrix4X4 CreateScale(Vector3 scale) /// 0 | 0 | 0 | 1 /// /// - public static Matrix4X4 CreateScale(float x, float y, float z, float w) + public static Matrix4X4 CreateScale(float x, float y, float z) { var result = Identity; result.M00 = x; result.M11 = y; result.M22 = z; - result.M33 = w; return result; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Matrix4X4 CreateRotation(Vector3 direction, float angle) + { + var cos = MathF.Cos(-angle); + var sin = MathF.Sin(-angle); + var t = 1.0f - cos; + + direction = direction.Normalized; + + return new Matrix4X4( + t * direction.X * direction.X + cos, + t * direction.X * direction.Y - sin * direction.Z, + t * direction.X * direction.Z + sin * direction.Y, + 0, + t * direction.X * direction.Y + sin * direction.Z, + t * direction.Y * direction.Y + cos, + t * direction.Y * direction.Z - sin * direction.X, + 0, + t * direction.X * direction.Z - sin * direction.Y, + t * direction.Y * direction.Z + sin * direction.X, + t * direction.Z * direction.Z + cos, + 0, + 0, + 0, + 0, + 1 + ); + } + + /// + /// Creating rotation axis X matrix + /// + /// 1 | 0 | 0 | 0 + /// 0 | cos | sin | 0 + /// 0 | -sin | cos | 0 + /// 0 | 0 | 0 | 1 + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Matrix4X4 CreateRotationX(float angle) + { + var cos = MathF.Cos(angle); + var sin = MathF.Sin(angle); + + return new Matrix4X4( + Vector4.UnitX, + new Vector4(0, cos, sin, 0), + new Vector4(0, -sin, cos, 0), + Vector4.UnitW + ); + } + /// - /// Creating orthographic matrix + /// Creating rotation axis Y matrix /// - /// 2 / (r - l) | 0 | 0 | -(r + l) / (r - l) - /// 0 | 2 / (t - b) | 0 | -(t + b) / (t - b) - /// 0 | 0 | -2 / (zF - zN) | -(zF + zN) / (zF - zN) - /// 0 | 0 | 0 | 1 + /// cos | 0 | -sin | 0 + /// 0 | 1 | 0 | 0 + /// sin | 0 | cos | 0 + /// 0 | 0 | 0 | 1 /// /// - public static Matrix4X4 CreateOrthographic(Box2 box2, float zNear, float zFar) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Matrix4X4 CreateRotationY(float angle) + { + var cos = MathF.Cos(angle); + var sin = MathF.Sin(angle); + + return new Matrix4X4( + new Vector4(cos, 0, -sin, 0), + Vector4.UnitY, + new Vector4(sin, 0, cos, 0), + Vector4.UnitW + ); + } + + /// + /// Creating rotation axis Z matrix + /// + /// cos | sin | 0 | 0 + /// -sin | cos | 0 | 0 + /// 0 | 0 | 1 | 0 + /// 0 | 0 | 0 | 1 + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Matrix4X4 CreateRotationZ(float angle) + { + var cos = MathF.Cos(angle); + var sin = MathF.Sin(angle); + + return new Matrix4X4( + new Vector4(cos, sin, 0, 0), + new Vector4(-sin, cos, 0, 0), + Vector4.UnitZ, + Vector4.UnitW + ); + } + + /// + /// Creating translate matrix + /// + /// 1 | 0 | 0 | v + /// 0 | 1 | 0 | v + /// 0 | 0 | 1 | v + /// 0 | 0 | 0 | 1 + /// + /// + public static Matrix4X4 CreateTranslation(float value) + { + return CreateTranslation(value, value, value); + } + + /// + /// Creating translate matrix + /// + /// 1 | 0 | 0 | x + /// 0 | 1 | 0 | y + /// 0 | 0 | 1 | 0 + /// 0 | 0 | 0 | 1 + /// + /// + public static Matrix4X4 CreateTranslation(Vector2 vector2) + { + return CreateTranslation(vector2.X, vector2.Y, 0f); + } + + /// + /// Creating translate matrix + /// + /// 1 | 0 | 0 | x + /// 0 | 1 | 0 | y + /// 0 | 0 | 1 | z + /// 0 | 0 | 0 | 1 + /// + /// + public static Matrix4X4 CreateTranslation(Vector3 vector3) + { + return CreateTranslation(vector3.X, vector3.Y, vector3.Z); + } + + /// + /// Creating translate matrix + /// + /// 1 | 0 | 0 | x + /// 0 | 1 | 0 | y + /// 0 | 0 | 1 | z + /// 0 | 0 | 0 | 1 + /// + /// + public static Matrix4X4 CreateTranslation(float x, float y, float z) { var result = Identity; - result.M00 = 2 / (box2.Right - box2.Left); - result.M11 = 2 / (box2.Top - box2.Bottom); - result.M22 = -2 / (zFar - zNear); + result.M03 = x; + result.M13 = y; + result.M23 = z; - result.M03 = -(box2.Right + box2.Left) / (box2.Right - box2.Left); - result.M13 = -(box2.Top + box2.Bottom) / (box2.Top - box2.Bottom); - result.M23 = -(zFar + zNear) / (zFar - zNear); - return result; } + + public static Matrix4X4 CreateOrthographic(Box2 box2, float zNear, float zFar) + { + return CreateOrthographic(box2.Width, box2.Height, zNear, zFar); + } + public static Matrix4X4 CreateOrthographic(Vector2 size, float zNear, float zFar) + { + return CreateOrthographic(size.X, size.Y, zNear, zFar); + } + + public static Matrix4X4 CreateOrthographic(float width, float height, float zNear, float zFar) + { + var result = Identity; + var range = 1.0f / (zNear - zFar); + + result.Row0 = new Vector4(2.0f / width, 0, 0, 0); + result.Row1 = new Vector4(0, 2.0f / height, 0, 0); + result.Row2 = new Vector4(0, 0, range, 0); + result.Row3 = new Vector4(0, 0, range * zNear, 1); + + return result; + } + /// /// Creating perspective matrix /// @@ -404,16 +600,15 @@ public static Matrix4X4 CreatePerspective(float fov, float aspect, float zNear, { var result = Zero; - var halfFov = fov / 2; - var tanHalfFov = (float)System.Math.Tan(halfFov); - var zDelta = zFar - zNear; - - result.M00 = 1 / (aspect * tanHalfFov); - result.M11 = 1 / tanHalfFov; - result.M22 = zFar / zDelta; - result.M23 = 1; - result.M32 = zFar * zNear / zDelta; + var height = 1.0f / MathF.Tan(fov * 0.5f); + var width = height / aspect; + var range = float.IsPositiveInfinity(zFar) ? -1.0f : zFar / (zNear - zFar); + result.Row0 = new Vector4(width, 0, 0, 0); + result.Row1 = new Vector4(0, height, 0, 0); + result.Row2 = new Vector4(0, 0, range, -1.0f); + result.Row3 = new Vector4(0, 0, range * zNear, 0); + return result; } -} \ No newline at end of file +} diff --git a/Hypercube.Shared.Math/Vector/Vector2.Compability.cs b/Hypercube.Shared.Math/Vector/Vector2.Compability.cs deleted file mode 100644 index 5462fa9..0000000 --- a/Hypercube.Shared.Math/Vector/Vector2.Compability.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace Hypercube.Shared.Math.Vector; - -public readonly partial struct Vector2 -{ - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Vector2(System.Numerics.Vector2 vector) - { - return new Vector2(vector.X, vector.Y); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator System.Numerics.Vector2(Vector2 vector) - { - return new System.Numerics.Vector2(vector.X, vector.Y); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Vector2(OpenTK.Mathematics.Vector2 vector) - { - return new Vector2(vector.X, vector.Y); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator OpenTK.Mathematics.Vector2(Vector2 vector) - { - return new OpenTK.Mathematics.Vector2(vector.X, vector.Y); - } -} \ No newline at end of file diff --git a/Hypercube.Shared.Math/Vector/Vector2.Compatibility.cs b/Hypercube.Shared.Math/Vector/Vector2.Compatibility.cs new file mode 100644 index 0000000..b79f9eb --- /dev/null +++ b/Hypercube.Shared.Math/Vector/Vector2.Compatibility.cs @@ -0,0 +1,86 @@ +using System.Runtime.CompilerServices; + +namespace Hypercube.Shared.Math.Vector; + +public readonly partial struct Vector2 +{ + /* + * Self Compatibility + */ + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Vector2Int(Vector2 vector) + { + return new Vector2Int((int)vector.X, (int)vector.Y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Vector3(Vector2 vector) + { + return new Vector3(vector.X, vector.Y, 0f); + } + + /* + * Tuple Compatibility + */ + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Vector2((float x, float y) a) + { + return new Vector2(a.x, a.y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator (float x, float y)(Vector2 a) + { + return (a.X, a.Y); + } + + /* + * System.Numerics Compatibility + */ + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Vector2(System.Numerics.Vector2 vector) + { + return new Vector2(vector.X, vector.Y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator System.Numerics.Vector2(Vector2 vector) + { + return new System.Numerics.Vector2(vector.X, vector.Y); + } + + /* + * OpenTK Compatibility + */ + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Vector2(OpenTK.Mathematics.Vector2 vector) + { + return new Vector2(vector.X, vector.Y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator OpenTK.Mathematics.Vector2(Vector2 vector) + { + return new OpenTK.Mathematics.Vector2(vector.X, vector.Y); + } + + /* + * OpenToolkit Compatibility + */ + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Vector2(OpenToolkit.Mathematics.Vector2 vector) + { + return new Vector2(vector.X, vector.Y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator OpenToolkit.Mathematics.Vector2(Vector2 vector) + { + return new OpenToolkit.Mathematics.Vector2(vector.X, vector.Y); + } +} \ No newline at end of file diff --git a/Hypercube.Shared.Math/Vector/Vector2.cs b/Hypercube.Shared.Math/Vector/Vector2.cs index 61b3cf9..4742380 100644 --- a/Hypercube.Shared.Math/Vector/Vector2.cs +++ b/Hypercube.Shared.Math/Vector/Vector2.cs @@ -1,25 +1,36 @@ using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace Hypercube.Shared.Math.Vector; -public readonly partial struct Vector2(float x, float y) : IEquatable +[StructLayout(LayoutKind.Sequential)] +public readonly partial struct Vector2 : IEquatable { public static readonly Vector2 Zero = new(0, 0); public static readonly Vector2 One = new(1, 1); - public static readonly Vector2 Up = new(0, 1); - public static readonly Vector2 Down = new(0, -1); - public static readonly Vector2 Right = new(1, 0); - public static readonly Vector2 Left = new(-1, 0); + public static readonly Vector2 UnitX = new(1, 0); public static readonly Vector2 UnitY = new(0, 1); - public readonly float X = x; - public readonly float Y = y; + public readonly float X; + public readonly float Y; + public float AspectRatio + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => X / Y; + } + public float Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => MathF.Sqrt(x * x + y * y); + get => MathF.Sqrt(X * X + Y * Y); + } + + public Vector2(float x, float y) + { + X = x; + Y = y; } public Vector2(float value) : this(value, value) @@ -63,7 +74,7 @@ public override int GetHashCode() [MethodImpl(MethodImplOptions.AggressiveInlining)] public override string ToString() { - return $"{x}, {y}"; + return $"{X}, {Y}"; } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/Hypercube.Shared.Math/Vector/Vector2Int.Compability.cs b/Hypercube.Shared.Math/Vector/Vector2Int.Compability.cs deleted file mode 100644 index f1df15b..0000000 --- a/Hypercube.Shared.Math/Vector/Vector2Int.Compability.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace Hypercube.Shared.Math.Vector; - -public readonly partial struct Vector2Int -{ - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Vector2Int(System.Drawing.Size size) - { - return new Vector2Int(size.Width, size.Height); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator System.Drawing.Size(Vector2Int vector2) - { - return new System.Drawing.Size(vector2.X, vector2.Y); - } -} \ No newline at end of file diff --git a/Hypercube.Shared.Math/Vector/Vector2Int.Compatibility.cs b/Hypercube.Shared.Math/Vector/Vector2Int.Compatibility.cs new file mode 100644 index 0000000..fc6d717 --- /dev/null +++ b/Hypercube.Shared.Math/Vector/Vector2Int.Compatibility.cs @@ -0,0 +1,86 @@ +using System.Runtime.CompilerServices; + +namespace Hypercube.Shared.Math.Vector; + +public readonly partial struct Vector2Int +{ + /* + * Self Compatibility + */ + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Vector2(Vector2Int vector) + { + return new Vector2(vector.X, vector.Y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Vector3(Vector2Int vector) + { + return new Vector3(vector.X, vector.Y, 0f); + } + + /* + * Tuple Compatibility + */ + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Vector2Int((int x, int y) a) + { + return new Vector2Int(a.x, a.y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator (int x, int y)(Vector2Int a) + { + return (a.X, a.Y); + } + + /* + * System.Drawing Compatibility + */ + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Vector2Int(System.Drawing.Size size) + { + return new Vector2Int(size.Width, size.Height); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator System.Drawing.Size(Vector2Int vector2) + { + return new System.Drawing.Size(vector2.X, vector2.Y); + } + + /* + * OpenTK Compatibility + */ + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Vector2Int(OpenTK.Mathematics.Vector2i vector) + { + return new Vector2Int(vector.X, vector.Y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator OpenTK.Mathematics.Vector2i(Vector2Int vector) + { + return new OpenTK.Mathematics.Vector2i(vector.X, vector.Y); + } + + /* + * OpenToolkit Compatibility + */ + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Vector2Int(OpenToolkit.Mathematics.Vector2i vector) + { + return new Vector2Int(vector.X, vector.Y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator OpenToolkit.Mathematics.Vector2i(Vector2Int vector) + { + return new OpenToolkit.Mathematics.Vector2i(vector.X, vector.Y); + } +} \ No newline at end of file diff --git a/Hypercube.Shared.Math/Vector/Vector2Int.cs b/Hypercube.Shared.Math/Vector/Vector2Int.cs index 63aaf8e..554e67f 100644 --- a/Hypercube.Shared.Math/Vector/Vector2Int.cs +++ b/Hypercube.Shared.Math/Vector/Vector2Int.cs @@ -1,110 +1,158 @@ -namespace Hypercube.Shared.Math.Vector; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; -public readonly partial struct Vector2Int(int x, int y) +namespace Hypercube.Shared.Math.Vector; + +[StructLayout(LayoutKind.Sequential)] +public readonly partial struct Vector2Int : IEquatable { public static readonly Vector2Int Zero = new(0, 0); public static readonly Vector2Int One = new(1, 1); - public static readonly Vector2Int Up = new(0, 1); - public static readonly Vector2Int Down = new(0, -1); - public static readonly Vector2Int Right = new(1, 0); - public static readonly Vector2Int Left = new(-1, 0); + + public static readonly Vector2Int UnitX = new(1, 0); + public static readonly Vector2Int UnitY = new(0, 1); + + public readonly int X; + public readonly int Y; - public readonly int X = x; - public readonly int Y = y; - public readonly float Ratio = x / (float)y; + public float AspectRatio + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => X / (float)Y; + } + + public float Length + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => MathF.Sqrt(X * X + Y * Y); + } + public Vector2Int(int x, int y) + { + X = x; + Y = y; + } + + public Vector2Int(int value) : this(value, value) + { + } + + public Vector2Int(Vector2Int vector2Int) : this(vector2Int.X, vector2Int.Y) + { + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector2Int WithX(int value) + { + return new Vector2Int(value, Y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector2Int WithY(int value) + { + return new Vector2Int(X, value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Vector2Int other) + { + return X == other.X && + Y == other.Y; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override bool Equals(object? obj) + { + return obj is Vector2Int vector && Equals(vector); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() + { + return HashCode.Combine(X, Y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override string ToString() + { + return $"{X}, {Y}"; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2Int operator +(Vector2Int a, Vector2Int b) { return new Vector2Int(a.X + b.X, a.Y + b.Y); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2Int operator +(Vector2Int a, int b) { return new Vector2Int(a.X + b, a.Y + b); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2Int operator -(Vector2Int a) + { + return new Vector2Int(-a.X, -a.Y); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2Int operator -(Vector2Int a, Vector2Int b) { return new Vector2Int(a.X - b.X, a.Y - b.Y); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2Int operator -(Vector2Int a, int b) { return new Vector2Int(a.X - b, a.Y - b); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2Int operator *(Vector2Int a, Vector2Int b) { return new Vector2Int(a.X * b.X, a.Y * b.Y); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2Int operator *(Vector2Int a, int b) { return new Vector2Int(a.X * b, a.Y * b); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 operator *(Vector2Int a, float b) { return new Vector2(a.X * b, a.Y * b); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2Int operator /(Vector2Int a, Vector2Int b) { return new Vector2Int(a.X / b.X, a.Y / b.Y); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2Int operator /(Vector2Int a, int b) { return new Vector2Int(a.X / b, a.Y / b); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 operator /(Vector2Int a, float b) { return new Vector2(a.X / b, a.Y / b); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Vector2Int a, Vector2Int b) { return a.Equals(b); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Vector2Int a, Vector2Int b) { return !a.Equals(b); } - - public static implicit operator Vector2(Vector2Int a) - { - return new Vector2(a.X, a.Y); - } - - public static implicit operator Vector2Int(Vector2 a) - { - return new Vector2Int((int)a.X, (int)a.Y); - } - - public static implicit operator Vector2Int((int x, int y) a) - { - return new Vector2Int(a.x, a.y); - } - - public readonly bool Equals(Vector2Int other) - { - return X == other.X && Y == other.Y; - } - - public readonly override bool Equals(object? obj) - { - return obj is Vector2Int vector && Equals(vector); - } - - public override int GetHashCode() - { - return x + y; - } - - public override string ToString() - { - return $"{x}, {y}"; - } } \ No newline at end of file diff --git a/Hypercube.Shared.Math/Vector/Vector3.Compatibility.cs b/Hypercube.Shared.Math/Vector/Vector3.Compatibility.cs new file mode 100644 index 0000000..5236e58 --- /dev/null +++ b/Hypercube.Shared.Math/Vector/Vector3.Compatibility.cs @@ -0,0 +1,86 @@ +using System.Runtime.CompilerServices; + +namespace Hypercube.Shared.Math.Vector; + +public readonly partial struct Vector3 +{ + /* + * Self Compatibility + */ + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Vector2(Vector3 vector) + { + return new Vector2(vector.X, vector.Y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Vector2Int(Vector3 vector) + { + return new Vector2Int((int)vector.X, (int)vector.Y); + } + + /* + * Tuple Compatibility + */ + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Vector3((float x, float y, float z) a) + { + return new Vector3(a.x, a.y, a.z); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator (float x, float y, float z)(Vector3 a) + { + return (a.X, a.Y, a.Z); + } + + /* + * System.Numerics Compatibility + */ + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator System.Numerics.Vector3(Vector3 vector3) + { + return new System.Numerics.Vector3(vector3.X, vector3.Y, vector3.Z); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Vector3(System.Numerics.Vector3 vector3) + { + return new Vector3(vector3.X, vector3.Y, vector3.Z); + } + + /* + * OpenTK Compatibility + */ + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator OpenTK.Mathematics.Vector3(Vector3 vector) + { + return new OpenTK.Mathematics.Vector3(vector.X, vector.Y, vector.Z); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Vector3(OpenTK.Mathematics.Vector3 vector) + { + return new Vector3(vector.X, vector.Y, vector.Z); + } + + /* + * OpenToolkit Compatibility + */ + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator OpenToolkit.Mathematics.Vector3(Vector3 vector) + { + return new OpenToolkit.Mathematics.Vector3(vector.X, vector.Y, vector.Z); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Vector3(OpenToolkit.Mathematics.Vector3 vector) + { + return new Vector3(vector.X, vector.Y, vector.Z); + } +} \ No newline at end of file diff --git a/Hypercube.Shared.Math/Vector/Vector3.cs b/Hypercube.Shared.Math/Vector/Vector3.cs index 6bc7cd8..e9f8463 100644 --- a/Hypercube.Shared.Math/Vector/Vector3.cs +++ b/Hypercube.Shared.Math/Vector/Vector3.cs @@ -1,17 +1,15 @@ using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Hypercube.Shared.Math.Extensions; namespace Hypercube.Shared.Math.Vector; -public readonly struct Vector3(float x, float y, float z) +[StructLayout(LayoutKind.Sequential)] +public readonly partial struct Vector3(float x, float y, float z) : IEquatable { public static readonly Vector3 Zero = new(0, 0, 0); public static readonly Vector3 One = new(1, 1, 1); - public static readonly Vector3 Forward = new(0, 0, 1); - public static readonly Vector3 Back = new(0, 0, -1); - public static readonly Vector3 Up = new(0, 1, 0); - public static readonly Vector3 Down = new(0, -1, 0); - public static readonly Vector3 Right = new(1, 0, 0); - public static readonly Vector3 Left = new(-1, 0, 0); + public static readonly Vector3 UnitX = new(1, 0, 0); public static readonly Vector3 UnitY = new(0, 1, 0); public static readonly Vector3 UnitZ = new(0, 0, 1); @@ -20,10 +18,26 @@ public readonly struct Vector3(float x, float y, float z) public readonly float Y = y; public readonly float Z = z; + public float Length + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => MathF.Sqrt(X * X + Y * Y + Z * Z); + } + + public Vector3 Normalized + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => this / Length; + } + public Vector3(float value) : this(value, value, value) { } + public Vector3(Vector2 vector2) : this(vector2.X, vector2.Y, 0) + { + } + public Vector3(Vector2 vector2, float z) : this(vector2.X, vector2.Y, z) { } @@ -56,6 +70,38 @@ public Vector3 WithZ(float value) return new Vector3(X, Y, value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector3 Cross(Vector3 other) + { + return Vector3.Cross(this, other); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Vector3 other) + { + return X.AboutEquals(other.X) && + Y.AboutEquals(other.Y) && + Z.AboutEquals(other.Z); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override bool Equals(object? obj) + { + return obj is Vector3 other && Equals(other); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() + { + return HashCode.Combine(X, Y, Z); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override string ToString() + { + return $"{x}, {y}, {z}"; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 operator +(Vector3 a, Vector3 b) { @@ -135,8 +181,23 @@ public Vector3 WithZ(float value) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override string ToString() + public static bool operator ==(Vector3 a, Vector3 b) { - return $"{x}, {y}, {z}"; + return a.Equals(b); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(Vector3 a, Vector3 b) + { + return !a.Equals(b); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Cross(Vector3 left, Vector3 right) + { + return new Vector3( + left.Y * right.Z - left.Z * right.Y, + left.Z * right.X - left.X * right.Z, + left.X * right.Y - left.Y * right.X); } } \ No newline at end of file diff --git a/Hypercube.Shared.Math/Vector/Vector4.Compatibility.cs b/Hypercube.Shared.Math/Vector/Vector4.Compatibility.cs new file mode 100644 index 0000000..61adf86 --- /dev/null +++ b/Hypercube.Shared.Math/Vector/Vector4.Compatibility.cs @@ -0,0 +1,54 @@ +using System.Runtime.CompilerServices; + +namespace Hypercube.Shared.Math.Vector; + +public readonly partial struct Vector4 +{ + /* + * System.Numerics Compatibility + */ + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Vector4(System.Numerics.Vector4 vector4) + { + return new Vector4(vector4.X, vector4.Y, vector4.Z, vector4.W); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator System.Numerics.Vector4(Vector4 vector4) + { + return new System.Numerics.Vector4(vector4.X, vector4.Y, vector4.Z, vector4.W); + } + + /* + * OpenTK Compatibility + */ + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Vector4(OpenTK.Mathematics.Vector4 vector4) + { + return new Vector4(vector4.X, vector4.Y, vector4.Z, vector4.W); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator OpenTK.Mathematics.Vector4(Vector4 vector4) + { + return new OpenTK.Mathematics.Vector4(vector4.X, vector4.Y, vector4.Z, vector4.W); + } + + /* + * OpenToolkit Compatibility + */ + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator OpenToolkit.Mathematics.Vector4(Vector4 vector4) + { + return new OpenToolkit.Mathematics.Vector4(vector4.X, vector4.Y, vector4.Z, vector4.W); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Vector4(OpenToolkit.Mathematics.Vector4 vector4) + { + return new Vector4(vector4.X, vector4.Y, vector4.Z, vector4.W); + } +} \ No newline at end of file diff --git a/Hypercube.Shared.Math/Vector/Vector4.cs b/Hypercube.Shared.Math/Vector/Vector4.cs index d1e9486..224dcb1 100644 --- a/Hypercube.Shared.Math/Vector/Vector4.cs +++ b/Hypercube.Shared.Math/Vector/Vector4.cs @@ -1,22 +1,33 @@ using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using Hypercube.Shared.Math.Extensions; namespace Hypercube.Shared.Math.Vector; -public readonly struct Vector4(float x, float y, float z, float w) : IEquatable +[StructLayout(LayoutKind.Sequential)] +public readonly partial struct Vector4 : IEquatable { public static readonly Vector4 Zero = new(0, 0, 0, 0); public static readonly Vector4 One = new(1, 1, 1, 1); + public static readonly Vector4 UnitX = new(1, 0, 0, 0); public static readonly Vector4 UnitY = new(0, 1, 0, 0); public static readonly Vector4 UnitZ = new(0, 0, 1, 0); public static readonly Vector4 UnitW = new(0, 0, 0, 1); - public readonly float X = x; - public readonly float Y = y; - public readonly float Z = z; - public readonly float W = w; + public readonly float X; + public readonly float Y; + public readonly float Z; + public readonly float W; + public Vector4(float x, float y, float z, float w) + { + X = x; + Y = y; + Z = z; + W = w; + } + public Vector4(float value) : this(value, value, value, value) { } @@ -25,7 +36,7 @@ public Vector4(Vector2 vector2, float z, float w) : this(vector2.X, vector2.Y, z { } - public Vector4(Vector4 Vector4, float w) : this(Vector4.X, Vector4.Y, Vector4.Z, w) + public Vector4(Vector4 vector4, float w) : this(vector4.X, vector4.Y, vector4.Z, w) { } @@ -79,7 +90,7 @@ public override bool Equals(object? obj) [MethodImpl(MethodImplOptions.AggressiveInlining)] public override string ToString() { - return $"{x}, {y}, {z}, {w}"; + return $"{X}, {Y}, {Z}, {W}"; } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/Resources/Shaders/base.frag b/Resources/Shaders/base.frag index e58fb8f..88f9e22 100644 --- a/Resources/Shaders/base.frag +++ b/Resources/Shaders/base.frag @@ -8,6 +8,6 @@ in vec2 TexCoord; uniform sampler2D texture0; void main() -{ - FragColor = texture(texture0, TexCoord) * Color; +{ + FragColor = texture(texture0, TexCoord) * Color; } \ No newline at end of file diff --git a/Resources/Shaders/base.vert b/Resources/Shaders/base.vert index 9a5affb..b663ed1 100644 --- a/Resources/Shaders/base.vert +++ b/Resources/Shaders/base.vert @@ -7,10 +7,14 @@ layout (location = 2) in vec2 aTexCoord; out vec4 Color; out vec2 TexCoord; +uniform mat4 projection; +uniform mat4 model; +uniform mat4 view; + void main() { - gl_Position = vec4(aPos, 1.0); + gl_Position = vec4(aPos, 1.0) * model * view * projection; - Color = aColor; - TexCoord = aTexCoord; + Color = aColor; + TexCoord = aTexCoord; } \ No newline at end of file