diff --git a/src/CortexEngine.App/Program.cs b/src/CortexEngine.App/Program.cs index ceb2e3b..d4c794e 100644 --- a/src/CortexEngine.App/Program.cs +++ b/src/CortexEngine.App/Program.cs @@ -1,4 +1,6 @@ +using System.Numerics; using Engine.Core; +using Engine.Core.Components; using Engine.Graphics; using Engine.Graphics.Vulkan; using Flecs.NET.Core; @@ -9,17 +11,31 @@ class Program { static async Task Main(string[] args) { - Console.WriteLine("Cortex Engine — Vulkan Triangle (pure P/Invoke)..."); + Console.WriteLine("Cortex Engine — Vulkan (pure P/Invoke)..."); try { VulkanBackendRegistrar.EnsureRegistered(); using var renderContext = RenderBackendFactory.Create("vulkan", 1280, 720, enableValidation: true); var window = renderContext.Window; + var input = window.Input; using var renderer = renderContext.CreateRenderer(); using var world = World.Create(); + var cameraEntity = world.Entity("Camera") + .Set(new Camera( + new Vector3(0, 0, -6), + new Vector3(0, 0, 0), + Vector3.UnitY, + MathF.PI / 4f, + 1280f / 720f, + 0.1f, + 100f)); + + var cameraController = new FreeFlyCameraController(cameraEntity); + Console.WriteLine("Camera: FreeFly (WASD + right-click mouse look, Q/E up/down, Shift boost)"); + var lastWidth = window.Width; var lastHeight = window.Height; var frames = 0; @@ -30,14 +46,20 @@ class Program { timing.Tick(); window.PumpEvents(); + input.BeginFrame(); if (window.Width != lastWidth || window.Height != lastHeight) { lastWidth = window.Width; lastHeight = window.Height; renderContext.Resize(lastWidth, lastHeight); + ref var cam = ref cameraEntity.Ensure(); + cam.AspectRatio = (float)lastWidth / lastHeight; + cameraEntity.Set(cam); } + cameraController.Update(input, (float)timing.DeltaTime); + renderer.RenderWorld(world); frames++; diff --git a/src/Engine.Graphics.Vulkan/VulkanRenderer.cs b/src/Engine.Graphics.Vulkan/VulkanRenderer.cs index 0053d3a..7e7a3ae 100644 --- a/src/Engine.Graphics.Vulkan/VulkanRenderer.cs +++ b/src/Engine.Graphics.Vulkan/VulkanRenderer.cs @@ -49,28 +49,29 @@ internal sealed unsafe class VulkanRenderer : IRenderer, Engine.Graphics.IScreen ctx.GraphicsQueue, ctx, mesh.Indices); } - private static Mesh LoadMesh(string path) - { - if (!File.Exists(path)) - { - var altPath = Path.Combine(AppContext.BaseDirectory, path); - if (!File.Exists(altPath)) - { - altPath = Path.Combine(AppContext.BaseDirectory, "Content", Path.GetFileName(path)); - if (!File.Exists(altPath)) - throw new FileNotFoundException($"Mesh file not found: {path}"); - } - return ObjLoader.Load(altPath, new Vector3(0.8f, 0.6f, 0.3f)); - } - return ObjLoader.Load(path, new Vector3(0.8f, 0.6f, 0.3f)); - } - public void RenderWorld(World world) { - Render(); + var vp = Matrix4x4.Identity; + var found = false; + world.Each((Entity e, ref Camera cam) => + { + var aspect = (float)_swapchain.Extent.Width / (float)_swapchain.Extent.Height; + cam.AspectRatio = aspect; + vp = cam.GetViewMatrix() * cam.GetProjectionMatrix(); + found = true; + }); + + if (!found) + { + var aspect = (float)_swapchain.Extent.Width / (float)_swapchain.Extent.Height; + vp = Matrix4x4.CreateLookAt(new Vector3(0, 0, -6), Vector3.Zero, Vector3.UnitY) + * Matrix4x4.CreatePerspectiveFieldOfView(MathF.PI / 4f, aspect, 0.1f, 100f); + } + + Render(vp); } - private void Render() + private void Render(Matrix4x4 vp) { _frameResources.WaitFrame(_frameIndex); @@ -82,7 +83,7 @@ internal sealed unsafe class VulkanRenderer : IRenderer, Engine.Graphics.IScreen { _swapchain.Recreate(_ctx.SurfaceExtent.Width == 0 ? 1280 : (int)_ctx.SurfaceExtent.Width, _ctx.SurfaceExtent.Height == 0 ? 720 : (int)_ctx.SurfaceExtent.Height); - Render(); + Render(vp); return; } @@ -91,7 +92,6 @@ internal sealed unsafe class VulkanRenderer : IRenderer, Engine.Graphics.IScreen _totalTime += 0.016f; - var vp = ComputeViewProjection(); _frameResources.UpdateUbo(_frameIndex, &vp, VulkanFrameResources.UboSize); var cmd = _frameResources.CommandBuffers[_frameIndex]; @@ -263,14 +263,6 @@ internal sealed unsafe class VulkanRenderer : IRenderer, Engine.Graphics.IScreen _frameIndex = (_frameIndex + 1) % VulkanFrameResources.MaxFramesInFlight; } - private Matrix4x4 ComputeViewProjection() - { - var aspect = (float)_swapchain.Extent.Width / (float)_swapchain.Extent.Height; - var proj = Matrix4x4.CreatePerspectiveFieldOfView(MathF.PI / 4f, aspect, 0.1f, 100f); - var view = Matrix4x4.CreateLookAt(new Vector3(0, 0, -6), Vector3.Zero, Vector3.UnitY); - return view * proj; - } - private static void TransitionImageLayout(VkCommandBuffer cmd, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, ulong srcStage, ulong srcAccess, @@ -337,6 +329,22 @@ internal sealed unsafe class VulkanRenderer : IRenderer, Engine.Graphics.IScreen Vk.vkCmdPipelineBarrier2(cmd, &depInfo); } + private static Mesh LoadMesh(string path) + { + if (!File.Exists(path)) + { + var altPath = Path.Combine(AppContext.BaseDirectory, path); + if (!File.Exists(altPath)) + { + altPath = Path.Combine(AppContext.BaseDirectory, "Content", Path.GetFileName(path)); + if (!File.Exists(altPath)) + throw new FileNotFoundException($"Mesh file not found: {path}"); + } + return ObjLoader.Load(altPath, new Vector3(0.8f, 0.6f, 0.3f)); + } + return ObjLoader.Load(path, new Vector3(0.8f, 0.6f, 0.3f)); + } + private static byte[] LoadShader(string path) { if (!File.Exists(path))