diff --git a/Engine/.editorconfig b/.editorconfig
similarity index 100%
rename from Engine/.editorconfig
rename to .editorconfig
diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
new file mode 100644
index 0000000..1318621
--- /dev/null
+++ b/.github/copilot-instructions.md
@@ -0,0 +1,17 @@
+When adding new public members or editing existing ones, please ensure that you update the XML documentation comments for those members.
+This helps maintain code readability and provides useful information for other developers who may use or maintain the code in the future.
+
+Additionally, if you are adding new features or making significant changes, consider updating any relevant unit tests to cover the new functionality and ensure that existing tests still pass.
+
+All changes need to be unit testable. Favor composition over inheritance when designing new classes or features, and ensure that your code adheres to SOLID principles for maintainability and scalability.
+When referencing classes like System.IO, System.Net.Http or similar, try to use a abstraction layer or interface to allow for easier testing and flexibility in the future.
+This will help decouple your code from specific implementations and make it easier to mock dependencies in unit tests.
+
+Give me a brief summary of the changes you are making, including the purpose and any relevant details, so that I can provide more specific guidance or suggestions if needed.
+
+If you see any areas of the codebase that could benefit from refactoring or improvement, please feel free to suggest those changes as well.
+This could include improving code readability, reducing complexity, or enhancing performance.
+All suggestions should be accompanied by a clear rationale and, if possible, examples of how the changes would improve the codebase.
+Suggestions need to be manually approved, so do not implement those by yourself without prior discussion and approval.
+
+Finally, please make sure to run all existing tests and any new tests you create to verify that your changes do not introduce any regressions or issues in the codebase.
\ No newline at end of file
diff --git a/.github/workflows/README.md b/.github/workflows/README.md
deleted file mode 100644
index 8f5aa5e..0000000
--- a/.github/workflows/README.md
+++ /dev/null
@@ -1,36 +0,0 @@
-# SharpEngine Pipelines
-
-## Pull Request pipelines
-
-
-
-## Deployment Pipelines
-
-SharpEngine consists of 5 different deployment pipelines:
-- Publish Core
-- Publish Asset Store
-- Publish Web
-- Publish Docs
-- Publish Launcher
-
-All of these pipelines are responsible of building and exposing the respective components of the system.
-
-### Publish Core
-The `publish-core.yml` creates a zip file of the engine and adds a tag to github and the zip to the releases section. That tag is also added for the commit that it was built off. If a tag for the commit this is being run-off is already found, we don't want to create another copy of the essentially the same version so we skip it.
-
-### Publish Asset Store
-The `publish-asset-store.yml` is responsible of deploying the Asset Store web interface, API and Database into Azure.
-
-All Asset Store's resources can be found under the `rg-asset-store` resource group.
-TODO: Enable from selected access ips
-
-### Publish Web
-The `publish-web.yml` is responsible of (similarly to the Asset Store) deploying the SharpEngine web interface, API and Database into Azure.
-
-All SharpEngine Web's resources can be found under the `rg-sharpengine-web` resource group.
-
-### Publish Docs
-The `publish-docs.yml` deploys the documentation files under the ´./docs´ in the root of the repository into the `docs.sharpengine.com` site.
-
-### Publish Launcher
-The ``
\ No newline at end of file
diff --git a/.github/workflows/azure-static-web-apps-victorious-moss-06d128203.yml b/.github/workflows/azure-static-web-apps-victorious-moss-06d128203.yml
deleted file mode 100644
index 3bc08ab..0000000
--- a/.github/workflows/azure-static-web-apps-victorious-moss-06d128203.yml
+++ /dev/null
@@ -1,59 +0,0 @@
-name: Azure Static Web Apps CI/CD
-
-on:
- push:
- branches:
- - main
- pull_request:
- types: [opened, synchronize, reopened, closed]
- branches:
- - main
-
-jobs:
- build_and_deploy_job:
- if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
- runs-on: ubuntu-latest
- name: Build and Deploy Job
- permissions:
- id-token: write
- contents: read
- steps:
- - uses: actions/checkout@v3
- with:
- submodules: true
- lfs: false
- - name: Install OIDC Client from Core Package
- run: npm install @actions/core@1.6.0 @actions/http-client
- - name: Get Id Token
- uses: actions/github-script@v6
- id: idtoken
- with:
- script: |
- const coredemo = require('@actions/core')
- return await coredemo.getIDToken()
- result-encoding: string
- - name: Build And Deploy
- id: builddeploy
- uses: Azure/static-web-apps-deploy@v1
- with:
- azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_VICTORIOUS_MOSS_06D128203 }}
- action: "upload"
- ###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
- # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
- app_location: "./Portal/sharpengine-web-ui" # App source code path
- # api_location: "" # Api source code path - optional
- output_location: "build" # Built app content directory - optional
- github_id_token: ${{ steps.idtoken.outputs.result }}
- app_build_command: "CI=false npm run build"
- ###### End of Repository/Build Configurations ######
-
- close_pull_request_job:
- if: github.event_name == 'pull_request' && github.event.action == 'closed'
- runs-on: ubuntu-latest
- name: Close Pull Request Job
- steps:
- - name: Close Pull Request
- id: closepullrequest
- uses: Azure/static-web-apps-deploy@v1
- with:
- action: "close"
diff --git a/.github/workflows/publish-asset-store.yml b/.github/workflows/publish-asset-store.yml
deleted file mode 100644
index e1a0afc..0000000
--- a/.github/workflows/publish-asset-store.yml
+++ /dev/null
@@ -1,65 +0,0 @@
-name: Publish Asset Store
-
-on:
- push:
- branches:
- - main
- - feature/52-av-web
- pull_request:
- types: [opened, synchronize, reopened, closed]
- branches:
- - main
- - feature/52-av-web
-
-jobs:
- build_and_deploy_job:
- if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
- runs-on: ubuntu-latest
- name: Build and Deploy Job
- permissions:
- id-token: write
- contents: read
- steps:
- - uses: actions/checkout@v3
- with:
- submodules: true
- lfs: false
-
- - name: Install OIDC Client from Core Package
- run: npm install @actions/core@1.6.0 @actions/http-client
-
- - name: Get Id Token
- uses: actions/github-script@v6
- id: idtoken
- with:
- script: |
- const coredemo = require('@actions/core')
- return await coredemo.getIDToken()
- result-encoding: string
-
- - name: Build And Deploy
- id: builddeploy
- uses: Azure/static-web-apps-deploy@v1
- with:
- azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_WHITE_SKY_0ACD4AD03 }}
- action: "upload"
- ###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
- # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
- app_location: "/AssetStore/asset-store-ui" # App source code path
- api_location: "" # Api source code path - optional
- # output_location: "app" # Built app content directory - optional
- github_id_token: ${{ steps.idtoken.outputs.result }}
- app_build_command: "CI=false npm run build"
- ###### End of Repository/Build Configurations ######
-
- close_pull_request_job:
- if: github.event_name == 'pull_request' && github.event.action == 'closed'
- runs-on: ubuntu-latest
- name: Close Pull Request Job
- steps:
- - name: Close Pull Request
- id: closepullrequest
- uses: Azure/static-web-apps-deploy@v1
- with:
- action: "close"
-
diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml
deleted file mode 100644
index 7931f80..0000000
--- a/.github/workflows/publish-docs.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-name: Publish Docs
-
-on:
- push:
- branches:
- - test
- pull_request:
- branches:
- - test
-
-jobs:
- echo:
- runs-on: ubuntu-latest
- steps:
- - name: Echo message
- run: echo "Hello from the test branch 👋"
diff --git a/.github/workflows/publish-launcher.yml b/.github/workflows/publish-launcher.yml
deleted file mode 100644
index 685b861..0000000
--- a/.github/workflows/publish-launcher.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-name: Publish Launcher
-
-on:
- push:
- branches:
- - test
- pull_request:
- branches:
- - test
-
-jobs:
- echo:
- runs-on: ubuntu-latest
- steps:
- - name: Echo message
- run: echo "Hello from the test branch 👋"
diff --git a/.github/workflows/publish-web.yml b/.github/workflows/publish-web.yml
deleted file mode 100644
index 017a6b2..0000000
--- a/.github/workflows/publish-web.yml
+++ /dev/null
@@ -1,49 +0,0 @@
-name: Publish SharpEngine Web Portal
-
-on:
- push:
- branches:
- # - main
- - feature/52-av-web
- pull_request:
- types: [closed]
- branches:
- - main
- # - feature/52-av-web
-
-jobs:
- build_and_deploy_job:
- if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
- runs-on: ubuntu-latest
- name: Build and Deploy Job
- steps:
- - uses: actions/checkout@v3
- with:
- submodules: true
- lfs: false
- - name: Build And Deploy
- id: builddeploy
- uses: Azure/static-web-apps-deploy@v1
- with:
- azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_KIND_MEADOW_06167BF03 }}
- repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
- action: "upload"
- ###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
- # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
- app_location: "./Portal/sharpengine-web-ui" # App source code path
- # api_location: "" # Api source code path - optional
- output_location: "build" # Built app content directory - optional
- app_build_command: "CI=false npm run build"
- ###### End of Repository/Build Configurations ######
-
- close_pull_request_job:
- if: github.event_name == 'pull_request' && github.event.action == 'closed'
- runs-on: ubuntu-latest
- name: Close Pull Request Job
- steps:
- - name: Close Pull Request
- id: closepullrequest
- uses: Azure/static-web-apps-deploy@v1
- with:
- azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_KIND_MEADOW_06167BF03 }}
- action: "close"
diff --git a/ATAM.md b/ATAM.md
new file mode 100644
index 0000000..e69de29
diff --git a/Engine/Directory.Build.props b/Directory.Build.props
similarity index 94%
rename from Engine/Directory.Build.props
rename to Directory.Build.props
index c13bb19..368b137 100644
--- a/Engine/Directory.Build.props
+++ b/Directory.Build.props
@@ -2,7 +2,7 @@
- net8.0
+ net8.0
diff --git a/Engine/Examples/MinecraftClone/Minecraft.csproj b/Engine/Examples/MinecraftClone/Minecraft.csproj
deleted file mode 100644
index d3d98c6..0000000
--- a/Engine/Examples/MinecraftClone/Minecraft.csproj
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
- Exe
- AnyCPU;x64;x86
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Engine/Examples/MinecraftClone/Program.cs b/Engine/Examples/MinecraftClone/Program.cs
deleted file mode 100644
index 727a8f4..0000000
--- a/Engine/Examples/MinecraftClone/Program.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using SharpEngine.Core.Interfaces;
-using SharpEngine.Core.Scenes;
-using SharpEngine.Core.Windowing;
-
-namespace Minecraft;
-
-///
-/// Represents the entry point of the application.
-///
-public static class Program
-{
- private static void Main()
- {
- DefaultSettings gameSettings = new()
- {
- UseWireFrame = false
- };
-
- Scene scene = new Scene();
- Minecraft game = new Minecraft(scene, gameSettings);
-
- using var window = new Window(game.Camera, scene, game.Camera.Settings);
- window.OnLoaded += game.Initialize;
- window.OnHandleMouse += game.HandleMouse;
- window.OnUpdate += game.Update;
- window.OnHandleKeyboard += game.HandleKeyboard;
- window.OnButtonMouseDown += game.HandleMouseDown;
- window.HandleMouseWheel += game.HandleMouseWheel;
- window.OnAfterRender += frame => game.OnAfterRender(frame);
-
- // TODO: #85 This needs to be streamlined.
- game.Window = window;
-
- window.Run();
- }
-}
diff --git a/Engine/ObjLoader/DataStore.cs b/Engine/ObjLoader/DataStore.cs
deleted file mode 100644
index 5ee2b5c..0000000
--- a/Engine/ObjLoader/DataStore.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-using ObjLoader.Loader.Common;
-using ObjLoader.Loader.Data.Elements;
-
-using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore;
-using SharpEngine.Core.Components.Properties;
-using SharpEngine.Core.Components.Properties.Meshes.MeshData;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace ObjLoader
-{
- public class DataStore : IGroupDataStore, IFaceGroup
- {
- private Group _currentGroup;
-
- private readonly List _groups = [];
- private readonly List _materials = [];
-
- public List Vertices { get; } = [];
-
- public List Textures { get; } = [];
-
- public List Normals { get; } = [];
-
- public List Materials { get; } = [];
-
- public List Groups { get; } = [];
-
- public DataStore()
- {
- PushGroup("default");
- }
-
- public void AddFace(Face face)
- {
- _currentGroup.AddFace(face);
- }
-
- public void PushGroup(string groupName)
- {
- _currentGroup = new Group(groupName);
- _groups.Add(_currentGroup);
- }
-
- ///
- public void SetMaterial(string materialName)
- {
- var material = _materials.SingleOrDefault(x => x.Name.EqualsOrdinalIgnoreCase(materialName));
- _currentGroup.Material = material;
- }
- }
-}
\ No newline at end of file
diff --git a/Engine/ObjLoader/Loaders/LoaderBase.cs b/Engine/ObjLoader/Loaders/LoaderBase.cs
deleted file mode 100644
index 0de39a2..0000000
--- a/Engine/ObjLoader/Loaders/LoaderBase.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using System.IO;
-
-namespace ObjLoader.Loader.Loaders
-{
- public abstract class LoaderBase
- {
- private StreamReader _lineStreamReader;
-
- protected void StartLoad(Stream lineStream)
- {
- _lineStreamReader = new StreamReader(lineStream);
-
- while (!_lineStreamReader.EndOfStream)
- {
- ParseLine();
- }
- }
-
- private void ParseLine()
- {
- var currentLine = _lineStreamReader.ReadLine();
-
- if (string.IsNullOrWhiteSpace(currentLine))
- return;
-
- if (currentLine[0] == '#')
- return;
-
- var fields = currentLine.Trim().Split(null, 2);
- var keyword = fields[0].Trim();
- var data = fields[1].Trim();
-
- ParseLine(keyword, data);
- }
-
- protected abstract void ParseLine(string keyword, string data);
- }
-}
\ No newline at end of file
diff --git a/Engine/ObjLoader/Loaders/MaterialLoader/IMaterialLibraryLoaderFacade.cs b/Engine/ObjLoader/Loaders/MaterialLoader/IMaterialLibraryLoaderFacade.cs
deleted file mode 100644
index 4417065..0000000
--- a/Engine/ObjLoader/Loaders/MaterialLoader/IMaterialLibraryLoaderFacade.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace ObjLoader.Loaders.MaterialLoader
-{
- public interface IMaterialLibraryLoaderFacade
- {
- void Load(string materialFileName);
- }
-}
\ No newline at end of file
diff --git a/Engine/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoader.cs b/Engine/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoader.cs
deleted file mode 100644
index 90ebb1b..0000000
--- a/Engine/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoader.cs
+++ /dev/null
@@ -1,107 +0,0 @@
-using ObjLoader.Loader.Common;
-using ObjLoader.Loader.Loaders;
-using SharpEngine.Core.Components.Properties;
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Numerics;
-
-namespace ObjLoader.Loaders.MaterialLoader
-{
- // https://paulbourke.net/dataformats/mtl/
-
- public class MaterialLibraryLoader : LoaderBase
- {
- private string _objPath;
- private readonly DataStore _dataStore;
- private readonly Dictionary> _parseActionDictionary = [];
- private readonly List _unrecognizedLines = [];
-
- private Material CurrentMaterial { get; set; }
-
- // TODO: #2 See Model class. This support both materials and textures
-
- public MaterialLibraryLoader(string objPath, DataStore dataStore)
- {
- _objPath = objPath;
- _dataStore = dataStore;
-
- AddParseAction("newmtl", PushMaterial);
- AddParseAction("Ka", d => CurrentMaterial.AmbientColor = ParseVec3(d));
- AddParseAction("Kd", d => CurrentMaterial.DiffuseColor = ParseVec3(d));
- AddParseAction("Ks", d => CurrentMaterial.SpecularColor = ParseVec3(d));
- AddParseAction("Ns", d => CurrentMaterial.SpecularCoefficient = d.ParseInvariantFloat());
-
- AddParseAction("d", d => CurrentMaterial.Transparency = d.ParseInvariantFloat());
- AddParseAction("Tr", d => CurrentMaterial.Transparency = d.ParseInvariantFloat());
-
- AddParseAction("illum", i => CurrentMaterial.IlluminationModel = i.ParseInvariantInt());
-
- AddParseAction("map_Ka", m => CurrentMaterial.AmbientTextureMap = m);
- AddParseAction("map_Kd", m => CurrentMaterial.DiffuseTextureMap = m);
-
- AddParseAction("map_Ks", m => CurrentMaterial.SpecularTextureMap = m);
- AddParseAction("map_Ns", m => CurrentMaterial.SpecularHighlightTextureMap = m);
-
- AddParseAction("map_d", m => CurrentMaterial.AlphaTextureMap = m);
-
- AddParseAction("map_bump", m => CurrentMaterial.BumpMap = m);
- AddParseAction("bump", m => CurrentMaterial.BumpMap = m);
-
- AddParseAction("disp", m => CurrentMaterial.DisplacementMap = m);
-
- AddParseAction("decal", m => CurrentMaterial.StencilDecalMap = m);
- }
-
- private void AddParseAction(string key, Action action) => _parseActionDictionary.Add(key.ToLowerInvariant(), action);
-
- ///
- protected override void ParseLine(string keyword, string data)
- {
- var parseAction = GetKeywordAction(keyword);
-
- if (parseAction == null)
- {
- _unrecognizedLines.Add(keyword + " " + data);
- return;
- }
-
- parseAction(data);
- }
-
- private Action GetKeywordAction(string keyword)
- {
- _parseActionDictionary.TryGetValue(keyword.ToLowerInvariant(), out var action);
-
- return action;
- }
-
- private void PushMaterial(string materialName)
- {
- CurrentMaterial = new Material(materialName);
- _dataStore.Materials.Add(CurrentMaterial);
- }
-
- private static Vector3 ParseVec3(string data)
- {
- string[] parts = data.Split(' ');
-
- float x = parts[0].ParseInvariantFloat();
- float y = parts[1].ParseInvariantFloat();
- float z = parts[2].ParseInvariantFloat();
-
- return new Vector3(x, y, z);
- }
-
- public void Load(Stream lineStream) => StartLoad(lineStream);
-
- ///
- public Stream Open(string materialFilePath)
- {
- var dir = Path.GetDirectoryName(_objPath);
- var path = Path.Combine(dir, materialFilePath);
- return File.Open(path, FileMode.Open, FileAccess.Read);
- }
- }
-}
\ No newline at end of file
diff --git a/Engine/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoaderFacade.cs b/Engine/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoaderFacade.cs
deleted file mode 100644
index c6f62af..0000000
--- a/Engine/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoaderFacade.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using SharpEngine.Shared;
-using System.IO;
-
-namespace ObjLoader.Loaders.MaterialLoader
-{
- public class MaterialLibraryLoaderFacade : IMaterialLibraryLoaderFacade
- {
- private readonly MaterialLibraryLoader _loader;
-
- ///
- /// Initializes a new instance of .
- ///
- /// Provides the functionality to load material libraries.
- public MaterialLibraryLoaderFacade(MaterialLibraryLoader loader)
- {
- _loader = loader;
- }
-
- ///
- public void Load(string materialFileName)
- {
- if (!File.Exists(materialFileName))
- {
- Debug.Log.Warning("Material file '{MaterialFileName}' doesn't exist.", materialFileName);
- return;
- }
-
- using var stream = _loader.Open(materialFileName);
-
- if (stream != null)
- _loader.Load(stream);
- }
- }
-}
\ No newline at end of file
diff --git a/Engine/ObjLoader/TypeParsers/GroupParser.cs b/Engine/ObjLoader/TypeParsers/GroupParser.cs
deleted file mode 100644
index b8d1512..0000000
--- a/Engine/ObjLoader/TypeParsers/GroupParser.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using ObjLoader.TypeParsers;
-
-namespace ObjLoader.Loader.TypeParsers
-{
- public class GroupParser : TypeParserBase, ITypeParser
- {
- private readonly DataStore _dataStore;
-
- public GroupParser(DataStore dataStore)
- {
- _dataStore = dataStore;
- }
-
- ///
- protected override string Keyword => "g";
-
- ///
- public override void Parse(string line)
- => _dataStore.PushGroup(line);
- }
-}
\ No newline at end of file
diff --git a/Engine/ObjLoader/TypeParsers/ITypeParser.cs b/Engine/ObjLoader/TypeParsers/ITypeParser.cs
deleted file mode 100644
index 9cb2d7e..0000000
--- a/Engine/ObjLoader/TypeParsers/ITypeParser.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace ObjLoader.TypeParsers
-{
- public interface ITypeParser
- {
- bool CanParse(string keyword);
- void Parse(string line);
- }
-}
\ No newline at end of file
diff --git a/Engine/ObjLoader/TypeParsers/MaterialLibraryParser.cs b/Engine/ObjLoader/TypeParsers/MaterialLibraryParser.cs
deleted file mode 100644
index 7b7c2b4..0000000
--- a/Engine/ObjLoader/TypeParsers/MaterialLibraryParser.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using ObjLoader.Loader.Loaders;
-using ObjLoader.Loaders.MaterialLoader;
-using ObjLoader.TypeParsers;
-
-namespace ObjLoader.Loader.TypeParsers
-{
- public class MaterialLibraryParser : TypeParserBase, ITypeParser
- {
- private readonly IMaterialLibraryLoaderFacade _libraryLoaderFacade;
-
- public MaterialLibraryParser(MaterialLibraryLoader loader)
- {
- _libraryLoaderFacade = new MaterialLibraryLoaderFacade(loader);
- }
-
- ///
- protected override string Keyword => "mtllib";
-
- ///
- public override void Parse(string line) => _libraryLoaderFacade.Load(line);
- }
-}
\ No newline at end of file
diff --git a/Engine/ObjLoader/TypeParsers/NormalParser.cs b/Engine/ObjLoader/TypeParsers/NormalParser.cs
deleted file mode 100644
index 49af71a..0000000
--- a/Engine/ObjLoader/TypeParsers/NormalParser.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using ObjLoader.Loader.Common;
-using ObjLoader.TypeParsers;
-using SharpEngine.Core.Components.Properties.Meshes.MeshData;
-
-namespace ObjLoader.Loader.TypeParsers
-{
- public class NormalParser : TypeParserBase, ITypeParser
- {
- private readonly DataStore _dataStore;
-
- public NormalParser(DataStore dataStore)
- {
- _dataStore = dataStore;
- }
-
- ///
- protected override string Keyword => "vn";
-
- ///
- public override void Parse(string line)
- {
- string[] parts = line.Split(' ');
-
- float x = parts[0].ParseInvariantFloat();
- float y = parts[1].ParseInvariantFloat();
- float z = parts[2].ParseInvariantFloat();
-
- var normal = new Normal(x, y, z);
- _dataStore.Normals.Add(normal);
- }
- }
-}
\ No newline at end of file
diff --git a/Engine/ObjLoader/TypeParsers/TextureParser.cs b/Engine/ObjLoader/TypeParsers/TextureParser.cs
deleted file mode 100644
index 0c596ba..0000000
--- a/Engine/ObjLoader/TypeParsers/TextureParser.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using ObjLoader.Loader.Common;
-using ObjLoader.TypeParsers;
-using SharpEngine.Core.Components.Properties.Meshes.MeshData;
-
-namespace ObjLoader.Loader.TypeParsers
-{
- public class TextureParser : TypeParserBase, ITypeParser
- {
- private readonly DataStore _dataStore;
-
- public TextureParser(DataStore dataStore)
- {
- _dataStore = dataStore;
- }
-
- ///
- protected override string Keyword => "vt";
-
- ///
- public override void Parse(string line)
- {
- string[] parts = line.Split(' ');
-
- float x = parts[0].ParseInvariantFloat();
- float y = parts[1].ParseInvariantFloat();
-
- var texture = new TextureCoordinate(x, y);
- _dataStore.Textures.Add(texture);
- }
- }
-}
\ No newline at end of file
diff --git a/Engine/ObjLoader/TypeParsers/TypeParserBase.cs b/Engine/ObjLoader/TypeParsers/TypeParserBase.cs
deleted file mode 100644
index 7880db8..0000000
--- a/Engine/ObjLoader/TypeParsers/TypeParserBase.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using ObjLoader.Loader.Common;
-using ObjLoader.TypeParsers;
-
-namespace ObjLoader.Loader.TypeParsers
-{
- public abstract class TypeParserBase : ITypeParser
- {
- protected abstract string Keyword { get; }
-
- public bool CanParse(string keyword) => keyword.EqualsOrdinalIgnoreCase(Keyword);
-
- public abstract void Parse(string line);
- }
-}
\ No newline at end of file
diff --git a/Engine/ObjLoader/TypeParsers/UseMaterialParser.cs b/Engine/ObjLoader/TypeParsers/UseMaterialParser.cs
deleted file mode 100644
index 72f33d8..0000000
--- a/Engine/ObjLoader/TypeParsers/UseMaterialParser.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using ObjLoader.TypeParsers;
-
-namespace ObjLoader.Loader.TypeParsers
-{
- public class UseMaterialParser : TypeParserBase, ITypeParser
- {
- private readonly DataStore _dataStore;
-
- public UseMaterialParser(DataStore dataStore)
- {
- _dataStore = dataStore;
- }
-
- ///
- protected override string Keyword => "usemtl";
-
- ///
- public override void Parse(string line) => _dataStore.SetMaterial(line);
- }
-}
\ No newline at end of file
diff --git a/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IFaceGroup.cs b/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IFaceGroup.cs
deleted file mode 100644
index e6c0922..0000000
--- a/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IFaceGroup.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using ObjLoader.Loader.Data.Elements;
-
-namespace SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore
-{
- public interface IFaceGroup
- {
- void AddFace(Face face);
- }
-}
\ No newline at end of file
diff --git a/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IGroupDataStore.cs b/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IGroupDataStore.cs
deleted file mode 100644
index 3fe9d69..0000000
--- a/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IGroupDataStore.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore
-{
- public interface IGroupDataStore
- {
- void PushGroup(string groupName);
- }
-}
\ No newline at end of file
diff --git a/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IMaterialLibrary.cs b/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IMaterialLibrary.cs
deleted file mode 100644
index 5652449..0000000
--- a/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IMaterialLibrary.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using SharpEngine.Core.Components.Properties;
-
-namespace SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore
-{
- public interface IMaterialLibrary
- {
- void Push(Material material);
- }
-}
\ No newline at end of file
diff --git a/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/INormalDataStore.cs b/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/INormalDataStore.cs
deleted file mode 100644
index 10ae87d..0000000
--- a/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/INormalDataStore.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using SharpEngine.Core.Components.Properties.Meshes.MeshData;
-
-namespace SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore
-{
- public interface INormalDataStore
- {
- void AddNormal(Normal normal);
- }
-}
\ No newline at end of file
diff --git a/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/ITextureDataStore.cs b/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/ITextureDataStore.cs
deleted file mode 100644
index a1591ff..0000000
--- a/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/ITextureDataStore.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using SharpEngine.Core.Components.Properties.Meshes.MeshData;
-
-namespace SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore
-{
- public interface ITextureDataStore
- {
- void AddTexture(TextureCoordinate texture);
- }
-}
\ No newline at end of file
diff --git a/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IVertexDataStore.cs b/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IVertexDataStore.cs
deleted file mode 100644
index 6667f06..0000000
--- a/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IVertexDataStore.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using SharpEngine.Core.Components.Properties.Meshes.MeshData;
-
-namespace SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore
-{
- public interface IVertexDataStore
- {
- void AddVertex(Vertex vertex);
- }
-}
\ No newline at end of file
diff --git a/Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/Face.cs b/Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/Face.cs
deleted file mode 100644
index e4dfdb5..0000000
--- a/Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/Face.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-namespace ObjLoader.Loader.Data.Elements
-{
- public class Face
- {
- public readonly List _vertices = [];
-
- public void AddVertex(FaceVertex vertex) => _vertices.Add(vertex);
-
- public FaceVertex this[int i] => _vertices[i];
-
- public int Count => _vertices.Count;
- }
-
- public struct FaceVertex
- {
- public FaceVertex(int vertexIndex, int textureIndex, int normalIndex) : this()
- {
- VertexIndex = vertexIndex;
- TextureIndex = textureIndex;
- NormalIndex = normalIndex;
- }
-
- public int VertexIndex { get; set; }
- public int TextureIndex { get; set; }
- public int NormalIndex { get; set; }
- }
-}
\ No newline at end of file
diff --git a/Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/Group.cs b/Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/Group.cs
deleted file mode 100644
index 1cd52c9..0000000
--- a/Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/Group.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore;
-using SharpEngine.Core.Components.Properties;
-
-namespace ObjLoader.Loader.Data.Elements
-{
- public class Group : IFaceGroup
- {
- private readonly List _faces = [];
-
- public Group(string name)
- {
- Name = name;
- }
-
- public string Name { get; private set; }
- public Material Material { get; set; }
-
- public IList Faces => _faces;
-
- public void AddFace(Face face) => _faces.Add(face);
- }
-}
\ No newline at end of file
diff --git a/Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/Normal.cs b/Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/Normal.cs
deleted file mode 100644
index 5e40c14..0000000
--- a/Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/Normal.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-namespace SharpEngine.Core.Components.Properties.Meshes.MeshData
-{
- public struct Normal
- {
- public Normal(float x, float y, float z) : this()
- {
- X = x;
- Y = y;
- Z = z;
- }
-
- public float X { get; private set; }
- public float Y { get; private set; }
- public float Z { get; private set; }
- }
-}
\ No newline at end of file
diff --git a/Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/TextureCoordinate.cs b/Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/TextureCoordinate.cs
deleted file mode 100644
index 5bd29ce..0000000
--- a/Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/TextureCoordinate.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace SharpEngine.Core.Components.Properties.Meshes.MeshData
-{
- public struct TextureCoordinate
- {
- public TextureCoordinate(float x, float y) : this()
- {
- X = x;
- Y = y;
- }
-
- public float X { get; private set; }
- public float Y { get; private set; }
- }
-}
\ No newline at end of file
diff --git a/Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/Vertex.cs b/Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/Vertex.cs
deleted file mode 100644
index 5eb1fda..0000000
--- a/Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/Vertex.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Numerics;
-
-namespace SharpEngine.Core.Components.Properties.Meshes.MeshData
-{
- public struct Vertex
- {
- public Vector3 Position;
- public Vector3 Normal;
- public Vector3 Tangent;
- public Vector2 TexCoords;
- public Vector3 Bitangent;
-
- // TODO: #65 Skeletal mesh
- public const int MAX_BONE_INFLUENCE = 4;
- public int[] BoneIds;
- public float[] Weights;
- }
-}
diff --git a/Engine/SharpEngine.Core.Components/Properties/Meshes/Model.cs b/Engine/SharpEngine.Core.Components/Properties/Meshes/Model.cs
deleted file mode 100644
index 513cf4e..0000000
--- a/Engine/SharpEngine.Core.Components/Properties/Meshes/Model.cs
+++ /dev/null
@@ -1,104 +0,0 @@
-using SharpEngine.Core.Components.Properties.Meshes.MeshData;
-using Silk.NET.Assimp;
-using Silk.NET.OpenGL;
-using System.Numerics;
-using System.Linq;
-using Mesh = SharpEngine.Core.Entities.Properties.Meshes.Mesh;
-using Texture = SharpEngine.Core.Components.Properties.Textures.Texture;
-
-namespace Tutorial
-{
- public class Model : IDisposable
- {
- public readonly string Path;
- public List Meshes { get; set; } = new List();
-
- private readonly GL _gl;
-
- public Model(GL gl, string path)
- {
- _gl = gl;
- Path = path;
- }
-
- public Model(GL gl, string path, List meshes)
- {
- _gl = gl;
- Path = path;
- Meshes = meshes;
-
- foreach (var mesh in Meshes)
- ProcessMesh(mesh);
- }
-
- public void Dispose()
- {
- foreach (var mesh in Meshes)
- {
- mesh.Dispose();
- }
-
- GC.SuppressFinalize(this);
- }
-
- public Mesh ProcessMesh(Mesh mesh)
- {
- // data to fill
- for (int i = 0; i < mesh.Vertices2.Count; i++)
- {
- var vertex = mesh.Vertices2[i];
- vertex.BoneIds = new int[Vertex.MAX_BONE_INFLUENCE];
- vertex.Weights = new float[Vertex.MAX_BONE_INFLUENCE];
- }
-
- List indices = new List();
- foreach (var group in mesh.Groups)
- {
- foreach (var face in group.Faces)
- {
- indices.AddRange(face._vertices.Select(v => (uint)v.VertexIndex));
- }
- }
-
- List textures = new List();
- foreach (var material in mesh.Materials)
- {
- if (material.DiffuseMap != null)
- textures.Add(material.DiffuseMap);
-
- if (material.UseSpecularMap && material.SpecularMap != null)
- textures.Add(material.SpecularMap);
- }
-
- // return a mesh object updated with the extracted mesh data
- mesh.Vertices = BuildVertices(mesh.Vertices2);
- mesh.Indices = BuildIndices(indices);
- mesh.Textures = textures;
-
- return mesh;
- }
-
- private float[] BuildVertices(List vertexCollection)
- {
- var vertices = new List();
-
- foreach (var vertex in vertexCollection)
- {
- vertices.Add(vertex.Position.X);
- vertices.Add(vertex.Position.Y);
- vertices.Add(vertex.Position.Z);
-
- // vertices.Add(vertex.Normal.X);
- // vertices.Add(vertex.Normal.Y);
-
- vertices.Add(vertex.TexCoords.X);
- vertices.Add(vertex.TexCoords.Y);
- }
-
- return vertices.ToArray();
- }
-
- private uint[] BuildIndices(List indices)
- => indices.ToArray();
- }
-}
diff --git a/Engine/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs b/Engine/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs
deleted file mode 100644
index 0f477aa..0000000
--- a/Engine/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs
+++ /dev/null
@@ -1,214 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using SharpEngine.Core.Components.Properties.Meshes.MeshData;
-using SharpEngine.Core.Entities.Properties.Meshes;
-using Silk.NET.Assimp;
-using Silk.NET.OpenGL;
-using System.Numerics;
-using AssimpMesh = Silk.NET.Assimp.Mesh;
-using Mesh = SharpEngine.Core.Entities.Properties.Meshes.Mesh;
-using Texture = SharpEngine.Core.Components.Properties.Textures.Texture;
-
-namespace Tutorial
-{
- [Obsolete("This should be removed and the ObjLoader should be used instead.")]
- public class Model_Old : IDisposable
- {
- public Model_Old(GL gl, string path)
- {
- _assimp = Assimp.GetApi();
- _gl = gl;
-
- if (!string.IsNullOrWhiteSpace(path))
- LoadModel(path);
- }
-
- public Model_Old(GL gl, Mesh mesh)
- {
- var result = new Mesh(gl, mesh.GetVertices(), mesh.Indices, mesh.Textures.ToList());
- Meshes.Add(result);
- }
-
- private readonly GL _gl;
- private Assimp _assimp;
- private List _texturesLoaded = [];
- public string Directory { get; protected set; } = string.Empty;
- public List Meshes { get; protected set; } = [];
-
- private unsafe void LoadModel(string path)
- {
- var scene = _assimp.ImportFile(path, (uint)PostProcessSteps.Triangulate);
-
- if (scene == null || scene->MFlags == Assimp.SceneFlagsIncomplete || scene->MRootNode == null)
- {
- string error = _assimp.GetErrorStringS();
- throw new Exception(error);
- }
-
- Directory = path;
-
- ProcessNode(scene->MRootNode, scene);
- }
-
- private unsafe void ProcessNode(Node* node, Scene* scene)
- {
- for (int i = 0; i < node->MNumMeshes; i++)
- {
- var mesh = scene->MMeshes[node->MMeshes[i]];
- Meshes.Add(ProcessMesh(mesh, scene));
-
- }
-
- for (int i = 0; i < node->MNumChildren; i++)
- {
- ProcessNode(node->MChildren[i], scene);
- }
- }
-
- private unsafe Mesh ProcessMesh(AssimpMesh* mesh, Scene* scene)
- {
- // data to fill
- List vertices = [];
- List indices = [];
- List textures = [];
-
- // walk through each of the mesh's vertices
- for (uint i = 0; i < mesh->MNumVertices; i++)
- {
- var vertex = new Vertex
- {
- BoneIds = new int[Vertex.MAX_BONE_INFLUENCE],
- Weights = new float[Vertex.MAX_BONE_INFLUENCE],
-
- Position = mesh->MVertices[i]
- };
-
- // normals
- if (mesh->MNormals != null)
- vertex.Normal = mesh->MNormals[i];
- // tangent
- if (mesh->MTangents != null)
- vertex.Tangent = mesh->MTangents[i];
- // bitangent
- if (mesh->MBitangents != null)
- vertex.Bitangent = mesh->MBitangents[i];
-
- // texture coordinates
- if (mesh->MTextureCoords[0] != null) // does the mesh contain texture coordinates?
- {
- // a vertex can contain up to 8 different texture coordinates. We thus make the assumption that we won't
- // use models where a vertex can have multiple texture coordinates so we always take the first set (0).
- var texcoord3 = mesh->MTextureCoords[0][i];
- vertex.TexCoords = new Vector2(texcoord3.X, texcoord3.Y);
- }
-
- vertices.Add(vertex);
- }
-
- // now wak through each of the mesh's faces (a face is a mesh its triangle) and retrieve the corresponding vertex indices.
- for (uint i = 0; i < mesh->MNumFaces; i++)
- {
- var face = mesh->MFaces[i];
- // retrieve all indices of the face and store them in the indices vector
- for (uint j = 0; j < face.MNumIndices; j++)
- indices.Add(face.MIndices[j]);
- }
-
- // process materials
- var material = scene->MMaterials[mesh->MMaterialIndex];
- // we assume a convention for sampler names in the shaders. Each diffuse texture should be named
- // as 'texture_diffuseN' where N is a sequential number ranging from 1 to MAX_SAMPLER_NUMBER.
- // Same applies to other texture as the following list summarizes:
- // diffuse: texture_diffuseN
- // specular: texture_specularN
- // normal: texture_normalN
-
- // 1. diffuse maps
- var diffuseMaps = LoadMaterialTextures(material, TextureType.Diffuse);
- if (diffuseMaps.Any())
- textures.AddRange(diffuseMaps);
-
- // 2. specular maps
- var specularMaps = LoadMaterialTextures(material, TextureType.Specular);
- if (specularMaps.Any())
- textures.AddRange(specularMaps);
-
- // 3. normal maps
- var normalMaps = LoadMaterialTextures(material, TextureType.Height);
- if (normalMaps.Any())
- textures.AddRange(normalMaps);
-
- // 4. height maps
- var heightMaps = LoadMaterialTextures(material, TextureType.Ambient);
- if (heightMaps.Any())
- textures.AddRange(heightMaps);
-
- // return a mesh object created from the extracted mesh data
- var result = new Mesh(_gl, BuildVertices(vertices), BuildIndices(indices), textures);
- return result;
- }
-
- private unsafe List LoadMaterialTextures(Material* mat, TextureType type)
- {
- uint textureCount = _assimp.GetMaterialTextureCount(mat, type);
- List textures = [];
- for (uint i = 0; i < textureCount; i++)
- {
- AssimpString path;
- _assimp.GetMaterialTexture(mat, type, i, &path, null, null, null, null, null, null);
- bool skip = false;
- for (int j = 0; j < _texturesLoaded.Count; j++)
- {
- if (_texturesLoaded[j].Path == path)
- {
- textures.Add(_texturesLoaded[j]);
- skip = true;
- break;
- }
- }
- if (!skip)
- {
- var texture = new Texture(_gl, Directory, type);
- textures.Add(texture);
- _texturesLoaded.Add(texture);
- }
- }
- return textures;
- }
-
- private static float[] BuildVertices(List vertexCollection)
- {
- var vertices = new List();
-
- foreach (var vertex in vertexCollection)
- {
- vertices.Add(vertex.Position.X);
- vertices.Add(vertex.Position.Y);
- vertices.Add(vertex.Position.Z);
-
- vertices.Add(vertex.Normal.X);
- vertices.Add(vertex.Normal.Y);
- vertices.Add(vertex.Normal.Z);
-
- vertices.Add(vertex.TexCoords.X);
- vertices.Add(vertex.TexCoords.Y);
- }
-
- return vertices.ToArray();
- }
-
- private static uint[] BuildIndices(List indices) => indices.ToArray();
-
- public void Dispose()
- {
- foreach (var mesh in Meshes)
- {
- mesh.Dispose();
- }
-
- _texturesLoaded = [];
- GC.SuppressFinalize(this);
- }
- }
-}
\ No newline at end of file
diff --git a/Engine/SharpEngine.Core.Components/Properties/Textures/Texture.cs b/Engine/SharpEngine.Core.Components/Properties/Textures/Texture.cs
deleted file mode 100644
index d271f1e..0000000
--- a/Engine/SharpEngine.Core.Components/Properties/Textures/Texture.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using Silk.NET.Assimp;
-using Silk.NET.OpenGL;
-
-namespace SharpEngine.Core.Components.Properties.Textures;
-
-///
-/// Represents a texture program.
-///
-public partial class Texture : IDisposable
-{
- /// The OpenGL handle for the texture.
- public readonly uint Handle;
- public readonly TextureType Type;
- public readonly string Path;
-
- private readonly GL _gl;
-
- ///
- /// Initializes a new instance of .
- ///
- public Texture(GL gl, string path, TextureType type = TextureType.Diffuse)
- {
- _gl = gl;
- Handle = _gl.GenTexture();
-
- Path = path;
- Type = type;
-
- Initialize();
- }
-}
diff --git a/Engine/SharpEngine.Core/Entities/GameObject.cs b/Engine/SharpEngine.Core/Entities/GameObject.cs
deleted file mode 100644
index 160896a..0000000
--- a/Engine/SharpEngine.Core/Entities/GameObject.cs
+++ /dev/null
@@ -1,114 +0,0 @@
-using SharpEngine.Core.Attributes;
-using SharpEngine.Core.Entities.Properties;
-using SharpEngine.Core.Entities.Views;
-using SharpEngine.Core.Interfaces;
-using SharpEngine.Core.Numerics;
-using SharpEngine.Core.Scenes;
-using SharpEngine.Core.Shaders;
-using SharpEngine.Core.Windowing;
-using Shader = SharpEngine.Core.Shaders.Shader;
-
-using Silk.NET.OpenGL;
-using Tutorial;
-using System.Threading.Tasks;
-
-namespace SharpEngine.Core.Entities;
-
-///
-/// Represents a game object in the scene.
-///
-public class GameObject : EmptyNode, IRenderable
-{
- ///
- /// Initializes a new instance of the .
- ///
- public GameObject() : base(string.Empty)
- {
- BoundingBox = BoundingBox.CalculateBoundingBox(Transform);
- Shader = ShaderService.Instance.LoadShader(_Resources.Default.VertexShader, _Resources.Default.FragmentShader, "lighting");
- }
-
- public GameObject(Model_Old model) : base(string.Empty)
- {
- Model = model;
- BoundingBox = BoundingBox.CalculateBoundingBox(Transform);
- Shader = ShaderService.Instance.LoadShader(_Resources.Default.VertexShader, _Resources.Default.FragmentShader, "lighting");
- }
-
- ///
- /// Initializes a new instance of the with specified textures and shaders.
- ///
- /// The file path of the diffuse map texture.
- /// The file path of the specular map texture.
- /// The file path of the vertex shader.
- /// The file path of the fragment shader.
- public GameObject(Shader shader, Model_Old model) : base(string.Empty)
- {
- Model = model;
- BoundingBox = BoundingBox.CalculateBoundingBox(Transform);
- Shader = shader;
- }
-
- public Shader Shader { get; set; }
-
- ///
- /// Gets or sets the mesh of the game object.
- ///
- public Model_Old Model { get; set; }
-
- ///
- /// Gets or sets the transform of the game object.
- ///
- public override Transform Transform
- {
- get => _transform;
- set
- {
- _transform = value;
- BoundingBox = BoundingBox.CalculateBoundingBox(_transform);
- }
- }
-
- private Transform _transform = new();
-
- ///
- /// Gets the bounding box of the game object.
- ///
- [Inspector(DisplayInInspector = false)]
- public BoundingBox BoundingBox { get; set; }
-
- protected virtual void SetShaderUniforms(CameraView camera)
- {
- Shader.SetMatrix4(ShaderAttributes.Model, Transform.ModelMatrix);
-
- // TODO: One of these could be calculated once and "reloaded" if it changes.
- Shader.SetMatrix4(ShaderAttributes.View, camera.GetViewMatrix(), true);
- Shader.SetMatrix4(ShaderAttributes.Projection, camera.GetProjectionMatrix(), true);
- }
-
- ///
- public override Task Render(CameraView camera, Window window)
- {
- // TODO: This needs to removed later once fixed.
- if (Model is null || Model.Meshes is null)
- return Task.CompletedTask;
-
- foreach (var mesh in Model.Meshes)
- {
- mesh.Bind();
-
- foreach (var texture in mesh.Textures)
- texture.Use();
-
- Shader.Use();
- SetShaderUniforms(camera);
-
- foreach (var material in mesh.Materials)
- material.SetUniformValues(Shader);
-
- Window.GL.DrawArrays(PrimitiveType.Triangles, 0, (uint)mesh.Vertices.Length);
- }
-
- return Task.CompletedTask;
- }
-}
diff --git a/Engine/SharpEngine.Core/Entities/MeshService.cs b/Engine/SharpEngine.Core/Entities/MeshService.cs
deleted file mode 100644
index 99a60a2..0000000
--- a/Engine/SharpEngine.Core/Entities/MeshService.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System.Collections.Generic;
-
-namespace SharpEngine.Core.Entities.Properties.Meshes;
-
-///
-/// Represents a service that loads meshes into the GPU.
-///
-public class MeshService
-{
- /// A global instance of the service.
- public static readonly MeshService Instance = new();
-
- private readonly Dictionary Meshes = [];
-
- private MeshService() { }
-
- ///
- /// Loads a mesh into the mesh cache.
- ///
- /// Used to cache the loaded mesh.
- /// The mesh that should be stored in to the GPU buffer.
- /// The loaded mesh.
- public Mesh LoadMesh(string identifier, Mesh mesh)
- {
- if (Meshes.TryGetValue(identifier, out var cachedMesh))
- return cachedMesh;
-
- Meshes.Add(identifier, mesh);
- return mesh;
- }
-}
\ No newline at end of file
diff --git a/Engine/SharpEngine.Core/Entities/UI/UIElement.cs b/Engine/SharpEngine.Core/Entities/UI/UIElement.cs
deleted file mode 100644
index 4230410..0000000
--- a/Engine/SharpEngine.Core/Entities/UI/UIElement.cs
+++ /dev/null
@@ -1,108 +0,0 @@
-using SharpEngine.Core.Entities.Properties;
-using SharpEngine.Core.Entities.Properties.Meshes;
-using SharpEngine.Core.Entities.Views;
-using SharpEngine.Core.Interfaces;
-using SharpEngine.Core.Scenes;
-using SharpEngine.Core.Shaders;
-using SharpEngine.Core.Windowing;
-
-using Silk.NET.OpenGL;
-using System.Numerics;
-using System.Threading.Tasks;
-using Vector2 = SharpEngine.Core.Numerics.Vector2;
-
-namespace SharpEngine.Core.Entities.UI;
-
-///
-/// Represents a User Interface entity.
-///
-public class UIElement : EmptyNode, IRenderable
-{
- ///
- /// Initializes a new instance of .
- ///
- public UIElement() : this("UIElement") { }
-
- ///
- /// Initializes a new instance of .
- ///
- /// The name of the UI element.
- public UIElement(string name) : base(name)
- {
- // TODO: #5 Support custom meshes?
- Mesh = MeshService.Instance.LoadMesh(nameof(Primitives.Plane), Primitives.Plane.Mesh);
-
- Initialize();
- }
-
- private readonly UIShader _uiShader = new();
-
- /// Gets or sets the width of the ui element.
- public float Width { get; set; } = 10;
-
- /// Gets or sets the height of the ui element.
- public float Height { get; set; } = 10;
-
- /// Gets or sets the mesh of the UI element.
- public Mesh Mesh { get; set; }
-
- ///
- public uint VAO { get; set; }
-
- ///
- public void Initialize()
- {
- VAO = Window.GL.GenVertexArray();
- Bind();
-
- InitializeBuffers(Mesh);
-
- _uiShader.Shader?.Use();
- _uiShader.SetAttributes();
- }
-
- ///
- public void Bind()
- {
- Window.GL.BindVertexArray(VAO);
- }
-
- ///
- public void InitializeBuffers(Mesh mesh, bool useMeshVertices = false)
- {
- var vertexBufferObject = Window.GL.GenBuffer();
- Window.GL.BindBuffer(GLEnum.ArrayBuffer, vertexBufferObject);
- Window.GL.BufferData(GLEnum.ArrayBuffer, mesh.GetVertices(), GLEnum.StaticDraw);
-
- var elementBufferObject = Window.GL.GenBuffer();
- Window.GL.BindBuffer(GLEnum.ElementArrayBuffer, elementBufferObject);
- Window.GL.BufferData(GLEnum.ElementArrayBuffer, mesh.Indices, GLEnum.StaticDraw);
- }
-
- Matrix4x4 OrthoMatrix = Matrix4x4.CreateOrthographicOffCenter(-1, 1, -1, 1, -1, 1);
-
- ///
- /// Render the UI element.
- ///
- public override Task Render(CameraView camera, Window window)
- {
- _uiShader.Shader.Use();
- Bind();
-
- // TODO: #75 These should come from somewhere else.
- const float screenWidth = 1280;
- const float screenHeight = 720;
-
- _uiShader.Shader.SetFloat("width", Width);
- _uiShader.Shader.SetFloat("height", Height);
- _uiShader.Shader.SetVector2("screenSize", new System.Numerics.Vector2(screenWidth, screenHeight));
- _uiShader.Shader.SetVector2("position", (System.Numerics.Vector2)Transform.Position);
- _uiShader.Shader.SetFloat("rotation", Math.DegreesToRadians(Transform.Rotation.Angle));
- _uiShader.Shader.SetMatrix4(ShaderAttributes.Model, Transform.ModelMatrix);
- _uiShader.Shader.SetMatrix4("orthoMatrix", OrthoMatrix); // Pass the orthographic matrix to the shader
-
- Window.GL.DrawElements(PrimitiveType.Triangles, (uint)Mesh.Indices.Length, DrawElementsType.UnsignedInt, []);
-
- return Task.CompletedTask;
- }
-}
diff --git a/Engine/SharpEngine.Core/Primitives/Cube.cs b/Engine/SharpEngine.Core/Primitives/Cube.cs
deleted file mode 100644
index 16be872..0000000
--- a/Engine/SharpEngine.Core/Primitives/Cube.cs
+++ /dev/null
@@ -1,203 +0,0 @@
-using SharpEngine.Core._Resources;
-using SharpEngine.Core.Entities.Properties.Meshes;
-using SharpEngine.Core.Textures;
-using SharpEngine.Core.Windowing;
-using Tutorial;
-
-namespace SharpEngine.Core.Primitives;
-
-///
-/// Used to create a primitive cube object.
-///
-public static class Cube
-{
- static Cube()
- {
- if (_loaded)
- return;
-
- var defaultTexture = TextureService.Instance.LoadTexture(Default.DebugTexture);
-
- var mesh = new Mesh(Window.GL)
- {
- Vertices = [.. Vertices],
- Normals = [.. Normals],
- TextureCoordinates = [.. TextureCoordinates],
- Indices = [.. Indices],
- Textures = [defaultTexture],
- // Materials = [MaterialService.Instance.LoadMaterial(Default.DebugMaterial)],
- Materials = [new(defaultTexture)]
- };
-
- Mesh = MeshService.Instance.LoadMesh(nameof(Cube), mesh);
- Model = new(Window.GL, Mesh);
-
- _loaded = true;
- }
-
- private static bool _loaded;
-
- public static Model_Old Model;
-
- /// The cube mesh.
- public static readonly Mesh Mesh;
-
- public static float[] Vertices =
- [
- -0.5f, -0.5f, -0.5f,
- 0.5f, -0.5f, -0.5f,
- 0.5f, 0.5f, -0.5f,
- 0.5f, 0.5f, -0.5f,
- -0.5f, 0.5f, -0.5f,
- -0.5f, -0.5f, -0.5f,
-
- -0.5f, -0.5f, 0.5f,
- 0.5f, -0.5f, 0.5f,
- 0.5f, 0.5f, 0.5f,
- 0.5f, 0.5f, 0.5f,
- -0.5f, 0.5f, 0.5f,
- -0.5f, -0.5f, 0.5f,
-
- -0.5f, 0.5f, 0.5f,
- -0.5f, 0.5f, -0.5f,
- -0.5f, -0.5f, -0.5f,
- -0.5f, -0.5f, -0.5f,
- -0.5f, -0.5f, 0.5f,
- -0.5f, 0.5f, 0.5f,
-
- 0.5f, 0.5f, 0.5f,
- 0.5f, 0.5f, -0.5f,
- 0.5f, -0.5f, -0.5f,
- 0.5f, -0.5f, -0.5f,
- 0.5f, -0.5f, 0.5f,
- 0.5f, 0.5f, 0.5f,
-
- -0.5f, -0.5f, -0.5f,
- 0.5f, -0.5f, -0.5f,
- 0.5f, -0.5f, 0.5f,
- 0.5f, -0.5f, 0.5f,
- -0.5f, -0.5f, 0.5f,
- -0.5f, -0.5f, -0.5f,
-
- -0.5f, 0.5f, -0.5f,
- 0.5f, 0.5f, -0.5f,
- 0.5f, 0.5f, 0.5f,
- 0.5f, 0.5f, 0.5f,
- -0.5f, 0.5f, 0.5f,
- -0.5f, 0.5f, -0.5f,
- ];
- public static float[] Normals =
- [
- 0.0f, 0.0f, -1.0f,
- 0.0f, 0.0f, -1.0f,
- 0.0f, 0.0f, -1.0f,
- 0.0f, 0.0f, -1.0f,
- 0.0f, 0.0f, -1.0f,
- 0.0f, 0.0f, -1.0f,
-
- 0.0f, 0.0f, 1.0f,
- 0.0f, 0.0f, 1.0f,
- 0.0f, 0.0f, 1.0f,
- 0.0f, 0.0f, 1.0f,
- 0.0f, 0.0f, 1.0f,
- 0.0f, 0.0f, 1.0f,
-
- -1.0f, 0.0f, 0.0f,
- -1.0f, 0.0f, 0.0f,
- -1.0f, 0.0f, 0.0f,
- -1.0f, 0.0f, 0.0f,
- -1.0f, 0.0f, 0.0f,
- -1.0f, 0.0f, 0.0f,
-
- 1.0f, 0.0f, 0.0f,
- 1.0f, 0.0f, 0.0f,
- 1.0f, 0.0f, 0.0f,
- 1.0f, 0.0f, 0.0f,
- 1.0f, 0.0f, 0.0f,
- 1.0f, 0.0f, 0.0f,
-
- 0.0f, -1.0f, 0.0f,
- 0.0f, -1.0f, 0.0f,
- 0.0f, -1.0f, 0.0f,
- 0.0f, -1.0f, 0.0f,
- 0.0f, -1.0f, 0.0f,
- 0.0f, -1.0f, 0.0f,
-
- 0.0f, 1.0f, 0.0f,
- 0.0f, 1.0f, 0.0f,
- 0.0f, 1.0f, 0.0f,
- 0.0f, 1.0f, 0.0f,
- 0.0f, 1.0f, 0.0f,
- 0.0f, 1.0f, 0.0f,
- ];
- public static float[] TextureCoordinates =
- [
- 0.0f, 0.0f,
- 1.0f, 0.0f,
- 1.0f, 1.0f,
- 1.0f, 1.0f,
- 0.0f, 1.0f,
- 0.0f, 0.0f,
-
- 0.0f, 0.0f,
- 1.0f, 0.0f,
- 1.0f, 1.0f,
- 1.0f, 1.0f,
- 0.0f, 1.0f,
- 0.0f, 0.0f,
-
- 1.0f, 0.0f,
- 1.0f, 1.0f,
- 0.0f, 1.0f,
- 0.0f, 1.0f,
- 0.0f, 0.0f,
- 1.0f, 0.0f,
-
- 1.0f, 0.0f,
- 1.0f, 1.0f,
- 0.0f, 1.0f,
- 0.0f, 1.0f,
- 0.0f, 0.0f,
- 1.0f, 0.0f,
-
- 0.0f, 1.0f,
- 1.0f, 1.0f,
- 1.0f, 0.0f,
- 1.0f, 0.0f,
- 0.0f, 0.0f,
- 0.0f, 1.0f,
-
- 0.0f, 1.0f,
- 1.0f, 1.0f,
- 1.0f, 0.0f,
- 1.0f, 0.0f,
- 0.0f, 0.0f,
- 0.0f, 1.0f
- ];
- public static uint[] Indices =
- [
- // Front face
- 0, 1, 2,
- 2, 3, 0,
-
- // Back face
- 4, 5, 6,
- 6, 7, 4,
-
- // Left face
- 4, 0, 3,
- 3, 7, 4,
-
- // Right face
- 1, 5, 6,
- 6, 2, 1,
-
- // Top face
- 3, 2, 6,
- 6, 7, 3,
-
- // Bottom face
- 4, 5, 1,
- 1, 0, 4
- ];
-}
diff --git a/Engine/SharpEngine.Core/Renderers/TextRenderer.cs b/Engine/SharpEngine.Core/Renderers/TextRenderer.cs
deleted file mode 100644
index 5787fc5..0000000
--- a/Engine/SharpEngine.Core/Renderers/TextRenderer.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using SharpEngine.Core.Entities.Views;
-using SharpEngine.Core.Interfaces;
-using SharpEngine.Core.Scenes;
-using SharpEngine.Core.Windowing;
-
-using System.Threading.Tasks;
-
-namespace SharpEngine.Core.Renderers;
-internal class TextRenderer : RendererBase
-{
- public TextRenderer(CameraView camera, Window window, ISettings settings, Scene scene) : base(settings)
- {
- }
-
- public override RenderFlags RenderFlag => RenderFlags.Text;
-
- ///
- public override Task Render()
- {
- return Task.CompletedTask;
- }
-}
diff --git a/Engine/SharpEngine.Core/Shaders/LampShader.cs b/Engine/SharpEngine.Core/Shaders/LampShader.cs
deleted file mode 100644
index 898d08b..0000000
--- a/Engine/SharpEngine.Core/Shaders/LampShader.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using SharpEngine.Core._Resources;
-using SharpEngine.Core.Entities.Properties.Meshes;
-using SharpEngine.Core.Extensions;
-using SharpEngine.Core.Windowing;
-using Silk.NET.OpenGL;
-
-namespace SharpEngine.Core.Shaders;
-
-internal class LampShader : ShaderBase
-{
- ///
- /// Initializes a new instance of .
- ///
- public LampShader()
- {
- Shader = ShaderService.Instance.LoadShader(Default.VertexShader, Default.LightShader, "lamp").Initialize();
-
- Vao = Window.GL.GenVertexArray();
- Window.GL.BindVertexArray(Vao);
-
- SetAttributes();
- }
-
- ///
- public override bool SetAttributes()
- {
- if (!base.SetAttributes())
- return false;
-
- if (!Shader!.TryGetAttribLocation(ShaderAttributes.Pos, out int positionLocation))
- return false;
-
- var positionLocationUint = (uint)positionLocation;
- Window.GL.EnableVertexAttribArray(positionLocationUint);
- Window.GL.VertexAttribPointer(positionLocationUint, 3, VertexAttribPointerType.Float, false, VertexData.Stride, 0);
-
- return true;
- }
-}
diff --git a/Engine/SharpEngine.Core/Shaders/LightingShader.cs b/Engine/SharpEngine.Core/Shaders/LightingShader.cs
deleted file mode 100644
index 0893499..0000000
--- a/Engine/SharpEngine.Core/Shaders/LightingShader.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-using SharpEngine.Core._Resources;
-using SharpEngine.Core.Entities.Properties.Meshes;
-using SharpEngine.Core.Extensions;
-using SharpEngine.Core.Windowing;
-using Silk.NET.OpenGL;
-
-namespace SharpEngine.Core.Shaders;
-
-internal class LightingShader : ShaderBase
-{
- ///
- /// Initializes a new instance of .
- ///
- public LightingShader()
- {
- Shader = ShaderService.Instance.LoadShader(Default.VertexShader, Default.FragmentShader, "lighting").Initialize();
-
- Vao = Window.GL.GenVertexArray();
- Window.GL.BindVertexArray(Vao);
-
- SetAttributes();
- }
-
- ///
- public override bool SetAttributes()
- {
- if (!base.SetAttributes())
- return false;
-
- /*if (!Shader!.TryGetAttribLocation(ShaderAttributes.Pos, out int positionLocation))
- return false;
-
- var positionLocationUint = (uint)positionLocation;
- Window.GL.EnableVertexAttribArray(positionLocationUint);
- Window.GL.VertexAttribPointer(positionLocationUint, VertexData.VerticesSize, VertexAttribPointerType.Float, false, VertexData.Stride, 0);
-
- if (!Shader!.TryGetAttribLocation(ShaderAttributes.Normal, out int normalLocation))
- return false;
-
- var normalLocationUint = (uint)normalLocation;
- Window.GL.EnableVertexAttribArray(normalLocationUint);
- Window.GL.VertexAttribPointer(normalLocationUint, VertexData.NormalsSize, VertexAttribPointerType.Float, false, VertexData.Stride, VertexData.NormalsOffset);
-
- if (!Shader!.TryGetAttribLocation(ShaderAttributes.TexCoords, out int texCoordLocation))
- return false;
-
- var texCoordLocationUint = (uint)texCoordLocation;
- Window.GL.EnableVertexAttribArray(texCoordLocationUint);
- Window.GL.VertexAttribPointer(texCoordLocationUint, VertexData.TexCoordsSize, VertexAttribPointerType.Float, false, VertexData.Stride, VertexData.TexCoordsOffset);
- */
- return true;
- }
-}
diff --git a/Engine/SharpEngine.Core/Shaders/ShaderService.cs b/Engine/SharpEngine.Core/Shaders/ShaderService.cs
deleted file mode 100644
index ee8f516..0000000
--- a/Engine/SharpEngine.Core/Shaders/ShaderService.cs
+++ /dev/null
@@ -1,93 +0,0 @@
-using System.IO;
-using System.Collections.Generic;
-
-using SharpEngine.Core.Windowing;
-using SharpEngine.Shared;
-
-namespace SharpEngine.Core.Shaders;
-
-///
-/// Contains all the shaders used in the game.
-///
-public class ShaderService
-{
- ///
- /// Gets the singleton instance of the .
- ///
- public static ShaderService Instance { get; } = new ShaderService();
-
- private readonly Dictionary _shaderCache = [];
-
- ///
- /// Gets or sets whether there are shaders to load.
- ///
- public bool HasShadersToLoad { get; set; } = true;
-
- ///
- /// Private constructor to prevent instantiation.
- ///
- private ShaderService() { }
-
- ///
- /// Gets all the shaders in the cache.
- ///
- /// All the shaders found from the cache.
- public List GetAll()
- {
- HasShadersToLoad = false;
- return [.. _shaderCache.Values];
- }
-
- ///
- /// Gets a shader by its name.
- ///
- /// The name of the shader to be found.
- /// The found shader.
- ///
- /// Thrown if a shader by that is not found.
- /// This exception is thrown to make sure there are no unexpected issues made by the developer.
- ///
- public Shader GetByName(string name)
- {
- if (_shaderCache.TryGetValue(name, out var cachedShader))
- return cachedShader;
-
- throw new KeyNotFoundException($"Shader with name {name} not found in cache.");
- }
-
- ///
- /// Loads a shader from the specified vertex and fragment paths.
- /// If the shader is loaded already, adds it to the cache.
- ///
- /// The vertex shader full path.
- /// The fragment shader full path.
- /// A name identifier for the shader.
- /// A shader with the given name.
- /// Thrown when either the vertex or fragment shader is not found.
- public Shader LoadShader(string vertPath, string fragPath, string name)
- {
- // Check if the shader is already in the cache
- if (_shaderCache.TryGetValue(name, out var cachedShader))
- return cachedShader;
-
- if (!File.Exists(vertPath))
- {
- Debug.Log.Information("Vertex shader file not found: {VertPath}", vertPath);
- throw new FileNotFoundException($"Vertex shader file not found: {vertPath}");
- }
-
- if (!File.Exists(fragPath))
- {
- Debug.Log.Information("Fragment shader file not found: {FragPath}", fragPath);
- throw new FileNotFoundException($"Fragment shader file not found: {fragPath}");
- }
-
- // Create a new shader instance and add it to the cache
- var shader = new Shader(Window.GL, vertPath, fragPath, name).Initialize();
- _shaderCache[name] = shader;
-
- HasShadersToLoad = true;
-
- return shader;
- }
-}
diff --git a/Engine/SharpEngine.Core/Shaders/UIShader.cs b/Engine/SharpEngine.Core/Shaders/UIShader.cs
deleted file mode 100644
index 37caf51..0000000
--- a/Engine/SharpEngine.Core/Shaders/UIShader.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-using SharpEngine.Core.Entities.Properties.Meshes;
-using SharpEngine.Core.Windowing;
-using SharpEngine.Core._Resources;
-
-using Silk.NET.OpenGL;
-
-namespace SharpEngine.Core.Shaders;
-
-internal class UIShader : ShaderBase
-{
- ///
- /// Initializes a new instance of .
- ///
- public UIShader()
- {
- Shader = new Shader(Window.GL, Default.UIVertexShader, Default.UIFragmentShader, nameof(UIShader)).Initialize();
- }
-
- ///
- public override bool SetAttributes()
- {
- if (!base.SetAttributes())
- return false;
-
- if (!Shader!.TryGetAttribLocation(ShaderAttributes.Pos, out int positionLocation))
- return false;
-
- var positionLocationUint = (uint)positionLocation;
- Window.GL.EnableVertexAttribArray(positionLocationUint);
- Window.GL.VertexAttribPointer(positionLocationUint, VertexData.VerticesSize, VertexAttribPointerType.Float, false, VertexData.Stride, 0);
-
- if (!Shader!.TryGetAttribLocation(ShaderAttributes.Normal, out int normalLocation))
- return false;
-
- var normalLocationUint = (uint)normalLocation;
- Window.GL.EnableVertexAttribArray(normalLocationUint);
- Window.GL.VertexAttribPointer(normalLocationUint, VertexData.NormalsSize, VertexAttribPointerType.Float, false, VertexData.Stride, VertexData.NormalsOffset);
-
- if (!Shader!.TryGetAttribLocation(ShaderAttributes.TexCoords, out int texCoordLocation))
- return false;
-
- var texCoordLocationUint = (uint)texCoordLocation;
- Window.GL.EnableVertexAttribArray(texCoordLocationUint);
- Window.GL.VertexAttribPointer(texCoordLocationUint, VertexData.TexCoordsSize, VertexAttribPointerType.Float, false, VertexData.Stride, VertexData.TexCoordsOffset);
-
- return true;
- }
-}
diff --git a/Engine/Tests/SharpEngine.Shared.Net8/Class1.cs b/Engine/Tests/SharpEngine.Shared.Net8/Class1.cs
deleted file mode 100644
index e8f6eff..0000000
--- a/Engine/Tests/SharpEngine.Shared.Net8/Class1.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace SharpEngine.Shared.Net8;
-
-public class Class1
-{
-
-}
diff --git a/Engine/Tests/SharpEngine.Shared.Net8/SharpEngine.Shared.Net8.csproj b/Engine/Tests/SharpEngine.Shared.Net8/SharpEngine.Shared.Net8.csproj
deleted file mode 100644
index fa71b7a..0000000
--- a/Engine/Tests/SharpEngine.Shared.Net8/SharpEngine.Shared.Net8.csproj
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
- net8.0
- enable
- enable
-
-
-
diff --git a/Engine/Tests/Test.Directory.Build.props b/Engine/Tests/Test.Directory.Build.props
deleted file mode 100644
index a52359c..0000000
--- a/Engine/Tests/Test.Directory.Build.props
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Engine/Examples/MinecraftClone/Block/BlockBase.cs b/Examples/MinecraftClone/Block/BlockBase.cs
similarity index 100%
rename from Engine/Examples/MinecraftClone/Block/BlockBase.cs
rename to Examples/MinecraftClone/Block/BlockBase.cs
diff --git a/Engine/Examples/MinecraftClone/Block/Dirt.cs b/Examples/MinecraftClone/Block/Dirt.cs
similarity index 100%
rename from Engine/Examples/MinecraftClone/Block/Dirt.cs
rename to Examples/MinecraftClone/Block/Dirt.cs
diff --git a/Engine/Examples/MinecraftClone/Block/Stone.cs b/Examples/MinecraftClone/Block/Stone.cs
similarity index 100%
rename from Engine/Examples/MinecraftClone/Block/Stone.cs
rename to Examples/MinecraftClone/Block/Stone.cs
diff --git a/Engine/Examples/MinecraftClone/BlockFactory.cs b/Examples/MinecraftClone/BlockFactory.cs
similarity index 100%
rename from Engine/Examples/MinecraftClone/BlockFactory.cs
rename to Examples/MinecraftClone/BlockFactory.cs
diff --git a/Engine/Examples/MinecraftClone/Input.cs b/Examples/MinecraftClone/Input.cs
similarity index 100%
rename from Engine/Examples/MinecraftClone/Input.cs
rename to Examples/MinecraftClone/Input.cs
diff --git a/Engine/Examples/MinecraftClone/Inventory.cs b/Examples/MinecraftClone/Inventory.cs
similarity index 100%
rename from Engine/Examples/MinecraftClone/Inventory.cs
rename to Examples/MinecraftClone/Inventory.cs
diff --git a/Engine/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs
similarity index 85%
rename from Engine/Examples/MinecraftClone/Minecraft.cs
rename to Examples/MinecraftClone/Minecraft.cs
index 92494da..1b347e2 100644
--- a/Engine/Examples/MinecraftClone/Minecraft.cs
+++ b/Examples/MinecraftClone/Minecraft.cs
@@ -1,25 +1,24 @@
using ImGuiNET;
+
using Minecraft.Block;
-using ObjLoader.Loaders.ObjLoader;
+using Microsoft.Extensions.Logging;
+
using SharpEngine.Core;
using SharpEngine.Core.Entities;
using SharpEngine.Core.Entities.Lights;
using SharpEngine.Core.Entities.Properties;
-using SharpEngine.Core.Entities.Properties.Meshes;
using SharpEngine.Core.Entities.UI;
using SharpEngine.Core.Entities.UI.Layouts;
using SharpEngine.Core.Enums;
using SharpEngine.Core.Interfaces;
using SharpEngine.Core.Scenes;
using SharpEngine.Core.Windowing;
-using SharpEngine.Shared;
-using Silk.NET.Core.Native;
+using SharpEngine.Core.ObjLoader.Loaders.ObjLoader;
+
using Silk.NET.Input;
+
using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Numerics;
-using Tutorial;
namespace Minecraft;
@@ -31,6 +30,7 @@ namespace Minecraft;
public class Minecraft : Game
{
private readonly Scene _scene;
+ private readonly ILogger _logger;
private SceneNode _lightsNode;
private SceneNode _blocksNode;
@@ -43,15 +43,20 @@ public class Minecraft : Game
///
/// Gets the main window.
///
- public Window? Window { get; set; }
+ public static Window Window
+ {
+ get => field ?? throw new InvalidOperationException("The game window has not been assigned yet.");
+ set;
+ }
///
/// Initializes a new instance of the .
///
- public Minecraft(Scene scene, ISettings settings)
+ public Minecraft(Scene scene, ISettings settings, ILogger logger)
{
_scene = scene;
CoreSettings = settings;
+ _logger = logger;
_inventory = new Inventory();
@@ -76,21 +81,21 @@ public override void Initialize()
_uiElem = new UIElement("uiElement");
_scene.UIElements.Add(_uiElem);
- //var uiElem2 = new UIElement("uiElement");
- //uiElem2.Transform.Scale = new SharpEngine.Core.Numerics.Vector2(0.2f, 0.2f);
- //uiElem2.Transform.Position = new Vector2(30, 0);
+ var uiElem2 = new UIElement("uiElement");
+ uiElem2.Transform.Scale = new SharpEngine.Core.Numerics.Vector2(0.2f, 0.2f);
+ uiElem2.Transform.Position = new SharpEngine.Core.Numerics.Vector2(30, 0);
- // gridLayout.AddChild(_uiElem, uiElem2);
- // _scene.UIElements.Add(_uiElem);
- // _scene.UIElements.Add(uiElem2);
+ gridLayout.AddChild(_uiElem, uiElem2);
+ _scene.UIElements.Add(_uiElem);
+ _scene.UIElements.Add(uiElem2);
- //_scene.UIElements.Add(gridLayout);
+ _scene.UIElements.Add(gridLayout);
InitializeWorld();
}
catch (Exception ex)
{
- Debug.Log.Information(ex.Message, "{Message}", ex.Message);
+ _logger.LogInformation(ex, "{Message}", ex.Message);
}
}
@@ -151,7 +156,7 @@ private void InitializeWorld()
// TODO: #2 Does not work yet.
// var torus = MeshService.Instance.LoadMesh("torus", @"C:\Users\antti\Documents\Untitled2.obj");
- var model = ObjLoaderFactory.Load(Window.GL, @"C:\Users\antti\Documents\Untitled2.obj");
+ var model = ObjLoaderFactory.Load(Window.GetGL(), @"C:\Users\antti\Documents\Untitled2.obj");
var go = new GameObject(model);
var go2 = new GameObject(model)
{
@@ -220,14 +225,8 @@ private void GenerateChunk(int chunkSize, Vector3 chunkPos)
}
///
- public override void Update(double deltaTime, IInputContext input)
- {
- //UpdateUI();
- _input.HandleKeyboard(input.Keyboards[0], (float)deltaTime);
- }
-
- private void UpdateUI()
- => _uiElem.Transform.Rotation.Angle += 0.01f;
+ public override void Update(double deltaTime, IInputContext input)
+ => _input.HandleKeyboard(input.Keyboards[0], (float)deltaTime);
// TODO: #21 Input system to let users change change key bindings?
///
@@ -238,7 +237,7 @@ public override void HandleKeyboard(IKeyboard input, double deltaTime)
if (input.IsKeyPressed(Key.Number0 + i))
{
_inventory.SetSelectedSlot(i);
- Debug.Log.Information("Selected slot: {I} ({Type})", i, _inventory.SelectedSlot.Items.Type);
+ _logger.LogInformation("Selected slot: {I} ({Type})", i, _inventory.SelectedSlot.Items.Type);
}
}
@@ -273,7 +272,7 @@ public override void HandleMouseDown(IMouse mouse, MouseButton button)
}
else
{
- Debug.Log.Information("No more {Type}s.", _inventory.SelectedSlot.Items.Type);
+ _logger.LogInformation("No more {Type}s.", _inventory.SelectedSlot.Items.Type);
}
}
@@ -284,7 +283,7 @@ public override void HandleMouseDown(IMouse mouse, MouseButton button)
{
// TODO: #86 The block should be added to the slot so that 0 is the last slot instead of 9.
// TODO: #86 The first block destroyed doesn't seem to be added to the inventory.
- Debug.Log.Information("Block destroyed: {DestroyedBlockType}.", destroyedBlockType);
+ _logger.LogInformation("Block destroyed: {DestroyedBlockType}.", destroyedBlockType);
_inventory.AddToolbarItem(destroyedBlockType);
}
}
@@ -313,7 +312,7 @@ private void PlaceBlock()
var newBlock = BlockFactory.CreateBlock(_inventory.SelectedSlot.Items.Type, newBlockPosition, $"Dirt ({_blocksNode.Children.Count})");
_blocksNode.AddChild(newBlock);
- Debug.Log.Information("New block created: {Pos}, block in view location: {IntersectingPos}", newBlock.Transform.Position, intersectingObject!.Transform.Position);
+ _logger.LogInformation("New block created: {Pos}, block in view location: {IntersectingPos}", newBlock.Transform.Position, intersectingObject!.Transform.Position);
}
private static Vector3 GetNewBlockPosition(Vector3 hitPosition, GameObject intersectingObject)
@@ -338,7 +337,7 @@ public override void HandleMouseWheel(MouseWheelScrollDirection direction, Scrol
slotIndex = 0;
_inventory.SetSelectedSlot(slotIndex);
- Debug.Log.Information("Selected slot: {Index}", slotIndex);
+ _logger.LogInformation("Selected slot: {Index}", slotIndex);
}
}
diff --git a/Examples/MinecraftClone/Minecraft.csproj b/Examples/MinecraftClone/Minecraft.csproj
new file mode 100644
index 0000000..447f24c
--- /dev/null
+++ b/Examples/MinecraftClone/Minecraft.csproj
@@ -0,0 +1,19 @@
+
+
+
+ Exe
+ $(DotNetTargetFramework)
+ AnyCPU;x64;x86
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Engine/Examples/MinecraftClone/Minecraft.sln b/Examples/MinecraftClone/Minecraft.sln
similarity index 100%
rename from Engine/Examples/MinecraftClone/Minecraft.sln
rename to Examples/MinecraftClone/Minecraft.sln
diff --git a/Examples/MinecraftClone/Program.cs b/Examples/MinecraftClone/Program.cs
new file mode 100644
index 0000000..97df2f9
--- /dev/null
+++ b/Examples/MinecraftClone/Program.cs
@@ -0,0 +1,69 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+
+using SharpEngine.Core.DependencyInjection;
+using SharpEngine.Core.Entities.Views;
+using SharpEngine.Core.Interfaces;
+using SharpEngine.Core.Renderers;
+using SharpEngine.Core.Scenes;
+using SharpEngine.Core.Windowing;
+
+namespace Minecraft;
+
+///
+/// Represents the entry point of the application.
+///
+public static class Program
+{
+ private static void Main()
+ {
+ var builder = new AppBuilder()
+ .ConfigureServices(ConfigureServices);
+
+ var app = builder.Build();
+ app.Run();
+ }
+
+ private static void ConfigureServices(IServiceCollection services)
+ {
+ services.AddLogging(builder => builder.AddConsole());
+
+ services.AddSingleton(_ => new DefaultSettings
+ {
+ UseWireFrame = false
+ });
+
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton(serviceProvider => serviceProvider.GetRequiredService().Camera);
+ services.AddTransient();
+ services.AddTransient();
+
+ services.AddWindow(
+ factory: serviceProvider =>
+ {
+ var game = serviceProvider.GetRequiredService();
+ var scene = serviceProvider.GetRequiredService();
+ var windowLogger = serviceProvider.GetRequiredService>();
+ var renderers = serviceProvider.GetServices();
+
+ return new Window(game.Camera, scene, game.Camera.Settings, windowLogger, renderers);
+ },
+ configure: (serviceProvider, window) =>
+ {
+ var game = serviceProvider.GetRequiredService();
+
+ window.OnLoaded += game.Initialize;
+ window.OnHandleMouse += game.HandleMouse;
+ window.OnUpdate += game.Update;
+ window.OnHandleKeyboard += game.HandleKeyboard;
+ window.OnButtonMouseDown += game.HandleMouseDown;
+ window.HandleMouseWheel += game.HandleMouseWheel;
+ window.OnAfterRender += game.OnAfterRender;
+
+ Minecraft.Window = window;
+ },
+ name: "minecraft",
+ isDefault: true);
+ }
+}
diff --git a/Engine/Examples/MinecraftClone/Resources/container2.png b/Examples/MinecraftClone/Resources/container2.png
similarity index 100%
rename from Engine/Examples/MinecraftClone/Resources/container2.png
rename to Examples/MinecraftClone/Resources/container2.png
diff --git a/Engine/Examples/MinecraftClone/Resources/container2_specular.png b/Examples/MinecraftClone/Resources/container2_specular.png
similarity index 100%
rename from Engine/Examples/MinecraftClone/Resources/container2_specular.png
rename to Examples/MinecraftClone/Resources/container2_specular.png
diff --git a/Engine/Examples/MinecraftClone/Resources/grass.jpg b/Examples/MinecraftClone/Resources/grass.jpg
similarity index 100%
rename from Engine/Examples/MinecraftClone/Resources/grass.jpg
rename to Examples/MinecraftClone/Resources/grass.jpg
diff --git a/Engine/Examples/Minimal/Minimal.csproj b/Examples/Minimal/Minimal.csproj
similarity index 82%
rename from Engine/Examples/Minimal/Minimal.csproj
rename to Examples/Minimal/Minimal.csproj
index 8bbdf5a..e786576 100644
--- a/Engine/Examples/Minimal/Minimal.csproj
+++ b/Examples/Minimal/Minimal.csproj
@@ -2,7 +2,7 @@
Exe
- net8.0
+ $(DotNetTargetFramework)enableenable
diff --git a/Engine/Examples/Minimal/Minimal.sln b/Examples/Minimal/Minimal.sln
similarity index 100%
rename from Engine/Examples/Minimal/Minimal.sln
rename to Examples/Minimal/Minimal.sln
diff --git a/Engine/Examples/Minimal/Program.cs b/Examples/Minimal/Program.cs
similarity index 61%
rename from Engine/Examples/Minimal/Program.cs
rename to Examples/Minimal/Program.cs
index 9751459..26310ec 100644
--- a/Engine/Examples/Minimal/Program.cs
+++ b/Examples/Minimal/Program.cs
@@ -1,5 +1,4 @@
using SharpEngine.Core.Interfaces;
-using SharpEngine.Core.Scenes;
using SharpEngine.Core.Windowing;
namespace Minimal;
@@ -14,10 +13,9 @@ public static class Program
///
public static void Main(string[] _)
{
- var game = new Minimal(new DefaultSettings());
- var scene = new Scene();
+ var game = new Minimal();
- using var window = new Window(game.Camera, scene, game.Camera.Settings);
+ using var window = new Window(game);
window.Run();
}
}
@@ -30,9 +28,7 @@ public class Minimal : Game
///
/// Initializes a new instance of
///
- /// Provides configuration options for the instance.
- public Minimal(ISettings settings)
+ public Minimal()
{
- CoreSettings = settings;
}
}
diff --git a/Engine/Examples/MultipleWindows/MultipleWindows.csproj b/Examples/MultipleWindows/MultipleWindows.csproj
similarity index 55%
rename from Engine/Examples/MultipleWindows/MultipleWindows.csproj
rename to Examples/MultipleWindows/MultipleWindows.csproj
index e48ece3..1596f7d 100644
--- a/Engine/Examples/MultipleWindows/MultipleWindows.csproj
+++ b/Examples/MultipleWindows/MultipleWindows.csproj
@@ -2,18 +2,12 @@
Exe
- net8.0
+ $(DotNetTargetFramework)enableenabletrue
-
-
-
-
-
-
diff --git a/Engine/Examples/MultipleWindows/Program.cs b/Examples/MultipleWindows/Program.cs
similarity index 68%
rename from Engine/Examples/MultipleWindows/Program.cs
rename to Examples/MultipleWindows/Program.cs
index 788b808..67751b3 100644
--- a/Engine/Examples/MultipleWindows/Program.cs
+++ b/Examples/MultipleWindows/Program.cs
@@ -1,10 +1,12 @@
-using Silk.NET.Input;
+using Microsoft.Extensions.Logging;
+using Silk.NET.Input;
using Silk.NET.Maths;
using Silk.NET.Windowing;
using System.Collections.Concurrent;
using SharpEngine.Core.Entities.Views.Settings;
-using SharpEngine.Shared;
+
+using Window = SharpEngine.Core.Windowing.Window;
namespace SharpEngine.Examples.MultipleWindows;
@@ -16,6 +18,10 @@ namespace SharpEngine.Examples.MultipleWindows;
///
public static partial class Program
{
+ private static readonly ILoggerFactory _loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
+ private static readonly ILogger _logger = _loggerFactory.CreateLogger(typeof(Program));
+ private static readonly ILogger _windowLogger = _loggerFactory.CreateLogger();
+
private static readonly List _windows = [];
private static readonly List _inputContexts = [];
private static readonly ConcurrentQueue _windowQueue = [];
@@ -25,28 +31,23 @@ public static partial class Program
/// The main entry point of the application.
///
/// Arguments discarded.
- public static void Main(string[] _)
+ public static async Task Main(string[] _)
{
- StartWindowQueueTask();
-
- try
- {
- while (!_cancellationTokenSource.IsCancellationRequested)
- {
- for (int i = 0; i < _windows.Count; i++)
- UpdateWindow(ref i);
-
- DequeueWindows();
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex.Message);
- }
- finally
- {
- _cancellationTokenSource.Dispose();
- }
+ Core.Handlers.WindowHandler windowHandler = new();
+ windowHandler.Start();
+
+ Console.WriteLine("end");
+ Console.ReadLine();
+
+ // StartWindowQueueTask();
+ //
+ // while (!_cancellationTokenSource.IsCancellationRequested)
+ // {
+ // for (int i = 0; i < _windows.Count; i++)
+ // UpdateWindow(ref i);
+ //
+ // DequeueWindows();
+ // }
}
private static void UpdateWindow(ref int i)
@@ -88,11 +89,11 @@ private static void StartWindowQueueTask()
while (!_cancellationTokenSource.IsCancellationRequested)
{
await Task.Delay(1000);
- Debug.Log.Information("Running loop on background thread...");
+ _logger.LogInformation("Running loop on background thread...");
}
});
- private static SharpEngine.Core.Windowing.Window CreateWindow()
+ private static Window CreateWindow()
{
var options = new DefaultViewSettings() with
{
@@ -106,8 +107,8 @@ private static SharpEngine.Core.Windowing.Window CreateWindow()
y: 400 + (50 * _windows.Count))
}
};
-
- var window = new SharpEngine.Core.Windowing.Window(new(), options);
+
+ var window = new Window(new(), options, _windowLogger);
window.Initialize();
return window;
@@ -123,8 +124,6 @@ private static void EnqueueWindow()
_windows.Add(window);
}
- private static void Mouse_Click(IMouse args1, Silk.NET.Input.MouseButton arg2, System.Numerics.Vector2 arg3)
- {
- _windowQueue.Enqueue(WindowOptions.Default);
- }
+ private static void Mouse_Click(IMouse args1, MouseButton arg2, System.Numerics.Vector2 arg3)
+ => _windowQueue.Enqueue(WindowOptions.Default);
}
diff --git a/Engine/Examples/Tutorial 4.1 - Model Loading/Program.cs b/Examples/Tutorial 4.1 - Model Loading/Program.cs
similarity index 78%
rename from Engine/Examples/Tutorial 4.1 - Model Loading/Program.cs
rename to Examples/Tutorial 4.1 - Model Loading/Program.cs
index 1bffe63..742d903 100644
--- a/Engine/Examples/Tutorial 4.1 - Model Loading/Program.cs
+++ b/Examples/Tutorial 4.1 - Model Loading/Program.cs
@@ -1,6 +1,7 @@
-using ObjLoader.Loaders.ObjLoader;
using SharpEngine.Core._Resources;
using SharpEngine.Core.Extensions;
+using SharpEngine.Core.Components.Properties.Meshes;
+using SharpEngine.Core.ObjLoader.Loaders.ObjLoader;
using Shader = SharpEngine.Core.Shaders.Shader;
using Texture = SharpEngine.Core.Components.Properties.Textures.Texture;
@@ -15,16 +16,20 @@
namespace Tutorial
{
+ ///
+ /// Represents the main entry point of the application, demonstrating model loading and rendering using Silk.NET and SharpEngine.Core.
+ ///
public static class Program
{
#region fields
- private static IWindow window;
- private static GL Gl;
- private static IKeyboard primaryKeyboard;
- private static Texture Texture;
- private static Shader Shader;
- private static List Models = [];
+ private static IWindow? window;
+ private static GL? Gl;
+ private static IKeyboard? primaryKeyboard;
+
+ private static Texture? Texture;
+ private static Shader? Shader;
+ private static readonly List _models = [];
//Setup the camera's location, directions, and movement speed
private static Vector3 CameraPosition = new(0.0f, 0.0f, 3.0f);
@@ -37,6 +42,7 @@ public static class Program
//Used to track change in mouse movement to allow for moving of the Camera
private static Vector2 LastMousePosition;
+
#endregion
private static void Main(string[] _)
@@ -59,11 +65,13 @@ private static void Main(string[] _)
private static void OnLoad()
{
+ if (window == null)
+ throw new NullReferenceException("Window is not initialized.");
+
IInputContext input = window.CreateInput();
primaryKeyboard = input.Keyboards[0];
- if (primaryKeyboard != null)
- primaryKeyboard.KeyDown += KeyDown;
+ primaryKeyboard?.KeyDown += KeyDown;
for (int i = 0; i < input.Mice.Count; i++)
{
@@ -79,12 +87,15 @@ private static void OnLoad()
var model = ObjLoaderFactory.Load(Gl, "Untitled2.obj");
- Models.Add(model);
- Models.Add(model);
+ _models.Add(model);
+ _models.Add(model);
}
private static void OnUpdate(double deltaTime)
{
+ if (primaryKeyboard == null)
+ throw new NullReferenceException("Primary keyboard is not initialized.");
+
var moveSpeed = 2.5f * (float) deltaTime;
//Move forwards
@@ -106,6 +117,12 @@ private static void OnUpdate(double deltaTime)
private static void OnRender(double deltaTime)
{
+ if (Gl == null)
+ throw new NullReferenceException("OpenGL context is not initialized.");
+
+ if (window == null)
+ throw new NullReferenceException("Window is not initialized.");
+
Gl.Enable(EnableCap.DepthTest);
Gl.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
@@ -121,17 +138,26 @@ private static void OnRender(double deltaTime)
//Note that the aspect ratio calculation must be performed as a float, otherwise integer division will be performed (truncating the result).
var projection = Matrix4x4.CreatePerspectiveFieldOfView(SharpEngine.Core.Math.DegreesToRadians(CameraZoom), (float)size.X / size.Y, 0.1f, 100.0f);
- for (int i = 0; i < Models.Count; i++)
+ for (int i = 0; i < _models.Count; i++)
{
if (i >= 1)
modelMatrix = Matrix4x4.CreateTranslation(0, -30.0f, 0.0f) * modelMatrix;
- RenderModel(Models[i], modelMatrix, view, projection);
+ RenderModel(_models[i], modelMatrix, view, projection);
}
}
- private static void RenderModel(Model_Old model, Matrix4x4 modelMatrix, Matrix4x4 view, Matrix4x4 projection)
+ private static void RenderModel(Model model, Matrix4x4 modelMatrix, Matrix4x4 view, Matrix4x4 projection)
{
+ if (Texture == null)
+ throw new NullReferenceException("Texture is not initialized.");
+
+ if (Shader == null)
+ throw new NullReferenceException("Shader is not initialized.");
+
+ if (Gl == null)
+ throw new NullReferenceException("OpenGL context is not initialized.");
+
foreach (var mesh in model.Meshes)
{
mesh.Bind();
@@ -148,7 +174,7 @@ private static void RenderModel(Model_Old model, Matrix4x4 modelMatrix, Matrix4x
}
}
- private static void OnFramebufferResize(Vector2D newSize) => Gl.Viewport(newSize);
+ private static void OnFramebufferResize(Vector2D newSize) => Gl!.Viewport(newSize);
private static void OnMouseMove(IMouse mouse, Vector2 position)
{
@@ -183,18 +209,18 @@ private static void OnMouseWheel(IMouse mouse, ScrollWheel scrollWheel)
private static void OnClose()
{
- foreach (var model in Models)
+ foreach (var model in _models)
model.Dispose();
- Shader.Dispose();
- Texture.Dispose();
+ Shader?.Dispose();
+ Texture?.Dispose();
}
private static void KeyDown(IKeyboard keyboard, Key key, int arg3)
{
if (key == Key.Escape)
{
- window.Close();
+ window!.Close();
}
}
}
diff --git a/Engine/Examples/Tutorial 4.1 - Model Loading/Tutorial 4.1 - Model Loading.csproj b/Examples/Tutorial 4.1 - Model Loading/Tutorial 4.1 - Model Loading.csproj
similarity index 56%
rename from Engine/Examples/Tutorial 4.1 - Model Loading/Tutorial 4.1 - Model Loading.csproj
rename to Examples/Tutorial 4.1 - Model Loading/Tutorial 4.1 - Model Loading.csproj
index 079bf1a..bbd8dbb 100644
--- a/Engine/Examples/Tutorial 4.1 - Model Loading/Tutorial 4.1 - Model Loading.csproj
+++ b/Examples/Tutorial 4.1 - Model Loading/Tutorial 4.1 - Model Loading.csproj
@@ -2,22 +2,10 @@
Exe
- net8.0
+ $(DotNetTargetFramework)Tutorial
-
-
-
-
-
-
-
diff --git a/Engine/Examples/Tutorial 4.1 - Model Loading/shader2.vert b/Examples/Tutorial 4.1 - Model Loading/shader2.vert
similarity index 100%
rename from Engine/Examples/Tutorial 4.1 - Model Loading/shader2.vert
rename to Examples/Tutorial 4.1 - Model Loading/shader2.vert
diff --git a/Engine/Examples/Tutorial 4.1 - Model Loading/silk.png b/Examples/Tutorial 4.1 - Model Loading/silk.png
similarity index 100%
rename from Engine/Examples/Tutorial 4.1 - Model Loading/silk.png
rename to Examples/Tutorial 4.1 - Model Loading/silk.png
diff --git a/ObjLoader/DataStore.cs b/ObjLoader/DataStore.cs
new file mode 100644
index 0000000..5833552
--- /dev/null
+++ b/ObjLoader/DataStore.cs
@@ -0,0 +1,83 @@
+using SharpEngine.Core.Components.ObjLoader.DataStore;
+using SharpEngine.Core.Components.Properties;
+using SharpEngine.Core.Components.Properties.Meshes.MeshData;
+using SharpEngine.Shared.Extensions;
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace SharpEngine.Core.ObjLoader
+{
+ ///
+ /// Stores parsed OBJ file data such as vertices, normals, texture coordinates, materials and groups.
+ /// This type is used by the OBJ loader type parsers to collect geometry and material information.
+ ///
+ ///
+ /// Stores parsed OBJ file data such as vertices, normals, texture coordinates, materials and groups.
+ /// This type is used by the OBJ loader type parsers to collect geometry and material information.
+ ///
+ public class DataStore : IGroupDataStore, IFaceGroup, ITextureDataStore, INormalDataStore, IVertexDataStore, IMaterialDataStore
+ {
+ private Group _currentGroup = null!;
+
+ /// Gets the list of parsed vertices.
+ public List Vertices { get; } = [];
+
+ /// Gets the list of parsed texture coordinates.
+ public List Textures { get; } = [];
+
+ /// Gets the list of parsed normals.
+ public List Normals { get; } = [];
+
+ /// Gets the collection of materials discovered in the file.
+ public List Materials { get; } = [];
+
+ /// Gets the list of groups present in the file.
+ public List Groups { get; } = [];
+
+ ///
+ /// Initializes a new instance of and creates a default group.
+ ///
+ public DataStore()
+ {
+ PushGroup("default");
+ }
+
+ ///
+ /// Adds a parsed face to the active group.
+ ///
+ /// The parsed face to add.
+ public void AddFace(Face face)
+ => _currentGroup.AddFace(face);
+
+ ///
+ /// Creates and activates a new group with the given name.
+ ///
+ /// The name of the group to create.
+ public void PushGroup(string groupName)
+ {
+ _currentGroup = new Group(groupName);
+ Groups.Add(_currentGroup);
+ }
+
+ ///
+ public void SetMaterial(string materialName)
+ {
+ // TOOD: This should probably throw or handle the case where the material is not found, but for now we'll just set it to null.
+ var material = Materials.SingleOrDefault(x => x.Name.EqualsOrdinalIgnoreCase(materialName));
+ _currentGroup.Material = material;
+ }
+
+ ///
+ public void AddTexture(TextureCoordinate texture)
+ => Textures.Add(texture);
+
+ ///
+ public void AddNormal(Normal normal)
+ => Normals.Add(normal);
+
+ ///
+ public void AddVertex(Vertex vertex)
+ => Vertices.Add(vertex);
+ }
+}
\ No newline at end of file
diff --git a/ObjLoader/IMaterialDataStore.cs b/ObjLoader/IMaterialDataStore.cs
new file mode 100644
index 0000000..38f3168
--- /dev/null
+++ b/ObjLoader/IMaterialDataStore.cs
@@ -0,0 +1,14 @@
+namespace SharpEngine.Core.ObjLoader;
+
+///
+/// Contains definitions for the material data store, which provides methods to manage material information during the OBJ file loading process.
+///
+public interface IMaterialDataStore
+{
+ ///
+ /// Sets the material for the current group.
+ ///
+ /// The name of the material to set.
+ public void SetMaterial(string materialName);
+
+}
\ No newline at end of file
diff --git a/ObjLoader/Loaders/LoaderBase.cs b/ObjLoader/Loaders/LoaderBase.cs
new file mode 100644
index 0000000..4ecbabc
--- /dev/null
+++ b/ObjLoader/Loaders/LoaderBase.cs
@@ -0,0 +1,50 @@
+using System.IO;
+
+namespace SharpEngine.Core.ObjLoader.Loader.Loaders
+{
+ ///
+ /// Represents a base class for loading .obj and .mtl files, providing common line parsing functionality.
+ ///
+ public abstract class LoaderBase
+ {
+ ///
+ /// Parses the file at the specified path and processes each line via .
+ ///
+ ///
+ /// I/O exceptions (for example FileNotFoundException, UnauthorizedAccessException, IOException) are propagated to the caller.
+ ///
+ /// The path of the file to open and parse.
+ public void ParseFile(string path)
+ {
+ using var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
+ using var lineStreamReader = new StreamReader(fileStream);
+
+ while (!lineStreamReader.EndOfStream)
+ {
+ var currentLine = lineStreamReader.ReadLine();
+
+ if (!string.IsNullOrWhiteSpace(currentLine))
+ ParseLine(currentLine);
+ }
+ }
+
+ private void ParseLine(string currentLine)
+ {
+ if (currentLine[0] == '#')
+ return;
+
+ var fields = currentLine.Trim().Split(null, 2);
+ var keyword = fields[0].Trim();
+ var data = fields[1].Trim();
+
+ ParseLine(keyword, data);
+ }
+
+ ///
+ /// Parses a single line consisting of a keyword and its associated data.
+ ///
+ /// Keyword that identifies the line type or command.
+ /// Data associated with the keyword; may be empty or contain parameters or raw text to interpret.
+ protected abstract void ParseLine(string keyword, string data);
+ }
+}
\ No newline at end of file
diff --git a/ObjLoader/Loaders/MaterialLoader/IMaterialLibraryLoaderFacade.cs b/ObjLoader/Loaders/MaterialLoader/IMaterialLibraryLoaderFacade.cs
new file mode 100644
index 0000000..5d4cde3
--- /dev/null
+++ b/ObjLoader/Loaders/MaterialLoader/IMaterialLibraryLoaderFacade.cs
@@ -0,0 +1,14 @@
+namespace SharpEngine.Core.ObjLoader.Loaders.MaterialLoader
+{
+ ///
+ /// Provides a facade for loading material library files into the application's material system.
+ ///
+ public interface IMaterialLibraryLoaderFacade
+ {
+ ///
+ /// Loads the specified material file into the application's material system.
+ ///
+ /// The name of the material file to load.
+ void Load(string materialFileName);
+ }
+}
\ No newline at end of file
diff --git a/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoader.cs b/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoader.cs
new file mode 100644
index 0000000..39aa7d3
--- /dev/null
+++ b/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoader.cs
@@ -0,0 +1,109 @@
+using SharpEngine.Core.Components.Properties;
+using SharpEngine.Core.ObjLoader.Loader.Loaders;
+using SharpEngine.Shared.Extensions;
+
+using System;
+using System.Collections.Generic;
+using System.Numerics;
+
+namespace SharpEngine.Core.ObjLoader.Loaders.MaterialLoader
+{
+ // https://paulbourke.net/dataformats/mtl/
+
+ ///
+ /// Handles loading of material libraries (.mtl files) referenced by .obj files.
+ ///
+ ///
+ /// Parses material properties and texture maps, and stores them in the provided .
+ /// Also handles opening material library files based on the path of the .obj file.
+ ///
+ public class MaterialLibraryLoader : LoaderBase
+ {
+ private readonly DataStore _dataStore;
+ private readonly Dictionary> _parseActionDictionary = [];
+ private readonly List _unrecognizedLines = [];
+
+ private Material _currentMaterial = new(string.Empty);
+
+ // TODO: #2 See Model class. This support both materials and textures
+
+ ///
+ /// Initializes a new instance of and registers parse actions for .mtl directives.
+ ///
+ ///
+ /// Registers parse actions for common .mtl directives (for example: newmtl, Ka, Kd, Ks,
+ /// Ns, d, Tr, illum, map_*, bump, disp, decal) to populate Material instances.
+ ///
+ /// DataStore used to register and store parsed materials and texture references.
+ public MaterialLibraryLoader(DataStore dataStore)
+ {
+ _dataStore = dataStore;
+
+ AddParseAction("newmtl", PushMaterial);
+ AddParseAction("Ka", d => _currentMaterial.AmbientColor = ParseVec3(d));
+ AddParseAction("Kd", d => _currentMaterial.DiffuseColor = ParseVec3(d));
+ AddParseAction("Ks", d => _currentMaterial.SpecularColor = ParseVec3(d));
+ AddParseAction("Ns", d => _currentMaterial.SpecularCoefficient = d.ParseInvariantFloat());
+
+ AddParseAction("d", d => _currentMaterial.Transparency = d.ParseInvariantFloat());
+ AddParseAction("Tr", d => _currentMaterial.Transparency = d.ParseInvariantFloat());
+
+ AddParseAction("illum", i => _currentMaterial.IlluminationModel = i.ParseInvariantInt());
+
+ AddParseAction("map_Ka", m => _currentMaterial.AmbientTextureMap = m);
+ AddParseAction("map_Kd", m => _currentMaterial.DiffuseTextureMap = m);
+
+ AddParseAction("map_Ks", m => _currentMaterial.SpecularTextureMap = m);
+ AddParseAction("map_Ns", m => _currentMaterial.SpecularHighlightTextureMap = m);
+
+ AddParseAction("map_d", m => _currentMaterial.AlphaTextureMap = m);
+
+ AddParseAction("map_bump", m => _currentMaterial.BumpMap = m);
+ AddParseAction("bump", m => _currentMaterial.BumpMap = m);
+
+ AddParseAction("disp", m => _currentMaterial.DisplacementMap = m);
+
+ AddParseAction("decal", m => _currentMaterial.StencilDecalMap = m);
+ }
+
+ private void AddParseAction(string key, Action action)
+ => _parseActionDictionary.Add(key.ToLowerInvariant(), action);
+
+ ///
+ protected override void ParseLine(string keyword, string data)
+ {
+ var parseAction = GetKeywordAction(keyword, out bool found);
+
+ if (!found)
+ {
+ _unrecognizedLines.Add(keyword + " " + data);
+ return;
+ }
+
+ parseAction!(data);
+ }
+
+ private Action? GetKeywordAction(string keyword, out bool found)
+ {
+ found = _parseActionDictionary.TryGetValue(keyword.ToLowerInvariant(), out var action);
+ return action;
+ }
+
+ private void PushMaterial(string materialName)
+ {
+ _currentMaterial = new Material(materialName);
+ _dataStore.Materials.Add(_currentMaterial);
+ }
+
+ private static Vector3 ParseVec3(string data)
+ {
+ string[] parts = data.Split(' ');
+
+ float x = parts[0].ParseInvariantFloat();
+ float y = parts[1].ParseInvariantFloat();
+ float z = parts[2].ParseInvariantFloat();
+
+ return new Vector3(x, y, z);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoaderFacade.cs b/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoaderFacade.cs
new file mode 100644
index 0000000..9ce3ee6
--- /dev/null
+++ b/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoaderFacade.cs
@@ -0,0 +1,43 @@
+using Microsoft.Extensions.Logging;
+using SharpEngine.Telemetry;
+using System.IO;
+
+namespace SharpEngine.Core.ObjLoader.Loaders.MaterialLoader
+{
+ ///
+ /// A facade for the to provide a simplified interface for loading material libraries.
+ ///
+ public class MaterialLibraryLoaderFacade : IMaterialLibraryLoaderFacade
+ {
+ private readonly ILogger _logger;
+ private readonly MaterialLibraryLoader _loader;
+ private readonly string _path;
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ /// Provides the functionality to load material libraries.
+ /// Optional path where the material file should exist.
+ /// The logger to use for logging messages.
+ public MaterialLibraryLoaderFacade(MaterialLibraryLoader loader, string path, ILogger? logger = null)
+ {
+ _loader = loader;
+ _path = path;
+
+ _logger = logger ?? LoggingExtensions.CreateLogger();
+ }
+
+ ///
+ public void Load(string materialFileName)
+ {
+ string materialFilePath = Path.Combine(Path.GetDirectoryName(_path)!, materialFileName);
+ if (!File.Exists(materialFilePath))
+ {
+ _logger.LogWarning("Material file '{MaterialFileName}' doesn't exist.", materialFileName);
+ return;
+ }
+
+ _loader.ParseFile(materialFilePath);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Engine/ObjLoader/Loaders/ObjLoader/ObjLoader.cs b/ObjLoader/Loaders/ObjLoader/ObjLoader.cs
similarity index 54%
rename from Engine/ObjLoader/Loaders/ObjLoader/ObjLoader.cs
rename to ObjLoader/Loaders/ObjLoader/ObjLoader.cs
index 798bc3c..cfcd5f0 100644
--- a/Engine/ObjLoader/Loaders/ObjLoader/ObjLoader.cs
+++ b/ObjLoader/Loaders/ObjLoader/ObjLoader.cs
@@ -1,14 +1,14 @@
-using ObjLoader.Loader.Loaders;
-using ObjLoader.TypeParsers;
-using SharpEngine.Core.Entities.Properties.Meshes;
-using Silk.NET.Core.Contexts;
+using SharpEngine.Core.Entities.Properties.Meshes;
+using SharpEngine.Core.ObjLoader.Loader.Loaders;
+using SharpEngine.Core.ObjLoader.TypeParsers;
using Silk.NET.OpenGL;
using System.Collections.Generic;
-using System.IO;
-using Tutorial;
-namespace ObjLoader.Loaders.ObjLoader
+namespace SharpEngine.Core.ObjLoader.Loaders.ObjLoader
{
+ ///
+ /// Loads an OBJ model file and converts its parsed data into runtime Mesh instances.
+ ///
public class ObjLoader : LoaderBase
{
private readonly string _path;
@@ -16,12 +16,22 @@ public class ObjLoader : LoaderBase
private readonly List _typeParsers = [];
private readonly List _unrecognizedLines = [];
+ ///
+ /// Initializes a new instance of with the specified file path and data store.
+ ///
+ /// The path to the OBJ file.
+ /// The data store to populate during parsing.
public ObjLoader(string path, DataStore dataStore)
{
_path = path;
_dataStore = dataStore;
}
+ ///
+ /// Adds the provided type parsers to the loader's internal list, enabling it to recognize and parse different line types in the OBJ file.
+ ///
+ /// The type parsers to add.
+ /// The current instance of .
public ObjLoader SetupTypeParsers(params ITypeParser[] parsers)
{
foreach (var parser in parsers)
@@ -43,10 +53,13 @@ protected override void ParseLine(string keyword, string data)
_unrecognizedLines.Add(keyword + " " + data);
}
+ ///
+ /// Loads the OBJ file and produces a list of objects suitable for rendering.
+ ///
+ /// The OpenGL context used to construct GPU resources.
public List Load(GL gl)
{
- var fileStream = new FileStream(_path, FileMode.Open, FileAccess.Read);
- StartLoad(fileStream);
+ ParseFile(_path);
return
[
diff --git a/Engine/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs b/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs
similarity index 61%
rename from Engine/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs
rename to ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs
index 408855c..5a7d90c 100644
--- a/Engine/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs
+++ b/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs
@@ -1,14 +1,15 @@
-using ObjLoader.Loader.TypeParsers;
-using ObjLoader.Loaders.MaterialLoader;
-
-using SharpEngine.Core.Entities.Properties.Meshes;
using Silk.NET.OpenGL;
+
using System;
using System.Collections.Generic;
using System.IO;
-using Tutorial;
-namespace ObjLoader.Loaders.ObjLoader
+using SharpEngine.Core.Entities.Properties.Meshes;
+using SharpEngine.Core.Components.Properties.Meshes;
+using SharpEngine.Core.ObjLoader.Loaders.MaterialLoader;
+using SharpEngine.Core.ObjLoader.Loader.TypeParsers;
+
+namespace SharpEngine.Core.ObjLoader.Loaders.ObjLoader
{
///
/// Handles loading 3D models.
@@ -22,10 +23,10 @@ public static class ObjLoaderFactory
/// Loads a mesh based on the file extension of the provided path.
///
/// The OpenGL context where the model should be bound.
- /// Specifies the file path of the mesh to be loaded, which determines the loading method based on its extension.
+ /// Specifies the file path of the mesh to be loaded, which determines the loading method based on its extension.
/// The model loaded from the file.
/// Thrown when the file extension of the provided path is not recognized as a supported mesh format.
- public static Model_Old Load(GL gl, string path)
+ public static Model Load(GL gl, string path)
=> Path.GetExtension(path) switch
{
FbxExtension => LoadFbx("", path),
@@ -34,18 +35,20 @@ public static Model_Old Load(GL gl, string path)
};
// TODO: #3 Load fbx mesh from file
- private static Model_Old LoadFbx(string identifier, string meshFilePath)
+ private static Model LoadFbx(string identifier, string meshFilePath)
{
throw new NotImplementedException();
}
- private static Model_Old LoadObj(GL gl, string path)
+ private static Model LoadObj(GL gl, string path)
{
- return new Model_Old(gl, path);
-
- // TOOD: Use the ObjLoader to load the model instead of the external library.
+ var meshes = LoadObjMeshes(gl, path);
+ return new Model(gl, path, meshes);
+ }
- /*var dataStore = new DataStore();
+ private static List LoadObjMeshes(GL gl, string path)
+ {
+ var dataStore = new DataStore();
var faceParser = new FaceParser(dataStore);
var groupParser = new GroupParser(dataStore);
@@ -53,13 +56,16 @@ private static Model_Old LoadObj(GL gl, string path)
var textureParser = new TextureParser(dataStore);
var vertexParser = new VertexParser(dataStore);
- var materialLibraryLoader = new MaterialLibraryLoader(path, dataStore);
- var materialLibraryParser = new MaterialLibraryParser(materialLibraryLoader);
+ var materialLibraryLoader = new MaterialLibraryLoader(dataStore);
+
+ var materialLoader = new MaterialLibraryLoaderFacade(materialLibraryLoader, path);
+ var materialLibraryParser = new MaterialLibraryParser(materialLoader);
var useMaterialParser = new UseMaterialParser(dataStore);
- var loader = new ObjLoader(path, dataStore).SetupTypeParsers(faceParser, groupParser, normalParser, textureParser, vertexParser, materialLibraryParser, useMaterialParser);
+ var loader = new ObjLoader(path, dataStore)
+ .SetupTypeParsers(faceParser, groupParser, normalParser, textureParser, vertexParser, materialLibraryParser, useMaterialParser);
+
return loader.Load(gl);
- */
}
}
}
\ No newline at end of file
diff --git a/Engine/ObjLoader/SharpEngine.Core.ObjLoader.csproj b/ObjLoader/SharpEngine.Core.ObjLoader.csproj
similarity index 60%
rename from Engine/ObjLoader/SharpEngine.Core.ObjLoader.csproj
rename to ObjLoader/SharpEngine.Core.ObjLoader.csproj
index 7cc24cf..7a52e96 100644
--- a/Engine/ObjLoader/SharpEngine.Core.ObjLoader.csproj
+++ b/ObjLoader/SharpEngine.Core.ObjLoader.csproj
@@ -1,16 +1,16 @@
-
+
- net8.0
+ $(DotNetTargetFramework)
-
+
-
+
\ No newline at end of file
diff --git a/Engine/ObjLoader/TypeParsers/FaceParser.cs b/ObjLoader/TypeParsers/FaceParser.cs
similarity index 73%
rename from Engine/ObjLoader/TypeParsers/FaceParser.cs
rename to ObjLoader/TypeParsers/FaceParser.cs
index c7328f7..0df5e68 100644
--- a/Engine/ObjLoader/TypeParsers/FaceParser.cs
+++ b/ObjLoader/TypeParsers/FaceParser.cs
@@ -1,15 +1,23 @@
-using ObjLoader.Loader.Common;
-using ObjLoader.Loader.Data.Elements;
-using ObjLoader.TypeParsers;
-using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore;
+using SharpEngine.Core.Components.ObjLoader.DataStore;
+using SharpEngine.Core.Components.Properties.Meshes.MeshData;
+using SharpEngine.Core.ObjLoader.TypeParsers;
+using SharpEngine.Shared.Extensions;
+
using System;
-namespace ObjLoader.Loader.TypeParsers
+namespace SharpEngine.Core.ObjLoader.Loader.TypeParsers
{
+ ///
+ /// Parses face definitions ("f") and populates the current group's faces.
+ ///
public class FaceParser : TypeParserBase, ITypeParser
{
private readonly IFaceGroup _faceGroup;
+ ///
+ /// Initializes a new instance of the .
+ ///
+ ///
public FaceParser(IFaceGroup faceGroup)
{
_faceGroup = faceGroup;
diff --git a/ObjLoader/TypeParsers/GroupParser.cs b/ObjLoader/TypeParsers/GroupParser.cs
new file mode 100644
index 0000000..e5dae69
--- /dev/null
+++ b/ObjLoader/TypeParsers/GroupParser.cs
@@ -0,0 +1,29 @@
+using SharpEngine.Core.Components.ObjLoader.DataStore;
+using SharpEngine.Core.ObjLoader.TypeParsers;
+
+namespace SharpEngine.Core.ObjLoader.Loader.TypeParsers
+{
+ ///
+ /// Parses group definition lines ("g") and pushes a new group into the data store.
+ ///
+ public class GroupParser : TypeParserBase, ITypeParser
+ {
+ private readonly IGroupDataStore _dataStore;
+
+ ///
+ /// Initializes a new instance of with the specified data store to populate during parsing.
+ ///
+ /// The data store to populate.
+ public GroupParser(IGroupDataStore dataStore)
+ {
+ _dataStore = dataStore;
+ }
+
+ ///
+ protected override string Keyword => "g";
+
+ ///
+ public override void Parse(string line)
+ => _dataStore.PushGroup(line);
+ }
+}
\ No newline at end of file
diff --git a/ObjLoader/TypeParsers/ITypeParser.cs b/ObjLoader/TypeParsers/ITypeParser.cs
new file mode 100644
index 0000000..1b041ba
--- /dev/null
+++ b/ObjLoader/TypeParsers/ITypeParser.cs
@@ -0,0 +1,21 @@
+namespace SharpEngine.Core.ObjLoader.TypeParsers
+{
+ ///
+ /// Defines a parser for handling different types of OBJ file lines.
+ ///
+ public interface ITypeParser
+ {
+ ///
+ /// Determines whether the specified keyword can be parsed.
+ ///
+ /// The keyword to check.
+ /// True if the keyword can be parsed; otherwise, false.
+ bool CanParse(string keyword);
+
+ ///
+ /// Parses a single input line and updates the object's state accordingly.
+ ///
+ /// The input line to parse.
+ void Parse(string line);
+ }
+}
\ No newline at end of file
diff --git a/ObjLoader/TypeParsers/MaterialLibraryParser.cs b/ObjLoader/TypeParsers/MaterialLibraryParser.cs
new file mode 100644
index 0000000..f622cc8
--- /dev/null
+++ b/ObjLoader/TypeParsers/MaterialLibraryParser.cs
@@ -0,0 +1,28 @@
+using SharpEngine.Core.ObjLoader.Loaders.MaterialLoader;
+using SharpEngine.Core.ObjLoader.TypeParsers;
+
+namespace SharpEngine.Core.ObjLoader.Loader.TypeParsers
+{
+ ///
+ /// Represents a parser for material library definitions in OBJ files, responsible for parsing lines that specify material libraries and delegating the loading of the material library to the provided loader facade.
+ ///
+ public class MaterialLibraryParser : TypeParserBase, ITypeParser
+ {
+ private readonly IMaterialLibraryLoaderFacade _libraryLoaderFacade;
+
+ ///
+ /// Initializes a new instance of the .
+ ///
+ /// The material library loader facade.
+ public MaterialLibraryParser(IMaterialLibraryLoaderFacade facade)
+ {
+ _libraryLoaderFacade = facade;
+ }
+
+ ///
+ protected override string Keyword => "mtllib";
+
+ ///
+ public override void Parse(string line) => _libraryLoaderFacade.Load(line);
+ }
+}
\ No newline at end of file
diff --git a/ObjLoader/TypeParsers/NormalParser.cs b/ObjLoader/TypeParsers/NormalParser.cs
new file mode 100644
index 0000000..af7974b
--- /dev/null
+++ b/ObjLoader/TypeParsers/NormalParser.cs
@@ -0,0 +1,40 @@
+using SharpEngine.Core.Components.ObjLoader.DataStore;
+using SharpEngine.Core.Components.Properties.Meshes.MeshData;
+using SharpEngine.Core.ObjLoader.TypeParsers;
+using SharpEngine.Shared.Extensions;
+
+namespace SharpEngine.Core.ObjLoader.Loader.TypeParsers
+{
+ ///
+ /// Represents a parser for normal vector definitions in an OBJ file, responsible for parsing lines that define vertex normals and storing them in the data store.
+ ///
+ public class NormalParser : TypeParserBase, ITypeParser
+ {
+ private readonly INormalDataStore _dataStore;
+
+ ///
+ /// Initializes a new instance of the .
+ ///
+ /// The data store to which the parsed normals will be added.
+ public NormalParser(INormalDataStore dataStore)
+ {
+ _dataStore = dataStore;
+ }
+
+ ///
+ protected override string Keyword => "vn";
+
+ ///
+ public override void Parse(string line)
+ {
+ string[] parts = line.Split(' ');
+
+ float x = parts[0].ParseInvariantFloat();
+ float y = parts[1].ParseInvariantFloat();
+ float z = parts[2].ParseInvariantFloat();
+
+ var normal = new Normal(x, y, z);
+ _dataStore.AddNormal(normal);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ObjLoader/TypeParsers/TextureParser.cs b/ObjLoader/TypeParsers/TextureParser.cs
new file mode 100644
index 0000000..43a2e8e
--- /dev/null
+++ b/ObjLoader/TypeParsers/TextureParser.cs
@@ -0,0 +1,39 @@
+using SharpEngine.Core.Components.ObjLoader.DataStore;
+using SharpEngine.Core.Components.Properties.Meshes.MeshData;
+using SharpEngine.Core.ObjLoader.TypeParsers;
+using SharpEngine.Shared.Extensions;
+
+namespace SharpEngine.Core.ObjLoader.Loader.TypeParsers
+{
+ ///
+ /// Represents a parser for texture coordinate definitions in an OBJ file, responsible for parsing lines that define texture coordinates and storing them in the data store.
+ ///
+ public class TextureParser : TypeParserBase, ITypeParser
+ {
+ private readonly ITextureDataStore _dataStore;
+
+ ///
+ /// Initializes a new instance of the .
+ ///
+ /// The data store to which the parsed texture coordinates will be added.
+ public TextureParser(ITextureDataStore dataStore)
+ {
+ _dataStore = dataStore;
+ }
+
+ ///
+ protected override string Keyword => "vt";
+
+ ///
+ public override void Parse(string line)
+ {
+ string[] parts = line.Split(' ');
+
+ float x = parts[0].ParseInvariantFloat();
+ float y = parts[1].ParseInvariantFloat();
+
+ var texture = new TextureCoordinate(x, y);
+ _dataStore.AddTexture(texture);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ObjLoader/TypeParsers/TypeParserBase.cs b/ObjLoader/TypeParsers/TypeParserBase.cs
new file mode 100644
index 0000000..7410790
--- /dev/null
+++ b/ObjLoader/TypeParsers/TypeParserBase.cs
@@ -0,0 +1,22 @@
+using SharpEngine.Core.ObjLoader.TypeParsers;
+using SharpEngine.Shared.Extensions;
+
+namespace SharpEngine.Core.ObjLoader.Loader.TypeParsers
+{
+ ///
+ /// Base implementation for OBJ file line type parsers. Provides a simple keyword matching helper.
+ ///
+ public abstract class TypeParserBase : ITypeParser
+ {
+ ///
+ /// The keyword this parser recognizes (e.g. "v", "vn", "f").
+ ///
+ protected abstract string Keyword { get; }
+
+ ///
+ public bool CanParse(string keyword) => keyword.EqualsOrdinalIgnoreCase(Keyword);
+
+ ///
+ public abstract void Parse(string line);
+ }
+}
\ No newline at end of file
diff --git a/ObjLoader/TypeParsers/UseMaterialParser.cs b/ObjLoader/TypeParsers/UseMaterialParser.cs
new file mode 100644
index 0000000..aa4d6eb
--- /dev/null
+++ b/ObjLoader/TypeParsers/UseMaterialParser.cs
@@ -0,0 +1,28 @@
+using SharpEngine.Core.Components.ObjLoader.DataStore;
+using SharpEngine.Core.ObjLoader.TypeParsers;
+
+namespace SharpEngine.Core.ObjLoader.Loader.TypeParsers
+{
+ ///
+ /// Parses material usage lines ("usemtl") and assigns materials to the current group.
+ ///
+ public class UseMaterialParser : TypeParserBase, ITypeParser
+ {
+ private readonly IMaterialDataStore _dataStore;
+
+ ///
+ /// Initializes a new instance of with the specified data store.
+ ///
+ /// The data store to use.
+ public UseMaterialParser(IMaterialDataStore dataStore)
+ {
+ _dataStore = dataStore;
+ }
+
+ ///
+ protected override string Keyword => "usemtl";
+
+ ///
+ public override void Parse(string line) => _dataStore.SetMaterial(line);
+ }
+}
\ No newline at end of file
diff --git a/Engine/ObjLoader/TypeParsers/VertexParser.cs b/ObjLoader/TypeParsers/VertexParser.cs
similarity index 52%
rename from Engine/ObjLoader/TypeParsers/VertexParser.cs
rename to ObjLoader/TypeParsers/VertexParser.cs
index d6b4fcf..94159b3 100644
--- a/Engine/ObjLoader/TypeParsers/VertexParser.cs
+++ b/ObjLoader/TypeParsers/VertexParser.cs
@@ -1,16 +1,24 @@
-using ObjLoader.Loader.Common;
-using ObjLoader.TypeParsers;
+using SharpEngine.Core.Components.ObjLoader.DataStore;
using SharpEngine.Core.Components.Properties.Meshes.MeshData;
+using SharpEngine.Core.ObjLoader.TypeParsers;
+using SharpEngine.Shared.Extensions;
+
using System;
-using Tutorial;
-namespace ObjLoader.Loader.TypeParsers
+namespace SharpEngine.Core.ObjLoader.Loader.TypeParsers
{
+ ///
+ /// Parses vertex position lines ("v x y z") and adds them to the data store.
+ ///
public class VertexParser : TypeParserBase, ITypeParser
{
- private readonly DataStore _dataStore;
+ private readonly IVertexDataStore _dataStore;
- public VertexParser(DataStore dataStore)
+ ///
+ /// Initializes a new instance of with the specified data store to populate.
+ ///
+ /// The data store to populate.
+ public VertexParser(IVertexDataStore dataStore)
{
_dataStore = dataStore;
}
@@ -31,7 +39,8 @@ public override void Parse(string line)
{
Position = new System.Numerics.Vector3(x, y, z),
};
- _dataStore.Vertices.Add(vertex);
+
+ _dataStore.AddVertex(vertex);
}
}
}
\ No newline at end of file
diff --git a/Engine/SharpEngine.Core.Components/IComponent.cs b/SharpEngine.Core.Components/IComponent.cs
similarity index 54%
rename from Engine/SharpEngine.Core.Components/IComponent.cs
rename to SharpEngine.Core.Components/IComponent.cs
index fdeaa85..5a744ba 100644
--- a/Engine/SharpEngine.Core.Components/IComponent.cs
+++ b/SharpEngine.Core.Components/IComponent.cs
@@ -8,6 +8,10 @@ namespace SharpEngine.Core.Components;
// TODO: #53 Entity Component System
+///
+/// Represents a generic component used by the entity component system.
+/// This interface is intentionally empty and serves as a marker for component types.
+///
internal interface IComponent
{
}
diff --git a/SharpEngine.Core.Components/ObjLoader/DataStore/IDataStore.cs b/SharpEngine.Core.Components/ObjLoader/DataStore/IDataStore.cs
new file mode 100644
index 0000000..ddb9558
--- /dev/null
+++ b/SharpEngine.Core.Components/ObjLoader/DataStore/IDataStore.cs
@@ -0,0 +1,10 @@
+namespace SharpEngine.Core.Components.ObjLoader.DataStore
+{
+ ///
+ /// Represents a data store that can be used to store and retrieve data related to the OBJ file loading process, such as vertex data, material information, and other relevant details.
+ /// This interface can be implemented by various classes to provide different storage mechanisms (e.g., in-memory, file-based, database) for managing the data during the OBJ loading process.
+ ///
+ public interface IDataStore
+ {
+ }
+}
\ No newline at end of file
diff --git a/SharpEngine.Core.Components/ObjLoader/DataStore/IFaceGroup.cs b/SharpEngine.Core.Components/ObjLoader/DataStore/IFaceGroup.cs
new file mode 100644
index 0000000..1ccee9c
--- /dev/null
+++ b/SharpEngine.Core.Components/ObjLoader/DataStore/IFaceGroup.cs
@@ -0,0 +1,19 @@
+using SharpEngine.Core.Components.Properties.Meshes.MeshData;
+
+namespace SharpEngine.Core.Components.ObjLoader.DataStore
+{
+ ///
+ /// Contains definitions for the interface, which represents a group of faces in an OBJ model, allowing for the organization and management of faces based on their associated materials or other grouping criteria.
+ ///
+ public interface IFaceGroup
+ {
+ ///
+ /// Adds a face to the face group.
+ ///
+ ///
+ /// This method allows for the inclusion of a face, represented by the class, into the group, enabling the organization of faces based on their associated materials or other grouping criteria.
+ ///
+ /// The face to add to the group.
+ void AddFace(Face face);
+ }
+}
\ No newline at end of file
diff --git a/SharpEngine.Core.Components/ObjLoader/DataStore/IGroupDataStore.cs b/SharpEngine.Core.Components/ObjLoader/DataStore/IGroupDataStore.cs
new file mode 100644
index 0000000..69bc335
--- /dev/null
+++ b/SharpEngine.Core.Components/ObjLoader/DataStore/IGroupDataStore.cs
@@ -0,0 +1,14 @@
+namespace SharpEngine.Core.Components.ObjLoader.DataStore
+{
+ ///
+ /// Defines operations for managing groups of faces while parsing OBJ files.
+ ///
+ public interface IGroupDataStore : IDataStore
+ {
+ ///
+ /// Creates and activates a new face group with the provided name.
+ ///
+ /// The name of the group to push.
+ void PushGroup(string groupName);
+ }
+}
\ No newline at end of file
diff --git a/SharpEngine.Core.Components/ObjLoader/DataStore/IMaterialLibrary.cs b/SharpEngine.Core.Components/ObjLoader/DataStore/IMaterialLibrary.cs
new file mode 100644
index 0000000..7a85ab6
--- /dev/null
+++ b/SharpEngine.Core.Components/ObjLoader/DataStore/IMaterialLibrary.cs
@@ -0,0 +1,16 @@
+using SharpEngine.Core.Components.Properties;
+
+namespace SharpEngine.Core.Components.ObjLoader.DataStore
+{
+ ///
+ /// Represents a storage for materials discovered while parsing an OBJ's associated MTL file.
+ ///
+ public interface IMaterialLibrary
+ {
+ ///
+ /// Adds a material to the library.
+ ///
+ /// The material to add.
+ void Push(Material material);
+ }
+}
diff --git a/SharpEngine.Core.Components/ObjLoader/DataStore/INormalDataStore.cs b/SharpEngine.Core.Components/ObjLoader/DataStore/INormalDataStore.cs
new file mode 100644
index 0000000..6c70e15
--- /dev/null
+++ b/SharpEngine.Core.Components/ObjLoader/DataStore/INormalDataStore.cs
@@ -0,0 +1,16 @@
+using SharpEngine.Core.Components.Properties.Meshes.MeshData;
+
+namespace SharpEngine.Core.Components.ObjLoader.DataStore
+{
+ ///
+ /// Defines storage operations for normal vector data parsed from an OBJ file.
+ ///
+ public interface INormalDataStore
+ {
+ ///
+ /// Adds a normal vector to the data store.
+ ///
+ /// The normal vector to add.
+ void AddNormal(Normal normal);
+ }
+}
diff --git a/SharpEngine.Core.Components/ObjLoader/DataStore/ITextureDataStore.cs b/SharpEngine.Core.Components/ObjLoader/DataStore/ITextureDataStore.cs
new file mode 100644
index 0000000..32ef8fb
--- /dev/null
+++ b/SharpEngine.Core.Components/ObjLoader/DataStore/ITextureDataStore.cs
@@ -0,0 +1,16 @@
+using SharpEngine.Core.Components.Properties.Meshes.MeshData;
+
+namespace SharpEngine.Core.Components.ObjLoader.DataStore
+{
+ ///
+ /// Defines storage operations for texture coordinate data parsed from an OBJ file.
+ ///
+ public interface ITextureDataStore
+ {
+ ///
+ /// Adds a texture coordinate to the underlying data store.
+ ///
+ /// The texture coordinate to add.
+ void AddTexture(TextureCoordinate texture);
+ }
+}
diff --git a/SharpEngine.Core.Components/ObjLoader/DataStore/IVertexDataStore.cs b/SharpEngine.Core.Components/ObjLoader/DataStore/IVertexDataStore.cs
new file mode 100644
index 0000000..b143211
--- /dev/null
+++ b/SharpEngine.Core.Components/ObjLoader/DataStore/IVertexDataStore.cs
@@ -0,0 +1,16 @@
+using SharpEngine.Core.Components.Properties.Meshes.MeshData;
+
+namespace SharpEngine.Core.Components.ObjLoader.DataStore
+{
+ ///
+ /// Defines storage operations for vertex data parsed from an OBJ file.
+ ///
+ public interface IVertexDataStore
+ {
+ ///
+ /// Adds a vertex to the underlying data store.
+ ///
+ /// The vertex to add.
+ void AddVertex(Vertex vertex);
+ }
+}
diff --git a/Engine/SharpEngine.Core.Components/Properties/BoundingBox.cs b/SharpEngine.Core.Components/Properties/BoundingBox.cs
similarity index 100%
rename from Engine/SharpEngine.Core.Components/Properties/BoundingBox.cs
rename to SharpEngine.Core.Components/Properties/BoundingBox.cs
diff --git a/Engine/SharpEngine.Core.Components/Properties/ITransform.cs b/SharpEngine.Core.Components/Properties/ITransform.cs
similarity index 100%
rename from Engine/SharpEngine.Core.Components/Properties/ITransform.cs
rename to SharpEngine.Core.Components/Properties/ITransform.cs
diff --git a/Engine/SharpEngine.Core.Components/Properties/Material.cs b/SharpEngine.Core.Components/Properties/Material.cs
similarity index 69%
rename from Engine/SharpEngine.Core.Components/Properties/Material.cs
rename to SharpEngine.Core.Components/Properties/Material.cs
index 07c21be..5d01401 100644
--- a/Engine/SharpEngine.Core.Components/Properties/Material.cs
+++ b/SharpEngine.Core.Components/Properties/Material.cs
@@ -8,14 +8,15 @@ namespace SharpEngine.Core.Components.Properties;
///
/// Represents the material rendered onto a game object.
///
-public class Material
+public class Material : ICloneable, IEquatable
{
///
/// Initializes a new instance of .
///
+ /// The name assigned to the new material.
/// The diffuse map texture of the material.
/// The specular map texture of the material. Defaults to the diffuse map if not provided.
- public Material(Texture diffuseMap, Texture? specularMap = null)
+ public Material(string materialName, Texture? diffuseMap = null, Texture? specularMap = null) : this(materialName)
{
DiffuseMap = diffuseMap;
SpecularMap = specularMap ?? diffuseMap;
@@ -37,19 +38,19 @@ public Material(string materialName)
public string Name { get; set; }
/// Gets or sets the diffuse map texture.
- public Texture DiffuseMap { get; set; }
+ public Texture? DiffuseMap { get; set; }
/// Gets or sets the path to the diffuse texture map.
- public string DiffuseTextureMap { get; set; }
+ public string? DiffuseTextureMap { get; set; }
/// Gets or sets the specular map texture.
- public Texture SpecularMap { get; set; }
+ public Texture? SpecularMap { get; set; }
/// Gets or sets the path to the specular texture map.
- public string SpecularTextureMap { get; set; }
+ public string? SpecularTextureMap { get; set; }
/// Gets a value indicating whether the material uses a specular map.
- public bool UseSpecularMap => SpecularMap.Handle != DiffuseMap.Handle;
+ public bool UseSpecularMap => SpecularMap is not null && SpecularMap?.Handle != DiffuseMap?.Handle;
/// The texture unit for the diffuse map.
public const int DIFFUSE_UNIT = 0;
@@ -82,22 +83,22 @@ public Material(string materialName)
public int IlluminationModel { get; set; }
/// Gets or sets the path to the ambient texture map.
- public string AmbientTextureMap { get; set; }
+ public string? AmbientTextureMap { get; set; }
/// Gets or sets the path to the specular highlight texture map.
- public string SpecularHighlightTextureMap { get; set; }
+ public string? SpecularHighlightTextureMap { get; set; }
/// Gets or sets the path to the bump map.
- public string BumpMap { get; set; }
+ public string? BumpMap { get; set; }
/// Gets or sets the path to the displacement map.
- public string DisplacementMap { get; set; }
+ public string? DisplacementMap { get; set; }
/// Gets or sets the path to the stencil decal map.
- public string StencilDecalMap { get; set; }
+ public string? StencilDecalMap { get; set; }
/// Gets or sets the path to the alpha texture map.
- public string AlphaTextureMap { get; set; }
+ public string? AlphaTextureMap { get; set; }
///
/// Sets the uniform values for the material in the specified shader.
@@ -107,21 +108,50 @@ public void SetUniformValues(Shader shader)
{
// TODO: Get all shader uniforms and set their values automatically
- DiffuseMap.Use(TextureUnit.Texture0);
- shader.SetInt("material.diffuse", DIFFUSE_UNIT);
+ if (DiffuseMap is not null)
+ {
+ DiffuseMap.Use(TextureUnit.Texture0);
+ shader.SetInt("material.diffuse", DIFFUSE_UNIT);
+ }
- if (UseSpecularMap)
+ if (SpecularMap is not null)
{
SpecularMap.Use(TextureUnit.Texture1);
shader.SetInt("material.specular", SPECULAR_UNIT);
- shader.SetVector3("material.specular", Specular);
shader.SetFloat("material.shininess", Shininess);
}
else
{
- shader.SetInt("material.specular", 0);
- shader.SetVector3("material.specular", Vector3.Zero);
+ shader.SetInt("material.specular", DIFFUSE_UNIT);
shader.SetFloat("material.shininess", 0);
}
}
+
+ ///
+ public object Clone()
+ => MemberwiseClone();
+
+ ///
+ public override bool Equals(object? obj)
+ {
+ if (obj is null)
+ return false;
+
+ if (ReferenceEquals(this, obj))
+ return true;
+
+ if (GetType() != obj.GetType())
+ return false;
+
+ return true;
+ }
+
+ ///
+ public bool Equals(Material? other) => Equals(other);
+
+ ///
+ public override int GetHashCode()
+ {
+ throw new NotImplementedException();
+ }
}
diff --git a/Engine/SharpEngine.Core.Components/Properties/Meshes/BufferObject.cs b/SharpEngine.Core.Components/Properties/Meshes/BufferObject.cs
similarity index 83%
rename from Engine/SharpEngine.Core.Components/Properties/Meshes/BufferObject.cs
rename to SharpEngine.Core.Components/Properties/Meshes/BufferObject.cs
index 1279b1d..9035976 100644
--- a/Engine/SharpEngine.Core.Components/Properties/Meshes/BufferObject.cs
+++ b/SharpEngine.Core.Components/Properties/Meshes/BufferObject.cs
@@ -1,12 +1,12 @@
using Silk.NET.OpenGL;
using System.Runtime.InteropServices;
-namespace SharpEngine.Core.Components.Properties.Meshes.MeshData
+namespace SharpEngine.Core.Components.Properties.Meshes
{
///
- /// Represents a buffer object in OpenGL that manages memory allocation and data transfer for a specific data type.
+ /// Represents an OpenGL buffer object that manages memory allocation and data transfer for a specific value type.
///
- /// Specifies the type of data stored in the buffer, which must be an unmanaged type for proper memory handling.
+ /// The unmanaged element type stored in the buffer.
public class BufferObject : IDisposable where TDataType : unmanaged
{
private readonly uint _handle;
diff --git a/Engine/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs
similarity index 92%
rename from Engine/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs
rename to SharpEngine.Core.Components/Properties/Meshes/Mesh.cs
index e6f66fc..bf63131 100644
--- a/Engine/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs
+++ b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs
@@ -1,17 +1,15 @@
-using ObjLoader.Loader.Data.Elements;
-using SharpEngine.Core.Attributes;
+using SharpEngine.Core.Attributes;
using SharpEngine.Core.Components.Properties;
+using SharpEngine.Core.Components.Properties.Meshes;
using SharpEngine.Core.Components.Properties.Meshes.MeshData;
using Silk.NET.OpenGL;
-using Tutorial;
-
+using System.Diagnostics.CodeAnalysis;
using Texture2 = SharpEngine.Core.Components.Properties.Textures.Texture;
namespace SharpEngine.Core.Entities.Properties.Meshes;
///
-/// Represents a game object mesh, which is a collection of vertices, normals, texture coordinates, and indices
-/// used to define the shape and appearance of a 3D object.
+/// Represents a mesh composed of vertex data, indices, textures and materials which can be uploaded to GPU buffers.
///
public class Mesh : IDisposable
{
@@ -74,17 +72,17 @@ public class Mesh : IDisposable
///
/// Gets or sets the textures used by the mesh.
///
- public IReadOnlyList Textures { get; set; }
+ public IReadOnlyList Textures { get; set; } = [];
///
/// Gets or sets the legacy textures used by the mesh.
///
- public IReadOnlyList Textures_Old { get; set; }
+ public IReadOnlyList Textures_Old { get; set; } = [];
///
/// Gets or sets the Vertex Array Object (VAO) for the mesh.
///
- public VertexArrayObject VAO { get; set; }
+ public VertexArrayObject VAO { get; private set; }
///
/// Gets or sets the Vertex Buffer Object (VBO) for the mesh.
@@ -146,6 +144,7 @@ public Mesh(GL gl)
///
/// Allocates the required memory for the mesh and sets up the Vertex Array Object (VAO), Vertex Buffer Object (VBO), and Element Buffer Object (EBO).
///
+ [MemberNotNull(nameof(EBO), nameof(VBO), nameof(VAO))]
public void SetupMesh()
{
EBO = new BufferObject(GL, Indices, BufferTargetARB.ElementArrayBuffer);
diff --git a/SharpEngine.Core.Components/Properties/Meshes/MeshData/Face.cs b/SharpEngine.Core.Components/Properties/Meshes/MeshData/Face.cs
new file mode 100644
index 0000000..39b7b76
--- /dev/null
+++ b/SharpEngine.Core.Components/Properties/Meshes/MeshData/Face.cs
@@ -0,0 +1,59 @@
+namespace SharpEngine.Core.Components.Properties.Meshes.MeshData
+{
+ ///
+ /// Represents a face in a 3D mesh, which is defined by a list of vertices.
+ ///
+ ///
+ /// Each vertex is represented by a struct that contains indices for the vertex position, texture coordinate, and normal vector.
+ ///
+ public class Face
+ {
+ private readonly List _vertices = [];
+
+ ///
+ /// Adds a vertex to the face.
+ ///
+ /// The vertex to add.
+ public void AddVertex(FaceVertex vertex) => _vertices.Add(vertex);
+
+ ///
+ /// An indexer to access the vertices of the face by their index.
+ ///
+ /// The index of the vertex to access.
+ /// The vertex at the specified index.
+ public FaceVertex this[int i] => _vertices[i];
+
+ /// Gets the number of vertices in the face.
+ public int Count => _vertices.Count;
+ }
+
+ ///
+ /// Represents a vertex in a face, which contains indices for the vertex position, texture coordinate, and normal vector.
+ ///
+ public struct FaceVertex
+ {
+ ///
+ /// Initializes a new instance of the .
+ ///
+ /// The index of the vertex position.
+ /// The index of the texture coordinate.
+ /// The index of the normal vector.
+ public FaceVertex(int vertexIndex, int textureIndex, int normalIndex)
+ {
+ VertexIndex = vertexIndex;
+ TextureIndex = textureIndex;
+ NormalIndex = normalIndex;
+ }
+
+ ///
+ /// Gets or sets the index of the vertex position in the mesh's vertex list.
+ ///
+ public int VertexIndex { get; set; }
+
+ /// Gets or sets the index of the texture coordinate in the mesh's texture coordinate list.
+ public int TextureIndex { get; set; }
+
+ /// Gets or sets the index of the normal vector in the mesh's normal vector list.
+ public int NormalIndex { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SharpEngine.Core.Components/Properties/Meshes/MeshData/Group.cs b/SharpEngine.Core.Components/Properties/Meshes/MeshData/Group.cs
new file mode 100644
index 0000000..504d811
--- /dev/null
+++ b/SharpEngine.Core.Components/Properties/Meshes/MeshData/Group.cs
@@ -0,0 +1,38 @@
+using SharpEngine.Core.Components.ObjLoader.DataStore;
+
+namespace SharpEngine.Core.Components.Properties.Meshes.MeshData
+{
+ ///
+ /// Represents a group of faces in a mesh, which can be used to organize faces that share the same material or other properties.
+ ///
+ public class Group : IFaceGroup
+ {
+ private readonly List _faces = [];
+
+ ///
+ /// Initializes a new instance of the .
+ ///
+ /// The name of the group.
+ public Group(string name)
+ {
+ Name = name;
+ }
+
+ ///
+ /// Gets the name of the group, which can be used to identify the group and associate it with specific materials or properties in the mesh.
+ ///
+ public string Name { get; private set; }
+
+ /// Gets or sets the material associated with the group, which defines the appearance of the faces in the group when rendered.
+ public Material? Material { get; set; }
+
+ /// Gets the list of faces that belong to the group.
+ public IList Faces => _faces;
+
+ ///
+ /// Adds a face to the group.
+ ///
+ /// The face to add to the group.
+ public void AddFace(Face face) => _faces.Add(face);
+ }
+}
\ No newline at end of file
diff --git a/SharpEngine.Core.Components/Properties/Meshes/MeshData/Normal.cs b/SharpEngine.Core.Components/Properties/Meshes/MeshData/Normal.cs
new file mode 100644
index 0000000..44e220f
--- /dev/null
+++ b/SharpEngine.Core.Components/Properties/Meshes/MeshData/Normal.cs
@@ -0,0 +1,36 @@
+namespace SharpEngine.Core.Components.Properties.Meshes.MeshData
+{
+ ///
+ /// Represents a normal vector in 3D space, which is used in mesh data to define the direction perpendicular to the surface of a triangle, affecting how light interacts with the surface for rendering purposes.
+ ///
+ public struct Normal
+ {
+ ///
+ /// Initializes a new instance of the struct with the specified x, y, and z components, representing the normal vector's direction in 3D space.
+ ///
+ /// The x-component of the normal vector.
+ /// The y-component of the normal vector.
+ /// The z-component of the normal vector.
+ public Normal(float x, float y, float z) : this()
+ {
+ X = x;
+ Y = y;
+ Z = z;
+ }
+
+ ///
+ /// Gets the x-component of the normal vector, representing the horizontal direction in 3D space.
+ ///
+ public float X { get; private set; }
+
+ ///
+ /// Gets the y-component of the normal vector, representing the vertical direction in 3D space.
+ ///
+ public float Y { get; private set; }
+
+ ///
+ /// Gets the z-component of the normal vector, representing the depth direction in 3D space.
+ ///
+ public float Z { get; private set; }
+ }
+}
\ No newline at end of file
diff --git a/SharpEngine.Core.Components/Properties/Meshes/MeshData/TextureCoordinate.cs b/SharpEngine.Core.Components/Properties/Meshes/MeshData/TextureCoordinate.cs
new file mode 100644
index 0000000..c997bf8
--- /dev/null
+++ b/SharpEngine.Core.Components/Properties/Meshes/MeshData/TextureCoordinate.cs
@@ -0,0 +1,36 @@
+namespace SharpEngine.Core.Components.Properties.Meshes.MeshData
+{
+ ///
+ /// Represents a texture coordinate, which is used to map textures onto the surface of a 3D model.
+ /// Each texture coordinate consists of two components: X and Y, which range from 0 to 1, where (0,0) corresponds to the bottom-left corner of the texture and (1,1) corresponds to the top-right corner.
+ ///
+ public struct TextureCoordinate
+ {
+ ///
+ /// Initializes a new instance of the struct with the specified X and Y values.
+ ///
+ /// The X-component of the texture coordinate.
+ /// The Y-component of the texture coordinate.
+ public TextureCoordinate(float x, float y) : this()
+ {
+ X = x;
+ Y = y;
+ }
+
+ ///
+ /// Gets the X-component of the texture coordinate, which represents the horizontal position on the texture map.
+ ///
+ ///
+ /// The value ranges from 0 to 1, where 0 corresponds to the left edge of the texture and 1 corresponds to the right edge.
+ ///
+ public float X { get; private set; }
+
+ ///
+ /// Gets the Y-component of the texture coordinate, which represents the vertical position on the texture map.
+ ///
+ ///
+ /// The value ranges from 0 to 1, where 0 corresponds to the bottom edge of the texture and 1 corresponds to the top edge.
+ ///
+ public float Y { get; private set; }
+ }
+}
\ No newline at end of file
diff --git a/SharpEngine.Core.Components/Properties/Meshes/MeshData/Vertex.cs b/SharpEngine.Core.Components/Properties/Meshes/MeshData/Vertex.cs
new file mode 100644
index 0000000..9a5bdfd
--- /dev/null
+++ b/SharpEngine.Core.Components/Properties/Meshes/MeshData/Vertex.cs
@@ -0,0 +1,56 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Numerics;
+
+namespace SharpEngine.Core.Components.Properties.Meshes.MeshData
+{
+ ///
+ /// Represents a vertex in a 3D mesh.
+ ///
+ public struct Vertex
+ {
+ ///
+ /// The position of the vertex in 3D space, represented as a containing the X, Y, and Z coordinates.
+ ///
+ public Vector3 Position;
+
+ ///
+ /// The normal vector at the vertex, which is used for lighting calculations to determine how light interacts with the surface of the mesh.
+ ///
+ public Vector3 Normal;
+
+ ///
+ /// The tangent vector at the vertex, which is used in conjunction with the normal and bitangent vectors to create a tangent space for normal mapping and other advanced shading techniques.
+ ///
+ public Vector3 Tangent;
+
+ ///
+ /// The texture coordinates (UV coordinates) for the vertex, represented as a containing the U and V coordinates that map the vertex to a specific point on a texture image.
+ ///
+ public Vector2 TexCoords;
+
+ ///
+ /// The bitangent vector at the vertex, which is used in conjunction with the normal and tangent vectors to create a tangent space for normal mapping and other advanced shading techniques.
+ ///
+ public Vector3 Bitangent;
+
+ // TODO: #65 Skeletal mesh
+
+ ///
+ /// The maximum number of bone influences that can affect a single vertex, which is typically set to 4 in many 3D graphics applications to balance performance and visual quality when animating skeletal meshes.
+ ///
+ public const int MAX_BONE_INFLUENCE = 4;
+
+ ///
+ /// The IDs of the bones that influence this vertex, where each ID corresponds to a specific bone in the skeleton of a skeletal mesh.
+ /// The length of this array should not exceed to ensure efficient processing during animation.
+ ///
+ public int[] BoneIds;
+
+ ///
+ /// The weights corresponding to each bone influence on this vertex, where each weight represents the degree of influence that a particular bone has on the vertex's position during skeletal animation.
+ ///
+ public float[] Weights;
+ }
+}
diff --git a/Engine/SharpEngine.Core.Components/Properties/Meshes/MeshExtensions.cs b/SharpEngine.Core.Components/Properties/Meshes/MeshExtensions.cs
similarity index 93%
rename from Engine/SharpEngine.Core.Components/Properties/Meshes/MeshExtensions.cs
rename to SharpEngine.Core.Components/Properties/Meshes/MeshExtensions.cs
index b28219a..908e955 100644
--- a/Engine/SharpEngine.Core.Components/Properties/Meshes/MeshExtensions.cs
+++ b/SharpEngine.Core.Components/Properties/Meshes/MeshExtensions.cs
@@ -1,6 +1,4 @@
-using System.Collections.Generic;
-
-namespace SharpEngine.Core.Entities.Properties.Meshes;
+namespace SharpEngine.Core.Entities.Properties.Meshes;
///
/// Contains extension methods for handling meshes.
diff --git a/SharpEngine.Core.Components/Properties/Meshes/Model.cs b/SharpEngine.Core.Components/Properties/Meshes/Model.cs
new file mode 100644
index 0000000..e5ba6b5
--- /dev/null
+++ b/SharpEngine.Core.Components/Properties/Meshes/Model.cs
@@ -0,0 +1,304 @@
+using SharpEngine.Core.Components.Properties.Meshes.MeshData;
+using SharpEngine.Core.Entities.Properties.Meshes;
+using EngineTexture = SharpEngine.Core.Components.Properties.Textures.Texture;
+using EngineTextureType = SharpEngine.Core.Components.Properties.Textures.TextureType;
+
+using Silk.NET.OpenGL;
+
+namespace SharpEngine.Core.Components.Properties.Meshes
+{
+ ///
+ /// Represents a 3D model, which may consist of multiple meshes, materials, and textures.
+ ///
+ ///
+ /// This class is responsible for processing raw mesh data into a format suitable for rendering, including expanding vertices based on face definitions and building materials and textures as needed.
+ ///
+ public class Model : IDisposable
+ {
+ private readonly GL _gl;
+
+ /// Gets the file path to where the model is stored.
+ public string Path { get; }
+
+ /// Gets the list of meshes contained within the model.
+ public List Meshes { get; set; } = [];
+
+ ///
+ /// Initializes a new instance of the Model class with the specified OpenGL context and model file path.
+ ///
+ /// The GL context used for rendering and resource management.
+ /// The file path of the model asset.
+ public Model(GL gl, string path)
+ {
+ _gl = gl;
+ Path = path;
+ }
+
+ ///
+ /// Initializes a new instance of the Model class, stores the GL context and path, and processes the provided meshes.
+ ///
+ ///
+ /// Input meshes are enumerated and processed immediately to populate the Model's Meshes collection.
+ ///
+ /// The OpenGL context used for creating and managing rendering resources.
+ /// The file path of the model resource.
+ /// A sequence of meshes to be processed and stored; each mesh is converted via ProcessMesh.
+ public Model(GL gl, string path, IEnumerable meshes)
+ {
+ _gl = gl;
+ Path = path;
+ Meshes = [.. meshes.Select(ProcessMesh)];
+ }
+
+ ///
+ public void Dispose()
+ {
+ foreach (var mesh in Meshes)
+ mesh.Dispose();
+
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Produces a GPU-ready Mesh from the provided mesh by cloning when already processed or by expanding vertices and constructing indices, materials, and textures.
+ ///
+ /// Source mesh to process. Must not be null.
+ ///
+ /// A Mesh prepared for rendering: either a cloned processed mesh if the input already contains vertex buffer
+ /// data, or a newly constructed Mesh with expanded vertices, generated index buffer, and associated textures
+ /// and materials.
+ ///
+ /// Thrown if the input mesh is null.
+ public Mesh ProcessMesh(Mesh mesh)
+ {
+ ArgumentNullException.ThrowIfNull(mesh);
+
+ // TODO: Instead of cloning the object, we should just update the values.
+ if (mesh.Vertices.Length > 0)
+ return CloneProcessedMesh(mesh);
+
+ var vertices = ExpandVertices(mesh);
+ var indices = Enumerable.Range(0, vertices.Count).Select(index => (uint)index).ToArray();
+ var materials = BuildMaterials(mesh).ToList();
+ var textures = BuildTextures(materials).ToList();
+
+ // TODO: Instead of cloning the object, we should just update the values.
+ return new Mesh(_gl, BuildVertices(vertices), indices, textures)
+ {
+ Name = mesh.Name,
+ Vertices2 = vertices,
+ Normals2 = mesh.Normals2,
+ TextureCoordinates2 = mesh.TextureCoordinates2,
+ Groups = mesh.Groups,
+ Materials = materials,
+ };
+ }
+
+ private Mesh CloneProcessedMesh(Mesh template)
+ {
+ var materials = template.Materials.Select(CloneMaterial).ToList();
+ var textures = materials.Count > 0 ? BuildTextures(materials) : CloneTextures(template.Textures);
+
+ return new Mesh(_gl, template.Vertices, template.Indices, textures.ToList())
+ {
+ Name = template.Name,
+ Vertices2 = template.Vertices2,
+ Normals2 = template.Normals2,
+ TextureCoordinates2 = template.TextureCoordinates2,
+ Groups = template.Groups,
+ Materials = materials,
+ };
+ }
+
+ private static List ExpandVertices(Mesh mesh)
+ {
+ var vertices = new List();
+
+ foreach (var faceVertex in EnumerateFaceVertices(mesh.Groups))
+ vertices.Add(CreateVertex(mesh, faceVertex));
+
+ if (vertices.Count > 0)
+ return vertices;
+
+ return [.. mesh.Vertices2.Select(vertex =>
+ {
+ vertex.BoneIds ??= new int[Vertex.MAX_BONE_INFLUENCE];
+ vertex.Weights ??= new float[Vertex.MAX_BONE_INFLUENCE];
+ return vertex;
+ })];
+ }
+
+ private static IEnumerable EnumerateFaceVertices(IEnumerable groups)
+ {
+ foreach (var group in groups)
+ foreach (var face in group.Faces)
+ for (int i = 0; i < face.Count; i++)
+ yield return face[i];
+ }
+
+ private static Vertex CreateVertex(Mesh mesh, FaceVertex faceVertex)
+ => new()
+ {
+ BoneIds = new int[Vertex.MAX_BONE_INFLUENCE],
+ Weights = new float[Vertex.MAX_BONE_INFLUENCE],
+ Position = GetVertexPosition(mesh, faceVertex.VertexIndex),
+ Normal = GetNormal(mesh, faceVertex.NormalIndex),
+ TexCoords = GetTextureCoordinates(mesh, faceVertex.TextureIndex),
+ };
+
+ private static System.Numerics.Vector3 GetVertexPosition(Mesh mesh, int vertexIndex)
+ => vertexIndex > 0 && vertexIndex <= mesh.Vertices2.Count
+ ? mesh.Vertices2[vertexIndex - 1].Position
+ : default;
+
+ private static System.Numerics.Vector3 GetNormal(Mesh mesh, int normalIndex)
+ => normalIndex > 0 && normalIndex <= mesh.Normals2.Count
+ ? new System.Numerics.Vector3(
+ mesh.Normals2[normalIndex - 1].X,
+ mesh.Normals2[normalIndex - 1].Y,
+ mesh.Normals2[normalIndex - 1].Z)
+ : default;
+
+ private static System.Numerics.Vector2 GetTextureCoordinates(Mesh mesh, int textureIndex)
+ => textureIndex > 0 && textureIndex <= mesh.TextureCoordinates2.Count ?
+ new System.Numerics.Vector2(mesh.TextureCoordinates2[textureIndex - 1].X, mesh.TextureCoordinates2[textureIndex - 1].Y) :
+ default;
+
+ private IEnumerable BuildMaterials(Mesh mesh)
+ {
+ var materialDefinitions = mesh.Groups
+ .Select(group => group.Material)
+ .Where(material => material is not null)
+ .DistinctBy(material => material!.Name)
+ .ToList();
+
+ if (materialDefinitions.Count == 0)
+ materialDefinitions = [.. mesh.Materials
+ .Where(material => material is not null)
+ .DistinctBy(material => material!.Name)];
+
+ foreach (var material in materialDefinitions)
+ {
+ var runtimeMaterial = CreateRuntimeMaterial(material!);
+ if (runtimeMaterial is not null)
+ yield return runtimeMaterial;
+ }
+ }
+
+ private Material? CreateRuntimeMaterial(Material definition)
+ {
+ if (string.IsNullOrWhiteSpace(definition.DiffuseTextureMap))
+ return null;
+
+ var diffuseTexture = new EngineTexture(_gl, ResolveAssetPath(definition.DiffuseTextureMap), EngineTextureType.Diffuse);
+ EngineTexture? specularTexture = null;
+
+ if (!string.IsNullOrWhiteSpace(definition.SpecularTextureMap))
+ specularTexture = new EngineTexture(_gl, ResolveAssetPath(definition.SpecularTextureMap), EngineTextureType.Specular);
+
+ return new Material(definition.Name, diffuseTexture, specularTexture)
+ {
+ Name = definition.Name,
+ AmbientColor = definition.AmbientColor,
+ DiffuseColor = definition.DiffuseColor,
+ SpecularColor = definition.SpecularColor,
+ SpecularCoefficient = definition.SpecularCoefficient,
+ Transparency = definition.Transparency,
+ IlluminationModel = definition.IlluminationModel,
+ DiffuseTextureMap = definition.DiffuseTextureMap,
+ SpecularTextureMap = definition.SpecularTextureMap,
+ AmbientTextureMap = definition.AmbientTextureMap,
+ SpecularHighlightTextureMap = definition.SpecularHighlightTextureMap,
+ AlphaTextureMap = definition.AlphaTextureMap,
+ BumpMap = definition.BumpMap,
+ DisplacementMap = definition.DisplacementMap,
+ StencilDecalMap = definition.StencilDecalMap,
+ };
+ }
+
+ private IEnumerable CloneTextures(IReadOnlyList textures)
+ => textures?.Select(texture => new EngineTexture(_gl, texture.Path, texture.Type)) ?? [];
+
+ private Material CloneMaterial(Material material)
+ {
+ EngineTexture? diffuseTexture = null;
+ if (material.DiffuseMap != null)
+ diffuseTexture = new EngineTexture(_gl, material.DiffuseMap.Path, material.DiffuseMap.Type);
+
+ EngineTexture? specularTexture = null;
+ if (material.UseSpecularMap)
+ specularTexture = new EngineTexture(_gl, material!.SpecularMap!.Path, material.SpecularMap.Type);
+
+ return new Material(material.Name, diffuseTexture, specularTexture)
+ {
+ Name = material.Name,
+ AmbientColor = material.AmbientColor,
+ DiffuseColor = material.DiffuseColor,
+ SpecularColor = material.SpecularColor,
+ SpecularCoefficient = material.SpecularCoefficient,
+ Transparency = material.Transparency,
+ IlluminationModel = material.IlluminationModel,
+ DiffuseTextureMap = material.DiffuseTextureMap,
+ SpecularTextureMap = material.SpecularTextureMap,
+ AmbientTextureMap = material.AmbientTextureMap,
+ SpecularHighlightTextureMap = material.SpecularHighlightTextureMap,
+ AlphaTextureMap = material.AlphaTextureMap,
+ BumpMap = material.BumpMap,
+ DisplacementMap = material.DisplacementMap,
+ StencilDecalMap = material.StencilDecalMap,
+ Specular = material.Specular,
+ Shininess = material.Shininess,
+ };
+ }
+
+ private static IEnumerable BuildTextures(IEnumerable materials)
+ => materials
+ .SelectMany(GetMaterialEngineTextures)
+ .Distinct();
+ private static EngineTexture[] GetMaterialEngineTextures(Material material)
+ {
+ ArgumentNullException.ThrowIfNull(material);
+
+ var materials = new List();
+ if (material.UseSpecularMap)
+ materials.Add(material.SpecularMap!);
+
+ if (material.DiffuseMap != null)
+ materials.Add(material.DiffuseMap);
+
+ return [.. materials];
+ }
+
+ private string ResolveAssetPath(string assetPath)
+ {
+ if (System.IO.Path.IsPathRooted(assetPath) || string.IsNullOrWhiteSpace(Path))
+ return assetPath;
+
+ var directory = System.IO.Path.GetDirectoryName(Path);
+
+ return string.IsNullOrWhiteSpace(directory) ?
+ assetPath : System.IO.Path.Combine(directory, assetPath);
+ }
+
+ private static float[] BuildVertices(IEnumerable vertexCollection)
+ {
+ var vertices = new List();
+
+ foreach (var vertex in vertexCollection)
+ {
+ vertices.Add(vertex.Position.X);
+ vertices.Add(vertex.Position.Y);
+ vertices.Add(vertex.Position.Z);
+
+ vertices.Add(vertex.Normal.X);
+ vertices.Add(vertex.Normal.Y);
+ vertices.Add(vertex.Normal.Z);
+
+ vertices.Add(vertex.TexCoords.X);
+ vertices.Add(vertex.TexCoords.Y);
+ }
+
+ return [.. vertices];
+ }
+ }
+}
diff --git a/Engine/SharpEngine.Core.Components/Properties/Meshes/ObjMeshData.cs b/SharpEngine.Core.Components/Properties/Meshes/ObjMeshData.cs
similarity index 100%
rename from Engine/SharpEngine.Core.Components/Properties/Meshes/ObjMeshData.cs
rename to SharpEngine.Core.Components/Properties/Meshes/ObjMeshData.cs
diff --git a/Engine/SharpEngine.Core.Components/Properties/Meshes/VertexArrayObject.cs b/SharpEngine.Core.Components/Properties/Meshes/VertexArrayObject.cs
similarity index 100%
rename from Engine/SharpEngine.Core.Components/Properties/Meshes/VertexArrayObject.cs
rename to SharpEngine.Core.Components/Properties/Meshes/VertexArrayObject.cs
diff --git a/Engine/SharpEngine.Core.Components/Properties/Meshes/VertexData.cs b/SharpEngine.Core.Components/Properties/Meshes/VertexData.cs
similarity index 100%
rename from Engine/SharpEngine.Core.Components/Properties/Meshes/VertexData.cs
rename to SharpEngine.Core.Components/Properties/Meshes/VertexData.cs
diff --git a/Engine/SharpEngine.Core.Components/Properties/Quaternion.cs b/SharpEngine.Core.Components/Properties/Quaternion.cs
similarity index 100%
rename from Engine/SharpEngine.Core.Components/Properties/Quaternion.cs
rename to SharpEngine.Core.Components/Properties/Quaternion.cs
diff --git a/Engine/SharpEngine.Core.Components/Properties/Shaders/Shader.cs b/SharpEngine.Core.Components/Properties/Shaders/Shader.cs
similarity index 81%
rename from Engine/SharpEngine.Core.Components/Properties/Shaders/Shader.cs
rename to SharpEngine.Core.Components/Properties/Shaders/Shader.cs
index 13aea94..06e8322 100644
--- a/Engine/SharpEngine.Core.Components/Properties/Shaders/Shader.cs
+++ b/SharpEngine.Core.Components/Properties/Shaders/Shader.cs
@@ -1,6 +1,6 @@
-using SharpEngine.Shared;
+using Microsoft.Extensions.Logging;
+using SharpEngine.Telemetry;
using Silk.NET.OpenGL;
-using System.Diagnostics.CodeAnalysis;
namespace SharpEngine.Core.Shaders;
@@ -21,9 +21,11 @@ public partial class Shader : IDisposable
/// Gets or sets the path to the fragment shader file.
public string FragPath { get; set; }
+ private readonly GL _gl;
+ private readonly ILogger _logger;
+
private Dictionary _uniformLocations = [];
private bool disposedValue;
- private readonly GL _gl;
///
/// Initializes a new instance of .
@@ -32,14 +34,16 @@ public partial class Shader : IDisposable
/// Shaders are written in GLSL, which is a language very similar to C in its semantics.
/// The GLSL source is compiled *at runtime*, so it can optimize itself for the graphics card it's currently being used on.
///
- /// The OpenGL instance where this shader is used.
+ /// The OpenGL context.
/// The vertex shader full path.
/// The fragment shader full path.
/// The identifier name of the shader.
public Shader(GL gl, string vertPath, string fragPath, string name)
{
- Name = name;
_gl = gl;
+ Name = name;
+
+ _logger = LoggingExtensions.CreateLogger();
// There are several different types of shaders, but the only two you need for basic rendering are the vertex and fragment shaders.
// The vertex shader is responsible for moving around vertices, and uploading that data to the fragment shader.
@@ -48,10 +52,10 @@ public Shader(GL gl, string vertPath, string fragPath, string name)
// The fragment shader is what we'll be using the most here.
if (!vertPath.EndsWith(".vert"))
- Debug.Log.Warning("Vertex shaders should have the file extension '.vert' for easier manageability.");
+ _logger.LogWarning("Vertex shaders should have the file extension '.vert' for easier manageability.");
if (!fragPath.EndsWith(".frag"))
- Debug.Log.Warning("Fragment shaders should have the file extension '.frag' for easier manageability.");
+ _logger.LogWarning("Fragment shaders should have the file extension '.frag' for easier manageability.");
VertPath = vertPath;
FragPath = fragPath;
@@ -65,7 +69,8 @@ protected virtual void Dispose(bool disposing)
if (disposing)
{
- _gl.DeleteProgram(Handle);
+ // TODO: Collect handles in a separate container with proper access to the shared GL context.
+ //_gl.DeleteProgram(Handle);
Handle = 0;
_uniformLocations.Clear();
}
diff --git a/Engine/SharpEngine.Core.Components/Properties/Shaders/ShaderAttributes.cs b/SharpEngine.Core.Components/Properties/Shaders/ShaderAttributes.cs
similarity index 85%
rename from Engine/SharpEngine.Core.Components/Properties/Shaders/ShaderAttributes.cs
rename to SharpEngine.Core.Components/Properties/Shaders/ShaderAttributes.cs
index 29c14ac..d6fbfd2 100644
--- a/Engine/SharpEngine.Core.Components/Properties/Shaders/ShaderAttributes.cs
+++ b/SharpEngine.Core.Components/Properties/Shaders/ShaderAttributes.cs
@@ -18,7 +18,9 @@ public static class ShaderAttributes
/// Represents the model matrix attribute.
public const string Model = "uModel";
+ /// Represents the view matrix attribute.
public const string View = "uView";
+ /// Represents the projection matrix attribute.
public const string Projection = "uProjection";
}
diff --git a/Engine/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs
similarity index 91%
rename from Engine/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs
rename to SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs
index 830a2aa..f9fb638 100644
--- a/Engine/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs
+++ b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs
@@ -1,4 +1,4 @@
-using SharpEngine.Shared;
+using Microsoft.Extensions.Logging;
using Silk.NET.OpenGL;
using System.Numerics;
using System.Text.RegularExpressions;
@@ -19,13 +19,13 @@ public Shader Initialize()
// Load and compile shader
if (!LoadShader(ShaderType.VertexShader, VertPath, out uint vertexShader))
{
- Debug.Log.Error("Unable to load vertex shader.");
+ _logger.LogError("Unable to load vertex shader.");
return this;
}
if (!LoadShader(ShaderType.FragmentShader, FragPath, out uint fragmentShader))
{
- Debug.Log.Error("Unable to load fragment shader.");
+ _logger.LogError("Unable to load fragment shader.");
return this;
}
@@ -50,7 +50,7 @@ public Shader Initialize()
if (!shaderLinked)
{
- Debug.Log.Information("Unable to link shader program.");
+ _logger.LogInformation("Unable to link shader program.");
return this;
}
@@ -66,7 +66,7 @@ private bool LoadShader(ShaderType shaderType, string shaderPath, out uint shade
{
if (!File.Exists(shaderPath))
{
- Debug.Log.Information("Shader file not found: {Path}", shaderPath);
+ _logger.LogInformation("Shader file not found: {Path}", shaderPath);
shader = 0;
return false;
@@ -81,7 +81,7 @@ private bool LoadShader(ShaderType shaderType, string shaderPath, out uint shade
if (!CompileShader(shader))
{
- Debug.Log.Information("Unable to load {Type} shader from '{Path}'.", shaderType, shaderPath);
+ _logger.LogInformation("Unable to load {Type} shader from '{Path}'.", shaderType, shaderPath);
return false;
}
@@ -133,7 +133,7 @@ private bool CompileShader(uint shader)
{
// We can use `GL.GetShaderInfoLog(shader)` to get information about the error.
var infoLog = _gl.GetShaderInfoLog(shader);
- Debug.Log.Error("Error occurred whilst compiling Shader({Shader}).\n\n{Log}", shader, infoLog);
+ _logger.LogError("Error occurred whilst compiling Shader({Shader}).\n\n{Log}", shader, infoLog);
return false;
}
@@ -149,7 +149,7 @@ private bool LinkProgram(uint program)
if (statusCode != (int)GLEnum.True)
{
string infoLog = _gl.GetProgramInfoLog(program);
- Debug.Log.Error("Error occurred whilst linking Program({Program}): {Info}", program, infoLog);
+ _logger.LogError("Error occurred whilst linking Program({Program}): {Info}", program, infoLog);
return false;
}
@@ -174,7 +174,7 @@ public bool TryGetAttribLocation(string attribName, out int location)
location = _gl.GetAttribLocation(Handle, attribName);
if (location == ShaderAttributes.AttributeLocationNotFound)
{
- Debug.Log.Warning("Attribute '{Attribute}' not found in shader program.", attribName);
+ _logger.LogWarning("Attribute '{Attribute}' not found in shader program.", attribName);
return false;
}
@@ -194,7 +194,7 @@ private bool TrySetUniform(string uniformName, T data, Action setter)
{
if (!_uniformLocations.TryGetValue(uniformName, out int location))
{
- Debug.Log.Information("Uniform '{UniformName}' not found in shader '{ShaderName}'.", uniformName, Name);
+ _logger.LogInformation("Uniform '{UniformName}' not found in shader '{ShaderName}'.", uniformName, Name);
return false;
}
diff --git a/SharpEngine.Core.Components/Properties/Textures/Texture.cs b/SharpEngine.Core.Components/Properties/Textures/Texture.cs
new file mode 100644
index 0000000..66213d3
--- /dev/null
+++ b/SharpEngine.Core.Components/Properties/Textures/Texture.cs
@@ -0,0 +1,66 @@
+using Silk.NET.OpenGL;
+
+namespace SharpEngine.Core.Components.Properties.Textures;
+
+///
+/// Represents a texture resource managed in OpenGL with associated metadata.
+///
+public partial class Texture : IDisposable, IEquatable
+{
+ /// The OpenGL handle for the texture.
+ public readonly uint Handle;
+
+ /// Gets the type of the texture.
+ public readonly TextureType Type;
+
+ /// Gets the path to the texture file.
+ public readonly string Path;
+
+ private readonly GL _gl;
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ /// The OpenGL context where this texture should be available.
+ /// The path to the texture file.
+ /// The type of the texture.
+ public Texture(GL gl, string path, TextureType type = TextureType.Diffuse)
+ {
+ _gl = gl;
+ Handle = _gl.GenTexture();
+
+ Path = path;
+ Type = type;
+
+ Initialize();
+ }
+
+ ///
+ /// Creates a deep clone of the texture using the same OpenGL context.
+ ///
+ /// Assumes that the OpenGL context is the same as the original texture.
+ public Texture DeepClone()
+ => new(_gl, Path, Type);
+
+ ///
+ public bool Equals(Texture? other)
+ {
+ if (other is null)
+ return false;
+
+ if (ReferenceEquals(this, other))
+ return true;
+
+ return Handle == other.Handle &&
+ Type == other.Type &&
+ Path == other.Path;
+ }
+
+ ///
+ public override bool Equals(object? obj)
+ => Equals(obj as Texture);
+
+ ///
+ public override int GetHashCode()
+ => HashCode.Combine(Handle, Type, Path);
+}
diff --git a/Engine/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs b/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs
similarity index 84%
rename from Engine/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs
rename to SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs
index a060f8c..81c3f1f 100644
--- a/Engine/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs
+++ b/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs
@@ -3,8 +3,11 @@
namespace SharpEngine.Core.Components.Properties.Textures;
-public partial class Texture
+public partial class Texture : IDisposable
{
+ ///
+ /// Initializes the texture by loading the image data and creating the OpenGL texture.
+ ///
public void Initialize()
{
// Bind the handle
@@ -30,14 +33,17 @@ public void Initialize()
_gl.GenerateMipmap(GLEnum.Texture2D);
}
+ ///
+ /// Configures the currently bound 2D texture.
+ ///
public void SetParameters()
{
_gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)GLEnum.ClampToEdge);
_gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)GLEnum.ClampToEdge);
_gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)GLEnum.LinearMipmapLinear);
_gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)GLEnum.Linear);
- _gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBaseLevel, 0);
- _gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMaxLevel, 8);
+ _gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBaseLevel, 0); // TODO: Calculate this based on the texture size
+ _gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMaxLevel, 8); // TODO: Calculate this based on the texture size
_gl.GenerateMipmap(TextureTarget.Texture2D);
}
@@ -55,6 +61,7 @@ public void Use(TextureUnit unit = TextureUnit.Texture0)
_gl.BindTexture(TextureTarget.Texture2D, Handle);
}
+ ///
public void Dispose()
{
_gl.DeleteTexture(Handle);
diff --git a/SharpEngine.Core.Components/Properties/Textures/TextureType.cs b/SharpEngine.Core.Components/Properties/Textures/TextureType.cs
new file mode 100644
index 0000000..9fd26b1
--- /dev/null
+++ b/SharpEngine.Core.Components/Properties/Textures/TextureType.cs
@@ -0,0 +1,27 @@
+namespace SharpEngine.Core.Components.Properties.Textures;
+
+///
+/// Represents the semantic role of a texture in a material.
+///
+public enum TextureType
+{
+ ///
+ /// A texture that defines the base color of a material, affecting how it appears under direct lighting.
+ ///
+ Diffuse,
+
+ ///
+ /// The texture that defines the shininess and reflectivity of a material, affecting how it interacts with light and creates highlights.
+ ///
+ Specular,
+
+ ///
+ /// The texture that defines the normal vectors of a surface, which are used to create the illusion of surface detail and depth without adding additional geometry.
+ ///
+ Ambient,
+
+ ///
+ /// The texture that defines the height information of a surface, which can be used to create parallax effects or to simulate surface displacement in advanced rendering techniques.
+ ///
+ Height
+}
\ No newline at end of file
diff --git a/Engine/SharpEngine.Core.Components/Properties/Transform.cs b/SharpEngine.Core.Components/Properties/Transform.cs
similarity index 88%
rename from Engine/SharpEngine.Core.Components/Properties/Transform.cs
rename to SharpEngine.Core.Components/Properties/Transform.cs
index 3f2f075..be8462d 100644
--- a/Engine/SharpEngine.Core.Components/Properties/Transform.cs
+++ b/SharpEngine.Core.Components/Properties/Transform.cs
@@ -12,6 +12,11 @@ public class Transform : ITransform
/// Initializes a new instance of .
///
public Transform() { }
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ /// The initial position of the game object.
public Transform(Vector3 position)
{
Position = position;
diff --git a/Engine/SharpEngine.Core.Components/Properties/Transform2D.cs b/SharpEngine.Core.Components/Properties/Transform2D.cs
similarity index 100%
rename from Engine/SharpEngine.Core.Components/Properties/Transform2D.cs
rename to SharpEngine.Core.Components/Properties/Transform2D.cs
diff --git a/Engine/SharpEngine.Core.Components/SharpEngine.Core.Components.csproj b/SharpEngine.Core.Components/SharpEngine.Core.Components.csproj
similarity index 51%
rename from Engine/SharpEngine.Core.Components/SharpEngine.Core.Components.csproj
rename to SharpEngine.Core.Components/SharpEngine.Core.Components.csproj
index 3ba046b..f411581 100644
--- a/Engine/SharpEngine.Core.Components/SharpEngine.Core.Components.csproj
+++ b/SharpEngine.Core.Components/SharpEngine.Core.Components.csproj
@@ -1,7 +1,7 @@
-
+
- net8.0
+ $(DotNetTargetFramework)enableenable
@@ -11,23 +11,15 @@
true
-
-
-
-
-
-
+
+
-
-
-
-
-
+
diff --git a/Engine/SharpEngine.Core.Numerics/Float.cs b/SharpEngine.Core.Numerics/Float.cs
similarity index 69%
rename from Engine/SharpEngine.Core.Numerics/Float.cs
rename to SharpEngine.Core.Numerics/Float.cs
index 333f856..f1f19c7 100644
--- a/Engine/SharpEngine.Core.Numerics/Float.cs
+++ b/SharpEngine.Core.Numerics/Float.cs
@@ -1,5 +1,8 @@
namespace SharpEngine.Core.Numerics;
+///
+/// Contains constants and utility methods related to floating-point numbers.
+///
public static class Float
{
///
diff --git a/Engine/SharpEngine.Core.Numerics/HashCodeHelper.cs b/SharpEngine.Core.Numerics/HashCodeHelper.cs
similarity index 51%
rename from Engine/SharpEngine.Core.Numerics/HashCodeHelper.cs
rename to SharpEngine.Core.Numerics/HashCodeHelper.cs
index 601d499..d8fa3e3 100644
--- a/Engine/SharpEngine.Core.Numerics/HashCodeHelper.cs
+++ b/SharpEngine.Core.Numerics/HashCodeHelper.cs
@@ -4,11 +4,18 @@
namespace SharpEngine.Core.Numerics
{
+ ///
+ /// Provides helper methods for combining hash codes in a deterministic manner.
+ /// This is used internally by numeric types to produce stable hash codes based on multiple fields.
+ ///
internal static class HashCodeHelper
{
///
- /// Combines two hash codes, useful for combining hash codes of individual vector elements
+ /// Combines two hash codes into a single hash code.
///
+ /// The first hash code.
+ /// The second hash code.
+ /// A combined hash code value.
internal static int CombineHashCodes(int h1, int h2)
=> (((h1 << 5) + h1) ^ h2);
}
diff --git a/Engine/SharpEngine.Core.Numerics/IVector.cs b/SharpEngine.Core.Numerics/IVector.cs
similarity index 88%
rename from Engine/SharpEngine.Core.Numerics/IVector.cs
rename to SharpEngine.Core.Numerics/IVector.cs
index a620e8d..939cf80 100644
--- a/Engine/SharpEngine.Core.Numerics/IVector.cs
+++ b/SharpEngine.Core.Numerics/IVector.cs
@@ -10,6 +10,4 @@ public interface IVector
///
float Y { get; set; }
-
- public const float Epsilon = 1e-5f;
}
\ No newline at end of file
diff --git a/Engine/SharpEngine.Core.Numerics/JitIntrinsicAttribute.cs b/SharpEngine.Core.Numerics/JitIntrinsicAttribute.cs
similarity index 100%
rename from Engine/SharpEngine.Core.Numerics/JitIntrinsicAttribute.cs
rename to SharpEngine.Core.Numerics/JitIntrinsicAttribute.cs
diff --git a/Engine/SharpEngine.Core.Numerics/SharpEngine.Core.Numerics.csproj b/SharpEngine.Core.Numerics/SharpEngine.Core.Numerics.csproj
similarity index 81%
rename from Engine/SharpEngine.Core.Numerics/SharpEngine.Core.Numerics.csproj
rename to SharpEngine.Core.Numerics/SharpEngine.Core.Numerics.csproj
index 3082977..8e540fa 100644
--- a/Engine/SharpEngine.Core.Numerics/SharpEngine.Core.Numerics.csproj
+++ b/SharpEngine.Core.Numerics/SharpEngine.Core.Numerics.csproj
@@ -1,7 +1,7 @@
- net8.0
+ $(DotNetTargetFramework)enableenable
diff --git a/Engine/SharpEngine.Core.Numerics/Vector2.cs b/SharpEngine.Core.Numerics/Vector2.cs
similarity index 100%
rename from Engine/SharpEngine.Core.Numerics/Vector2.cs
rename to SharpEngine.Core.Numerics/Vector2.cs
diff --git a/Engine/SharpEngine.Core.Numerics/Vector2_Intrinsics.cs b/SharpEngine.Core.Numerics/Vector2_Intrinsics.cs
similarity index 100%
rename from Engine/SharpEngine.Core.Numerics/Vector2_Intrinsics.cs
rename to SharpEngine.Core.Numerics/Vector2_Intrinsics.cs
diff --git a/Engine/SharpEngine.Core.Numerics/Vector3.cs b/SharpEngine.Core.Numerics/Vector3.cs
similarity index 99%
rename from Engine/SharpEngine.Core.Numerics/Vector3.cs
rename to SharpEngine.Core.Numerics/Vector3.cs
index da6f282..8e5fc83 100644
--- a/Engine/SharpEngine.Core.Numerics/Vector3.cs
+++ b/SharpEngine.Core.Numerics/Vector3.cs
@@ -304,18 +304,6 @@ public static Vector3 Transform(Vector3 position, Matrix4x4 matrix)
(position.X * matrix.M12) + (position.Y * matrix.M22) + (position.Z * matrix.M32) + matrix.M42,
(position.X * matrix.M13) + (position.Y * matrix.M23) + (position.Z * matrix.M33) + matrix.M43);
- ///
- /// Transforms a vector normal by the given matrix.
- ///
- /// The source vector.
- /// The transformation matrix.
- /// The transformed vector.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Vector3 TransformNormal(Vector3 normal, Matrix4x4 matrix)
- => new((normal.X * matrix.M11) + (normal.Y * matrix.M21) + (normal.Z * matrix.M31),
- (normal.X * matrix.M12) + (normal.Y * matrix.M22) + (normal.Z * matrix.M32),
- (normal.X * matrix.M13) + (normal.Y * matrix.M23) + (normal.Z * matrix.M33));
-
///
/// Transforms a vector by the given Quaternion rotation value.
///
@@ -344,6 +332,19 @@ public static Vector3 Transform(Vector3 value, Quaternion rotation)
(value.X * (xy2 + wz2)) + (value.Y * (1.0f - xx2 - zz2)) + (value.Z * (yz2 - wx2)),
(value.X * (xz2 - wy2)) + (value.Y * (yz2 + wx2)) + (value.Z * (1.0f - xx2 - yy2)));
}
+
+ ///
+ /// Transforms a vector normal by the given matrix.
+ ///
+ /// The source vector.
+ /// The transformation matrix.
+ /// The transformed vector.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector3 TransformNormal(Vector3 normal, Matrix4x4 matrix)
+ => new((normal.X * matrix.M11) + (normal.Y * matrix.M21) + (normal.Z * matrix.M31),
+ (normal.X * matrix.M12) + (normal.Y * matrix.M22) + (normal.Z * matrix.M32),
+ (normal.X * matrix.M13) + (normal.Y * matrix.M23) + (normal.Z * matrix.M33));
+
#endregion Public Static Methods
#region Public operator methods
diff --git a/Engine/SharpEngine.Core.Numerics/Vector3_Intrinsics.cs b/SharpEngine.Core.Numerics/Vector3_Intrinsics.cs
similarity index 100%
rename from Engine/SharpEngine.Core.Numerics/Vector3_Intrinsics.cs
rename to SharpEngine.Core.Numerics/Vector3_Intrinsics.cs
diff --git a/Engine/SharpEngine.Core/Abstractions/IGame.cs b/SharpEngine.Core/Abstractions/IGame.cs
similarity index 63%
rename from Engine/SharpEngine.Core/Abstractions/IGame.cs
rename to SharpEngine.Core/Abstractions/IGame.cs
index de0b798..0fad3ee 100644
--- a/Engine/SharpEngine.Core/Abstractions/IGame.cs
+++ b/SharpEngine.Core/Abstractions/IGame.cs
@@ -1,7 +1,7 @@
-using SharpEngine.Core.Entities.Views;
+using SharpEngine.Core.Entities.Views;
using SharpEngine.Core.Entities.Views.Settings;
using SharpEngine.Core.Enums;
-
+using SharpEngine.Core.Scenes;
using Silk.NET.Input;
namespace SharpEngine.Core.Interfaces;
@@ -10,8 +10,41 @@ namespace SharpEngine.Core.Interfaces;
/// Contains definitions the Game class must implement.
/// To consider: move into a abstract class so that the game doesn't necessarily have to implement all methods.
///
-public class Game
+public abstract class Game
{
+ ///
+ /// Initializes a new instance of the .
+ ///
+ ///
+ /// Sets up a default scene and camera.
+ ///
+ public Game()
+ {
+ Scene = new Scene();
+ Camera = new(new System.Numerics.Vector3(0), new DefaultViewSettings());
+ }
+
+ ///
+ /// Initializes a new instance of the .
+ ///
+ ///
+ /// Sets up a default camera.
+ ///
+ public Game(Scene scene)
+ {
+ Scene = scene;
+ Camera = new(new System.Numerics.Vector3(0), new DefaultViewSettings());
+ }
+
+ ///
+ /// Initializes a new instance of the .
+ ///
+ public Game(Scene scene, CameraView camera)
+ {
+ Scene = scene;
+ Camera = camera;
+ }
+
///
/// Gets or sets the core settings of the game.
///
@@ -20,7 +53,12 @@ public class Game
///
/// Gets or sets the camera of the game.
///
- public CameraView Camera { get; set; } = new(new System.Numerics.Vector3(0), new DefaultViewSettings());
+ public CameraView Camera { get; set; } = CameraView.CreateDefault();
+
+ ///
+ /// Gets or sets the scene loaded in the game.
+ ///
+ public Scene Scene { get; init; }
///
/// Executed when a mouse button is pressed.
diff --git a/Engine/SharpEngine.Core/Abstractions/IRenderable.cs b/SharpEngine.Core/Abstractions/IRenderable.cs
similarity index 66%
rename from Engine/SharpEngine.Core/Abstractions/IRenderable.cs
rename to SharpEngine.Core/Abstractions/IRenderable.cs
index e248e60..72eb7e8 100644
--- a/Engine/SharpEngine.Core/Abstractions/IRenderable.cs
+++ b/SharpEngine.Core/Abstractions/IRenderable.cs
@@ -1,6 +1,4 @@
-using SharpEngine.Core.Entities.Properties.Meshes;
-
-namespace SharpEngine.Core.Interfaces;
+namespace SharpEngine.Core.Interfaces;
// TODO: #55 Make an abstract class and move Render method here?
diff --git a/Engine/SharpEngine.Core/Abstractions/ISettings.cs b/SharpEngine.Core/Abstractions/ISettings.cs
similarity index 98%
rename from Engine/SharpEngine.Core/Abstractions/ISettings.cs
rename to SharpEngine.Core/Abstractions/ISettings.cs
index 23888d2..6800463 100644
--- a/Engine/SharpEngine.Core/Abstractions/ISettings.cs
+++ b/SharpEngine.Core/Abstractions/ISettings.cs
@@ -1,6 +1,5 @@
using SharpEngine.Core.Renderers;
using Silk.NET.Input;
-using Silk.NET.Windowing;
namespace SharpEngine.Core.Interfaces;
diff --git a/Engine/SharpEngine.Core/Audio/Audio.cs b/SharpEngine.Core/Audio/Audio.cs
similarity index 100%
rename from Engine/SharpEngine.Core/Audio/Audio.cs
rename to SharpEngine.Core/Audio/Audio.cs
diff --git a/Engine/SharpEngine.Core/Audio/AudioBuffer.cs b/SharpEngine.Core/Audio/AudioBuffer.cs
similarity index 100%
rename from Engine/SharpEngine.Core/Audio/AudioBuffer.cs
rename to SharpEngine.Core/Audio/AudioBuffer.cs
diff --git a/Engine/SharpEngine.Core/Audio/AudioDevice.cs b/SharpEngine.Core/Audio/AudioDevice.cs
similarity index 100%
rename from Engine/SharpEngine.Core/Audio/AudioDevice.cs
rename to SharpEngine.Core/Audio/AudioDevice.cs
diff --git a/Engine/SharpEngine.Core/Audio/AudioFileExtensions.cs b/SharpEngine.Core/Audio/AudioFileExtensions.cs
similarity index 100%
rename from Engine/SharpEngine.Core/Audio/AudioFileExtensions.cs
rename to SharpEngine.Core/Audio/AudioFileExtensions.cs
diff --git a/Engine/SharpEngine.Core/Audio/AudioPlayerBase.cs b/SharpEngine.Core/Audio/AudioPlayerBase.cs
similarity index 100%
rename from Engine/SharpEngine.Core/Audio/AudioPlayerBase.cs
rename to SharpEngine.Core/Audio/AudioPlayerBase.cs
diff --git a/Engine/SharpEngine.Core/Audio/AudioProperties.cs b/SharpEngine.Core/Audio/AudioProperties.cs
similarity index 100%
rename from Engine/SharpEngine.Core/Audio/AudioProperties.cs
rename to SharpEngine.Core/Audio/AudioProperties.cs
diff --git a/Engine/SharpEngine.Core/Audio/AudioSource.cs b/SharpEngine.Core/Audio/AudioSource.cs
similarity index 82%
rename from Engine/SharpEngine.Core/Audio/AudioSource.cs
rename to SharpEngine.Core/Audio/AudioSource.cs
index 9e59179..d0a3669 100644
--- a/Engine/SharpEngine.Core/Audio/AudioSource.cs
+++ b/SharpEngine.Core/Audio/AudioSource.cs
@@ -3,7 +3,7 @@
namespace SharpEngine.Core.Audio;
///
-/// Represents a source for audio
+/// Represents a source for audio that can be played, stopped and queried.
///
public class AudioSource
{
@@ -21,9 +21,9 @@ public AudioSource(AL al)
}
///
- /// Gets the source identifier.
+ /// Gets the numeric identifier for the OpenAL source.
///
- /// The identifier to the source.
+ /// The identifier of the underlying OpenAL source.
public uint Get() => _source;
///
diff --git a/Engine/SharpEngine.Core/Audio/WavData.cs b/SharpEngine.Core/Audio/WavData.cs
similarity index 100%
rename from Engine/SharpEngine.Core/Audio/WavData.cs
rename to SharpEngine.Core/Audio/WavData.cs
diff --git a/Engine/SharpEngine.Core/Audio/WavPlayer.cs b/SharpEngine.Core/Audio/WavPlayer.cs
similarity index 92%
rename from Engine/SharpEngine.Core/Audio/WavPlayer.cs
rename to SharpEngine.Core/Audio/WavPlayer.cs
index a686bea..7869f28 100644
--- a/Engine/SharpEngine.Core/Audio/WavPlayer.cs
+++ b/SharpEngine.Core/Audio/WavPlayer.cs
@@ -1,4 +1,4 @@
-using SharpEngine.Shared;
+using Microsoft.Extensions.Logging;
using Silk.NET.OpenAL;
using System;
@@ -12,6 +12,8 @@ namespace SharpEngine.Core.Audio;
///
public class WavPlayer : AudioPlayerBase
{
+ private static readonly ILogger Logger = LoggerFactory.Create(builder => builder.AddConsole()).CreateLogger();
+
///
protected override string FileExtension => ".wav";
@@ -41,7 +43,7 @@ public override void Play(string filePath)
if (!CheckHeader(file, ref index, WavConstants.RiffHeader))
{
- Debug.Log.Warning("Given file is not in RIFF format");
+ Logger.LogWarning("Given file is not in RIFF format");
return;
}
@@ -49,7 +51,7 @@ public override void Play(string filePath)
if (!CheckHeader(file, ref index, WavConstants.WaveHeader))
{
- Debug.Log.Warning("Given file is not in WAVE format");
+ Logger.LogWarning("Given file is not in WAVE format");
return;
}
diff --git a/SharpEngine.Core/Components/ObjLoader/DataStore/IVertexDataStore.cs b/SharpEngine.Core/Components/ObjLoader/DataStore/IVertexDataStore.cs
new file mode 100644
index 0000000..e69de29
diff --git a/SharpEngine.Core/DependencyInjection/App.cs b/SharpEngine.Core/DependencyInjection/App.cs
new file mode 100644
index 0000000..3b9b7cb
--- /dev/null
+++ b/SharpEngine.Core/DependencyInjection/App.cs
@@ -0,0 +1,100 @@
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+
+using SharpEngine.Core.Windowing;
+
+using System;
+using System.Threading;
+
+namespace SharpEngine.Core.DependencyInjection;
+
+///
+/// Represents the application entry point responsible for resolving required services and running the main loop or window.
+///
+public class App
+{
+ private static IConfiguration? _configuration;
+ private readonly IServiceProvider _serviceProvider;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The service provider for dependency injection.
+ /// The application configuration.
+ public App(IServiceProvider serviceProvider, IConfiguration configuration)
+ {
+ _serviceProvider = serviceProvider;
+ _configuration = configuration;
+ }
+
+ ///
+ /// Runs the application by resolving required services and starting either a window or a main processing loop.
+ ///
+ /// Signals that the operation should be canceled.
+ public void Run(CancellationToken cancellationToken)
+ {
+ var logger = _serviceProvider.GetService>()!;
+
+ try
+ {
+
+ logger.LogInformation("App started. Resolving services.");
+
+ if (cancellationToken.IsCancellationRequested)
+ return;
+
+ var windowFactory = _serviceProvider.GetService();
+ if (windowFactory is not null && windowFactory.RegisteredWindows.Count > 0)
+ {
+ using var factoryWindow = windowFactory.CreateWindow();
+
+ logger.LogInformation("Required services resolved.");
+ logger.LogInformation("Starting window.");
+
+ factoryWindow.Initialize();
+ factoryWindow.Run();
+ return;
+ }
+
+ var window = _serviceProvider.GetService();
+ if (window is not null)
+ {
+ logger.LogInformation("Required services resolved.");
+ logger.LogInformation("Starting window.");
+
+ using (window)
+ {
+ window.Initialize();
+ window.Run();
+ }
+
+ return;
+ }
+
+ // This is just an example of how to use the scopes. In App we should always use '_serviceProvider'.
+ var scopeFactory = _serviceProvider.GetRequiredService();
+ using var scope = scopeFactory.CreateScope();
+
+ logger.LogInformation("Required services resolved.");
+ logger.LogInformation("Entering main loop.");
+
+ bool running = !cancellationToken.IsCancellationRequested;
+ while (running)
+ {
+ logger.LogInformation("frame tick.");
+
+ Thread.Sleep(1000); // Simulate frame delay
+ }
+ }
+ catch (Exception ex)
+ {
+ logger.LogError(ex, "Exception occurred.");
+ }
+ }
+
+ ///
+ /// Runs the application without a .
+ ///
+ public void Run() => Run(CancellationToken.None);
+}
diff --git a/SharpEngine.Core/DependencyInjection/AppBuilder.cs b/SharpEngine.Core/DependencyInjection/AppBuilder.cs
new file mode 100644
index 0000000..9cf7f30
--- /dev/null
+++ b/SharpEngine.Core/DependencyInjection/AppBuilder.cs
@@ -0,0 +1,68 @@
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+
+namespace SharpEngine.Core.DependencyInjection;
+
+///
+/// Represents a Dependency Injection builder for configuring services and building the application.
+///
+public class AppBuilder
+{
+ private readonly IServiceCollection _services = new ServiceCollection();
+ private IConfiguration? _configuration;
+
+ private App? App;
+
+ ///
+ /// Configures the application using the specified configuration action.
+ ///
+ /// An action to configure the configuration builder.
+ /// The current instance for method chaining.
+ public AppBuilder Configure(Action configure)
+ {
+ var configBuilder = new ConfigurationBuilder();
+ configure(configBuilder);
+
+ Configure(configBuilder);
+ return this;
+ }
+
+ private void Configure(ConfigurationBuilder? configBuilder = null)
+ {
+ var builder = configBuilder ?? new ConfigurationBuilder();
+
+ _configuration = builder.Build();
+ _services.AddSingleton(_configuration);
+ }
+
+ ///
+ /// Configures the application services using the specified configuration action.
+ ///
+ /// The configuration action to apply to the service collection.
+ /// The current instance for method chaining.
+ public AppBuilder ConfigureServices(Action configure)
+ {
+ configure(_services);
+ return this;
+ }
+
+ ///
+ /// Builds the App instance if not already built.
+ ///
+ ///
+ /// This method lazily initializes and caches the App instance.
+ ///
+ /// The App instance.
+ public App Build()
+ {
+ if (App != null)
+ return App;
+
+ if (_configuration == null)
+ Configure();
+
+ App = new App(_services.BuildServiceProvider(), _configuration!);
+ return App;
+ }
+}
\ No newline at end of file
diff --git a/SharpEngine.Core/DependencyInjection/ServiceCollectionExtensions.cs b/SharpEngine.Core/DependencyInjection/ServiceCollectionExtensions.cs
new file mode 100644
index 0000000..72ac3d8
--- /dev/null
+++ b/SharpEngine.Core/DependencyInjection/ServiceCollectionExtensions.cs
@@ -0,0 +1,46 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using SharpEngine.Core.Windowing;
+using System;
+using System.Linq;
+
+namespace SharpEngine.Core.DependencyInjection;
+
+///
+/// Provides window-related dependency injection registrations.
+///
+public static class ServiceCollectionExtensions
+{
+ ///
+ /// Registers a window factory and an optional configuration callback.
+ ///
+ /// The service collection.
+ /// Creates the window instance.
+ /// Configures the created window.
+ /// The optional registration name.
+ /// Whether this registration should be used as the default app window.
+ /// The service collection.
+ public static IServiceCollection AddWindow(
+ this IServiceCollection services,
+ Func factory,
+ Action? configure = null,
+ string? name = null,
+ bool isDefault = false)
+ {
+ ArgumentNullException.ThrowIfNull(services);
+ ArgumentNullException.ThrowIfNull(factory);
+
+ services.TryAddSingleton();
+
+ var registrationName = name ?? $"window-{services.Count(service => service.ServiceType == typeof(WindowRegistration))}";
+ services.AddSingleton(new WindowRegistration
+ {
+ Name = registrationName,
+ Factory = factory,
+ Configure = configure,
+ IsDefault = isDefault
+ });
+
+ return services;
+ }
+}
diff --git a/SharpEngine.Core/Engine.cs b/SharpEngine.Core/Engine.cs
new file mode 100644
index 0000000..dde1280
--- /dev/null
+++ b/SharpEngine.Core/Engine.cs
@@ -0,0 +1,80 @@
+using Microsoft.Extensions.Logging;
+
+using SharpEngine.Core.Handlers;
+using SharpEngine.Core.Interfaces;
+using SharpEngine.Core.Windowing;
+using SharpEngine.Telemetry;
+
+using System.Threading.Tasks;
+
+namespace SharpEngine.Core;
+
+///
+/// Manages the engine's services and provides methods to initialize, register handlers, and shut down asynchronously.
+///
+public static class Engine
+{
+ ///
+ /// Gets the manager responsible for handling engine services.
+ ///
+ public static EngineServiceManager Services { get; private set; } = new();
+
+ private static bool _initialized = false;
+
+ private readonly static ILogger _logger;
+
+ static Engine()
+ {
+ Initialize();
+ _logger = LoggingExtensions.CreateLogger(typeof(Engine));
+ }
+
+ ///
+ /// Initializes the engine for use.
+ ///
+ public static void Initialize()
+ {
+ _logger.LogDebug("Initializing engine...");
+
+ if (_initialized)
+ {
+ _logger.LogWarning("Reinitializing engine.");
+ Services.StopAllAsync().Wait();
+ }
+
+ _initialized = true;
+ _logger.LogDebug("Engine successfully initialized.");
+ }
+
+ ///
+ /// Creates and initializes a new window using the provided context and registers the window handler.
+ ///
+ /// The game context provides access to the current scene and camera settings for window initialization.
+ /// Returns the newly created instance.
+ public static Window Initialize(Game game)
+ {
+ var window = new Window(game);
+
+ Initialize();
+ Services.RegisterHandler(new WindowHandler(window));
+
+ return window;
+ }
+
+ ///
+ /// Stops all engine services and shuts down the engine asynchronously.
+ ///
+ /// A that completes when shutdown finishes.
+ public static async Task ShutdownAsync()
+ {
+ if (Services == null)
+ return;
+
+ _logger.LogDebug("Shutting down engine...");
+
+ await Services.StopAllAsync();
+
+ _initialized = false;
+ _logger.LogDebug("Engine successfully shut down.");
+ }
+}
\ No newline at end of file
diff --git a/SharpEngine.Core/EngineServiceManager.cs b/SharpEngine.Core/EngineServiceManager.cs
new file mode 100644
index 0000000..d926a94
--- /dev/null
+++ b/SharpEngine.Core/EngineServiceManager.cs
@@ -0,0 +1,52 @@
+using Microsoft.Extensions.Logging;
+
+using SharpEngine.Core.Handlers;
+using SharpEngine.Telemetry;
+
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace SharpEngine.Core;
+
+///
+/// Contains all the engine handlers and manages their lifecycle.
+///
+public class EngineServiceManager
+{
+ private readonly List handlers = [];
+ private readonly ILogger _logger;
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ /// The logger to use for logging messages.
+ public EngineServiceManager(ILogger? logger = null)
+ {
+ _logger = logger ?? LoggingExtensions.CreateLogger();
+ }
+
+ ///
+ /// Registers a new engine handler and starts its operation.
+ ///
+ /// The handler to register.
+ public void RegisterHandler(EngineHandler handler)
+ {
+ _logger.LogDebug("Registering handler: '{Handler}'.", handler.GetType().Name);
+
+ handlers.Add(handler);
+ handler.Start();
+
+ _logger.LogDebug("Handler '{Handler}' registered successfully.", handler.GetType().Name);
+ }
+
+ ///
+ /// Stops all active handlers asynchronously by calling their StopAsync method.
+ ///
+ /// A representing the asynchronous operation.
+ public async Task StopAllAsync()
+ {
+ var stopTasks = handlers.Select(handler => handler.StopAsync());
+ await Task.WhenAll(stopTasks);
+ }
+}
\ No newline at end of file
diff --git a/Engine/SharpEngine.Core/Entities/BezierCurve.cs b/SharpEngine.Core/Entities/BezierCurve.cs
similarity index 100%
rename from Engine/SharpEngine.Core/Entities/BezierCurve.cs
rename to SharpEngine.Core/Entities/BezierCurve.cs
diff --git a/SharpEngine.Core/Entities/GameObject.cs b/SharpEngine.Core/Entities/GameObject.cs
new file mode 100644
index 0000000..1b52fea
--- /dev/null
+++ b/SharpEngine.Core/Entities/GameObject.cs
@@ -0,0 +1,249 @@
+using SharpEngine.Core.Attributes;
+using SharpEngine.Core.Entities.Properties;
+using SharpEngine.Core.Entities.Properties.Meshes;
+using SharpEngine.Core.Entities.Views;
+using SharpEngine.Core.Components.Properties;
+using SharpEngine.Core.Components.Properties.Meshes;
+using SharpEngine.Core.Interfaces;
+using SharpEngine.Core.Numerics;
+using SharpEngine.Core.Scenes;
+using SharpEngine.Core.Shaders;
+using SharpEngine.Core.Windowing;
+using Shader = SharpEngine.Core.Shaders.Shader;
+using EngineTexture = SharpEngine.Core.Components.Properties.Textures.Texture;
+
+using Silk.NET.OpenGL;
+using System.Threading.Tasks;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace SharpEngine.Core.Entities;
+
+///
+/// Represents a game object in the scene.
+///
+public class GameObject : EmptyNode, IRenderable
+{
+ private readonly object _modelCacheLock = new();
+ private readonly Dictionary
public float Quadratic { get; set; }
+ ///
+ ///
protected override void SetShaderUniforms(CameraView camera)
{
+ if (Shader == null)
+ throw new NullReferenceException(nameof(Shader));
+
Shader.SetVector3($"pointLights[{_index}].position", (Vector3)Transform.Position);
Shader.SetVector3($"pointLights[{_index}].ambient", Ambient);
Shader.SetVector3($"pointLights[{_index}].diffuse", Diffuse);
@@ -65,8 +71,9 @@ protected override void SetShaderUniforms(CameraView camera)
}
///
- public Task Render(CameraView camera, Window window)
+ public override Task Render(CameraView camera, Window window)
{
+ Shader = ShaderService.Instance.LoadShader(window, Default.VertexShader, Default.FragmentShader, "lighting");
SetShaderUniforms(camera);
return Task.CompletedTask;
diff --git a/Engine/SharpEngine.Core/Entities/Lights/SpotLight.cs b/SharpEngine.Core/Entities/Lights/SpotLight.cs
similarity index 88%
rename from Engine/SharpEngine.Core/Entities/Lights/SpotLight.cs
rename to SharpEngine.Core/Entities/Lights/SpotLight.cs
index 59ad0fe..1da0b41 100644
--- a/Engine/SharpEngine.Core/Entities/Lights/SpotLight.cs
+++ b/SharpEngine.Core/Entities/Lights/SpotLight.cs
@@ -1,8 +1,9 @@
using SharpEngine.Core._Resources;
using SharpEngine.Core.Entities.Views;
-using SharpEngine.Core.Extensions;
using SharpEngine.Core.Shaders;
using SharpEngine.Core.Windowing;
+
+using System;
using System.Numerics;
using System.Threading.Tasks;
@@ -25,7 +26,6 @@ public SpotLight()
Linear = 0.09f;
Quadratic = 0.032f;
- Shader = ShaderService.Instance.LoadShader(Default.VertexShader, Default.FragmentShader, "lighting");
}
///
@@ -58,8 +58,13 @@ public SpotLight()
///
public float Quadratic { get; set; }
+ ///
+ ///
protected override void SetShaderUniforms(CameraView camera)
{
+ if (Shader == null)
+ throw new NullReferenceException(nameof(Shader));
+
Shader.SetVector3("spotLight.position", (Vector3)Transform.Position);
Shader.SetVector3("spotLight.direction", Direction);
Shader.SetVector3("spotLight.ambient", Ambient);
@@ -77,6 +82,7 @@ protected override void SetShaderUniforms(CameraView camera)
///
public override Task Render(CameraView camera, Window window)
{
+ Shader = ShaderService.Instance.LoadShader(window, Default.VertexShader, Default.FragmentShader, "lighting");
SetShaderUniforms(camera);
return Task.CompletedTask;
diff --git a/SharpEngine.Core/Entities/MeshService.cs b/SharpEngine.Core/Entities/MeshService.cs
new file mode 100644
index 0000000..ea51e4d
--- /dev/null
+++ b/SharpEngine.Core/Entities/MeshService.cs
@@ -0,0 +1,40 @@
+using System.Collections.Generic;
+
+namespace SharpEngine.Core.Entities.Properties.Meshes;
+
+///
+/// Service responsible for caching and providing meshes bound to GPU resources.
+///
+public class MeshService : IMeshService
+{
+ /// A global instance of the service.
+ public static readonly MeshService Instance = new();
+
+ private readonly Dictionary Meshes = [];
+
+ private MeshService() { }
+
+ ///
+ public Mesh LoadMesh(string identifier, Mesh mesh)
+ {
+ if (Meshes.TryGetValue(identifier, out var cachedMesh))
+ return cachedMesh;
+
+ Meshes.Add(identifier, mesh);
+ return mesh;
+ }
+}
+
+///
+/// Provides methods to load and retrieve Mesh instances from a cache keyed by an identifier.
+///
+public interface IMeshService
+{
+ ///
+ /// Loads a mesh into the mesh cache or returns an existing cached instance for the identifier.
+ ///
+ /// The cache key used to identify the mesh.
+ /// The mesh to cache if not already present.
+ /// The cached or newly stored instance.
+ Mesh LoadMesh(string identifier, Mesh mesh);
+}
\ No newline at end of file
diff --git a/SharpEngine.Core/Entities/Particle.cs b/SharpEngine.Core/Entities/Particle.cs
new file mode 100644
index 0000000..542d126
--- /dev/null
+++ b/SharpEngine.Core/Entities/Particle.cs
@@ -0,0 +1,35 @@
+using System;
+
+namespace SharpEngine.Core.Entities;
+
+///
+/// Represents a particle emitted by a particle system.
+///
+public class Particle : GameObject
+{
+ ///
+ /// Initializes a new instance of with a specified lifetime.
+ ///
+ /// Determines how long the particle should stay on the screen.
+ public Particle(int lifeTimeMilliseconds)
+ {
+ LifeTimeMilliseconds = lifeTimeMilliseconds;
+ StartTimeTicks = DateTime.UtcNow.Ticks;
+ }
+
+ ///
+ /// Gets or sets the time when the particle was emitted, represented in ticks.
+ ///
+ ///
+ /// This value is used to determine when the particle should be removed based on its lifetime.
+ ///
+ public long StartTimeTicks { get; private set; }
+
+ ///
+ /// Gets or sets the lifetime of the particle in milliseconds.
+ ///
+ ///
+ /// This value is used to determine when the particle should be removed based on its start time.
+ ///
+ public int LifeTimeMilliseconds { get; private set; }
+}
diff --git a/Engine/SharpEngine.Core/Entities/UI/Layouts/FlexLayout.cs b/SharpEngine.Core/Entities/UI/Layouts/FlexLayout.cs
similarity index 97%
rename from Engine/SharpEngine.Core/Entities/UI/Layouts/FlexLayout.cs
rename to SharpEngine.Core/Entities/UI/Layouts/FlexLayout.cs
index b0dded0..373fda3 100644
--- a/Engine/SharpEngine.Core/Entities/UI/Layouts/FlexLayout.cs
+++ b/SharpEngine.Core/Entities/UI/Layouts/FlexLayout.cs
@@ -1,7 +1,6 @@
using SharpEngine.Core.Numerics;
using SharpEngine.Core.Scenes;
using System;
-using System.Numerics;
namespace SharpEngine.Core.Entities.UI.Layouts;
diff --git a/Engine/SharpEngine.Core/Entities/UI/Layouts/GridLayout.cs b/SharpEngine.Core/Entities/UI/Layouts/GridLayout.cs
similarity index 96%
rename from Engine/SharpEngine.Core/Entities/UI/Layouts/GridLayout.cs
rename to SharpEngine.Core/Entities/UI/Layouts/GridLayout.cs
index 452cc3e..3f7a339 100644
--- a/Engine/SharpEngine.Core/Entities/UI/Layouts/GridLayout.cs
+++ b/SharpEngine.Core/Entities/UI/Layouts/GridLayout.cs
@@ -1,6 +1,4 @@
-using SharpEngine.Core.Entities.Properties;
-using SharpEngine.Core.Numerics;
-using SharpEngine.Core.Scenes;
+using SharpEngine.Core.Scenes;
using System;
namespace SharpEngine.Core.Entities.UI.Layouts;
diff --git a/Engine/SharpEngine.Core/Entities/UI/Layouts/LayoutBase.cs b/SharpEngine.Core/Entities/UI/Layouts/LayoutBase.cs
similarity index 100%
rename from Engine/SharpEngine.Core/Entities/UI/Layouts/LayoutBase.cs
rename to SharpEngine.Core/Entities/UI/Layouts/LayoutBase.cs
diff --git a/SharpEngine.Core/Entities/UI/UIElement.cs b/SharpEngine.Core/Entities/UI/UIElement.cs
new file mode 100644
index 0000000..50d498a
--- /dev/null
+++ b/SharpEngine.Core/Entities/UI/UIElement.cs
@@ -0,0 +1,162 @@
+using SharpEngine.Core.Entities.Properties;
+using SharpEngine.Core.Entities.Properties.Meshes;
+using SharpEngine.Core.Entities.Views;
+using SharpEngine.Core.Interfaces;
+using SharpEngine.Core.Scenes;
+using SharpEngine.Core.Shaders;
+using SharpEngine.Core.Textures;
+using SharpEngine.Core.Windowing;
+using SharpEngine.Core._Resources;
+using Vector2 = SharpEngine.Core.Numerics.Vector2;
+using Texture = SharpEngine.Core.Components.Properties.Textures.Texture;
+
+using Silk.NET.OpenGL;
+using System.Collections.Generic;
+using System.Numerics;
+using System.Threading.Tasks;
+
+namespace SharpEngine.Core.Entities.UI;
+
+///
+/// Represents a User Interface entity.
+///
+public class UIElement : EmptyNode, IRenderable
+{
+ ///
+ /// Initializes a new instance of .
+ ///
+ public UIElement() : this("UIElement") { }
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ /// The name of the UI element.
+ public UIElement(string name) : base(name)
+ {
+ // TODO: #5 Support custom meshes?
+ Mesh = MeshService.Instance.LoadMesh(nameof(Primitives.Plane), Primitives.Plane.Mesh);
+ }
+
+ private readonly UIShader _uiShader = new();
+ private readonly Texture _texture = TextureService.Instance.LoadTexture(Default.DebugTexture);
+
+ /// Gets or sets the width of the ui element.
+ public float Width { get; set; } = 10;
+
+ /// Gets or sets the height of the ui element.
+ public float Height { get; set; } = 10;
+
+ /// Gets or sets the mesh of the UI element.
+ public Mesh Mesh { get; set; }
+
+ ///
+ /// Gets the most recently used VAO for this element.
+ ///
+ ///
+ /// UIElement maintains VAOs per OpenGL context. This property is updated on render.
+ ///
+ public uint VAO { get; private set; }
+
+ private sealed record SharedBuffers(uint Vbo, uint Ebo, int IndexCount);
+ private sealed record ContextState(uint Vao);
+
+ private readonly object _gpuLock = new();
+ private readonly Dictionary
public class Renderer : RendererBase
{
- private readonly LampShader _lampShader;
- private readonly LightingShader _lightingShader;
+ private LampShader _lampShader = null!;
+ private LightingShader _lightingShader = null!;
private readonly CameraView _camera;
private readonly Scene _scene;
- private readonly Window _window;
+ private readonly ILogger _logger;
+
+ private GL _gl = null!;
// TODO: #7 Property for specific type of objects
// No heavy iteration reads for filtering,
@@ -40,18 +44,24 @@ public class Renderer : RendererBase
/// Initializes a new instance of .
///
/// The game the renderer is being used for.
- /// The window executing the renderer.
/// The settings for the renderer.
/// The game scene to be rendered.
- public Renderer(CameraView camera, Window window, ISettings settings, Scene scene) : base(settings)
+ /// The logger for the renderer.
+ public Renderer(CameraView camera, ISettings settings, Scene scene, ILogger logger) : base(settings)
{
_camera = camera;
_scene = scene;
- _window = window;
+ _logger = logger;
+ }
+
+ ///
+ protected override void OnWindowAttached(Window window)
+ {
+ _gl = window.GetGL();
// TODO: #5 These should be refactored out. The minimum build shouldn't need to use these.
- _lightingShader = new LightingShader();
- _lampShader = new LampShader();
+ _lightingShader = new LightingShader(_gl);
+ _lampShader = new LampShader(_gl);
}
///
@@ -62,33 +72,37 @@ public override Task Render()
try
{
- Window.GL.Enable(EnableCap.DepthTest);
+ _gl.Enable(EnableCap.DepthTest);
// Enable image transparency.
// TODO: #62 Needs testing.
- Window.GL.Enable(EnableCap.Blend);
- Window.GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
+ _gl.Enable(EnableCap.Blend);
+ _gl.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
_camera.SetShaderUniforms(_lightingShader.Shader!);
- Window.GL.BindVertexArray(_lightingShader.Vao);
+ _gl.BindVertexArray(_lightingShader.Vao);
+ var lightRenderTasks = _scene.IterateAsync(_scene.Root.Children, RenderLight);
+ Task.WaitAll([.. lightRenderTasks]);
+
+ // TODO: Streamline this part where the game objects are rendered
var gameObjectRenderTasks = _scene.IterateAsync(_scene.Root.Children, RenderGameObject);
var renderTask = Task.WhenAll(gameObjectRenderTasks);
- Window.GL.BindVertexArray(_lampShader.Vao);
+ _gl.BindVertexArray(_lampShader.Vao);
return renderTask;
}
catch (Exception ex)
{
- Debug.Log.Error(ex, "{Message}", ex.Message);
+ _logger.LogError(ex, "{Message}", ex.Message);
return Task.FromException(ex);
}
}
private Task RenderGameObject(SceneNode node)
{
- if (node is not GameObject gameObject)
+ if (node is not GameObject gameObject || node is Light)
return Task.CompletedTask;
// TODO: #7 Fix culling for blocks that are partially in view
@@ -97,8 +111,16 @@ private Task RenderGameObject(SceneNode node)
return Task.CompletedTask;
// TODO: #7 Skip blocks that are behind others relative to the camera
- return gameObject.Render(_camera, _window);
- // gameObject.Render(_camera, _window);
+ return gameObject.Render(_camera, Window);
+ // gameObject.Render(_camera, Window);
+ }
+
+ private Task RenderLight(SceneNode node)
+ {
+ if (node is not Light light)
+ return Task.CompletedTask;
+
+ return light.Render(_camera, Window);
}
private static bool IsInViewFrustum(BoundingBox boundingBox, CameraView camera)
diff --git a/Engine/SharpEngine.Core/Renderers/RendererBase.cs b/SharpEngine.Core/Renderers/RendererBase.cs
similarity index 64%
rename from Engine/SharpEngine.Core/Renderers/RendererBase.cs
rename to SharpEngine.Core/Renderers/RendererBase.cs
index 1491fab..ea99872 100644
--- a/Engine/SharpEngine.Core/Renderers/RendererBase.cs
+++ b/SharpEngine.Core/Renderers/RendererBase.cs
@@ -1,5 +1,6 @@
-using SharpEngine.Core.Entities.Views;
using SharpEngine.Core.Interfaces;
+using SharpEngine.Core.Windowing;
+
using System;
using System.Threading.Tasks;
@@ -13,6 +14,9 @@ public abstract class RendererBase : IDisposable
/// Gets or sets the settings for the renderer.
protected ISettings Settings;
+ /// Gets the window attached to the renderer.
+ protected Window Window { get; private set; } = null!;
+
///
/// Initializes a new instance of .
///
@@ -27,6 +31,24 @@ protected RendererBase(ISettings settings)
///
public abstract RenderFlags RenderFlag { get; }
+ ///
+ /// Attaches the renderer to a window after both have been constructed.
+ ///
+ /// The window that owns the renderer.
+ public void AttachWindow(Window window)
+ {
+ ArgumentNullException.ThrowIfNull(window);
+
+ Window = window;
+ OnWindowAttached(window);
+ }
+
+ ///
+ /// Allows derived renderers to react when a window is attached.
+ ///
+ /// The attached window.
+ protected virtual void OnWindowAttached(Window window) { }
+
///
/// Initializes the renderer.
///
diff --git a/SharpEngine.Core/Renderers/TextRenderer.cs b/SharpEngine.Core/Renderers/TextRenderer.cs
new file mode 100644
index 0000000..15670c8
--- /dev/null
+++ b/SharpEngine.Core/Renderers/TextRenderer.cs
@@ -0,0 +1,31 @@
+using SharpEngine.Core.Entities.Views;
+using SharpEngine.Core.Interfaces;
+using SharpEngine.Core.Scenes;
+
+using System.Threading.Tasks;
+
+namespace SharpEngine.Core.Renderers;
+
+///
+/// A renderer responsible for rendering text in the scene.
+///
+internal class TextRenderer : RendererBase
+{
+ ///
+ /// Initializes a new instance of the TextRenderer class with the specified camera, settings, and scene.
+ ///
+ /// CameraView that provides view and projection information for rendering.
+ /// ISettings that configures renderer behavior.
+ /// Scene that contains renderable text elements.
+ public TextRenderer(CameraView camera, ISettings settings, Scene scene) : base(settings)
+ {
+ }
+
+ public override RenderFlags RenderFlag => RenderFlags.Text;
+
+ ///
+ public override Task Render()
+ {
+ return Task.CompletedTask;
+ }
+}
diff --git a/Engine/SharpEngine.Core/Renderers/UIRenderer.cs b/SharpEngine.Core/Renderers/UIRenderer.cs
similarity index 56%
rename from Engine/SharpEngine.Core/Renderers/UIRenderer.cs
rename to SharpEngine.Core/Renderers/UIRenderer.cs
index 54ee5da..931b0c5 100644
--- a/Engine/SharpEngine.Core/Renderers/UIRenderer.cs
+++ b/SharpEngine.Core/Renderers/UIRenderer.cs
@@ -2,9 +2,9 @@
using SharpEngine.Core.Entities.Views;
using SharpEngine.Core.Interfaces;
using SharpEngine.Core.Scenes;
-using SharpEngine.Core.Shaders;
using SharpEngine.Core.Windowing;
-using SharpEngine.Shared;
+
+using Microsoft.Extensions.Logging;
using Silk.NET.OpenGL;
using System;
@@ -19,7 +19,9 @@ public class UIRenderer : RendererBase
{
private readonly Scene _scene;
private readonly CameraView _camera;
- private readonly Window _window;
+ private readonly ILogger _logger;
+
+ private GL _gl = null!;
///
public override RenderFlags RenderFlag => RenderFlags.UIRenderer;
@@ -27,11 +29,25 @@ public class UIRenderer : RendererBase
///
/// Initializes a new instance of .
///
- public UIRenderer(CameraView camera, Window window, ISettings settings, Scene scene) : base(settings)
+ public UIRenderer(CameraView camera, ISettings settings, Scene scene)
+ : this(camera, settings, scene, LoggerFactory.Create(builder => builder.AddConsole()).CreateLogger())
+ {
+ }
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ public UIRenderer(CameraView camera, ISettings settings, Scene scene, ILogger logger) : base(settings)
{
_scene = scene;
_camera = camera;
- _window = window;
+ _logger = logger;
+ }
+
+ ///
+ protected override void OnWindowAttached(Window window)
+ {
+ _gl = window.GetGL();
}
///
@@ -42,19 +58,19 @@ public override Task Render()
try
{
- Window.GL.Enable(EnableCap.DepthTest);
- Window.GL.DepthFunc(DepthFunction.Less);
+ _gl.Enable(EnableCap.DepthTest);
+ _gl.DepthFunc(DepthFunction.Less);
// Disable face culling to render both sides of the quad
- Window.GL.Disable(EnableCap.CullFace);
+ _gl.Disable(EnableCap.CullFace);
- var uiElementRenderTasks = _scene.IterateAsync(_scene.UIElements, elem => elem.Render(_camera, _window));
+ var uiElementRenderTasks = _scene.IterateAsync(_scene.UIElements, elem => elem.Render(_camera, Window));
return Task.WhenAll(uiElementRenderTasks);
}
catch (Exception ex)
{
- Debug.Log.Error(ex, "{Message}", ex.Message);
+ _logger.LogError(ex, "{Message}", ex.Message);
return Task.FromException(ex);
}
}
diff --git a/Engine/SharpEngine.Core/Scenes/Scene.cs b/SharpEngine.Core/Scenes/Scene.cs
similarity index 97%
rename from Engine/SharpEngine.Core/Scenes/Scene.cs
rename to SharpEngine.Core/Scenes/Scene.cs
index e53d524..ff4db26 100644
--- a/Engine/SharpEngine.Core/Scenes/Scene.cs
+++ b/SharpEngine.Core/Scenes/Scene.cs
@@ -1,7 +1,6 @@
-using SharpEngine.Core.Entities;
+using Microsoft.Extensions.Logging;
using SharpEngine.Core.Entities.Properties;
-using SharpEngine.Core.Entities.UI;
-using SharpEngine.Shared;
+
using System;
using System.Collections.Generic;
using System.Linq;
@@ -15,6 +14,8 @@ namespace SharpEngine.Core.Scenes;
///
public class Scene
{
+ private static readonly ILogger Logger = LoggerFactory.Create(builder => builder.AddConsole()).CreateLogger();
+
/// The file extension by which saved scenes are associated with.
public const string SceneFileExtension = "sharpscene";
@@ -183,7 +184,7 @@ public IEnumerable IterateAsync(List elements, FuncThe scene from the given file. Loads an empty scene if unable to load the scene.
public static Scene LoadScene(string sceneFile)
{
- Debug.Log.Debug(sceneFile);
+ Logger.LogDebug("Loading scene from {SceneFile}", sceneFile);
var loadedScene = JsonSerializer.Deserialize(sceneFile);
diff --git a/Engine/SharpEngine.Core/Scenes/SceneNode.cs b/SharpEngine.Core/Scenes/SceneNode.cs
similarity index 100%
rename from Engine/SharpEngine.Core/Scenes/SceneNode.cs
rename to SharpEngine.Core/Scenes/SceneNode.cs
diff --git a/SharpEngine.Core/Shaders/LampShader.cs b/SharpEngine.Core/Shaders/LampShader.cs
new file mode 100644
index 0000000..f7ce4e1
--- /dev/null
+++ b/SharpEngine.Core/Shaders/LampShader.cs
@@ -0,0 +1,43 @@
+using SharpEngine.Core._Resources;
+using SharpEngine.Core.Entities.Properties.Meshes;
+
+using Silk.NET.OpenGL;
+
+namespace SharpEngine.Core.Shaders;
+
+internal class LampShader : ShaderBase
+{
+ private readonly GL _gl;
+
+ ///
+ /// Initializes a new instance of using the provided OpenGL context.
+ ///
+ /// The OpenGL context to use for shader and VAO creation.
+ public LampShader(GL gl)
+ {
+ _gl = gl;
+
+ Shader = ShaderService.Instance.LoadShader(_gl, Default.VertexShader, Default.LightShader, "lamp");
+
+ Vao = _gl.GenVertexArray();
+ _gl.BindVertexArray(Vao);
+
+ SetAttributes(_gl);
+ }
+
+ ///
+ public override bool SetAttributes(GL gl)
+ {
+ if (!base.SetAttributes(gl))
+ return false;
+
+ if (!Shader!.TryGetAttribLocation(ShaderAttributes.Pos, out int positionLocation))
+ return false;
+
+ var positionLocationUint = (uint)positionLocation;
+ _gl.EnableVertexAttribArray(positionLocationUint);
+ _gl.VertexAttribPointer(positionLocationUint, 3, VertexAttribPointerType.Float, false, VertexData.Stride, 0);
+
+ return true;
+ }
+}
diff --git a/SharpEngine.Core/Shaders/LightingShader.cs b/SharpEngine.Core/Shaders/LightingShader.cs
new file mode 100644
index 0000000..55b5e5e
--- /dev/null
+++ b/SharpEngine.Core/Shaders/LightingShader.cs
@@ -0,0 +1,56 @@
+using SharpEngine.Core._Resources;
+
+using Silk.NET.OpenGL;
+
+namespace SharpEngine.Core.Shaders;
+
+internal class LightingShader : ShaderBase
+{
+ private readonly GL _gl;
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ /// The OpenGL context used to create and configure the shader program.
+ public LightingShader(GL gl)
+ {
+ _gl = gl;
+
+ Shader = ShaderService.Instance.LoadShader(_gl, Default.VertexShader, Default.FragmentShader, "lighting");
+
+ Vao = _gl.GenVertexArray();
+ _gl.BindVertexArray(Vao);
+
+ SetAttributes(_gl);
+ }
+
+ ///
+ public override bool SetAttributes(GL gl)
+ {
+ if (!base.SetAttributes(gl))
+ return false;
+
+ /*if (!Shader!.TryGetAttribLocation(ShaderAttributes.Pos, out int positionLocation))
+ return false;
+
+ var positionLocationUint = (uint)positionLocation;
+ _gl.EnableVertexAttribArray(positionLocationUint);
+ _gl.VertexAttribPointer(positionLocationUint, VertexData.VerticesSize, VertexAttribPointerType.Float, false, VertexData.Stride, 0);
+
+ if (!Shader!.TryGetAttribLocation(ShaderAttributes.Normal, out int normalLocation))
+ return false;
+
+ var normalLocationUint = (uint)normalLocation;
+ _gl.EnableVertexAttribArray(normalLocationUint);
+ _gl.VertexAttribPointer(normalLocationUint, VertexData.NormalsSize, VertexAttribPointerType.Float, false, VertexData.Stride, VertexData.NormalsOffset);
+
+ if (!Shader!.TryGetAttribLocation(ShaderAttributes.TexCoords, out int texCoordLocation))
+ return false;
+
+ var texCoordLocationUint = (uint)texCoordLocation;
+ _gl.EnableVertexAttribArray(texCoordLocationUint);
+ _gl.VertexAttribPointer(texCoordLocationUint, VertexData.TexCoordsSize, VertexAttribPointerType.Float, false, VertexData.Stride, VertexData.TexCoordsOffset);
+ */
+ return true;
+ }
+}
diff --git a/Engine/SharpEngine.Core/Shaders/ShaderBase.cs b/SharpEngine.Core/Shaders/ShaderBase.cs
similarity index 69%
rename from Engine/SharpEngine.Core/Shaders/ShaderBase.cs
rename to SharpEngine.Core/Shaders/ShaderBase.cs
index e7fd389..492217a 100644
--- a/Engine/SharpEngine.Core/Shaders/ShaderBase.cs
+++ b/SharpEngine.Core/Shaders/ShaderBase.cs
@@ -1,6 +1,5 @@
-using SharpEngine.Core.Components.Properties;
-using SharpEngine.Shared;
-using System;
+using Microsoft.Extensions.Logging;
+using Silk.NET.OpenGL;
namespace SharpEngine.Core.Shaders;
@@ -9,6 +8,8 @@ namespace SharpEngine.Core.Shaders;
///
public abstract class ShaderBase
{
+ private static readonly ILogger Logger = LoggerFactory.Create(builder => builder.AddConsole()).CreateLogger();
+
/// Gets the shader.
public Shader? Shader { get; protected set; }
@@ -21,11 +22,11 @@ public abstract class ShaderBase
///
/// if the attributes were set successfully; otherwise .
///
- public virtual bool SetAttributes()
+ public virtual bool SetAttributes(GL gl)
{
if (Shader is null)
{
- Debug.Log.Error("Unable to set shader attributes, shader not found.");
+ Logger.LogError("Unable to set shader attributes, shader not found.");
return false;
}
diff --git a/SharpEngine.Core/Shaders/ShaderService.cs b/SharpEngine.Core/Shaders/ShaderService.cs
new file mode 100644
index 0000000..74fee61
--- /dev/null
+++ b/SharpEngine.Core/Shaders/ShaderService.cs
@@ -0,0 +1,134 @@
+using Microsoft.Extensions.Logging;
+using System.Collections.Generic;
+using System.IO;
+
+using SharpEngine.Core.Windowing;
+using Silk.NET.OpenGL;
+
+namespace SharpEngine.Core.Shaders;
+
+///
+/// Contains all the shaders used in the game.
+///
+public class ShaderService
+{
+ private static readonly ILogger Logger = LoggerFactory.Create(builder => builder.AddConsole()).CreateLogger();
+
+ ///
+ /// Gets the singleton instance of the .
+ ///
+ public static ShaderService Instance { get; } = new ShaderService();
+
+ private readonly Dictionary _shaderCache = [];
+
+ private readonly record struct ShaderCacheKey(string Name, object ShareGroupKey);
+
+ ///
+ /// Gets or sets whether there are shaders to load.
+ ///
+ public bool HasShadersToLoad { get; set; } = true;
+
+ ///
+ /// Private constructor to prevent instantiation.
+ ///
+ private ShaderService() { }
+
+ ///
+ /// Gets all the shaders in the cache.
+ ///
+ /// All the shaders found from the cache.
+ public List GetAll()
+ {
+ HasShadersToLoad = false;
+ return [.. _shaderCache.Values];
+ }
+
+ ///
+ /// Gets a shader by its name.
+ ///
+ /// The name of the shader to be found.
+ /// The found shader.
+ ///
+ /// Thrown if a shader by that is not found.
+ /// This exception is thrown to make sure there are no unexpected issues made by the developer.
+ ///
+ public Shader GetByName(string name)
+ {
+ // Legacy API: return first shader found with this name.
+ foreach (var kvp in _shaderCache)
+ if (kvp.Key.Name == name)
+ return kvp.Value;
+
+ throw new KeyNotFoundException($"Shader with name {name} not found in cache.");
+ }
+
+ ///
+ /// Loads a shader from the specified vertex and fragment paths.
+ /// If the shader is loaded already, adds it to the cache.
+ ///
+ /// The game window.
+ /// The vertex shader full path.
+ /// The fragment shader full path.
+ /// A name identifier for the shader.
+ /// A shader with the given name.
+ /// Thrown when either the vertex or fragment shader is not found.
+ public Shader LoadShader(Window window, string vertPath, string fragPath, string name)
+ => LoadShader(window.GetGL(), GetShareGroupKey(window), vertPath, fragPath, name);
+
+ ///
+ /// Loads a shader from the specified vertex and fragment paths.
+ /// If the shader is loaded already, adds it to the cache.
+ ///
+ /// The OpenGL context.
+ /// The vertex shader full path.
+ /// The fragment shader full path.
+ /// A name identifier for the shader.
+ /// A shader with the given name.
+ /// Thrown when either the vertex or fragment shader is not found.
+ public Shader LoadShader(GL gl, string vertPath, string fragPath, string name)
+ => LoadShader(gl, shareGroupKey: gl, vertPath, fragPath, name);
+
+ ///
+ /// Loads a shader from the specified vertex and fragment paths.
+ /// If the shader is loaded already, adds it to the cache.
+ ///
+ /// The OpenGL context.
+ /// A key representing the share group for the shader.
+ /// The vertex shader full path.
+ /// The fragment shader full path.
+ /// A name identifier for the shader.
+ /// A shader with the given name.
+ /// Thrown when either the vertex or fragment shader is not found.
+ public Shader LoadShader(GL gl, object shareGroupKey, string vertPath, string fragPath, string name)
+ {
+ var cacheKey = new ShaderCacheKey(name, shareGroupKey);
+
+ // Check if the shader is already in the cache for this share group.
+ if (_shaderCache.TryGetValue(cacheKey, out var cachedShader))
+ return cachedShader;
+
+ if (!File.Exists(vertPath))
+ {
+ Logger.LogInformation("Vertex shader file not found: {VertPath}", vertPath);
+ throw new FileNotFoundException($"Vertex shader file not found: {vertPath}");
+ }
+
+ if (!File.Exists(fragPath))
+ {
+ Logger.LogInformation("Fragment shader file not found: {FragPath}", fragPath);
+ throw new FileNotFoundException($"Fragment shader file not found: {fragPath}");
+ }
+
+ // Create a new shader instance and add it to the cache.
+ // Shader program objects are shareable across contexts *only* when those contexts share.
+ var shader = new Shader(gl, vertPath, fragPath, name).Initialize();
+ _shaderCache[cacheKey] = shader;
+
+ HasShadersToLoad = true;
+
+ return shader;
+ }
+
+ private static object GetShareGroupKey(Window window)
+ => (object?)window.SharedContext ?? (object?)window.GLContext ?? (object)window;
+}
diff --git a/SharpEngine.Core/Shaders/UIShader.cs b/SharpEngine.Core/Shaders/UIShader.cs
new file mode 100644
index 0000000..50e80a6
--- /dev/null
+++ b/SharpEngine.Core/Shaders/UIShader.cs
@@ -0,0 +1,50 @@
+using SharpEngine.Core.Entities.Properties.Meshes;
+using SharpEngine.Core.Windowing;
+using SharpEngine.Core._Resources;
+
+using Silk.NET.OpenGL;
+
+namespace SharpEngine.Core.Shaders;
+
+///
+/// Represents a shader used for rendering UI elements.
+///
+///
+/// This shader is responsible for rendering 2D UI components on the screen, such as buttons, panels, and other interface elements.
+/// It is designed to work with the specific vertex and fragment shaders defined for UI rendering in the game engine.
+///
+internal class UIShader : ShaderBase
+{
+ ///
+ /// Ensures that the shader is initialized.
+ ///
+ ///
+ /// This method should be called before using the shader to ensure that it is properly loaded and ready for use.
+ ///
+ /// The window where the shader will be used.
+ public void EnsureInitialized(Window window)
+ {
+ if (Shader is not null)
+ return;
+
+ Shader = ShaderService.Instance.LoadShader(window, Default.UIVertexShader, Default.UIFragmentShader, nameof(UIShader));
+ }
+
+ ///
+ public override bool SetAttributes(GL gl)
+ {
+ if (!base.SetAttributes(gl))
+ return false;
+
+ gl.EnableVertexAttribArray(0);
+ gl.VertexAttribPointer(0, VertexData.VerticesSize, VertexAttribPointerType.Float, false, VertexData.Stride, 0);
+
+ gl.EnableVertexAttribArray(1);
+ gl.VertexAttribPointer(1, VertexData.NormalsSize, VertexAttribPointerType.Float, false, VertexData.Stride, VertexData.NormalsOffset);
+
+ gl.EnableVertexAttribArray(2);
+ gl.VertexAttribPointer(2, VertexData.TexCoordsSize, VertexAttribPointerType.Float, false, VertexData.Stride, VertexData.TexCoordsOffset);
+
+ return true;
+ }
+}
diff --git a/Engine/SharpEngine.Core/SharpEngine.Core.csproj b/SharpEngine.Core/SharpEngine.Core.csproj
similarity index 75%
rename from Engine/SharpEngine.Core/SharpEngine.Core.csproj
rename to SharpEngine.Core/SharpEngine.Core.csproj
index 8633518..04fb6cb 100644
--- a/Engine/SharpEngine.Core/SharpEngine.Core.csproj
+++ b/SharpEngine.Core/SharpEngine.Core.csproj
@@ -1,6 +1,8 @@
+ $(DotNetTargetFramework)
+
Everything needed to build games using a purely C# game engine.AnyCPU;x64;x86
@@ -19,20 +21,24 @@
-
-
-
-
-
+
+
+
+
+
-
+
+
+
+
+
+
-
diff --git a/Engine/SharpEngine.Core/Textures/TextureService.cs b/SharpEngine.Core/Textures/TextureService.cs
similarity index 88%
rename from Engine/SharpEngine.Core/Textures/TextureService.cs
rename to SharpEngine.Core/Textures/TextureService.cs
index 4c40568..2f25e90 100644
--- a/Engine/SharpEngine.Core/Textures/TextureService.cs
+++ b/SharpEngine.Core/Textures/TextureService.cs
@@ -1,9 +1,9 @@
using System.IO;
using System.Collections.Generic;
+using SharpEngine.Core.Components.Properties.Textures;
using SharpEngine.Core.Windowing;
using Texture = SharpEngine.Core.Components.Properties.Textures.Texture;
-using TextureType = Silk.NET.Assimp.TextureType;
namespace SharpEngine.Core.Textures;
@@ -25,6 +25,7 @@ private TextureService() { }
/// Loads a texture from the specified path.
///
/// the full path to the texture.
+ /// The type of the texture.
/// The loaded texture program.
public Texture LoadTexture(string path, TextureType textureType = TextureType.Diffuse)
{
@@ -39,7 +40,7 @@ public Texture LoadTexture(string path, TextureType textureType = TextureType.Di
return cachedTexture;
// Generate handle
- var texture = new Texture(Window.GL, path, textureType);
+ var texture = new Texture(Window.SharedGL, path, textureType);
// Add it to the cache
_textureCache[path] = texture;
diff --git a/Engine/SharpEngine.Core/Windowing/Frame.cs b/SharpEngine.Core/Windowing/Frame.cs
similarity index 100%
rename from Engine/SharpEngine.Core/Windowing/Frame.cs
rename to SharpEngine.Core/Windowing/Frame.cs
diff --git a/SharpEngine.Core/Windowing/IWindowFactory.cs b/SharpEngine.Core/Windowing/IWindowFactory.cs
new file mode 100644
index 0000000..881042c
--- /dev/null
+++ b/SharpEngine.Core/Windowing/IWindowFactory.cs
@@ -0,0 +1,27 @@
+using System.Collections.Generic;
+
+namespace SharpEngine.Core.Windowing;
+
+///
+/// Creates configured window instances from DI registrations.
+///
+public interface IWindowFactory
+{
+ ///
+ /// Gets the registered window names.
+ ///
+ IReadOnlyList RegisteredWindows { get; }
+
+ ///
+ /// Creates a configured window instance.
+ ///
+ /// The optional window registration name.
+ /// A configured .
+ Window CreateWindow(string? name = null);
+
+ ///
+ /// Creates one window for each registration.
+ ///
+ /// The configured windows.
+ IReadOnlyList CreateAllWindows();
+}
diff --git a/Engine/SharpEngine.Core/Windowing/SilkWindow.cs b/SharpEngine.Core/Windowing/SilkWindow.cs
similarity index 95%
rename from Engine/SharpEngine.Core/Windowing/SilkWindow.cs
rename to SharpEngine.Core/Windowing/SilkWindow.cs
index 4301fa0..1f5e1dd 100644
--- a/Engine/SharpEngine.Core/Windowing/SilkWindow.cs
+++ b/SharpEngine.Core/Windowing/SilkWindow.cs
@@ -1,3 +1,5 @@
+using SharpEngine.Core.Entities.Views.Settings;
+
using Silk.NET.Core;
using Silk.NET.Core.Contexts;
using Silk.NET.Input;
@@ -13,6 +15,9 @@
namespace SharpEngine.Core.Windowing;
+// TODO: The warnings produced by enabling this need to be implemented.
+#pragma warning disable CS0067 // Event is required by IWindow but not used by this implementation
+
///
/// Represents an abstraction for the interface.
///
@@ -38,6 +43,11 @@ public bool IsClosing
set => CurrentWindow.IsClosing = value;
}
+ ///
+ /// Gets the settings for the current window.
+ ///
+ public IViewSettings Settings { get; protected set; } = ViewSettings.Default;
+
/// Gets or sets the input context for the window.
public IInputContext? Input { get; protected set; }
@@ -159,6 +169,7 @@ public bool VSync
set => CurrentWindow.ShouldSwapAutomatically = value;
}
+ /// Gets a value indicating whether the window is focused.
public bool IsFocused { get; }
///
diff --git a/Engine/SharpEngine.Core/Windowing/Window.cs b/SharpEngine.Core/Windowing/Window.cs
similarity index 57%
rename from Engine/SharpEngine.Core/Windowing/Window.cs
rename to SharpEngine.Core/Windowing/Window.cs
index c566254..903f3df 100644
--- a/Engine/SharpEngine.Core/Windowing/Window.cs
+++ b/SharpEngine.Core/Windowing/Window.cs
@@ -1,4 +1,3 @@
-using SharpEngine.Core.Entities.Properties.Meshes;
using SharpEngine.Core.Entities.Views;
using SharpEngine.Core.Entities.Views.Settings;
using SharpEngine.Core.Enums;
@@ -6,6 +5,12 @@
using SharpEngine.Core.Renderers;
using SharpEngine.Core.Scenes;
using SharpEngine.Core.Shaders;
+using SharpEngine.Core.Interfaces;
+using Shader = SharpEngine.Core.Shaders.Shader;
+
+using SharpEngine.Shared.Dto;
+
+using Microsoft.Extensions.Logging;
using Silk.NET.Input;
using Silk.NET.Maths;
@@ -18,10 +23,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
-using System.Threading.Tasks;
-using Shader = SharpEngine.Core.Shaders.Shader;
-using Silk.NET.GLFW;
-using SharpEngine.Shared;
namespace SharpEngine.Core.Windowing;
@@ -30,8 +31,11 @@ namespace SharpEngine.Core.Windowing;
///
public class Window : SilkWindow
{
+ private const string _iconPath = "_Resources/icon.png";
private bool _windowInitialized;
private bool _initialized;
+ private readonly RendererBase[] _registeredRenderers;
+ private readonly ILogger _logger;
private IEnumerable _renderers = [];
private ImGuiController? _imGuiController;
@@ -41,11 +45,6 @@ public class Window : SilkWindow
///
public readonly CameraView Camera;
- ///
- /// Gets the settings for the current window.
- ///
- public IViewSettings Settings;
-
/// The event executed when mouse events are executed.
public event Action? OnHandleMouse;
@@ -67,29 +66,84 @@ public class Window : SilkWindow
protected Scene Scene { get; private set; }
/// The OpenGL context.
- public static GL GL;
+ private GL _gl = null!;
+
+ private static GL? _sharedGl;
+
+ ///
+ /// Gets the shared OpenGL instance used for resource creation when windows share an OpenGL context.
+ ///
+ ///
+ /// This is primarily for backward compatibility with code that assumed a single global GL instance.
+ /// For multi-window support, prefer using and ensuring the correct context is current.
+ ///
+ public static GL SharedGL
+ => _sharedGl ?? throw new InvalidOperationException("No OpenGL context has been created yet.");
+
+ ///
+ /// Backward compatible alias for .
+ ///
+ public static GL GL => SharedGL;
- // TODO: #93 Use this method.
///
/// Gets the current OpenGL context.
///
/// The OpenGL context for this window.
- public static GL GetGL() => GL;
- private static void SetGL(GL gl) => GL = gl;
-
+ public GL GetGL() => _gl;
+ private void SetGL(GL gl) => _gl = gl;
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ /// The camera the window should render from.
+ /// Contains the game scene.
+ /// The settings for the window.
+ public Window(CameraView camera, Scene scene, IViewSettings settings) :
+ this(camera, scene, settings, LoggerFactory.Create(builder => builder.AddConsole()).CreateLogger()) { }
+
///
/// Initializes a new instance of .
///
/// The camera the window should render from.
/// Contains the game scene.
/// The settings for the window.
- public Window(CameraView camera, Scene scene, IViewSettings settings)
+ /// The logger for the window.
+ /// The renderers for the window.
+ public Window(CameraView camera, Scene scene, IViewSettings settings, ILogger logger, IEnumerable? renderers = null)
{
+ // TODO:
+ // Should the developer need to call for a window initialization?
+ // Meaning should should we move this project loading part to a separate function?
+
Scene = scene;
Settings = settings;
Camera = camera;
+ _registeredRenderers = renderers?.ToArray() ?? [];
+ _logger = logger;
+
+ CheckEngineVersion();
+
+ // NOTE: Window initialization is intentionally not performed automatically
+ // here. Call InitializeWindow() explicitly when ready to create the underlying
+ // native window and load resources. See the TODO in the project for reasoning.
}
+ private void CheckEngineVersion()
+ {
+ var project = new Project();
+ var currentAssemlyVersion = typeof(Window).Assembly.GetVersion();
+
+ if (currentAssemlyVersion != project.EngineVersion)
+ _logger.LogWarning("The current engine version ({CurrentVersion}) does not match the project engine version ({ProjectVersion}). This may lead to unexpected behavior.", currentAssemlyVersion, project.EngineVersion);
+ }
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ /// The game instance.
+ public Window(Game game)
+ : this(game.Scene, game.Camera.Settings, LoggerFactory.Create(builder => builder.AddConsole()).CreateLogger()) { }
+
///
/// Initializes a new instance of .
///
@@ -98,17 +152,22 @@ public Window(CameraView camera, Scene scene, IViewSettings settings)
///
/// Contains the game scene.
/// The settings for the window.
- public Window(Scene scene, IViewSettings settings)
+ /// The logger for the window.
+ /// The renderers for the window.
+ public Window(Scene scene, IViewSettings settings, ILogger logger, IEnumerable? renderers = null)
{
Scene = scene;
Settings = settings;
Camera = new(Vector3.One, settings);
+ _registeredRenderers = renderers?.ToArray() ?? [];
+ _logger = logger;
+
+ // Initialization is deferred. Call Initialize() when you want the
+ // native window to be created and resources to be loaded.
}
- ///
- /// Initializes the ga
- ///
- public void InitializeWindow()
+ ///
+ public override void Initialize()
{
if (_initialized)
return;
@@ -136,7 +195,7 @@ public override void Run(Action onFrame)
}
catch (Exception ex)
{
- Debug.Log.Error(ex, "Error running window: {Message}", ex.Message);
+ _logger.LogError(ex, "Error running window: {Message}", ex.Message);
}
}
@@ -148,43 +207,36 @@ public override void OnLoad()
var context = CurrentWindow.CreateOpenGL();
SetGL(context);
+ // Capture the first created GL as the shared GL. This enables resource caches to work across windows
+ // when those windows are created with a shared OpenGL context.
+ _sharedGl ??= context;
+
Input = CurrentWindow.CreateInput();
+
+ // TODO: Skip calling this for secondary windows?
CurrentWindow.MakeCurrent();
- SetWindowIcon(PathExtensions.GetAssemblyPath("_Resources/icon.png"));
+ SetWindowIcon(PathExtensions.GetAssemblyPath(_iconPath));
AssignInputEvents();
- GL.ClearColor(0.2f, 0.3f, 0.3f, 1.0f);
+ _gl.ClearColor(0.2f, 0.3f, 0.3f, 1.0f);
- // Load all meshes from the mesh cache
- // MeshService.Instance.LoadMesh("cube", Primitives.Cube.Mesh);
-
- // Using reflection, find all renderers that implement the RendererBase.
- var rendererTypes = AppDomain.CurrentDomain.GetAssemblies()
- .SelectMany(assembly => assembly.GetTypes())
- .Where(type => type.IsSubclassOf(typeof(RendererBase)) && !type.IsAbstract);
-
- foreach (var type in rendererTypes)
- {
- // Make sure the renderer has the correct constructor parameters!
- // TODO: #75 The static reference to the context will not work when multiple windows are implemented, since the context will be different.
- var requiredArguments = new object[] { Camera, this, Settings, Scene };
- var renderer = (RendererBase)Activator.CreateInstance(type, requiredArguments)!;
-
- _renderers = _renderers.Append(renderer);
- }
+ _renderers = CreateRenderers();
foreach (var renderer in _renderers)
+ {
+ renderer.AttachWindow(this);
renderer.Initialize();
+ }
- _imGuiController = new ImGuiController(GL, CurrentWindow, Input);
+ _imGuiController = new ImGuiController(_gl, CurrentWindow, Input);
_initialized = true;
}
catch (Exception ex)
{
- Debug.Log.Information(ex, "Error loading window: {Message}", ex.Message);
+ _logger.LogInformation(ex, "Error loading window: {Message}", ex.Message);
}
base.OnLoad();
@@ -207,17 +259,18 @@ protected void RenderFrame(Frame frame)
_imGuiController?.Update((float)frame.FrameTime);
- GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
+ _gl.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
ToggleWireFrame(Settings.UseWireFrame);
UseShaders();
- var renderTasks = _renderers.Where(renderer => Settings.RendererFlags.HasFlag(renderer.RenderFlag))
- .Select(renderer => renderer.Render())
- .ToList();
+ var activeRenderers = _renderers.Where(renderer => Settings.RendererFlags.HasFlag(renderer.RenderFlag))
+ .OrderBy(renderer => renderer.RenderFlag)
+ .ToList();
- Task.WaitAll([.. renderTasks]);
+ foreach (var renderer in activeRenderers)
+ renderer.Render().GetAwaiter().GetResult();
AfterRender(frame);
@@ -225,16 +278,35 @@ protected void RenderFrame(Frame frame)
}
catch (Exception ex)
{
- Debug.Log.Information(ex.Message);
+ _logger.LogInformation("{Message}", ex.Message);
}
}
+ private RendererBase[] CreateRenderers()
+ {
+ // Return the renderers that have been registered
+ if (_registeredRenderers.Length > 0)
+ return _registeredRenderers;
+
+ // When no renderers have been registered, fall back to use all that are discoverable.
+ var rendererTypes = AppDomain.CurrentDomain.GetAssemblies()
+ .SelectMany(assembly => assembly.GetTypes())
+ .Where(type => type.IsSubclassOf(typeof(RendererBase)) && !type.IsAbstract);
+
+ return [.. rendererTypes
+ .Select(type =>
+ {
+ var requiredArguments = new object[] { Camera, Settings, Scene };
+ return (RendererBase)Activator.CreateInstance(type, requiredArguments)!;
+ })];
+ }
+
///
/// Toggles the renderer between wireframe and fill mode.
///
/// Determines whether objects should be rendered in wireframe.
- private static void ToggleWireFrame(bool useWireFrame)
- => GL.PolygonMode(GLEnum.FrontAndBack, useWireFrame ? PolygonMode.Line : PolygonMode.Fill);
+ private void ToggleWireFrame(bool useWireFrame)
+ => _gl.PolygonMode(GLEnum.FrontAndBack, useWireFrame ? PolygonMode.Line : PolygonMode.Fill);
private List _shaders = [];
@@ -255,7 +327,7 @@ protected void OnUpdateFrame(Frame frame)
}
if (Settings.PrintFrameRate)
- Debug.Log.Information($"FPS: {frame.FrameRate}");
+ _logger.LogInformation("FPS: {FrameRate}", frame.FrameRate);
// TODO: #21 Handle multiple mice?
var mouse = Input?.Mice[0];
@@ -283,7 +355,7 @@ private void AssignInputEvents()
{
if (Input is null)
{
- Debug.Log.Information("Input is null. No input events will be assigned.");
+ _logger.LogInformation("Input is null. No input events will be assigned.");
return;
}
@@ -325,7 +397,7 @@ protected void OnMouseWheel(IMouse mouse, ScrollWheel sw)
///
protected void OnResize(Vector2D size)
{
- GL.Viewport(size);
+ _gl.Viewport(size);
if (size != Vector2D.Zero)
Camera.AspectRatio = (float)size.X / size.Y;
diff --git a/SharpEngine.Core/Windowing/WindowFactory.cs b/SharpEngine.Core/Windowing/WindowFactory.cs
new file mode 100644
index 0000000..f2774ea
--- /dev/null
+++ b/SharpEngine.Core/Windowing/WindowFactory.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace SharpEngine.Core.Windowing;
+
+///
+/// Creates window instances from a collection of entries.
+///
+/// The service provider used to resolve window dependencies.
+/// The registrations that describe available windows.
+internal sealed class WindowFactory(IServiceProvider serviceProvider, IEnumerable registrations) : IWindowFactory
+{
+ private readonly IServiceProvider _serviceProvider = serviceProvider;
+ private readonly IReadOnlyList _registrations = registrations.ToArray();
+
+ ///
+ /// Gets the names of all registered windows.
+ ///
+ public IReadOnlyList RegisteredWindows => [.. _registrations.Select(registration => registration.Name)];
+
+ ///
+ /// Creates a window by its registration name.
+ ///
+ ///
+ /// If is null, the default registration (or the first registration if none are marked default) is used.
+ ///
+ /// Optional name of the window registration to create.
+ /// The created instance.
+ /// Thrown when no registrations exist or when a named registration cannot be found.
+ public Window CreateWindow(string? name = null)
+ {
+ var registration = ResolveRegistration(name);
+ var window = registration.Factory(_serviceProvider);
+ registration.Configure?.Invoke(_serviceProvider, window);
+ return window;
+ }
+
+ ///
+ /// Creates instances for all registered windows in the order they were registered.
+ ///
+ /// A read-only list containing all created window instances.
+ public IReadOnlyList CreateAllWindows()
+ => [.. _registrations.Select(registration => CreateWindow(registration.Name))];
+
+ ///
+ /// Resolves the appropriate registration for the given name.
+ ///
+ /// The optional registration name to resolve.
+ ///
+ /// The matching or returns the default registration when is null.
+ ///
+ /// Thrown when no registrations exist or when a named registration cannot be found.
+ private WindowRegistration ResolveRegistration(string? name)
+ {
+ if (_registrations.Count == 0)
+ throw new InvalidOperationException("No windows have been registered. Call AddWindow during service configuration.");
+
+ if (name is not null)
+ {
+ var namedRegistration = _registrations.FirstOrDefault(registration => string.Equals(registration.Name, name, StringComparison.OrdinalIgnoreCase));
+ return namedRegistration ?? throw new InvalidOperationException($"No window named '{name}' has been registered.");
+ }
+
+ return _registrations.FirstOrDefault(registration => registration.IsDefault) ?? _registrations[0];
+ }
+}
diff --git a/SharpEngine.Core/Windowing/WindowRegistration.cs b/SharpEngine.Core/Windowing/WindowRegistration.cs
new file mode 100644
index 0000000..f6c64c4
--- /dev/null
+++ b/SharpEngine.Core/Windowing/WindowRegistration.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace SharpEngine.Core.Windowing;
+
+///
+/// Holds registration information for a window type.
+///
+internal sealed class WindowRegistration
+{
+ /// Gets or initializes the name for the window.
+ public required string Name { get; init; }
+
+ /// Gets or initializes the factory delegate used to create the window instance.
+ /// The service provider is supplied to allow resolving dependencies required by the window.
+ public required Func Factory { get; init; }
+
+ /// Gets or initializes the optional configuration action invoked immediately after the window is created.
+ public Action? Configure { get; init; }
+
+ /// Gets or initializes a value indicating whether this registration should be used as the default when no specific window name is requested.
+ public bool IsDefault { get; init; }
+}
diff --git a/Engine/SharpEngine.Core/_Resources/Default.cs b/SharpEngine.Core/_Resources/Default.cs
similarity index 77%
rename from Engine/SharpEngine.Core/_Resources/Default.cs
rename to SharpEngine.Core/_Resources/Default.cs
index ef3e138..88fc100 100644
--- a/Engine/SharpEngine.Core/_Resources/Default.cs
+++ b/SharpEngine.Core/_Resources/Default.cs
@@ -16,8 +16,12 @@ public static class Default
/// Gets the path to the lighting fragment shader.
public static string FragmentShader => PathExtensions.GetAssemblyPath("_Resources\\Shaders\\lighting.frag");
+ /// Gets the path to the default shader used for rendering light sources.
public static string LightShader => PathExtensions.GetAssemblyPath("_Resources\\Shaders\\shader.frag");
-
+
+ /// Gets the path to the default vertex shader used for rendering UI elements.
public static string UIVertexShader => PathExtensions.GetAssemblyPath("_Resources\\Shaders\\uiShader.vert");
+
+ /// Gets the path to the default fragment shader used for rendering UI elements.
public static string UIFragmentShader => PathExtensions.GetAssemblyPath("_Resources\\Shaders\\uiShader.frag");
}
diff --git a/Engine/SharpEngine.Core/_Resources/Shaders/Light/DirectionalLight.glsl b/SharpEngine.Core/_Resources/Shaders/Light/DirectionalLight.glsl
similarity index 100%
rename from Engine/SharpEngine.Core/_Resources/Shaders/Light/DirectionalLight.glsl
rename to SharpEngine.Core/_Resources/Shaders/Light/DirectionalLight.glsl
diff --git a/Engine/SharpEngine.Core/_Resources/Shaders/Light/PointLight.glsl b/SharpEngine.Core/_Resources/Shaders/Light/PointLight.glsl
similarity index 100%
rename from Engine/SharpEngine.Core/_Resources/Shaders/Light/PointLight.glsl
rename to SharpEngine.Core/_Resources/Shaders/Light/PointLight.glsl
diff --git a/Engine/SharpEngine.Core/_Resources/Shaders/Light/SpotLight.glsl b/SharpEngine.Core/_Resources/Shaders/Light/SpotLight.glsl
similarity index 100%
rename from Engine/SharpEngine.Core/_Resources/Shaders/Light/SpotLight.glsl
rename to SharpEngine.Core/_Resources/Shaders/Light/SpotLight.glsl
diff --git a/Engine/SharpEngine.Core/_Resources/Shaders/Material.glsl b/SharpEngine.Core/_Resources/Shaders/Material.glsl
similarity index 100%
rename from Engine/SharpEngine.Core/_Resources/Shaders/Material.glsl
rename to SharpEngine.Core/_Resources/Shaders/Material.glsl
diff --git a/Engine/SharpEngine.Core/_Resources/Shaders/lighting.frag b/SharpEngine.Core/_Resources/Shaders/lighting.frag
similarity index 100%
rename from Engine/SharpEngine.Core/_Resources/Shaders/lighting.frag
rename to SharpEngine.Core/_Resources/Shaders/lighting.frag
diff --git a/Engine/SharpEngine.Core/_Resources/Shaders/shader.frag b/SharpEngine.Core/_Resources/Shaders/shader.frag
similarity index 100%
rename from Engine/SharpEngine.Core/_Resources/Shaders/shader.frag
rename to SharpEngine.Core/_Resources/Shaders/shader.frag
diff --git a/Engine/SharpEngine.Core/_Resources/Shaders/shader.vert b/SharpEngine.Core/_Resources/Shaders/shader.vert
similarity index 100%
rename from Engine/SharpEngine.Core/_Resources/Shaders/shader.vert
rename to SharpEngine.Core/_Resources/Shaders/shader.vert
diff --git a/Engine/SharpEngine.Core/_Resources/Shaders/shader2.vert b/SharpEngine.Core/_Resources/Shaders/shader2.vert
similarity index 100%
rename from Engine/SharpEngine.Core/_Resources/Shaders/shader2.vert
rename to SharpEngine.Core/_Resources/Shaders/shader2.vert
diff --git a/Engine/SharpEngine.Core/_Resources/Shaders/uiShader.frag b/SharpEngine.Core/_Resources/Shaders/uiShader.frag
similarity index 100%
rename from Engine/SharpEngine.Core/_Resources/Shaders/uiShader.frag
rename to SharpEngine.Core/_Resources/Shaders/uiShader.frag
diff --git a/Engine/SharpEngine.Core/_Resources/Shaders/uiShader.vert b/SharpEngine.Core/_Resources/Shaders/uiShader.vert
similarity index 100%
rename from Engine/SharpEngine.Core/_Resources/Shaders/uiShader.vert
rename to SharpEngine.Core/_Resources/Shaders/uiShader.vert
diff --git a/Engine/SharpEngine.Core/_Resources/Textures/debug.jpg b/SharpEngine.Core/_Resources/Textures/debug.jpg
similarity index 100%
rename from Engine/SharpEngine.Core/_Resources/Textures/debug.jpg
rename to SharpEngine.Core/_Resources/Textures/debug.jpg
diff --git a/Engine/SharpEngine.Core/_Resources/icon.png b/SharpEngine.Core/_Resources/icon.png
similarity index 100%
rename from Engine/SharpEngine.Core/_Resources/icon.png
rename to SharpEngine.Core/_Resources/icon.png
diff --git a/SharpEngine.Shared/Debug.cs b/SharpEngine.Shared/Debug.cs
new file mode 100644
index 0000000..43c2f7a
--- /dev/null
+++ b/SharpEngine.Shared/Debug.cs
@@ -0,0 +1,79 @@
+using Serilog;
+using Serilog.Events;
+using System;
+using System.Numerics;
+
+namespace SharpEngine.Shared;
+
+///
+/// Contains methods for debugging the application.
+///
+public static class Debug
+{
+ ///
+ /// A logger instance used for debugging the application.
+ ///
+ public static ILogger Log { get; set; }
+
+ private static LogEventLevel _logLevel = LogEventLevel.Information;
+
+ ///
+ /// Initializes the class instance.
+ ///
+ static Debug()
+ {
+ SetLogger();
+ }
+
+ ///
+ /// Updates the logger instance.
+ ///
+ public static void SetLogger()
+ => Log = new LoggerConfiguration()
+ .MinimumLevel.Is(_logLevel)
+ .WriteTo.Console()
+ .CreateLogger();
+
+ ///
+ /// Sets the logging level for the application.
+ ///
+ ///
+ /// This affects the granularity of log messages generated.
+ ///
+ /// Specifies the severity level of log messages to be recorded.
+ public static void SetLogLevel(LogEventLevel logLevel)
+ {
+ _logLevel = logLevel;
+ SetLogger();
+ }
+
+#if DEBUG
+
+ ///
+ /// Draws a line on the screen.
+ ///
+ /// The starting point for the line.
+ /// The direction where the vector needs to be drawn.
+ /// Determines how long the line needs to be.
+ /// Determines how wide of a vector needs to be drawn.
+ /// Thrown when the method is called, indicating that the implementation is not yet provided.
+ public static void DrawLine(Vector3 startPoint, Vector3 direction, float length, float width = 1)
+ {
+ // https://math.stackexchange.com/questions/1286489/how-to-find-direction-and-normal-vector
+ throw new NotImplementedException();
+ }
+
+ ///
+ /// Draws a box in 3D space defined by two corner points.
+ ///
+ /// Specifies one corner of the box in 3D coordinates.
+ /// Specifies the opposite corner of the box in 3D coordinates.
+ /// Determines whether the box is rendered as a solid shape or as a wireframe.
+ /// Thrown when the method has not been implemented yet.
+ public static void DrawBox(Vector3 min, Vector3 max, bool wireframe = true)
+ {
+ throw new NotImplementedException();
+ }
+
+#endif
+}
\ No newline at end of file
diff --git a/Engine/SharpEngine.slnx b/SharpEngine.slnx
similarity index 74%
rename from Engine/SharpEngine.slnx
rename to SharpEngine.slnx
index 32cc136..4cfa5e7 100644
--- a/Engine/SharpEngine.slnx
+++ b/SharpEngine.slnx
@@ -1,9 +1,15 @@
+
+
+
+
+
+
@@ -18,14 +24,17 @@
+
+
+
-
-
+
+
@@ -38,12 +47,17 @@
-
-
+
+
+
+
+
+
+
+
-
-
-
+
+
@@ -55,10 +69,5 @@
-
-
-
-
-
-
+
diff --git a/Tests/Directory.Build.props b/Tests/Directory.Build.props
new file mode 100644
index 0000000..3ad3602
--- /dev/null
+++ b/Tests/Directory.Build.props
@@ -0,0 +1,10 @@
+
+
+
+
+
+ False
+
+
+
+
\ No newline at end of file
diff --git a/Engine/Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs b/Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs
similarity index 85%
rename from Engine/Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs
rename to Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs
index 39c13c4..be3028c 100644
--- a/Engine/Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs
+++ b/Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs
@@ -1,32 +1,30 @@
using System.Collections.Generic;
-using System.IO;
-using System.Text;
-using NUnit.Framework;
-using ObjLoader.Loader.Data;
using System.Linq;
+
+using NUnit.Framework;
using FluentAssertions;
-using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore;
-using SharpEngine.Core.Entities.Properties;
+using SharpEngine.Core.Components.ObjLoader.DataStore;
using SharpEngine.Core.Components.Properties;
-using ObjLoader.Loaders.MaterialLoader;
+using SharpEngine.Core.ObjLoader.Loaders.MaterialLoader;
+using System.Diagnostics.CodeAnalysis;
-namespace ObjLoader.Test.Loaders
+namespace SharpEngine.Core.ObjLoader.Tests.Loaders
{
[TestFixture]
public class MaterialLibraryLoaderTests
{
- private MaterialLibrarySpy _materialLibrarySpy;
+ private readonly MaterialLibrarySpy _materialLibrarySpy;
+ private readonly MaterialLibraryLoader _materialLibraryLoader;
+
private Material _firstMaterial;
private Material _secondMaterial;
private const float Epsilon = 0.000001f;
- private MaterialLibraryLoader _materialLibraryLoader;
- [SetUp]
- public void SetUp()
+ public MaterialLibraryLoaderTests()
{
_materialLibrarySpy = new MaterialLibrarySpy();
- // _materialLibraryLoader = new MaterialLibraryLoader(_materialLibrarySpy);
+ _materialLibraryLoader = new MaterialLibraryLoader(null!);
}
[Test]
@@ -102,12 +100,10 @@ public void Sets_correct_texure_maps()
_firstMaterial.StencilDecalMap.Should().BeEquivalentTo("lenna_stencil.tga");
}
+ [MemberNotNull(nameof(_firstMaterial), nameof(_secondMaterial))]
private void LoadMaterial()
{
- var data = Encoding.ASCII.GetBytes(MaterialLibrary);
- var materialStream = new MemoryStream(data);
-
- _materialLibraryLoader.Load(materialStream);
+ _materialLibraryLoader.ParseFile(MaterialLibrary);
_firstMaterial = _materialLibrarySpy.Materials.First();
_secondMaterial = _materialLibrarySpy.Materials.ElementAt(1);
}
diff --git a/Engine/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs b/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs
similarity index 82%
rename from Engine/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs
rename to Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs
index 8e4190a..56e9765 100644
--- a/Engine/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs
+++ b/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs
@@ -2,13 +2,15 @@
using System.Text;
using System.Linq;
using NUnit.Framework;
-using ObjLoader.Loader.Loaders;
-using ObjLoader.Loader.TypeParsers;
using FluentAssertions;
-using ObjLoader.Loaders.MaterialLoader;
+
using SharpEngine.Core.Entities.Properties.Meshes;
+using SharpEngine.Core.ObjLoader.Loader.TypeParsers;
+using SharpEngine.Core.ObjLoader.Loaders.MaterialLoader;
+
+using CoreObjLoader = SharpEngine.Core.ObjLoader.Loaders.ObjLoader.ObjLoader;
-namespace ObjLoader.Test.Loaders
+namespace SharpEngine.Core.ObjLoader.Tests.Loaders
{
[TestFixture]
public class ObjLoaderTests
@@ -25,7 +27,7 @@ public Stream Open(string materialFilePath)
}
}
- private ObjLoader.Loaders.ObjLoader.ObjLoader _loader;
+ private CoreObjLoader _loader;
private Mesh _loadResult;
private DataStore _textureDataStore;
@@ -53,12 +55,12 @@ public void SetUp()
_materialStreamProviderSpy = new MaterialStreamProviderSpy();
_materialStreamProviderSpy.StreamToReturn = CreateMemoryStreamFromString(MaterialLibraryString);
- _materialLibraryLoader = new MaterialLibraryLoader("", _textureDataStore);
- _materialLibraryLoaderFacade = new MaterialLibraryLoaderFacade(_materialLibraryLoader);
- // _materialLibraryParser = new MaterialLibraryParser(_materialLibraryLoaderFacade);
+ _materialLibraryLoader = new MaterialLibraryLoader(_textureDataStore);
+ _materialLibraryLoaderFacade = new MaterialLibraryLoaderFacade(_materialLibraryLoader, "");
+ _materialLibraryParser = new MaterialLibraryParser(_materialLibraryLoaderFacade);
_useMaterialParser = new UseMaterialParser(_textureDataStore);
- // _loader = new Loader.Loaders.ObjLoader(_textureDataStore, _faceParser, _groupParser, _normalParser, _textureParser, _vertexParser, _materialLibraryParser, _useMaterialParser);
+ _loader = new CoreObjLoader("", _textureDataStore);
}
[Test]
@@ -77,17 +79,17 @@ public void Loads_object_and_material_correctly()
var group = _loadResult.Groups.First();
group.Faces.Should().HaveCount(12);
- group.Material.Name.Should().BeEquivalentTo("cube_material");
+ group.Material!.Name.Should().BeEquivalentTo("cube_material");
}
[Test]
public void Loads_object_correctly_when_material_is_not_found()
{
- _materialStreamProviderSpy.StreamToReturn = null;
- var materialLibraryLoaderFacade = new MaterialLibraryLoaderFacade(_materialLibraryLoader);
- // var materialLibraryParser = new MaterialLibraryParser(materialLibraryLoaderFacade);
+ _materialStreamProviderSpy.StreamToReturn = null!;
+ var materialLibraryLoaderFacade = new MaterialLibraryLoaderFacade(_materialLibraryLoader, "");
+ var materialLibraryParser = new MaterialLibraryParser(_materialLibraryLoaderFacade);
- // _loader = new Loader.Loaders.ObjLoader(_textureDataStore, _faceParser, _groupParser, _normalParser, _textureParser, _vertexParser, materialLibraryParser, _useMaterialParser);
+ _loader = new CoreObjLoader("", _textureDataStore);
Load();
@@ -107,7 +109,7 @@ private void Load()
{
var objectStream = CreateMemoryStreamFromString(ObjectFileString);
- // _loadResult = _loader.Load(objectStream);
+ _loadResult = _loader.Load(null!).First();
}
private Stream CreateMemoryStreamFromString(string str)
diff --git a/Engine/Tests/ObjLoader.Test/ObjLoader.Tests.csproj b/Tests/ObjLoader.Test/SharpEngine.Core.ObjLoader.Tests.csproj
similarity index 82%
rename from Engine/Tests/ObjLoader.Test/ObjLoader.Tests.csproj
rename to Tests/ObjLoader.Test/SharpEngine.Core.ObjLoader.Tests.csproj
index 7725988..6a619d7 100644
--- a/Engine/Tests/ObjLoader.Test/ObjLoader.Tests.csproj
+++ b/Tests/ObjLoader.Test/SharpEngine.Core.ObjLoader.Tests.csproj
@@ -1,7 +1,7 @@
- net8.0
+ $(DotNetTargetFramework)
@@ -11,6 +11,10 @@
+
+
+ CS8618
+
diff --git a/Engine/Tests/ObjLoader.Test/TypeParsers/FaceParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/FaceParserTests.cs
similarity index 94%
rename from Engine/Tests/ObjLoader.Test/TypeParsers/FaceParserTests.cs
rename to Tests/ObjLoader.Test/TypeParsers/FaceParserTests.cs
index 64ba447..df5b03a 100644
--- a/Engine/Tests/ObjLoader.Test/TypeParsers/FaceParserTests.cs
+++ b/Tests/ObjLoader.Test/TypeParsers/FaceParserTests.cs
@@ -1,11 +1,11 @@
using FluentAssertions;
using NUnit.Framework;
-using ObjLoader.Loader.Data;
-using ObjLoader.Loader.Data.Elements;
-using ObjLoader.Loader.TypeParsers;
-using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore;
-namespace ObjLoader.Test.TypeParsers
+using SharpEngine.Core.Components.ObjLoader.DataStore;
+using SharpEngine.Core.Components.Properties.Meshes.MeshData;
+using SharpEngine.Core.ObjLoader.Loader.TypeParsers;
+
+namespace SharpEngine.Core.ObjLoader.Tests.TypeParsers
{
[TestFixture]
public class FaceParserTests
diff --git a/Engine/Tests/ObjLoader.Test/TypeParsers/GroupParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/GroupParserTests.cs
similarity index 76%
rename from Engine/Tests/ObjLoader.Test/TypeParsers/GroupParserTests.cs
rename to Tests/ObjLoader.Test/TypeParsers/GroupParserTests.cs
index 97ea846..061dd2d 100644
--- a/Engine/Tests/ObjLoader.Test/TypeParsers/GroupParserTests.cs
+++ b/Tests/ObjLoader.Test/TypeParsers/GroupParserTests.cs
@@ -1,23 +1,21 @@
using FluentAssertions;
using NUnit.Framework;
-using ObjLoader.Loader.Data;
-using ObjLoader.Loader.TypeParsers;
-using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore;
-namespace ObjLoader.Test.TypeParsers
+using SharpEngine.Core.Components.ObjLoader.DataStore;
+using SharpEngine.Core.ObjLoader.Loader.TypeParsers;
+
+namespace SharpEngine.Core.ObjLoader.Tests.TypeParsers
{
[TestFixture]
public class GroupParserTests
{
- private GroupDataStoreMock _groupDataStoreMock;
- private GroupParser _groupParser;
+ private readonly GroupDataStoreMock _groupDataStoreMock;
+ private readonly GroupParser _groupParser;
- [SetUp]
- public void SetUp()
+ public GroupParserTests()
{
_groupDataStoreMock = new GroupDataStoreMock();
-
- // _groupParser = new GroupParser(_groupDataStoreMock);
+ _groupParser = new GroupParser(_groupDataStoreMock);
}
[Test]
diff --git a/Engine/Tests/ObjLoader.Test/TypeParsers/MaterialLibraryParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/MaterialLibraryParserTests.cs
similarity index 75%
rename from Engine/Tests/ObjLoader.Test/TypeParsers/MaterialLibraryParserTests.cs
rename to Tests/ObjLoader.Test/TypeParsers/MaterialLibraryParserTests.cs
index 91089f1..3c974a6 100644
--- a/Engine/Tests/ObjLoader.Test/TypeParsers/MaterialLibraryParserTests.cs
+++ b/Tests/ObjLoader.Test/TypeParsers/MaterialLibraryParserTests.cs
@@ -1,21 +1,20 @@
using FluentAssertions;
using NUnit.Framework;
-using ObjLoader.Loader.TypeParsers;
-using ObjLoader.Loaders.MaterialLoader;
+using SharpEngine.Core.ObjLoader.Loader.TypeParsers;
+using SharpEngine.Core.ObjLoader.Loaders.MaterialLoader;
-namespace ObjLoader.Test.TypeParsers
+namespace SharpEngine.Core.ObjLoader.Tests.TypeParsers
{
[TestFixture]
public class MaterialLibraryParserTests
{
- private MaterialLibraryLoaderFacadeSpy _materialLibraryLoaderFacadeSpy;
- private MaterialLibraryParser _parser;
+ private readonly MaterialLibraryLoaderFacadeSpy _materialLibraryLoaderFacadeSpy;
+ private readonly MaterialLibraryParser _parser;
- [SetUp]
- public void SetUp()
+ public MaterialLibraryParserTests()
{
_materialLibraryLoaderFacadeSpy = new MaterialLibraryLoaderFacadeSpy();
- // _parser = new MaterialLibraryParser(_materialLibraryLoaderFacadeSpy);
+ _parser = new MaterialLibraryParser(_materialLibraryLoaderFacadeSpy);
}
[Test]
diff --git a/Engine/Tests/ObjLoader.Test/TypeParsers/NormalParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/NormalParserTests.cs
similarity index 80%
rename from Engine/Tests/ObjLoader.Test/TypeParsers/NormalParserTests.cs
rename to Tests/ObjLoader.Test/TypeParsers/NormalParserTests.cs
index f9e03c7..f047eb5 100644
--- a/Engine/Tests/ObjLoader.Test/TypeParsers/NormalParserTests.cs
+++ b/Tests/ObjLoader.Test/TypeParsers/NormalParserTests.cs
@@ -1,23 +1,22 @@
using FluentAssertions;
using NUnit.Framework;
-using ObjLoader.Loader.TypeParsers;
-using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore;
+
+using SharpEngine.Core.Components.ObjLoader.DataStore;
using SharpEngine.Core.Components.Properties.Meshes.MeshData;
+using SharpEngine.Core.ObjLoader.Loader.TypeParsers;
-namespace ObjLoader.Test.TypeParsers
+namespace SharpEngine.Core.ObjLoader.Tests.TypeParsers
{
[TestFixture]
public class NormalParserTests
{
- private NormalParser _normalParser;
- private NormalDataStoreMock _normalDataStoreMock;
+ private readonly NormalParser _normalParser;
+ private readonly NormalDataStoreMock _normalDataStoreMock;
- [SetUp]
- public void SetUp()
+ public NormalParserTests()
{
_normalDataStoreMock = new NormalDataStoreMock();
-
- // _normalParser = new NormalParser(_normalDataStoreMock);
+ _normalParser = new NormalParser(_normalDataStoreMock);
}
[Test]
diff --git a/Engine/Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs
similarity index 80%
rename from Engine/Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs
rename to Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs
index 539308b..4b9ffd9 100644
--- a/Engine/Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs
+++ b/Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs
@@ -1,23 +1,23 @@
using FluentAssertions;
using NUnit.Framework;
-using ObjLoader.Loader.TypeParsers;
-using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore;
+
+using SharpEngine.Core.Components.ObjLoader.DataStore;
using SharpEngine.Core.Components.Properties.Meshes.MeshData;
+using SharpEngine.Core.ObjLoader.Loader.TypeParsers;
-namespace ObjLoader.Test.TypeParsers
+namespace SharpEngine.Core.ObjLoader.Tests.TypeParsers
{
[TestFixture]
public class TextureParserTests
{
- private TextureDataStoreMock _textureDataStoreMock;
- private TextureParser _textureParser;
+ private readonly TextureDataStoreMock _textureDataStoreMock;
+ private readonly TextureParser _textureParser;
- [SetUp]
- public void SetUp()
+ public TextureParserTests()
{
_textureDataStoreMock = new TextureDataStoreMock();
- // _textureParser = new TextureParser(_textureDataStoreMock);
+ _textureParser = new TextureParser(_textureDataStoreMock);
}
[Test]
diff --git a/Engine/Tests/ObjLoader.Test/TypeParsers/UseMaterialParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/UseMaterialParserTests.cs
similarity index 75%
rename from Engine/Tests/ObjLoader.Test/TypeParsers/UseMaterialParserTests.cs
rename to Tests/ObjLoader.Test/TypeParsers/UseMaterialParserTests.cs
index 863fac8..29cbaa8 100644
--- a/Engine/Tests/ObjLoader.Test/TypeParsers/UseMaterialParserTests.cs
+++ b/Tests/ObjLoader.Test/TypeParsers/UseMaterialParserTests.cs
@@ -1,20 +1,19 @@
using FluentAssertions;
using NUnit.Framework;
-using ObjLoader.Loader.TypeParsers;
+using SharpEngine.Core.ObjLoader.Loader.TypeParsers;
-namespace ObjLoader.Test.TypeParsers
+namespace SharpEngine.Core.ObjLoader.Tests.TypeParsers
{
[TestFixture]
public class UseMaterialParserTests
{
- private ElementGroupSpy _elementGroupSpy;
- private UseMaterialParser _parser;
+ private readonly ElementGroupSpy _elementGroupSpy;
+ private readonly UseMaterialParser _parser;
- [SetUp]
- public void SetUp()
+ public UseMaterialParserTests()
{
_elementGroupSpy = new ElementGroupSpy();
- // _parser = new UseMaterialParser(_elementGroupSpy);
+ _parser = new UseMaterialParser(_elementGroupSpy);
}
[Test]
@@ -44,7 +43,7 @@ public void Parses_usemtl_line_correctly_1()
_elementGroupSpy.MaterialName.Should().BeEquivalentTo("materialName");
}
- private class ElementGroupSpy // : IElementGroup
+ private class ElementGroupSpy : IMaterialDataStore
{
public string MaterialName { get; private set; }
diff --git a/Engine/Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs
similarity index 80%
rename from Engine/Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs
rename to Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs
index ba27316..8009a66 100644
--- a/Engine/Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs
+++ b/Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs
@@ -1,23 +1,22 @@
using FluentAssertions;
using NUnit.Framework;
-using ObjLoader.Loader.TypeParsers;
-using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore;
+
+using SharpEngine.Core.Components.ObjLoader.DataStore;
using SharpEngine.Core.Components.Properties.Meshes.MeshData;
+using SharpEngine.Core.ObjLoader.Loader.TypeParsers;
-namespace ObjLoader.Test.TypeParsers
+namespace SharpEngine.Core.ObjLoader.Tests.TypeParsers
{
[TestFixture]
public class VertexParserTests
{
- private VertexDataStoreMock _vertexDataStoreMock;
- private VertexParser _vertexParser;
+ private readonly VertexDataStoreMock _vertexDataStoreMock;
+ private readonly VertexParser _vertexParser;
- [SetUp]
- public void SetUp()
+ public VertexParserTests()
{
_vertexDataStoreMock = new VertexDataStoreMock();
-
- // _vertexParser = new VertexParser(_vertexDataStoreMock);
+ _vertexParser = new VertexParser(_vertexDataStoreMock);
}
[Test]
@@ -64,6 +63,5 @@ public void AddVertex(Vertex vertex)
ParsedVertex = vertex;
}
}
-
}
}
\ No newline at end of file
diff --git a/Engine/Tests/SharpEngine.Core.Tests/Class1.cs b/Tests/SharpEngine.Core.Tests/Class1.cs
similarity index 100%
rename from Engine/Tests/SharpEngine.Core.Tests/Class1.cs
rename to Tests/SharpEngine.Core.Tests/Class1.cs
diff --git a/Engine/Tests/SharpEngine.Core.Tests/SharpEngine.Core.Tests.csproj b/Tests/SharpEngine.Core.Tests/SharpEngine.Core.Tests.csproj
similarity index 71%
rename from Engine/Tests/SharpEngine.Core.Tests/SharpEngine.Core.Tests.csproj
rename to Tests/SharpEngine.Core.Tests/SharpEngine.Core.Tests.csproj
index fa71b7a..bbcf245 100644
--- a/Engine/Tests/SharpEngine.Core.Tests/SharpEngine.Core.Tests.csproj
+++ b/Tests/SharpEngine.Core.Tests/SharpEngine.Core.Tests.csproj
@@ -1,7 +1,7 @@
- net8.0
+ $(DotNetTargetFramework)enableenable
diff --git a/Engine/Tests/SharpEngine.Editor.Tests/Class1.cs b/Tests/SharpEngine.Editor.Tests/Class1.cs
similarity index 100%
rename from Engine/Tests/SharpEngine.Editor.Tests/Class1.cs
rename to Tests/SharpEngine.Editor.Tests/Class1.cs
diff --git a/Engine/Tests/SharpEngine.Editor.Tests/SharpEngine.Editor.Tests.csproj b/Tests/SharpEngine.Editor.Tests/SharpEngine.Editor.Tests.csproj
similarity index 71%
rename from Engine/Tests/SharpEngine.Editor.Tests/SharpEngine.Editor.Tests.csproj
rename to Tests/SharpEngine.Editor.Tests/SharpEngine.Editor.Tests.csproj
index fa71b7a..bbcf245 100644
--- a/Engine/Tests/SharpEngine.Editor.Tests/SharpEngine.Editor.Tests.csproj
+++ b/Tests/SharpEngine.Editor.Tests/SharpEngine.Editor.Tests.csproj
@@ -1,7 +1,7 @@
- net8.0
+ $(DotNetTargetFramework)enableenable
diff --git a/Engine/Tests/SharpEngine.Shared.Tests/Class1.cs b/Tests/SharpEngine.Shared.Tests/Class1.cs
similarity index 100%
rename from Engine/Tests/SharpEngine.Shared.Tests/Class1.cs
rename to Tests/SharpEngine.Shared.Tests/Class1.cs
diff --git a/Engine/Tests/SharpEngine.Shared.Tests/SharpEngine.Shared.Tests.csproj b/Tests/SharpEngine.Shared.Tests/SharpEngine.Shared.Tests.csproj
similarity index 100%
rename from Engine/Tests/SharpEngine.Shared.Tests/SharpEngine.Shared.Tests.csproj
rename to Tests/SharpEngine.Shared.Tests/SharpEngine.Shared.Tests.csproj