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 Silk.NET.OpenGL;
namespace EngineSharp.Core.ECS;
public class Scene
{
private Dictionary<long, LogicComponent> _logicComponents = new();
private Dictionary<long, DataComponent> _dataComponents = new();
private readonly Dictionary<long, List<LogicComponent>> _logicComponents = 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)
{
@ -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<T>(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<T>(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<T, LogicComponent>(entity.Id, _logicComponents),
DataComponent => GetComponent<T, DataComponent>(entity.Id, _dataComponents),
RenderComponent => GetComponent<T, RenderComponent>(entity.Id, _renderComponents),
_ => 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;
}
private DataComponent? GetComponent(long id, DataComponent component)
private static void AddComponent<TComponent, TArchetype>(long id, TComponent component, Dictionary<long, List<TArchetype>> componentStore)
where TArchetype : class, IComponent
where TComponent : TArchetype
{
if (_dataComponents.TryGetValue(id, out var data))
if (componentStore.TryGetValue(id, out var components))
{
return data;
components.Add(component);
}
else
{
componentStore.Add(id, [component]);
}
return null;
}
}

View File

@ -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<int> newDimensions)

View File

@ -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);