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) => { MainWindow.OnCloseEvent += (w) => {
quit = true; Quit();
}; };
AudioDevice = new AudioDevice(); AudioDevice = new AudioDevice();

View File

@ -37,8 +37,7 @@ internal class GuiController : IDisposable
private readonly Shader imGuiFragmentShader; private readonly Shader imGuiFragmentShader;
private readonly Sampler imGuiSampler; private readonly Sampler imGuiSampler;
private readonly GuiTextureStorage textureStorage = new GuiTextureStorage(); private readonly GuiTextureStorage textureStorage = new GuiTextureStorage();
private readonly Dictionary<Window, GCHandle> windowToHandle = new Dictionary<Window, GCHandle>(16); private readonly GuiViewportWindow mainViewportWindow;
private readonly Dictionary<ImGuiViewportPtr, Window> imguiToWindow = new Dictionary<ImGuiViewportPtr, Window>(16);
private Texture fontTexture = null; private Texture fontTexture = null;
private uint vertexCount = 0; 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) public GuiController(GraphicsDevice graphicsDevice, Window mainWindow, Color clearColor, ImGuiConfigFlags configFlags = ImGuiConfigFlags.NavEnableKeyboard | ImGuiConfigFlags.DockingEnable | ImGuiConfigFlags.ViewportsEnable)
{ {
this.graphicsDevice = graphicsDevice;
this.mainWindow = mainWindow; this.mainWindow = mainWindow;
this.clearColor = clearColor; this.clearColor = clearColor;
@ -110,9 +110,7 @@ public GuiController(GraphicsDevice graphicsDevice, Window mainWindow, Color cle
ImGuiPlatformIOPtr platformIO = ImGui.GetPlatformIO(); ImGuiPlatformIOPtr platformIO = ImGui.GetPlatformIO();
ImGuiViewportPtr mainViewport = platformIO.Viewports[0]; ImGuiViewportPtr mainViewport = platformIO.Viewports[0];
mainViewport.PlatformHandle = mainWindow.Handle; mainViewport.PlatformHandle = mainWindow.Handle;
GCHandle handle = GCHandle.Alloc(mainWindow); mainViewportWindow = new GuiViewportWindow(graphicsDevice, mainViewport, mainWindow);
mainViewport.PlatformUserData = (IntPtr)handle;
AddWindow(mainWindow, mainViewport, handle);
unsafe unsafe
{ {
@ -177,7 +175,7 @@ private void UpdatePerFrameImGuiData(float deltaSeconds)
io.DeltaTime = deltaSeconds; // DeltaTime is in seconds. io.DeltaTime = deltaSeconds; // DeltaTime is in seconds.
} }
private void UpdateInput() private static void UpdateInput()
{ {
ImGuiIOPtr io = ImGui.GetIO(); ImGuiIOPtr io = ImGui.GetIO();
@ -242,7 +240,7 @@ private void UpdateInput()
} }
} }
private void UpdateCursor() private static void UpdateCursor()
{ {
ImGuiIOPtr io = ImGui.GetIO(); ImGuiIOPtr io = ImGui.GetIO();
@ -255,7 +253,7 @@ private void UpdateCursor()
if (imGuiCursor == ImGuiMouseCursor.None || io.MouseDrawCursor) if (imGuiCursor == ImGuiMouseCursor.None || io.MouseDrawCursor)
{ {
SDL2.SDL.SDL_ShowCursor(0); _ = SDL2.SDL.SDL_ShowCursor(0);
} }
else else
{ {
@ -273,7 +271,7 @@ private void UpdateCursor()
_ => SDL2.SDL.SDL_CreateSystemCursor(SDL2.SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_ARROW), _ => SDL2.SDL.SDL_CreateSystemCursor(SDL2.SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_ARROW),
}; };
SDL2.SDL.SDL_SetCursor(sdlCursor); 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++) for (int i = 0; i < platformIO.Viewports.Size; i++)
{ {
ImGuiViewportPtr vp = platformIO.Viewports[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; continue;
} }
@ -328,7 +326,7 @@ public void Render()
UpdateImGuiBuffers(vp.DrawData); UpdateImGuiBuffers(vp.DrawData);
CommandBuffer commandBuffer = graphicsDevice.AcquireCommandBuffer(); CommandBuffer commandBuffer = graphicsDevice.AcquireCommandBuffer();
Texture swapchainTexture = commandBuffer.AcquireSwapchainTexture(window); Texture swapchainTexture = commandBuffer.AcquireSwapchainTexture(window.Window);
if (swapchainTexture != null) if (swapchainTexture != null)
{ {
@ -357,7 +355,7 @@ public void Render()
{ {
RenderCommandLists(commandBuffer, swapchainTexture, drawDataPtr); RenderCommandLists(commandBuffer, swapchainTexture, drawDataPtr);
graphicsDevice.Submit(commandBuffer); graphicsDevice.Submit(commandBuffer);
graphicsDevice.Wait(); //graphicsDevice.Wait();
} }
} }
} }
@ -534,80 +532,33 @@ out int bytesPerPixel
#region Window #region Window
private void CreateWindow(ImGuiViewportPtr vp) private void CreateWindow(ImGuiViewportPtr vp)
{ {
// TODO: Handle all flags. GuiViewportWindow window = new GuiViewportWindow(graphicsDevice, vp);
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);
} }
private void DestroyWindow(ImGuiViewportPtr 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)) GuiViewportWindow window = (GuiViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target;
{
graphicsDevice.UnclaimWindow(window);
if (windowToHandle.TryGetValue(window, out GCHandle handle))
{
handle.Free();
windowToHandle.Remove(window);
}
imguiToWindow.Remove(vp);
window.Dispose(); window.Dispose();
}
}
private void AddWindow(Window window, ImGuiViewportPtr vp, GCHandle handle) vp.PlatformUserData = IntPtr.Zero;
{
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);
} }
private void ShowWindow(ImGuiViewportPtr vp) private void ShowWindow(ImGuiViewportPtr vp)
{ {
if (vp.PlatformUserData == IntPtr.Zero) return; 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_ShowWindow(window.Handle); SDL2.SDL.SDL_ShowWindow(window.Window.Handle);
} }
private unsafe void GetWindowPos(ImGuiViewportPtr vp, Vector2* outPos) private unsafe void GetWindowPos(ImGuiViewportPtr vp, Vector2* outPos)
{ {
if (vp.PlatformUserData == IntPtr.Zero) return; 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_GetWindowPosition(window.Handle, out int x, out int y); SDL2.SDL.SDL_GetWindowPosition(window.Window.Handle, out int x, out int y);
*outPos = new Vector2(x, y); *outPos = new Vector2(x, y);
} }
@ -615,24 +566,24 @@ private void SetWindowPos(ImGuiViewportPtr vp, Vector2 pos)
{ {
if (vp.PlatformUserData == IntPtr.Zero) return; 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_SetWindowPosition(window.Handle, (int)pos.X, (int)pos.Y); SDL2.SDL.SDL_SetWindowPosition(window.Window.Handle, (int)pos.X, (int)pos.Y);
} }
private void SetWindowSize(ImGuiViewportPtr vp, Vector2 size) private void SetWindowSize(ImGuiViewportPtr vp, Vector2 size)
{ {
if (vp.PlatformUserData == IntPtr.Zero) return; 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_SetWindowSize(window.Handle, (int)size.X, (int)size.Y); SDL2.SDL.SDL_SetWindowSize(window.Window.Handle, (int)size.X, (int)size.Y);
} }
private unsafe void GetWindowSize(ImGuiViewportPtr vp, Vector2* outSize) private unsafe void GetWindowSize(ImGuiViewportPtr vp, Vector2* outSize)
{ {
if (vp.PlatformUserData == IntPtr.Zero) return; 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_GetWindowSize(window.Handle, out int w, out int h); SDL2.SDL.SDL_GetWindowSize(window.Window.Handle, out int w, out int h);
*outSize = new Vector2(w, h); *outSize = new Vector2(w, h);
} }
@ -640,26 +591,28 @@ private void SetWindowFocus(ImGuiViewportPtr vp)
{ {
if (vp.PlatformUserData == IntPtr.Zero) return; 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_SetWindowInputFocus(window.Handle);
SDL2.SDL.SDL_RaiseWindow(window.Handle); SDL2.SDL.SDL_RaiseWindow(window.Window.Handle);
} }
private byte GetWindowFocus(ImGuiViewportPtr vp) private byte GetWindowFocus(ImGuiViewportPtr vp)
{ {
if (vp.PlatformUserData == IntPtr.Zero) return (byte)0; if (vp.PlatformUserData == IntPtr.Zero) return (byte)0;
Window window = (Window)GCHandle.FromIntPtr(vp.PlatformUserData).Target; GuiViewportWindow window = (GuiViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target;
SDL2.SDL.SDL_WindowFlags flags = (SDL2.SDL.SDL_WindowFlags)SDL2.SDL.SDL_GetWindowFlags(window.Handle); 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; return (flags & SDL2.SDL.SDL_WindowFlags.SDL_WINDOW_INPUT_FOCUS) != 0 ? (byte)1 : (byte)0;
} }
private byte GetWindowMinimized(ImGuiViewportPtr vp) 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; 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; 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; byte* titlePtr = (byte*)title;
int count = 0; int count = 0;
while (titlePtr[count] != 0) while (titlePtr[count] != 0)
{ {
count += 1; 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 #endregion
@ -688,16 +641,5 @@ public void Dispose()
imGuiPipeline?.Dispose(); imGuiPipeline?.Dispose();
imGuiSampler?.Dispose(); imGuiSampler?.Dispose();
resourceUploader?.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;
}
}
}