improved ECS and added new render component

This commit is contained in:
2025-11-08 11:33:07 +01:00
parent 24cf84491f
commit 2f07a00173
4 changed files with 67 additions and 35 deletions

View File

@ -0,0 +1,8 @@
using Silk.NET.OpenGL;
namespace EngineSharp.Core.ECS;
public abstract class RenderComponent : IComponent
{
internal abstract void Render(GL gl);
}

View File

@ -1,13 +1,15 @@
using System.Linq; using System.Linq;
using Silk.NET.OpenGL;
namespace EngineSharp.Core.ECS; namespace EngineSharp.Core.ECS;
public class Scene public class Scene
{ {
private Dictionary<long, LogicComponent> _logicComponents = new(); private readonly Dictionary<long, List<LogicComponent>> _logicComponents = new();
private Dictionary<long, DataComponent> _dataComponents = new(); private readonly Dictionary<long, List<DataComponent>> _dataComponents = new();
private readonly Dictionary<long, List<RenderComponent>> _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) public Entity CreateEntity(string name)
{ {
@ -16,63 +18,80 @@ public class Scene
internal void StartComponents() 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) 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<T>(Entity entity, T component)
where T : class, IComponent
{ {
switch (component) switch (component)
{ {
case LogicComponent logic: case LogicComponent logic:
_logicComponents.TryAdd(entity.Id, logic); AddComponent(entity.Id, logic, _logicComponents);
break; break;
case DataComponent data: case DataComponent data:
_dataComponents.TryAdd(entity.Id, data); AddComponent(entity.Id, data, _dataComponents);
break;
case RenderComponent render:
AddComponent(entity.Id, render, _renderComponents);
break; break;
} }
} }
internal IComponent? GetComponent(Entity entity, IComponent component) internal T? GetComponent<T>(Entity entity, T component)
where T : class, IComponent
{ {
switch (component) return component switch
{ {
case LogicComponent logic: LogicComponent => GetComponent<T, LogicComponent>(entity.Id, _logicComponents),
return GetComponent(entity.Id, logic); DataComponent => GetComponent<T, DataComponent>(entity.Id, _dataComponents),
case DataComponent data: RenderComponent => GetComponent<T, RenderComponent>(entity.Id, _renderComponents),
return GetComponent(entity.Id, data); _ => null
default: };
return null;
}
} }
private LogicComponent? GetComponent(long id, LogicComponent component) private static TComponent? GetComponent<TComponent, TArchetype>(long id, Dictionary<long, List<TArchetype>> 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<TComponent>().SingleOrDefault();
} }
return null; return null;
} }
private DataComponent? GetComponent(long id, DataComponent component)
{
if (_dataComponents.TryGetValue(id, out var data))
{
return data;
}
return null; private static void AddComponent<TComponent, TArchetype>(long id, TComponent component, Dictionary<long, List<TArchetype>> componentStore)
where TArchetype : class, IComponent
where TComponent : TArchetype
{
if (componentStore.TryGetValue(id, out var components))
{
components.Add(component);
}
else
{
componentStore.Add(id, [component]);
}
} }
} }

View File

@ -80,8 +80,12 @@ internal class OpenGLEngine : IEngine
var viewMatrix = _camera.ViewMatrix; var viewMatrix = _camera.ViewMatrix;
// TODO: Here render all meshes etc. // 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) // 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<int> newDimensions) private void OnResize(Vector2D<int> newDimensions)

View File

@ -1,14 +1,15 @@
using Silk.NET.OpenGL; using EngineSharp.Core.ECS;
using Silk.NET.OpenGL;
namespace EngineSharp.Core.Rendering; namespace EngineSharp.Core.Rendering;
public class MeshRenderer public class MeshRenderer : RenderComponent
{ {
public Mesh Mesh { get; set; } public Mesh Mesh { get; set; }
private uint vao, vbo, ebo; private uint vao, vbo, ebo;
internal void Render(GL gl) internal override void Render(GL gl)
{ {
GenerateRenderableMesh(gl); GenerateRenderableMesh(gl);
gl.BindVertexArray(vao); gl.BindVertexArray(vao);