diff --git a/src/EngineSharp.Core/EngineSharp.Core/ECS/Scene.cs b/src/EngineSharp.Core/EngineSharp.Core/ECS/Scene.cs index c01ecab..2ef75e3 100644 --- a/src/EngineSharp.Core/EngineSharp.Core/ECS/Scene.cs +++ b/src/EngineSharp.Core/EngineSharp.Core/ECS/Scene.cs @@ -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.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)); } } diff --git a/src/EngineSharp.Core/EngineSharp.Core/IEngine.cs b/src/EngineSharp.Core/EngineSharp.Core/IEngine.cs index cc37de0..23fb0fe 100644 --- a/src/EngineSharp.Core/EngineSharp.Core/IEngine.cs +++ b/src/EngineSharp.Core/EngineSharp.Core/IEngine.cs @@ -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)) }; diff --git a/src/EngineSharp.Core/EngineSharp.Core/OpenGLEngine.cs b/src/EngineSharp.Core/EngineSharp.Core/OpenGLEngine.cs index 3d55189..f7af9da 100644 --- a/src/EngineSharp.Core/EngineSharp.Core/OpenGLEngine.cs +++ b/src/EngineSharp.Core/EngineSharp.Core/OpenGLEngine.cs @@ -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 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.Zero, _window.FramebufferSize); + + InitialiseShaders(Directory.GetFiles("./assets/shaders", "*.vert")); + // TODO: SetCurrentScene -> with the default scene } private void OnUpdate(double deltaTime) diff --git a/src/EngineSharp.Core/EngineSharp.Core/Rendering/Engine.cs b/src/EngineSharp.Core/EngineSharp.Core/Rendering/Engine.cs index ae0d598..87b6061 100644 --- a/src/EngineSharp.Core/EngineSharp.Core/Rendering/Engine.cs +++ b/src/EngineSharp.Core/EngineSharp.Core/Rendering/Engine.cs @@ -4,25 +4,27 @@ namespace EngineSharp.Core.Rendering; internal abstract class Engine : IEngine { - protected readonly Dictionary> _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 _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); - } \ No newline at end of file diff --git a/src/EngineSharp.Core/EngineSharp.Core/Rendering/Shader.cs b/src/EngineSharp.Core/EngineSharp.Core/Rendering/Shader.cs index 34e715b..76e2c44 100644 --- a/src/EngineSharp.Core/EngineSharp.Core/Rendering/Shader.cs +++ b/src/EngineSharp.Core/EngineSharp.Core/Rendering/Shader.cs @@ -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); + } + /// /// Initialises the shader, by compiling it and making it ready to be used in the application.
/// Only initialises the first time it is called. Is a NoOp every subsequent call. diff --git a/src/EngineSharp/EngineSharp.csproj b/src/EngineSharp/EngineSharp.csproj index 3644c70..061aabf 100644 --- a/src/EngineSharp/EngineSharp.csproj +++ b/src/EngineSharp/EngineSharp.csproj @@ -18,7 +18,9 @@ - + + PreserveNewest + diff --git a/src/EngineSharp/Planet.cs b/src/EngineSharp/Planet.cs index b63975e..8978726 100644 --- a/src/EngineSharp/Planet.cs +++ b/src/EngineSharp/Planet.cs @@ -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) diff --git a/src/EngineSharp/Program.cs b/src/EngineSharp/Program.cs index 5c4a218..01e7358 100644 --- a/src/EngineSharp/Program.cs +++ b/src/EngineSharp/Program.cs @@ -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(); } } \ No newline at end of file