code refactor (#2)

* Added StyleCop.Analyser to clean the code

* updated HookController and AssemblyInfo code quality

* code refactor

* minor fixup

* refactor code

* minor fixup
master
Zaafar Ahmed 7 years ago committed by GitHub
parent 7c5327b618
commit 94af78513c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      ClickableTransparentOverlay/ClickableTransparentOverlay.csproj
  2. 155
      ClickableTransparentOverlay/HookController.cs
  3. 498
      ClickableTransparentOverlay/ImGuiController.cs
  4. 62
      ClickableTransparentOverlay/NativeMethods.cs
  5. 236
      ClickableTransparentOverlay/Overlay.cs
  6. 7
      ClickableTransparentOverlay/Properties/AssemblyInfo.cs
  7. 1
      ClickableTransparentOverlay/packages.config
  8. 14
      ClickableTransparentOverlay/stylecop.json
  9. 12
      DriverProgram/App.config
  10. 12
      DriverProgram/Program.cs

@ -44,6 +44,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<RunCodeAnalysis>false</RunCodeAnalysis> <RunCodeAnalysis>false</RunCodeAnalysis>
<DocumentationFile>bin\x64\Debug\ClickableTransparentOverlay.xml</DocumentationFile>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath> <OutputPath>bin\x64\Release\</OutputPath>
@ -58,6 +59,7 @@
<NoWarn> <NoWarn>
</NoWarn> </NoWarn>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies> <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<DocumentationFile>bin\x64\Release\ClickableTransparentOverlay.xml</DocumentationFile>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Gma.System.MouseKeyHook, Version=5.6.130.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="Gma.System.MouseKeyHook, Version=5.6.130.0, Culture=neutral, processorArchitecture=MSIL">
@ -112,12 +114,17 @@
<None Include="packages.config" /> <None Include="packages.config" />
<EmbeddedResource Include="Shaders\HLSL\imgui-vertex.hlsl.bytes" LogicalName="imgui-vertex.hlsl.bytes" /> <EmbeddedResource Include="Shaders\HLSL\imgui-vertex.hlsl.bytes" LogicalName="imgui-vertex.hlsl.bytes" />
<EmbeddedResource Include="Shaders\HLSL\imgui-frag.hlsl.bytes" LogicalName="imgui-frag.hlsl.bytes" /> <EmbeddedResource Include="Shaders\HLSL\imgui-frag.hlsl.bytes" LogicalName="imgui-frag.hlsl.bytes" />
<AdditionalFiles Include="stylecop.json" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="cimgui.dll"> <Content Include="cimgui.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Analyzer Include="..\packages\StyleCop.Analyzers.1.0.2\analyzers\dotnet\cs\StyleCop.Analyzers.CodeFixes.dll" />
<Analyzer Include="..\packages\StyleCop.Analyzers.1.0.2\analyzers\dotnet\cs\StyleCop.Analyzers.dll" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\Veldrid.SDL2.4.5.0\build\net40\Veldrid.SDL2.targets" Condition="Exists('..\packages\Veldrid.SDL2.4.5.0\build\net40\Veldrid.SDL2.targets')" /> <Import Project="..\packages\Veldrid.SDL2.4.5.0\build\net40\Veldrid.SDL2.targets" Condition="Exists('..\packages\Veldrid.SDL2.4.5.0\build\net40\Veldrid.SDL2.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">

@ -1,52 +1,104 @@
namespace ClickableTransparentOverlay // <copyright file="HookController.cs" company="Zaafar Ahmed">
// Copyright (c) Zaafar Ahmed. All rights reserved.
// </copyright>
namespace ClickableTransparentOverlay
{ {
using Gma.System.MouseKeyHook;
using ImGuiNET;
using System.Numerics; using System.Numerics;
using System.Windows.Forms; using System.Windows.Forms;
using Gma.System.MouseKeyHook;
using ImGuiNET;
/// <summary>
/// This class Hooks the Global Window Mouse/Keyboard events
/// and pass them into ImGui Overlay.
/// </summary>
public class HookController public class HookController
{ {
private IKeyboardMouseEvents _hook; private IKeyboardMouseEvents myHook;
private bool Enable; private bool enable;
private int WindowX; private int windowX;
private int WindowY; private int windowY;
/// <summary>
/// Initializes a new instance of the <see cref="HookController"/> class.
/// </summary>
/// <param name="x">
/// Transparent SDL2Window top left corner X axis.
/// </param>
/// <param name="y">
/// Transparent SDL2Window top left corner Y axis.
/// </param>
public HookController(int x, int y) public HookController(int x, int y)
{ {
WindowX = x; this.windowX = x;
WindowY = y; this.windowY = y;
Enable = true; this.enable = true;
_hook = Hook.GlobalEvents(); this.myHook = Hook.GlobalEvents();
} }
/// <summary>
/// Enable this class functionality ( only call it once ).
/// </summary>
public void EnableHooks() public void EnableHooks()
{ {
_hook.KeyDown += _hook_KeyDown; this.myHook.KeyDown += this.HookKeyDown;
_hook.KeyUp += _hook_KeyUp; this.myHook.KeyUp += this.HookKeyUp;
_hook.KeyPress += _hook_KeyPress; this.myHook.KeyPress += this.HookKeyPress;
_hook.MouseDownExt += _hook_MouseDownExt; this.myHook.MouseDownExt += this.HookMouseDownExt;
_hook.MouseMove += _hook_MouseMove; this.myHook.MouseMove += this.HookMouseMove;
_hook.MouseUpExt += _hook_MouseUpExt; this.myHook.MouseUpExt += this.HookMouseUpExt;
_hook.MouseWheelExt += _hook_MouseWheelExt; this.myHook.MouseWheelExt += this.HookMouseWheelExt;
} }
/// <summary>
/// Update transparent SDL2Window top left position.
/// </summary>
/// <param name="x">
/// X axis of the SDL2Window top left corner
/// </param>
/// <param name="y">
/// Y axis of the SDL2Window top left corner
/// </param>
public void UpdateWindowPosition(int x, int y) public void UpdateWindowPosition(int x, int y)
{ {
WindowX = x; this.windowX = x;
WindowY = y; this.windowY = y;
} }
/// <summary>
/// Pause the hooks.
/// </summary>
public void PauseHooks() public void PauseHooks()
{ {
Enable = false; this.enable = false;
} }
/// <summary>
/// Resume the hooks.
/// </summary>
public void ResumeHooks() public void ResumeHooks()
{ {
Enable = true; this.enable = true;
}
/// <summary>
/// Dispose the resources acquired by this class
/// </summary>
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();
} }
private void MouseButtonFunction(MouseEventExtArgs e, bool isDownEvent) private void MouseButtonFunction(MouseEventExtArgs e, bool isDownEvent)
@ -83,39 +135,40 @@
} }
} }
private void _hook_MouseUpExt(object sender, MouseEventExtArgs e) private void HookMouseUpExt(object sender, MouseEventExtArgs e)
{ {
if (Enable) if (this.enable)
{ {
MouseButtonFunction(e, false); this.MouseButtonFunction(e, false);
} }
} }
private void _hook_MouseDownExt(object sender, MouseEventExtArgs e) private void HookMouseDownExt(object sender, MouseEventExtArgs e)
{ {
if (Enable) if (this.enable)
{ {
MouseButtonFunction(e, true); this.MouseButtonFunction(e, true);
} }
} }
private void _hook_MouseMove(object sender, MouseEventArgs e) private void HookMouseMove(object sender, MouseEventArgs e)
{ {
if (!Enable) if (!this.enable)
{ {
return; return;
} }
ImGuiIOPtr io = ImGui.GetIO(); ImGuiIOPtr io = ImGui.GetIO();
io.MousePos = new Vector2(e.X - WindowX, e.Y - WindowY); io.MousePos = new Vector2(e.X - this.windowX, e.Y - this.windowY);
// TODO: Show ImGUI Cursor/Hide ImGui Cursor // TODO: Show ImGUI Cursor/Hide ImGui Cursor
// ImGui.GetIO().MouseDrawCursor = true; // ImGui.GetIO().MouseDrawCursor = true;
// Window32 API ShowCursor(false) // Window32 API ShowCursor(false)
} }
private void _hook_MouseWheelExt(object sender, MouseEventExtArgs e) private void HookMouseWheelExt(object sender, MouseEventExtArgs e)
{ {
if (!Enable) if (!this.enable)
{ {
return; return;
} }
@ -128,8 +181,7 @@
} }
} }
private void HookKeyUp(object sender, KeyEventArgs e)
private void _hook_KeyUp(object sender, KeyEventArgs e)
{ {
var io = ImGui.GetIO(); var io = ImGui.GetIO();
io.KeysDown[e.KeyValue] = false; io.KeysDown[e.KeyValue] = false;
@ -157,9 +209,9 @@
} }
} }
private void _hook_KeyDown(object sender, KeyEventArgs e) private void HookKeyDown(object sender, KeyEventArgs e)
{ {
if (!Enable) if (!this.enable)
{ {
return; return;
} }
@ -180,11 +232,10 @@
io.KeyCtrl = true; io.KeyCtrl = true;
e.Handled = true; e.Handled = true;
break; break;
case Keys.LMenu: case Keys.LMenu: // LAlt is LMenu
case Keys.RMenu: case Keys.RMenu: // RAlt is RMenu
io.KeyAlt = true; io.KeyAlt = true;
break; break;
// Alt is LMenu/RMenu
case Keys.LShiftKey: case Keys.LShiftKey:
case Keys.RShiftKey: case Keys.RShiftKey:
io.KeyShift = true; io.KeyShift = true;
@ -192,20 +243,22 @@
default: default:
// Ignoring ALT key so we can do ALT+TAB or ALT+F4 etc. // 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. // Not sure if ImGUI needs to use ALT+XXX key for anything.
// Ignoring Capital/NumLock key so Windows can use it // Ignoring Capital/NumLock key so Windows can use it.
// Ignoring Win/Super key so we can do Win+D or other stuff // 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) if (!io.KeyAlt && e.KeyCode != Keys.Capital && e.KeyCode != Keys.NumLock && !io.KeySuper)
{ {
e.Handled = true; e.Handled = true;
} }
break; break;
} }
} }
} }
private void _hook_KeyPress(object sender, KeyPressEventArgs e) private void HookKeyPress(object sender, KeyPressEventArgs e)
{ {
if (!Enable) if (!this.enable)
{ {
return; return;
} }
@ -226,19 +279,5 @@
e.Handled = true; e.Handled = true;
} }
} }
public void Dispose()
{
_hook.KeyDown -= _hook_KeyDown;
_hook.KeyUp -= _hook_KeyUp;
_hook.KeyPress -= _hook_KeyPress;
_hook.MouseDownExt -= _hook_MouseDownExt;
_hook.MouseMove -= _hook_MouseMove;
_hook.MouseUpExt -= _hook_MouseUpExt;
_hook.MouseWheelExt -= _hook_MouseWheelExt;
_hook.Dispose();
}
} }
} }

@ -1,14 +1,15 @@
namespace ClickableTransparentOverlay // <auto-generated />
namespace ClickableTransparentOverlay
{ {
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Numerics; using System.Numerics;
using System.Reflection; using System.Reflection;
using System.IO;
using Veldrid;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using ImGuiNET; using ImGuiNET;
using NativeLibraryLoader; using NativeLibraryLoader;
using Veldrid;
/// <summary> /// <summary>
/// A modified version of ImGui.NET.SampleProgram's ImGuiController. /// A modified version of ImGui.NET.SampleProgram's ImGuiController.
@ -16,93 +17,135 @@
/// </summary> /// </summary>
public sealed class ImGuiController : IDisposable public sealed class ImGuiController : IDisposable
{ {
private GraphicsDevice _gd; #pragma warning disable CS0169 // Force Copy this DLL
private bool _frameBegun; private readonly DefaultPathResolver useless;
#pragma warning restore CS0169
// Veldrid objects private readonly IntPtr fontAtlasID = (IntPtr)1;
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 IntPtr _fontAtlasID = (IntPtr)1;
private int _windowWidth;
private int _windowHeight;
private Vector2 _scaleFactor = Vector2.One;
// Image trackers // Image trackers
private readonly Dictionary<TextureView, ResourceSetInfo> _setsByView private readonly Dictionary<TextureView, ResourceSetInfo> setsByView
= new Dictionary<TextureView, ResourceSetInfo>(); = new Dictionary<TextureView, ResourceSetInfo>();
private readonly Dictionary<Texture, TextureView> _autoViewsByTexture
private readonly Dictionary<Texture, TextureView> autoViewsByTexture
= new Dictionary<Texture, TextureView>(); = new Dictionary<Texture, TextureView>();
private readonly Dictionary<IntPtr, ResourceSetInfo> _viewsById = new Dictionary<IntPtr, ResourceSetInfo>();
private readonly List<IDisposable> _ownedResources = new List<IDisposable>();
private int _lastAssignedID = 100;
#pragma warning disable CS0169 // Force Copy this DLL private readonly Dictionary<IntPtr, ResourceSetInfo> viewsById
private static DefaultPathResolver ___; = new Dictionary<IntPtr, ResourceSetInfo>();
#pragma warning restore CS0169
private readonly List<IDisposable> ownedResources
= new List<IDisposable>();
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;
/// <summary> /// <summary>
/// Constructs a new ImGuiController. /// Initializes a new instance of the <see cref="ImGuiController"/> class.
/// </summary> /// </summary>
/// <param name="gd">
/// Graphic Device
/// </param>
/// <param name="outputDescription">
/// Output Description
/// </param>
/// <param name="width">
/// SDL2Window Window width
/// </param>
/// <param name="height">
/// SDL2Window Window height
/// </param>
/// <param name="fps">
/// desired FPS of the ImGui Overlay
/// </param>
public ImGuiController(GraphicsDevice gd, OutputDescription outputDescription, int width, int height, int fps) public ImGuiController(GraphicsDevice gd, OutputDescription outputDescription, int width, int height, int fps)
{ {
_gd = gd; this.gd = gd;
_windowWidth = width; this.windowWidth = width;
_windowHeight = height; this.windowHeight = height;
IntPtr context = ImGui.CreateContext(); IntPtr context = ImGui.CreateContext();
ImGui.SetCurrentContext(context); ImGui.SetCurrentContext(context);
ImGui.GetIO().Fonts.AddFontDefault(); ImGui.GetIO().Fonts.AddFontDefault();
CreateDeviceResources(gd, outputDescription); this.CreateDeviceResources(gd, outputDescription);
SetKeyMappings(); SetKeyMappings();
SetPerFrameImGuiData(1f / fps); this.SetPerFrameImGuiData(1f / fps);
ImGui.NewFrame(); ImGui.NewFrame();
_frameBegun = true; this.frameBegun = true;
} }
/// <summary>
/// Updates the ImGui about the SDL2Window Size
/// </summary>
/// <param name="width">
/// Width of the SDL2Window
/// </param>
/// <param name="height">
/// Height of the SDL2Window
/// </param>
public void WindowResized(int width, int height) public void WindowResized(int width, int height)
{ {
_windowWidth = width; this.windowWidth = width;
_windowHeight = height; this.windowHeight = height;
} }
/// <summary>
/// Disposes the resources acquired by the ImGuiController class.
/// </summary>
public void DestroyDeviceObjects() public void DestroyDeviceObjects()
{ {
Dispose(); this.Dispose();
} }
/// <summary>
/// Initializes different resources for ImGui Controller class.
/// </summary>
/// <param name="gd">
/// Graphic Device
/// </param>
/// <param name="outputDescription">
/// Output Description
/// </param>
public void CreateDeviceResources(GraphicsDevice gd, OutputDescription outputDescription) public void CreateDeviceResources(GraphicsDevice gd, OutputDescription outputDescription)
{ {
_gd = gd; this.gd = gd;
ResourceFactory factory = gd.ResourceFactory; ResourceFactory factory = gd.ResourceFactory;
_vertexBuffer = factory.CreateBuffer(new BufferDescription(10000, BufferUsage.VertexBuffer | BufferUsage.Dynamic)); this.vertexBuffer = factory.CreateBuffer(new BufferDescription(10000, BufferUsage.VertexBuffer | BufferUsage.Dynamic));
_vertexBuffer.Name = "ImGui.NET Vertex Buffer"; this.vertexBuffer.Name = "ImGui.NET Vertex Buffer";
_indexBuffer = factory.CreateBuffer(new BufferDescription(2000, BufferUsage.IndexBuffer | BufferUsage.Dynamic)); this.indexBuffer = factory.CreateBuffer(new BufferDescription(2000, BufferUsage.IndexBuffer | BufferUsage.Dynamic));
_indexBuffer.Name = "ImGui.NET Index Buffer"; this.indexBuffer.Name = "ImGui.NET Index Buffer";
RecreateFontDeviceTexture(gd); this.RecreateFontDeviceTexture(gd);
_projMatrixBuffer = factory.CreateBuffer(new BufferDescription(64, BufferUsage.UniformBuffer | BufferUsage.Dynamic)); this.projMatrixBuffer = factory.CreateBuffer(new BufferDescription(64, BufferUsage.UniformBuffer | BufferUsage.Dynamic));
_projMatrixBuffer.Name = "ImGui.NET Projection Buffer"; this.projMatrixBuffer.Name = "ImGui.NET Projection Buffer";
byte[] vertexShaderBytes = LoadEmbeddedShaderCode(gd.ResourceFactory, "imgui-vertex", ShaderStages.Vertex); byte[] vertexShaderBytes = this.LoadEmbeddedShaderCode(gd.ResourceFactory, "imgui-vertex", ShaderStages.Vertex);
byte[] fragmentShaderBytes = LoadEmbeddedShaderCode(gd.ResourceFactory, "imgui-frag", ShaderStages.Fragment); byte[] fragmentShaderBytes = this.LoadEmbeddedShaderCode(gd.ResourceFactory, "imgui-frag", ShaderStages.Fragment);
_vertexShader = factory.CreateShader(new ShaderDescription(ShaderStages.Vertex, vertexShaderBytes, "VS")); this.vertexShader = factory.CreateShader(new ShaderDescription(ShaderStages.Vertex, vertexShaderBytes, "VS"));
_fragmentShader = factory.CreateShader(new ShaderDescription(ShaderStages.Fragment, fragmentShaderBytes, "FS")); this.fragmentShader = factory.CreateShader(new ShaderDescription(ShaderStages.Fragment, fragmentShaderBytes, "FS"));
VertexLayoutDescription[] vertexLayouts = new VertexLayoutDescription[] VertexLayoutDescription[] vertexLayouts = new VertexLayoutDescription[]
{ {
@ -112,10 +155,10 @@
new VertexElementDescription("in_color", VertexElementSemantic.Color, VertexElementFormat.Byte4_Norm)) new VertexElementDescription("in_color", VertexElementSemantic.Color, VertexElementFormat.Byte4_Norm))
}; };
_layout = factory.CreateResourceLayout(new ResourceLayoutDescription( this.layout = factory.CreateResourceLayout(new ResourceLayoutDescription(
new ResourceLayoutElementDescription("ProjectionMatrixBuffer", ResourceKind.UniformBuffer, ShaderStages.Vertex), new ResourceLayoutElementDescription("ProjectionMatrixBuffer", ResourceKind.UniformBuffer, ShaderStages.Vertex),
new ResourceLayoutElementDescription("MainSampler", ResourceKind.Sampler, ShaderStages.Fragment))); new ResourceLayoutElementDescription("MainSampler", ResourceKind.Sampler, ShaderStages.Fragment)));
_textureLayout = factory.CreateResourceLayout(new ResourceLayoutDescription( this.textureLayout = factory.CreateResourceLayout(new ResourceLayoutDescription(
new ResourceLayoutElementDescription("MainTexture", ResourceKind.TextureReadOnly, ShaderStages.Fragment))); new ResourceLayoutElementDescription("MainTexture", ResourceKind.TextureReadOnly, ShaderStages.Fragment)));
GraphicsPipelineDescription pd = new GraphicsPipelineDescription( GraphicsPipelineDescription pd = new GraphicsPipelineDescription(
@ -123,65 +166,85 @@
new DepthStencilStateDescription(false, false, ComparisonKind.Always), new DepthStencilStateDescription(false, false, ComparisonKind.Always),
new RasterizerStateDescription(FaceCullMode.None, PolygonFillMode.Solid, FrontFace.Clockwise, false, true), new RasterizerStateDescription(FaceCullMode.None, PolygonFillMode.Solid, FrontFace.Clockwise, false, true),
PrimitiveTopology.TriangleList, PrimitiveTopology.TriangleList,
new ShaderSetDescription(vertexLayouts, new[] { _vertexShader, _fragmentShader }), new ShaderSetDescription(vertexLayouts, new[] { this.vertexShader, this.fragmentShader }),
new ResourceLayout[] { _layout, _textureLayout }, new ResourceLayout[] { this.layout, this.textureLayout },
outputDescription); outputDescription);
_pipeline = factory.CreateGraphicsPipeline(ref pd); this.pipeline = factory.CreateGraphicsPipeline(ref pd);
_mainResourceSet = factory.CreateResourceSet(new ResourceSetDescription(_layout, this.mainResourceSet = factory.CreateResourceSet(new ResourceSetDescription(
_projMatrixBuffer, this.layout, this.projMatrixBuffer, gd.PointSampler));
gd.PointSampler));
_fontTextureResourceSet = factory.CreateResourceSet(new ResourceSetDescription(_textureLayout, _fontTextureView)); this.fontTextureResourceSet = factory.CreateResourceSet(
new ResourceSetDescription(this.textureLayout, this.fontTextureView));
} }
/// <summary> /// <summary>
/// Gets or creates a handle for a texture to be drawn with ImGui. /// Gets or creates a handle for a texture to be drawn with ImGui.
/// Pass the returned handle to Image() or ImageButton(). /// Pass the returned handle to Image() or ImageButton().
/// </summary> /// </summary>
/// <param name="factory">
/// Resource Factory
/// </param>
/// <param name="textureView">
/// Texture View
/// </param>
/// <returns>
/// Creates ImGui Binding
/// </returns>
public IntPtr GetOrCreateImGuiBinding(ResourceFactory factory, TextureView textureView) public IntPtr GetOrCreateImGuiBinding(ResourceFactory factory, TextureView textureView)
{ {
if (!_setsByView.TryGetValue(textureView, out ResourceSetInfo rsi)) if (!this.setsByView.TryGetValue(textureView, out ResourceSetInfo rsi))
{ {
ResourceSet resourceSet = factory.CreateResourceSet(new ResourceSetDescription(_textureLayout, textureView)); ResourceSet resourceSet = factory.CreateResourceSet(
rsi = new ResourceSetInfo(GetNextImGuiBindingID(), resourceSet); new ResourceSetDescription(this.textureLayout, textureView));
_setsByView.Add(textureView, rsi); rsi = new ResourceSetInfo(this.GetNextImGuiBindingID(), resourceSet);
_viewsById.Add(rsi.ImGuiBinding, rsi);
_ownedResources.Add(resourceSet);
}
return rsi.ImGuiBinding; this.setsByView.Add(textureView, rsi);
this.viewsById.Add(rsi.ImGuiBinding, rsi);
this.ownedResources.Add(resourceSet);
} }
private IntPtr GetNextImGuiBindingID() return rsi.ImGuiBinding;
{
int newID = _lastAssignedID++;
return (IntPtr)newID;
} }
/// <summary> /// <summary>
/// Gets or creates a handle for a texture to be drawn with ImGui. /// Gets or creates a handle for a texture to be drawn with ImGui.
/// Pass the returned handle to Image() or ImageButton(). /// Pass the returned handle to Image() or ImageButton().
/// </summary> /// </summary>
/// <param name="factory">
/// Resource Factory
/// </param>
/// <param name="texture">
/// Texture information
/// </param>
/// <returns>
/// Pointer to the resource
/// </returns>
public IntPtr GetOrCreateImGuiBinding(ResourceFactory factory, Texture texture) public IntPtr GetOrCreateImGuiBinding(ResourceFactory factory, Texture texture)
{ {
if (!_autoViewsByTexture.TryGetValue(texture, out TextureView textureView)) if (!this.autoViewsByTexture.TryGetValue(texture, out TextureView textureView))
{ {
textureView = factory.CreateTextureView(texture); textureView = factory.CreateTextureView(texture);
_autoViewsByTexture.Add(texture, textureView); this.autoViewsByTexture.Add(texture, textureView);
_ownedResources.Add(textureView); this.ownedResources.Add(textureView);
} }
return GetOrCreateImGuiBinding(factory, textureView); return this.GetOrCreateImGuiBinding(factory, textureView);
} }
/// <summary> /// <summary>
/// Retrieves the shader texture binding for the given helper handle. /// Retrieves the shader texture binding for the given helper handle.
/// </summary> /// </summary>
/// <param name="imGuiBinding">
/// ImGui Binding resource pointer.
/// </param>
/// <returns>
/// Resource
/// </returns>
public ResourceSet GetImageResourceSet(IntPtr imGuiBinding) public ResourceSet GetImageResourceSet(IntPtr imGuiBinding)
{ {
if (!_viewsById.TryGetValue(imGuiBinding, out ResourceSetInfo tvi)) if (!this.viewsById.TryGetValue(imGuiBinding, out ResourceSetInfo tvi))
{ {
throw new InvalidOperationException("No registered ImGui binding with id " + imGuiBinding.ToString()); throw new InvalidOperationException("No registered ImGui binding with id " + imGuiBinding.ToString());
} }
@ -189,83 +252,51 @@
return tvi.ResourceSet; return tvi.ResourceSet;
} }
/// <summary>
/// Clears the cache images.
/// </summary>
public void ClearCachedImageResources() public void ClearCachedImageResources()
{ {
foreach (IDisposable resource in _ownedResources) foreach (IDisposable resource in this.ownedResources)
{ {
resource.Dispose(); resource.Dispose();
} }
_ownedResources.Clear(); this.ownedResources.Clear();
_setsByView.Clear(); this.setsByView.Clear();
_viewsById.Clear(); this.viewsById.Clear();
_autoViewsByTexture.Clear(); this.autoViewsByTexture.Clear();
_lastAssignedID = 100; this.lastAssignedID = 100;
}
private byte[] LoadEmbeddedShaderCode(ResourceFactory factory, string name, ShaderStages stage)
{
switch (factory.BackendType)
{
case GraphicsBackend.Direct3D11:
{
string resourceName = name + ".hlsl.bytes";
return GetEmbeddedResourceBytes(resourceName);
}
case GraphicsBackend.OpenGL:
{
string resourceName = name + ".glsl";
return GetEmbeddedResourceBytes(resourceName);
}
case GraphicsBackend.Vulkan:
{
string resourceName = name + ".spv";
return GetEmbeddedResourceBytes(resourceName);
}
case GraphicsBackend.Metal:
{
string resourceName = name + ".metallib";
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;
}
} }
/// <summary> /// <summary>
/// Recreates the device texture used to render text. /// Recreates the device texture used to render text.
/// </summary> /// </summary>
/// <param name="gd">
/// Graphic Device
/// </param>
public unsafe void RecreateFontDeviceTexture(GraphicsDevice gd) public unsafe void RecreateFontDeviceTexture(GraphicsDevice gd)
{ {
ImGuiIOPtr io = ImGui.GetIO(); ImGuiIOPtr io = ImGui.GetIO();
// Build // Build
byte* pixels; byte* pixels;
int width, height, bytesPerPixel; int width, height, bytesPerPixel;
io.Fonts.GetTexDataAsRGBA32(out pixels, out width, out height, out bytesPerPixel); io.Fonts.GetTexDataAsRGBA32(out pixels, out width, out height, out bytesPerPixel);
// Store our identifier // Store our identifier
io.Fonts.SetTexID(_fontAtlasID); io.Fonts.SetTexID(this.fontAtlasID);
_fontTexture = gd.ResourceFactory.CreateTexture(TextureDescription.Texture2D( this.fontTexture = gd.ResourceFactory.CreateTexture(TextureDescription.Texture2D(
(uint)width, (uint)width,
(uint)height, (uint)height,
1, 1,
1, 1,
PixelFormat.R8_G8_B8_A8_UNorm, PixelFormat.R8_G8_B8_A8_UNorm,
TextureUsage.Sampled)); TextureUsage.Sampled));
_fontTexture.Name = "ImGui.NET Font Texture"; this.fontTexture.Name = "ImGui.NET Font Texture";
gd.UpdateTexture( gd.UpdateTexture(
_fontTexture, this.fontTexture,
(IntPtr)pixels, (IntPtr)pixels,
(uint)(bytesPerPixel * width * height), (uint)(bytesPerPixel * width * height),
0, 0,
@ -276,7 +307,7 @@
1, 1,
0, 0,
0); 0);
_fontTextureView = gd.ResourceFactory.CreateTextureView(_fontTexture); this.fontTextureView = gd.ResourceFactory.CreateTextureView(this.fontTexture);
io.Fonts.ClearTexData(); io.Fonts.ClearTexData();
} }
@ -287,46 +318,67 @@
/// or index data has increased beyond the capacity of the existing buffers. /// or index data has increased beyond the capacity of the existing buffers.
/// A <see cref="CommandList"/> is needed to submit drawing and resource update commands. /// A <see cref="CommandList"/> is needed to submit drawing and resource update commands.
/// </summary> /// </summary>
/// <param name="gd">
/// Graphic Device
/// </param>
/// <param name="cl">
/// Command List
/// </param>
public void Render(GraphicsDevice gd, CommandList cl) public void Render(GraphicsDevice gd, CommandList cl)
{ {
if (_frameBegun) if (this.frameBegun)
{ {
_frameBegun = false; this.frameBegun = false;
ImGui.Render(); ImGui.Render();
RenderImDrawData(ImGui.GetDrawData(), gd, cl); this.RenderImDrawData(ImGui.GetDrawData(), gd, cl);
} }
} }
/// <summary> /// <summary>
/// Initilizes a new frame /// Initilizes a new frame
/// </summary> /// </summary>
/// <param name="deltaSeconds">
/// FPS delay
/// </param>
public void InitlizeFrame(float deltaSeconds) public void InitlizeFrame(float deltaSeconds)
{ {
if (_frameBegun) if (this.frameBegun)
{ {
ImGui.Render(); ImGui.Render();
} }
SetPerFrameImGuiData(deltaSeconds); this.SetPerFrameImGuiData(deltaSeconds);
_frameBegun = true; this.frameBegun = true;
ImGui.NewFrame(); ImGui.NewFrame();
} }
/// <summary> /// <summary>
/// Sets per-frame data based on the associated window. /// Frees all graphics resources used by the renderer.
/// This is called by Update(float).
/// </summary> /// </summary>
private void SetPerFrameImGuiData(float deltaSeconds) public void Dispose()
{ {
ImGuiIOPtr io = ImGui.GetIO(); this.vertexBuffer.Dispose();
io.DisplaySize = new Vector2( this.indexBuffer.Dispose();
_windowWidth / _scaleFactor.X, this.projMatrixBuffer.Dispose();
_windowHeight / _scaleFactor.Y); this.fontTexture.Dispose();
io.DisplayFramebufferScale = _scaleFactor; this.fontTextureView.Dispose();
io.DeltaTime = deltaSeconds; // DeltaTime is in seconds. this.vertexShader.Dispose();
this.fragmentShader.Dispose();
this.layout.Dispose();
this.textureLayout.Dispose();
this.pipeline.Dispose();
this.mainResourceSet.Dispose();
foreach (IDisposable resource in this.ownedResources)
{
resource.Dispose();
}
} }
/// <summary>
/// Allows ImGui to identify the Keys
/// </summary>
private static void SetKeyMappings() private static void SetKeyMappings()
{ {
ImGuiIOPtr io = ImGui.GetIO(); ImGuiIOPtr io = ImGui.GetIO();
@ -343,7 +395,8 @@
io.KeyMap[(int)ImGuiKey.Backspace] = (int)System.Windows.Forms.Keys.Back; 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.Enter] = (int)System.Windows.Forms.Keys.Enter;
io.KeyMap[(int)ImGuiKey.Escape] = (int)System.Windows.Forms.Keys.Escape; 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.COUNT] = (int)System.Windows.Forms.Keys.un;
io.KeyMap[(int)ImGuiKey.Insert] = (int)System.Windows.Forms.Keys.Insert; 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.Space] = (int)System.Windows.Forms.Keys.Space;
io.KeyMap[(int)ImGuiKey.A] = (int)System.Windows.Forms.Keys.A; io.KeyMap[(int)ImGuiKey.A] = (int)System.Windows.Forms.Keys.A;
@ -354,6 +407,94 @@
io.KeyMap[(int)ImGuiKey.Z] = (int)System.Windows.Forms.Keys.Z; io.KeyMap[(int)ImGuiKey.Z] = (int)System.Windows.Forms.Keys.Z;
} }
/// <summary>
/// Get the Next ImGui Binding ID.
/// </summary>
/// <returns>
/// ImGui next binding ID.
/// </returns>
private IntPtr GetNextImGuiBindingID()
{
int newID = this.lastAssignedID++;
return (IntPtr)newID;
}
/// <summary>
/// Loading Shader Code
/// </summary>
/// <param name="factory">
/// Resource Factory
/// </param>
/// <param name="name">
/// Shader file name
/// </param>
/// <param name="stage">
/// Shader stage
/// </param>
/// <returns>
/// Returns shader byte code
/// </returns>
private byte[] LoadEmbeddedShaderCode(ResourceFactory factory, string name, ShaderStages stage)
{
switch (factory.BackendType)
{
case GraphicsBackend.Direct3D11:
string resourceName = name + ".hlsl.bytes";
return this.GetEmbeddedResourceBytes(resourceName);
default:
throw new NotImplementedException();
}
}
/// <summary>
/// Get embedded resource file in bytes
/// </summary>
/// <param name="resourceName">
/// Name of the resource file
/// </param>
/// <returns>
/// Byte code of the resource file
/// </returns>
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;
}
}
/// <summary>
/// Sets per-frame data based on the associated window.
/// This is called by Update(float).
/// </summary>
/// <param name="deltaSeconds">
/// FPS delay
/// </param>
private void SetPerFrameImGuiData(float deltaSeconds)
{
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.
}
/// <summary>
/// Draw the ImGui graphic data
/// </summary>
/// <param name="draw_data">
/// ImGui data to draw
/// </param>
/// <param name="gd">
/// Graphic Device
/// </param>
/// <param name="cl">
/// Command List
/// </param>
private void RenderImDrawData(ImDrawDataPtr draw_data, GraphicsDevice gd, CommandList cl) private void RenderImDrawData(ImDrawDataPtr draw_data, GraphicsDevice gd, CommandList cl)
{ {
uint vertexOffsetInVertices = 0; uint vertexOffsetInVertices = 0;
@ -365,17 +506,19 @@
} }
uint totalVBSize = (uint)(draw_data.TotalVtxCount * Unsafe.SizeOf<ImDrawVert>()); uint totalVBSize = (uint)(draw_data.TotalVtxCount * Unsafe.SizeOf<ImDrawVert>());
if (totalVBSize > _vertexBuffer.SizeInBytes) if (totalVBSize > this.vertexBuffer.SizeInBytes)
{ {
gd.DisposeWhenIdle(_vertexBuffer); gd.DisposeWhenIdle(this.vertexBuffer);
_vertexBuffer = gd.ResourceFactory.CreateBuffer(new BufferDescription((uint)(totalVBSize * 1.5f), BufferUsage.VertexBuffer | BufferUsage.Dynamic)); this.vertexBuffer = gd.ResourceFactory.CreateBuffer(new BufferDescription(
(uint)(totalVBSize * 1.5f), BufferUsage.VertexBuffer | BufferUsage.Dynamic));
} }
uint totalIBSize = (uint)(draw_data.TotalIdxCount * sizeof(ushort)); uint totalIBSize = (uint)(draw_data.TotalIdxCount * sizeof(ushort));
if (totalIBSize > _indexBuffer.SizeInBytes) if (totalIBSize > this.indexBuffer.SizeInBytes)
{ {
gd.DisposeWhenIdle(_indexBuffer); gd.DisposeWhenIdle(this.indexBuffer);
_indexBuffer = gd.ResourceFactory.CreateBuffer(new BufferDescription((uint)(totalIBSize * 1.5f), BufferUsage.IndexBuffer | BufferUsage.Dynamic)); this.indexBuffer = gd.ResourceFactory.CreateBuffer(new BufferDescription(
(uint)(totalIBSize * 1.5f), BufferUsage.IndexBuffer | BufferUsage.Dynamic));
} }
for (int i = 0; i < draw_data.CmdListsCount; i++) for (int i = 0; i < draw_data.CmdListsCount; i++)
@ -383,13 +526,13 @@
ImDrawListPtr cmd_list = draw_data.CmdListsRange[i]; ImDrawListPtr cmd_list = draw_data.CmdListsRange[i];
cl.UpdateBuffer( cl.UpdateBuffer(
_vertexBuffer, this.vertexBuffer,
vertexOffsetInVertices * (uint)Unsafe.SizeOf<ImDrawVert>(), vertexOffsetInVertices * (uint)Unsafe.SizeOf<ImDrawVert>(),
cmd_list.VtxBuffer.Data, cmd_list.VtxBuffer.Data,
(uint)(cmd_list.VtxBuffer.Size * Unsafe.SizeOf<ImDrawVert>())); (uint)(cmd_list.VtxBuffer.Size * Unsafe.SizeOf<ImDrawVert>()));
cl.UpdateBuffer( cl.UpdateBuffer(
_indexBuffer, this.indexBuffer,
indexOffsetInElements * sizeof(ushort), indexOffsetInElements * sizeof(ushort),
cmd_list.IdxBuffer.Data, cmd_list.IdxBuffer.Data,
(uint)(cmd_list.IdxBuffer.Size * sizeof(ushort))); (uint)(cmd_list.IdxBuffer.Size * sizeof(ushort)));
@ -408,12 +551,12 @@
-1.0f, -1.0f,
1.0f); 1.0f);
_gd.UpdateBuffer(_projMatrixBuffer, 0, ref mvp); this.gd.UpdateBuffer(this.projMatrixBuffer, 0, ref mvp);
cl.SetVertexBuffer(0, _vertexBuffer); cl.SetVertexBuffer(0, this.vertexBuffer);
cl.SetIndexBuffer(_indexBuffer, IndexFormat.UInt16); cl.SetIndexBuffer(this.indexBuffer, IndexFormat.UInt16);
cl.SetPipeline(_pipeline); cl.SetPipeline(this.pipeline);
cl.SetGraphicsResourceSet(0, _mainResourceSet); cl.SetGraphicsResourceSet(0, this.mainResourceSet);
draw_data.ScaleClipRects(io.DisplayFramebufferScale); draw_data.ScaleClipRects(io.DisplayFramebufferScale);
@ -434,13 +577,15 @@
{ {
if (pcmd.TextureId != IntPtr.Zero) if (pcmd.TextureId != IntPtr.Zero)
{ {
if (pcmd.TextureId == _fontAtlasID) if (pcmd.TextureId == this.fontAtlasID)
{ {
cl.SetGraphicsResourceSet(1, _fontTextureResourceSet); cl.SetGraphicsResourceSet(
1, this.fontTextureResourceSet);
} }
else else
{ {
cl.SetGraphicsResourceSet(1, GetImageResourceSet(pcmd.TextureId)); cl.SetGraphicsResourceSet(
1, this.GetImageResourceSet(pcmd.TextureId));
} }
} }
@ -456,33 +601,14 @@
idx_offset += (int)pcmd.ElemCount; idx_offset += (int)pcmd.ElemCount;
} }
vtx_offset += cmd_list.VtxBuffer.Size; vtx_offset += cmd_list.VtxBuffer.Size;
} }
} }
/// <summary> /// <summary>
/// Frees all graphics resources used by the renderer. /// ResourceSetInfo
/// </summary> /// </summary>
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();
foreach (IDisposable resource in _ownedResources)
{
resource.Dispose();
}
}
private struct ResourceSetInfo private struct ResourceSetInfo
{ {
public readonly IntPtr ImGuiBinding; public readonly IntPtr ImGuiBinding;
@ -490,8 +616,8 @@
public ResourceSetInfo(IntPtr imGuiBinding, ResourceSet resourceSet) public ResourceSetInfo(IntPtr imGuiBinding, ResourceSet resourceSet)
{ {
ImGuiBinding = imGuiBinding; this.ImGuiBinding = imGuiBinding;
ResourceSet = resourceSet; this.ResourceSet = resourceSet;
} }
} }
} }

@ -1,8 +1,16 @@
namespace ClickableTransparentOverlay // <copyright file="NativeMethods.cs" company="Zaafar Ahmed">
// Copyright (c) Zaafar Ahmed. All rights reserved.
// </copyright>
namespace ClickableTransparentOverlay
{ {
using System; using System;
using System.Drawing;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
/// <summary>
/// This class allow user to access Win32 API functions.
/// </summary>
public static class NativeMethods public static class NativeMethods
{ {
private const int GWL_EXSTYLE = -20; private const int GWL_EXSTYLE = -20;
@ -12,7 +20,16 @@
private const int SW_HIDE = 0x00; private const int SW_HIDE = 0x00;
private const int SW_SHOW = 0x05; private const int SW_SHOW = 0x05;
public static void EnableTransparent(IntPtr handle, System.Drawing.Rectangle size) /// <summary>
/// Allows the SDL2Window to become transparent.
/// </summary>
/// <param name="handle">
/// Veldrid window handle in IntPtr format.
/// </param>
/// <param name="size">
/// Size of the SDL2Window.
/// </param>
public static void EnableTransparent(IntPtr handle, Rectangle size)
{ {
IntPtr windowLong = GetWindowLongPtr(handle, GWL_EXSTYLE); IntPtr windowLong = GetWindowLongPtr(handle, GWL_EXSTYLE);
windowLong = new IntPtr(windowLong.ToInt64() | WS_EX_LAYERED | WS_EX_TRANSPARENT); windowLong = new IntPtr(windowLong.ToInt64() | WS_EX_LAYERED | WS_EX_TRANSPARENT);
@ -21,22 +38,46 @@
DwmExtendFrameIntoClientArea(handle, ref margins); DwmExtendFrameIntoClientArea(handle, ref margins);
} }
/// <summary>
/// Allows hiding the console window.
/// </summary>
public static void HideConsoleWindow() public static void HideConsoleWindow()
{ {
var handle = GetConsoleWindow(); var handle = GetConsoleWindow();
ShowWindow(handle, SW_HIDE); ShowWindow(handle, SW_HIDE);
} }
/// <summary>
/// Allows displaying the console window.
/// </summary>
public static void ShowConsoleWindow() public static void ShowConsoleWindow()
{ {
var handle = GetConsoleWindow(); var handle = GetConsoleWindow();
ShowWindow(handle, SW_SHOW); ShowWindow(handle, SW_SHOW);
} }
[DllImport("dwmapi.dll")]
private static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref Margins pMarInset);
[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]
private static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]
private static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
[DllImport("kernel32.dll")]
private static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll", EntryPoint = "ShowWindow", SetLastError = true)]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
private struct Margins private struct Margins
{ {
private int left, right, top, bottom; private int left;
private int right;
private int top;
private int bottom;
public static Margins FromRectangle(System.Drawing.Rectangle rectangle) public static Margins FromRectangle(System.Drawing.Rectangle rectangle)
{ {
@ -50,20 +91,5 @@
return margins; return margins;
} }
} }
[DllImport("dwmapi.dll")]
private static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref Margins pMarInset);
[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]
private static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]
private static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll", EntryPoint = "ShowWindow", SetLastError = true)]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
} }
} }

@ -1,4 +1,8 @@
namespace ClickableTransparentOverlay // <copyright file="Overlay.cs" company="Zaafar Ahmed">
// Copyright (c) Zaafar Ahmed. All rights reserved.
// </copyright>
namespace ClickableTransparentOverlay
{ {
using System; using System;
using System.Numerics; using System.Numerics;
@ -8,160 +12,214 @@
using Veldrid.Sdl2; using Veldrid.Sdl2;
using Veldrid.StartupUtilities; using Veldrid.StartupUtilities;
/// <summary>
/// A class to create clickable transparent overlay
/// </summary>
public class Overlay public class Overlay
{ {
private static Sdl2Window _window; private static Sdl2Window window;
private static GraphicsDevice _gd; private static GraphicsDevice graphicsDevice;
private static CommandList _cl; private static CommandList commandList;
private static ImGuiController _im_controller; private static ImGuiController imController;
private static HookController _hook_controller; private static HookController hookController;
private static Thread _ui_thread; private static Thread uiThread;
public event EventHandler SubmitUI;
// UI State // UI State
private static Vector4 _clearColor; private static Vector4 clearColor;
private static Vector2 _future_pos; private static Vector2 futurePos;
private static Vector2 _future_size; private static Vector2 futureSize;
private static int _fps; private static int myFps;
private static bool _is_visible; private static bool isVisible;
private static bool _is_closed; private static bool isClosed;
private static bool _require_resize; private static bool requireResize;
private static bool _start_resizing; private static bool startResizing;
private static object _resize_thread_lock; private static object resizeLock;
/// <summary>
/// Initializes a new instance of the <see cref="Overlay"/> class.
/// </summary>
/// <param name="x">
/// x position of the overlay
/// </param>
/// <param name="y">
/// y position of the overlay
/// </param>
/// <param name="width">
/// width of the overlay
/// </param>
/// <param name="height">
/// height of the Overlay
/// </param>
/// <param name="fps">
/// fps of the overlay
/// </param>
public Overlay(int x, int y, int width, int height, int fps) public Overlay(int x, int y, int width, int height, int fps)
{ {
_clearColor = new Vector4(0.00f, 0.00f, 0.00f, 0.00f); clearColor = new Vector4(0.00f, 0.00f, 0.00f, 0.00f);
_fps = fps; myFps = fps;
_is_visible = true; isVisible = true;
_is_closed = false; isClosed = false;
// Stuff related to (thread safe) resizing of SDL2Window // Stuff related to (thread safe) resizing of SDL2Window
_require_resize = false; requireResize = false;
_start_resizing = false; startResizing = false;
_resize_thread_lock = new object(); resizeLock = new object();
_future_size = Vector2.Zero; futureSize = Vector2.Zero;
_future_pos = Vector2.Zero; futurePos = Vector2.Zero;
_window = new Sdl2Window("Overlay", x, x, width, height, SDL_WindowFlags.Borderless | SDL_WindowFlags.AlwaysOnTop | SDL_WindowFlags.SkipTaskbar, true); window = new Sdl2Window("Overlay", x, x, width, height, SDL_WindowFlags.Borderless | SDL_WindowFlags.AlwaysOnTop | SDL_WindowFlags.SkipTaskbar, true);
// TODO: Create a new branch for Non-Veldrid dependent version. Ideally, we can directly use SDL2Window. graphicsDevice = VeldridStartup.CreateGraphicsDevice(window, new GraphicsDeviceOptions(true, null, true), GraphicsBackend.Direct3D11);
_gd = VeldridStartup.CreateGraphicsDevice(_window, new GraphicsDeviceOptions(true, null, true), GraphicsBackend.Direct3D11); NativeMethods.EnableTransparent(window.Handle, new System.Drawing.Rectangle(window.X, window.Y, window.Width, window.Height));
NativeMethods.EnableTransparent(_window.Handle, new System.Drawing.Rectangle(_window.X , _window.Y, _window.Width, _window.Height)); window.Resized += () =>
_window.Resized += () =>
{ {
_gd.MainSwapchain.Resize((uint)_window.Width, (uint)_window.Height); graphicsDevice.MainSwapchain.Resize((uint)window.Width, (uint)window.Height);
_im_controller.WindowResized(_window.Width, _window.Height); imController.WindowResized(window.Width, window.Height);
lock (_resize_thread_lock) lock (resizeLock)
{ {
_require_resize = false; requireResize = false;
_start_resizing = false; startResizing = false;
} }
}; };
_window.Closed += () => window.Closed += () =>
{ {
_is_closed = true; isClosed = true;
}; };
_cl = _gd.ResourceFactory.CreateCommandList(); commandList = graphicsDevice.ResourceFactory.CreateCommandList();
_im_controller = new ImGuiController(_gd, _gd.MainSwapchain.Framebuffer.OutputDescription, _window.Width, _window.Height, _fps); imController = new ImGuiController(graphicsDevice, graphicsDevice.MainSwapchain.Framebuffer.OutputDescription, window.Width, window.Height, myFps);
_ui_thread = new Thread(WhileLoop); uiThread = new Thread(this.WhileLoop);
_hook_controller = new HookController(_window.X, _window.Y); hookController = new HookController(window.X, window.Y);
} }
/// <summary>
/// To submit ImGui code for generating the UI.
/// </summary>
public event EventHandler SubmitUI;
/// <summary>
/// Starts the overlay
/// </summary>
public void Run() public void Run()
{ {
_ui_thread.Start(); uiThread.Start();
_hook_controller.EnableHooks(); hookController.EnableHooks();
NativeMethods.HideConsoleWindow(); NativeMethods.HideConsoleWindow();
Application.Run(new ApplicationContext()); Application.Run(new ApplicationContext());
} }
/// <summary>
/// Free all resources acquired by the overlay
/// </summary>
public void Dispose() public void Dispose()
{ {
_is_visible = false; isVisible = false;
_window.Close(); window.Close();
while (!_is_closed) while (!isClosed)
{ {
Thread.Sleep(10); Thread.Sleep(10);
} }
_ui_thread.Join(); uiThread.Join();
_gd.WaitForIdle(); graphicsDevice.WaitForIdle();
_im_controller.Dispose(); imController.Dispose();
_cl.Dispose(); commandList.Dispose();
_gd.Dispose(); graphicsDevice.Dispose();
_hook_controller.Dispose(); hookController.Dispose();
NativeMethods.ShowConsoleWindow(); NativeMethods.ShowConsoleWindow();
_resize_thread_lock = null; resizeLock = null;
SubmitUI = null; this.SubmitUI = null;
Console.WriteLine("All Overlay resources are cleared."); Console.WriteLine("All Overlay resources are cleared.");
Application.Exit(); Application.Exit();
} }
public void ResizeWindow(int x, int y, int width, int height) /// <summary>
{ /// Resizes the overlay
_future_pos.X = x; /// </summary>
_future_pos.Y = y; /// <param name="x">
_future_size.X = width; /// x axis of the overlay
_future_size.Y = height; /// </param>
/// <param name="y">
/// y axis of the overlay
/// </param>
/// <param name="width">
/// width of the overlay
/// </param>
/// <param name="height">
/// height of the overlay
/// </param>
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 // TODO: move following two lines to _window.Moved
_hook_controller.UpdateWindowPosition(x, y); hookController.UpdateWindowPosition(x, y);
NativeMethods.EnableTransparent(_window.Handle, new System.Drawing.Rectangle(x, y, width, height)); NativeMethods.EnableTransparent(window.Handle, new System.Drawing.Rectangle(x, y, width, height));
_require_resize = true; requireResize = true;
} }
public void ShowWindow() /// <summary>
/// Shows the overlay
/// </summary>
public void Show()
{ {
_hook_controller.ResumeHooks(); hookController.ResumeHooks();
_is_visible = true; isVisible = true;
} }
public void HideWindow() /// <summary>
/// hides the overlay
/// </summary>
public void Hide()
{ {
// TODO: Improve this function to do the following // TODO: Improve this function to do the following
// 1: Hide SDL2Window // 1: Hide SDL2Window
// 2: Pause WhileLoop // 2: Pause WhileLoop
// This will ensure we don't waste CPU/GPU resources while window is hidden // This will ensure we don't waste CPU/GPU resources while window is hidden
_hook_controller.PauseHooks(); hookController.PauseHooks();
_is_visible = false; isVisible = false;
} }
private void WhileLoop() private void WhileLoop()
{ {
while (_window.Exists) while (window.Exists)
{ {
lock (_resize_thread_lock) lock (resizeLock)
{ {
if (_require_resize) if (requireResize)
{ {
if (!_start_resizing) if (!startResizing)
{ {
Sdl2Native.SDL_SetWindowPosition(_window.SdlWindowHandle, (int)_future_pos.X, (int)_future_pos.Y); Sdl2Native.SDL_SetWindowPosition(window.SdlWindowHandle, (int)futurePos.X, (int)futurePos.Y);
Sdl2Native.SDL_SetWindowSize(_window.SdlWindowHandle, (int)_future_size.X, (int)_future_size.Y); Sdl2Native.SDL_SetWindowSize(window.SdlWindowHandle, (int)futureSize.X, (int)futureSize.Y);
_start_resizing = true; startResizing = true;
} }
continue; continue;
} }
} }
if (!_window.Exists) if (!window.Exists)
{ {
break; break;
} }
_im_controller.InitlizeFrame(1f / _fps); imController.InitlizeFrame(1f / myFps);
if (_is_visible) if (isVisible)
{ {
SubmitUI?.Invoke(this, new EventArgs()); this.SubmitUI?.Invoke(this, new EventArgs());
} }
_cl.Begin(); commandList.Begin();
_cl.SetFramebuffer(_gd.MainSwapchain.Framebuffer); commandList.SetFramebuffer(graphicsDevice.MainSwapchain.Framebuffer);
_cl.ClearColorTarget(0, new RgbaFloat(_clearColor.X, _clearColor.Y, _clearColor.Z, _clearColor.W)); commandList.ClearColorTarget(0, new RgbaFloat(clearColor.X, clearColor.Y, clearColor.Z, clearColor.W));
_im_controller.Render(_gd, _cl); imController.Render(graphicsDevice, commandList);
_cl.End(); commandList.End();
_gd.SubmitCommands(_cl); graphicsDevice.SubmitCommands(commandList);
_gd.SwapBuffers(_gd.MainSwapchain); graphicsDevice.SwapBuffers(graphicsDevice.MainSwapchain);
} }
} }
} }

@ -1,5 +1,8 @@
using System.Reflection; // <copyright file="AssemblyInfo.cs" company="Zaafar Ahmed">
using System.Runtime.CompilerServices; // Copyright (c) Zaafar Ahmed. All rights reserved.
// </copyright>
using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following // General Information about an assembly is controlled through the following

@ -6,6 +6,7 @@
<package id="SharpDX" version="4.2.0" targetFramework="net472" /> <package id="SharpDX" version="4.2.0" targetFramework="net472" />
<package id="SharpDX.Direct3D11" version="4.2.0" targetFramework="net472" /> <package id="SharpDX.Direct3D11" version="4.2.0" targetFramework="net472" />
<package id="SharpDX.DXGI" version="4.2.0" targetFramework="net472" /> <package id="SharpDX.DXGI" version="4.2.0" targetFramework="net472" />
<package id="StyleCop.Analyzers" version="1.0.2" targetFramework="net472" developmentDependency="true" />
<package id="System.Buffers" version="4.5.0" targetFramework="net472" /> <package id="System.Buffers" version="4.5.0" targetFramework="net472" />
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net472" /> <package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net472" />
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net472" /> <package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net472" />

@ -0,0 +1,14 @@
{
// 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"
}
}
}

@ -17,6 +17,18 @@
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.1" /> <bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.1" />
</dependentAssembly> </dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="SharpDX.Direct3D11" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="SharpDX" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="SharpDX.DXGI" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
</dependentAssembly>
</assemblyBinding> </assemblyBinding>
</runtime> </runtime>
</configuration> </configuration>

@ -41,12 +41,12 @@
public static void DistroyDemo() public static void DistroyDemo()
{ {
Thread.Sleep(RunFor * 1000); Thread.Sleep(RunFor * 1000);
//demo.ResizeWindow(0, 0, 2560, 1440); demo.Resize(200, 200, 1024, 1024);
//Thread.Sleep(10000); Thread.Sleep(RunFor * 1000);
//demo.HideWindow(); demo.Hide();
//Thread.Sleep(10000); Thread.Sleep(RunFor * 1000);
//demo.ShowWindow(); demo.Show();
//Thread.Sleep(10000); Thread.Sleep(RunFor * 1000);
demo.Dispose(); demo.Dispose();
} }
} }

Loading…
Cancel
Save