Fix viewports

This commit is contained in:
max 2024-07-12 16:38:30 +02:00
parent 42b978e8c9
commit d8b41b0827
3 changed files with 125 additions and 96 deletions

View File

@ -65,7 +65,7 @@ internal static void Run(string[] args)
}
MainWindow.OnCloseEvent += (w) => {
quit = true;
Quit();
};
AudioDevice = new AudioDevice();

View File

@ -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<Window, GCHandle> windowToHandle = new Dictionary<Window, GCHandle>(16);
private readonly Dictionary<ImGuiViewportPtr, Window> imguiToWindow = new Dictionary<ImGuiViewportPtr, Window>(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, GCHandle> window in windowToHandle)
{
if (window.Key == mainWindow) continue;
graphicsDevice.UnclaimWindow(window.Key);
window.Key.Dispose();
window.Value.Free();
}
windowToHandle.Clear();
imguiToWindow.Clear();
}
}

View File

@ -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;
}
}
}