diff --git a/Nerfed.Runtime/Engine.cs b/Nerfed.Runtime/Engine.cs index da76aa9..1ebede4 100644 --- a/Nerfed.Runtime/Engine.cs +++ b/Nerfed.Runtime/Engine.cs @@ -65,7 +65,7 @@ internal static void Run(string[] args) } MainWindow.OnCloseEvent += (w) => { - quit = true; + Quit(); }; AudioDevice = new AudioDevice(); diff --git a/Nerfed.Runtime/Gui/GuiController.cs b/Nerfed.Runtime/Gui/GuiController.cs index f8e36ff..ae610c9 100644 --- a/Nerfed.Runtime/Gui/GuiController.cs +++ b/Nerfed.Runtime/Gui/GuiController.cs @@ -37,8 +37,7 @@ internal class GuiController : IDisposable private readonly Shader imGuiFragmentShader; private readonly Sampler imGuiSampler; private readonly GuiTextureStorage textureStorage = new GuiTextureStorage(); - private readonly Dictionary windowToHandle = new Dictionary(16); - private readonly Dictionary imguiToWindow = new Dictionary(16); + private readonly GuiViewportWindow mainViewportWindow; private Texture fontTexture = null; private uint vertexCount = 0; @@ -49,6 +48,7 @@ internal class GuiController : IDisposable public GuiController(GraphicsDevice graphicsDevice, Window mainWindow, Color clearColor, ImGuiConfigFlags configFlags = ImGuiConfigFlags.NavEnableKeyboard | ImGuiConfigFlags.DockingEnable | ImGuiConfigFlags.ViewportsEnable) { + this.graphicsDevice = graphicsDevice; this.mainWindow = mainWindow; this.clearColor = clearColor; @@ -110,9 +110,7 @@ public GuiController(GraphicsDevice graphicsDevice, Window mainWindow, Color cle ImGuiPlatformIOPtr platformIO = ImGui.GetPlatformIO(); ImGuiViewportPtr mainViewport = platformIO.Viewports[0]; mainViewport.PlatformHandle = mainWindow.Handle; - GCHandle handle = GCHandle.Alloc(mainWindow); - mainViewport.PlatformUserData = (IntPtr)handle; - AddWindow(mainWindow, mainViewport, handle); + mainViewportWindow = new GuiViewportWindow(graphicsDevice, mainViewport, mainWindow); unsafe { @@ -177,7 +175,7 @@ private void UpdatePerFrameImGuiData(float deltaSeconds) io.DeltaTime = deltaSeconds; // DeltaTime is in seconds. } - private void UpdateInput() + private static void UpdateInput() { ImGuiIOPtr io = ImGui.GetIO(); @@ -242,7 +240,7 @@ private void UpdateInput() } } - private void UpdateCursor() + private static void UpdateCursor() { ImGuiIOPtr io = ImGui.GetIO(); @@ -255,7 +253,7 @@ private void UpdateCursor() if (imGuiCursor == ImGuiMouseCursor.None || io.MouseDrawCursor) { - SDL2.SDL.SDL_ShowCursor(0); + _ = SDL2.SDL.SDL_ShowCursor(0); } else { @@ -273,7 +271,7 @@ private void UpdateCursor() _ => SDL2.SDL.SDL_CreateSystemCursor(SDL2.SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_ARROW), }; SDL2.SDL.SDL_SetCursor(sdlCursor); - SDL2.SDL.SDL_ShowCursor(1); + _ = SDL2.SDL.SDL_ShowCursor(1); } } @@ -318,9 +316,9 @@ public void Render() for (int i = 0; i < platformIO.Viewports.Size; i++) { ImGuiViewportPtr vp = platformIO.Viewports[i]; - Window window = (Window)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + GuiViewportWindow window = (GuiViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target; - if (!window.Claimed) + if (!window.Window.Claimed) { continue; } @@ -328,7 +326,7 @@ public void Render() UpdateImGuiBuffers(vp.DrawData); CommandBuffer commandBuffer = graphicsDevice.AcquireCommandBuffer(); - Texture swapchainTexture = commandBuffer.AcquireSwapchainTexture(window); + Texture swapchainTexture = commandBuffer.AcquireSwapchainTexture(window.Window); if (swapchainTexture != null) { @@ -357,7 +355,7 @@ public void Render() { RenderCommandLists(commandBuffer, swapchainTexture, drawDataPtr); graphicsDevice.Submit(commandBuffer); - graphicsDevice.Wait(); + //graphicsDevice.Wait(); } } } @@ -534,80 +532,33 @@ out int bytesPerPixel #region Window private void CreateWindow(ImGuiViewportPtr vp) { - // TODO: Handle all flags. - ScreenMode screenMode = vp.Flags.HasFlag(ImGuiViewportFlags.NoDecoration) ? ScreenMode.WindowedBorderless : ScreenMode.Windowed; - bool systemResizable = !vp.Flags.HasFlag(ImGuiViewportFlags.NoDecoration); - - WindowCreateInfo info = new WindowCreateInfo("Window Title", (uint)vp.Pos.X, (uint)vp.Pos.Y, screenMode, systemResizable, false); - - Window window = new Window(graphicsDevice, info); - graphicsDevice.ClaimWindow(window, SwapchainComposition.SDR, PresentMode.Immediate); // What PresentMode do we need? - - GCHandle handle = GCHandle.Alloc(window); - vp.PlatformUserData = (IntPtr)handle; - - AddWindow(window, vp, handle); + GuiViewportWindow window = new GuiViewportWindow(graphicsDevice, vp); } private void DestroyWindow(ImGuiViewportPtr vp) { - //Window window = (Window)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + if (vp.PlatformUserData == IntPtr.Zero) return; - if(imguiToWindow.TryGetValue(vp, out Window window)) - { - graphicsDevice.UnclaimWindow(window); + GuiViewportWindow window = (GuiViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + window.Dispose(); - if (windowToHandle.TryGetValue(window, out GCHandle handle)) - { - handle.Free(); - windowToHandle.Remove(window); - } - - imguiToWindow.Remove(vp); - window.Dispose(); - } - } - - private void AddWindow(Window window, ImGuiViewportPtr vp, GCHandle handle) - { - window.OnResizedEvent += ((win, w, h) => { - vp.PlatformRequestResize = true; - }); - - window.OnMovedEvent += ((win, x, y) => - { - vp.PlatformRequestMove = true; - }); - - window.OnCloseEvent += (win) => - { - ImGuiPlatformIOPtr platformIO = ImGui.GetPlatformIO(); - - for (int i = 0; i < platformIO.Viewports.Capacity; i++) - { - ImGuiViewportPtr vp = platformIO.Viewports[i]; - DestroyWindow(vp); - } - }; - - windowToHandle.Add(window, handle); - imguiToWindow.Add(vp, window); + vp.PlatformUserData = IntPtr.Zero; } 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); + GuiViewportWindow window = (GuiViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + SDL2.SDL.SDL_ShowWindow(window.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); + GuiViewportWindow window = (GuiViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + SDL2.SDL.SDL_GetWindowPosition(window.Window.Handle, out int x, out int y); *outPos = new Vector2(x, y); } @@ -615,24 +566,24 @@ 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); + GuiViewportWindow window = (GuiViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + SDL2.SDL.SDL_SetWindowPosition(window.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); + GuiViewportWindow window = (GuiViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + SDL2.SDL.SDL_SetWindowSize(window.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); + GuiViewportWindow window = (GuiViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + SDL2.SDL.SDL_GetWindowSize(window.Window.Handle, out int w, out int h); *outSize = new Vector2(w, h); } @@ -640,26 +591,28 @@ private void SetWindowFocus(ImGuiViewportPtr vp) { if (vp.PlatformUserData == IntPtr.Zero) return; - Window window = (Window)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + GuiViewportWindow window = (GuiViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target; //SDL2.SDL.SDL_SetWindowInputFocus(window.Handle); - SDL2.SDL.SDL_RaiseWindow(window.Handle); + SDL2.SDL.SDL_RaiseWindow(window.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); + GuiViewportWindow window = (GuiViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + SDL2.SDL.SDL_WindowFlags flags = (SDL2.SDL.SDL_WindowFlags)SDL2.SDL.SDL_GetWindowFlags(window.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; + if (vp.PlatformUserData == IntPtr.Zero) return 0; + + GuiViewportWindow window = (GuiViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + SDL2.SDL.SDL_WindowFlags flags = (SDL2.SDL.SDL_WindowFlags)SDL2.SDL.SDL_GetWindowFlags(window.Window.Handle); - 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; } @@ -667,14 +620,14 @@ private unsafe void SetWindowTitle(ImGuiViewportPtr vp, IntPtr title) { if (vp.PlatformUserData == IntPtr.Zero) return; - Window window = (Window)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + GuiViewportWindow window = (GuiViewportWindow)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)); + SDL2.SDL.SDL_SetWindowTitle(window.Window.Handle, System.Text.Encoding.ASCII.GetString(titlePtr, count)); } #endregion @@ -688,16 +641,5 @@ public void Dispose() imGuiPipeline?.Dispose(); imGuiSampler?.Dispose(); resourceUploader?.Dispose(); - - foreach (KeyValuePair window in windowToHandle) - { - if (window.Key == mainWindow) continue; - - graphicsDevice.UnclaimWindow(window.Key); - window.Key.Dispose(); - window.Value.Free(); - } - windowToHandle.Clear(); - imguiToWindow.Clear(); } } \ No newline at end of file diff --git a/Nerfed.Runtime/Gui/GuiViewportWindow.cs b/Nerfed.Runtime/Gui/GuiViewportWindow.cs new file mode 100644 index 0000000..92abb2d --- /dev/null +++ b/Nerfed.Runtime/Gui/GuiViewportWindow.cs @@ -0,0 +1,87 @@ +using ImGuiNET; +using Nerfed.Runtime.Graphics; +using System.Runtime.InteropServices; + +namespace Nerfed.Runtime.Gui +{ + internal class GuiViewportWindow + { + private readonly GCHandle gcHandle; + private readonly GraphicsDevice gd; + private readonly ImGuiViewportPtr vp; + private readonly Window window; + + public Window Window => window; + + public GuiViewportWindow(GraphicsDevice gd, ImGuiViewportPtr vp, Window window) + { + this.gd = gd; + this.vp = vp; + this.window = window; + + gcHandle = GCHandle.Alloc(this); + + if (!window.Claimed) + { + gd.ClaimWindow(window, SwapchainComposition.SDR, PresentMode.Immediate); // What PresentMode do we need? + } + + vp.PlatformUserData = (IntPtr)gcHandle; + } + + public GuiViewportWindow(GraphicsDevice gd, ImGuiViewportPtr vp) + { + this.gd = gd; + this.vp = vp; + + gcHandle = GCHandle.Alloc(this); + + // TODO: Handle all flags. + ScreenMode screenMode = ScreenMode.Windowed; + bool systemResizable = true; + + if ((vp.Flags & ImGuiViewportFlags.NoDecoration) == ImGuiViewportFlags.NoDecoration) + { + screenMode = ScreenMode.WindowedBorderless; + systemResizable = false; + } + + WindowCreateInfo info = new WindowCreateInfo("Window Title", (uint)vp.Pos.X, (uint)vp.Pos.Y, screenMode, systemResizable, false); + + window = new Window(gd, info); + gd.ClaimWindow(window, SwapchainComposition.SDR, PresentMode.Immediate); // What PresentMode do we need? + + window.OnMovedEvent += HandleOnMovedEvent; + window.OnResizedEvent += HandleOnResizedEvent; + window.OnCloseEvent += HandleOnCloseEvent; + + vp.PlatformUserData = (IntPtr)gcHandle; + } + + public void Dispose() + { + window.OnMovedEvent -= HandleOnMovedEvent; + window.OnResizedEvent -= HandleOnResizedEvent; + window.OnCloseEvent -= HandleOnCloseEvent; + + gd.UnclaimWindow(window); + window.Dispose(); + gcHandle.Free(); + } + + private void HandleOnMovedEvent(Window window, int x, int y) + { + vp.PlatformRequestMove = true; + } + + private void HandleOnResizedEvent(Window window, uint w, uint h) + { + vp.PlatformRequestResize = true; + } + + private void HandleOnCloseEvent(Window window) + { + vp.PlatformRequestClose = true; + } + } +} \ No newline at end of file