fix: wire complete ImGui window input
This commit is contained in:
+153
-12
@@ -83,6 +83,8 @@ class Program
|
||||
|
||||
var lastWidth = window.Width;
|
||||
var lastHeight = window.Height;
|
||||
var lastDrawableWidth = window.DrawableWidth;
|
||||
var lastDrawableHeight = window.DrawableHeight;
|
||||
var frames = 0;
|
||||
var lastFpsTime = 0.0;
|
||||
var timing = new Timing();
|
||||
@@ -132,13 +134,17 @@ class Program
|
||||
}
|
||||
#endif
|
||||
|
||||
if (window.Width != lastWidth || window.Height != lastHeight)
|
||||
if (window.Width != lastWidth || window.Height != lastHeight ||
|
||||
window.DrawableWidth != lastDrawableWidth || window.DrawableHeight != lastDrawableHeight)
|
||||
{
|
||||
lastWidth = window.Width;
|
||||
lastHeight = window.Height;
|
||||
if (lastWidth > 0 && lastHeight > 0)
|
||||
lastDrawableWidth = window.DrawableWidth;
|
||||
lastDrawableHeight = window.DrawableHeight;
|
||||
if (lastWidth > 0 && lastHeight > 0 &&
|
||||
lastDrawableWidth > 0 && lastDrawableHeight > 0)
|
||||
{
|
||||
renderContext.Resize(lastWidth, lastHeight);
|
||||
renderContext.Resize(lastDrawableWidth, lastDrawableHeight);
|
||||
ref var cam = ref cameraEntity.Ensure<Camera>();
|
||||
cam.AspectRatio = (float)lastWidth / lastHeight;
|
||||
cameraEntity.Set(cam);
|
||||
@@ -215,14 +221,21 @@ class Program
|
||||
|
||||
if (hasImGui)
|
||||
{
|
||||
var displayWidth = Math.Max(window.Width, 1);
|
||||
var displayHeight = Math.Max(window.Height, 1);
|
||||
var drawableWidth = Math.Max(window.DrawableWidth, 1);
|
||||
var drawableHeight = Math.Max(window.DrawableHeight, 1);
|
||||
var framebufferScaleX = (float)drawableWidth / displayWidth;
|
||||
var framebufferScaleY = (float)drawableHeight / displayHeight;
|
||||
var io = ImGui.GetIO();
|
||||
io.DisplaySize = new System.Numerics.Vector2(window.Width, window.Height);
|
||||
io.MousePos = new System.Numerics.Vector2(input.MouseX, input.MouseY);
|
||||
io.MouseDown[0] = input.MouseLeft;
|
||||
io.MouseDown[1] = input.MouseRight;
|
||||
io.MouseDown[2] = input.MouseMiddle;
|
||||
UpdateImGuiInput(io, input);
|
||||
|
||||
renderer.BeginImGuiFrame();
|
||||
renderer.BeginImGuiFrame(
|
||||
displayWidth,
|
||||
displayHeight,
|
||||
framebufferScaleX,
|
||||
framebufferScaleY,
|
||||
(float)timing.DeltaTime);
|
||||
|
||||
ImGui.Begin("Cortex Engine Debug");
|
||||
ImGui.Text($"FPS: {frames}");
|
||||
@@ -388,7 +401,7 @@ class Program
|
||||
}
|
||||
|
||||
var paramsText = sb.ToString();
|
||||
ImGui.SetClipboardText(paramsText);
|
||||
window.SetClipboardText(paramsText);
|
||||
Console.WriteLine("[App] Parameters copied to clipboard:");
|
||||
Console.WriteLine(paramsText);
|
||||
}
|
||||
@@ -406,8 +419,8 @@ class Program
|
||||
recordingPath = $"Videos/cortex_{timestamp}.mp4";
|
||||
Directory.CreateDirectory("Videos");
|
||||
|
||||
var w = window.Width;
|
||||
var h = window.Height;
|
||||
var w = window.DrawableWidth;
|
||||
var h = window.DrawableHeight;
|
||||
var outputPath = recordingPath!;
|
||||
|
||||
// ArgumentList avoids shell-specific quoting rules and works
|
||||
@@ -540,6 +553,134 @@ class Program
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
private static void UpdateImGuiInput(ImGuiIOPtr io, IInputState input)
|
||||
{
|
||||
io.AddMousePosEvent(input.MouseX, input.MouseY);
|
||||
|
||||
foreach (var inputEvent in input.Events)
|
||||
{
|
||||
switch (inputEvent.Type)
|
||||
{
|
||||
case InputEventType.KeyDown:
|
||||
case InputEventType.KeyUp:
|
||||
if (TryMapImGuiKey(inputEvent.Key, out var imguiKey))
|
||||
io.AddKeyEvent(imguiKey, inputEvent.Type == InputEventType.KeyDown);
|
||||
break;
|
||||
|
||||
case InputEventType.TextInput:
|
||||
if (!string.IsNullOrEmpty(inputEvent.Text))
|
||||
io.AddInputCharactersUTF8(inputEvent.Text);
|
||||
break;
|
||||
|
||||
case InputEventType.MouseButtonDown:
|
||||
case InputEventType.MouseButtonUp:
|
||||
io.AddMouseButtonEvent(
|
||||
inputEvent.MouseButton,
|
||||
inputEvent.Type == InputEventType.MouseButtonDown);
|
||||
break;
|
||||
|
||||
case InputEventType.MouseWheel:
|
||||
io.AddMouseWheelEvent(inputEvent.WheelX, inputEvent.WheelY);
|
||||
break;
|
||||
|
||||
case InputEventType.FocusGained:
|
||||
io.AddFocusEvent(true);
|
||||
break;
|
||||
|
||||
case InputEventType.FocusLost:
|
||||
io.AddFocusEvent(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ImGui uses separate virtual modifier keys for shortcuts and navigation.
|
||||
io.AddKeyEvent(ImGuiKey.ModCtrl,
|
||||
input.IsKeyDown(Key.LeftControl) || input.IsKeyDown(Key.RightControl));
|
||||
io.AddKeyEvent(ImGuiKey.ModShift,
|
||||
input.IsKeyDown(Key.LeftShift) || input.IsKeyDown(Key.RightShift));
|
||||
io.AddKeyEvent(ImGuiKey.ModAlt,
|
||||
input.IsKeyDown(Key.LeftAlt) || input.IsKeyDown(Key.RightAlt));
|
||||
}
|
||||
|
||||
private static bool TryMapImGuiKey(Key key, out ImGuiKey imguiKey)
|
||||
{
|
||||
imguiKey = key switch
|
||||
{
|
||||
Key.Space => ImGuiKey.Space,
|
||||
Key.Escape => ImGuiKey.Escape,
|
||||
Key.Enter => ImGuiKey.Enter,
|
||||
Key.Tab => ImGuiKey.Tab,
|
||||
Key.Backspace => ImGuiKey.Backspace,
|
||||
Key.Insert => ImGuiKey.Insert,
|
||||
Key.Delete => ImGuiKey.Delete,
|
||||
Key.Home => ImGuiKey.Home,
|
||||
Key.End => ImGuiKey.End,
|
||||
Key.PageUp => ImGuiKey.PageUp,
|
||||
Key.PageDown => ImGuiKey.PageDown,
|
||||
Key.Left => ImGuiKey.LeftArrow,
|
||||
Key.Right => ImGuiKey.RightArrow,
|
||||
Key.Up => ImGuiKey.UpArrow,
|
||||
Key.Down => ImGuiKey.DownArrow,
|
||||
Key.A => ImGuiKey.A,
|
||||
Key.B => ImGuiKey.B,
|
||||
Key.C => ImGuiKey.C,
|
||||
Key.D => ImGuiKey.D,
|
||||
Key.E => ImGuiKey.E,
|
||||
Key.F => ImGuiKey.F,
|
||||
Key.G => ImGuiKey.G,
|
||||
Key.H => ImGuiKey.H,
|
||||
Key.I => ImGuiKey.I,
|
||||
Key.J => ImGuiKey.J,
|
||||
Key.K => ImGuiKey.K,
|
||||
Key.L => ImGuiKey.L,
|
||||
Key.M => ImGuiKey.M,
|
||||
Key.N => ImGuiKey.N,
|
||||
Key.O => ImGuiKey.O,
|
||||
Key.P => ImGuiKey.P,
|
||||
Key.Q => ImGuiKey.Q,
|
||||
Key.R => ImGuiKey.R,
|
||||
Key.S => ImGuiKey.S,
|
||||
Key.T => ImGuiKey.T,
|
||||
Key.U => ImGuiKey.U,
|
||||
Key.V => ImGuiKey.V,
|
||||
Key.W => ImGuiKey.W,
|
||||
Key.X => ImGuiKey.X,
|
||||
Key.Y => ImGuiKey.Y,
|
||||
Key.Z => ImGuiKey.Z,
|
||||
Key.Zero => ImGuiKey._0,
|
||||
Key.One => ImGuiKey._1,
|
||||
Key.Two => ImGuiKey._2,
|
||||
Key.Three => ImGuiKey._3,
|
||||
Key.Four => ImGuiKey._4,
|
||||
Key.Five => ImGuiKey._5,
|
||||
Key.Six => ImGuiKey._6,
|
||||
Key.Seven => ImGuiKey._7,
|
||||
Key.Eight => ImGuiKey._8,
|
||||
Key.Nine => ImGuiKey._9,
|
||||
Key.F1 => ImGuiKey.F1,
|
||||
Key.F2 => ImGuiKey.F2,
|
||||
Key.F3 => ImGuiKey.F3,
|
||||
Key.F4 => ImGuiKey.F4,
|
||||
Key.F5 => ImGuiKey.F5,
|
||||
Key.F6 => ImGuiKey.F6,
|
||||
Key.F7 => ImGuiKey.F7,
|
||||
Key.F8 => ImGuiKey.F8,
|
||||
Key.F9 => ImGuiKey.F9,
|
||||
Key.F10 => ImGuiKey.F10,
|
||||
Key.F11 => ImGuiKey.F11,
|
||||
Key.F12 => ImGuiKey.F12,
|
||||
Key.LeftShift => ImGuiKey.LeftShift,
|
||||
Key.RightShift => ImGuiKey.RightShift,
|
||||
Key.LeftControl => ImGuiKey.LeftCtrl,
|
||||
Key.RightControl => ImGuiKey.RightCtrl,
|
||||
Key.LeftAlt => ImGuiKey.LeftAlt,
|
||||
Key.RightAlt => ImGuiKey.RightAlt,
|
||||
_ => ImGuiKey.None,
|
||||
};
|
||||
|
||||
return imguiKey != ImGuiKey.None;
|
||||
}
|
||||
|
||||
static int ParseMcpPort(string[] args)
|
||||
{
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
|
||||
@@ -13,6 +13,12 @@ public interface IInputState
|
||||
bool MouseMiddle { get; }
|
||||
float MouseWheelDelta { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Events received since the last <see cref="BeginFrame"/> call.
|
||||
/// Backends that do not expose an event queue may return an empty list.
|
||||
/// </summary>
|
||||
IReadOnlyList<InputEvent> Events => Array.Empty<InputEvent>();
|
||||
|
||||
bool IsKeyDown(Key key);
|
||||
bool IsKeyPressed(Key key);
|
||||
bool IsKeyReleased(Key key);
|
||||
|
||||
@@ -9,6 +9,14 @@ public interface IWindow : IDisposable
|
||||
{
|
||||
int Width { get; }
|
||||
int Height { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the drawable Vulkan framebuffer in physical pixels. This can
|
||||
/// differ from <see cref="Width"/>/<see cref="Height"/> on high-DPI displays.
|
||||
/// </summary>
|
||||
int DrawableWidth => Width;
|
||||
int DrawableHeight => Height;
|
||||
|
||||
bool ShouldClose { get; }
|
||||
|
||||
/// <summary>
|
||||
@@ -27,6 +35,11 @@ public interface IWindow : IDisposable
|
||||
/// </summary>
|
||||
void Close();
|
||||
|
||||
/// <summary>
|
||||
/// Places UTF-8 text on the platform clipboard when supported.
|
||||
/// </summary>
|
||||
void SetClipboardText(string text) { }
|
||||
|
||||
/// <summary>
|
||||
/// Native window handle (e.g. <c>SDL_Window*</c>). Used by backends that need
|
||||
/// the raw OS handle for surface creation. Returns 0 if not applicable.
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
namespace Engine.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Backend-agnostic input event captured during the current frame.
|
||||
/// </summary>
|
||||
public readonly record struct InputEvent(
|
||||
InputEventType Type,
|
||||
Key Key = Key.Unknown,
|
||||
bool IsRepeat = false,
|
||||
int MouseButton = -1,
|
||||
float WheelX = 0,
|
||||
float WheelY = 0,
|
||||
string? Text = null);
|
||||
|
||||
public enum InputEventType
|
||||
{
|
||||
KeyDown,
|
||||
KeyUp,
|
||||
TextInput,
|
||||
MouseButtonDown,
|
||||
MouseButtonUp,
|
||||
MouseWheel,
|
||||
FocusGained,
|
||||
FocusLost,
|
||||
}
|
||||
@@ -7,11 +7,12 @@ namespace Engine.Core;
|
||||
/// SDL3-backed implementation of <see cref="IInputState"/>.
|
||||
/// Populated by polling SDL events via <see cref="ProcessEvent"/> once per frame.
|
||||
/// </summary>
|
||||
public sealed class InputMapping : IInputState
|
||||
public sealed unsafe class InputMapping : IInputState
|
||||
{
|
||||
private readonly HashSet<Key> _keysPressed = new();
|
||||
private readonly HashSet<Key> _keysDown = new();
|
||||
private readonly HashSet<Key> _keysReleased = new();
|
||||
private readonly List<InputEvent> _events = new();
|
||||
|
||||
public int MouseX { get; private set; }
|
||||
public int MouseY { get; private set; }
|
||||
@@ -19,11 +20,13 @@ public sealed class InputMapping : IInputState
|
||||
public bool MouseRight { get; private set; }
|
||||
public bool MouseMiddle { get; private set; }
|
||||
public float MouseWheelDelta { get; private set; }
|
||||
public IReadOnlyList<InputEvent> Events => _events;
|
||||
|
||||
public void BeginFrame()
|
||||
{
|
||||
_keysPressed.Clear();
|
||||
_keysReleased.Clear();
|
||||
_events.Clear();
|
||||
MouseWheelDelta = 0;
|
||||
}
|
||||
|
||||
@@ -38,6 +41,10 @@ public sealed class InputMapping : IInputState
|
||||
if (!_keysDown.Contains(key))
|
||||
_keysPressed.Add(key);
|
||||
_keysDown.Add(key);
|
||||
_events.Add(new InputEvent(
|
||||
InputEventType.KeyDown,
|
||||
Key: key,
|
||||
IsRepeat: evt.key.repeat));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -47,6 +54,7 @@ public sealed class InputMapping : IInputState
|
||||
if (key == Key.Unknown) break;
|
||||
_keysDown.Remove(key);
|
||||
_keysReleased.Add(key);
|
||||
_events.Add(new InputEvent(InputEventType.KeyUp, Key: key));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -57,14 +65,46 @@ public sealed class InputMapping : IInputState
|
||||
|
||||
case SDL_EventType.SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||
SetMouseButton(evt.button.button, true);
|
||||
if (evt.button.button is >= 1 and <= 3)
|
||||
_events.Add(new InputEvent(
|
||||
InputEventType.MouseButtonDown,
|
||||
MouseButton: evt.button.button - 1));
|
||||
break;
|
||||
|
||||
case SDL_EventType.SDL_EVENT_MOUSE_BUTTON_UP:
|
||||
SetMouseButton(evt.button.button, false);
|
||||
if (evt.button.button is >= 1 and <= 3)
|
||||
_events.Add(new InputEvent(
|
||||
InputEventType.MouseButtonUp,
|
||||
MouseButton: evt.button.button - 1));
|
||||
break;
|
||||
|
||||
case SDL_EventType.SDL_EVENT_MOUSE_WHEEL:
|
||||
MouseWheelDelta += evt.wheel.y;
|
||||
_events.Add(new InputEvent(
|
||||
InputEventType.MouseWheel,
|
||||
WheelX: evt.wheel.x,
|
||||
WheelY: evt.wheel.y));
|
||||
break;
|
||||
|
||||
case SDL_EventType.SDL_EVENT_TEXT_INPUT:
|
||||
{
|
||||
var text = SDL3.PtrToStringUTF8(evt.text.text);
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
_events.Add(new InputEvent(InputEventType.TextInput, Text: text));
|
||||
break;
|
||||
}
|
||||
|
||||
case SDL_EventType.SDL_EVENT_WINDOW_FOCUS_GAINED:
|
||||
_events.Add(new InputEvent(InputEventType.FocusGained));
|
||||
break;
|
||||
|
||||
case SDL_EventType.SDL_EVENT_WINDOW_FOCUS_LOST:
|
||||
_keysDown.Clear();
|
||||
MouseLeft = false;
|
||||
MouseRight = false;
|
||||
MouseMiddle = false;
|
||||
_events.Add(new InputEvent(InputEventType.FocusLost));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,16 +18,25 @@ public sealed unsafe class Sdl3Window : IWindow
|
||||
|
||||
public int Width { get; private set; }
|
||||
public int Height { get; private set; }
|
||||
public int DrawableWidth { get; private set; }
|
||||
public int DrawableHeight { get; private set; }
|
||||
public bool ShouldClose { get; private set; }
|
||||
public IInputState Input => _input;
|
||||
public nint Handle => (nint)_window;
|
||||
|
||||
public void Close() => ShouldClose = true;
|
||||
|
||||
public void SetClipboardText(string text)
|
||||
{
|
||||
SDL3.SDL_SetClipboardText(text);
|
||||
}
|
||||
|
||||
public Sdl3Window(string title, int width, int height, bool vulkanSurface = true)
|
||||
{
|
||||
Width = width;
|
||||
Height = height;
|
||||
DrawableWidth = width;
|
||||
DrawableHeight = height;
|
||||
|
||||
if (!SDL3.SDL_Init(SDL_InitFlags.SDL_INIT_VIDEO))
|
||||
throw new InvalidOperationException($"SDL_Init failed: {SDL3.SDL_GetError()}");
|
||||
@@ -49,6 +58,8 @@ public sealed unsafe class Sdl3Window : IWindow
|
||||
|
||||
SDL3.SDL_ShowWindow(_window);
|
||||
SDL3.SDL_RaiseWindow(_window);
|
||||
UpdateDrawableSize();
|
||||
SDL3.SDL_StartTextInput(_window);
|
||||
|
||||
// On Wayland, the compositor needs an event round-trip before mapping
|
||||
// the window. Pump events to flush the show request without blocking.
|
||||
@@ -80,6 +91,16 @@ public sealed unsafe class Sdl3Window : IWindow
|
||||
case SDL_EventType.SDL_EVENT_WINDOW_RESIZED:
|
||||
Width = evt.window.data1;
|
||||
Height = evt.window.data2;
|
||||
UpdateDrawableSize();
|
||||
break;
|
||||
|
||||
case SDL_EventType.SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
|
||||
DrawableWidth = evt.window.data1;
|
||||
DrawableHeight = evt.window.data2;
|
||||
break;
|
||||
|
||||
case SDL_EventType.SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED:
|
||||
UpdateDrawableSize();
|
||||
break;
|
||||
|
||||
case SDL_EventType.SDL_EVENT_KEY_DOWN:
|
||||
@@ -104,11 +125,25 @@ public sealed unsafe class Sdl3Window : IWindow
|
||||
return result;
|
||||
}
|
||||
|
||||
private void UpdateDrawableSize()
|
||||
{
|
||||
if (_window == null) return;
|
||||
|
||||
var pixelWidth = Width;
|
||||
var pixelHeight = Height;
|
||||
if (SDL3.SDL_GetWindowSizeInPixels(_window, &pixelWidth, &pixelHeight))
|
||||
{
|
||||
DrawableWidth = pixelWidth;
|
||||
DrawableHeight = pixelHeight;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
|
||||
SDL3.SDL_StopTextInput(_window);
|
||||
SDL3.SDL_DestroyWindow(_window);
|
||||
SDL3.SDL_Quit();
|
||||
}
|
||||
|
||||
@@ -447,11 +447,13 @@ internal sealed unsafe class VulkanImGui : IDisposable
|
||||
_indexMemory = im;
|
||||
}
|
||||
|
||||
public void NewFrame()
|
||||
public void NewFrame(float displayWidth, float displayHeight,
|
||||
float framebufferScaleX, float framebufferScaleY, float deltaTime)
|
||||
{
|
||||
var io = ImGui.GetIO();
|
||||
io.DisplaySize = new System.Numerics.Vector2(1280, 720);
|
||||
io.DeltaTime = 0.016f;
|
||||
io.DisplaySize = new Vector2(displayWidth, displayHeight);
|
||||
io.DisplayFramebufferScale = new Vector2(framebufferScaleX, framebufferScaleY);
|
||||
io.DeltaTime = MathF.Max(deltaTime, 1f / 1000f);
|
||||
ImGui.NewFrame();
|
||||
}
|
||||
|
||||
@@ -520,13 +522,21 @@ internal sealed unsafe class VulkanImGui : IDisposable
|
||||
{
|
||||
var pcmd = list.CmdBuffer[i];
|
||||
var clip = pcmd.ClipRect;
|
||||
var framebufferScale = io.DisplayFramebufferScale;
|
||||
var clipMinX = MathF.Max(clip.X * framebufferScale.X, 0f);
|
||||
var clipMinY = MathF.Max(clip.Y * framebufferScale.Y, 0f);
|
||||
var clipMaxX = MathF.Min(clip.Z * framebufferScale.X, width);
|
||||
var clipMaxY = MathF.Min(clip.W * framebufferScale.Y, height);
|
||||
if (clipMaxX <= clipMinX || clipMaxY <= clipMinY)
|
||||
continue;
|
||||
|
||||
var scissor = new VkRect2D
|
||||
{
|
||||
Offset = new VkOffset2D { X = (int)clip.X, Y = (int)clip.Y },
|
||||
Offset = new VkOffset2D { X = (int)clipMinX, Y = (int)clipMinY },
|
||||
Extent = new VkExtent2D
|
||||
{
|
||||
Width = (uint)(clip.Z - clip.X),
|
||||
Height = (uint)(clip.W - clip.Y),
|
||||
Width = (uint)(clipMaxX - clipMinX),
|
||||
Height = (uint)(clipMaxY - clipMinY),
|
||||
},
|
||||
};
|
||||
Vk.vkCmdSetScissor(cmd, 0, 1, &scissor);
|
||||
|
||||
@@ -23,7 +23,7 @@ internal sealed class VulkanRenderContext : IRenderContext{
|
||||
};
|
||||
|
||||
_swapchain = new VulkanSwapchain(_ctx.Device, _ctx.PhysicalDevice, _ctx.Surface,
|
||||
surfaceFormat, window.Width, window.Height, _ctx);
|
||||
surfaceFormat, window.DrawableWidth, window.DrawableHeight, _ctx);
|
||||
}
|
||||
|
||||
public IRenderer CreateRenderer()
|
||||
|
||||
@@ -179,9 +179,11 @@ public sealed unsafe class VulkanRenderer : IRenderer, Engine.Graphics.IScreensh
|
||||
return result;
|
||||
}
|
||||
|
||||
public void BeginImGuiFrame()
|
||||
public void BeginImGuiFrame(float displayWidth, float displayHeight,
|
||||
float framebufferScaleX, float framebufferScaleY, float deltaTime)
|
||||
{
|
||||
_imGui?.NewFrame();
|
||||
_imGui?.NewFrame(displayWidth, displayHeight,
|
||||
framebufferScaleX, framebufferScaleY, deltaTime);
|
||||
}
|
||||
|
||||
public void EndImGuiFrame()
|
||||
@@ -296,7 +298,7 @@ public sealed unsafe class VulkanRenderer : IRenderer, Engine.Graphics.IScreensh
|
||||
|
||||
// A minimized window has no drawable surface. Keep the frame fence signaled and wait
|
||||
// for the window event loop to provide a non-zero extent before trying to acquire.
|
||||
if (_window.Width <= 0 || _window.Height <= 0)
|
||||
if (_window.DrawableWidth <= 0 || _window.DrawableHeight <= 0)
|
||||
return;
|
||||
|
||||
// Read captured frame from previous render (GPU has finished by now)
|
||||
@@ -324,7 +326,7 @@ public sealed unsafe class VulkanRenderer : IRenderer, Engine.Graphics.IScreensh
|
||||
// from this frame would leave the next WaitForFrame blocked forever.
|
||||
if (acquireResult == VkResult.ErrorOutOfDateKHR)
|
||||
{
|
||||
RecreateSwapchain(_window.Width, _window.Height);
|
||||
RecreateSwapchain(_window.DrawableWidth, _window.DrawableHeight);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -657,7 +659,7 @@ public sealed unsafe class VulkanRenderer : IRenderer, Engine.Graphics.IScreensh
|
||||
|
||||
if (presentResult == VkResult.ErrorOutOfDateKHR || presentResult == VkResult.SuboptimalKHR)
|
||||
{
|
||||
RecreateSwapchain(_window.Width, _window.Height);
|
||||
RecreateSwapchain(_window.DrawableWidth, _window.DrawableHeight);
|
||||
}
|
||||
|
||||
_frameIndex = (_frameIndex + 1) % VulkanFrameResources.MaxFramesInFlight;
|
||||
|
||||
@@ -17,8 +17,11 @@ public interface IRenderer : IDisposable
|
||||
/// <summary>
|
||||
/// Called before RenderWorld to begin a new ImGui frame.
|
||||
/// Null if the backend doesn't support ImGui.
|
||||
/// <paramref name="displayWidth"/> and <paramref name="displayHeight"/> are
|
||||
/// logical window coordinates; framebuffer scale maps them to pixels.
|
||||
/// </summary>
|
||||
void BeginImGuiFrame() { }
|
||||
void BeginImGuiFrame(float displayWidth, float displayHeight,
|
||||
float framebufferScaleX, float framebufferScaleY, float deltaTime) { }
|
||||
|
||||
/// <summary>
|
||||
/// Called after RenderWorld to render ImGui draw data.
|
||||
|
||||
Reference in New Issue
Block a user