From d47ac23e1b655315f30b75aba4086f3fb58fa255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20L=C3=BCbe=C3=9F?= Date: Sat, 26 Nov 2022 15:24:33 +0100 Subject: [PATCH] Raw Input and some ImGuiExtension changes --- GlitchyEditor/src/EditorLayer.bf | 2 + GlitchyEngine/src/Application.bf | 2 + GlitchyEngine/src/Events/MouseEvent.bf | 27 +++ GlitchyEngine/src/ImGui/ImGuiExtension.bf | 143 +++++++++++----- GlitchyEngine/src/Input.bf | 158 ++++++++++++++++-- GlitchyEngine/src/Math/ColorRGBA.bf | 9 + .../src/Physics/PhysicsMaterial2D.bf | 9 + .../src/Platform/Windows/WindowsInput.bf | 120 +++++++++---- .../src/Platform/Windows/WindowsWindow.bf | 25 +++ 9 files changed, 408 insertions(+), 87 deletions(-) create mode 100644 GlitchyEngine/src/Physics/PhysicsMaterial2D.bf diff --git a/GlitchyEditor/src/EditorLayer.bf b/GlitchyEditor/src/EditorLayer.bf index 3b8baa6..55d6921 100644 --- a/GlitchyEditor/src/EditorLayer.bf +++ b/GlitchyEditor/src/EditorLayer.bf @@ -245,6 +245,8 @@ namespace GlitchyEditor private bool OnImGuiRender(ImGuiRenderEvent event) { + Input.ImGuiDebugDraw(); + //viewer.ViewTexture(Renderer.[Friend]_gBuffer.Target); ImGui.Viewport* viewport = ImGui.GetMainViewport(); diff --git a/GlitchyEngine/src/Application.bf b/GlitchyEngine/src/Application.bf index 7b61e3a..d1c7bf8 100644 --- a/GlitchyEngine/src/Application.bf +++ b/GlitchyEngine/src/Application.bf @@ -55,6 +55,8 @@ namespace GlitchyEngine _window = new Window(.Default); _window.EventCallback = new => OnEvent; + Input.Init(); + _rendererApi = new RendererAPI(); _rendererApi.Context = _window.Context; diff --git a/GlitchyEngine/src/Events/MouseEvent.bf b/GlitchyEngine/src/Events/MouseEvent.bf index 493eaa1..c785594 100644 --- a/GlitchyEngine/src/Events/MouseEvent.bf +++ b/GlitchyEngine/src/Events/MouseEvent.bf @@ -28,6 +28,33 @@ namespace GlitchyEngine.Events strBuffer.AppendF("MouseMovedEvent: Position: ({}, {})", _mouseX, _mouseY); } } + + public class RawMouseMovedEvent : Event, IEvent + { + private int32 _mouseX, _mouseY; + + public override EventType EventType => .MouseMoved; + + public override StringView Name => "RawMouseMoved"; + + public override EventCategory Category => .Input | .Mouse; + + public static EventType StaticType => .MouseMoved; + + public int32 PositionX => _mouseX; + public int32 PositionY => _mouseY; + + public this(int32 x, int32 y) + { + _mouseX = x; + _mouseY = y; + } + + public override void ToString(String strBuffer) + { + strBuffer.AppendF("RawMouseMovedEvent: Position: ({}, {})", _mouseX, _mouseY); + } + } public class MouseScrolledEvent : Event, IEvent { diff --git a/GlitchyEngine/src/ImGui/ImGuiExtension.bf b/GlitchyEngine/src/ImGui/ImGuiExtension.bf index 732a399..20b4d1f 100644 --- a/GlitchyEngine/src/ImGui/ImGuiExtension.bf +++ b/GlitchyEngine/src/ImGui/ImGuiExtension.bf @@ -3,8 +3,18 @@ using GlitchyEngine.Renderer; using System; using GlitchyEngine; +namespace GlitchyEngine.Math +{ + extension ColorRGBA + { + internal uint32 ImGuiU32 => ImGui.ImGui.ColorConvertFloat4ToU32((.)(Vector4)this); + } +} + namespace ImGui { + using internal GlitchyEngine.Math; + extension ImGui { extension Vec2 @@ -12,118 +22,141 @@ namespace ImGui public static explicit operator Vector2(Vec2 v) => .(v.x, v.y); public static explicit operator Vec2(Vector2 v) => .(v.X, v.Y); } - + extension Vec4 { public static explicit operator Vector4(Vec4 v) => .(v.x, v.y, v.z, v.w); public static explicit operator Vec4(Vector4 v) => .(v.X, v.Y, v.Z, v.W); } + /*public static bool IsItemJustDeactivated() + { + return IsItemDeactivatedAfterEdit(); + } + + public static bool IsItemActiveLastFrame() + { + Context* g = GetCurrentContext(); + if (g.ActiveIdPreviousFrame != 0) + return g.ActiveIdPreviousFrame == g.CurrentWindow.DC.LastItemId; + + return false; + } + + public static bool IsItemJustActivated() + { + return IsItemActive() && !IsItemActiveLastFrame(); + } + + public static bool IsItemEditing() + { + return IsItemActive(); + }*/ + // TODO: Color-functions public static bool ColorEdit3(char* label, ref ColorRGB col, ColorEditFlags flags = (ColorEditFlags) 0) => ColorEdit3Impl(label, *(float[3]*)&col, flags); public static bool ColorEdit3(char* label, ref ColorRGBA col, ColorEditFlags flags = (ColorEditFlags) 0) => ColorEdit3Impl(label, *(float[3]*)&col, flags); - + public static bool ColorEdit4(char* label, ref ColorRGBA col, ColorEditFlags flags = (ColorEditFlags) 0) => ColorEdit4Impl(label, *(float[4]*)&col, flags); - - public static bool ColorPicker3(char* label, ref ColorRGB col, ColorEditFlags flags = (ColorEditFlags) 0) => ColorPicker3Impl(label, *(float[3]*)&col, flags); - public static bool ColorPicker3(char* label, ref ColorRGBA col, ColorEditFlags flags = (ColorEditFlags) 0) => ColorPicker3Impl(label, *(float[3]*)&col, flags); + + public static bool ColorPicker3(char* label, ref ColorRGB col, ColorEditFlags flags = (ColorEditFlags) 0) => ColorPicker3Impl(label, *(float[3]*)&col, flags); + public static bool ColorPicker3(char* label, ref ColorRGBA col, ColorEditFlags flags = (ColorEditFlags) 0) => ColorPicker3Impl(label, *(float[3]*)&col, flags); public static bool ColorPicker4(char* label, ref ColorRGBA col, ColorEditFlags flags = (ColorEditFlags) 0, float* ref_col = null) => ColorPicker4Impl(label, *(float[4]*)&col, flags, ref_col); - + public static void Image(Texture2D texture, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 tint_col = Vec4.Ones, Vec4 border_col = Vec4.Zero) { Image(texture.GetViewBinding(), size, uv0, uv1, tint_col, border_col); } - + public static void Image(SubTexture2D subTexture, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 tint_col = Vec4.Ones, Vec4 border_col = Vec4.Zero) { if (uv0 != .Zero || uv1 != .Ones) Runtime.NotImplemented(); - + Vector2 v = (.)subTexture.TexCoords.XY + subTexture.TexCoords.ZW; - + Image(subTexture.Texture.GetViewBinding(), size, (.)subTexture.TexCoords.XY, (.)v, tint_col, border_col); } - + public static void Image(RenderTarget2D texture, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 tint_col = Vec4.Ones, Vec4 border_col = Vec4.Zero) { Image(texture.GetViewBinding(), size, uv0, uv1, tint_col, border_col); } - + public static extern void Image(TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, Vec4 tint_col = Vec4.Ones, Vec4 border_col = Vec4.Zero); - + public static bool ImageButton(SubTexture2D subTexture, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, int32 frame_padding = -1, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones) { if (uv0 != .Zero || uv1 != .Ones) Runtime.NotImplemented(); - + Vector2 v = (.)subTexture.TexCoords.XY + subTexture.TexCoords.ZW; - + return ImageButton(subTexture.Texture.GetViewBinding(), size, (.)subTexture.TexCoords.XY, (.)v, frame_padding, bg_col, tint_col); } - + public static extern bool ImageButton(TextureViewBinding textureViewBinding, Vec2 size, Vec2 uv0 = Vec2.Zero, Vec2 uv1 = Vec2.Ones, int32 frame_padding = -1, Vec4 bg_col = Vec4.Zero, Vec4 tint_col = Vec4.Ones); - + public static void TextUnformatted(StringView text) => TextUnformattedImpl(text.Ptr, text.Ptr + text.Length); public static void PushID(StringView id) => PushID(id.Ptr, id.Ptr + id.Length); - + /// Releases references that accumulated calls like ImGui::Image protected internal static extern void CleanupFrame(); - + /// Control to edit a vector 2 with drag functionality and reset buttons public static bool EditVector2(StringView label, ref Vector2 value, Vector2 resetValues = .Zero, float dragSpeed = 0.1f, float columnWidth = 100f, Vector2 minValue = .Zero, Vector2 maxValue = .Zero) { return EditVector<2>(label, ref *(float[2]*)&value, (float[2])resetValues, dragSpeed, columnWidth, (float[2])minValue, (float[2])maxValue); } - + /// Control to edit a vector 3 with drag functionality and reset buttons public static bool EditVector3(StringView label, ref Vector3 value, Vector3 resetValues = .Zero, float dragSpeed = 0.1f, float columnWidth = 100f, Vector3 minValue = .Zero, Vector3 maxValue = .Zero) { return EditVector<3>(label, ref *(float[3]*)&value, (float[3])resetValues, dragSpeed, columnWidth, (float[3])minValue, (float[3])maxValue); } - + /// Control to edit a vector 4 with drag functionality and reset buttons public static bool EditVector4(StringView label, ref Vector4 value, Vector4 resetValues = .Zero, float dragSpeed = 0.1f, float columnWidth = 100f, Vector4 minValue = .Zero, Vector4 maxValue = .Zero) { return EditVector<4>(label, ref *(float[4]*)&value, (float[4])resetValues, dragSpeed, columnWidth, (float[4])minValue, (float[4])maxValue); } - - static (Color Default, Color Hovered, Color Active)[?] VectorButtonColors = .( - (Color(230, 25, 45), Color(150, 25, 45), Color(230, 90, 90)), - (Color(50, 190, 15), Color(50, 120, 15), Color(116, 190, 99)), - (Color(55, 55, 230), Color(55, 55, 150), Color(90, 90, 230)), - (Color(230, 25, 45), Color(230, 25, 45), Color(230, 25, 45))); - + + static (ColorRGBA Default, ColorRGBA Hovered, ColorRGBA Active)[?] VectorButtonColors = .( + (.(230, 25, 45), .(150, 25, 45), .(230, 90, 90)), + (.(50, 190, 15), .(50, 120, 15), .(116, 190, 99)), + (.(55, 55, 230), .(55, 55, 150), .(90, 90, 230)), + (.(230, 25, 45), .(230, 25, 45), .(230, 25, 45))); + public static bool EditVector(StringView label, ref float[NumComponents] value, float[NumComponents] resetValues = .(), float dragSpeed = 0.1f, float columnWidth = 100f, float[NumComponents] minValue = .(), float[NumComponents] maxValue = .()) where NumComponents : const int32 { const String[?] componentNames = .("X", "Y", "Z", "W"); const String[?] componentIds = .("##X", "##Y", "##Z", "##W"); - /*(Color Default, Color Hovered, Color Active)[?] VectorButtonColors = .( - (Color(230, 25, 45), Color(150, 25, 45), Color(230, 90, 90)), - (Color(50, 190, 15), Color(50, 120, 15), Color(116, 190, 99)), - (Color(55, 55, 230), Color(55, 55, 150), Color(90, 90, 230)), - (Color(230, 25, 45), Color(230, 25, 45), Color(230, 25, 45)));*/ + static int mouseLockId = 0; bool changed = false; - + bool deactivated = false; + PushID(label); defer PopID(); + int currentId = ImGui.GetID(""); + Columns(2); defer Columns(1); SetColumnWidth(0, columnWidth); - + TextUnformatted(label); - + NextColumn(); - + PushMultiItemsWidths(NumComponents, CalcItemWidth()); float lineHeight = GetFont().FontSize + GetStyle().FramePadding.y * 2.0f; ImGui.Vec2 buttonSize = .(lineHeight + 3.0f, lineHeight); - + PushStyleVar(.ItemSpacing, Vec2.Zero); for (int i < NumComponents) @@ -132,10 +165,10 @@ namespace ImGui { SameLine(); } - - PushStyleColor(.Button, VectorButtonColors[i].Default.Value); - PushStyleColor(.ButtonHovered, VectorButtonColors[i].Hovered.Value); - PushStyleColor(.ButtonActive, VectorButtonColors[i].Active.Value); + + PushStyleColor(.Button, VectorButtonColors[i].Default.ImGuiU32); + PushStyleColor(.ButtonHovered, VectorButtonColors[i].Hovered.ImGuiU32); + PushStyleColor(.ButtonActive, VectorButtonColors[i].Active.ImGuiU32); if (Button(componentNames[i], buttonSize)) { @@ -144,23 +177,43 @@ namespace ImGui } SameLine(); - + if (DragFloat(componentIds[i], &value[i], dragSpeed, minValue[i], maxValue[i])) + { changed = true; + + /*if (mouseLockId != currentId) + { + mouseLockId = currentId; + + Mouse.LockCurrentPosition(mouseLockId); + }*/ + } + + /*if (IsItemDeactivatedAfterEdit()) + { + deactivated = true; + }*/ PopItemWidth(); PopStyleColor(3); } - + PopStyleVar(); + /*if (mouseLockId == currentId && deactivated) + { + Mouse.UnlockPosition(mouseLockId); + mouseLockId = 0; + }*/ + return changed; } - + /// Draws a rectangle with the given color. public static void DrawRect(Vec2 min, Vec2 max, Color color) { ImGui.GetForegroundDrawList().AddRect(min, max, ImGui.GetColorU32(color.Value)); } } -} +} \ No newline at end of file diff --git a/GlitchyEngine/src/Input.bf b/GlitchyEngine/src/Input.bf index 2d3cf19..a1d9173 100644 --- a/GlitchyEngine/src/Input.bf +++ b/GlitchyEngine/src/Input.bf @@ -1,6 +1,8 @@ using System; using GlitchyEngine.Events; using GlitchyEngine.Math; +using System.Collections; +using ImGui; namespace GlitchyEngine { @@ -24,26 +26,154 @@ namespace GlitchyEngine * @remarks IsKeyReleasing(kc) == !IsKeyPressed(kc) && IsKeyReleased(kc) */ public static extern bool IsKeyReleasing(Key keycode); + + // TODO: Should Input be able to set mousepos? + public static extern void SetMousePosition(Int2 pos); public static extern bool IsMouseButtonPressed(MouseButton button); public static extern bool IsMouseButtonReleased(MouseButton button); - public static extern Int2 GetMousePosition(); - public static extern int32 GetMouseX(); - public static extern int32 GetMouseY(); - - // TODO: Should Input be able to set mousepos? - public static extern void SetMousePosition(Int2 pos); - - public static extern bool WasMouseButtonPressed(MouseButton button); - public static extern bool WasMouseButtonReleased(MouseButton button); - public static extern Int2 GetLastMousePosition(); - public static extern int32 GetLastMouseX(); - public static extern int32 GetLastMouseY(); - public static extern bool IsMouseButtonPressing(MouseButton button); public static extern bool IsMouseButtonReleasing(MouseButton button); + public static extern Int2 GetMousePosition(); public static extern Int2 GetMouseMovement(); + public static extern Int2 GetRawMouseMovement(); + public static extern int32 GetMouseX(); + public static extern int32 GetMouseY(); + + public static extern bool WasMouseButtonPressed(MouseButton button); + // public static extern bool WasMouseButtonPressing(MouseButton button); + public static extern bool WasMouseButtonReleased(MouseButton button); + //public static extern bool WasMouseButtonReleasing(MouseButton button); + public static extern Int2 GetLastMousePosition(); + public static extern Int2 GetLastMouseMovement(); + public static extern Int2 GetLastRawMouseMovement(); + public static extern int32 GetLastMouseX(); + public static extern int32 GetLastMouseY(); - public static extern void NewFrame(); + public static extern void Init(); + + public static void NewFrame() + { + [Inline] + Impl_NewFrame(); + + Mouse.NewFrame(); + + [Inline] + Impl_EndFrame(); + } + + public static extern void Impl_NewFrame(); + public static extern void Impl_EndFrame(); + + public static void ImGuiDebugDraw() + { + if (ImGui.Begin("Input")) + { + ImGui.TextUnformatted("Last Mouse state"); + + ImGui.Columns(2); + + ImGui.TextUnformatted("Position"); + ImGui.NextColumn(); + ImGui.Text($"{GetLastMousePosition()}"); + ImGui.NextColumn(); + + ImGui.TextUnformatted("Movement"); + ImGui.NextColumn(); + ImGui.Text($"{GetLastMouseMovement()}"); + ImGui.NextColumn(); + + ImGui.TextUnformatted("RawMovement"); + ImGui.NextColumn(); + ImGui.Text($"{GetLastRawMouseMovement()}"); + ImGui.NextColumn(); + + ImGui.Columns(1); + + ImGui.Separator(); + + ImGui.TextUnformatted("Current Mouse state"); + + ImGui.Columns(2); + + ImGui.TextUnformatted("Position"); + ImGui.NextColumn(); + ImGui.Text($"{GetMousePosition()}"); + ImGui.NextColumn(); + + ImGui.TextUnformatted("Movement"); + ImGui.NextColumn(); + ImGui.Text($"{GetMouseMovement()}"); + ImGui.NextColumn(); + + ImGui.TextUnformatted("RawMovement"); + ImGui.NextColumn(); + ImGui.Text($"{GetRawMouseMovement()}"); + ImGui.NextColumn(); + + ImGui.Columns(1); + } + + ImGui.End(); + } + } + + public static class Mouse + { + private static append List<(Int2 Position, int Hash)> _lockPositions = .(); + + public static void LockCurrentPosition(int hash) + { + LockPosition(Input.GetMousePosition(), hash); + } + + public static void LockPosition(Int2 pos, int hash) + { + for (var entry in _lockPositions) + { + if (entry.Hash == hash) + { + entry.Position = pos; + break; + } + } + + _lockPositions.Add((pos, hash)); + } + + public static void UnlockPosition(int hash) + { + for (var entry in _lockPositions) + { + if (entry.Hash == hash) + { + @entry.Remove(); + break; + } + } + + //Log.EngineLogger.AssertDebug(false, "No mouse lock position with hash found."); + } + + public static Int2? LockedPosition; + + public static void NewFrame() + { + Log.EngineLogger.Info($"{Input.GetMousePosition()}"); + + if (_lockPositions.Count > 0) + { + var position = _lockPositions.Back.Position; + + LockedPosition = position; + + Input.SetMousePosition(position); + } + else + { + LockedPosition = null; + } + } } } diff --git a/GlitchyEngine/src/Math/ColorRGBA.bf b/GlitchyEngine/src/Math/ColorRGBA.bf index efe6bf4..9704e42 100644 --- a/GlitchyEngine/src/Math/ColorRGBA.bf +++ b/GlitchyEngine/src/Math/ColorRGBA.bf @@ -185,6 +185,15 @@ namespace GlitchyEngine.Math A = a; } + /// Creates a new instance of ColorRGBA with the specified values. + public this(uint8 r, uint8 g, uint8 b, uint8 a = 255) + { + R = r / 255f; + G = g / 255f; + B = b / 255f; + A = a / 255f; + } + /// Creates a new instance of ColorRGBA with the specified values. public this(ColorRGB color, float a = 1.0f) { diff --git a/GlitchyEngine/src/Physics/PhysicsMaterial2D.bf b/GlitchyEngine/src/Physics/PhysicsMaterial2D.bf new file mode 100644 index 0000000..f35f518 --- /dev/null +++ b/GlitchyEngine/src/Physics/PhysicsMaterial2D.bf @@ -0,0 +1,9 @@ +namespace GlitchyEngine.Physics; + +struct PhysicsMaterial2D +{ + public float Density = 1.0f; + public float Friction = 0.5f; + public float Restitution = 0.0f; + public float RestitutionThreshold = 0.5f; +} \ No newline at end of file diff --git a/GlitchyEngine/src/Platform/Windows/WindowsInput.bf b/GlitchyEngine/src/Platform/Windows/WindowsInput.bf index 5289330..c93556d 100644 --- a/GlitchyEngine/src/Platform/Windows/WindowsInput.bf +++ b/GlitchyEngine/src/Platform/Windows/WindowsInput.bf @@ -1,11 +1,14 @@ #if BF_PLATFORM_WINDOWS -using System; -using GlitchyEngine.Events; -using DirectX.Windows.VirtualKeyCodes; using DirectX.Windows; -using GlitchyEngine.Math; +using DirectX.Windows.Winuser; +using DirectX.Windows.Winuser.RawInput; +using DirectX.Windows.VirtualKeyCodes; +using System; using System.Interop; +using GlitchyEngine.Events; +using GlitchyEngine.Math; + using static System.Windows; namespace GlitchyEngine @@ -13,12 +16,43 @@ namespace GlitchyEngine /// Windows (WinApi) specific implementation of the Input-class extension Input { + //[CLink, CallingConvention(.Stdcall)] + //static extern int16 GetKeyState(int32 keycode); + [CLink, CallingConvention(.Stdcall)] + static extern IntBool GetCursorPos(out Int2 p); + [CLink, CallingConvention(.Stdcall)] + static extern IntBool SetCursorPos(c_int x, c_int y); + [CLink, CallingConvention(.Stdcall)] + static extern IntBool ScreenToClient(HWnd hWnd, ref Int2 p); + [CLink, CallingConvention(.Stdcall)] + static extern IntBool ClientToScreen(HWnd hWnd, ref Int2 p); + + [Import("user32.lib"), CLink] + public static extern IntBool RegisterRawInputDevices(RAWINPUTDEVICE* pRawInputDevices, uint32 uiNumDevices, uint32 cbSize); + + public static void RegisterRIDs() + { + RAWINPUTDEVICE rid; + + rid.UsagePage = 0x01; + rid.Usage = 0x02; + rid.Flags = 0; + rid.Target = 0; + + if(RegisterRawInputDevices(&rid, 1, sizeof(RAWINPUTDEVICE)) == 0) + { + Log.EngineLogger.Error("Failed to register raw input devices: {0}", GetLastError()); + Log.EngineLogger.AssertDebug(false, "Failed to register raw input device."); + } + } + /// Represents the state of the input devices on the windows platform (WinApi that is). struct WindowsInputState { public int8[256] KeyStates; public Int2 CursorPosition; public Int2 CursorPositionDifference; + public Int2 RawCursorMovement; } static WindowsInputState[2] IputStates; @@ -119,8 +153,16 @@ namespace GlitchyEngine return state >= 0; } + public override static bool IsMouseButtonPressing(MouseButton button) => IsMouseButtonPressed(button) && WasMouseButtonReleased(button); + + public override static bool IsMouseButtonReleasing(MouseButton button) => IsMouseButtonReleased(button) && WasMouseButtonPressed(button); + public override static Int2 GetMousePosition() => CurrentState.CursorPosition; + public override static Int2 GetMouseMovement() => CurrentState.CursorPositionDifference; + + public override static Int2 GetRawMouseMovement() => CurrentState.RawCursorMovement; + public override static int32 GetMouseX() => CurrentState.CursorPosition.X; public override static int32 GetMouseY() => CurrentState.CursorPosition.Y; @@ -141,33 +183,38 @@ namespace GlitchyEngine } public override static Int2 GetLastMousePosition() => LastState.CursorPosition; + + public override static Int2 GetLastMouseMovement() => LastState.CursorPositionDifference; + + public override static Int2 GetLastRawMouseMovement() => LastState.RawCursorMovement; public override static int32 GetLastMouseX() => LastState.CursorPosition.X; public override static int32 GetLastMouseY() => LastState.CursorPosition.Y; - // - // Mouse state transition - // - public override static bool IsMouseButtonPressing(MouseButton button) => IsMouseButtonPressed(button) && WasMouseButtonReleased(button); - - public override static bool IsMouseButtonReleasing(MouseButton button) => IsMouseButtonReleased(button) && WasMouseButtonPressed(button); - - public override static Int2 GetMouseMovement() => CurrentState.CursorPositionDifference; - - public override static void SetMousePosition(Int2 pos) => SetCursorPos(pos.X, pos.Y); - - //[CLink, CallingConvention(.Stdcall)] - //static extern int16 GetKeyState(int32 keycode); - [CLink, CallingConvention(.Stdcall)] - static extern IntBool GetCursorPos(out Int2 p); - [CLink, CallingConvention(.Stdcall)] - static extern IntBool SetCursorPos(c_int x, c_int y); - [CLink, CallingConvention(.Stdcall)] - static extern IntBool ScreenToClient(HWnd hWnd, ref Int2 p); - - public override static void NewFrame() + public override static void SetMousePosition(Int2 pos) { + HWnd windowHandle = (HWnd)(int)Application.Get().Window.NativeWindow; + + var pos; + + // TODO: can fail + ClientToScreen(windowHandle, ref pos); + + SetCursorPos(pos.X, pos.Y); + } + + public override static void Init() + { + RegisterRIDs(); + } + + //public override + + public override static void Impl_NewFrame() + { + Window window = Application.Get().Window; + Debug.Profiler.ProfileFunction!(); Swap!(CurrentState, LastState); @@ -182,7 +229,7 @@ namespace GlitchyEngine // Get the current mouse position if (GetCursorPos(out CurrentState.CursorPosition) != 0) { - HWnd windowHandle = (HWnd)(int)Application.Get().Window.NativeWindow; + HWnd windowHandle = (HWnd)(int)window.NativeWindow; if (ScreenToClient(windowHandle, ref CurrentState.CursorPosition) == 0) { DirectX.Common.HResult errorCode = (.)GetLastError(); @@ -195,8 +242,25 @@ namespace GlitchyEngine Log.EngineLogger.Error($"Failed to get mouse position. Message({(int32)errorCode}){errorCode}:"); } - // Calculate cursor movement - CurrentState.CursorPositionDifference = CurrentState.CursorPosition - LastState.CursorPosition; + CurrentState.RawCursorMovement = window.[Friend]_rawMouseMovementAccumulator; + + if (Mouse.LockedPosition == null) + { + // Calculate cursor movement + CurrentState.CursorPositionDifference = CurrentState.CursorPosition - LastState.CursorPosition; + } + else + { + // Calculate cursor movement + CurrentState.CursorPositionDifference = CurrentState.CursorPosition - Mouse.LockedPosition.Value; + CurrentState.CursorPosition = Mouse.LockedPosition.Value; + + } + } + + public override static void Impl_EndFrame() + { + Application.Get().Window.[Friend]_rawMouseMovementAccumulator = .Zero; } } } diff --git a/GlitchyEngine/src/Platform/Windows/WindowsWindow.bf b/GlitchyEngine/src/Platform/Windows/WindowsWindow.bf index d919d86..106de61 100644 --- a/GlitchyEngine/src/Platform/Windows/WindowsWindow.bf +++ b/GlitchyEngine/src/Platform/Windows/WindowsWindow.bf @@ -10,6 +10,7 @@ using GlitchyEngine.Events; using System.Diagnostics; using GlitchyEngine.Math; using GlitchyEngine.Renderer; +using DirectX.Windows.Winuser.RawInput; using static System.Windows; using internal GlitchyEngine; @@ -262,6 +263,8 @@ namespace GlitchyEngine return .Ok; } + internal Int2 _rawMouseMovementAccumulator; + private static LRESULT MessageHandler(HWND hwnd, uint32 uMsg, WPARAM wParam, LPARAM lParam) { void* windowPtr = (void*)GetWindowLongPtrW(hwnd, GWL_USERDATA); @@ -458,6 +461,28 @@ namespace GlitchyEngine var event = scope MouseMovedEvent(x, y); window._eventCallback(event); } + case WM_INPUT: + { + uint32 dataSize = ?; + GetRawInputData((.)lParam, RID_INPUT, null, &dataSize, sizeof(RAWINPUTHEADER)); + + if (dataSize > 0) + { + uint8[] rawData = scope .[dataSize]; + if (GetRawInputData((.)lParam, RID_INPUT, rawData.CArray(), &dataSize, sizeof(RAWINPUTHEADER)) == dataSize) + { + RAWINPUT* raw = (.)rawData.CArray(); + if (raw.Header.Type == RIM_TYPEMOUSE) + { + var event = scope MouseMovedEvent(raw.Data.Mouse.lLastX, raw.Data.Mouse.lLastY); + window._eventCallback(event); + + // We accumulate the raw movements an collect them once each frame in WindowsInput.Impl_NewFrame() + window._rawMouseMovementAccumulator += Int2(raw.Data.Mouse.lLastX, raw.Data.Mouse.lLastY); + } + } + } + } // Todo: DirectInput