From 0094db9cb321f592a56b14fbf4210c85fc451618 Mon Sep 17 00:00:00 2001 From: Zaafar Ahmed Date: Wed, 10 Jun 2020 10:39:13 -0400 Subject: [PATCH] F/make net core 3 compatible (#11) * This is backword incompatible! 1: making overlay compatible with .NET Core 2. 2: Removing the dep on lib GlobalHook. 3: Adding coroutines for better foreground thread management. 4: FPS now defaults to vsync --- ClickableTransparentOverlay.sln | 30 +- .../HLSL/imgui-frag.hlsl.bytes | Bin .../HLSL/imgui-vertex.hlsl.bytes | Bin .../ClickableTransparentOverlay.csproj | 157 +---- ClickableTransparentOverlay/HookController.cs | 470 ------------- .../ImGuiController.cs | 655 +++++++++--------- ClickableTransparentOverlay/NativeMethods.cs | 128 +++- ClickableTransparentOverlay/Overlay.cs | 297 ++++---- .../Properties/AssemblyInfo.cs | 39 -- .../Shaders/HLSL/imgui-frag.hlsl | 15 - .../Shaders/HLSL/imgui-vertex.hlsl | 27 - ClickableTransparentOverlay/app.config | 35 - ClickableTransparentOverlay/packages.config | 20 - ClickableTransparentOverlay/stylecop.json | 14 - DriverProgram/App.config | 38 - DriverProgram/DriverProgram.csproj | 104 +-- DriverProgram/Program.cs | 216 +++--- DriverProgram/Properties/AssemblyInfo.cs | 35 - DriverProgram/packages.config | 5 - 19 files changed, 724 insertions(+), 1561 deletions(-) rename ClickableTransparentOverlay/{Shaders => Assets}/HLSL/imgui-frag.hlsl.bytes (100%) rename ClickableTransparentOverlay/{Shaders => Assets}/HLSL/imgui-vertex.hlsl.bytes (100%) delete mode 100644 ClickableTransparentOverlay/HookController.cs delete mode 100644 ClickableTransparentOverlay/Properties/AssemblyInfo.cs delete mode 100644 ClickableTransparentOverlay/Shaders/HLSL/imgui-frag.hlsl delete mode 100644 ClickableTransparentOverlay/Shaders/HLSL/imgui-vertex.hlsl delete mode 100644 ClickableTransparentOverlay/app.config delete mode 100644 ClickableTransparentOverlay/packages.config delete mode 100644 ClickableTransparentOverlay/stylecop.json delete mode 100644 DriverProgram/App.config delete mode 100644 DriverProgram/Properties/AssemblyInfo.cs delete mode 100644 DriverProgram/packages.config diff --git a/ClickableTransparentOverlay.sln b/ClickableTransparentOverlay.sln index 1a56a0c..3d8e324 100644 --- a/ClickableTransparentOverlay.sln +++ b/ClickableTransparentOverlay.sln @@ -1,31 +1,31 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.168 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30128.36 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClickableTransparentOverlay", "ClickableTransparentOverlay\ClickableTransparentOverlay.csproj", "{F5CF8972-D0DA-4FC0-8796-E7C60101C8EA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClickableTransparentOverlay", "ClickableTransparentOverlay\ClickableTransparentOverlay.csproj", "{210EB536-2C1F-48C0-BE59-6C945FC3E1F2}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DriverProgram", "DriverProgram\DriverProgram.csproj", "{370E1945-EF74-4618-A2DE-B5796AC3093E}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DriverProgram", "DriverProgram\DriverProgram.csproj", "{8F05BC9C-06E7-49F8-8417-E2E24F07726A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Release|x64 = Release|x64 + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {F5CF8972-D0DA-4FC0-8796-E7C60101C8EA}.Debug|x64.ActiveCfg = Debug|x64 - {F5CF8972-D0DA-4FC0-8796-E7C60101C8EA}.Debug|x64.Build.0 = Debug|x64 - {F5CF8972-D0DA-4FC0-8796-E7C60101C8EA}.Release|x64.ActiveCfg = Release|x64 - {F5CF8972-D0DA-4FC0-8796-E7C60101C8EA}.Release|x64.Build.0 = Release|x64 - {370E1945-EF74-4618-A2DE-B5796AC3093E}.Debug|x64.ActiveCfg = Debug|x64 - {370E1945-EF74-4618-A2DE-B5796AC3093E}.Debug|x64.Build.0 = Debug|x64 - {370E1945-EF74-4618-A2DE-B5796AC3093E}.Release|x64.ActiveCfg = Release|x64 - {370E1945-EF74-4618-A2DE-B5796AC3093E}.Release|x64.Build.0 = Release|x64 + {210EB536-2C1F-48C0-BE59-6C945FC3E1F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {210EB536-2C1F-48C0-BE59-6C945FC3E1F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {210EB536-2C1F-48C0-BE59-6C945FC3E1F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {210EB536-2C1F-48C0-BE59-6C945FC3E1F2}.Release|Any CPU.Build.0 = Release|Any CPU + {8F05BC9C-06E7-49F8-8417-E2E24F07726A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8F05BC9C-06E7-49F8-8417-E2E24F07726A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8F05BC9C-06E7-49F8-8417-E2E24F07726A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8F05BC9C-06E7-49F8-8417-E2E24F07726A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {CC9A7790-CFC1-4D4F-AE2C-177A80D122C8} + SolutionGuid = {0CA675A0-B7AC-4B41-9E79-BFD0DD4F8285} EndGlobalSection EndGlobal diff --git a/ClickableTransparentOverlay/Shaders/HLSL/imgui-frag.hlsl.bytes b/ClickableTransparentOverlay/Assets/HLSL/imgui-frag.hlsl.bytes similarity index 100% rename from ClickableTransparentOverlay/Shaders/HLSL/imgui-frag.hlsl.bytes rename to ClickableTransparentOverlay/Assets/HLSL/imgui-frag.hlsl.bytes diff --git a/ClickableTransparentOverlay/Shaders/HLSL/imgui-vertex.hlsl.bytes b/ClickableTransparentOverlay/Assets/HLSL/imgui-vertex.hlsl.bytes similarity index 100% rename from ClickableTransparentOverlay/Shaders/HLSL/imgui-vertex.hlsl.bytes rename to ClickableTransparentOverlay/Assets/HLSL/imgui-vertex.hlsl.bytes diff --git a/ClickableTransparentOverlay/ClickableTransparentOverlay.csproj b/ClickableTransparentOverlay/ClickableTransparentOverlay.csproj index 864da1d..9b12ffc 100644 --- a/ClickableTransparentOverlay/ClickableTransparentOverlay.csproj +++ b/ClickableTransparentOverlay/ClickableTransparentOverlay.csproj @@ -1,147 +1,26 @@ - - - + + - Debug - AnyCPU - {F5CF8972-D0DA-4FC0-8796-E7C60101C8EA} - Library - Properties - ClickableTransparentOverlay - ClickableTransparentOverlay - v4.7.2 - 512 - true - - + netstandard2.0 - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - AnyCPU - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - true - bin\x64\Debug\ - DEBUG;TRACE - full - x64 - prompt - MinimumRecommendedRules.ruleset - true - false - false - bin\x64\Debug\ClickableTransparentOverlay.xml - - - bin\x64\Release\ - - - true - none - x64 - prompt - MinimumRecommendedRules.ruleset - true - - - Off - bin\x64\Release\ClickableTransparentOverlay.xml - - - - ..\packages\MouseKeyHook.5.6.0\lib\net40\Gma.System.MouseKeyHook.dll - - - ..\packages\ImGui.NET.1.75.0\lib\netstandard2.0\ImGui.NET.dll - - - ..\packages\NativeLibraryLoader.1.0.12\lib\netstandard2.0\NativeLibraryLoader.dll - - - ..\packages\SharpDX.4.2.0\lib\net45\SharpDX.dll - - - ..\packages\SharpDX.Direct3D11.4.2.0\lib\net45\SharpDX.Direct3D11.dll - - - ..\packages\SharpDX.DXGI.4.2.0\lib\net45\SharpDX.DXGI.dll - - - ..\packages\SixLabors.Core.1.0.0-beta0007\lib\netstandard2.0\SixLabors.Core.dll - - - ..\packages\SixLabors.ImageSharp.1.0.0-beta0006\lib\net472\SixLabors.ImageSharp.dll - - - - ..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll - - - - ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll - - - - ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll - - - ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll - - - - - ..\packages\Veldrid.4.7.0\lib\netstandard2.0\Veldrid.dll - - - ..\packages\Veldrid.ImageSharp.4.7.0\lib\netstandard2.0\Veldrid.ImageSharp.dll - - - ..\packages\Veldrid.SDL2.4.7.0\lib\netstandard2.0\Veldrid.SDL2.dll - - - ..\packages\Veldrid.StartupUtilities.4.7.0\lib\netstandard2.0\Veldrid.StartupUtilities.dll - - + - - - - - + + + - - - - - + + + - - + + + + + + - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - \ No newline at end of file + + diff --git a/ClickableTransparentOverlay/HookController.cs b/ClickableTransparentOverlay/HookController.cs deleted file mode 100644 index 1220e8b..0000000 --- a/ClickableTransparentOverlay/HookController.cs +++ /dev/null @@ -1,470 +0,0 @@ -// -// Copyright (c) Zaafar Ahmed. All rights reserved. -// - -namespace ClickableTransparentOverlay -{ - using System; - using System.Collections.Generic; - using System.Numerics; - using System.Windows.Forms; - using Gma.System.MouseKeyHook; - using ImGuiNET; - - /// - /// This class Hooks the Global Window Keyboard/Mouse events - /// and pass them into the ImGui Overlay. - /// - /// NOTE: This class might miss/skip a Keyboard/Mouse event - /// if ImGui render function takes a lot of time. Report on GitHub - /// if that happens. - /// - public class HookController - { - private readonly Queue messages; - private IKeyboardMouseEvents myHook; - private bool enable; - private int windowX; - private int windowY; - - /// - /// Initializes a new instance of the class. - /// - /// - /// Transparent SDL2Window top left corner X axis. - /// - /// - /// Transparent SDL2Window top left corner Y axis. - /// - public HookController(int x, int y) - { - this.messages = new Queue(); - this.windowX = x; - this.windowY = y; - this.enable = true; - this.myHook = Hook.GlobalEvents(); - } - - private enum HookControllerMessageType - { - MouseUpDown, - MouseMove, - MouseWheel, - KeyUp, - KeyDown, - KeyPress, - } - - /// - /// Enable this class functionality ( only call it once ). - /// - public void EnableHooks() - { - this.myHook.KeyDown += this.HookKeyDown; - this.myHook.KeyUp += this.HookKeyUp; - this.myHook.KeyPress += this.HookKeyPress; - - this.myHook.MouseDownExt += this.HookMouseDownExt; - this.myHook.MouseMove += this.HookMouseMove; - this.myHook.MouseUpExt += this.HookMouseUpExt; - - this.myHook.MouseWheelExt += this.HookMouseWheelExt; - } - - /// - /// Update transparent SDL2Window top left position. - /// - /// - /// X axis of the SDL2Window top left corner. - /// - /// - /// Y axis of the SDL2Window top left corner. - /// - public void UpdateWindowPosition(int x, int y) - { - this.windowX = x; - this.windowY = y; - } - - /// - /// Pause the hooks. - /// - public void PauseHooks() - { - this.enable = false; - } - - /// - /// Resume the hooks. - /// - public void ResumeHooks() - { - this.enable = true; - } - - /// - /// Dispose the resources acquired by this class. - /// - public void Dispose() - { - this.myHook.KeyDown -= this.HookKeyDown; - this.myHook.KeyUp -= this.HookKeyUp; - this.myHook.KeyPress -= this.HookKeyPress; - - this.myHook.MouseDownExt -= this.HookMouseDownExt; - this.myHook.MouseMove -= this.HookMouseMove; - this.myHook.MouseUpExt -= this.HookMouseUpExt; - - this.myHook.MouseWheelExt -= this.HookMouseWheelExt; - this.myHook.Dispose(); - this.messages.Clear(); - } - - /// - /// Consumes all (max limit 10 to avoid infinite loop) the - /// keyboard/mouse messages from the message queue. - /// - public void PopMessages() - { - int counter = 0; - int maxCounter = 20; - while (counter < maxCounter && this.messages.Count > 0) - { - var message = this.messages.Dequeue(); - try - { - switch (message.Type) - { - case HookControllerMessageType.MouseUpDown: - this.ProcessMouseUpDown((MouseEventExtArgs)message.E, message.MiscArg, true); - break; - case HookControllerMessageType.MouseMove: - this.ProcessMouseMove((MouseEventArgs)message.E, true); - break; - case HookControllerMessageType.MouseWheel: - this.ProcessMouseWheel((MouseEventExtArgs)message.E, true); - break; - case HookControllerMessageType.KeyUp: - this.ProcessKeyUp((KeyEventArgs)message.E, true); - break; - case HookControllerMessageType.KeyDown: - this.ProcessKeyDown((KeyEventArgs)message.E, true); - break; - case HookControllerMessageType.KeyPress: - this.ProcessKeyPress((KeyPressEventArgs)message.E, true); - break; - default: - break; - } - } - catch (Exception e) - { - Console.WriteLine("Warning: Caught an exception while handling keyboard/mouse inputs." + - "Report to the GitHub repository if this effects your work & it's reproduceable."); - Console.WriteLine(e.Message); - Console.WriteLine(e.StackTrace); - } - - counter++; - } - } - - /// - /// Push the keyboard/mouse message to the message queue. - /// - /// - /// Message Type. - /// - /// - /// Message details. - /// - /// - /// Only Mouse Up/Down hook uses this param to pass isDownEvent param. - /// - private void PushMessage(HookControllerMessageType type, EventArgs e, bool miscArg = false) - { - var message = new HookControllerMessage() - { - Type = type, - E = e, - MiscArg = miscArg, - }; - - this.messages.Enqueue(message); - } - - private void ProcessMouseUpDown(MouseEventExtArgs e, bool isDownEvent, bool shouldSendToImGui) - { - ImGuiIOPtr io = ImGui.GetIO(); - if (shouldSendToImGui) - { - switch (e.Button) - { - case MouseButtons.Left: - io.MouseDown[0] = isDownEvent; - break; - case MouseButtons.Right: - io.MouseDown[1] = isDownEvent; - break; - case MouseButtons.Middle: - io.MouseDown[2] = isDownEvent; - break; - case MouseButtons.XButton1: - io.MouseDown[3] = isDownEvent; - break; - case MouseButtons.XButton2: - io.MouseDown[4] = isDownEvent; - break; - case MouseButtons.None: - // TODO: Find out what does this None mean - break; - default: - // TODO: Make a Logger for the whole Overlay - break; - } - } - else - { - this.PushMessage(HookControllerMessageType.MouseUpDown, e, isDownEvent); - } - - if (io.WantCaptureMouse) - { - e.Handled = true; - } - } - - private void ProcessMouseMove(MouseEventArgs e, bool shouldSendToImGui) - { - if (shouldSendToImGui) - { - ImGuiIOPtr io = ImGui.GetIO(); - io.MousePos = new Vector2(e.X - this.windowX, e.Y - this.windowY); - - // TODO: Show ImGUI Cursor/Hide ImGui Cursor - // ImGui.GetIO().MouseDrawCursor = true; - // Window32 API ShowCursor(false) - } - else - { - this.PushMessage(HookControllerMessageType.MouseMove, e); - } - } - - private void ProcessMouseWheel(MouseEventExtArgs e, bool shouldSendToImGui) - { - ImGuiIOPtr io = ImGui.GetIO(); - if (io.WantCaptureMouse) - { - if (shouldSendToImGui) - { - io.MouseWheel = e.Delta / SystemInformation.MouseWheelScrollDelta; - } - else - { - this.PushMessage(HookControllerMessageType.MouseWheel, e); - } - - e.Handled = true; - } - } - - private void ProcessKeyUp(KeyEventArgs e, bool shouldSendToImGui) - { - if (shouldSendToImGui) - { - var io = ImGui.GetIO(); - io.KeysDown[e.KeyValue] = false; - - switch (e.KeyCode) - { - case Keys.LWin: - case Keys.RWin: - io.KeySuper = false; - break; - case Keys.LControlKey: - case Keys.RControlKey: - io.KeyCtrl = false; - break; - case Keys.LMenu: - case Keys.RMenu: - io.KeyAlt = false; - break; - case Keys.LShiftKey: - case Keys.RShiftKey: - io.KeyShift = false; - break; - default: - break; - } - } - else - { - this.PushMessage(HookControllerMessageType.KeyUp, e); - } - } - - private void ProcessKeyDown(KeyEventArgs e, bool shouldSendToImGui) - { - var io = ImGui.GetIO(); - if (io.WantCaptureKeyboard) - { - if (shouldSendToImGui) - { - io.KeysDown[e.KeyValue] = true; - } - else - { - this.PushMessage(HookControllerMessageType.KeyDown, e); - } - - switch (e.KeyCode) - { - case Keys.LWin: - case Keys.RWin: - if (shouldSendToImGui) - { - io.KeySuper = true; - } - - break; - case Keys.LControlKey: - case Keys.RControlKey: - if (shouldSendToImGui) - { - io.KeyCtrl = true; - } - - e.Handled = true; - break; - case Keys.LMenu: // LAlt is LMenu - case Keys.RMenu: // RAlt is RMenu - if (shouldSendToImGui) - { - io.KeyAlt = true; - } - - break; - case Keys.LShiftKey: - case Keys.RShiftKey: - if (shouldSendToImGui) - { - io.KeyShift = true; - } - - break; - default: - // Ignoring ALT key so we can do ALT+TAB or ALT+F4 etc. - // Not sure if ImGUI needs to use ALT+XXX key for anything. - // Ignoring Capital/NumLock key so Windows can use it. - // Ignoring Win/Super key so we can do Win+D or other stuff. - // Create a new issue on the repo if I miss any important key. - if (!io.KeyAlt && e.KeyCode != Keys.Capital && e.KeyCode != Keys.NumLock && !io.KeySuper && - e.KeyCode != Keys.PrintScreen && e.KeyCode != Keys.Print) - { - e.Handled = true; - } - - break; - } - } - } - - private void ProcessKeyPress(KeyPressEventArgs e, bool shouldSendToImGui) - { - var io = ImGui.GetIO(); - - // Ignoring Win/Super key so we can do Win+D or other stuff - // Ignoring ALT key so we can do ALT+TAB or ALT+F4 etc. - // Not sure if ImGUI needs to use ALT+XXX or Super+XXX key for anything. - if (io.KeySuper || io.KeyAlt) - { - return; - } - - if (io.WantTextInput || io.WantCaptureKeyboard) - { - if (shouldSendToImGui) - { - io.AddInputCharacter(e.KeyChar); - } - else - { - this.PushMessage(HookControllerMessageType.KeyPress, e); - } - - e.Handled = true; - } - } - - private void HookMouseUpExt(object sender, MouseEventExtArgs e) - { - if (this.enable) - { - this.ProcessMouseUpDown(e, false, false); - } - } - - private void HookMouseDownExt(object sender, MouseEventExtArgs e) - { - if (this.enable) - { - this.ProcessMouseUpDown(e, true, false); - } - } - - private void HookMouseMove(object sender, MouseEventArgs e) - { - if (!this.enable) - { - return; - } - - this.ProcessMouseMove(e, false); - } - - private void HookMouseWheelExt(object sender, MouseEventExtArgs e) - { - if (!this.enable) - { - return; - } - - this.ProcessMouseWheel(e, false); - } - - private void HookKeyUp(object sender, KeyEventArgs e) - { - this.ProcessKeyUp(e, true); - } - - private void HookKeyDown(object sender, KeyEventArgs e) - { - if (!this.enable) - { - return; - } - - this.ProcessKeyDown(e, true); - } - - private void HookKeyPress(object sender, KeyPressEventArgs e) - { - if (!this.enable) - { - return; - } - - this.ProcessKeyPress(e, false); - } - - private struct HookControllerMessage - { - public HookControllerMessageType Type { get; set; } - - public EventArgs E { get; set; } - - public bool MiscArg { get; set; } - } - } -} diff --git a/ClickableTransparentOverlay/ImGuiController.cs b/ClickableTransparentOverlay/ImGuiController.cs index 813eab6..8ac8482 100644 --- a/ClickableTransparentOverlay/ImGuiController.cs +++ b/ClickableTransparentOverlay/ImGuiController.cs @@ -1,151 +1,108 @@ -// +using System; +using System.Collections.Generic; +using System.Numerics; +using System.Reflection; +using System.IO; +using Veldrid; +using System.Runtime.CompilerServices; +using ImGuiNET; + namespace ClickableTransparentOverlay { - using System; - using System.Collections.Generic; - using System.IO; - using System.Numerics; - using System.Reflection; - using System.Runtime.CompilerServices; - using ImGuiNET; - using NativeLibraryLoader; - using Veldrid; - /// - /// A modified version of ImGui.NET.SampleProgram's ImGuiController. + /// A modified version of Veldrid.ImGui's ImGuiRenderer. /// Manages input for ImGui and handles rendering ImGui's DrawLists with Veldrid. /// - public sealed class ImGuiController : IDisposable + public class ImGuiController : IDisposable { -#pragma warning disable CS0169 // Force Copy this DLL - private readonly DefaultPathResolver useless; -#pragma warning restore CS0169 + private GraphicsDevice _gd; + private bool _frameBegun; - private readonly IntPtr fontAtlasID = (IntPtr)1; + // Veldrid objects + private DeviceBuffer _vertexBuffer; + private DeviceBuffer _indexBuffer; + private DeviceBuffer _projMatrixBuffer; + private Texture _fontTexture; + private TextureView _fontTextureView; + private Shader _vertexShader; + private Shader _fragmentShader; + private ResourceLayout _layout; + private ResourceLayout _textureLayout; + private Pipeline _pipeline; + private ResourceSet _mainResourceSet; + private ResourceSet _fontTextureResourceSet; + + private readonly IntPtr _fontAtlasID = (IntPtr)1; + private bool _controlDown; + private bool _shiftDown; + private bool _altDown; + private bool _winKeyDown; + + private int _windowWidth; + private int _windowHeight; + private Vector2 _scaleFactor = Vector2.One; // Image trackers - private readonly Dictionary setsByView + private readonly Dictionary _setsByView = new Dictionary(); - - private readonly Dictionary autoViewsByTexture + private readonly Dictionary _autoViewsByTexture = new Dictionary(); - - private readonly Dictionary viewsById - = new Dictionary(); - - private readonly List ownedResources - = new List(); - - private int lastAssignedID = 100; - - private GraphicsDevice gd; - private bool frameBegun; - - // Veldrid objects - private DeviceBuffer vertexBuffer; - private DeviceBuffer indexBuffer; - private DeviceBuffer projMatrixBuffer; - private Texture fontTexture; - private TextureView fontTextureView; - private Shader vertexShader; - private Shader fragmentShader; - private ResourceLayout layout; - private ResourceLayout textureLayout; - private Pipeline pipeline; - private ResourceSet mainResourceSet; - private ResourceSet fontTextureResourceSet; - - private int windowWidth; - private int windowHeight; - private Vector2 scaleFactor = Vector2.One; + private readonly Dictionary _viewsById = new Dictionary(); + private readonly List _ownedResources = new List(); + private int _lastAssignedID = 100; /// - /// Initializes a new instance of the class. + /// Constructs a new ImGuiController. /// - /// - /// Graphic Device - /// - /// - /// Output Description - /// - /// - /// SDL2Window Window width - /// - /// - /// SDL2Window Window height - /// - /// - /// desired FPS of the ImGui Overlay - /// - public ImGuiController(GraphicsDevice gd, OutputDescription outputDescription, int width, int height, int fps) + public ImGuiController(GraphicsDevice gd, OutputDescription outputDescription, int width, int height) { - this.gd = gd; - this.windowWidth = width; - this.windowHeight = height; + _gd = gd; + _windowWidth = width; + _windowHeight = height; IntPtr context = ImGui.CreateContext(); ImGui.SetCurrentContext(context); - ImGui.GetIO().Fonts.AddFontDefault(); - this.CreateDeviceResources(gd, outputDescription); + CreateDeviceResources(gd, outputDescription); SetKeyMappings(); - this.SetPerFrameImGuiData(1f / fps); + SetPerFrameImGuiData(1f / 60f); ImGui.NewFrame(); - this.frameBegun = true; + _frameBegun = true; } - /// - /// Updates the ImGui about the SDL2Window Size - /// - /// - /// Width of the SDL2Window - /// - /// - /// Height of the SDL2Window - /// public void WindowResized(int width, int height) { - this.windowWidth = width; - this.windowHeight = height; + _windowWidth = width; + _windowHeight = height; } - /// - /// Disposes the resources acquired by the ImGuiController class. - /// public void DestroyDeviceObjects() { - this.Dispose(); + Dispose(); } - /// - /// Initializes different resources for ImGui Controller class. - /// - /// - /// Graphic Device - /// - /// - /// Output Description - /// public void CreateDeviceResources(GraphicsDevice gd, OutputDescription outputDescription) { - this.gd = gd; + _gd = gd; ResourceFactory factory = gd.ResourceFactory; - this.vertexBuffer = factory.CreateBuffer(new BufferDescription(10000, BufferUsage.VertexBuffer | BufferUsage.Dynamic)); - this.vertexBuffer.Name = "ImGui.NET Vertex Buffer"; - this.indexBuffer = factory.CreateBuffer(new BufferDescription(2000, BufferUsage.IndexBuffer | BufferUsage.Dynamic)); - this.indexBuffer.Name = "ImGui.NET Index Buffer"; - this.RecreateFontDeviceTexture(gd); - - this.projMatrixBuffer = factory.CreateBuffer(new BufferDescription(64, BufferUsage.UniformBuffer | BufferUsage.Dynamic)); - this.projMatrixBuffer.Name = "ImGui.NET Projection Buffer"; - - byte[] vertexShaderBytes = this.LoadEmbeddedShaderCode(gd.ResourceFactory, "imgui-vertex", ShaderStages.Vertex); - byte[] fragmentShaderBytes = this.LoadEmbeddedShaderCode(gd.ResourceFactory, "imgui-frag", ShaderStages.Fragment); - this.vertexShader = factory.CreateShader(new ShaderDescription(ShaderStages.Vertex, vertexShaderBytes, "VS")); - this.fragmentShader = factory.CreateShader(new ShaderDescription(ShaderStages.Fragment, fragmentShaderBytes, "FS")); + _vertexBuffer = factory.CreateBuffer(new BufferDescription(10000, BufferUsage.VertexBuffer | BufferUsage.Dynamic)); + _vertexBuffer.Name = "ImGui.NET Vertex Buffer"; + _indexBuffer = factory.CreateBuffer(new BufferDescription(2000, BufferUsage.IndexBuffer | BufferUsage.Dynamic)); + _indexBuffer.Name = "ImGui.NET Index Buffer"; + RecreateFontDeviceTexture(gd); + + _projMatrixBuffer = factory.CreateBuffer(new BufferDescription(64, BufferUsage.UniformBuffer | BufferUsage.Dynamic)); + _projMatrixBuffer.Name = "ImGui.NET Projection Buffer"; + + byte[] vertexShaderBytes = LoadEmbeddedShaderCode(gd.ResourceFactory, "imgui-vertex", ShaderStages.Vertex); + byte[] fragmentShaderBytes = LoadEmbeddedShaderCode(gd.ResourceFactory, "imgui-frag", ShaderStages.Fragment); + _vertexShader = factory.CreateShader(new ShaderDescription( + ShaderStages.Vertex, vertexShaderBytes, _gd.BackendType == GraphicsBackend.Vulkan ? "main" : "VS")); + _fragmentShader = factory.CreateShader(new ShaderDescription( + ShaderStages.Fragment, fragmentShaderBytes, _gd.BackendType == GraphicsBackend.Vulkan ? "main" : "FS")); VertexLayoutDescription[] vertexLayouts = new VertexLayoutDescription[] { @@ -155,10 +112,10 @@ namespace ClickableTransparentOverlay new VertexElementDescription("in_color", VertexElementSemantic.Color, VertexElementFormat.Byte4_Norm)) }; - this.layout = factory.CreateResourceLayout(new ResourceLayoutDescription( + _layout = factory.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription("ProjectionMatrixBuffer", ResourceKind.UniformBuffer, ShaderStages.Vertex), new ResourceLayoutElementDescription("MainSampler", ResourceKind.Sampler, ShaderStages.Fragment))); - this.textureLayout = factory.CreateResourceLayout(new ResourceLayoutDescription( + _textureLayout = factory.CreateResourceLayout(new ResourceLayoutDescription( new ResourceLayoutElementDescription("MainTexture", ResourceKind.TextureReadOnly, ShaderStages.Fragment))); GraphicsPipelineDescription pd = new GraphicsPipelineDescription( @@ -166,85 +123,96 @@ namespace ClickableTransparentOverlay new DepthStencilStateDescription(false, false, ComparisonKind.Always), new RasterizerStateDescription(FaceCullMode.None, PolygonFillMode.Solid, FrontFace.Clockwise, false, true), PrimitiveTopology.TriangleList, - new ShaderSetDescription(vertexLayouts, new[] { this.vertexShader, this.fragmentShader }), - new ResourceLayout[] { this.layout, this.textureLayout }, - outputDescription); - this.pipeline = factory.CreateGraphicsPipeline(ref pd); + new ShaderSetDescription(vertexLayouts, new[] { _vertexShader, _fragmentShader }), + new ResourceLayout[] { _layout, _textureLayout }, + outputDescription, + ResourceBindingModel.Default); + _pipeline = factory.CreateGraphicsPipeline(ref pd); - this.mainResourceSet = factory.CreateResourceSet(new ResourceSetDescription( - this.layout, this.projMatrixBuffer, gd.PointSampler)); + _mainResourceSet = factory.CreateResourceSet(new ResourceSetDescription(_layout, + _projMatrixBuffer, + gd.PointSampler)); - this.fontTextureResourceSet = factory.CreateResourceSet( - new ResourceSetDescription(this.textureLayout, this.fontTextureView)); + _fontTextureResourceSet = factory.CreateResourceSet(new ResourceSetDescription(_textureLayout, _fontTextureView)); } /// /// Gets or creates a handle for a texture to be drawn with ImGui. - /// Pass the returned handle to Image() or ImageButton(). + /// E.G. Pass the returned handle to Image() or ImageButton(). /// - /// - /// Resource Factory - /// - /// - /// Texture View - /// - /// - /// Creates ImGui Binding - /// public IntPtr GetOrCreateImGuiBinding(ResourceFactory factory, TextureView textureView) { - if (!this.setsByView.TryGetValue(textureView, out ResourceSetInfo rsi)) + if (!_setsByView.TryGetValue(textureView, out ResourceSetInfo rsi)) { - ResourceSet resourceSet = factory.CreateResourceSet( - new ResourceSetDescription(this.textureLayout, textureView)); - - rsi = new ResourceSetInfo(this.GetNextImGuiBindingID(), resourceSet); + ResourceSet resourceSet = factory.CreateResourceSet(new ResourceSetDescription(_textureLayout, textureView)); + rsi = new ResourceSetInfo(GetNextImGuiBindingID(), resourceSet); - this.setsByView.Add(textureView, rsi); - this.viewsById.Add(rsi.ImGuiBinding, rsi); - this.ownedResources.Add(resourceSet); + _setsByView.Add(textureView, rsi); + _viewsById.Add(rsi.ImGuiBinding, rsi); + _ownedResources.Add(resourceSet); } return rsi.ImGuiBinding; } + /// + /// Removes the texture from the resources. + /// + /// texture to remove + public void RemoveImGuiBinding(TextureView textureView) + { + if (_setsByView.TryGetValue(textureView, out ResourceSetInfo rsi)) + { + _setsByView.Remove(textureView); + _viewsById.Remove(rsi.ImGuiBinding); + _ownedResources.Remove(rsi.ResourceSet); + rsi.ResourceSet.Dispose(); + } + } + + /// + /// Removes the texture from the resources. + /// + /// texture to remove + public void RemoveImGuiBinding(Texture texture) + { + if (_autoViewsByTexture.TryGetValue(texture, out TextureView textureView)) + { + _autoViewsByTexture.Remove(texture); + _ownedResources.Remove(textureView); + textureView.Dispose(); + RemoveImGuiBinding(textureView); + } + } + + private IntPtr GetNextImGuiBindingID() + { + int newID = _lastAssignedID++; + return (IntPtr)newID; + } + /// /// Gets or creates a handle for a texture to be drawn with ImGui. /// Pass the returned handle to Image() or ImageButton(). /// - /// - /// Resource Factory - /// - /// - /// Texture information - /// - /// - /// Pointer to the resource - /// public IntPtr GetOrCreateImGuiBinding(ResourceFactory factory, Texture texture) { - if (!this.autoViewsByTexture.TryGetValue(texture, out TextureView textureView)) + if (!_autoViewsByTexture.TryGetValue(texture, out TextureView textureView)) { textureView = factory.CreateTextureView(texture); - this.autoViewsByTexture.Add(texture, textureView); - this.ownedResources.Add(textureView); + _autoViewsByTexture.Add(texture, textureView); + _ownedResources.Add(textureView); } - return this.GetOrCreateImGuiBinding(factory, textureView); + return GetOrCreateImGuiBinding(factory, textureView); } /// /// Retrieves the shader texture binding for the given helper handle. /// - /// - /// ImGui Binding resource pointer. - /// - /// - /// Resource - /// public ResourceSet GetImageResourceSet(IntPtr imGuiBinding) { - if (!this.viewsById.TryGetValue(imGuiBinding, out ResourceSetInfo tvi)) + if (!_viewsById.TryGetValue(imGuiBinding, out ResourceSetInfo tvi)) { throw new InvalidOperationException("No registered ImGui binding with id " + imGuiBinding.ToString()); } @@ -252,52 +220,71 @@ namespace ClickableTransparentOverlay return tvi.ResourceSet; } - /// - /// Clears the cache images. - /// public void ClearCachedImageResources() { - foreach (IDisposable resource in this.ownedResources) + foreach (IDisposable resource in _ownedResources) { resource.Dispose(); } - this.ownedResources.Clear(); - this.setsByView.Clear(); - this.viewsById.Clear(); - this.autoViewsByTexture.Clear(); - this.lastAssignedID = 100; + _ownedResources.Clear(); + _setsByView.Clear(); + _viewsById.Clear(); + _autoViewsByTexture.Clear(); + _lastAssignedID = 100; + } + + private byte[] LoadEmbeddedShaderCode(ResourceFactory factory, string name, ShaderStages _) + { + switch (factory.BackendType) + { + case GraphicsBackend.Direct3D11: + { + string resourceName = name + ".hlsl.bytes"; + return GetEmbeddedResourceBytes(resourceName); + } + default: + throw new NotImplementedException(); + } + } + + private byte[] GetEmbeddedResourceBytes(string resourceName) + { + Assembly assembly = typeof(ImGuiController).Assembly; + using (Stream s = assembly.GetManifestResourceStream(resourceName)) + { + byte[] ret = new byte[s.Length]; + s.Read(ret, 0, (int)s.Length); + return ret; + } } /// /// Recreates the device texture used to render text. /// - /// - /// Graphic Device - /// - public unsafe void RecreateFontDeviceTexture(GraphicsDevice gd) + public void RecreateFontDeviceTexture(GraphicsDevice gd) { ImGuiIOPtr io = ImGui.GetIO(); - // Build - byte* pixels; - int width, height, bytesPerPixel; - io.Fonts.GetTexDataAsRGBA32(out pixels, out width, out height, out bytesPerPixel); - + io.Fonts.GetTexDataAsRGBA32( + out IntPtr pixels, + out int width, + out int height, + out int bytesPerPixel); // Store our identifier - io.Fonts.SetTexID(this.fontAtlasID); + io.Fonts.SetTexID(_fontAtlasID); - this.fontTexture = gd.ResourceFactory.CreateTexture(TextureDescription.Texture2D( + _fontTexture = gd.ResourceFactory.CreateTexture(TextureDescription.Texture2D( (uint)width, (uint)height, 1, 1, PixelFormat.R8_G8_B8_A8_UNorm, TextureUsage.Sampled)); - this.fontTexture.Name = "ImGui.NET Font Texture"; + _fontTexture.Name = "ImGui.NET Font Texture"; gd.UpdateTexture( - this.fontTexture, - (IntPtr)pixels, + _fontTexture, + pixels, (uint)(bytesPerPixel * width * height), 0, 0, @@ -307,7 +294,7 @@ namespace ClickableTransparentOverlay 1, 0, 0); - this.fontTextureView = gd.ResourceFactory.CreateTextureView(this.fontTexture); + _fontTextureView = gd.ResourceFactory.CreateTextureView(_fontTexture); io.Fonts.ClearTexData(); } @@ -318,180 +305,150 @@ namespace ClickableTransparentOverlay /// or index data has increased beyond the capacity of the existing buffers. /// A is needed to submit drawing and resource update commands. /// - /// - /// Graphic Device - /// - /// - /// Command List - /// public void Render(GraphicsDevice gd, CommandList cl) { - if (this.frameBegun) + if (_frameBegun) { - this.frameBegun = false; + _frameBegun = false; ImGui.Render(); - this.RenderImDrawData(ImGui.GetDrawData(), gd, cl); + RenderImDrawData(ImGui.GetDrawData(), gd, cl); } } /// - /// Initilizes a new frame + /// Updates ImGui input and IO configuration state. /// - /// - /// FPS delay - /// - public void InitlizeFrame(float deltaSeconds) + public void Update(float deltaSeconds, InputSnapshot snapshot, IntPtr handle) { - if (this.frameBegun) + if (_frameBegun) { ImGui.Render(); } - this.SetPerFrameImGuiData(deltaSeconds); + SetPerFrameImGuiData(deltaSeconds); + UpdateImGuiInput(snapshot, handle); - this.frameBegun = true; + _frameBegun = true; ImGui.NewFrame(); } /// - /// Frees all graphics resources used by the renderer. + /// Sets per-frame data based on the associated window. + /// This is called by Update(float). /// - public void Dispose() + private void SetPerFrameImGuiData(float deltaSeconds) { - this.vertexBuffer.Dispose(); - this.indexBuffer.Dispose(); - this.projMatrixBuffer.Dispose(); - this.fontTexture.Dispose(); - this.fontTextureView.Dispose(); - this.vertexShader.Dispose(); - this.fragmentShader.Dispose(); - this.layout.Dispose(); - this.textureLayout.Dispose(); - this.pipeline.Dispose(); - this.mainResourceSet.Dispose(); - this.fontTextureResourceSet.Dispose(); - this.ClearCachedImageResources(); + ImGuiIOPtr io = ImGui.GetIO(); + io.DisplaySize = new Vector2( + _windowWidth / _scaleFactor.X, + _windowHeight / _scaleFactor.Y); + io.DisplayFramebufferScale = _scaleFactor; + io.DeltaTime = deltaSeconds; // DeltaTime is in seconds. } - /// - /// Allows ImGui to identify the Keys - /// - private static void SetKeyMappings() + private void UpdateImGuiInput(InputSnapshot snapshot, IntPtr handle) { ImGuiIOPtr io = ImGui.GetIO(); - io.KeyMap[(int)ImGuiKey.Tab] = (int)System.Windows.Forms.Keys.Tab; - io.KeyMap[(int)ImGuiKey.LeftArrow] = (int)System.Windows.Forms.Keys.Left; - io.KeyMap[(int)ImGuiKey.RightArrow] = (int)System.Windows.Forms.Keys.Right; - io.KeyMap[(int)ImGuiKey.UpArrow] = (int)System.Windows.Forms.Keys.Up; - io.KeyMap[(int)ImGuiKey.DownArrow] = (int)System.Windows.Forms.Keys.Down; - io.KeyMap[(int)ImGuiKey.PageUp] = (int)System.Windows.Forms.Keys.PageUp; - io.KeyMap[(int)ImGuiKey.PageDown] = (int)System.Windows.Forms.Keys.PageDown; - io.KeyMap[(int)ImGuiKey.Home] = (int)System.Windows.Forms.Keys.Home; - io.KeyMap[(int)ImGuiKey.End] = (int)System.Windows.Forms.Keys.End; - io.KeyMap[(int)ImGuiKey.Delete] = (int)System.Windows.Forms.Keys.Delete; - io.KeyMap[(int)ImGuiKey.Backspace] = (int)System.Windows.Forms.Keys.Back; - io.KeyMap[(int)ImGuiKey.Enter] = (int)System.Windows.Forms.Keys.Enter; - io.KeyMap[(int)ImGuiKey.Escape] = (int)System.Windows.Forms.Keys.Escape; - - // io.KeyMap[(int)ImGuiKey.COUNT] = (int)System.Windows.Forms.Keys.un; - io.KeyMap[(int)ImGuiKey.Insert] = (int)System.Windows.Forms.Keys.Insert; - io.KeyMap[(int)ImGuiKey.Space] = (int)System.Windows.Forms.Keys.Space; - io.KeyMap[(int)ImGuiKey.A] = (int)System.Windows.Forms.Keys.A; - io.KeyMap[(int)ImGuiKey.C] = (int)System.Windows.Forms.Keys.C; - io.KeyMap[(int)ImGuiKey.V] = (int)System.Windows.Forms.Keys.V; - io.KeyMap[(int)ImGuiKey.X] = (int)System.Windows.Forms.Keys.X; - io.KeyMap[(int)ImGuiKey.Y] = (int)System.Windows.Forms.Keys.Y; - io.KeyMap[(int)ImGuiKey.Z] = (int)System.Windows.Forms.Keys.Z; - } - /// - /// Get the Next ImGui Binding ID. - /// - /// - /// ImGui next binding ID. - /// - private IntPtr GetNextImGuiBindingID() - { - int newID = this.lastAssignedID++; - return (IntPtr)newID; - } + // Determine if any of the mouse buttons were pressed during this snapshot period, even if they are no longer held. + bool leftPressed = false; + bool middlePressed = false; + bool rightPressed = false; + for (int i = 0; i < snapshot.MouseEvents.Count; i++) + { + MouseEvent me = snapshot.MouseEvents[i]; + if (me.Down) + { + switch (me.MouseButton) + { + case MouseButton.Left: + leftPressed = true; + break; + case MouseButton.Middle: + middlePressed = true; + break; + case MouseButton.Right: + rightPressed = true; + break; + } + } + } - /// - /// Loading Shader Code - /// - /// - /// Resource Factory - /// - /// - /// Shader file name - /// - /// - /// Shader stage - /// - /// - /// Returns shader byte code - /// - private byte[] LoadEmbeddedShaderCode(ResourceFactory factory, string name, ShaderStages stage) - { - switch (factory.BackendType) + io.MouseDown[0] = leftPressed || snapshot.IsMouseDown(MouseButton.Left); + io.MouseDown[1] = rightPressed || snapshot.IsMouseDown(MouseButton.Right); + io.MouseDown[2] = middlePressed || snapshot.IsMouseDown(MouseButton.Middle); + io.MousePos = NativeMethods.GetCursorPosition(handle); + io.MouseWheel = snapshot.WheelDelta; + + IReadOnlyList keyCharPresses = snapshot.KeyCharPresses; + for (int i = 0; i < keyCharPresses.Count; i++) { - case GraphicsBackend.Direct3D11: - string resourceName = name + ".hlsl.bytes"; - return this.GetEmbeddedResourceBytes(resourceName); - default: - throw new NotImplementedException(); + char c = keyCharPresses[i]; + io.AddInputCharacter(c); } - } - /// - /// Get embedded resource file in bytes - /// - /// - /// Name of the resource file - /// - /// - /// Byte code of the resource file - /// - private byte[] GetEmbeddedResourceBytes(string resourceName) - { - Assembly assembly = typeof(ImGuiController).Assembly; - using (Stream s = assembly.GetManifestResourceStream(resourceName)) + IReadOnlyList keyEvents = snapshot.KeyEvents; + for (int i = 0; i < keyEvents.Count; i++) { - byte[] ret = new byte[s.Length]; - s.Read(ret, 0, (int)s.Length); - return ret; + KeyEvent keyEvent = keyEvents[i]; + io.KeysDown[(int)keyEvent.Key] = keyEvent.Down; + if (keyEvent.Key == Key.ControlLeft) + { + _controlDown = keyEvent.Down; + } + if (keyEvent.Key == Key.ShiftLeft) + { + _shiftDown = keyEvent.Down; + } + if (keyEvent.Key == Key.AltLeft) + { + _altDown = keyEvent.Down; + } + if (keyEvent.Key == Key.WinLeft) + { + _winKeyDown = keyEvent.Down; + } + } + + io.KeyCtrl = _controlDown; + io.KeyAlt = _altDown; + io.KeyShift = _shiftDown; + io.KeySuper = _winKeyDown; + + if (io.WantCaptureKeyboard || io.WantCaptureMouse) + { + NativeMethods.SetOverlayClickable(handle, true); + } + else + { + NativeMethods.SetOverlayClickable(handle, false); } } - /// - /// Sets per-frame data based on the associated window. - /// This is called by Update(float). - /// - /// - /// FPS delay - /// - private void SetPerFrameImGuiData(float deltaSeconds) + private static void SetKeyMappings() { ImGuiIOPtr io = ImGui.GetIO(); - io.DisplaySize = new Vector2( - this.windowWidth / this.scaleFactor.X, - this.windowHeight / this.scaleFactor.Y); - io.DisplayFramebufferScale = this.scaleFactor; - io.DeltaTime = deltaSeconds; // DeltaTime is in seconds. + io.KeyMap[(int)ImGuiKey.Tab] = (int)Key.Tab; + io.KeyMap[(int)ImGuiKey.LeftArrow] = (int)Key.Left; + io.KeyMap[(int)ImGuiKey.RightArrow] = (int)Key.Right; + io.KeyMap[(int)ImGuiKey.UpArrow] = (int)Key.Up; + io.KeyMap[(int)ImGuiKey.DownArrow] = (int)Key.Down; + io.KeyMap[(int)ImGuiKey.PageUp] = (int)Key.PageUp; + io.KeyMap[(int)ImGuiKey.PageDown] = (int)Key.PageDown; + io.KeyMap[(int)ImGuiKey.Home] = (int)Key.Home; + io.KeyMap[(int)ImGuiKey.End] = (int)Key.End; + io.KeyMap[(int)ImGuiKey.Delete] = (int)Key.Delete; + io.KeyMap[(int)ImGuiKey.Backspace] = (int)Key.BackSpace; + io.KeyMap[(int)ImGuiKey.Enter] = (int)Key.Enter; + io.KeyMap[(int)ImGuiKey.Escape] = (int)Key.Escape; + io.KeyMap[(int)ImGuiKey.A] = (int)Key.A; + io.KeyMap[(int)ImGuiKey.C] = (int)Key.C; + io.KeyMap[(int)ImGuiKey.V] = (int)Key.V; + io.KeyMap[(int)ImGuiKey.X] = (int)Key.X; + io.KeyMap[(int)ImGuiKey.Y] = (int)Key.Y; + io.KeyMap[(int)ImGuiKey.Z] = (int)Key.Z; } - /// - /// Draw the ImGui graphic data - /// - /// - /// ImGui data to draw - /// - /// - /// Graphic Device - /// - /// - /// Command List - /// private void RenderImDrawData(ImDrawDataPtr draw_data, GraphicsDevice gd, CommandList cl) { uint vertexOffsetInVertices = 0; @@ -503,19 +460,17 @@ namespace ClickableTransparentOverlay } uint totalVBSize = (uint)(draw_data.TotalVtxCount * Unsafe.SizeOf()); - if (totalVBSize > this.vertexBuffer.SizeInBytes) + if (totalVBSize > _vertexBuffer.SizeInBytes) { - gd.DisposeWhenIdle(this.vertexBuffer); - this.vertexBuffer = gd.ResourceFactory.CreateBuffer(new BufferDescription( - (uint)(totalVBSize * 1.5f), BufferUsage.VertexBuffer | BufferUsage.Dynamic)); + _vertexBuffer.Dispose(); + _vertexBuffer = gd.ResourceFactory.CreateBuffer(new BufferDescription((uint)(totalVBSize * 1.5f), BufferUsage.VertexBuffer | BufferUsage.Dynamic)); } uint totalIBSize = (uint)(draw_data.TotalIdxCount * sizeof(ushort)); - if (totalIBSize > this.indexBuffer.SizeInBytes) + if (totalIBSize > _indexBuffer.SizeInBytes) { - gd.DisposeWhenIdle(this.indexBuffer); - this.indexBuffer = gd.ResourceFactory.CreateBuffer(new BufferDescription( - (uint)(totalIBSize * 1.5f), BufferUsage.IndexBuffer | BufferUsage.Dynamic)); + _indexBuffer.Dispose(); + _indexBuffer = gd.ResourceFactory.CreateBuffer(new BufferDescription((uint)(totalIBSize * 1.5f), BufferUsage.IndexBuffer | BufferUsage.Dynamic)); } for (int i = 0; i < draw_data.CmdListsCount; i++) @@ -523,13 +478,13 @@ namespace ClickableTransparentOverlay ImDrawListPtr cmd_list = draw_data.CmdListsRange[i]; cl.UpdateBuffer( - this.vertexBuffer, + _vertexBuffer, vertexOffsetInVertices * (uint)Unsafe.SizeOf(), cmd_list.VtxBuffer.Data, (uint)(cmd_list.VtxBuffer.Size * Unsafe.SizeOf())); cl.UpdateBuffer( - this.indexBuffer, + _indexBuffer, indexOffsetInElements * sizeof(ushort), cmd_list.IdxBuffer.Data, (uint)(cmd_list.IdxBuffer.Size * sizeof(ushort))); @@ -548,12 +503,12 @@ namespace ClickableTransparentOverlay -1.0f, 1.0f); - this.gd.UpdateBuffer(this.projMatrixBuffer, 0, ref mvp); + _gd.UpdateBuffer(_projMatrixBuffer, 0, ref mvp); - cl.SetVertexBuffer(0, this.vertexBuffer); - cl.SetIndexBuffer(this.indexBuffer, IndexFormat.UInt16); - cl.SetPipeline(this.pipeline); - cl.SetGraphicsResourceSet(0, this.mainResourceSet); + cl.SetVertexBuffer(0, _vertexBuffer); + cl.SetIndexBuffer(_indexBuffer, IndexFormat.UInt16); + cl.SetPipeline(_pipeline); + cl.SetGraphicsResourceSet(0, _mainResourceSet); draw_data.ScaleClipRects(io.DisplayFramebufferScale); @@ -574,15 +529,13 @@ namespace ClickableTransparentOverlay { if (pcmd.TextureId != IntPtr.Zero) { - if (pcmd.TextureId == this.fontAtlasID) + if (pcmd.TextureId == _fontAtlasID) { - cl.SetGraphicsResourceSet( - 1, this.fontTextureResourceSet); + cl.SetGraphicsResourceSet(1, _fontTextureResourceSet); } else { - cl.SetGraphicsResourceSet( - 1, this.GetImageResourceSet(pcmd.TextureId)); + cl.SetGraphicsResourceSet(1, GetImageResourceSet(pcmd.TextureId)); } } @@ -598,14 +551,30 @@ namespace ClickableTransparentOverlay idx_offset += (int)pcmd.ElemCount; } - vtx_offset += cmd_list.VtxBuffer.Size; } } /// - /// ResourceSetInfo + /// Frees all graphics resources used by the renderer. /// + public void Dispose() + { + _vertexBuffer.Dispose(); + _indexBuffer.Dispose(); + _projMatrixBuffer.Dispose(); + _fontTexture.Dispose(); + _fontTextureView.Dispose(); + _vertexShader.Dispose(); + _fragmentShader.Dispose(); + _layout.Dispose(); + _textureLayout.Dispose(); + _pipeline.Dispose(); + _mainResourceSet.Dispose(); + ClearCachedImageResources(); + _fontTextureResourceSet.Dispose(); + } + private struct ResourceSetInfo { public readonly IntPtr ImGuiBinding; @@ -613,8 +582,8 @@ namespace ClickableTransparentOverlay public ResourceSetInfo(IntPtr imGuiBinding, ResourceSet resourceSet) { - this.ImGuiBinding = imGuiBinding; - this.ResourceSet = resourceSet; + ImGuiBinding = imGuiBinding; + ResourceSet = resourceSet; } } } diff --git a/ClickableTransparentOverlay/NativeMethods.cs b/ClickableTransparentOverlay/NativeMethods.cs index 8f80b14..b410533 100644 --- a/ClickableTransparentOverlay/NativeMethods.cs +++ b/ClickableTransparentOverlay/NativeMethods.cs @@ -1,13 +1,10 @@ -// -// Copyright (c) Zaafar Ahmed. All rights reserved. -// +using System; +using System.Drawing; +using System.Numerics; +using System.Runtime.InteropServices; namespace ClickableTransparentOverlay { - using System; - using System.Drawing; - using System.Runtime.InteropServices; - /// /// This class allow user to access Win32 API functions. /// @@ -20,39 +17,107 @@ namespace ClickableTransparentOverlay private const int SW_HIDE = 0x00; private const int SW_SHOW = 0x05; + public static bool IsClickable = true; + private static IntPtr GWL_EXSTYLE_CLICKABLE = IntPtr.Zero; + private static IntPtr GWL_EXSTYLE_NOT_CLICKABLE = IntPtr.Zero; + + private const int KEY_PRESSED = 0x8000; + /// /// Allows the SDL2Window to become transparent. /// /// /// Veldrid window handle in IntPtr format. /// - public static void EnableTransparent(IntPtr handle) + public static void InitTransparency(IntPtr handle) { - IntPtr windowLong = GetWindowLongPtr(handle, GWL_EXSTYLE); - windowLong = new IntPtr(windowLong.ToInt64() | WS_EX_LAYERED | WS_EX_TRANSPARENT); - SetWindowLongPtr(handle, GWL_EXSTYLE, windowLong); + GWL_EXSTYLE_CLICKABLE = GetWindowLongPtr(handle, GWL_EXSTYLE); + GWL_EXSTYLE_NOT_CLICKABLE = new IntPtr( + GWL_EXSTYLE_CLICKABLE.ToInt64() | WS_EX_LAYERED | WS_EX_TRANSPARENT); + Margins margins = Margins.FromRectangle(new Rectangle(-1, -1, -1, -1)); DwmExtendFrameIntoClientArea(handle, ref margins); } /// - /// Allows hiding the console window. + /// Enables (clickable) / Disables (not clickable) the SDL2Window keyboard/mouse inputs. + /// NOTE: This function depends on InitTransparency being called when the SDL2Winhdow was created. + /// + /// Veldrid window handle in IntPtr format. + /// Set to true if you want to make the window clickable otherwise false. + public static void SetOverlayClickable(IntPtr handle, bool WantClickable) + { + if (!IsClickable && WantClickable) + { + SetWindowLongPtr(handle, GWL_EXSTYLE, GWL_EXSTYLE_CLICKABLE); + SetFocus(handle); + IsClickable = true; + } + else if(IsClickable && !WantClickable) + { + SetWindowLongPtr(handle, GWL_EXSTYLE, GWL_EXSTYLE_NOT_CLICKABLE); + IsClickable = false; + } + } + + /// + /// Allows showing/hiding the console window. + /// + public static void SetConsoleWindow(bool visiable) + { + if (visiable) + { + var handle = GetConsoleWindow(); + ShowWindow(handle, SW_SHOW); + } + else + { + var handle = GetConsoleWindow(); + ShowWindow(handle, SW_HIDE); + } + } + + /// + /// Returns the current mouse position w.r.t the window in Vector2 format. + /// Also, returns Zero in case of any errors. /// - public static void HideConsoleWindow() + /// + /// + public static Vector2 GetCursorPosition(IntPtr hWnd) { - var handle = GetConsoleWindow(); - ShowWindow(handle, SW_HIDE); + if (GetCursorPos(out var lpPoint)) + { + ScreenToClient(hWnd, ref lpPoint); + return lpPoint; + } + + return Vector2.Zero; } /// - /// Allows displaying the console window. + /// Returns true if the key is pressed. + /// For keycode information visit: https://www.pinvoke.net/default.aspx/user32.getkeystate /// - public static void ShowConsoleWindow() + /// key to look for. + /// weather the key is pressed or not. + public static bool isKeyPressed(int nVirtKey) { - var handle = GetConsoleWindow(); - ShowWindow(handle, SW_SHOW); + return Convert.ToBoolean(GetKeyState(nVirtKey) & KEY_PRESSED); } + [DllImport("USER32.dll")] + static extern short GetKeyState(int nVirtKey); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + static extern bool GetCursorPos(out POINT lpPoint); + + [DllImport("user32.dll")] + static extern bool ScreenToClient(IntPtr hWnd, ref POINT lpPoint); + + [DllImport("user32.dll", SetLastError = true)] + static extern IntPtr SetFocus(IntPtr hWnd); + [DllImport("dwmapi.dll")] private static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref Margins pMarInset); @@ -88,5 +153,28 @@ namespace ClickableTransparentOverlay return margins; } } + + [StructLayout(LayoutKind.Sequential)] + public struct POINT + { + public int X; + public int Y; + + public POINT(int x, int y) + { + this.X = x; + this.Y = y; + } + + public static implicit operator Point(POINT p) + { + return new Point(p.X, p.Y); + } + + public static implicit operator Vector2(POINT p) + { + return new Vector2(p.X, p.Y); + } + } } -} \ No newline at end of file +} diff --git a/ClickableTransparentOverlay/Overlay.cs b/ClickableTransparentOverlay/Overlay.cs index e91c95a..716d619 100644 --- a/ClickableTransparentOverlay/Overlay.cs +++ b/ClickableTransparentOverlay/Overlay.cs @@ -1,42 +1,28 @@ -// -// Copyright (c) Zaafar Ahmed. All rights reserved. -// +using System; +using System.Collections.Generic; +using System.Numerics; +using System.Threading; +using Coroutine; +using Veldrid; +using Veldrid.ImageSharp; +using Veldrid.Sdl2; +using Veldrid.StartupUtilities; namespace ClickableTransparentOverlay { - using System; - using System.Collections.Generic; - using System.Numerics; - using System.Threading; - using System.Windows.Forms; - using Veldrid; - using Veldrid.ImageSharp; - using Veldrid.Sdl2; - using Veldrid.StartupUtilities; - + // TODO: Implement overlay info, warn, error logger. /// /// A class to create clickable transparent overlay. /// - public class Overlay + public static class Overlay { - private static Sdl2Window window; - private static GraphicsDevice graphicsDevice; - private static CommandList commandList; - private static ImGuiController imController; - private static HookController hookController; - private static Thread uiThread; - - // UI State - private static Vector4 clearColor; - private static int myFps; - private static bool isClosed; - private static Dictionary loadedImages; - - // For Resizing SDL2Window - private static Vector2 futurePos; - private static Vector2 futureSize; - private static bool requireResize; - private static bool debugMode; + private readonly static Sdl2Window window; + private readonly static GraphicsDevice graphicsDevice; + private readonly static CommandList commandList; + private readonly static ImGuiController imController; + private readonly static Vector4 clearColor; + private readonly static Dictionary loadedImages; + private static bool terminal = true; /// /// Initializes a new instance of the class. @@ -59,149 +45,139 @@ namespace ClickableTransparentOverlay /// /// In this mode, overlay will not hide the Console. /// - public Overlay(int x, int y, int width, int height, int fps, bool debug) + static Overlay() { - loadedImages = new Dictionary(); clearColor = new Vector4(0.00f, 0.00f, 0.00f, 0.00f); - myFps = fps; - isClosed = false; - debugMode = debug; - - // Stuff related to (thread safe) resizing of SDL2Window - requireResize = false; - futureSize = Vector2.Zero; - futurePos = Vector2.Zero; - - window = new Sdl2Window("Overlay", x, y, width, height, SDL_WindowFlags.Borderless | SDL_WindowFlags.AlwaysOnTop | SDL_WindowFlags.SkipTaskbar, false); - graphicsDevice = VeldridStartup.CreateGraphicsDevice(window, new GraphicsDeviceOptions(true, null, true), GraphicsBackend.Direct3D11); - - // graphicsDevice = VeldridStartup.CreateDefaultD3D11GraphicsDevice(new GraphicsDeviceOptions(true, null, true), window); - NativeMethods.EnableTransparent(window.Handle); + loadedImages = new Dictionary(); + window = new Sdl2Window( + "Overlay", + 0, + 0, + 2560, + 1440, + SDL_WindowFlags.Borderless | + SDL_WindowFlags.AlwaysOnTop | + SDL_WindowFlags.SkipTaskbar, + false); + graphicsDevice = VeldridStartup.CreateDefaultD3D11GraphicsDevice( + new GraphicsDeviceOptions(false, null, true), + window); + commandList = graphicsDevice.ResourceFactory.CreateCommandList(); + imController = new ImGuiController( + graphicsDevice, + graphicsDevice.MainSwapchain.Framebuffer.OutputDescription, + window.Width, + window.Height); window.Resized += () => { graphicsDevice.MainSwapchain.Resize((uint)window.Width, (uint)window.Height); imController.WindowResized(window.Width, window.Height); - futureSize = Vector2.Zero; - futurePos = Vector2.Zero; - requireResize = false; - }; - window.Closed += () => - { - isClosed = true; }; - commandList = graphicsDevice.ResourceFactory.CreateCommandList(); - imController = new ImGuiController(graphicsDevice, graphicsDevice.MainSwapchain.Framebuffer.OutputDescription, window.Width, window.Height, myFps); - uiThread = new Thread(this.WhileLoop); - hookController = new HookController(window.X, window.Y); + NativeMethods.InitTransparency(window.Handle); + NativeMethods.SetOverlayClickable(window.Handle, false); } - /// - /// To submit ImGui code for generating the UI. - /// - public event EventHandler SubmitUI; - - /// - /// Starts the overlay. - /// - public void Run() + public static void RunInfiniteLoop() { - uiThread.Start(); - hookController.EnableHooks(); - if (!debugMode) + DateTime previous = DateTime.Now; + DateTime current; + TimeSpan interval; + float sec; + while (window.Exists && !Close) { - NativeMethods.HideConsoleWindow(); + InputSnapshot snapshot = window.PumpEvents(); + if (!window.Exists) { break; } + current = DateTime.Now; + interval = current - previous; + sec = (float)interval.TotalSeconds; + previous = current; + imController.Update(sec > 0 ? sec : 0.001f, snapshot, window.Handle); + CoroutineHandler.Tick(interval.TotalSeconds); + if (Visible) + { + CoroutineHandler.RaiseEvent(OnRender); + } + + commandList.Begin(); + commandList.SetFramebuffer(graphicsDevice.MainSwapchain.Framebuffer); + commandList.ClearColorTarget(0, new RgbaFloat(clearColor.X, clearColor.Y, clearColor.Z, clearColor.W)); + imController.Render(graphicsDevice, commandList); + commandList.End(); + graphicsDevice.SubmitCommands(commandList); + graphicsDevice.SwapBuffers(graphicsDevice.MainSwapchain); } - Application.Run(new ApplicationContext()); + Dispose(); } /// - /// Set the overlay FPS. + /// To submit ImGui code for generating the UI. /// - /// - /// FPS to set. - /// - public void SetFps(int fps) - { - myFps = fps; - } + public static Event OnRender = new Event(); /// - /// Resizes the overlay. + /// Safely Closes the Overlay. + /// Doesn't matter if you set it to true multiple times. /// - /// - /// x axis of the overlay. - /// - /// - /// y axis of the overlay. - /// - /// - /// width of the overlay. - /// - /// - /// height of the overlay. - /// - public void Resize(int x, int y, int width, int height) - { - futurePos.X = x; - futurePos.Y = y; - futureSize.X = width; - futureSize.Y = height; - - // TODO: move following two lines to _window.Moved - hookController.UpdateWindowPosition(x, y); - NativeMethods.EnableTransparent(window.Handle); - requireResize = true; - } + public static bool Close { get; set; } = false; /// - /// Shows the overlay. + /// Makes the overlay visible or invisible. Invisible Overlay + /// will not call OnRender coroutines, however time based + /// coroutines are still called. /// - public void Show() + public static bool Visible { get; set; } = true; + + public static bool TerminalWindow { - hookController.ResumeHooks(); - window.Visible = true; + get => terminal; + set + { + if (value != terminal) + { + NativeMethods.SetConsoleWindow(value); + } + + terminal = value; + } } /// - /// hides the overlay. + /// Gets or sets the position of the overlay window. /// - public void Hide() + public static Point Position { - hookController.PauseHooks(); - window.Visible = false; + get + { + return new Point(window.X, window.Y); + } + set + { + Sdl2Native.SDL_SetWindowPosition(window.SdlWindowHandle, value.X, value.Y); + } } /// - /// Free all resources acquired by the overlay. + /// Gets or sets the size of the overlay window. /// - public void Dispose() + public static Point Size { - window.Close(); - while (!isClosed) + get { - Thread.Sleep(10); + return new Point(window.Width, window.Height); + } + set + { + Sdl2Native.SDL_SetWindowSize(window.SdlWindowHandle, value.X, value.Y); } - - uiThread.Join(); - graphicsDevice.WaitForIdle(); - imController.Dispose(); - commandList.Dispose(); - graphicsDevice.Dispose(); - hookController.Dispose(); - NativeMethods.ShowConsoleWindow(); - this.SubmitUI = null; - loadedImages.Clear(); - Console.WriteLine("All Overlay resources are cleared."); - Application.Exit(); } /// /// Adds the image to the Graphic Device as a texture. /// Then returns the pointer of the added texture. It also /// cache the image internally rather than creating a new texture on every call, - /// so this function can be called multiple times per image (per FPS). + /// so this function can be called multiple times per frame. /// /// /// Path to the image on disk. If the image is loaded in the memory @@ -211,7 +187,7 @@ namespace ClickableTransparentOverlay /// /// A pointer to the Texture in the Graphic Device. /// - public IntPtr AddOrGetImagePointer(string filePath) + public static IntPtr AddOrGetImagePointer(string filePath) { if (!loadedImages.TryGetValue(filePath, out Texture texture)) { @@ -224,43 +200,34 @@ namespace ClickableTransparentOverlay } /// - /// Infinite While Loop to render the ImGui. + /// Gets or sets the overlay clickable feature. /// - private void WhileLoop() + public static bool Clickable { - while (window.Exists) + get => NativeMethods.IsClickable; + set { - if (requireResize) - { - Sdl2Native.SDL_SetWindowPosition(window.SdlWindowHandle, (int)futurePos.X, (int)futurePos.Y); - Sdl2Native.SDL_SetWindowSize(window.SdlWindowHandle, (int)futureSize.X, (int)futureSize.Y); - window.PumpEvents(); - continue; - } - - if (!window.Visible) - { - window.PumpEvents(); - Thread.Sleep(10); - continue; - } - - hookController.PopMessages(); - if (!window.Exists) - { - break; - } + NativeMethods.SetOverlayClickable(window.Handle, value); + } + } - imController.InitlizeFrame(1f / myFps); - this.SubmitUI?.Invoke(this, new EventArgs()); - commandList.Begin(); - commandList.SetFramebuffer(graphicsDevice.MainSwapchain.Framebuffer); - commandList.ClearColorTarget(0, new RgbaFloat(clearColor.X, clearColor.Y, clearColor.Z, clearColor.W)); - imController.Render(graphicsDevice, commandList); - commandList.End(); - graphicsDevice.SubmitCommands(commandList); - graphicsDevice.SwapBuffers(graphicsDevice.MainSwapchain); + /// + /// Free all resources acquired by the overlay. + /// + private static void Dispose() + { + window.Close(); + while (window.Exists) + { + Thread.Sleep(1); } + + graphicsDevice.WaitForIdle(); + imController.Dispose(); + commandList.Dispose(); + graphicsDevice.Dispose(); + loadedImages.Clear(); + NativeMethods.SetConsoleWindow(true); } } } diff --git a/ClickableTransparentOverlay/Properties/AssemblyInfo.cs b/ClickableTransparentOverlay/Properties/AssemblyInfo.cs deleted file mode 100644 index 42b9748..0000000 --- a/ClickableTransparentOverlay/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright (c) Zaafar Ahmed. All rights reserved. -// - -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ClickableTransparentOverlay")] -[assembly: AssemblyDescription("A library for creating clickable transparent overlay")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ClickableTransparentOverlay")] -[assembly: AssemblyCopyright("Copyright © 2019")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(true)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("f5cf8972-d0da-4fc0-8796-e7c60101c8ea")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/ClickableTransparentOverlay/Shaders/HLSL/imgui-frag.hlsl b/ClickableTransparentOverlay/Shaders/HLSL/imgui-frag.hlsl deleted file mode 100644 index 63d175f..0000000 --- a/ClickableTransparentOverlay/Shaders/HLSL/imgui-frag.hlsl +++ /dev/null @@ -1,15 +0,0 @@ -struct PS_INPUT -{ - float4 pos : SV_POSITION; - float4 col : COLOR0; - float2 uv : TEXCOORD0; -}; - -Texture2D FontTexture : register(t0); -sampler FontSampler : register(s0); - -float4 FS(PS_INPUT input) : SV_Target -{ - float4 out_col = input.col * FontTexture.Sample(FontSampler, input.uv); - return out_col; -} \ No newline at end of file diff --git a/ClickableTransparentOverlay/Shaders/HLSL/imgui-vertex.hlsl b/ClickableTransparentOverlay/Shaders/HLSL/imgui-vertex.hlsl deleted file mode 100644 index 55793c1..0000000 --- a/ClickableTransparentOverlay/Shaders/HLSL/imgui-vertex.hlsl +++ /dev/null @@ -1,27 +0,0 @@ -cbuffer ProjectionMatrixBuffer : register(b0) -{ - float4x4 ProjectionMatrix; -}; - -struct VS_INPUT -{ - float2 pos : POSITION; - float2 uv : TEXCOORD0; - float4 col : COLOR0; -}; - -struct PS_INPUT -{ - float4 pos : SV_POSITION; - float4 col : COLOR0; - float2 uv : TEXCOORD0; -}; - -PS_INPUT VS(VS_INPUT input) -{ - PS_INPUT output; - output.pos = mul(ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f)); - output.col = input.col; - output.uv = input.uv; - return output; -} \ No newline at end of file diff --git a/ClickableTransparentOverlay/app.config b/ClickableTransparentOverlay/app.config deleted file mode 100644 index a89fbba..0000000 --- a/ClickableTransparentOverlay/app.config +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/ClickableTransparentOverlay/packages.config b/ClickableTransparentOverlay/packages.config deleted file mode 100644 index 076e1c5..0000000 --- a/ClickableTransparentOverlay/packages.config +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/ClickableTransparentOverlay/stylecop.json b/ClickableTransparentOverlay/stylecop.json deleted file mode 100644 index 81fde14..0000000 --- a/ClickableTransparentOverlay/stylecop.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - // ACTION REQUIRED: This file was automatically added to your project, but it - // will not take effect until additional steps are taken to enable it. See the - // following page for additional information: - // - // https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/EnableConfiguration.md - - "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", - "settings": { - "documentationRules": { - "companyName": "Zaafar Ahmed" - } - } -} diff --git a/DriverProgram/App.config b/DriverProgram/App.config deleted file mode 100644 index 962ed6c..0000000 --- a/DriverProgram/App.config +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/DriverProgram/DriverProgram.csproj b/DriverProgram/DriverProgram.csproj index fbfceb0..054d916 100644 --- a/DriverProgram/DriverProgram.csproj +++ b/DriverProgram/DriverProgram.csproj @@ -1,104 +1,18 @@ - - - + + - Debug - AnyCPU - {370E1945-EF74-4618-A2DE-B5796AC3093E} Exe - DriverProgram - OverlayDemo - v4.7.2 - 512 - true - true - - + netcoreapp3.1 - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - true - bin\x64\Debug\ - DEBUG;TRACE - full - x64 - prompt - MinimumRecommendedRules.ruleset - true - false - - - bin\x64\Release\ - - - true - none - x64 - prompt - MinimumRecommendedRules.ruleset - false - true - - - Off - - - - - + - - + + - - {f5cf8972-d0da-4fc0-8796-e7c60101c8ea} - ClickableTransparentOverlay - - - - - ..\packages\ImGui.NET.1.75.0\lib\netstandard2.0\ImGui.NET.dll - - - - ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll - - - - + PreserveNewest - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - \ No newline at end of file + + diff --git a/DriverProgram/Program.cs b/DriverProgram/Program.cs index 1420f6e..bf4f42a 100644 --- a/DriverProgram/Program.cs +++ b/DriverProgram/Program.cs @@ -1,123 +1,167 @@ -namespace DriverProgram +using System; +using System.Collections.Generic; +using System.IO; +using System.Numerics; +using ClickableTransparentOverlay; +using Coroutine; +using ImGuiNET; + +namespace DriverProgram { - using ClickableTransparentOverlay; - using ImGuiNET; - using System; - using System.IO; - using System.Numerics; - using System.Threading; - class Program { - private static bool isRunning = true; - private static bool showImGuiDemo = false; - - private static bool drawOnScreen = false; - private static Random randomGen = new Random(); - private static int totalCircles = 10; - private static Vector2[] circleCenters = new Vector2[totalCircles]; + public static bool showClickableMenu = true; + public static bool showOverlaySample1 = true; + public static bool showOverlaySample2 = false; + public static bool showImGuiDemo = false; - private static int Fps = 144; private static int[] resizeHelper = new int[4] { 0, 0, 2560, 1440 }; - private static int seconds = 5; - private static Overlay overlay = new Overlay(0, 0, 2560, 1440, Fps, true); - private static void MainApplicationLogic() - { - while (isRunning) - { - for (int i = 0; i < circleCenters.Length; i++) - { - circleCenters[i].X = randomGen.Next(0, 2560); - circleCenters[i].Y = randomGen.Next(0, 1440); - } - Thread.Sleep(600); - } + private static int seconds = 5; - overlay.Dispose(); - } + private static Random randomGen = new Random(); + private static Vector2[] circleCenters = new Vector2[200]; - static void Main(string[] args) + static void Main() { - overlay.SubmitUI += RenderUi; - Thread p = new Thread(MainApplicationLogic); - p.Start(); - overlay.Run(); - p.Join(); + CoroutineHandler.Start(UpdateOverlaySample2()); + CoroutineHandler.Start(SubmitRenderLogic()); + Overlay.RunInfiniteLoop(); } - private static void RenderUi(object sender, System.EventArgs e) + private static IEnumerator SubmitRenderLogic() { - if(isRunning) + while (true) { - ImGui.Begin("Overlay Config", ref isRunning, ImGuiWindowFlags.NoResize | ImGuiWindowFlags.AlwaysAutoResize); - - if (ImGui.SliderInt("Set FPS", ref Fps, 30, 144)) - { - overlay.SetFps(Fps); - } + yield return new WaitEvent(Overlay.OnRender); - ImGui.NewLine(); - ImGui.SliderInt2("Set Position", ref resizeHelper[0], 0, 3840); - ImGui.SliderInt2("Set Size", ref resizeHelper[2], 0, 3840); - if (ImGui.Button("Resize")) + if (NativeMethods.isKeyPressed(0x7B)) //F12. { - overlay.Resize(resizeHelper[0], resizeHelper[1], resizeHelper[2], resizeHelper[3]); + showClickableMenu = !showClickableMenu; } - ImGui.NewLine(); - ImGui.SliderInt("###time(sec)", ref seconds, 1, 30); - if (ImGui.Button($"Hide for {seconds} seconds")) + if (showImGuiDemo) { - new Thread(() => { Thread.Sleep(seconds * 1000); overlay.Show(); }).Start(); - overlay.Hide(); + ImGui.ShowDemoWindow(ref showImGuiDemo); } - ImGui.NewLine(); - if(ImGui.Button("Show ImGui Demo")) + if (showOverlaySample1) { - showImGuiDemo = true; + ImGui.SetNextWindowPos(new Vector2(0f, 0f)); + ImGui.SetNextWindowBgAlpha(0.9f); + ImGui.Begin( + "Sample Overlay", + ImGuiWindowFlags.NoInputs | + ImGuiWindowFlags.NoCollapse | + ImGuiWindowFlags.NoTitleBar | + ImGuiWindowFlags.AlwaysAutoResize | + ImGuiWindowFlags.NoResize); + + ImGui.Text("I am sample Overlay"); + ImGui.Text("You can not click me"); + ImGui.Text("I am here just to display stuff"); + ImGui.Text($"Current Date: {DateTime.Now.Date}"); + ImGui.Text($"Current Time: {DateTime.Now.TimeOfDay}"); + ImGui.End(); } - ImGui.NewLine(); - if(ImGui.Button("Draw on Screen")) + if (showOverlaySample2) { - drawOnScreen = true; + ImGui.SetNextWindowContentSize(ImGui.GetIO().DisplaySize); + ImGui.SetNextWindowPos(new Vector2(0, 0)); + ImGui.Begin( + "Background Screen", + ref showOverlaySample2, + ImGuiWindowFlags.NoInputs | + ImGuiWindowFlags.NoBackground | + ImGuiWindowFlags.NoBringToFrontOnFocus | + ImGuiWindowFlags.NoCollapse | + ImGuiWindowFlags.NoMove | + ImGuiWindowFlags.NoScrollbar | + ImGuiWindowFlags.NoSavedSettings | + ImGuiWindowFlags.NoResize | + ImGuiWindowFlags.NoTitleBar); + var windowPtr = ImGui.GetWindowDrawList(); + for (int i = 0; i < circleCenters.Length; i++) + { + windowPtr.AddCircleFilled(circleCenters[i], 10.0f, (uint)(((255 << 24) | (00 << 16) | (00 << 8) | 255) & 0xffffffffL)); + } + ImGui.End(); } - ImGui.NewLine(); - if (File.Exists("image.png")) + if (showClickableMenu) { - ImGui.Image(overlay.AddOrGetImagePointer("image.png"), new Vector2(256, 256)); + bool isRunning = true; + if (!ImGui.Begin("Overlay Main Menu", ref isRunning, ImGuiWindowFlags.NoResize | ImGuiWindowFlags.AlwaysAutoResize)) + { + Overlay.Close = !isRunning; + ImGui.End(); + continue; + } + + Overlay.Close = !isRunning; + ImGui.Text("Try pressing F12 button to show/hide this menu."); + ImGui.Text("Click X on top right of this menu to close the overlay."); + ImGui.Checkbox("Show non-clickable transparent overlay Sample 1.", ref showOverlaySample1); + ImGui.Checkbox("Show full-screen non-clickable transparent overlay sample 2.", ref showOverlaySample2); + ImGui.NewLine(); + + ImGui.SliderInt2("Set Position", ref resizeHelper[0], 0, 3840); + ImGui.SliderInt2("Set Size", ref resizeHelper[2], 0, 3840); + if (ImGui.Button("Resize")) + { + Overlay.Position = new Veldrid.Point(resizeHelper[0], resizeHelper[1]); + Overlay.Size = new Veldrid.Point(resizeHelper[2], resizeHelper[3]); + } + + ImGui.NewLine(); + ImGui.SliderInt("###time(sec)", ref seconds, 1, 30); + if (ImGui.Button($"Hide for {seconds} seconds")) + { + Overlay.Visible = false; + // Time Based Coroutines are executed even when the Overlay is invisible. + // So in case there is a reason you want to hide the overlay, u can use timebased + // coroutines to bring it back. + CoroutineHandler.InvokeLater(new WaitSeconds(seconds), () => { Overlay.Visible = true; }); + } + + ImGui.NewLine(); + if (ImGui.Button("Toggle ImGui Demo")) + { + showImGuiDemo = !showImGuiDemo; + } + + if (ImGui.Button("Toggle Terminal")) + { + Overlay.TerminalWindow = !Overlay.TerminalWindow; + } + + ImGui.NewLine(); + if (File.Exists("image.png")) + { + ImGui.Image(Overlay.AddOrGetImagePointer("image.png"), new Vector2(256, 256)); + } + else + { + ImGui.Text("Put any image where the exe is, name is 'image.png'"); + } + + ImGui.End(); } - else - { - ImGui.Text("Put any image where the exe is, name is 'image.png'"); - } - - ImGui.End(); - } - - if (showImGuiDemo) - { - ImGui.ShowDemoWindow(ref showImGuiDemo); } + } - if(drawOnScreen) + private static IEnumerator UpdateOverlaySample2() + { + while (true) { - ImGui.SetNextWindowContentSize(ImGui.GetIO().DisplaySize); - ImGui.SetNextWindowPos(new Vector2(0, 0)); - ImGui.Begin("Background Screen", ref drawOnScreen, ImGuiWindowFlags.NoInputs | - ImGuiWindowFlags.NoBackground | ImGuiWindowFlags.NoBringToFrontOnFocus | - ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoScrollbar | - ImGuiWindowFlags.NoSavedSettings | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoTitleBar); - var windowPtr = ImGui.GetWindowDrawList(); + yield return new WaitSeconds(1); for (int i = 0; i < circleCenters.Length; i++) { - windowPtr.AddCircleFilled(circleCenters[i], 10.0f, (uint)(((255 << 24) | (00 << 16) | (00 << 8) | 255) & 0xffffffffL)); + circleCenters[i].X = randomGen.Next(0, 2560); + circleCenters[i].Y = randomGen.Next(0, 1440); } - ImGui.End(); } } } -} \ No newline at end of file +} diff --git a/DriverProgram/Properties/AssemblyInfo.cs b/DriverProgram/Properties/AssemblyInfo.cs deleted file mode 100644 index 77f1968..0000000 --- a/DriverProgram/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("OverlayDemo")] -[assembly: AssemblyDescription("Overlay Demo with ImGui")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("DriverProgram")] -[assembly: AssemblyCopyright("Copyright © 2019")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("370e1945-ef74-4618-a2de-b5796ac3093e")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/DriverProgram/packages.config b/DriverProgram/packages.config deleted file mode 100644 index b89d42a..0000000 --- a/DriverProgram/packages.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file