fix native libs

add SdlEvent callback
add OpenWindow function
This commit is contained in:
art0007i
2025-10-02 03:35:32 +02:00
parent 0d3fb60b4c
commit bdca389f2e
5 changed files with 100 additions and 24 deletions
+63 -7
View File
@@ -15,7 +15,14 @@ public class ImGuiInstance
}
public string Name => _name;
/// <summary>
/// Called whenever ImGui is being rendered. You can use ImGui functions inside here.
/// </summary>
public event Action? Layout;
/// <summary>
/// Called whenever the window is processing an event. Returning false means that the event will not be processed further.
/// </summary>
public event Func<SDL.Event, bool>? SdlEvent;
private string _name;
private ConfigEntry<int4> _entry;
@@ -26,6 +33,14 @@ public class ImGuiInstance
internal static ConcurrentQueue<ImGuiInstance> newInstances = new();
internal static ConcurrentQueue<(string, Action<SDL3Window>)> windowRequests = new();
/// <summary>
/// Tries to open the window. If it's already open, nothing happens. This function may be expensive to call rapidly.
/// </summary>
public void OpenWindow()
{
newInstances.Enqueue(this);
}
/// <summary>
/// Gets a reference to the SDL3Window inside of a callback.
/// The callback will be called inside the SDL3 Thread.
@@ -74,7 +89,7 @@ public class ImGuiInstance
if (IsSDL3Running)
return;
_sdl3Thread = new Thread(() => RunSDL3())
_sdl3Thread = new Thread(RunSDL3)
{
Name = $"Resonite ImGui SDL3",
Priority = ThreadPriority.Highest,
@@ -93,16 +108,21 @@ public class ImGuiInstance
{
while (newInstances.TryDequeue(out var request))
{
if (windows.ContainsKey(request.Name)) continue;
SDL3Window app = new SDL3Window("ImGuiContext: " + request.Name, request._entry.Value.x, request._entry.Value.y, request._entry.Value.z, request._entry.Value.w);
app.WindowRectModified += (rect) => request._entry.Value = rect;
// TODO: maybe listen to config changes to resize window
// request._entry.SettingChanged += (_, _) => { };
app.RenderCallback = request.Layout!;
windows[request.Name] = app;
var winId = SDL.GetWindowID(app.Window);
if (!windowsById.TryAdd(winId, app))
app.RenderCallback = request.Layout;
app.SdlEventReceived = request.SdlEvent;
if (!windows.TryAdd(request.Name, app))
{
Plugin.Log.LogError($"Failed to add window with id {(uint) app.Window}, name {request.Name}!");
Plugin.Log.LogError($"Failed to add window with name {request.Name}!");
}
if (!windowsById.TryAdd(app.SdlWindowId, app))
{
Plugin.Log.LogError($"Failed to add window with id {app.SdlWindowId}, name {request.Name}!");
}
}
for (int i = 0; i < windowRequests.Count; i++)
@@ -119,7 +139,6 @@ public class ImGuiInstance
}
}
}
while (SDL.PollEvent(out SDL.Event ev))
{
if (windowsById.TryGetValue(ev.Window.WindowID, out var window))
@@ -128,10 +147,47 @@ public class ImGuiInstance
}
}
var removed = new HashSet<(string, uint)>();
foreach (var (key, window) in windows)
{
if(window.Disposed)
{
removed.Add((key, window.SdlWindowId));
continue;
}
window.SetContext();
if (Plugin.CancellationToken.IsCancellationRequested)
{
window.ForceDispose();
continue;
}
if (window.ShouldClose)
{
removed.Add((key, window.SdlWindowId));
window.Dispose();
continue;
}
window.RunOneFrame();
}
foreach (var (k, k2) in removed)
{
var b = windows.Remove(k);
var b2 = windowsById.Remove(k2);
Plugin.Log.LogDebug($"Removed window {k}, success codes: {b}|{b2}");
}
if (Plugin.CancellationToken.IsCancellationRequested)
{
break;
}
// Prevent busy looping when nothing is happening.
if (windows.Count == 0)
{
Thread.Sleep(1000);
}
}
}
catch (Exception e)
+1 -1
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Version>2.0.0</Version>
<Version>2.1.0</Version>
<Authors>art0007i</Authors>
<TargetFramework>net9.0</TargetFramework>
<RepositoryUrl>https://github.com/art0007i/ResoniteImGuiLib</RepositoryUrl>
+31 -13
View File
@@ -1,5 +1,4 @@
using CodeGenerationConfig;
using Elements.Core;
using Elements.Core;
using ImGuiNET;
using SDL3;
using System.Diagnostics;
@@ -12,12 +11,14 @@ public class SDL3Window : IDisposable
public readonly IntPtr Device;
public readonly ImGuiSDL3 Platform;
public readonly ImGuiSDL3Renderer Renderer;
public readonly uint SdlWindowId;
internal readonly Queue<SDL.Event> EventQueue = new();
internal Action? RenderCallback { get; set; }
internal Func<SDL.Event, bool>? SdlEventReceived { get; set; }
public event Action<int4>? WindowRectModified;
public color? ClearColor = null;
public Action? RenderCallback { get; set; }
private readonly Stopwatch _timer = Stopwatch.StartNew();
private TimeSpan _time = TimeSpan.Zero;
@@ -57,9 +58,11 @@ public class SDL3Window : IDisposable
Platform = new ImGuiSDL3(Window, Device);
Renderer = new ImGuiSDL3Renderer(Device);
SdlWindowId = SDL.GetWindowID(Window);
//ImGuiManager.TriggerImGuiRecreated();
}
public bool Disposed => _disposed;
private bool _disposed;
~SDL3Window()
@@ -68,6 +71,11 @@ public class SDL3Window : IDisposable
}
public void Dispose()
{
Dispose(false);
}
public void ForceDispose()
{
Dispose(true);
GC.SuppressFinalize(this);
@@ -102,8 +110,8 @@ public class SDL3Window : IDisposable
if (_imGuiContext != IntPtr.Zero)
{
ImGui.SetCurrentContext(_imGuiContext);
ImGui.DestroyContext();
ImGui.SetCurrentContext(IntPtr.Zero);
ImGui.DestroyContext(_imGuiContext);
_imGuiContext = IntPtr.Zero;
}
@@ -118,12 +126,15 @@ public class SDL3Window : IDisposable
}
}
public void SetContext()
{
ImGui.SetCurrentContext(_imGuiContext);
}
public void RunOneFrame()
{
if (_disposed) return;
ImGui.SetCurrentContext(_imGuiContext);
ImGui.GetIO().DeltaTime = (float) (_timer.Elapsed - _time).TotalSeconds;
_time = _timer.Elapsed;
@@ -136,14 +147,10 @@ public class SDL3Window : IDisposable
Render();
if (_shouldClose || Plugin.CancellationToken.IsCancellationRequested)
{
Dispose();
}
ImGui.SetCurrentContext(IntPtr.Zero);
}
private bool _shouldClose;
public bool ShouldClose;
private void PollEvents()
{
@@ -154,6 +161,17 @@ public class SDL3Window : IDisposable
while (EventQueue.TryDequeue(out var ev))
{
var skip = false;
foreach (var func in Delegate.EnumerateInvocationList(SdlEventReceived))
{
if (!func(ev))
{
skip = true;
break;
}
}
if (skip) continue;
Platform.ProcessEvent(ev);
switch ((SDL.EventType) ev.Type)
@@ -168,7 +186,7 @@ public class SDL3Window : IDisposable
case SDL.EventType.Terminating:
case SDL.EventType.WindowCloseRequested:
case SDL.EventType.Quit:
_shouldClose = true;
ShouldClose = true;
break;
case SDL.EventType.WindowResized:
SetupScreenClipRect();