From 60c51c09fd31c1a0fa5196b1ac7266de5fd24953 Mon Sep 17 00:00:00 2001 From: Eric Mellino Date: Wed, 26 Aug 2020 00:37:09 -0700 Subject: [PATCH 1/2] Working multi-viewport renderer using Veldrid. --- .../FixedAsciiString.cs | 27 ++ .../ImGui.NET.SampleProgram.csproj | 6 +- .../ImGuiController.cs | 278 +++++++++++++++++- src/ImGui.NET.SampleProgram/Program.cs | 8 +- .../VeldridImGuiWindow.cs | 86 ++++++ src/ImGui.NET/Delegates.cs | 17 ++ src/ImGui.NET/ImGuiNative.Manual.cs | 13 + src/ImGui.NET/ImVector.cs | 7 + 8 files changed, 422 insertions(+), 20 deletions(-) create mode 100644 src/ImGui.NET.SampleProgram/FixedAsciiString.cs create mode 100644 src/ImGui.NET.SampleProgram/VeldridImGuiWindow.cs create mode 100644 src/ImGui.NET/Delegates.cs create mode 100644 src/ImGui.NET/ImGuiNative.Manual.cs diff --git a/src/ImGui.NET.SampleProgram/FixedAsciiString.cs b/src/ImGui.NET.SampleProgram/FixedAsciiString.cs new file mode 100644 index 00000000..a879fd61 --- /dev/null +++ b/src/ImGui.NET.SampleProgram/FixedAsciiString.cs @@ -0,0 +1,27 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace ImGui.NET.SampleProgram +{ + public class FixedAsciiString : IDisposable + { + public IntPtr DataPtr { get; } + + public unsafe FixedAsciiString(string s) + { + int byteCount = Encoding.ASCII.GetByteCount(s); + DataPtr = Marshal.AllocHGlobal(byteCount + 1); + fixed (char* sPtr = s) + { + int end = Encoding.ASCII.GetBytes(sPtr, s.Length, (byte*)DataPtr, byteCount); + ((byte*)DataPtr)[end] = 0; + } + } + + public void Dispose() + { + Marshal.FreeHGlobal(DataPtr); + } + } +} diff --git a/src/ImGui.NET.SampleProgram/ImGui.NET.SampleProgram.csproj b/src/ImGui.NET.SampleProgram/ImGui.NET.SampleProgram.csproj index 6f7e9841..3edae655 100644 --- a/src/ImGui.NET.SampleProgram/ImGui.NET.SampleProgram.csproj +++ b/src/ImGui.NET.SampleProgram/ImGui.NET.SampleProgram.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,6 +6,10 @@ true + + true + + diff --git a/src/ImGui.NET.SampleProgram/ImGuiController.cs b/src/ImGui.NET.SampleProgram/ImGuiController.cs index 4cbe6155..fbdf25a4 100644 --- a/src/ImGui.NET.SampleProgram/ImGuiController.cs +++ b/src/ImGui.NET.SampleProgram/ImGuiController.cs @@ -5,6 +5,9 @@ using System.IO; using Veldrid; using System.Runtime.CompilerServices; +using ImGui.NET.SampleProgram; +using Veldrid.Sdl2; +using System.Runtime.InteropServices; namespace ImGuiNET { @@ -15,6 +18,7 @@ namespace ImGuiNET public class ImGuiController : IDisposable { private GraphicsDevice _gd; + private readonly Sdl2Window _window; private bool _frameBegun; // Veldrid objects @@ -48,31 +52,185 @@ private readonly Dictionary _autoViewsByTexture = new Dictionary(); private readonly Dictionary _viewsById = new Dictionary(); private readonly List _ownedResources = new List(); + private readonly VeldridImGuiWindow _mainViewportWindow; + 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 int _lastAssignedID = 100; /// /// Constructs a new ImGuiController. /// - public ImGuiController(GraphicsDevice gd, OutputDescription outputDescription, int width, int height) + public unsafe ImGuiController(GraphicsDevice gd, Sdl2Window window, OutputDescription outputDescription, int width, int height) { _gd = gd; + _window = window; _windowWidth = width; _windowHeight = height; IntPtr context = ImGui.CreateContext(); ImGui.SetCurrentContext(context); - var fonts = ImGui.GetIO().Fonts; - ImGui.GetIO().Fonts.AddFontDefault(); + ImGuiIOPtr io = ImGui.GetIO(); + + io.ConfigFlags |= ImGuiConfigFlags.DockingEnable; + io.ConfigFlags |= ImGuiConfigFlags.ViewportsEnable; + + ImGuiPlatformIOPtr platformIO = ImGui.GetPlatformIO(); + ImGuiViewportPtr mainViewport = platformIO.Viewports[0]; + mainViewport.PlatformHandle = window.Handle; + _mainViewportWindow = new VeldridImGuiWindow(gd, mainViewport, _window); + + _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)); + + unsafe + { + io.NativePtr->BackendPlatformName = (byte*)new FixedAsciiString("Veldrid.SDL2 Backend").DataPtr; + } + io.BackendFlags |= ImGuiBackendFlags.HasMouseCursors; + io.BackendFlags |= ImGuiBackendFlags.HasSetMousePos; + io.BackendFlags |= ImGuiBackendFlags.PlatformHasViewports; + io.BackendFlags |= ImGuiBackendFlags.RendererHasViewports; + + io.Fonts.AddFontDefault(); CreateDeviceResources(gd, outputDescription); SetKeyMappings(); SetPerFrameImGuiData(1f / 60f); + UpdateMonitors(); ImGui.NewFrame(); _frameBegun = true; } + private void CreateWindow(ImGuiViewportPtr vp) + { + VeldridImGuiWindow window = new VeldridImGuiWindow(_gd, vp); + } + + private void DestroyWindow(ImGuiViewportPtr vp) + { + if (vp.PlatformUserData != IntPtr.Zero) + { + VeldridImGuiWindow window = (VeldridImGuiWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + window.Dispose(); + + vp.PlatformUserData = IntPtr.Zero; + } + } + + private void ShowWindow(ImGuiViewportPtr vp) + { + VeldridImGuiWindow window = (VeldridImGuiWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + Sdl2Native.SDL_ShowWindow(window.Window.SdlWindowHandle); + } + + private unsafe void GetWindowPos(ImGuiViewportPtr vp, Vector2* outPos) + { + VeldridImGuiWindow window = (VeldridImGuiWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + *outPos = new Vector2(window.Window.Bounds.X, window.Window.Bounds.Y); + } + + private void SetWindowPos(ImGuiViewportPtr vp, Vector2 pos) + { + VeldridImGuiWindow window = (VeldridImGuiWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + window.Window.X = (int)pos.X; + window.Window.Y = (int)pos.Y; + } + + private void SetWindowSize(ImGuiViewportPtr vp, Vector2 size) + { + VeldridImGuiWindow window = (VeldridImGuiWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + Sdl2Native.SDL_SetWindowSize(window.Window.SdlWindowHandle, (int)size.X, (int)size.Y); + } + + private unsafe void GetWindowSize(ImGuiViewportPtr vp, Vector2* outSize) + { + VeldridImGuiWindow window = (VeldridImGuiWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + Rectangle bounds = window.Window.Bounds; + *outSize = new Vector2(bounds.Width, bounds.Height); + } + + private delegate void SDL_RaiseWindow_t(IntPtr sdl2Window); + private static SDL_RaiseWindow_t p_sdl_RaiseWindow; + + private unsafe delegate uint SDL_GetGlobalMouseState_t(int* x, int* y); + private static SDL_GetGlobalMouseState_t p_sdl_GetGlobalMouseState; + + private unsafe delegate int SDL_GetDisplayUsableBounds_t(int displayIndex, Rectangle* rect); + private static SDL_GetDisplayUsableBounds_t p_sdl_GetDisplayUsableBounds_t; + + private delegate int SDL_GetNumVideoDisplays_t(); + private static SDL_GetNumVideoDisplays_t p_sdl_GetNumVideoDisplays; + + private void SetWindowFocus(ImGuiViewportPtr vp) + { + if (p_sdl_RaiseWindow == null) + { + p_sdl_RaiseWindow = Sdl2Native.LoadFunction("SDL_RaiseWindow"); + } + + VeldridImGuiWindow window = (VeldridImGuiWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + p_sdl_RaiseWindow(window.Window.SdlWindowHandle); + } + + private byte GetWindowFocus(ImGuiViewportPtr vp) + { + VeldridImGuiWindow window = (VeldridImGuiWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + SDL_WindowFlags flags = Sdl2Native.SDL_GetWindowFlags(window.Window.SdlWindowHandle); + return (flags & SDL_WindowFlags.InputFocus) != 0 ? (byte)1 : (byte)0; + } + + private byte GetWindowMinimized(ImGuiViewportPtr vp) + { + VeldridImGuiWindow window = (VeldridImGuiWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + SDL_WindowFlags flags = Sdl2Native.SDL_GetWindowFlags(window.Window.SdlWindowHandle); + return (flags & SDL_WindowFlags.Minimized) != 0 ? (byte)1 : (byte)0; + } + + private unsafe void SetWindowTitle(ImGuiViewportPtr vp, IntPtr title) + { + VeldridImGuiWindow window = (VeldridImGuiWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + byte* titlePtr = (byte*)title; + int count = 0; + while (titlePtr[count] != 0) + { + titlePtr += 1; + } + window.Window.Title = System.Text.Encoding.ASCII.GetString(titlePtr, count); + } + public void WindowResized(int width, int height) { _windowWidth = width; @@ -245,11 +403,11 @@ private byte[] GetEmbeddedResourceBytes(string resourceName) /// /// Recreates the device texture used to render text. /// - public void RecreateFontDeviceTexture(GraphicsDevice gd) + public unsafe void RecreateFontDeviceTexture(GraphicsDevice gd) { ImGuiIOPtr io = ImGui.GetIO(); // Build - IntPtr pixels; + byte* pixels; int width, height, bytesPerPixel; io.Fonts.GetTexDataAsRGBA32(out pixels, out width, out height, out bytesPerPixel); // Store our identifier @@ -265,7 +423,7 @@ public void RecreateFontDeviceTexture(GraphicsDevice gd) _fontTexture.Name = "ImGui.NET Font Texture"; gd.UpdateTexture( _fontTexture, - pixels, + (IntPtr)pixels, (uint)(bytesPerPixel * width * height), 0, 0, @@ -293,6 +451,31 @@ public void Render(GraphicsDevice gd, CommandList cl) _frameBegun = false; ImGui.Render(); RenderImDrawData(ImGui.GetDrawData(), gd, cl); + + // Update and Render additional Platform Windows + if ((ImGui.GetIO().ConfigFlags & ImGuiConfigFlags.ViewportsEnable) != 0) + { + ImGui.UpdatePlatformWindows(); + ImGuiPlatformIOPtr platformIO = ImGui.GetPlatformIO(); + for (int i = 1; i < platformIO.Viewports.Size; i++) + { + ImGuiViewportPtr vp = platformIO.Viewports[i]; + VeldridImGuiWindow window = (VeldridImGuiWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + cl.SetFramebuffer(window.Swapchain.Framebuffer); + RenderImDrawData(vp.DrawData, gd, cl); + } + } + } + } + + public void SwapExtraWindows(GraphicsDevice gd) + { + ImGuiPlatformIOPtr platformIO = ImGui.GetPlatformIO(); + for (int i = 1; i < platformIO.Viewports.Size; i++) + { + ImGuiViewportPtr vp = platformIO.Viewports[i]; + VeldridImGuiWindow window = (VeldridImGuiWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target; + gd.SwapBuffers(window.Swapchain); } } @@ -304,13 +487,48 @@ public void Update(float deltaSeconds, InputSnapshot snapshot) if (_frameBegun) { ImGui.Render(); + ImGui.UpdatePlatformWindows(); } SetPerFrameImGuiData(deltaSeconds); UpdateImGuiInput(snapshot); + UpdateMonitors(); _frameBegun = true; ImGui.NewFrame(); + + ImGui.Text($"Main viewport Position: {ImGui.GetPlatformIO().Viewports[0].Pos}"); + ImGui.Text($"Main viewport Size: {ImGui.GetPlatformIO().Viewports[0].Size}"); + ImGui.Text($"MoouseHoveredViewport: {ImGui.GetIO().MouseHoveredViewport}"); + } + + private unsafe void UpdateMonitors() + { + if (p_sdl_GetNumVideoDisplays == null) + { + p_sdl_GetNumVideoDisplays = Sdl2Native.LoadFunction("SDL_GetNumVideoDisplays"); + } + if (p_sdl_GetDisplayUsableBounds_t == null) + { + p_sdl_GetDisplayUsableBounds_t = Sdl2Native.LoadFunction("SDL_GetDisplayUsableBounds"); + } + + ImGuiPlatformIOPtr platformIO = ImGui.GetPlatformIO(); + Marshal.FreeHGlobal(platformIO.NativePtr->Monitors.Data); + int numMonitors = p_sdl_GetNumVideoDisplays(); + IntPtr data = Marshal.AllocHGlobal(Unsafe.SizeOf() * numMonitors); + platformIO.NativePtr->Monitors = new ImVector(numMonitors, numMonitors, data); + for (int i = 0; i < numMonitors; i++) + { + Rectangle r; + p_sdl_GetDisplayUsableBounds_t(i, &r); + ImGuiPlatformMonitorPtr monitor = platformIO.Monitors[i]; + monitor.DpiScale = 1f; + monitor.MainPos = new Vector2(r.X, r.Y); + monitor.MainSize = new Vector2(r.Width, r.Height); + monitor.WorkPos = new Vector2(r.X, r.Y); + monitor.WorkSize = new Vector2(r.Width, r.Height); + } } /// @@ -325,6 +543,9 @@ private void SetPerFrameImGuiData(float deltaSeconds) _windowHeight / _scaleFactor.Y); io.DisplayFramebufferScale = _scaleFactor; io.DeltaTime = deltaSeconds; // DeltaTime is in seconds. + + ImGui.GetPlatformIO().Viewports[0].Pos = new Vector2(_window.X, _window.Y); + ImGui.GetPlatformIO().Viewports[0].Size = new Vector2(_window.Width, _window.Height); } private void UpdateImGuiInput(InputSnapshot snapshot) @@ -357,9 +578,24 @@ private void UpdateImGuiInput(InputSnapshot snapshot) } io.MouseDown[0] = leftPressed || snapshot.IsMouseDown(MouseButton.Left); - io.MouseDown[1] = rightPressed || snapshot.IsMouseDown(MouseButton.Right); - io.MouseDown[2] = middlePressed || snapshot.IsMouseDown(MouseButton.Middle); - io.MousePos = mousePosition; + io.MouseDown[1] = middlePressed || snapshot.IsMouseDown(MouseButton.Right); + io.MouseDown[2] = rightPressed || snapshot.IsMouseDown(MouseButton.Middle); + + if (p_sdl_GetGlobalMouseState == null) + { + p_sdl_GetGlobalMouseState = Sdl2Native.LoadFunction("SDL_GetGlobalMouseState"); + } + + int x, y; + unsafe + { + uint buttons = p_sdl_GetGlobalMouseState(&x, &y); + io.MouseDown[0] = (buttons & 0b0001) != 0; + io.MouseDown[1] = (buttons & 0b0010) != 0; + io.MouseDown[2] = (buttons & 0b0100) != 0; + } + + io.MousePos = new Vector2(x, y); io.MouseWheel = snapshot.WheelDelta; IReadOnlyList keyCharPresses = snapshot.KeyCharPresses; @@ -396,6 +632,14 @@ private void UpdateImGuiInput(InputSnapshot snapshot) io.KeyAlt = _altDown; io.KeyShift = _shiftDown; io.KeySuper = _winKeyDown; + + ImVector viewports = ImGui.GetPlatformIO().Viewports; + for (int i = 1; i < viewports.Size; i++) + { + ImGuiViewportPtr v = viewports[i]; + VeldridImGuiWindow window = ((VeldridImGuiWindow)GCHandle.FromIntPtr(v.PlatformUserData).Target); + window.Update(); + } } private static void SetKeyMappings() @@ -421,6 +665,7 @@ private static void SetKeyMappings() io.KeyMap[(int)ImGuiKey.X] = (int)Key.X; io.KeyMap[(int)ImGuiKey.Y] = (int)Key.Y; io.KeyMap[(int)ImGuiKey.Z] = (int)Key.Z; + io.KeyMap[(int)ImGuiKey.Space] = (int)Key.Space; } private void RenderImDrawData(ImDrawDataPtr draw_data, GraphicsDevice gd, CommandList cl) @@ -447,6 +692,7 @@ private void RenderImDrawData(ImDrawDataPtr draw_data, GraphicsDevice gd, Comman _indexBuffer = gd.ResourceFactory.CreateBuffer(new BufferDescription((uint)(totalIBSize * 1.5f), BufferUsage.IndexBuffer | BufferUsage.Dynamic)); } + Vector2 pos = draw_data.DisplayPos; for (int i = 0; i < draw_data.CmdListsCount; i++) { ImDrawListPtr cmd_list = draw_data.CmdListsRange[i]; @@ -470,14 +716,14 @@ private void RenderImDrawData(ImDrawDataPtr draw_data, GraphicsDevice gd, Comman // Setup orthographic projection matrix into our constant buffer ImGuiIOPtr io = ImGui.GetIO(); Matrix4x4 mvp = Matrix4x4.CreateOrthographicOffCenter( - 0f, - io.DisplaySize.X, - io.DisplaySize.Y, - 0.0f, + pos.X, + pos.X + draw_data.DisplaySize.X, + pos.Y + draw_data.DisplaySize.Y, + pos.Y, -1.0f, 1.0f); - _gd.UpdateBuffer(_projMatrixBuffer, 0, ref mvp); + cl.UpdateBuffer(_projMatrixBuffer, 0, ref mvp); cl.SetVertexBuffer(0, _vertexBuffer); cl.SetIndexBuffer(_indexBuffer, IndexFormat.UInt16); @@ -515,8 +761,8 @@ private void RenderImDrawData(ImDrawDataPtr draw_data, GraphicsDevice gd, Comman cl.SetScissorRect( 0, - (uint)pcmd.ClipRect.X, - (uint)pcmd.ClipRect.Y, + (uint)(pcmd.ClipRect.X - pos.X), + (uint)(pcmd.ClipRect.Y - pos.Y), (uint)(pcmd.ClipRect.Z - pcmd.ClipRect.X), (uint)(pcmd.ClipRect.W - pcmd.ClipRect.Y)); diff --git a/src/ImGui.NET.SampleProgram/Program.cs b/src/ImGui.NET.SampleProgram/Program.cs index 634cb984..b87269d2 100644 --- a/src/ImGui.NET.SampleProgram/Program.cs +++ b/src/ImGui.NET.SampleProgram/Program.cs @@ -46,7 +46,7 @@ static void Main(string[] args) _controller.WindowResized(_window.Width, _window.Height); }; _cl = _gd.ResourceFactory.CreateCommandList(); - _controller = new ImGuiController(_gd, _gd.MainSwapchain.Framebuffer.OutputDescription, _window.Width, _window.Height); + _controller = new ImGuiController(_gd, _window, _gd.MainSwapchain.Framebuffer.OutputDescription, _window.Width, _window.Height); _memoryEditor = new MemoryEditor(); Random random = new Random(); _memoryEditorData = Enumerable.Range(0, 1024).Select(i => (byte)random.Next(255)).ToArray(); @@ -67,6 +67,7 @@ static void Main(string[] args) _cl.End(); _gd.SubmitCommands(_cl); _gd.SwapBuffers(_gd.MainSwapchain); + _controller.SwapExtraWindows(_gd); } // Clean up Veldrid resources @@ -89,6 +90,7 @@ private static unsafe void SubmitUI() //ImGui.ColorEdit3("clear color", ref _clearColor); // Edit 3 floats representing a color ImGui.Text($"Mouse position: {ImGui.GetMousePos()}"); + ImGui.Text($"Mouse down: {ImGui.GetIO().MouseDown[0]}"); ImGui.Checkbox("ImGui Demo Window", ref _showImGuiDemoWindow); // Edit bools storing our windows open/close state ImGui.Checkbox("Another Window", ref _showAnotherWindow); @@ -160,9 +162,9 @@ private static unsafe void SubmitUI() if ((s_tab_bar_flags & (uint)ImGuiTabBarFlags.FittingPolicyMask) == 0) s_tab_bar_flags |= (uint)ImGuiTabBarFlags.FittingPolicyDefault; if (ImGui.CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", ref s_tab_bar_flags, (uint)ImGuiTabBarFlags.FittingPolicyResizeDown)) - s_tab_bar_flags &= ~((uint)ImGuiTabBarFlags.FittingPolicyMask ^ (uint)ImGuiTabBarFlags.FittingPolicyResizeDown); + s_tab_bar_flags &= ~((uint)ImGuiTabBarFlags.FittingPolicyMask ^ (uint)ImGuiTabBarFlags.FittingPolicyResizeDown); if (ImGui.CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", ref s_tab_bar_flags, (uint)ImGuiTabBarFlags.FittingPolicyScroll)) - s_tab_bar_flags &= ~((uint)ImGuiTabBarFlags.FittingPolicyMask ^ (uint)ImGuiTabBarFlags.FittingPolicyScroll); + s_tab_bar_flags &= ~((uint)ImGuiTabBarFlags.FittingPolicyMask ^ (uint)ImGuiTabBarFlags.FittingPolicyScroll); // Tab Bar string[] names = { "Artichoke", "Beetroot", "Celery", "Daikon" }; diff --git a/src/ImGui.NET.SampleProgram/VeldridImGuiWindow.cs b/src/ImGui.NET.SampleProgram/VeldridImGuiWindow.cs new file mode 100644 index 00000000..dc04b13d --- /dev/null +++ b/src/ImGui.NET.SampleProgram/VeldridImGuiWindow.cs @@ -0,0 +1,86 @@ +using ImGuiNET; +using System; +using System.Runtime.InteropServices; +using Veldrid; +using Veldrid.Sdl2; +using Veldrid.StartupUtilities; + +namespace ImGui.NET.SampleProgram +{ + public class VeldridImGuiWindow : IDisposable + { + private readonly GCHandle _gcHandle; + private readonly GraphicsDevice _gd; + private readonly ImGuiViewportPtr _vp; + private readonly Sdl2Window _window; + private readonly Swapchain _sc; + + public Sdl2Window Window => _window; + public Swapchain Swapchain => _sc; + + public VeldridImGuiWindow(GraphicsDevice gd, ImGuiViewportPtr vp) + { + _gcHandle = GCHandle.Alloc(this); + _gd = gd; + _vp = vp; + + SDL_WindowFlags flags = SDL_WindowFlags.Hidden; + if ((vp.Flags & ImGuiViewportFlags.NoTaskBarIcon) != 0) + { + flags |= SDL_WindowFlags.SkipTaskbar; + } + if ((vp.Flags & ImGuiViewportFlags.NoDecoration) != 0) + { + flags |= SDL_WindowFlags.Borderless; + } + else + { + flags |= SDL_WindowFlags.Resizable; + } + + if ((vp.Flags & ImGuiViewportFlags.TopMost) != 0) + { + flags |= SDL_WindowFlags.AlwaysOnTop; + } + + _window = new Sdl2Window( + "No Title Yet", + (int)vp.Pos.X, (int)vp.Pos.Y, + (int)vp.Size.X, (int)vp.Size.Y, + flags, + false); + _window.Resized += () => _vp.PlatformRequestResize = true; + _window.Moved += p => _vp.PlatformRequestMove = true; + _window.Closed += () => _vp.PlatformRequestClose = true; + + SwapchainSource scSource = VeldridStartup.GetSwapchainSource(_window); + SwapchainDescription scDesc = new SwapchainDescription(scSource, (uint)_window.Width, (uint)_window.Height, null, true, false); + _sc = _gd.ResourceFactory.CreateSwapchain(scDesc); + _window.Resized += () => _sc.Resize((uint)_window.Width, (uint)_window.Height); + + vp.PlatformUserData = (IntPtr)_gcHandle; + } + + public VeldridImGuiWindow(GraphicsDevice gd, ImGuiViewportPtr vp, Sdl2Window window) + { + _gcHandle = GCHandle.Alloc(this); + _gd = gd; + _vp = vp; + _window = window; + vp.PlatformUserData = (IntPtr)_gcHandle; + } + + public void Update() + { + _window.PumpEvents(); + } + + public void Dispose() + { + _gd.WaitForIdle(); // TODO: Shouldn't be necessary, but Vulkan backend trips a validation error (swapchain in use when disposed). + _sc.Dispose(); + _window.Close(); + _gcHandle.Free(); + } + } +} diff --git a/src/ImGui.NET/Delegates.cs b/src/ImGui.NET/Delegates.cs new file mode 100644 index 00000000..4075f150 --- /dev/null +++ b/src/ImGui.NET/Delegates.cs @@ -0,0 +1,17 @@ +using System; +using System.Numerics; + +namespace ImGuiNET +{ + public delegate void Platform_CreateWindow(ImGuiViewportPtr vp); // Create a new platform window for the given viewport + public delegate void Platform_DestroyWindow(ImGuiViewportPtr vp); + public delegate void Platform_ShowWindow(ImGuiViewportPtr vp); // Newly created windows are initially hidden so SetWindowPos/Size/Title can be called on them first + public delegate void Platform_SetWindowPos(ImGuiViewportPtr vp, Vector2 pos); + public unsafe delegate void Platform_GetWindowPos(ImGuiViewportPtr vp, Vector2* outPos); + public delegate void Platform_SetWindowSize(ImGuiViewportPtr vp, Vector2 size); + public unsafe delegate void Platform_GetWindowSize(ImGuiViewportPtr vp, Vector2* outSize); + public delegate void Platform_SetWindowFocus(ImGuiViewportPtr vp); // Move window to front and set input focus + public delegate byte Platform_GetWindowFocus(ImGuiViewportPtr vp); + public delegate byte Platform_GetWindowMinimized(ImGuiViewportPtr vp); + public delegate void Platform_SetWindowTitle(ImGuiViewportPtr vp, IntPtr title); +} diff --git a/src/ImGui.NET/ImGuiNative.Manual.cs b/src/ImGui.NET/ImGuiNative.Manual.cs new file mode 100644 index 00000000..be8cbdc9 --- /dev/null +++ b/src/ImGui.NET/ImGuiNative.Manual.cs @@ -0,0 +1,13 @@ +using System; +using System.Runtime.InteropServices; + +namespace ImGuiNET +{ + public static unsafe partial class ImGuiNative + { + [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)] + public static extern void ImGuiPlatformIO_Set_Platform_GetWindowPos(ImGuiPlatformIO* platform_io, IntPtr funcPtr); + [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)] + public static extern void ImGuiPlatformIO_Set_Platform_GetWindowSize(ImGuiPlatformIO* platform_io, IntPtr funcPtr); + } +} diff --git a/src/ImGui.NET/ImVector.cs b/src/ImGui.NET/ImVector.cs index 76411b86..22a51a6b 100644 --- a/src/ImGui.NET/ImVector.cs +++ b/src/ImGui.NET/ImVector.cs @@ -9,6 +9,13 @@ public unsafe struct ImVector public readonly int Capacity; public readonly IntPtr Data; + public ImVector(int size, int capacity, IntPtr data) + { + Size = size; + Capacity = capacity; + Data = data; + } + public ref T Ref(int index) { return ref Unsafe.AsRef((byte*)Data + index * Unsafe.SizeOf()); From c37419bad8c117641ebd1d0a959557fc79845b7f Mon Sep 17 00:00:00 2001 From: pragmascript Date: Sat, 18 Jun 2022 14:39:34 +0200 Subject: [PATCH 2/2] Fixed small bug in null-terminated string counting --- src/ImGui.NET.SampleProgram/ImGuiController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImGui.NET.SampleProgram/ImGuiController.cs b/src/ImGui.NET.SampleProgram/ImGuiController.cs index 838dc316..2d3bfc26 100644 --- a/src/ImGui.NET.SampleProgram/ImGuiController.cs +++ b/src/ImGui.NET.SampleProgram/ImGuiController.cs @@ -228,7 +228,7 @@ private unsafe void SetWindowTitle(ImGuiViewportPtr vp, IntPtr title) int count = 0; while (titlePtr[count] != 0) { - titlePtr += 1; + count += 1; } window.Window.Title = System.Text.Encoding.ASCII.GetString(titlePtr, count); }