fixed shader creation and made plan for fixing switching scenes

This commit is contained in:
2025-12-20 12:29:14 +01:00
parent bde20fbf01
commit ad5d46ff0e
8 changed files with 72 additions and 62 deletions

View File

@@ -45,7 +45,8 @@ public class Scene
// TODO: retrieve the transform component of the entity to generate the model matrix
// TODO: make a record which holds the matrices and maybe more, so the parameter list doesn't explode
var modelMatrix = Matrix4X4<float>.Identity;
components.ForEach(c => c.Render(gl, projectionMatrix, viewMatrix, modelMatrix));
var t = Matrix4X4.CreateTranslation(0, 0, -10f);
components.ForEach(c => c.Render(gl, projectionMatrix, viewMatrix, t));
}
}

View File

@@ -9,10 +9,11 @@ public interface IEngine
{
void Start();
void Stop();
Scene CreateScene();
Shader CreateShader(string vertexShaderPath, string fragmentShaderPath);
Scene CreateScene();
void SetCurrentScene(Scene scene);
Shader GetShader(string vertexShaderPath);
}
public enum GraphicsAPI
@@ -27,7 +28,7 @@ public static class EngineFactory
{
return api switch
{
GraphicsAPI.OpenGL => new OpenGLEngine(windowOptions),
GraphicsAPI.OpenGL => OpenGLEngine.Create(windowOptions),
GraphicsAPI.Vulkan => throw new NotSupportedException($"The graphics API {api} is not currently supported"),
_ => throw new ArgumentException($"The graphics API {api} is unknown.", nameof(api))
};

View File

@@ -18,7 +18,7 @@ internal class OpenGLEngine : Engine
private PerspectiveCamera _camera = null!;
private Scene? _currentScene;
public OpenGLEngine(WindowOptions windowOptions)
private OpenGLEngine(WindowOptions windowOptions)
{
_window = Window.Create(windowOptions);
_window.Load += OnLoad;
@@ -28,7 +28,15 @@ internal class OpenGLEngine : Engine
_scenes = [];
}
public static IEngine Create(WindowOptions windowOptions)
{
var engine = new OpenGLEngine(windowOptions);
SingletonInstance = engine;
return engine;
}
public override void Start()
{
_window.Run();
@@ -39,6 +47,9 @@ internal class OpenGLEngine : Engine
_window.Close();
}
// TODO: pass in name as parameter
// Name must be unique and is used to switch scenes while the application is running.
// We need exactly one default scene which is the initial scene (call SetCurrentScene during the Load() method
public override Scene CreateScene()
{
var scene = new Scene();
@@ -46,32 +57,22 @@ internal class OpenGLEngine : Engine
return scene;
}
public override Shader CreateShader(string vertexShaderPath, string fragmentShaderPath)
private void InitialiseShaders(IEnumerable<string> vertexShaderFiles)
{
if (_currentScene is null)
foreach (var vertexShaderFile in vertexShaderFiles)
{
throw new InvalidOperationException("Cannot create a shader if there is no scene set as the current scene.");
}
var shader = new Shader(vertexShaderPath, fragmentShaderPath);
RegisterShader(_currentScene, shader);
return shader;
}
protected override void InitialiseShaders(Scene scene)
{
if (_shaders.TryGetValue(scene, out var shaders))
{
shaders.ForEach(s => s.Initialize(_gl));
var fragmentShaderFile = vertexShaderFile.Replace(".vert", ".frag");
var shader = new Shader(vertexShaderFile, fragmentShaderFile);
shader.Initialize(_gl);
_shaders.Add(vertexShaderFile, shader);
}
}
public void SetCurrentScene(Scene scene)
public override void SetCurrentScene(Scene scene)
{
_currentScene = scene;
_currentScene.InitialiseComponents();
InitialiseShaders(scene);
}
private void OnLoad()
@@ -83,6 +84,9 @@ internal class OpenGLEngine : Engine
_gl.Enable(EnableCap.DepthTest);
_camera = new PerspectiveCamera(Vector3D<float>.Zero, _window.FramebufferSize);
InitialiseShaders(Directory.GetFiles("./assets/shaders", "*.vert"));
// TODO: SetCurrentScene -> with the default scene
}
private void OnUpdate(double deltaTime)

View File

@@ -4,25 +4,27 @@ namespace EngineSharp.Core.Rendering;
internal abstract class Engine : IEngine
{
protected readonly Dictionary<Scene, List<Shader>> _shaders = [];
protected static Engine? SingletonInstance
{
get;
set => field = field is null
? value
: throw new InvalidOperationException("Only one engine can exist at a time.");
}
protected readonly Dictionary<string, Shader> _shaders = [];
public static Engine Instance => SingletonInstance ?? throw new InvalidOperationException("No engine has been created yet. Cannot return an instance.");
public abstract void Start();
public abstract void Stop();
public abstract Scene CreateScene();
public abstract Shader CreateShader(string vertexShaderPath, string fragmentShaderPath);
public abstract void SetCurrentScene(Scene scene);
protected void RegisterShader(Scene scene, Shader shader)
public Shader GetShader(string vertexShaderPath)
{
if (_shaders.TryGetValue(scene, out var shaders))
{
shaders.Add(shader);
}
else
{
_shaders.Add(scene, [shader]);
}
Instance._shaders.TryGetValue(vertexShaderPath, out var shader);
return shader ?? throw new ArgumentException($"Shader '{vertexShaderPath}' does not exist.");
}
protected abstract void InitialiseShaders(Scene scene);
}

View File

@@ -1,5 +1,4 @@
using System.IO;
using EngineSharp.Core.Rendering.Exceptions;
using EngineSharp.Core.Rendering.Exceptions;
using Silk.NET.Maths;
using Silk.NET.OpenGL;
@@ -15,15 +14,17 @@ public class Shader
private GL? _gl; // not as a variable. In the future it should be possible to compile the shaders beforehand. Right now, all shaders are JIT compiled which isn't great
private uint? _shaderProgramId;
// TODO: Make this public. The paths are then used as an index into a dictionary. This dictionary stores the shaderProgramId (maybe only use one path as an index, as the other shader should have the same name, just with a different file ending)
// With this, the shaders can be compiled once the engine is started (shaders must be in folder "assets/shaders"). With this I don't have to worry how I can create the shader class and make it compile the shader etc.
// Maybe the dict needs to also store the GL context so the shader can be used ans values can be set on it, but we will see
internal Shader(string pathToVertexShader, string pathToFragmentShader)
{
_vertexCode = File.ReadAllText(pathToVertexShader);
_fragmentCode = File.ReadAllText(pathToFragmentShader);
}
public static Shader GetShader(string pathToVertexShader)
{
return Engine.Instance.GetShader(pathToVertexShader);
}
/// <summary>
/// Initialises the shader, by compiling it and making it ready to be used in the application. <br/>
/// Only initialises the first time it is called. <b>Is a NoOp every subsequent call.</b>

View File

@@ -18,7 +18,9 @@
</ItemGroup>
<ItemGroup>
<Folder Include="assets\" />
<Content Include="assets\**">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>

View File

@@ -9,19 +9,20 @@ public class Planet : Core.ECS.LogicComponent
public override void Initialise()
{
// var material = new Material
// {
// Shader = shader,
// };
// var sphereGenerator = new IcoSphere
// {
// Resolution = 10,
// Material = material,
// };
// PlanetMesh = new MeshRenderer
// {
// Mesh = sphereGenerator.CreateSphere(),
// };
var shader = Shader.GetShader("./assets/shaders/sphere.vert");
var material = new Material
{
Shader = shader,
};
var sphereGenerator = new IcoSphere
{
Resolution = 10,
Material = material,
};
PlanetMesh = new MeshRenderer
{
Mesh = sphereGenerator.CreateSphere(),
};
}
public override void OnUpdate(double deltaTime)

View File

@@ -1,6 +1,4 @@
using Engine_silk.NET;
using EngineSharp.Core;
using EngineSharp.Core.Rendering;
using EngineSharp.Core;
using Silk.NET.Maths;
using Silk.NET.Windowing;
using GraphicsAPI = EngineSharp.Core.GraphicsAPI;
@@ -9,6 +7,7 @@ namespace EngineSharp;
internal static class Program
{
private static void Main(string[] args)
{
var options = WindowOptions.Default with
@@ -20,11 +19,10 @@ internal static class Program
var engine = EngineFactory.Create(GraphicsAPI.OpenGL, options);
var mainScene = engine.CreateScene();
var planet = mainScene.CreateEntity("planet");
var shader = engine.CreateShader("./assets/shaders/sphere.vert", "./assets/shaders/sphere.frag");
planet.AddComponent(new Planet());
engine.SetCurrentScene(mainScene);
engine.Start();
}
}