Added ImGui.NET
Start working on controller.
This commit is contained in:
		
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @@ -13,3 +13,6 @@ | |||||||
| [submodule "Nerfed.Runtime/Libraries/dav1dfile"] | [submodule "Nerfed.Runtime/Libraries/dav1dfile"] | ||||||
| 	path = Nerfed.Runtime/Libraries/dav1dfile | 	path = Nerfed.Runtime/Libraries/dav1dfile | ||||||
| 	url = https://github.com/MoonsideGames/dav1dfile.git | 	url = https://github.com/MoonsideGames/dav1dfile.git | ||||||
|  | [submodule "Nerfed.Runtime/Libraries/ImGui.NET"] | ||||||
|  | 	path = Nerfed.Runtime/Libraries/ImGui.NET | ||||||
|  | 	url = https://github.com/ImGuiNET/ImGui.NET.git | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								Nerfed.Runtime/Assets/Shaders/imgui-frag.spv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Nerfed.Runtime/Assets/Shaders/imgui-frag.spv
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Nerfed.Runtime/Assets/Shaders/imgui-vertex.spv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Nerfed.Runtime/Assets/Shaders/imgui-vertex.spv
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -1,7 +1,7 @@ | |||||||
| using System.Diagnostics; |  | ||||||
| using Nerfed.Runtime.Audio; | using Nerfed.Runtime.Audio; | ||||||
| using Nerfed.Runtime.Graphics; | using Nerfed.Runtime.Graphics; | ||||||
| using SDL2; | using SDL2; | ||||||
|  | using System.Diagnostics; | ||||||
| 
 | 
 | ||||||
| namespace Nerfed.Runtime; | namespace Nerfed.Runtime; | ||||||
| 
 | 
 | ||||||
| @@ -39,6 +39,8 @@ public static class Engine | |||||||
|     private const string WindowTitle = "Nerfed"; |     private const string WindowTitle = "Nerfed"; | ||||||
|     //.. |     //.. | ||||||
| 
 | 
 | ||||||
|  |     private static Gui.Controller Controller; | ||||||
|  | 
 | ||||||
|     internal static void Run(string[] args) |     internal static void Run(string[] args) | ||||||
|     { |     { | ||||||
|         Timestep = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / TargetTimestep); |         Timestep = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / TargetTimestep); | ||||||
| @@ -65,11 +67,17 @@ public static class Engine | |||||||
| 
 | 
 | ||||||
|         AudioDevice = new AudioDevice(); |         AudioDevice = new AudioDevice(); | ||||||
| 
 | 
 | ||||||
|  |         Controller = new Gui.Controller(GraphicsDevice, MainWindow, Color.DarkOliveGreen); | ||||||
|  |         Controller.OnGui += () => { | ||||||
|  |             ImGuiNET.ImGui.ShowDemoWindow(); | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|         while (!quit) |         while (!quit) | ||||||
|         { |         { | ||||||
|             Tick(); |             Tick(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         Controller.Dispose(); | ||||||
|         GraphicsDevice.UnclaimWindow(MainWindow); |         GraphicsDevice.UnclaimWindow(MainWindow); | ||||||
|         MainWindow.Dispose(); |         MainWindow.Dispose(); | ||||||
|         GraphicsDevice.Dispose(); |         GraphicsDevice.Dispose(); | ||||||
| @@ -145,6 +153,7 @@ public static class Engine | |||||||
| 
 | 
 | ||||||
|                 ProcessSDLEvents(); |                 ProcessSDLEvents(); | ||||||
| 
 | 
 | ||||||
|  |                 Controller.Update((float)Timestep.TotalSeconds); | ||||||
|                 // Tick game here... |                 // Tick game here... | ||||||
| 
 | 
 | ||||||
|                 AudioDevice.WakeThread(); |                 AudioDevice.WakeThread(); | ||||||
| @@ -154,6 +163,7 @@ public static class Engine | |||||||
|             double alpha = accumulatedUpdateTime / Timestep; |             double alpha = accumulatedUpdateTime / Timestep; | ||||||
| 
 | 
 | ||||||
|             // Render here.. |             // Render here.. | ||||||
|  |             Controller.Render(); | ||||||
| 
 | 
 | ||||||
|             accumulatedDrawTime -= framerateCapTimeSpan; |             accumulatedDrawTime -= framerateCapTimeSpan; | ||||||
|         } |         } | ||||||
|   | |||||||
							
								
								
									
										48
									
								
								Nerfed.Runtime/Gui/Clipboard.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								Nerfed.Runtime/Gui/Clipboard.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | |||||||
|  | using System.Runtime.InteropServices; | ||||||
|  | using System.Text; | ||||||
|  | 
 | ||||||
|  | namespace Nerfed.Runtime.Gui; | ||||||
|  | 
 | ||||||
|  | public static unsafe class Clipboard | ||||||
|  | { | ||||||
|  |     private static IntPtr clipboard; | ||||||
|  |     private static readonly Dictionary<Delegate, IntPtr> pinned = new(); | ||||||
|  | 
 | ||||||
|  |     private static unsafe void Set(void* userdata, byte* text) | ||||||
|  |     { | ||||||
|  |         int len = 0; while (text[len] != 0) len++; | ||||||
|  |         string str = Encoding.UTF8.GetString(text, len); | ||||||
|  |         SDL2.SDL.SDL_SetClipboardText(str); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static unsafe byte* Get(void* userdata) | ||||||
|  |     { | ||||||
|  |         if (clipboard != IntPtr.Zero) | ||||||
|  |         { | ||||||
|  |             NativeMemory.Free((void*) clipboard); | ||||||
|  |             clipboard = IntPtr.Zero; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         string str = SDL2.SDL.SDL_GetClipboardText(); | ||||||
|  |         int length = Encoding.UTF8.GetByteCount(str); | ||||||
|  |         byte* bytes = (byte*)(clipboard = (nint)NativeMemory.Alloc((nuint)(length + 1))); | ||||||
|  | 
 | ||||||
|  |         Encoding.UTF8.GetBytes(str, new Span<byte>(bytes, length)); | ||||||
|  |         bytes[length] = 0; | ||||||
|  |         return bytes; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Stops the delegate pointer from being collected | ||||||
|  |     private static IntPtr GetPointerTo<T>(T fn) where T : Delegate | ||||||
|  |     { | ||||||
|  |         if (pinned.TryGetValue(fn, out nint ptr)) | ||||||
|  |             return ptr; | ||||||
|  | 
 | ||||||
|  |         ptr = Marshal.GetFunctionPointerForDelegate(fn); | ||||||
|  |         pinned.Add(fn, ptr); | ||||||
|  |         return ptr; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static readonly IntPtr GetFnPtr = GetPointerTo(Get); | ||||||
|  |     public static readonly IntPtr SetFnPtr = GetPointerTo(Set); | ||||||
|  | } | ||||||
							
								
								
									
										661
									
								
								Nerfed.Runtime/Gui/Controller.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										661
									
								
								Nerfed.Runtime/Gui/Controller.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,661 @@ | |||||||
|  | // ImGuiController with docking and viewport support for MoonWorks/Refresh. | ||||||
|  | // Based on the example im ImGui.NET and MoonWorksDearImGuiScaffold. | ||||||
|  | 
 | ||||||
|  | using ImGuiNET; | ||||||
|  | using Nerfed.Runtime.Graphics; | ||||||
|  | using System.Numerics; | ||||||
|  | using System.Runtime.CompilerServices; | ||||||
|  | using System.Runtime.InteropServices; | ||||||
|  | 
 | ||||||
|  | namespace Nerfed.Runtime.Gui; | ||||||
|  | 
 | ||||||
|  | internal class Controller : IDisposable | ||||||
|  | { | ||||||
|  |     public event Action OnGui; | ||||||
|  | 
 | ||||||
|  |     private readonly string shaderContentPath = Path.Combine(System.AppContext.BaseDirectory, "Assets", "Shaders"); | ||||||
|  | 
 | ||||||
|  |     private readonly GraphicsDevice graphicsDevice; | ||||||
|  |     private readonly Window mainWindow; | ||||||
|  |     private readonly Color clearColor; | ||||||
|  | 
 | ||||||
|  |     private readonly Platform_CreateWindow createWindow; | ||||||
|  |     private readonly Platform_DestroyWindow destroyWindow; | ||||||
|  |     private readonly Platform_GetWindowPos getWindowPos; | ||||||
|  |     private readonly Platform_ShowWindow showWindow; | ||||||
|  |     private readonly Platform_SetWindowPos setWindowPos; | ||||||
|  |     private readonly Platform_SetWindowSize setWindowSize; | ||||||
|  |     private readonly Platform_GetWindowSize getWindowSize; | ||||||
|  |     private readonly Platform_SetWindowFocus setWindowFocus; | ||||||
|  |     private readonly Platform_GetWindowFocus getWindowFocus; | ||||||
|  |     private readonly Platform_GetWindowMinimized getWindowMinimized; | ||||||
|  |     private readonly Platform_SetWindowTitle setWindowTitle; | ||||||
|  | 
 | ||||||
|  |     private readonly ResourceUploader resourceUploader; | ||||||
|  |     private readonly GraphicsPipeline imGuiPipeline; | ||||||
|  |     private readonly Shader imGuiVertexShader; | ||||||
|  |     private readonly Shader imGuiFragmentShader; | ||||||
|  |     private readonly Sampler imGuiSampler; | ||||||
|  |     private readonly TextureStorage textureStorage = new TextureStorage(); | ||||||
|  |     private readonly Dictionary<Window, GCHandle> windows = new Dictionary<Window, GCHandle>(16); | ||||||
|  | 
 | ||||||
|  |     private Texture fontTexture = null; | ||||||
|  |     private uint vertexCount = 0; | ||||||
|  |     private uint indexCount = 0; | ||||||
|  |     private Graphics.Buffer imGuiVertexBuffer = null; | ||||||
|  |     private Graphics.Buffer imGuiIndexBuffer = null; | ||||||
|  |     private bool frameBegun = false; | ||||||
|  | 
 | ||||||
|  |     public Controller(GraphicsDevice graphicsDevice, Window mainWindow, Color clearColor, ImGuiConfigFlags configFlags = ImGuiConfigFlags.NavEnableKeyboard | ImGuiConfigFlags.DockingEnable | ImGuiConfigFlags.ViewportsEnable) | ||||||
|  |     { | ||||||
|  |         this.mainWindow = mainWindow; | ||||||
|  |         this.graphicsDevice = graphicsDevice; | ||||||
|  |         this.clearColor = clearColor; | ||||||
|  | 
 | ||||||
|  |         resourceUploader = new ResourceUploader(graphicsDevice); | ||||||
|  | 
 | ||||||
|  |         ImGui.CreateContext(); | ||||||
|  | 
 | ||||||
|  |         ImGuiIOPtr io = ImGui.GetIO(); | ||||||
|  |         io.DisplaySize = new Vector2(mainWindow.Width, mainWindow.Height); | ||||||
|  |         io.DisplayFramebufferScale = Vector2.One; | ||||||
|  | 
 | ||||||
|  |         ShaderCreateInfo vertexCreateInfo = new ShaderCreateInfo { | ||||||
|  |             ShaderStage = ShaderStage.Vertex, | ||||||
|  |             ShaderFormat = ShaderFormat.SPIRV, | ||||||
|  |             UniformBufferCount = 1, | ||||||
|  |         }; | ||||||
|  |         imGuiVertexShader = new Shader(graphicsDevice, Path.Combine(shaderContentPath, "imgui-vertex.spv"), "main", in vertexCreateInfo); | ||||||
|  |         ShaderCreateInfo fragCreateInfo = new ShaderCreateInfo { | ||||||
|  |             ShaderStage = ShaderStage.Fragment, | ||||||
|  |             ShaderFormat = ShaderFormat.SPIRV, | ||||||
|  |             SamplerCount = 1, | ||||||
|  |              | ||||||
|  |         }; | ||||||
|  |         imGuiFragmentShader = new Shader(graphicsDevice, Path.Combine(shaderContentPath, "imgui-frag.spv"), "main", in fragCreateInfo); | ||||||
|  | 
 | ||||||
|  |         imGuiSampler = new Sampler(graphicsDevice, SamplerCreateInfo.LinearClamp); | ||||||
|  | 
 | ||||||
|  |         imGuiPipeline = new GraphicsPipeline( | ||||||
|  |             graphicsDevice, | ||||||
|  |             new GraphicsPipelineCreateInfo | ||||||
|  |             { | ||||||
|  |                 AttachmentInfo = new GraphicsPipelineAttachmentInfo( | ||||||
|  |                     new ColorAttachmentDescription( | ||||||
|  |                         mainWindow.SwapchainFormat, | ||||||
|  |                         ColorAttachmentBlendState.NonPremultiplied | ||||||
|  |                     ) | ||||||
|  |                 ), | ||||||
|  |                 DepthStencilState = DepthStencilState.Disable, | ||||||
|  |                 MultisampleState = MultisampleState.None, | ||||||
|  |                 PrimitiveType = PrimitiveType.TriangleList, | ||||||
|  |                 RasterizerState = RasterizerState.CW_CullNone, | ||||||
|  |                 VertexInputState = VertexInputState.CreateSingleBinding<Position2DTextureColorVertex>(), | ||||||
|  |                 VertexShader = imGuiVertexShader, | ||||||
|  |                 FragmentShader = imGuiFragmentShader, | ||||||
|  |             } | ||||||
|  |         ); | ||||||
|  | 
 | ||||||
|  |         BuildFontAtlas(); | ||||||
|  | 
 | ||||||
|  |         io.ConfigFlags = configFlags; | ||||||
|  |         //io.MouseDrawCursor = true; | ||||||
|  | 
 | ||||||
|  |         if (!OperatingSystem.IsWindows()) | ||||||
|  |         { | ||||||
|  |             io.SetClipboardTextFn = Clipboard.SetFnPtr; | ||||||
|  |             io.GetClipboardTextFn = Clipboard.GetFnPtr; | ||||||
|  |         } | ||||||
|  |              | ||||||
|  |         ImGuiPlatformIOPtr platformIO = ImGui.GetPlatformIO(); | ||||||
|  |         ImGuiViewportPtr mainViewport = platformIO.Viewports[0]; | ||||||
|  |         mainViewport.PlatformHandle = mainWindow.Handle; | ||||||
|  |         GCHandle handle = GCHandle.Alloc(mainWindow); | ||||||
|  |         mainViewport.PlatformUserData = (IntPtr)handle; | ||||||
|  |         windows.Add(mainWindow, handle); | ||||||
|  | 
 | ||||||
|  |         unsafe | ||||||
|  |         { | ||||||
|  |             createWindow = CreateWindow; | ||||||
|  |             destroyWindow = DestroyWindow; | ||||||
|  |             getWindowPos = GetWindowPos; | ||||||
|  |             showWindow = ShowWindow; | ||||||
|  |             setWindowPos = SetWindowPos; | ||||||
|  |             setWindowSize = SetWindowSize; | ||||||
|  |             getWindowSize = GetWindowSize; | ||||||
|  |             setWindowFocus = SetWindowFocus; | ||||||
|  |             getWindowFocus = GetWindowFocus; | ||||||
|  |             getWindowMinimized = GetWindowMinimized; | ||||||
|  |             setWindowTitle = SetWindowTitle; | ||||||
|  | 
 | ||||||
|  |             platformIO.Platform_CreateWindow = Marshal.GetFunctionPointerForDelegate(createWindow); | ||||||
|  |             platformIO.Platform_DestroyWindow = Marshal.GetFunctionPointerForDelegate(destroyWindow); | ||||||
|  |             platformIO.Platform_ShowWindow = Marshal.GetFunctionPointerForDelegate(showWindow); | ||||||
|  |             platformIO.Platform_SetWindowPos = Marshal.GetFunctionPointerForDelegate(setWindowPos); | ||||||
|  |             platformIO.Platform_SetWindowSize = Marshal.GetFunctionPointerForDelegate(setWindowSize); | ||||||
|  |             platformIO.Platform_SetWindowFocus = Marshal.GetFunctionPointerForDelegate(setWindowFocus); | ||||||
|  |             platformIO.Platform_GetWindowFocus = Marshal.GetFunctionPointerForDelegate(getWindowFocus); | ||||||
|  |             platformIO.Platform_GetWindowMinimized = Marshal.GetFunctionPointerForDelegate(getWindowMinimized); | ||||||
|  |             platformIO.Platform_SetWindowTitle = Marshal.GetFunctionPointerForDelegate(setWindowTitle); | ||||||
|  | 
 | ||||||
|  |             ImGuiNative.ImGuiPlatformIO_Set_Platform_GetWindowPos(platformIO.NativePtr, Marshal.GetFunctionPointerForDelegate(getWindowPos)); | ||||||
|  |             ImGuiNative.ImGuiPlatformIO_Set_Platform_GetWindowSize(platformIO.NativePtr, Marshal.GetFunctionPointerForDelegate(getWindowSize)); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         //io.BackendFlags |= ImGuiBackendFlags.HasMouseCursors; | ||||||
|  |         io.BackendFlags |= ImGuiBackendFlags.HasSetMousePos; | ||||||
|  |         io.BackendFlags |= ImGuiBackendFlags.PlatformHasViewports; | ||||||
|  |         io.BackendFlags |= ImGuiBackendFlags.RendererHasViewports; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void Update(float deltaTime) | ||||||
|  |     { | ||||||
|  |         if (frameBegun) | ||||||
|  |         { | ||||||
|  |             ImGui.Render(); | ||||||
|  |             ImGui.UpdatePlatformWindows(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         UpdatePerFrameImGuiData(deltaTime); | ||||||
|  |         UpdateInput(); | ||||||
|  |         UpdateMonitors(); | ||||||
|  | 
 | ||||||
|  |         frameBegun = true; | ||||||
|  |         ImGui.NewFrame(); | ||||||
|  | 
 | ||||||
|  |         OnGui?.Invoke(); | ||||||
|  | 
 | ||||||
|  |         {   // Debug | ||||||
|  |             ImGuiIOPtr io = ImGui.GetIO(); | ||||||
|  |             ImGui.Text($"mouse pos: {io.MousePos}"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         ImGui.EndFrame(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void UpdatePerFrameImGuiData(float deltaSeconds) | ||||||
|  |     { | ||||||
|  |         ImGuiIOPtr io = ImGui.GetIO(); | ||||||
|  |         io.DisplaySize = new Vector2(mainWindow.Width, mainWindow.Height); | ||||||
|  |         io.DisplayFramebufferScale = new Vector2(1, 1); | ||||||
|  |         io.DeltaTime = deltaSeconds; // DeltaTime is in seconds. | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void UpdateInput() | ||||||
|  |     { | ||||||
|  |         ImGuiIOPtr io = ImGui.GetIO(); | ||||||
|  | 
 | ||||||
|  |         if ((ImGui.GetIO().ConfigFlags & ImGuiConfigFlags.ViewportsEnable) != 0) | ||||||
|  |         { | ||||||
|  |             // For viewports we use the global mouse position. | ||||||
|  |             _ = SDL2.SDL.SDL_GetGlobalMouseState(out int x, out int y); | ||||||
|  |             io.MousePos = new Vector2(x, y); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             // Without viewports we need to use the relative position. | ||||||
|  |             //_ = SDL2.SDL.SDL_GetMouseState(out int x, out int y); | ||||||
|  |             io.MousePos = Mouse.Position; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         io.MouseDown[0] = Mouse.IsButtonDown(MouseButton.Left); | ||||||
|  |         io.MouseDown[1] = Mouse.IsButtonDown(MouseButton.Right); | ||||||
|  |         io.MouseDown[2] = Mouse.IsButtonDown(MouseButton.Middle); | ||||||
|  |          | ||||||
|  |         io.MouseWheel = Mouse.GetWheel(); | ||||||
|  | 
 | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.A, Keyboard.IsKeyDown(Key.A)); | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.Z, Keyboard.IsKeyDown(Key.Z)); | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.Y, Keyboard.IsKeyDown(Key.Y)); | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.X, Keyboard.IsKeyDown(Key.X)); | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.C, Keyboard.IsKeyDown(Key.C)); | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.V, Keyboard.IsKeyDown(Key.V)); | ||||||
|  | 
 | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.Tab, Keyboard.IsKeyDown(Key.Tab)); | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.LeftArrow, Keyboard.IsKeyDown(Key.Left)); | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.RightArrow, Keyboard.IsKeyDown(Key.Right)); | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.UpArrow, Keyboard.IsKeyDown(Key.Up)); | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.DownArrow, Keyboard.IsKeyDown(Key.Down)); | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.Enter, Keyboard.IsKeyDown(Key.Enter)); | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.Escape, Keyboard.IsKeyDown(Key.Escape)); | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.Delete, Keyboard.IsKeyDown(Key.Delete)); | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.Backspace, Keyboard.IsKeyDown(Key.Backspace)); | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.Home, Keyboard.IsKeyDown(Key.Home)); | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.End, Keyboard.IsKeyDown(Key.End)); | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.PageDown, Keyboard.IsKeyDown(Key.PageDown)); | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.PageUp, Keyboard.IsKeyDown(Key.PageUp)); | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.Insert, Keyboard.IsKeyDown(Key.Insert)); | ||||||
|  | 
 | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.ModCtrl, Keyboard.IsKeyDown(Key.LeftControl) || Keyboard.IsKeyDown(Key.RightControl)); | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.ModShift, Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift)); | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.ModAlt, Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt)); | ||||||
|  |         //io.AddKeyEvent(ImGuiKey.ModSuper, Keyboard.IsKeyDown(Key.LeftSuper) || Keyboard.IsKeyDown(Key.RightSuper)); | ||||||
|  | 
 | ||||||
|  |         //ReadOnlySpan<char> input = Keyboard.GetTextInput(); | ||||||
|  |         //if (!input.IsEmpty) | ||||||
|  |         //{ | ||||||
|  |         //    foreach (char c in input) | ||||||
|  |         //    { | ||||||
|  |         //        if (c == '\t') | ||||||
|  |         //        { | ||||||
|  |         //            break; | ||||||
|  |         //        } | ||||||
|  | 
 | ||||||
|  |         //        io.AddInputCharacter(c); | ||||||
|  |         //    } | ||||||
|  |         //} | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private unsafe void UpdateMonitors() | ||||||
|  |     { | ||||||
|  |         ImGuiPlatformIOPtr platformIO = ImGui.GetPlatformIO(); | ||||||
|  |         Marshal.FreeHGlobal(platformIO.NativePtr->Monitors.Data); | ||||||
|  |         int videoDisplayCount = SDL2.SDL.SDL_GetNumVideoDisplays(); | ||||||
|  |         IntPtr data = Marshal.AllocHGlobal(Unsafe.SizeOf<ImGuiPlatformMonitor>() * videoDisplayCount); | ||||||
|  |         platformIO.NativePtr->Monitors = new ImVector(videoDisplayCount, videoDisplayCount, data); | ||||||
|  | 
 | ||||||
|  |         for (int i = 0; i < videoDisplayCount; i++) | ||||||
|  |         { | ||||||
|  |             _ = SDL2.SDL.SDL_GetDisplayUsableBounds(i, out SDL2.SDL.SDL_Rect usableBounds); | ||||||
|  |             _ = SDL2.SDL.SDL_GetDisplayBounds(i, out SDL2.SDL.SDL_Rect bounds); | ||||||
|  |             _ = SDL2.SDL.SDL_GetDisplayDPI(i, out float ddpi, out float hdpi, out float vdpi); | ||||||
|  |             ImGuiPlatformMonitorPtr monitor = platformIO.Monitors[i]; | ||||||
|  |             float standardDpi = 96f; // Standard DPI typically used | ||||||
|  |             monitor.DpiScale = hdpi / standardDpi; | ||||||
|  |             monitor.MainPos = new Vector2(bounds.x, bounds.y); | ||||||
|  |             monitor.MainSize = new Vector2(bounds.w, bounds.h); | ||||||
|  |             monitor.WorkPos = new Vector2(usableBounds.x, usableBounds.y); | ||||||
|  |             monitor.WorkSize = new Vector2(usableBounds.w, usableBounds.h); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void Render() | ||||||
|  |     { | ||||||
|  |         if (!frameBegun) | ||||||
|  |         { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         frameBegun = false; | ||||||
|  | 
 | ||||||
|  |         if ((ImGui.GetIO().ConfigFlags & ImGuiConfigFlags.ViewportsEnable) != 0) | ||||||
|  |         { | ||||||
|  |             ImGui.Render(); | ||||||
|  |             ImGui.UpdatePlatformWindows(); | ||||||
|  |             ImGuiPlatformIOPtr platformIO = ImGui.GetPlatformIO(); | ||||||
|  | 
 | ||||||
|  |             for (int i = 0; i < platformIO.Viewports.Size; i++) | ||||||
|  |             { | ||||||
|  |                 ImGuiViewportPtr vp = platformIO.Viewports[i]; | ||||||
|  |                 Window window = (Window)GCHandle.FromIntPtr(vp.PlatformUserData).Target; | ||||||
|  | 
 | ||||||
|  |                 if (!window.Claimed) | ||||||
|  |                 { | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 UpdateImGuiBuffers(vp.DrawData); | ||||||
|  | 
 | ||||||
|  |                 CommandBuffer commandBuffer = graphicsDevice.AcquireCommandBuffer(); | ||||||
|  |                 Texture swapchainTexture = commandBuffer.AcquireSwapchainTexture(window); | ||||||
|  | 
 | ||||||
|  |                 if (swapchainTexture != null) | ||||||
|  |                 { | ||||||
|  |                     RenderCommandLists(commandBuffer, swapchainTexture, vp.DrawData); | ||||||
|  |                     graphicsDevice.Submit(commandBuffer); | ||||||
|  |                     graphicsDevice.Wait(); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             ImGui.Render(); | ||||||
|  | 
 | ||||||
|  |             if (!mainWindow.Claimed) | ||||||
|  |             { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             ImDrawDataPtr drawDataPtr = ImGui.GetDrawData(); | ||||||
|  |             UpdateImGuiBuffers(drawDataPtr); | ||||||
|  | 
 | ||||||
|  |             CommandBuffer commandBuffer = graphicsDevice.AcquireCommandBuffer(); | ||||||
|  |             Texture swapchainTexture = commandBuffer.AcquireSwapchainTexture(mainWindow); | ||||||
|  | 
 | ||||||
|  |             if (swapchainTexture != null) | ||||||
|  |             { | ||||||
|  |                 RenderCommandLists(commandBuffer, swapchainTexture, drawDataPtr); | ||||||
|  |                 graphicsDevice.Submit(commandBuffer); | ||||||
|  |                 graphicsDevice.Wait(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private unsafe void UpdateImGuiBuffers(ImDrawDataPtr drawDataPtr) | ||||||
|  |     { | ||||||
|  |         if (drawDataPtr.TotalVtxCount == 0 || drawDataPtr.CmdListsCount == 0) | ||||||
|  |         { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (drawDataPtr.TotalVtxCount > vertexCount) | ||||||
|  |         { | ||||||
|  |             imGuiVertexBuffer?.Dispose(); | ||||||
|  | 
 | ||||||
|  |             vertexCount = (uint)(drawDataPtr.TotalVtxCount * 1.5f); | ||||||
|  |             imGuiVertexBuffer = Graphics.Buffer.Create<Position2DTextureColorVertex>( | ||||||
|  |                 graphicsDevice, | ||||||
|  |                 BufferUsageFlags.Vertex, | ||||||
|  |                 vertexCount | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (drawDataPtr.TotalIdxCount > indexCount) | ||||||
|  |         { | ||||||
|  |             imGuiIndexBuffer?.Dispose(); | ||||||
|  | 
 | ||||||
|  |             indexCount = (uint)(drawDataPtr.TotalIdxCount * 1.5f); | ||||||
|  |             imGuiIndexBuffer = Graphics.Buffer.Create<ushort>( | ||||||
|  |                 graphicsDevice, | ||||||
|  |                 BufferUsageFlags.Index, | ||||||
|  |                 indexCount | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         uint vertexOffset = 0; | ||||||
|  |         uint indexOffset = 0; | ||||||
|  | 
 | ||||||
|  |         for (int n = 0; n < drawDataPtr.CmdListsCount; n++) | ||||||
|  |         { | ||||||
|  |             ImDrawListPtr cmdList = drawDataPtr.CmdLists[n]; | ||||||
|  | 
 | ||||||
|  |             resourceUploader.SetBufferData( | ||||||
|  |                 imGuiVertexBuffer,  | ||||||
|  |                 vertexOffset,  | ||||||
|  |                 new Span<Position2DTextureColorVertex>(cmdList.VtxBuffer.Data.ToPointer(), cmdList.VtxBuffer.Size), | ||||||
|  |                 n == 0 | ||||||
|  |             ); | ||||||
|  | 
 | ||||||
|  |             resourceUploader.SetBufferData( | ||||||
|  |                 imGuiIndexBuffer, | ||||||
|  |                 indexOffset, | ||||||
|  |                 new Span<ushort>(cmdList.IdxBuffer.Data.ToPointer(), cmdList.IdxBuffer.Size), | ||||||
|  |                 n == 0 | ||||||
|  |             ); | ||||||
|  | 
 | ||||||
|  |             vertexOffset += (uint)cmdList.VtxBuffer.Size; | ||||||
|  |             indexOffset += (uint)cmdList.IdxBuffer.Size; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         resourceUploader.Upload(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void RenderCommandLists(CommandBuffer commandBuffer, Texture renderTexture, ImDrawDataPtr drawDataPtr) | ||||||
|  |     { | ||||||
|  |         Vector2 pos = drawDataPtr.DisplayPos; | ||||||
|  | 
 | ||||||
|  |         RenderPass renderPass = commandBuffer.BeginRenderPass( | ||||||
|  |             new ColorAttachmentInfo(renderTexture, false, clearColor) | ||||||
|  |         ); | ||||||
|  | 
 | ||||||
|  |         renderPass.BindGraphicsPipeline(imGuiPipeline); | ||||||
|  | 
 | ||||||
|  |         // It is possible that the buffers are null (for example nothing is in our main windows viewport, then we exixt early but still clear it). | ||||||
|  |         if (imGuiVertexBuffer == null || imGuiIndexBuffer == null) | ||||||
|  |         { | ||||||
|  |             commandBuffer.EndRenderPass(renderPass); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Matrix4x4 projectionMatrix = Matrix4x4.CreateOrthographicOffCenter( | ||||||
|  |             pos.X, | ||||||
|  |             pos.X + drawDataPtr.DisplaySize.X, | ||||||
|  |             pos.Y + drawDataPtr.DisplaySize.Y, | ||||||
|  |             pos.Y, | ||||||
|  |             -1.0f, | ||||||
|  |             1.0f | ||||||
|  |         ); | ||||||
|  |         TransformVertexUniform vertexUniform = new TransformVertexUniform(projectionMatrix); | ||||||
|  | 
 | ||||||
|  |         renderPass.BindVertexBuffer(imGuiVertexBuffer); | ||||||
|  |         renderPass.BindIndexBuffer(imGuiIndexBuffer, IndexElementSize.Sixteen); | ||||||
|  | 
 | ||||||
|  |         commandBuffer.PushVertexUniformData(in vertexUniform); | ||||||
|  | 
 | ||||||
|  |         uint vertexOffset = 0; | ||||||
|  |         uint indexOffset = 0; | ||||||
|  | 
 | ||||||
|  |         for (int n = 0; n < drawDataPtr.CmdListsCount; n++) | ||||||
|  |         { | ||||||
|  |             ImDrawListPtr cmdList = drawDataPtr.CmdLists[n]; | ||||||
|  | 
 | ||||||
|  |             for (int cmdIndex = 0; cmdIndex < cmdList.CmdBuffer.Size; cmdIndex++) | ||||||
|  |             { | ||||||
|  |                 ImDrawCmdPtr drawCmd = cmdList.CmdBuffer[cmdIndex]; | ||||||
|  | 
 | ||||||
|  |                 Texture texture = textureStorage.GetTexture(drawCmd.TextureId); | ||||||
|  | 
 | ||||||
|  |                 if (texture == null) | ||||||
|  |                 { | ||||||
|  |                     Log.Error("Texture or drawCmd.TextureId became null. Fit it!"); | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 renderPass.BindFragmentSampler(new TextureSamplerBinding(texture, imGuiSampler)); | ||||||
|  | 
 | ||||||
|  |                 float width = drawCmd.ClipRect.Z - (int)drawCmd.ClipRect.X; | ||||||
|  |                 float height = drawCmd.ClipRect.W - (int)drawCmd.ClipRect.Y; | ||||||
|  | 
 | ||||||
|  |                 if (width <= 0 || height <= 0) | ||||||
|  |                 { | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 renderPass.SetScissor( | ||||||
|  |                     new Rect( | ||||||
|  |                         (int)drawCmd.ClipRect.X - (int)pos.X, | ||||||
|  |                         (int)drawCmd.ClipRect.Y - (int)pos.Y, | ||||||
|  |                         (int)drawCmd.ClipRect.Z - (int)drawCmd.ClipRect.X, | ||||||
|  |                         (int)drawCmd.ClipRect.W - (int)drawCmd.ClipRect.Y | ||||||
|  |                     ) | ||||||
|  |                 ); | ||||||
|  | 
 | ||||||
|  |                 renderPass.DrawIndexedPrimitives(vertexOffset, indexOffset, drawCmd.ElemCount / 3); | ||||||
|  | 
 | ||||||
|  |                 indexOffset += drawCmd.ElemCount; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             vertexOffset += (uint)cmdList.VtxBuffer.Size; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         commandBuffer.EndRenderPass(renderPass); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private unsafe void BuildFontAtlas() | ||||||
|  |     { | ||||||
|  |         ResourceUploader resourceUploader = new ResourceUploader(graphicsDevice); | ||||||
|  | 
 | ||||||
|  |         ImGuiIOPtr io = ImGui.GetIO(); | ||||||
|  | 
 | ||||||
|  |         io.Fonts.GetTexDataAsRGBA32( | ||||||
|  |             out nint pixelData, | ||||||
|  |             out int width, | ||||||
|  |             out int height, | ||||||
|  |             out int bytesPerPixel | ||||||
|  |         ); | ||||||
|  | 
 | ||||||
|  |         Texture fontTexture = resourceUploader.CreateTexture2D( | ||||||
|  |             new Span<byte>((void*)pixelData, width * height * bytesPerPixel), | ||||||
|  |             (uint)width, | ||||||
|  |             (uint)height | ||||||
|  |         ); | ||||||
|  | 
 | ||||||
|  |         resourceUploader.Upload(); | ||||||
|  |         resourceUploader.Dispose(); | ||||||
|  | 
 | ||||||
|  |         io.Fonts.SetTexID(fontTexture.Handle); | ||||||
|  |         io.Fonts.ClearTexData(); | ||||||
|  | 
 | ||||||
|  |         textureStorage.Add(fontTexture);    // <-- The fontTexture seems to get lost after some time (CG?). | ||||||
|  |         this.fontTexture = fontTexture;     // <-- So we also keep a reference to make sure it doesn't happen. | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #region Window | ||||||
|  |     private void CreateWindow(ImGuiViewportPtr vp) | ||||||
|  |     { | ||||||
|  |         WindowCreateInfo info = new WindowCreateInfo("Window Title", (uint)vp.Pos.X, (uint)vp.Pos.Y, ScreenMode.Windowed); | ||||||
|  | 
 | ||||||
|  |         //SDL2.SDL.SDL_WindowFlags flags = graphicsDevice.WindowFlags; | ||||||
|  |         //flags |= SDL2.SDL.SDL_WindowFlags.SDL_WINDOW_HIDDEN; | ||||||
|  | 
 | ||||||
|  |         //if ((vp.Flags & ImGuiViewportFlags.NoTaskBarIcon) != 0) | ||||||
|  |         //{ | ||||||
|  |         //    flags |= SDL2.SDL.SDL_WindowFlags.SDL_WINDOW_SKIP_TASKBAR; | ||||||
|  |         //} | ||||||
|  | 
 | ||||||
|  |         //if ((vp.Flags & ImGuiViewportFlags.NoDecoration) != 0) | ||||||
|  |         //{ | ||||||
|  |         //    flags |= SDL2.SDL.SDL_WindowFlags.SDL_WINDOW_BORDERLESS; | ||||||
|  |         //    info.SystemResizable = false; | ||||||
|  |         //} | ||||||
|  |         //else | ||||||
|  |         //{ | ||||||
|  |         //    flags |= SDL2.SDL.SDL_WindowFlags.SDL_WINDOW_RESIZABLE; | ||||||
|  |         //    info.SystemResizable = true; | ||||||
|  |         //} | ||||||
|  | 
 | ||||||
|  |         //if ((vp.Flags & ImGuiViewportFlags.TopMost) != 0) | ||||||
|  |         //{ | ||||||
|  |         //    flags |= SDL2.SDL.SDL_WindowFlags.SDL_WINDOW_ALWAYS_ON_TOP; | ||||||
|  |         //} | ||||||
|  | 
 | ||||||
|  |         Window window = new Window(graphicsDevice, info); | ||||||
|  |         graphicsDevice.ClaimWindow(window, SwapchainComposition.SDR, PresentMode.Immediate); | ||||||
|  | 
 | ||||||
|  |         GCHandle handle = GCHandle.Alloc(window); | ||||||
|  |         vp.PlatformUserData = (IntPtr)handle; | ||||||
|  | 
 | ||||||
|  |         windows.Add(window, handle); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void DestroyWindow(ImGuiViewportPtr vp) | ||||||
|  |     { | ||||||
|  |         if (vp.PlatformUserData == IntPtr.Zero) return; | ||||||
|  | 
 | ||||||
|  |         Window window = (Window)GCHandle.FromIntPtr(vp.PlatformUserData).Target; | ||||||
|  |         graphicsDevice.UnclaimWindow(window); | ||||||
|  | 
 | ||||||
|  |         if (windows.TryGetValue(window, out GCHandle handle)) | ||||||
|  |         { | ||||||
|  |             handle.Free(); | ||||||
|  |             windows.Remove(window); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         graphicsDevice.Wait(); | ||||||
|  |         window.Dispose(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void ShowWindow(ImGuiViewportPtr vp) | ||||||
|  |     { | ||||||
|  |         if (vp.PlatformUserData == IntPtr.Zero) return; | ||||||
|  | 
 | ||||||
|  |         Window window = (Window)GCHandle.FromIntPtr(vp.PlatformUserData).Target; | ||||||
|  |         SDL2.SDL.SDL_ShowWindow(window.Handle); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private unsafe void GetWindowPos(ImGuiViewportPtr vp, Vector2* outPos) | ||||||
|  |     { | ||||||
|  |         if (vp.PlatformUserData == IntPtr.Zero) return; | ||||||
|  | 
 | ||||||
|  |         Window window = (Window)GCHandle.FromIntPtr(vp.PlatformUserData).Target; | ||||||
|  |         SDL2.SDL.SDL_GetWindowPosition(window.Handle, out int x, out int y); | ||||||
|  |         *outPos = new Vector2(x, y); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void SetWindowPos(ImGuiViewportPtr vp, Vector2 pos) | ||||||
|  |     { | ||||||
|  |         if (vp.PlatformUserData == IntPtr.Zero) return; | ||||||
|  | 
 | ||||||
|  |         Window window = (Window)GCHandle.FromIntPtr(vp.PlatformUserData).Target; | ||||||
|  |         SDL2.SDL.SDL_SetWindowPosition(window.Handle, (int)pos.X, (int)pos.Y); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void SetWindowSize(ImGuiViewportPtr vp, Vector2 size) | ||||||
|  |     { | ||||||
|  |         if (vp.PlatformUserData == IntPtr.Zero) return; | ||||||
|  | 
 | ||||||
|  |         Window window = (Window)GCHandle.FromIntPtr(vp.PlatformUserData).Target; | ||||||
|  |         SDL2.SDL.SDL_SetWindowSize(window.Handle, (int)size.X, (int)size.Y); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private unsafe void GetWindowSize(ImGuiViewportPtr vp, Vector2* outSize) | ||||||
|  |     { | ||||||
|  |         if (vp.PlatformUserData == IntPtr.Zero) return; | ||||||
|  | 
 | ||||||
|  |         Window window = (Window)GCHandle.FromIntPtr(vp.PlatformUserData).Target; | ||||||
|  |         SDL2.SDL.SDL_GetWindowSize(window.Handle, out int w, out int h); | ||||||
|  |         *outSize = new Vector2(w, h); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void SetWindowFocus(ImGuiViewportPtr vp) | ||||||
|  |     { | ||||||
|  |         if (vp.PlatformUserData == IntPtr.Zero) return; | ||||||
|  | 
 | ||||||
|  |         Window window = (Window)GCHandle.FromIntPtr(vp.PlatformUserData).Target; | ||||||
|  |         //SDL2.SDL.SDL_SetWindowInputFocus(window.Handle); | ||||||
|  |         SDL2.SDL.SDL_RaiseWindow(window.Handle); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private byte GetWindowFocus(ImGuiViewportPtr vp) | ||||||
|  |     { | ||||||
|  |         if (vp.PlatformUserData == IntPtr.Zero) return (byte)0; | ||||||
|  | 
 | ||||||
|  |         Window window = (Window)GCHandle.FromIntPtr(vp.PlatformUserData).Target; | ||||||
|  |         SDL2.SDL.SDL_WindowFlags flags = (SDL2.SDL.SDL_WindowFlags)SDL2.SDL.SDL_GetWindowFlags(window.Handle); | ||||||
|  |         return (flags & SDL2.SDL.SDL_WindowFlags.SDL_WINDOW_INPUT_FOCUS) != 0 ? (byte)1 : (byte)0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private byte GetWindowMinimized(ImGuiViewportPtr vp) | ||||||
|  |     { | ||||||
|  |         if (vp.PlatformUserData == IntPtr.Zero) return (byte)0; | ||||||
|  | 
 | ||||||
|  |         Window window = (Window)GCHandle.FromIntPtr(vp.PlatformUserData).Target; | ||||||
|  |         SDL2.SDL.SDL_WindowFlags flags = (SDL2.SDL.SDL_WindowFlags)SDL2.SDL.SDL_GetWindowFlags(window.Handle); | ||||||
|  |         return (flags & SDL2.SDL.SDL_WindowFlags.SDL_WINDOW_MINIMIZED) != 0 ? (byte)1 : (byte)0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private unsafe void SetWindowTitle(ImGuiViewportPtr vp, IntPtr title) | ||||||
|  |     { | ||||||
|  |         if (vp.PlatformUserData == IntPtr.Zero) return; | ||||||
|  | 
 | ||||||
|  |         Window window = (Window)GCHandle.FromIntPtr(vp.PlatformUserData).Target; | ||||||
|  |         byte* titlePtr = (byte*)title; | ||||||
|  |         int count = 0; | ||||||
|  |         while (titlePtr[count] != 0) | ||||||
|  |         { | ||||||
|  |             count += 1; | ||||||
|  |         } | ||||||
|  |         SDL2.SDL.SDL_SetWindowTitle(window.Handle, System.Text.Encoding.ASCII.GetString(titlePtr, count)); | ||||||
|  |     } | ||||||
|  |     #endregion | ||||||
|  | 
 | ||||||
|  |     public void Dispose() | ||||||
|  |     { | ||||||
|  |         fontTexture?.Dispose(); | ||||||
|  |         imGuiVertexBuffer?.Dispose(); | ||||||
|  |         imGuiIndexBuffer?.Dispose(); | ||||||
|  |         imGuiFragmentShader?.Dispose(); | ||||||
|  |         imGuiVertexShader?.Dispose(); | ||||||
|  |         imGuiPipeline?.Dispose(); | ||||||
|  |         imGuiSampler?.Dispose(); | ||||||
|  |         resourceUploader?.Dispose(); | ||||||
|  | 
 | ||||||
|  |         foreach (KeyValuePair<Window, GCHandle> window in windows) | ||||||
|  |         { | ||||||
|  |             graphicsDevice.UnclaimWindow(window.Key); | ||||||
|  |             window.Key.Dispose(); | ||||||
|  |             window.Value.Free(); | ||||||
|  |         } | ||||||
|  |         windows.Clear(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										2
									
								
								Nerfed.Runtime/Gui/Shaders/generate-spirv.bat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								Nerfed.Runtime/Gui/Shaders/generate-spirv.bat
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | glslangvalidator -V imgui-vertex.glsl -o imgui-vertex.spv -S vert | ||||||
|  | glslangvalidator -V imgui-frag.glsl -o imgui-frag.spv -S frag | ||||||
							
								
								
									
										13
									
								
								Nerfed.Runtime/Gui/Shaders/imgui-frag.glsl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								Nerfed.Runtime/Gui/Shaders/imgui-frag.glsl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | #version 450 | ||||||
|  |  | ||||||
|  | layout (location = 0) in vec4 color; | ||||||
|  | layout (location = 1) in vec2 texCoord; | ||||||
|  |  | ||||||
|  | layout(set = 2, binding = 0) uniform sampler2D Sampler; | ||||||
|  |  | ||||||
|  | layout (location = 0) out vec4 outputColor; | ||||||
|  |  | ||||||
|  | void main() | ||||||
|  | { | ||||||
|  |     outputColor = color * texture(Sampler, texCoord); | ||||||
|  | } | ||||||
							
								
								
									
										
											BIN
										
									
								
								Nerfed.Runtime/Gui/Shaders/imgui-frag.spv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Nerfed.Runtime/Gui/Shaders/imgui-frag.spv
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										20
									
								
								Nerfed.Runtime/Gui/Shaders/imgui-vertex.glsl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								Nerfed.Runtime/Gui/Shaders/imgui-vertex.glsl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | #version 450 | ||||||
|  |  | ||||||
|  | layout (location = 0) in vec2 in_position; | ||||||
|  | layout (location = 1) in vec2 in_texCoord; | ||||||
|  | layout (location = 2) in vec4 in_color; | ||||||
|  |  | ||||||
|  | layout (set = 1, binding = 0) uniform ProjectionMatrixBuffer | ||||||
|  | { | ||||||
|  |     mat4 projection_matrix; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | layout (location = 0) out vec4 color; | ||||||
|  | layout (location = 1) out vec2 texCoord; | ||||||
|  |  | ||||||
|  | void main()  | ||||||
|  | { | ||||||
|  |     gl_Position = projection_matrix * vec4(in_position, 0, 1); | ||||||
|  |     color = in_color; | ||||||
|  |     texCoord = in_texCoord; | ||||||
|  | } | ||||||
							
								
								
									
										
											BIN
										
									
								
								Nerfed.Runtime/Gui/Shaders/imgui-vertex.spv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Nerfed.Runtime/Gui/Shaders/imgui-vertex.spv
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										49
									
								
								Nerfed.Runtime/Gui/Structs.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								Nerfed.Runtime/Gui/Structs.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | |||||||
|  | using Nerfed.Runtime.Graphics; | ||||||
|  | using System.Numerics; | ||||||
|  | using System.Runtime.InteropServices; | ||||||
|  | 
 | ||||||
|  | namespace Nerfed.Runtime.Gui; | ||||||
|  | 
 | ||||||
|  | [StructLayout(LayoutKind.Sequential)] | ||||||
|  | public struct Position2DTextureColorVertex : IVertexType | ||||||
|  | { | ||||||
|  |     public Vector2 Position; | ||||||
|  |     public Vector2 TexCoord; | ||||||
|  |     public Color Color; | ||||||
|  | 
 | ||||||
|  |     public Position2DTextureColorVertex( | ||||||
|  |         Vector2 position, | ||||||
|  |         Vector2 texcoord, | ||||||
|  |         Color color | ||||||
|  |     ) | ||||||
|  |     { | ||||||
|  |         Position = position; | ||||||
|  |         TexCoord = texcoord; | ||||||
|  |         Color = color; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static VertexElementFormat[] Formats { get; } = new VertexElementFormat[3] | ||||||
|  |     { | ||||||
|  |         VertexElementFormat.Vector2, | ||||||
|  |         VertexElementFormat.Vector2, | ||||||
|  |         VertexElementFormat.Color | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     public static uint[] Offsets => new uint[3] | ||||||
|  |     { | ||||||
|  |         0, | ||||||
|  |         8, | ||||||
|  |         16 | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | [StructLayout(LayoutKind.Sequential)] | ||||||
|  | public struct TransformVertexUniform | ||||||
|  | { | ||||||
|  |     public Matrix4x4 ProjectionMatrix; | ||||||
|  | 
 | ||||||
|  |     public TransformVertexUniform(Matrix4x4 projectionMatrix) | ||||||
|  |     { | ||||||
|  |         ProjectionMatrix = projectionMatrix; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										35
									
								
								Nerfed.Runtime/Gui/TextureStorage.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								Nerfed.Runtime/Gui/TextureStorage.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | using Nerfed.Runtime.Graphics; | ||||||
|  | 
 | ||||||
|  | namespace Nerfed.Runtime.Gui; | ||||||
|  | 
 | ||||||
|  | public class TextureStorage | ||||||
|  | { | ||||||
|  |     private readonly Dictionary<IntPtr, WeakReference<Texture>> pointerToTexture = new Dictionary<IntPtr, WeakReference<Texture>>(); | ||||||
|  | 
 | ||||||
|  |     public IntPtr Add(Texture texture) | ||||||
|  |     { | ||||||
|  |         if (!pointerToTexture.ContainsKey(texture.Handle)) | ||||||
|  |         { | ||||||
|  |             pointerToTexture.Add(texture.Handle, new WeakReference<Texture>(texture)); | ||||||
|  |         } | ||||||
|  |         return texture.Handle; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Texture GetTexture(IntPtr pointer) | ||||||
|  |     { | ||||||
|  |         if (!pointerToTexture.ContainsKey(pointer)) | ||||||
|  |         { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         WeakReference<Texture> result = pointerToTexture[pointer]; | ||||||
|  | 
 | ||||||
|  |         if (!result.TryGetTarget(out Texture texture)) | ||||||
|  |         { | ||||||
|  |             pointerToTexture.Remove(pointer); | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return texture; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								Nerfed.Runtime/Libraries/ImGui.NET
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								Nerfed.Runtime/Libraries/ImGui.NET
									
									
									
									
									
										Submodule
									
								
							 Submodule Nerfed.Runtime/Libraries/ImGui.NET added at ae493d92a3
									
								
							| @@ -12,6 +12,16 @@ | |||||||
|         <Compile Include="Libraries\dav1dfile\csharp\dav1dfile.cs" /> |         <Compile Include="Libraries\dav1dfile\csharp\dav1dfile.cs" /> | ||||||
|     </ItemGroup> |     </ItemGroup> | ||||||
|  |  | ||||||
|  |     <ItemGroup> | ||||||
|  |       <ProjectReference Include="Libraries\ImGui.NET\src\ImGui.NET\ImGui.NET.csproj" /> | ||||||
|  |     </ItemGroup> | ||||||
|  |  | ||||||
|  |     <ItemGroup> | ||||||
|  |         <Content Include="Assets\**\*.*"> | ||||||
|  |             <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||||||
|  |         </Content> | ||||||
|  |     </ItemGroup> | ||||||
|  |  | ||||||
|     <PropertyGroup> |     <PropertyGroup> | ||||||
|         <OutputType>Exe</OutputType> |         <OutputType>Exe</OutputType> | ||||||
|         <TargetFramework>net8.0</TargetFramework> |         <TargetFramework>net8.0</TargetFramework> | ||||||
|   | |||||||
| @@ -5,6 +5,8 @@ VisualStudioVersion = 17.10.35013.160 | |||||||
| MinimumVisualStudioVersion = 10.0.40219.1 | MinimumVisualStudioVersion = 10.0.40219.1 | ||||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerfed.Runtime", "Nerfed.Runtime\Nerfed.Runtime.csproj", "{98E09BAF-587F-4238-89BD-7693C036C233}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerfed.Runtime", "Nerfed.Runtime\Nerfed.Runtime.csproj", "{98E09BAF-587F-4238-89BD-7693C036C233}" | ||||||
| EndProject | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImGui.NET", "Nerfed.Runtime\Libraries\ImGui.NET\src\ImGui.NET\ImGui.NET.csproj", "{4EC3C399-4E09-4A36-B11E-391F0792C1C8}" | ||||||
|  | EndProject | ||||||
| Global | Global | ||||||
| 	GlobalSection(SolutionConfigurationPlatforms) = preSolution | 	GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||||
| 		Debug|Any CPU = Debug|Any CPU | 		Debug|Any CPU = Debug|Any CPU | ||||||
| @@ -15,6 +17,10 @@ Global | |||||||
| 		{98E09BAF-587F-4238-89BD-7693C036C233}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{98E09BAF-587F-4238-89BD-7693C036C233}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{98E09BAF-587F-4238-89BD-7693C036C233}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{98E09BAF-587F-4238-89BD-7693C036C233}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{98E09BAF-587F-4238-89BD-7693C036C233}.Release|Any CPU.Build.0 = Release|Any CPU | 		{98E09BAF-587F-4238-89BD-7693C036C233}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
|  | 		{4EC3C399-4E09-4A36-B11E-391F0792C1C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
|  | 		{4EC3C399-4E09-4A36-B11E-391F0792C1C8}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
|  | 		{4EC3C399-4E09-4A36-B11E-391F0792C1C8}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
|  | 		{4EC3C399-4E09-4A36-B11E-391F0792C1C8}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 	EndGlobalSection | 	EndGlobalSection | ||||||
| 	GlobalSection(SolutionProperties) = preSolution | 	GlobalSection(SolutionProperties) = preSolution | ||||||
| 		HideSolutionNode = FALSE | 		HideSolutionNode = FALSE | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								libs/x64/cimgui.dll
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								libs/x64/cimgui.dll
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
		Reference in New Issue
	
	Block a user