From 1e1ed303add45dae3d4f2ede4fd2e9a752421f32 Mon Sep 17 00:00:00 2001 From: max Date: Fri, 5 Jul 2024 21:56:14 +0200 Subject: [PATCH 01/11] Added ImGui.NET Start working on controller. --- .gitmodules | 3 + Nerfed.Runtime/Assets/Shaders/imgui-frag.spv | Bin 0 -> 664 bytes .../Assets/Shaders/imgui-vertex.spv | Bin 0 -> 1440 bytes Nerfed.Runtime/Engine.cs | 12 +- Nerfed.Runtime/Gui/Clipboard.cs | 48 ++ Nerfed.Runtime/Gui/Controller.cs | 661 ++++++++++++++++++ Nerfed.Runtime/Gui/Shaders/generate-spirv.bat | 2 + Nerfed.Runtime/Gui/Shaders/imgui-frag.glsl | 13 + Nerfed.Runtime/Gui/Shaders/imgui-frag.spv | Bin 0 -> 664 bytes Nerfed.Runtime/Gui/Shaders/imgui-vertex.glsl | 20 + Nerfed.Runtime/Gui/Shaders/imgui-vertex.spv | Bin 0 -> 1440 bytes Nerfed.Runtime/Gui/Structs.cs | 49 ++ Nerfed.Runtime/Gui/TextureStorage.cs | 35 + Nerfed.Runtime/Libraries/ImGui.NET | 1 + Nerfed.Runtime/Nerfed.Runtime.csproj | 10 + Nerfed.sln | 6 + libs/x64/cimgui.dll | 3 + 17 files changed, 862 insertions(+), 1 deletion(-) create mode 100644 Nerfed.Runtime/Assets/Shaders/imgui-frag.spv create mode 100644 Nerfed.Runtime/Assets/Shaders/imgui-vertex.spv create mode 100644 Nerfed.Runtime/Gui/Clipboard.cs create mode 100644 Nerfed.Runtime/Gui/Controller.cs create mode 100644 Nerfed.Runtime/Gui/Shaders/generate-spirv.bat create mode 100644 Nerfed.Runtime/Gui/Shaders/imgui-frag.glsl create mode 100644 Nerfed.Runtime/Gui/Shaders/imgui-frag.spv create mode 100644 Nerfed.Runtime/Gui/Shaders/imgui-vertex.glsl create mode 100644 Nerfed.Runtime/Gui/Shaders/imgui-vertex.spv create mode 100644 Nerfed.Runtime/Gui/Structs.cs create mode 100644 Nerfed.Runtime/Gui/TextureStorage.cs create mode 160000 Nerfed.Runtime/Libraries/ImGui.NET create mode 100644 libs/x64/cimgui.dll diff --git a/.gitmodules b/.gitmodules index 110dc50..63fa691 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,6 @@ [submodule "Nerfed.Runtime/Libraries/dav1dfile"] path = Nerfed.Runtime/Libraries/dav1dfile 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 diff --git a/Nerfed.Runtime/Assets/Shaders/imgui-frag.spv b/Nerfed.Runtime/Assets/Shaders/imgui-frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..550f9a08131507837953b6970d98bb906d49c1c9 GIT binary patch literal 664 zcmYk2y-osA5QVR-izv#EC}>O!NKY)(m>6v+Xy_=ciBOn;OK?ei0bk6gvN7@dc9(>k z%+5V$&YU~5QK^3r!d|F`O1KF5X@(L^fGcNtG@gtHpXqFHcYmv*7NSh3rcU2J*;r2B zKP(&)RpN|jptZ&$+#;Mq_@Oa|-R+5C>`ON3YLgC=MY7H``n+W*?`eQ1)8%S0w;pG2 zr1P&~lB{Qx!U$J=t_2*i9=lkN8^T$vi+hAe?A+?zuZ2ooFPlE^X>%{bb%_pocN4o$ zmv4paACiA6urtY7KO*bBt&5#e?vm+G$oh$Q&lX?dRHL9yzj`5(^F6UUd7ST*te<f3}G`R{`3aM#D$ O3$OTpDW7}yxh@@(>*Im<@s7zH_1x)sYf>Kj$;4LuRi^J zkW;SYs1=+Dm6+Ng#X+8rPjE|2E#b}JL(u9Ke6wmrta?XZIE09)i##=mn7){A(k7!X z?+`>CTnQ#W#`f=;$M~4SP0SkdtkI^1TI^!>5#uJl%UFHtWmLu1o{!bWIM!1a<5*8k zV!RGZUXvc2OMeq@k-dR!ai4t}JMRYn%j^xzwKt8g;9Gx(_$s@6u{xgm#2V(b2E6O+ zQOmc}*l$YAdsa$bRo8orS25Q%vD#VJzUrJ(LosXLVs{oXYa6SpnEBgNU%oSLvDvu42NF#GV#V@xf~shM%?@j1S8n^O { + ImGuiNET.ImGui.ShowDemoWindow(); + }; + while (!quit) { Tick(); } + Controller.Dispose(); GraphicsDevice.UnclaimWindow(MainWindow); MainWindow.Dispose(); GraphicsDevice.Dispose(); @@ -145,6 +153,7 @@ private static void Tick() ProcessSDLEvents(); + Controller.Update((float)Timestep.TotalSeconds); // Tick game here... AudioDevice.WakeThread(); @@ -154,6 +163,7 @@ private static void Tick() double alpha = accumulatedUpdateTime / Timestep; // Render here.. + Controller.Render(); accumulatedDrawTime -= framerateCapTimeSpan; } diff --git a/Nerfed.Runtime/Gui/Clipboard.cs b/Nerfed.Runtime/Gui/Clipboard.cs new file mode 100644 index 0000000..ddb883f --- /dev/null +++ b/Nerfed.Runtime/Gui/Clipboard.cs @@ -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 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(bytes, length)); + bytes[length] = 0; + return bytes; + } + + // Stops the delegate pointer from being collected + private static IntPtr GetPointerTo(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); +} \ No newline at end of file diff --git a/Nerfed.Runtime/Gui/Controller.cs b/Nerfed.Runtime/Gui/Controller.cs new file mode 100644 index 0000000..6d4990d --- /dev/null +++ b/Nerfed.Runtime/Gui/Controller.cs @@ -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 windows = new Dictionary(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(), + 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 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() * 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( + graphicsDevice, + BufferUsageFlags.Vertex, + vertexCount + ); + } + + if (drawDataPtr.TotalIdxCount > indexCount) + { + imGuiIndexBuffer?.Dispose(); + + indexCount = (uint)(drawDataPtr.TotalIdxCount * 1.5f); + imGuiIndexBuffer = Graphics.Buffer.Create( + 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(cmdList.VtxBuffer.Data.ToPointer(), cmdList.VtxBuffer.Size), + n == 0 + ); + + resourceUploader.SetBufferData( + imGuiIndexBuffer, + indexOffset, + new Span(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((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 in windows) + { + graphicsDevice.UnclaimWindow(window.Key); + window.Key.Dispose(); + window.Value.Free(); + } + windows.Clear(); + } +} \ No newline at end of file diff --git a/Nerfed.Runtime/Gui/Shaders/generate-spirv.bat b/Nerfed.Runtime/Gui/Shaders/generate-spirv.bat new file mode 100644 index 0000000..62d1d99 --- /dev/null +++ b/Nerfed.Runtime/Gui/Shaders/generate-spirv.bat @@ -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 diff --git a/Nerfed.Runtime/Gui/Shaders/imgui-frag.glsl b/Nerfed.Runtime/Gui/Shaders/imgui-frag.glsl new file mode 100644 index 0000000..126b932 --- /dev/null +++ b/Nerfed.Runtime/Gui/Shaders/imgui-frag.glsl @@ -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); +} \ No newline at end of file diff --git a/Nerfed.Runtime/Gui/Shaders/imgui-frag.spv b/Nerfed.Runtime/Gui/Shaders/imgui-frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..550f9a08131507837953b6970d98bb906d49c1c9 GIT binary patch literal 664 zcmYk2y-osA5QVR-izv#EC}>O!NKY)(m>6v+Xy_=ciBOn;OK?ei0bk6gvN7@dc9(>k z%+5V$&YU~5QK^3r!d|F`O1KF5X@(L^fGcNtG@gtHpXqFHcYmv*7NSh3rcU2J*;r2B zKP(&)RpN|jptZ&$+#;Mq_@Oa|-R+5C>`ON3YLgC=MY7H``n+W*?`eQ1)8%S0w;pG2 zr1P&~lB{Qx!U$J=t_2*i9=lkN8^T$vi+hAe?A+?zuZ2ooFPlE^X>%{bb%_pocN4o$ zmv4paACiA6urtY7KO*bBt&5#e?vm+G$oh$Q&lX?dRHL9yzj`5(^F6UUd7ST*te<f3}G`R{`3aM#D$ O3$OTpDW7}yxh@@(>*Im<@s7zH_1x)sYf>Kj$;4LuRi^J zkW;SYs1=+Dm6+Ng#X+8rPjE|2E#b}JL(u9Ke6wmrta?XZIE09)i##=mn7){A(k7!X z?+`>CTnQ#W#`f=;$M~4SP0SkdtkI^1TI^!>5#uJl%UFHtWmLu1o{!bWIM!1a<5*8k zV!RGZUXvc2OMeq@k-dR!ai4t}JMRYn%j^xzwKt8g;9Gx(_$s@6u{xgm#2V(b2E6O+ zQOmc}*l$YAdsa$bRo8orS25Q%vD#VJzUrJ(LosXLVs{oXYa6SpnEBgNU%oSLvDvu42NF#GV#V@xf~shM%?@j1S8n^O new uint[3] + { + 0, + 8, + 16 + }; +} + +[StructLayout(LayoutKind.Sequential)] +public struct TransformVertexUniform +{ + public Matrix4x4 ProjectionMatrix; + + public TransformVertexUniform(Matrix4x4 projectionMatrix) + { + ProjectionMatrix = projectionMatrix; + } +} \ No newline at end of file diff --git a/Nerfed.Runtime/Gui/TextureStorage.cs b/Nerfed.Runtime/Gui/TextureStorage.cs new file mode 100644 index 0000000..e56da06 --- /dev/null +++ b/Nerfed.Runtime/Gui/TextureStorage.cs @@ -0,0 +1,35 @@ +using Nerfed.Runtime.Graphics; + +namespace Nerfed.Runtime.Gui; + +public class TextureStorage +{ + private readonly Dictionary> pointerToTexture = new Dictionary>(); + + public IntPtr Add(Texture texture) + { + if (!pointerToTexture.ContainsKey(texture.Handle)) + { + pointerToTexture.Add(texture.Handle, new WeakReference(texture)); + } + return texture.Handle; + } + + public Texture GetTexture(IntPtr pointer) + { + if (!pointerToTexture.ContainsKey(pointer)) + { + return null; + } + + WeakReference result = pointerToTexture[pointer]; + + if (!result.TryGetTarget(out Texture texture)) + { + pointerToTexture.Remove(pointer); + return null; + } + + return texture; + } +} \ No newline at end of file diff --git a/Nerfed.Runtime/Libraries/ImGui.NET b/Nerfed.Runtime/Libraries/ImGui.NET new file mode 160000 index 0000000..ae493d9 --- /dev/null +++ b/Nerfed.Runtime/Libraries/ImGui.NET @@ -0,0 +1 @@ +Subproject commit ae493d92a312810b66483af1922babe2eb434a47 diff --git a/Nerfed.Runtime/Nerfed.Runtime.csproj b/Nerfed.Runtime/Nerfed.Runtime.csproj index a27271a..d209046 100644 --- a/Nerfed.Runtime/Nerfed.Runtime.csproj +++ b/Nerfed.Runtime/Nerfed.Runtime.csproj @@ -12,6 +12,16 @@ + + + + + + + Always + + + Exe net8.0 diff --git a/Nerfed.sln b/Nerfed.sln index be1920e..30ec14e 100644 --- a/Nerfed.sln +++ b/Nerfed.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 17.10.35013.160 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerfed.Runtime", "Nerfed.Runtime\Nerfed.Runtime.csproj", "{98E09BAF-587F-4238-89BD-7693C036C233}" 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 GlobalSection(SolutionConfigurationPlatforms) = preSolution 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}.Release|Any CPU.ActiveCfg = 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 GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/libs/x64/cimgui.dll b/libs/x64/cimgui.dll new file mode 100644 index 0000000..94c3de9 --- /dev/null +++ b/libs/x64/cimgui.dll @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c1c7185401fdc2e008a4bf04ea6c667811f8f06b7fb3d33c18ef7ca983641e27 +size 1204224 From 7cbb74572180674b8a6f363335c28f02d7486bfb Mon Sep 17 00:00:00 2001 From: max Date: Fri, 5 Jul 2024 23:22:11 +0200 Subject: [PATCH 02/11] fix library and input --- Nerfed.Runtime/Gui/Controller.cs | 101 ++++++++++++------------------- libs/x64/cimgui.dll | 4 +- 2 files changed, 42 insertions(+), 63 deletions(-) diff --git a/Nerfed.Runtime/Gui/Controller.cs b/Nerfed.Runtime/Gui/Controller.cs index 6d4990d..b9a5b72 100644 --- a/Nerfed.Runtime/Gui/Controller.cs +++ b/Nerfed.Runtime/Gui/Controller.cs @@ -66,6 +66,7 @@ public Controller(GraphicsDevice graphicsDevice, Window mainWindow, Color clearC 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, @@ -204,46 +205,46 @@ private void UpdateInput() 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.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.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)); + 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 input = Keyboard.GetTextInput(); - //if (!input.IsEmpty) - //{ - // foreach (char c in input) - // { - // if (c == '\t') - // { - // break; - // } + ReadOnlySpan input = Keyboard.GetTextInput(); + if (!input.IsEmpty) + { + foreach (char c in input) + { + if (c == '\t') + { + break; + } - // io.AddInputCharacter(c); - // } - //} + io.AddInputCharacter(c); + } + } } private unsafe void UpdateMonitors() @@ -505,32 +506,8 @@ 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); + graphicsDevice.ClaimWindow(window, SwapchainComposition.SDR, PresentMode.Immediate); // What PresentMode do we need? GCHandle handle = GCHandle.Alloc(window); vp.PlatformUserData = (IntPtr)handle; @@ -652,6 +629,8 @@ public void Dispose() foreach (KeyValuePair window in windows) { + if (window.Key == mainWindow) continue; + graphicsDevice.UnclaimWindow(window.Key); window.Key.Dispose(); window.Value.Free(); diff --git a/libs/x64/cimgui.dll b/libs/x64/cimgui.dll index 94c3de9..3f2319a 100644 --- a/libs/x64/cimgui.dll +++ b/libs/x64/cimgui.dll @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c1c7185401fdc2e008a4bf04ea6c667811f8f06b7fb3d33c18ef7ca983641e27 -size 1204224 +oid sha256:af446d0eeda59d2b36638fa4a6449491473724860f6e78b1f5cca65d228c8094 +size 1225216 From 1eb899b2402768a90b2faf089a3907bd8807ea5e Mon Sep 17 00:00:00 2001 From: max Date: Sat, 6 Jul 2024 01:29:12 +0200 Subject: [PATCH 03/11] gui events fix scroll input handle gui side, move and closed events --- Nerfed.Runtime/Engine.cs | 2 +- Nerfed.Runtime/Gui/Controller.cs | 42 ++++++++++++++++++++++--- Nerfed.Runtime/Input/Devices/Mouse.cs | 10 +++--- Nerfed.Runtime/Window/ScreenMode.cs | 7 +++-- Nerfed.Runtime/Window/Window.cs | 44 +++++++++++++++------------ 5 files changed, 73 insertions(+), 32 deletions(-) diff --git a/Nerfed.Runtime/Engine.cs b/Nerfed.Runtime/Engine.cs index 486b151..f02da70 100644 --- a/Nerfed.Runtime/Engine.cs +++ b/Nerfed.Runtime/Engine.cs @@ -153,8 +153,8 @@ private static void Tick() ProcessSDLEvents(); - Controller.Update((float)Timestep.TotalSeconds); // Tick game here... + Controller.Update((float)Timestep.TotalSeconds); AudioDevice.WakeThread(); accumulatedUpdateTime -= Timestep; diff --git a/Nerfed.Runtime/Gui/Controller.cs b/Nerfed.Runtime/Gui/Controller.cs index b9a5b72..e11c366 100644 --- a/Nerfed.Runtime/Gui/Controller.cs +++ b/Nerfed.Runtime/Gui/Controller.cs @@ -113,7 +113,7 @@ public Controller(GraphicsDevice graphicsDevice, Window mainWindow, Color clearC mainViewport.PlatformHandle = mainWindow.Handle; GCHandle handle = GCHandle.Alloc(mainWindow); mainViewport.PlatformUserData = (IntPtr)handle; - windows.Add(mainWindow, handle); + AddWindow(mainWindow, mainViewport, handle); unsafe { @@ -504,7 +504,11 @@ out int bytesPerPixel #region Window private void CreateWindow(ImGuiViewportPtr vp) { - WindowCreateInfo info = new WindowCreateInfo("Window Title", (uint)vp.Pos.X, (uint)vp.Pos.Y, ScreenMode.Windowed); + // 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? @@ -512,7 +516,7 @@ private void CreateWindow(ImGuiViewportPtr vp) GCHandle handle = GCHandle.Alloc(window); vp.PlatformUserData = (IntPtr)handle; - windows.Add(window, handle); + AddWindow(window, vp, handle); } private void DestroyWindow(ImGuiViewportPtr vp) @@ -528,8 +532,38 @@ private void DestroyWindow(ImGuiViewportPtr vp) windows.Remove(window); } - graphicsDevice.Wait(); + //graphicsDevice.Wait(); window.Dispose(); + + vp.PlatformUserData = IntPtr.Zero; + } + + 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]; + if(win == (Window)GCHandle.FromIntPtr(vp.PlatformUserData).Target) + { + DestroyWindow(vp); + } + } + }; + + windows.Add(window, handle); } private void ShowWindow(ImGuiViewportPtr vp) diff --git a/Nerfed.Runtime/Input/Devices/Mouse.cs b/Nerfed.Runtime/Input/Devices/Mouse.cs index 6386fcd..d87f98b 100644 --- a/Nerfed.Runtime/Input/Devices/Mouse.cs +++ b/Nerfed.Runtime/Input/Devices/Mouse.cs @@ -1,5 +1,5 @@ -using System.Numerics; -using SDL2; +using SDL2; +using System.Numerics; namespace Nerfed.Runtime; @@ -65,6 +65,8 @@ public static int GetWheelHorizontal() internal static void Update() { + wheelX = 0; + wheelY = 0; Array.Copy(buttonStates, lastButtonStates, buttonStates.Length); } @@ -105,8 +107,8 @@ private static void ProcessButtonUpEvent(ref SDL.SDL_MouseButtonEvent ev) private static void ProcessWheelEvent(ref SDL.SDL_MouseWheelEvent ev) { - wheelX += ev.x; - wheelY += ev.y; + wheelX = ev.x; + wheelY = ev.y; } private static void ProcessMotionEvent(ref SDL.SDL_MouseMotionEvent ev) diff --git a/Nerfed.Runtime/Window/ScreenMode.cs b/Nerfed.Runtime/Window/ScreenMode.cs index e9a34ff..3228b38 100644 --- a/Nerfed.Runtime/Window/ScreenMode.cs +++ b/Nerfed.Runtime/Window/ScreenMode.cs @@ -3,6 +3,7 @@ namespace Nerfed.Runtime; public enum ScreenMode { Fullscreen, - BorderlessFullscreen, - Windowed -} + FullscreenBorderless, + Windowed, + WindowedBorderless +} \ No newline at end of file diff --git a/Nerfed.Runtime/Window/Window.cs b/Nerfed.Runtime/Window/Window.cs index 42b9066..56ca056 100644 --- a/Nerfed.Runtime/Window/Window.cs +++ b/Nerfed.Runtime/Window/Window.cs @@ -11,6 +11,10 @@ namespace Nerfed.Runtime; /// public class Window { + public event Action OnResizedEvent; + public event Action OnMovedEvent; + public event Action OnCloseEvent; + internal IntPtr Handle { get; } public ScreenMode ScreenMode { get; private set; } public uint Width { get; private set; } @@ -33,9 +37,7 @@ public class Window public string Title { get; private set;} private bool IsDisposed; - private System.Action SizeChangeCallback = null; - - private static readonly Dictionary windowsById = new Dictionary(); + private static readonly Dictionary windowsById = new Dictionary(); public Window(GraphicsDevice graphicsDevice, WindowCreateInfo windowCreateInfo) { @@ -54,10 +56,14 @@ public Window(GraphicsDevice graphicsDevice, WindowCreateInfo windowCreateInfo) { flags |= SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN; } - else if (windowCreateInfo.ScreenMode == ScreenMode.BorderlessFullscreen) + else if (windowCreateInfo.ScreenMode == ScreenMode.FullscreenBorderless) { flags |= SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP; } + else if(windowCreateInfo.ScreenMode == ScreenMode.WindowedBorderless) + { + flags |= SDL.SDL_WindowFlags.SDL_WINDOW_BORDERLESS; + } if (windowCreateInfo.SystemResizable) { @@ -104,29 +110,35 @@ internal static void ProcessEvent(ref SDL.SDL_Event ev) case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_SIZE_CHANGED: window.ProcessSizeChangedEvent(ref ev.window); break; + case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_MOVED: + window.ProcessMovedChangedEvent(ref ev.window); + break; case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_CLOSE: window.ProcessCloseEvent(ref ev.window); break; } } - private void ProcessSizeChangedEvent(ref SDL.SDL_WindowEvent ev) + private void ProcessSizeChangedEvent(ref SDL.SDL_WindowEvent ev) { uint newWidth = (uint)ev.data1; uint newHeight = (uint)ev.data2; Width = newWidth; Height = newHeight; - if (SizeChangeCallback != null) - { - SizeChangeCallback(newWidth, newHeight); - } + OnResizedEvent?.Invoke(this, Width, Height); } - private void ProcessCloseEvent(ref SDL.SDL_WindowEvent ev) + private void ProcessMovedChangedEvent(ref SDL.SDL_WindowEvent ev) + { + OnMovedEvent?.Invoke(this, ev.data1, ev.data2); + } + + private void ProcessCloseEvent(ref SDL.SDL_WindowEvent ev) { Engine.GraphicsDevice.UnclaimWindow(this); Dispose(); + OnCloseEvent?.Invoke(this); } /// @@ -140,7 +152,7 @@ public void SetScreenMode(ScreenMode screenMode) { windowFlag = SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN; } - else if (screenMode == ScreenMode.BorderlessFullscreen) + else if (screenMode == ScreenMode.FullscreenBorderless) { windowFlag = SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP; } @@ -195,15 +207,7 @@ internal void Show() SDL.SDL_ShowWindow(Handle); } - /// - /// You can specify a method to run when the window size changes. - /// - public void RegisterSizeChangeCallback(System.Action sizeChangeCallback) - { - SizeChangeCallback = sizeChangeCallback; - } - - protected virtual void Dispose(bool disposing) + protected virtual void Dispose(bool disposing) { if (!IsDisposed) { From 2c839d8fadc421203888896a6ebca946f74f32a6 Mon Sep 17 00:00:00 2001 From: max Date: Wed, 10 Jul 2024 21:50:04 +0200 Subject: [PATCH 04/11] Rename and mouse cursor support --- Nerfed.Runtime/Engine.cs | 4 +- .../Gui/{Clipboard.cs => GuiClipboard.cs} | 12 +++-- .../Gui/{Controller.cs => GuiController.cs} | 52 ++++++++++++++++--- Nerfed.Runtime/Gui/GuiStructs.cs | 33 ++++++++++++ ...TextureStorage.cs => GuiTextureStorage.cs} | 6 +-- Nerfed.Runtime/Gui/Structs.cs | 49 ----------------- 6 files changed, 89 insertions(+), 67 deletions(-) rename Nerfed.Runtime/Gui/{Clipboard.cs => GuiClipboard.cs} (93%) rename Nerfed.Runtime/Gui/{Controller.cs => GuiController.cs} (90%) create mode 100644 Nerfed.Runtime/Gui/GuiStructs.cs rename Nerfed.Runtime/Gui/{TextureStorage.cs => GuiTextureStorage.cs} (81%) delete mode 100644 Nerfed.Runtime/Gui/Structs.cs diff --git a/Nerfed.Runtime/Engine.cs b/Nerfed.Runtime/Engine.cs index f02da70..7a6a21b 100644 --- a/Nerfed.Runtime/Engine.cs +++ b/Nerfed.Runtime/Engine.cs @@ -39,7 +39,7 @@ public static class Engine private const string WindowTitle = "Nerfed"; //.. - private static Gui.Controller Controller; + private static Gui.GuiController Controller; internal static void Run(string[] args) { @@ -67,7 +67,7 @@ internal static void Run(string[] args) AudioDevice = new AudioDevice(); - Controller = new Gui.Controller(GraphicsDevice, MainWindow, Color.DarkOliveGreen); + Controller = new Gui.GuiController(GraphicsDevice, MainWindow, Color.DarkOliveGreen); Controller.OnGui += () => { ImGuiNET.ImGui.ShowDemoWindow(); }; diff --git a/Nerfed.Runtime/Gui/Clipboard.cs b/Nerfed.Runtime/Gui/GuiClipboard.cs similarity index 93% rename from Nerfed.Runtime/Gui/Clipboard.cs rename to Nerfed.Runtime/Gui/GuiClipboard.cs index ddb883f..0c1b7e7 100644 --- a/Nerfed.Runtime/Gui/Clipboard.cs +++ b/Nerfed.Runtime/Gui/GuiClipboard.cs @@ -3,10 +3,13 @@ namespace Nerfed.Runtime.Gui; -public static unsafe class Clipboard +public static unsafe class GuiClipboard { private static IntPtr clipboard; - private static readonly Dictionary pinned = new(); + private static readonly Dictionary pinned = new Dictionary(); + + public static readonly IntPtr GetFnPtr = GetPointerTo(Get); + public static readonly IntPtr SetFnPtr = GetPointerTo(Set); private static unsafe void Set(void* userdata, byte* text) { @@ -36,13 +39,12 @@ private static unsafe void Set(void* userdata, byte* text) private static IntPtr GetPointerTo(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); } \ No newline at end of file diff --git a/Nerfed.Runtime/Gui/Controller.cs b/Nerfed.Runtime/Gui/GuiController.cs similarity index 90% rename from Nerfed.Runtime/Gui/Controller.cs rename to Nerfed.Runtime/Gui/GuiController.cs index e11c366..5b278de 100644 --- a/Nerfed.Runtime/Gui/Controller.cs +++ b/Nerfed.Runtime/Gui/GuiController.cs @@ -9,7 +9,7 @@ namespace Nerfed.Runtime.Gui; -internal class Controller : IDisposable +internal class GuiController : IDisposable { public event Action OnGui; @@ -36,7 +36,7 @@ internal class Controller : IDisposable private readonly Shader imGuiVertexShader; private readonly Shader imGuiFragmentShader; private readonly Sampler imGuiSampler; - private readonly TextureStorage textureStorage = new TextureStorage(); + private readonly GuiTextureStorage textureStorage = new GuiTextureStorage(); private readonly Dictionary windows = new Dictionary(16); private Texture fontTexture = null; @@ -46,7 +46,7 @@ internal class Controller : IDisposable 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) + public GuiController(GraphicsDevice graphicsDevice, Window mainWindow, Color clearColor, ImGuiConfigFlags configFlags = ImGuiConfigFlags.NavEnableKeyboard | ImGuiConfigFlags.DockingEnable | ImGuiConfigFlags.ViewportsEnable) { this.mainWindow = mainWindow; this.graphicsDevice = graphicsDevice; @@ -104,10 +104,10 @@ public Controller(GraphicsDevice graphicsDevice, Window mainWindow, Color clearC if (!OperatingSystem.IsWindows()) { - io.SetClipboardTextFn = Clipboard.SetFnPtr; - io.GetClipboardTextFn = Clipboard.GetFnPtr; + io.SetClipboardTextFn = GuiClipboard.SetFnPtr; + io.GetClipboardTextFn = GuiClipboard.GetFnPtr; } - + ImGuiPlatformIOPtr platformIO = ImGui.GetPlatformIO(); ImGuiViewportPtr mainViewport = platformIO.Viewports[0]; mainViewport.PlatformHandle = mainWindow.Handle; @@ -143,7 +143,7 @@ public Controller(GraphicsDevice graphicsDevice, Window mainWindow, Color clearC ImGuiNative.ImGuiPlatformIO_Set_Platform_GetWindowSize(platformIO.NativePtr, Marshal.GetFunctionPointerForDelegate(getWindowSize)); } - //io.BackendFlags |= ImGuiBackendFlags.HasMouseCursors; + io.BackendFlags |= ImGuiBackendFlags.HasMouseCursors; io.BackendFlags |= ImGuiBackendFlags.HasSetMousePos; io.BackendFlags |= ImGuiBackendFlags.PlatformHasViewports; io.BackendFlags |= ImGuiBackendFlags.RendererHasViewports; @@ -159,6 +159,7 @@ public void Update(float deltaTime) UpdatePerFrameImGuiData(deltaTime); UpdateInput(); + UpdateCursor(); UpdateMonitors(); frameBegun = true; @@ -247,6 +248,41 @@ private void UpdateInput() } } + private void UpdateCursor() + { + ImGuiIOPtr io = ImGui.GetIO(); + + if ((io.ConfigFlags & ImGuiConfigFlags.NoMouseCursorChange) != 0) + { + return; + } + + ImGuiMouseCursor imGuiCursor = ImGui.GetMouseCursor(); + + if (imGuiCursor == ImGuiMouseCursor.None || io.MouseDrawCursor) + { + SDL2.SDL.SDL_ShowCursor(0); + } + else + { + nint sdlCursor = imGuiCursor switch + { + ImGuiMouseCursor.Arrow => SDL2.SDL.SDL_CreateSystemCursor(SDL2.SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_ARROW), + ImGuiMouseCursor.TextInput => SDL2.SDL.SDL_CreateSystemCursor(SDL2.SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_IBEAM), + ImGuiMouseCursor.ResizeAll => SDL2.SDL.SDL_CreateSystemCursor(SDL2.SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZEALL), + ImGuiMouseCursor.ResizeNS => SDL2.SDL.SDL_CreateSystemCursor(SDL2.SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZENS), + ImGuiMouseCursor.ResizeEW => SDL2.SDL.SDL_CreateSystemCursor(SDL2.SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZEWE), + ImGuiMouseCursor.ResizeNESW => SDL2.SDL.SDL_CreateSystemCursor(SDL2.SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZENESW), + ImGuiMouseCursor.ResizeNWSE => SDL2.SDL.SDL_CreateSystemCursor(SDL2.SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZENWSE), + ImGuiMouseCursor.Hand => SDL2.SDL.SDL_CreateSystemCursor(SDL2.SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_HAND), + ImGuiMouseCursor.NotAllowed => SDL2.SDL.SDL_CreateSystemCursor(SDL2.SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_NO), + _ => SDL2.SDL.SDL_CreateSystemCursor(SDL2.SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_ARROW), + }; + SDL2.SDL.SDL_SetCursor(sdlCursor); + SDL2.SDL.SDL_ShowCursor(1); + } + } + private unsafe void UpdateMonitors() { ImGuiPlatformIOPtr platformIO = ImGui.GetPlatformIO(); @@ -304,7 +340,7 @@ public void Render() { RenderCommandLists(commandBuffer, swapchainTexture, vp.DrawData); graphicsDevice.Submit(commandBuffer); - graphicsDevice.Wait(); + //graphicsDevice.Wait(); } } } diff --git a/Nerfed.Runtime/Gui/GuiStructs.cs b/Nerfed.Runtime/Gui/GuiStructs.cs new file mode 100644 index 0000000..d34d349 --- /dev/null +++ b/Nerfed.Runtime/Gui/GuiStructs.cs @@ -0,0 +1,33 @@ +using Nerfed.Runtime.Graphics; +using System.Numerics; +using System.Runtime.InteropServices; + +namespace Nerfed.Runtime.Gui; + +[StructLayout(LayoutKind.Sequential)] +public struct Position2DTextureColorVertex(Vector2 position, Vector2 texcoord, Color color) : IVertexType +{ + public Vector2 Position = position; + public Vector2 TexCoord = texcoord; + public Color Color = color; + + public static VertexElementFormat[] Formats { get; } = new VertexElementFormat[3] + { + VertexElementFormat.Vector2, + VertexElementFormat.Vector2, + VertexElementFormat.Color + }; + + public static uint[] Offsets { get; } = new uint[3] + { + 0, + 8, + 16 + }; +} + +[StructLayout(LayoutKind.Sequential)] +public struct TransformVertexUniform(Matrix4x4 projectionMatrix) +{ + public Matrix4x4 ProjectionMatrix = projectionMatrix; +} \ No newline at end of file diff --git a/Nerfed.Runtime/Gui/TextureStorage.cs b/Nerfed.Runtime/Gui/GuiTextureStorage.cs similarity index 81% rename from Nerfed.Runtime/Gui/TextureStorage.cs rename to Nerfed.Runtime/Gui/GuiTextureStorage.cs index e56da06..817204b 100644 --- a/Nerfed.Runtime/Gui/TextureStorage.cs +++ b/Nerfed.Runtime/Gui/GuiTextureStorage.cs @@ -2,7 +2,7 @@ namespace Nerfed.Runtime.Gui; -public class TextureStorage +public class GuiTextureStorage { private readonly Dictionary> pointerToTexture = new Dictionary>(); @@ -17,12 +17,12 @@ public IntPtr Add(Texture texture) public Texture GetTexture(IntPtr pointer) { - if (!pointerToTexture.ContainsKey(pointer)) + if (!pointerToTexture.TryGetValue(pointer, out WeakReference value)) { return null; } - WeakReference result = pointerToTexture[pointer]; + WeakReference result = value; if (!result.TryGetTarget(out Texture texture)) { diff --git a/Nerfed.Runtime/Gui/Structs.cs b/Nerfed.Runtime/Gui/Structs.cs deleted file mode 100644 index a633ba6..0000000 --- a/Nerfed.Runtime/Gui/Structs.cs +++ /dev/null @@ -1,49 +0,0 @@ -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; - } -} \ No newline at end of file From 42b978e8c977165fd13662423c5b97ae10232dc5 Mon Sep 17 00:00:00 2001 From: max Date: Wed, 10 Jul 2024 23:18:56 +0200 Subject: [PATCH 05/11] working on window handling --- Nerfed.Runtime/Engine.cs | 5 ++- Nerfed.Runtime/Gui/GuiController.cs | 47 ++++++++++++----------------- Nerfed.Runtime/Window/Window.cs | 2 +- 3 files changed, 25 insertions(+), 29 deletions(-) diff --git a/Nerfed.Runtime/Engine.cs b/Nerfed.Runtime/Engine.cs index 7a6a21b..da76aa9 100644 --- a/Nerfed.Runtime/Engine.cs +++ b/Nerfed.Runtime/Engine.cs @@ -19,7 +19,6 @@ public static class Engine private static Stopwatch gameTimer; private static long previousTicks = 0; private static TimeSpan accumulatedUpdateTime = TimeSpan.Zero; - private static TimeSpan accumulatedDrawTime = TimeSpan.Zero; // must be a power of 2 so we can do a bitmask optimization when checking worst case @@ -65,6 +64,10 @@ internal static void Run(string[] args) throw new Exception("Failed to claim window"); } + MainWindow.OnCloseEvent += (w) => { + quit = true; + }; + AudioDevice = new AudioDevice(); Controller = new Gui.GuiController(GraphicsDevice, MainWindow, Color.DarkOliveGreen); diff --git a/Nerfed.Runtime/Gui/GuiController.cs b/Nerfed.Runtime/Gui/GuiController.cs index 5b278de..f8e36ff 100644 --- a/Nerfed.Runtime/Gui/GuiController.cs +++ b/Nerfed.Runtime/Gui/GuiController.cs @@ -37,7 +37,8 @@ internal class GuiController : IDisposable private readonly Shader imGuiFragmentShader; private readonly Sampler imGuiSampler; private readonly GuiTextureStorage textureStorage = new GuiTextureStorage(); - private readonly Dictionary windows = new Dictionary(16); + private readonly Dictionary windowToHandle = new Dictionary(16); + private readonly Dictionary imguiToWindow = new Dictionary(16); private Texture fontTexture = null; private uint vertexCount = 0; @@ -49,7 +50,6 @@ internal class GuiController : IDisposable public GuiController(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); @@ -100,7 +100,6 @@ public GuiController(GraphicsDevice graphicsDevice, Window mainWindow, Color cle BuildFontAtlas(); io.ConfigFlags = configFlags; - //io.MouseDrawCursor = true; if (!OperatingSystem.IsWindows()) { @@ -167,11 +166,6 @@ public void Update(float deltaTime) OnGui?.Invoke(); - { // Debug - ImGuiIOPtr io = ImGui.GetIO(); - ImGui.Text($"mouse pos: {io.MousePos}"); - } - ImGui.EndFrame(); } @@ -557,21 +551,21 @@ private void CreateWindow(ImGuiViewportPtr vp) private void DestroyWindow(ImGuiViewportPtr vp) { - if (vp.PlatformUserData == IntPtr.Zero) return; + //Window window = (Window)GCHandle.FromIntPtr(vp.PlatformUserData).Target; - Window window = (Window)GCHandle.FromIntPtr(vp.PlatformUserData).Target; - graphicsDevice.UnclaimWindow(window); - - if (windows.TryGetValue(window, out GCHandle handle)) + if(imguiToWindow.TryGetValue(vp, out Window window)) { - handle.Free(); - windows.Remove(window); + graphicsDevice.UnclaimWindow(window); + + if (windowToHandle.TryGetValue(window, out GCHandle handle)) + { + handle.Free(); + windowToHandle.Remove(window); + } + + imguiToWindow.Remove(vp); + window.Dispose(); } - - //graphicsDevice.Wait(); - window.Dispose(); - - vp.PlatformUserData = IntPtr.Zero; } private void AddWindow(Window window, ImGuiViewportPtr vp, GCHandle handle) @@ -592,14 +586,12 @@ private void AddWindow(Window window, ImGuiViewportPtr vp, GCHandle handle) for (int i = 0; i < platformIO.Viewports.Capacity; i++) { ImGuiViewportPtr vp = platformIO.Viewports[i]; - if(win == (Window)GCHandle.FromIntPtr(vp.PlatformUserData).Target) - { - DestroyWindow(vp); - } + DestroyWindow(vp); } }; - windows.Add(window, handle); + windowToHandle.Add(window, handle); + imguiToWindow.Add(vp, window); } private void ShowWindow(ImGuiViewportPtr vp) @@ -697,7 +689,7 @@ public void Dispose() imGuiSampler?.Dispose(); resourceUploader?.Dispose(); - foreach (KeyValuePair window in windows) + foreach (KeyValuePair window in windowToHandle) { if (window.Key == mainWindow) continue; @@ -705,6 +697,7 @@ public void Dispose() window.Key.Dispose(); window.Value.Free(); } - windows.Clear(); + windowToHandle.Clear(); + imguiToWindow.Clear(); } } \ No newline at end of file diff --git a/Nerfed.Runtime/Window/Window.cs b/Nerfed.Runtime/Window/Window.cs index 56ca056..d9f5cb3 100644 --- a/Nerfed.Runtime/Window/Window.cs +++ b/Nerfed.Runtime/Window/Window.cs @@ -136,9 +136,9 @@ private void ProcessMovedChangedEvent(ref SDL.SDL_WindowEvent ev) private void ProcessCloseEvent(ref SDL.SDL_WindowEvent ev) { + OnCloseEvent?.Invoke(this); Engine.GraphicsDevice.UnclaimWindow(this); Dispose(); - OnCloseEvent?.Invoke(this); } /// From d8b41b08275f3e2b962fcfe57871fe0a404ab3a4 Mon Sep 17 00:00:00 2001 From: max Date: Fri, 12 Jul 2024 16:38:30 +0200 Subject: [PATCH 06/11] Fix viewports --- Nerfed.Runtime/Engine.cs | 2 +- Nerfed.Runtime/Gui/GuiController.cs | 132 +++++++----------------- Nerfed.Runtime/Gui/GuiViewportWindow.cs | 87 ++++++++++++++++ 3 files changed, 125 insertions(+), 96 deletions(-) create mode 100644 Nerfed.Runtime/Gui/GuiViewportWindow.cs 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 From 9890026656bafb9ea4332afebd06dcfd56706971 Mon Sep 17 00:00:00 2001 From: max Date: Fri, 12 Jul 2024 16:38:42 +0200 Subject: [PATCH 07/11] Fix viewports --- Nerfed.Runtime/Gui/GuiViewportWindow.cs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Nerfed.Runtime/Gui/GuiViewportWindow.cs b/Nerfed.Runtime/Gui/GuiViewportWindow.cs index 92abb2d..4fbe54c 100644 --- a/Nerfed.Runtime/Gui/GuiViewportWindow.cs +++ b/Nerfed.Runtime/Gui/GuiViewportWindow.cs @@ -6,16 +6,16 @@ namespace Nerfed.Runtime.Gui { internal class GuiViewportWindow { + public Window Window => window; + private readonly GCHandle gcHandle; - private readonly GraphicsDevice gd; + private readonly GraphicsDevice graphicsDevice; private readonly ImGuiViewportPtr vp; private readonly Window window; - public Window Window => window; - - public GuiViewportWindow(GraphicsDevice gd, ImGuiViewportPtr vp, Window window) + public GuiViewportWindow(GraphicsDevice graphicsDevice, ImGuiViewportPtr vp, Window window) { - this.gd = gd; + this.graphicsDevice = graphicsDevice; this.vp = vp; this.window = window; @@ -23,15 +23,15 @@ public GuiViewportWindow(GraphicsDevice gd, ImGuiViewportPtr vp, Window window) if (!window.Claimed) { - gd.ClaimWindow(window, SwapchainComposition.SDR, PresentMode.Immediate); // What PresentMode do we need? + graphicsDevice.ClaimWindow(window, SwapchainComposition.SDR, PresentMode.Immediate); // What PresentMode do we need? } vp.PlatformUserData = (IntPtr)gcHandle; } - public GuiViewportWindow(GraphicsDevice gd, ImGuiViewportPtr vp) + public GuiViewportWindow(GraphicsDevice graphicsDevice, ImGuiViewportPtr vp) { - this.gd = gd; + this.graphicsDevice = graphicsDevice; this.vp = vp; gcHandle = GCHandle.Alloc(this); @@ -48,8 +48,8 @@ public GuiViewportWindow(GraphicsDevice gd, ImGuiViewportPtr vp) 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 = new Window(graphicsDevice, info); + graphicsDevice.ClaimWindow(window, SwapchainComposition.SDR, PresentMode.Immediate); // What PresentMode do we need? window.OnMovedEvent += HandleOnMovedEvent; window.OnResizedEvent += HandleOnResizedEvent; @@ -64,7 +64,7 @@ public void Dispose() window.OnResizedEvent -= HandleOnResizedEvent; window.OnCloseEvent -= HandleOnCloseEvent; - gd.UnclaimWindow(window); + graphicsDevice.UnclaimWindow(window); window.Dispose(); gcHandle.Free(); } From 4b824f32057dab6d99ba1a6abcaec6526fc0e9dd Mon Sep 17 00:00:00 2001 From: max Date: Fri, 12 Jul 2024 16:38:54 +0200 Subject: [PATCH 08/11] Add License --- LICENSE | 9 +++++++++ README.md | 10 +++++++++- THIRD_PARTY_LICENSES | 29 +++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 LICENSE create mode 100644 THIRD_PARTY_LICENSES diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d2ea520 --- /dev/null +++ b/LICENSE @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) 2024 Nerfed Engine + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 47b8b30..75f1bd8 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,11 @@ # Nerfed -nerfed game engine \ No newline at end of file +nerfed game engine + +## License + +This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. + +## Third-Party Licenses + +This project includes third-party libraries with their respective licenses, which can be found in the [THIRD_PARTY_LICENSES](THIRD_PARTY_LICENSES) file. \ No newline at end of file diff --git a/THIRD_PARTY_LICENSES b/THIRD_PARTY_LICENSES new file mode 100644 index 0000000..0340413 --- /dev/null +++ b/THIRD_PARTY_LICENSES @@ -0,0 +1,29 @@ +# Third-Party Licenses + +## ImGui + +**Name:** Dear ImGui +**License:** MIT License + +MIT License + +Copyright (c) 2014-2022 Omar Cornut + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + From 16b04ea22a14ffdfcf3c5e1596701c5f65d60f2b Mon Sep 17 00:00:00 2001 From: max Date: Fri, 12 Jul 2024 17:27:01 +0200 Subject: [PATCH 09/11] Editor dummy code --- Nerfed.Editor/Editor/EditorGui.cs | 30 ++++++++++++++++++++++++++++++ Nerfed.Editor/Nerfed.Editor.csproj | 4 ++-- Nerfed.Editor/Program.cs | 29 ++++++++++++++++++++++++++++- Nerfed.Runtime/Engine.cs | 13 ++++++++++++- 4 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 Nerfed.Editor/Editor/EditorGui.cs diff --git a/Nerfed.Editor/Editor/EditorGui.cs b/Nerfed.Editor/Editor/EditorGui.cs new file mode 100644 index 0000000..8a9f6a9 --- /dev/null +++ b/Nerfed.Editor/Editor/EditorGui.cs @@ -0,0 +1,30 @@ +namespace Nerfed.Editor.Editor +{ + internal static class EditorGui + { + internal static void Initialize() + { + // Create GuiController. + + // Subscribe to GUI update. + // GuiController.OnGui call => UpdateDock; + // GuiController.OnGui call => UpdateEditorWindows; + // GuiController.OnGui call => ...; + } + + internal static void Update() + { + // Update GuiController. + } + + internal static void Render() + { + // Reneder GuiController. + } + + private static void UpdateDock() + { + // Setup default dockspace for the main window. + } + } +} \ No newline at end of file diff --git a/Nerfed.Editor/Nerfed.Editor.csproj b/Nerfed.Editor/Nerfed.Editor.csproj index cfa3c24..8aec954 100644 --- a/Nerfed.Editor/Nerfed.Editor.csproj +++ b/Nerfed.Editor/Nerfed.Editor.csproj @@ -23,8 +23,8 @@ - + - + diff --git a/Nerfed.Editor/Program.cs b/Nerfed.Editor/Program.cs index 7c4737d..92bbbc8 100644 --- a/Nerfed.Editor/Program.cs +++ b/Nerfed.Editor/Program.cs @@ -6,6 +6,33 @@ internal class Program { private static void Main(string[] args) { + Engine.OnInitialize += HandleOnInitialize; + Engine.OnUpdate += HandleOnUpdate; + Engine.OnRender += HandleOnRender; + Engine.OnQuit += HandleOnQuit; + Engine.Run(args); } -} + + private static void HandleOnInitialize() + { + // Open project. + // Setip EditorGui. + } + + private static void HandleOnUpdate() + { + // Editor Update. + + // Try Catch UserCode Update. + } + + private static void HandleOnRender() + { + // Editor GUI Render. + } + + private static void HandleOnQuit() + { + } +} \ No newline at end of file diff --git a/Nerfed.Runtime/Engine.cs b/Nerfed.Runtime/Engine.cs index 8d951eb..7dd741e 100644 --- a/Nerfed.Runtime/Engine.cs +++ b/Nerfed.Runtime/Engine.cs @@ -1,12 +1,17 @@ -using System.Diagnostics; using Nerfed.Runtime.Audio; using Nerfed.Runtime.Graphics; using SDL2; +using System.Diagnostics; namespace Nerfed.Runtime; public static class Engine { + public static event Action OnInitialize; + public static event Action OnUpdate; + public static event Action OnRender; + public static event Action OnQuit; + public static TimeSpan MaxDeltaTime { get; set; } = TimeSpan.FromMilliseconds(100); public static bool VSync { get; set; } @@ -65,11 +70,15 @@ public static void Run(string[] args) AudioDevice = new AudioDevice(); + OnInitialize?.Invoke(); + while (!quit) { Tick(); } + OnQuit?.Invoke(); + GraphicsDevice.UnclaimWindow(MainWindow); MainWindow.Dispose(); GraphicsDevice.Dispose(); @@ -146,6 +155,7 @@ private static void Tick() ProcessSDLEvents(); // Tick game here... + OnUpdate?.Invoke(); AudioDevice.WakeThread(); accumulatedUpdateTime -= Timestep; @@ -154,6 +164,7 @@ private static void Tick() double alpha = accumulatedUpdateTime / Timestep; // Render here.. + OnRender?.Invoke(); accumulatedDrawTime -= framerateCapTimeSpan; } From 777059489c0e461d51d63d02170c8f53280a3cc2 Mon Sep 17 00:00:00 2001 From: max Date: Fri, 12 Jul 2024 17:59:06 +0200 Subject: [PATCH 10/11] updated project structure --- .../{Gui => Content}/Shaders/generate-spirv.bat | 0 .../{Gui => Content}/Shaders/imgui-frag.glsl | 0 .../{Assets => Content}/Shaders/imgui-frag.spv | Bin .../{Gui => Content}/Shaders/imgui-vertex.glsl | 0 .../{Assets => Content}/Shaders/imgui-vertex.spv | Bin Nerfed.Runtime/Gui/GuiController.cs | 8 +++++--- Nerfed.Runtime/Gui/Shaders/imgui-frag.spv | Bin 664 -> 0 bytes Nerfed.Runtime/Gui/Shaders/imgui-vertex.spv | Bin 1440 -> 0 bytes Nerfed.Runtime/Nerfed.Runtime.csproj | 9 +++------ Nerfed.sln | 6 ------ 10 files changed, 8 insertions(+), 15 deletions(-) rename Nerfed.Runtime/{Gui => Content}/Shaders/generate-spirv.bat (100%) rename Nerfed.Runtime/{Gui => Content}/Shaders/imgui-frag.glsl (100%) rename Nerfed.Runtime/{Assets => Content}/Shaders/imgui-frag.spv (100%) rename Nerfed.Runtime/{Gui => Content}/Shaders/imgui-vertex.glsl (100%) rename Nerfed.Runtime/{Assets => Content}/Shaders/imgui-vertex.spv (100%) delete mode 100644 Nerfed.Runtime/Gui/Shaders/imgui-frag.spv delete mode 100644 Nerfed.Runtime/Gui/Shaders/imgui-vertex.spv diff --git a/Nerfed.Runtime/Gui/Shaders/generate-spirv.bat b/Nerfed.Runtime/Content/Shaders/generate-spirv.bat similarity index 100% rename from Nerfed.Runtime/Gui/Shaders/generate-spirv.bat rename to Nerfed.Runtime/Content/Shaders/generate-spirv.bat diff --git a/Nerfed.Runtime/Gui/Shaders/imgui-frag.glsl b/Nerfed.Runtime/Content/Shaders/imgui-frag.glsl similarity index 100% rename from Nerfed.Runtime/Gui/Shaders/imgui-frag.glsl rename to Nerfed.Runtime/Content/Shaders/imgui-frag.glsl diff --git a/Nerfed.Runtime/Assets/Shaders/imgui-frag.spv b/Nerfed.Runtime/Content/Shaders/imgui-frag.spv similarity index 100% rename from Nerfed.Runtime/Assets/Shaders/imgui-frag.spv rename to Nerfed.Runtime/Content/Shaders/imgui-frag.spv diff --git a/Nerfed.Runtime/Gui/Shaders/imgui-vertex.glsl b/Nerfed.Runtime/Content/Shaders/imgui-vertex.glsl similarity index 100% rename from Nerfed.Runtime/Gui/Shaders/imgui-vertex.glsl rename to Nerfed.Runtime/Content/Shaders/imgui-vertex.glsl diff --git a/Nerfed.Runtime/Assets/Shaders/imgui-vertex.spv b/Nerfed.Runtime/Content/Shaders/imgui-vertex.spv similarity index 100% rename from Nerfed.Runtime/Assets/Shaders/imgui-vertex.spv rename to Nerfed.Runtime/Content/Shaders/imgui-vertex.spv diff --git a/Nerfed.Runtime/Gui/GuiController.cs b/Nerfed.Runtime/Gui/GuiController.cs index ae610c9..f560b45 100644 --- a/Nerfed.Runtime/Gui/GuiController.cs +++ b/Nerfed.Runtime/Gui/GuiController.cs @@ -13,7 +13,7 @@ internal class GuiController : IDisposable { public event Action OnGui; - private readonly string shaderContentPath = Path.Combine(System.AppContext.BaseDirectory, "Assets", "Shaders"); + private readonly string shaderContentPath = Path.Combine(System.AppContext.BaseDirectory, "Content", "Shaders"); private readonly GraphicsDevice graphicsDevice; private readonly Window mainWindow; @@ -175,7 +175,7 @@ private void UpdatePerFrameImGuiData(float deltaSeconds) io.DeltaTime = deltaSeconds; // DeltaTime is in seconds. } - private static void UpdateInput() + private void UpdateInput() { ImGuiIOPtr io = ImGui.GetIO(); @@ -240,7 +240,7 @@ private static void UpdateInput() } } - private static void UpdateCursor() + private void UpdateCursor() { ImGuiIOPtr io = ImGui.GetIO(); @@ -500,6 +500,7 @@ private void RenderCommandLists(CommandBuffer commandBuffer, Texture renderTextu commandBuffer.EndRenderPass(renderPass); } + #region Resources private unsafe void BuildFontAtlas() { ResourceUploader resourceUploader = new ResourceUploader(graphicsDevice); @@ -528,6 +529,7 @@ out int bytesPerPixel 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. } + #endregion #region Window private void CreateWindow(ImGuiViewportPtr vp) diff --git a/Nerfed.Runtime/Gui/Shaders/imgui-frag.spv b/Nerfed.Runtime/Gui/Shaders/imgui-frag.spv deleted file mode 100644 index 550f9a08131507837953b6970d98bb906d49c1c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 664 zcmYk2y-osA5QVR-izv#EC}>O!NKY)(m>6v+Xy_=ciBOn;OK?ei0bk6gvN7@dc9(>k z%+5V$&YU~5QK^3r!d|F`O1KF5X@(L^fGcNtG@gtHpXqFHcYmv*7NSh3rcU2J*;r2B zKP(&)RpN|jptZ&$+#;Mq_@Oa|-R+5C>`ON3YLgC=MY7H``n+W*?`eQ1)8%S0w;pG2 zr1P&~lB{Qx!U$J=t_2*i9=lkN8^T$vi+hAe?A+?zuZ2ooFPlE^X>%{bb%_pocN4o$ zmv4paACiA6urtY7KO*bBt&5#e?vm+G$oh$Q&lX?dRHL9yzj`5(^F6UUd7ST*te<f3}G`R{`3aM#D$ O3$OTpDW7}yxh@@(>*Im<@s7zH_1x)sYf>Kj$;4LuRi^J zkW;SYs1=+Dm6+Ng#X+8rPjE|2E#b}JL(u9Ke6wmrta?XZIE09)i##=mn7){A(k7!X z?+`>CTnQ#W#`f=;$M~4SP0SkdtkI^1TI^!>5#uJl%UFHtWmLu1o{!bWIM!1a<5*8k zV!RGZUXvc2OMeq@k-dR!ai4t}JMRYn%j^xzwKt8g;9Gx(_$s@6u{xgm#2V(b2E6O+ zQOmc}*l$YAdsa$bRo8orS25Q%vD#VJzUrJ(LosXLVs{oXYa6SpnEBgNU%oSLvDvu42NF#GV#V@xf~shM%?@j1S8n^O - + + - - - - - + Always diff --git a/Nerfed.sln b/Nerfed.sln index 30ec14e..be1920e 100644 --- a/Nerfed.sln +++ b/Nerfed.sln @@ -5,8 +5,6 @@ VisualStudioVersion = 17.10.35013.160 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerfed.Runtime", "Nerfed.Runtime\Nerfed.Runtime.csproj", "{98E09BAF-587F-4238-89BD-7693C036C233}" 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 GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -17,10 +15,6 @@ Global {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.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 GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 60b85960ff2b54a3329c76ce97485591c04176af Mon Sep 17 00:00:00 2001 From: max Date: Fri, 12 Jul 2024 19:09:59 +0200 Subject: [PATCH 11/11] EditorGui setup --- Nerfed.Editor/Editor/EditorGui.cs | 45 +++++++++++++++++++++++++++-- Nerfed.Editor/Program.cs | 6 +++- Nerfed.Runtime/Gui/GuiController.cs | 12 +++++--- 3 files changed, 56 insertions(+), 7 deletions(-) diff --git a/Nerfed.Editor/Editor/EditorGui.cs b/Nerfed.Editor/Editor/EditorGui.cs index 8a9f6a9..cb14a5d 100644 --- a/Nerfed.Editor/Editor/EditorGui.cs +++ b/Nerfed.Editor/Editor/EditorGui.cs @@ -1,30 +1,71 @@ -namespace Nerfed.Editor.Editor +using ImGuiNET; +using Nerfed.Runtime; +using Nerfed.Runtime.Graphics; +using Nerfed.Runtime.Gui; + +namespace Nerfed.Editor { internal static class EditorGui { + private static GuiController guiController; + internal static void Initialize() { // Create GuiController. - + guiController = new GuiController(Engine.GraphicsDevice, Engine.MainWindow, Color.DimGray); // Subscribe to GUI update. // GuiController.OnGui call => UpdateDock; // GuiController.OnGui call => UpdateEditorWindows; // GuiController.OnGui call => ...; + guiController.OnGui += HandleOnGui; } internal static void Update() { // Update GuiController. + guiController.Update(Engine.Timestep.TotalSeconds); } internal static void Render() { // Reneder GuiController. + guiController.Render(); + } + + internal static void Quit() + { + guiController.Dispose(); } private static void UpdateDock() { // Setup default dockspace for the main window. + uint id = ImGui.GetID("MainDockSpace"); + ImGui.DockSpaceOverViewport(id, ImGui.GetMainViewport(), ImGuiDockNodeFlags.None); + } + + private static void UpdateMainMenu() + { + if (ImGui.BeginMainMenuBar()) + { + if (ImGui.BeginMenu("File")) + { + if (ImGui.MenuItem("Exit")) + { + Engine.Quit(); + } + ImGui.EndMenu(); + } + ImGui.EndMainMenuBar(); + } + } + + private static void HandleOnGui() + { + UpdateMainMenu(); + UpdateDock(); + + ImGui.ShowDemoWindow(); } } } \ No newline at end of file diff --git a/Nerfed.Editor/Program.cs b/Nerfed.Editor/Program.cs index 92bbbc8..6b21d4a 100644 --- a/Nerfed.Editor/Program.cs +++ b/Nerfed.Editor/Program.cs @@ -18,21 +18,25 @@ private static void HandleOnInitialize() { // Open project. // Setip EditorGui. + EditorGui.Initialize(); } private static void HandleOnUpdate() { // Editor Update. + EditorGui.Update(); + // Try Catch UserCode Update. } private static void HandleOnRender() { - // Editor GUI Render. + EditorGui.Render(); } private static void HandleOnQuit() { + EditorGui.Quit(); } } \ No newline at end of file diff --git a/Nerfed.Runtime/Gui/GuiController.cs b/Nerfed.Runtime/Gui/GuiController.cs index f560b45..3db9cdd 100644 --- a/Nerfed.Runtime/Gui/GuiController.cs +++ b/Nerfed.Runtime/Gui/GuiController.cs @@ -9,7 +9,7 @@ namespace Nerfed.Runtime.Gui; -internal class GuiController : IDisposable +public class GuiController : IDisposable { public event Action OnGui; @@ -144,9 +144,13 @@ public GuiController(GraphicsDevice graphicsDevice, Window mainWindow, Color cle io.BackendFlags |= ImGuiBackendFlags.HasSetMousePos; io.BackendFlags |= ImGuiBackendFlags.PlatformHasViewports; io.BackendFlags |= ImGuiBackendFlags.RendererHasViewports; + + UpdatePerFrameImGuiData(1.0 / 60.0); + ImGui.NewFrame(); + frameBegun = true; } - public void Update(float deltaTime) + public void Update(double deltaTime) { if (frameBegun) { @@ -167,12 +171,12 @@ public void Update(float deltaTime) ImGui.EndFrame(); } - private void UpdatePerFrameImGuiData(float deltaSeconds) + private void UpdatePerFrameImGuiData(double 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. + io.DeltaTime = (float)deltaSeconds; // DeltaTime is in seconds. } private void UpdateInput()