feat: Step 3 Flecs.NET ECS integration with animated triangle

- Add Transform component and ECS world in Engine.Core.
- TriangleRenderer.RenderWorld queries entities and applies transforms.
- Animate a single triangle entity in Program.cs.
- Pin ppy.SDL3-CS to 2026.520.0 and add linux-x64 RID for bundled native SDL3.
- Add Flecs.NET.Debug/Release 4.0.4-build.546 per configuration.
- Update SDL3 API usage for the 2026.520.0 binding.
- Update architecture file to Silk.NET.Vulkan and Flecs 4.0.4.
This commit is contained in:
emil28092005
2026-06-16 19:06:04 +03:00
parent b32469d42d
commit 608c3c24a8
10 changed files with 112 additions and 10 deletions
@@ -20,6 +20,8 @@
<ItemGroup>
<PackageReference Include="Silk.NET.Vulkan" Version="2.21.0" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.21.0" />
<PackageReference Include="Flecs.NET.Debug" Version="4.0.4-build.546" Condition="'$(Configuration)' == 'Debug'" />
<PackageReference Include="Flecs.NET.Release" Version="4.0.4-build.546" Condition="'$(Configuration)' == 'Release'" />
</ItemGroup>
<ItemGroup>
+46 -3
View File
@@ -1,12 +1,15 @@
using System;
using System.Numerics;
using Flecs.NET.Core;
using Silk.NET.Core;
using Silk.NET.Vulkan;
using Engine.Core.Components;
namespace Engine.Graphics;
/// <summary>
/// Renders a colored triangle using a vertex buffer and a simple graphics pipeline.
/// Uses Silk.NET.Vulkan.
/// Uses Silk.NET.Vulkan and reads entity transforms from the ECS world.
/// </summary>
public sealed unsafe class TriangleRenderer : IDisposable
{
@@ -115,7 +118,7 @@ public sealed unsafe class TriangleRenderer : IDisposable
}
}
public void RenderFrame()
public void RenderWorld(World world)
{
var frame = _currentFrame % 2;
@@ -160,7 +163,14 @@ public sealed unsafe class TriangleRenderer : IDisposable
var vertexBuffer = _vertexBuffer.Buffer;
var offset = 0ul;
_context.Vk.CmdBindVertexBuffers(cmd, 0, 1, &vertexBuffer, &offset);
_context.Vk.CmdDraw(cmd, 3, 1, 0, 0);
var drawCmd = cmd;
world.Each((Entity e, ref Transform transform) =>
{
var bytes = BuildTriangleVertices(transform);
_vertexBuffer.Update(bytes);
_context.Vk.CmdDraw(drawCmd, 3, 1, 0, 0);
});
_context.Vk.CmdEndRenderPass(cmd);
_context.Vk.EndCommandBuffer(cmd);
@@ -197,6 +207,39 @@ public sealed unsafe class TriangleRenderer : IDisposable
_currentFrame++;
}
private byte[] BuildTriangleVertices(Transform transform)
{
var matrix = transform.GetMatrix();
var positions = new Vector3[]
{
new Vector3(0.0f, -0.5f, 0.0f),
new Vector3(0.5f, 0.5f, 0.0f),
new Vector3(-0.5f, 0.5f, 0.0f)
};
var colors = new[]
{
new Vector3(1.0f, 0.0f, 0.0f),
new Vector3(0.0f, 1.0f, 0.0f),
new Vector3(0.0f, 0.0f, 1.0f)
};
var bytes = new byte[3 * 5 * sizeof(float)];
fixed (byte* p = bytes)
{
var dst = (float*)p;
for (var i = 0; i < 3; i++)
{
var transformed = Vector3.Transform(positions[i], matrix);
dst[i * 5 + 0] = transformed.X;
dst[i * 5 + 1] = transformed.Y;
dst[i * 5 + 2] = colors[i].X;
dst[i * 5 + 3] = colors[i].Y;
dst[i * 5 + 4] = colors[i].Z;
}
}
return bytes;
}
public void Dispose()
{
_context.Vk.DeviceWaitIdle(_context.Device);
+8
View File
@@ -102,6 +102,14 @@ public sealed unsafe class VertexBuffer : IDisposable
_context.Vk.UnmapMemory(_context.Device, Memory);
}
public void Update(ReadOnlySpan<byte> data)
{
if ((ulong)data.Length != Size)
throw new ArgumentException($"Vertex buffer update size mismatch: {data.Length} != {Size}");
CopyData(data);
}
public void Dispose()
{
_context.Vk.DeviceWaitIdle(_context.Device);