feat: ImGui integration + real screenshot capture via Vulkan
ImGui: - ImGui.NET 1.91.6.1 NuGet package - VulkanImGui: font texture upload, ImGui pipeline (blending, no depth), vertex/index buffer streaming - GLSL 450 ImGui shaders (vert: scale/translate push constants, frag: font texture sampler) - Compiled to SPIR-V via @webgpu/glslang - Debug overlay: FPS, camera position, entity count, light list - 1600+ FPS with ImGui active Screenshot: - vkCmdCopyImageToBuffer embedded in main command buffer - Layout transition PresentSrcKHR→TransferSrcOptimal→PresentSrcKHR - Deferred read: staging buffer read on next frame after fence - BMP format written directly to FileStream (row by row) - All 16 camera tour screenshots captured (1280x720x32bpp) All 66 tests pass.
This commit is contained in:
@@ -14,6 +14,7 @@ using Engine.Graphics.Loaders;
|
||||
using Engine.Graphics.Vulkan;
|
||||
using Engine.Physics;
|
||||
using Flecs.NET.Core;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace CortexEngine.App;
|
||||
|
||||
@@ -46,6 +47,16 @@ class Program
|
||||
var input = window.Input;
|
||||
using var renderer = renderContext.CreateRenderer();
|
||||
|
||||
VulkanImGui? imGuiLayer = null;
|
||||
if (!cameraTour && renderer is VulkanRenderer vkRenderer)
|
||||
{
|
||||
ImGui.CreateContext();
|
||||
imGuiLayer = new VulkanImGui(vkRenderer._ctx, vkRenderer._swapchain);
|
||||
vkRenderer.ImGuiLayer = imGuiLayer;
|
||||
ImGui.GetIO().DisplaySize = new System.Numerics.Vector2(window.Width, window.Height);
|
||||
Console.WriteLine("[App] ImGui initialized.");
|
||||
}
|
||||
|
||||
var (modelPath, mcpPort) = ParseArgs(args);
|
||||
var mesh = LoadModel(modelPath);
|
||||
|
||||
@@ -249,6 +260,35 @@ class Program
|
||||
demoScreenshotRequested = true;
|
||||
}
|
||||
|
||||
if (imGuiLayer != null)
|
||||
{
|
||||
ImGui.NewFrame();
|
||||
ImGui.Begin("Cortex Engine Debug");
|
||||
ImGui.Text($"FPS: {currentFps}");
|
||||
ImGui.Text($"Delta: {timing.DeltaTime * 1000.0:F2} ms");
|
||||
ImGui.Text($"Camera: {cameraController.Name}");
|
||||
ImGui.Separator();
|
||||
var cam = cameraEntity.Get<Camera>();
|
||||
ImGui.Text($"Pos: ({cam.Position.X:F2}, {cam.Position.Y:F2}, {cam.Position.Z:F2})");
|
||||
ImGui.Text($"Target: ({cam.Target.X:F2}, {cam.Target.Y:F2}, {cam.Target.Z:F2})");
|
||||
ImGui.Separator();
|
||||
|
||||
var entityCount = 0;
|
||||
world.Each((Entity e, ref Transform _) => entityCount++);
|
||||
ImGui.Text($"Entities: {entityCount}");
|
||||
ImGui.Text($"Press F to toggle camera");
|
||||
|
||||
ImGui.Separator();
|
||||
ImGui.Text("Lights:");
|
||||
world.Each((Entity e, ref Light light) =>
|
||||
{
|
||||
ImGui.Text($" {e.Name()}: {light.Type} I={light.Intensity:F1}");
|
||||
});
|
||||
|
||||
ImGui.End();
|
||||
ImGui.Render();
|
||||
}
|
||||
|
||||
renderer.RenderWorld(world);
|
||||
queue.CompletePendingScreenshots();
|
||||
|
||||
@@ -263,6 +303,7 @@ class Program
|
||||
}
|
||||
|
||||
Console.WriteLine("Shutting down...");
|
||||
imGuiLayer?.Dispose();
|
||||
#if !RELEASE_AOT
|
||||
if (mcpApp != null)
|
||||
await mcpApp.StopAsync();
|
||||
|
||||
Reference in New Issue
Block a user