From 2f07a001737537feb0a5edf562d1b7c0669cf6b4 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sat, 8 Nov 2025 11:33:07 +0100 Subject: [PATCH] improved ECS and added new render component --- .../EngineSharp.Core/ECS/RenderComponent.cs | 8 ++ .../EngineSharp.Core/ECS/Scene.cs | 81 ++++++++++++------- .../EngineSharp.Core/OpenGLEngine.cs | 6 +- .../Rendering/MeshRenderer.cs | 7 +- 4 files changed, 67 insertions(+), 35 deletions(-) create mode 100644 src/EngineSharp.Core/EngineSharp.Core/ECS/RenderComponent.cs diff --git a/src/EngineSharp.Core/EngineSharp.Core/ECS/RenderComponent.cs b/src/EngineSharp.Core/EngineSharp.Core/ECS/RenderComponent.cs new file mode 100644 index 0000000..929fe79 --- /dev/null +++ b/src/EngineSharp.Core/EngineSharp.Core/ECS/RenderComponent.cs @@ -0,0 +1,8 @@ +using Silk.NET.OpenGL; + +namespace EngineSharp.Core.ECS; + +public abstract class RenderComponent : IComponent +{ + internal abstract void Render(GL gl); +} \ No newline at end of file diff --git a/src/EngineSharp.Core/EngineSharp.Core/ECS/Scene.cs b/src/EngineSharp.Core/EngineSharp.Core/ECS/Scene.cs index 745eed9..a777a32 100644 --- a/src/EngineSharp.Core/EngineSharp.Core/ECS/Scene.cs +++ b/src/EngineSharp.Core/EngineSharp.Core/ECS/Scene.cs @@ -1,13 +1,15 @@ using System.Linq; +using Silk.NET.OpenGL; namespace EngineSharp.Core.ECS; public class Scene { - private Dictionary _logicComponents = new(); - private Dictionary _dataComponents = new(); + private readonly Dictionary> _logicComponents = new(); + private readonly Dictionary> _dataComponents = new(); + private readonly Dictionary> _renderComponents = new(); - private long _nextSceneId; // ugly solution but it works + private long _nextSceneId; // not the prettiest solution but it works public Entity CreateEntity(string name) { @@ -16,63 +18,80 @@ public class Scene internal void StartComponents() { - foreach (var component in _logicComponents.Values) + foreach (var components in _logicComponents.Values) { - component.Start(); + components.ForEach(c => c.Start()); } } internal void UpdateComponents(double deltaTime) { - foreach (var component in _logicComponents.Values) + foreach (var components in _logicComponents.Values) { - component.OnUpdate(deltaTime); + components.ForEach(c => c.OnUpdate(deltaTime)); } } - - internal void AddComponent(Entity entity, IComponent component) + + internal void RenderComponents(GL gl) + { + foreach (var components in _renderComponents.Values) + { + components.ForEach(c => c.Render(gl)); + } + } + + internal void AddComponent(Entity entity, T component) + where T : class, IComponent { switch (component) { case LogicComponent logic: - _logicComponents.TryAdd(entity.Id, logic); + AddComponent(entity.Id, logic, _logicComponents); break; case DataComponent data: - _dataComponents.TryAdd(entity.Id, data); + AddComponent(entity.Id, data, _dataComponents); + break; + case RenderComponent render: + AddComponent(entity.Id, render, _renderComponents); break; } } - internal IComponent? GetComponent(Entity entity, IComponent component) + internal T? GetComponent(Entity entity, T component) + where T : class, IComponent { - switch (component) + return component switch { - case LogicComponent logic: - return GetComponent(entity.Id, logic); - case DataComponent data: - return GetComponent(entity.Id, data); - default: - return null; - } + LogicComponent => GetComponent(entity.Id, _logicComponents), + DataComponent => GetComponent(entity.Id, _dataComponents), + RenderComponent => GetComponent(entity.Id, _renderComponents), + _ => null + }; } - private LogicComponent? GetComponent(long id, LogicComponent component) + private static TComponent? GetComponent(long id, Dictionary> componentStore) + where TComponent : class, IComponent { - if (_logicComponents.TryGetValue(id, out var logic)) + // ReSharper disable once ConvertIfStatementToReturnStatement + if (componentStore.TryGetValue(id, out var components)) { - return logic; + return components.OfType().SingleOrDefault(); } return null; } - - private DataComponent? GetComponent(long id, DataComponent component) - { - if (_dataComponents.TryGetValue(id, out var data)) - { - return data; - } - return null; + private static void AddComponent(long id, TComponent component, Dictionary> componentStore) + where TArchetype : class, IComponent + where TComponent : TArchetype + { + if (componentStore.TryGetValue(id, out var components)) + { + components.Add(component); + } + else + { + componentStore.Add(id, [component]); + } } } \ No newline at end of file diff --git a/src/EngineSharp.Core/EngineSharp.Core/OpenGLEngine.cs b/src/EngineSharp.Core/EngineSharp.Core/OpenGLEngine.cs index 0cca0c7..683fd99 100644 --- a/src/EngineSharp.Core/EngineSharp.Core/OpenGLEngine.cs +++ b/src/EngineSharp.Core/EngineSharp.Core/OpenGLEngine.cs @@ -80,8 +80,12 @@ internal class OpenGLEngine : IEngine var viewMatrix = _camera.ViewMatrix; // TODO: Here render all meshes etc. - // On constructing a MeshRenderer, register it somewhere so it can be rendered here (MeshRenderer would then be a component while Mesh would be a normal C# object in the context of an ECS) // MeshRenderer contains a mesh; Mesh contains a material; Material contains a shader and the values for all uniforms of the shader (apart from the matrices; I am not sure how to best handle the model matrix with this approach) + + if (_currentScene is not null) + { + _currentScene.RenderComponents(_gl); + } } private void OnResize(Vector2D newDimensions) diff --git a/src/EngineSharp.Core/EngineSharp.Core/Rendering/MeshRenderer.cs b/src/EngineSharp.Core/EngineSharp.Core/Rendering/MeshRenderer.cs index ecaf096..180caf3 100644 --- a/src/EngineSharp.Core/EngineSharp.Core/Rendering/MeshRenderer.cs +++ b/src/EngineSharp.Core/EngineSharp.Core/Rendering/MeshRenderer.cs @@ -1,14 +1,15 @@ -using Silk.NET.OpenGL; +using EngineSharp.Core.ECS; +using Silk.NET.OpenGL; namespace EngineSharp.Core.Rendering; -public class MeshRenderer +public class MeshRenderer : RenderComponent { public Mesh Mesh { get; set; } private uint vao, vbo, ebo; - internal void Render(GL gl) + internal override void Render(GL gl) { GenerateRenderableMesh(gl); gl.BindVertexArray(vao);