feat: switch default backend to Silk.NET OpenGL

- OpenGLRenderContext: Initialize() + CreateOpenGL() for non-blocking
- OpenGLWindow: Initialize() instead of Run(), CreateGL() method
- Program.cs: default backend is now 'opengl', SwapBuffers per frame
- ImGui guarded: only initialized for RaylibRenderer, ObjectManipulator
  checks _imGuiAvailable before calling ImGui.GetIO()
- 66/66 tests, 145 FPS with OpenGL backend
This commit is contained in:
emil28092005
2026-06-17 20:14:15 +03:00
parent cc9a1a4602
commit 417915e861
6 changed files with 40 additions and 23 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ Size=250,398
Collapsed=0
[Window][Inspector]
Pos=36,302
Pos=112,297
Size=300,425
Collapsed=0
@@ -26,6 +26,7 @@
<ProjectReference Include="..\Engine.Graphics.Vulkan\Engine.Graphics.Vulkan.csproj" />
<ProjectReference Include="..\Engine.AI\Engine.AI.csproj" />
<ProjectReference Include="..\Engine.Physics\Engine.Physics.csproj" />
<ProjectReference Include="..\Engine.Graphics.OpenGL\Engine.Graphics.OpenGL.csproj" />
</ItemGroup>
<ItemGroup>
+5 -1
View File
@@ -28,10 +28,14 @@ public sealed class ObjectManipulator
/// Process input for object picking and dragging.
/// Returns true if input was consumed (ImGui should be ignored).
/// </summary>
private bool _imGuiAvailable;
public void SetImGuiAvailable(bool available) => _imGuiAvailable = available;
public bool ProcessInput(World world, Camera camera, IInputState input)
{
// Skip if ImGui is capturing mouse
if (ImGuiNET.ImGui.GetIO().WantCaptureMouse)
if (_imGuiAvailable && ImGuiNET.ImGui.GetIO().WantCaptureMouse)
{
_isDragging = false;
return false;
+18 -11
View File
@@ -11,6 +11,7 @@ using Engine.Core;
using Engine.Core.Components;
using Engine.Graphics;
using Engine.Graphics.Loaders;
using Engine.Graphics.OpenGL;
using Engine.Graphics.RaylibBackend;
using Engine.Graphics.Vulkan;
using Engine.Physics;
@@ -43,19 +44,22 @@ class Program
RaylibBackendRegistrar.EnsureRegistered();
VulkanBackendRegistrar.EnsureRegistered();
using var renderContext = RenderBackendFactory.Create("raylib", 1280, 720, enableValidation: false);
OpenGLBackendRegistrar.EnsureRegistered();
using var renderContext = RenderBackendFactory.Create("opengl", 1280, 720, enableValidation: false);
var window = renderContext.Window;
var input = window.Input;
using var renderer = renderContext.CreateRenderer();
// ImGui editor layer
var imGuiLayer = new ImGuiLayer();
// ImGui editor layer (Raylib only)
ImGuiLayer? imGuiLayer = null;
var objectManipulator = new ObjectManipulator();
if (!cameraTour)
objectManipulator.SetImGuiAvailable(false);
if (!cameraTour && renderer is RaylibRenderer rlRenderer)
{
imGuiLayer = new ImGuiLayer();
imGuiLayer.Initialize();
if (renderer is RaylibRenderer rlRenderer)
rlRenderer.ImGuiLayer = imGuiLayer;
rlRenderer.ImGuiLayer = imGuiLayer;
objectManipulator.SetImGuiAvailable(true);
}
var (modelPath, mcpPort) = ParseArgs(args);
@@ -283,15 +287,18 @@ class Program
}
// Feed frame data to ImGui before rendering.
imGuiLayer.SetFrameData(world, timing, currentFps);
if (imGuiLayer != null)
imGuiLayer.SetFrameData(world, timing, currentFps);
// Sync selection between manipulator and ImGui
if (objectManipulator.IsDragging && !string.IsNullOrEmpty(objectManipulator.SelectedEntityName))
imGuiLayer.SetSelectedEntity(objectManipulator.SelectedEntityName);
objectManipulator.SetImGuiAvailable(imGuiLayer != null);
renderer.RenderWorld(world);
queue.CompletePendingScreenshots();
// Swap buffers for OpenGL backend
if (renderContext is OpenGLRenderContext glCtx2)
glCtx2.SwapBuffers();
frames++;
if (timing.TotalTime - lastFpsTime >= 1.0)
{
@@ -303,7 +310,7 @@ class Program
}
Console.WriteLine("Shutting down...");
imGuiLayer.Dispose();
imGuiLayer?.Dispose();
#if !RELEASE_AOT
if (mcpApp != null)
await mcpApp.StopAsync();
@@ -1,7 +1,9 @@
using Engine.Core;
using Engine.Graphics;
using Silk.NET.OpenGL;
using Silk.NET.Windowing;
using SilkWindow = Silk.NET.Windowing.IWindow;
using CoreIWindow = Engine.Core.IWindow;
namespace Engine.Graphics.OpenGL;
@@ -12,16 +14,15 @@ public sealed class OpenGLRenderContext : IRenderContext
private OpenGLRenderer? _renderer;
private bool _disposed;
public IWindow Window => _window;
public CoreIWindow Window => _window;
public OpenGLRenderContext(int width, int height, bool enableValidation = false)
{
_window = new OpenGLWindow("Cortex Engine (OpenGL)", width, height);
}
public void OnLoad()
{
_gl = _window.SilkView.CreateOpenGL();
// Initialize() triggers the Load callback which creates the GL context
_window.SilkView.Initialize();
// After Initialize, CreateOpenGL should work
_gl = _window.CreateGL();
_window.OnLoad();
}
@@ -31,10 +32,9 @@ public sealed class OpenGLRenderContext : IRenderContext
return _renderer;
}
public void Resize(int width, int height)
{
_renderer?.SetScreenSize(width, height);
}
public void Resize(int width, int height) => _renderer?.SetScreenSize(width, height);
public void SwapBuffers() => _window.SilkView.SwapBuffers();
public void Dispose()
{
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using Engine.Core;
using Silk.NET.Input;
using Silk.NET.OpenGL;
using Silk.NET.Windowing;
using SilkWindow = Silk.NET.Windowing.IWindow;
@@ -31,6 +32,8 @@ public sealed class OpenGLWindow : Engine.Core.IWindow, IDisposable
_silkWindow = Window.Create(options);
_silkWindow.Closing += () => _shouldClose = true;
// Initialize without Run() — enables non-blocking event loop
_silkWindow.Initialize();
}
public void OnLoad()
@@ -39,6 +42,8 @@ public sealed class OpenGLWindow : Engine.Core.IWindow, IDisposable
_input.Initialize(inputContext);
}
public GL CreateGL() => _silkWindow.CreateOpenGL();
public void PumpEvents() => _silkWindow.DoEvents();
public void Close() => _shouldClose = true;
public string[] GetRequiredVulkanExtensions() => Array.Empty<string>();