Compare commits
4 Commits
NerfedIcon
...
2c839d8fad
Author | SHA1 | Date | |
---|---|---|---|
2c839d8fad | |||
1eb899b240 | |||
7cbb745721 | |||
1e1ed303ad |
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -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
|
||||
|
BIN
Nerfed.Runtime/Assets/Shaders/imgui-frag.spv
Normal file
BIN
Nerfed.Runtime/Assets/Shaders/imgui-frag.spv
Normal file
Binary file not shown.
BIN
Nerfed.Runtime/Assets/Shaders/imgui-vertex.spv
Normal file
BIN
Nerfed.Runtime/Assets/Shaders/imgui-vertex.spv
Normal file
Binary file not shown.
@ -1,7 +1,7 @@
|
||||
using System.Diagnostics;
|
||||
using Nerfed.Runtime.Audio;
|
||||
using Nerfed.Runtime.Graphics;
|
||||
using SDL2;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Nerfed.Runtime;
|
||||
|
||||
@ -39,6 +39,8 @@ public static class Engine
|
||||
private const string WindowTitle = "Nerfed";
|
||||
//..
|
||||
|
||||
private static Gui.GuiController Controller;
|
||||
|
||||
internal static void Run(string[] args)
|
||||
{
|
||||
Timestep = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / TargetTimestep);
|
||||
@ -65,11 +67,17 @@ public static class Engine
|
||||
|
||||
AudioDevice = new AudioDevice();
|
||||
|
||||
Controller = new Gui.GuiController(GraphicsDevice, MainWindow, Color.DarkOliveGreen);
|
||||
Controller.OnGui += () => {
|
||||
ImGuiNET.ImGui.ShowDemoWindow();
|
||||
};
|
||||
|
||||
while (!quit)
|
||||
{
|
||||
Tick();
|
||||
}
|
||||
|
||||
Controller.Dispose();
|
||||
GraphicsDevice.UnclaimWindow(MainWindow);
|
||||
MainWindow.Dispose();
|
||||
GraphicsDevice.Dispose();
|
||||
@ -146,6 +154,7 @@ public static class Engine
|
||||
ProcessSDLEvents();
|
||||
|
||||
// Tick game here...
|
||||
Controller.Update((float)Timestep.TotalSeconds);
|
||||
|
||||
AudioDevice.WakeThread();
|
||||
accumulatedUpdateTime -= Timestep;
|
||||
@ -154,6 +163,7 @@ public static class Engine
|
||||
double alpha = accumulatedUpdateTime / Timestep;
|
||||
|
||||
// Render here..
|
||||
Controller.Render();
|
||||
|
||||
accumulatedDrawTime -= framerateCapTimeSpan;
|
||||
}
|
||||
|
50
Nerfed.Runtime/Gui/GuiClipboard.cs
Normal file
50
Nerfed.Runtime/Gui/GuiClipboard.cs
Normal file
@ -0,0 +1,50 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Nerfed.Runtime.Gui;
|
||||
|
||||
public static unsafe class GuiClipboard
|
||||
{
|
||||
private static IntPtr clipboard;
|
||||
private static readonly Dictionary<Delegate, IntPtr> pinned = new Dictionary<Delegate, IntPtr>();
|
||||
|
||||
public static readonly IntPtr GetFnPtr = GetPointerTo(Get);
|
||||
public static readonly IntPtr SetFnPtr = GetPointerTo(Set);
|
||||
|
||||
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<byte>(bytes, length));
|
||||
bytes[length] = 0;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// Stops the delegate pointer from being collected
|
||||
private static IntPtr GetPointerTo<T>(T fn) where T : Delegate
|
||||
{
|
||||
if (pinned.TryGetValue(fn, out nint ptr))
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
ptr = Marshal.GetFunctionPointerForDelegate(fn);
|
||||
pinned.Add(fn, ptr);
|
||||
return ptr;
|
||||
}
|
||||
}
|
710
Nerfed.Runtime/Gui/GuiController.cs
Normal file
710
Nerfed.Runtime/Gui/GuiController.cs
Normal file
@ -0,0 +1,710 @@
|
||||
// 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 GuiController : 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 GuiTextureStorage textureStorage = new GuiTextureStorage();
|
||||
private readonly Dictionary<Window, GCHandle> windows = new Dictionary<Window, GCHandle>(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 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);
|
||||
|
||||
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<Position2DTextureColorVertex>(),
|
||||
VertexShader = imGuiVertexShader,
|
||||
FragmentShader = imGuiFragmentShader,
|
||||
}
|
||||
);
|
||||
|
||||
BuildFontAtlas();
|
||||
|
||||
io.ConfigFlags = configFlags;
|
||||
//io.MouseDrawCursor = true;
|
||||
|
||||
if (!OperatingSystem.IsWindows())
|
||||
{
|
||||
io.SetClipboardTextFn = GuiClipboard.SetFnPtr;
|
||||
io.GetClipboardTextFn = GuiClipboard.GetFnPtr;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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();
|
||||
UpdateCursor();
|
||||
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<char> input = Keyboard.GetTextInput();
|
||||
if (!input.IsEmpty)
|
||||
{
|
||||
foreach (char c in input)
|
||||
{
|
||||
if (c == '\t')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
io.AddInputCharacter(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
Marshal.FreeHGlobal(platformIO.NativePtr->Monitors.Data);
|
||||
int videoDisplayCount = SDL2.SDL.SDL_GetNumVideoDisplays();
|
||||
IntPtr data = Marshal.AllocHGlobal(Unsafe.SizeOf<ImGuiPlatformMonitor>() * 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<Position2DTextureColorVertex>(
|
||||
graphicsDevice,
|
||||
BufferUsageFlags.Vertex,
|
||||
vertexCount
|
||||
);
|
||||
}
|
||||
|
||||
if (drawDataPtr.TotalIdxCount > indexCount)
|
||||
{
|
||||
imGuiIndexBuffer?.Dispose();
|
||||
|
||||
indexCount = (uint)(drawDataPtr.TotalIdxCount * 1.5f);
|
||||
imGuiIndexBuffer = Graphics.Buffer.Create<ushort>(
|
||||
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<Position2DTextureColorVertex>(cmdList.VtxBuffer.Data.ToPointer(), cmdList.VtxBuffer.Size),
|
||||
n == 0
|
||||
);
|
||||
|
||||
resourceUploader.SetBufferData(
|
||||
imGuiIndexBuffer,
|
||||
indexOffset,
|
||||
new Span<ushort>(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<byte>((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)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
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)
|
||||
{
|
||||
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, GCHandle> window in windows)
|
||||
{
|
||||
if (window.Key == mainWindow) continue;
|
||||
|
||||
graphicsDevice.UnclaimWindow(window.Key);
|
||||
window.Key.Dispose();
|
||||
window.Value.Free();
|
||||
}
|
||||
windows.Clear();
|
||||
}
|
||||
}
|
33
Nerfed.Runtime/Gui/GuiStructs.cs
Normal file
33
Nerfed.Runtime/Gui/GuiStructs.cs
Normal file
@ -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;
|
||||
}
|
35
Nerfed.Runtime/Gui/GuiTextureStorage.cs
Normal file
35
Nerfed.Runtime/Gui/GuiTextureStorage.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using Nerfed.Runtime.Graphics;
|
||||
|
||||
namespace Nerfed.Runtime.Gui;
|
||||
|
||||
public class GuiTextureStorage
|
||||
{
|
||||
private readonly Dictionary<IntPtr, WeakReference<Texture>> pointerToTexture = new Dictionary<IntPtr, WeakReference<Texture>>();
|
||||
|
||||
public IntPtr Add(Texture texture)
|
||||
{
|
||||
if (!pointerToTexture.ContainsKey(texture.Handle))
|
||||
{
|
||||
pointerToTexture.Add(texture.Handle, new WeakReference<Texture>(texture));
|
||||
}
|
||||
return texture.Handle;
|
||||
}
|
||||
|
||||
public Texture GetTexture(IntPtr pointer)
|
||||
{
|
||||
if (!pointerToTexture.TryGetValue(pointer, out WeakReference<Texture> value))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
WeakReference<Texture> result = value;
|
||||
|
||||
if (!result.TryGetTarget(out Texture texture))
|
||||
{
|
||||
pointerToTexture.Remove(pointer);
|
||||
return null;
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
}
|
2
Nerfed.Runtime/Gui/Shaders/generate-spirv.bat
Normal file
2
Nerfed.Runtime/Gui/Shaders/generate-spirv.bat
Normal file
@ -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
|
13
Nerfed.Runtime/Gui/Shaders/imgui-frag.glsl
Normal file
13
Nerfed.Runtime/Gui/Shaders/imgui-frag.glsl
Normal file
@ -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);
|
||||
}
|
BIN
Nerfed.Runtime/Gui/Shaders/imgui-frag.spv
Normal file
BIN
Nerfed.Runtime/Gui/Shaders/imgui-frag.spv
Normal file
Binary file not shown.
20
Nerfed.Runtime/Gui/Shaders/imgui-vertex.glsl
Normal file
20
Nerfed.Runtime/Gui/Shaders/imgui-vertex.glsl
Normal file
@ -0,0 +1,20 @@
|
||||
#version 450
|
||||
|
||||
layout (location = 0) in vec2 in_position;
|
||||
layout (location = 1) in vec2 in_texCoord;
|
||||
layout (location = 2) in vec4 in_color;
|
||||
|
||||
layout (set = 1, binding = 0) uniform ProjectionMatrixBuffer
|
||||
{
|
||||
mat4 projection_matrix;
|
||||
};
|
||||
|
||||
layout (location = 0) out vec4 color;
|
||||
layout (location = 1) out vec2 texCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = projection_matrix * vec4(in_position, 0, 1);
|
||||
color = in_color;
|
||||
texCoord = in_texCoord;
|
||||
}
|
BIN
Nerfed.Runtime/Gui/Shaders/imgui-vertex.spv
Normal file
BIN
Nerfed.Runtime/Gui/Shaders/imgui-vertex.spv
Normal file
Binary file not shown.
@ -1,5 +1,5 @@
|
||||
using System.Numerics;
|
||||
using SDL2;
|
||||
using SDL2;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Nerfed.Runtime;
|
||||
|
||||
@ -65,6 +65,8 @@ internal static class Mouse
|
||||
|
||||
internal static void Update()
|
||||
{
|
||||
wheelX = 0;
|
||||
wheelY = 0;
|
||||
Array.Copy(buttonStates, lastButtonStates, buttonStates.Length);
|
||||
}
|
||||
|
||||
@ -105,8 +107,8 @@ internal static class Mouse
|
||||
|
||||
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)
|
||||
|
1
Nerfed.Runtime/Libraries/ImGui.NET
Submodule
1
Nerfed.Runtime/Libraries/ImGui.NET
Submodule
Submodule Nerfed.Runtime/Libraries/ImGui.NET added at ae493d92a3
@ -12,6 +12,16 @@
|
||||
<Compile Include="Libraries\dav1dfile\csharp\dav1dfile.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="Libraries\ImGui.NET\src\ImGui.NET\ImGui.NET.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="Assets\**\*.*">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
|
@ -3,6 +3,7 @@ namespace Nerfed.Runtime;
|
||||
public enum ScreenMode
|
||||
{
|
||||
Fullscreen,
|
||||
BorderlessFullscreen,
|
||||
Windowed
|
||||
FullscreenBorderless,
|
||||
Windowed,
|
||||
WindowedBorderless
|
||||
}
|
@ -11,6 +11,10 @@ namespace Nerfed.Runtime;
|
||||
/// </summary>
|
||||
public class Window
|
||||
{
|
||||
public event Action<Window, uint, uint> OnResizedEvent;
|
||||
public event Action<Window, int, int> OnMovedEvent;
|
||||
public event Action<Window> OnCloseEvent;
|
||||
|
||||
internal IntPtr Handle { get; }
|
||||
public ScreenMode ScreenMode { get; private set; }
|
||||
public uint Width { get; private set; }
|
||||
@ -33,8 +37,6 @@ public class Window
|
||||
public string Title { get; private set;}
|
||||
|
||||
private bool IsDisposed;
|
||||
private System.Action<uint, uint> SizeChangeCallback = null;
|
||||
|
||||
private static readonly Dictionary<uint, Window> windowsById = new Dictionary<uint, Window>();
|
||||
|
||||
public Window(GraphicsDevice graphicsDevice, WindowCreateInfo windowCreateInfo)
|
||||
@ -54,10 +56,14 @@ public class Window
|
||||
{
|
||||
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,6 +110,9 @@ public class Window
|
||||
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;
|
||||
@ -117,16 +126,19 @@ public class Window
|
||||
Width = newWidth;
|
||||
Height = newHeight;
|
||||
|
||||
if (SizeChangeCallback != null)
|
||||
{
|
||||
SizeChangeCallback(newWidth, newHeight);
|
||||
OnResizedEvent?.Invoke(this, Width, Height);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -140,7 +152,7 @@ public class Window
|
||||
{
|
||||
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,14 +207,6 @@ public class Window
|
||||
SDL.SDL_ShowWindow(Handle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// You can specify a method to run when the window size changes.
|
||||
/// </summary>
|
||||
public void RegisterSizeChangeCallback(System.Action<uint, uint> sizeChangeCallback)
|
||||
{
|
||||
SizeChangeCallback = sizeChangeCallback;
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!IsDisposed)
|
||||
|
@ -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
|
||||
|
BIN
libs/x64/cimgui.dll
(Stored with Git LFS)
Normal file
BIN
libs/x64/cimgui.dll
(Stored with Git LFS)
Normal file
Binary file not shown.
Reference in New Issue
Block a user