From 44e916056b10b5f425a1a89122598e13da3bcc1e Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Mon, 24 Mar 2025 22:15:59 +0200 Subject: [PATCH 01/92] Temp --- Core/Renderers/Renderer.cs | 1 + Core/Shaders/LampShader.cs | 11 ++- Core/Shaders/LightingShader.cs | 32 +++++--- Core/Shaders/Shader.cs | 16 ++-- Core/Shaders/UIShader.cs | 5 +- Core/SilkWindow.cs | 30 +++++-- Core/Textures/TextureService.cs | 2 +- Core/Window.cs | 31 ++++---- Editor/EditorWindow.cs | 79 +++++++++++-------- Editor/Windows/ImGuiWindowBase.cs | 46 ++++++----- .../MultipleWindows/MultipleWindows.csproj | 17 ++++ Examples/MultipleWindows/Program.cs | 45 +++++++++++ SharpEngine.sln | 11 ++- 13 files changed, 226 insertions(+), 100 deletions(-) create mode 100644 Examples/MultipleWindows/MultipleWindows.csproj create mode 100644 Examples/MultipleWindows/Program.cs diff --git a/Core/Renderers/Renderer.cs b/Core/Renderers/Renderer.cs index 9532509..ae52bed 100644 --- a/Core/Renderers/Renderer.cs +++ b/Core/Renderers/Renderer.cs @@ -41,6 +41,7 @@ public Renderer(CameraView camera, ISettings settings, Scene scene) : base(setti _camera = camera; _scene = scene; + // TODO: These should be refactored out. The minimum build shouldn't need to use these. _lightingShader = new LightingShader(); _lampShader = new LampShader(); } diff --git a/Core/Shaders/LampShader.cs b/Core/Shaders/LampShader.cs index ced37b6..aa63ddb 100644 --- a/Core/Shaders/LampShader.cs +++ b/Core/Shaders/LampShader.cs @@ -1,4 +1,4 @@ -using SharpEngine.Core.Entities.Properties; +using SharpEngine.Core.Entities.Properties; using SharpEngine.Core.Extensions; using Silk.NET.OpenGL; @@ -22,9 +22,12 @@ public override bool SetAttributes() if (!base.SetAttributes()) return false; - var positionLocation = (uint)Shader!.GetAttribLocation(ShaderAttributes.Pos); - Window.GL.EnableVertexAttribArray(positionLocation); - Window.GL.VertexAttribPointer(positionLocation, 3, VertexAttribPointerType.Float, false, VertexData.Stride, 0); + 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/Core/Shaders/LightingShader.cs b/Core/Shaders/LightingShader.cs index 340a003..5ab80f1 100644 --- a/Core/Shaders/LightingShader.cs +++ b/Core/Shaders/LightingShader.cs @@ -1,6 +1,7 @@ -using SharpEngine.Core.Entities.Properties; +using SharpEngine.Core.Entities.Properties; using SharpEngine.Core.Extensions; using Silk.NET.OpenGL; +using System; namespace SharpEngine.Core.Shaders; @@ -22,17 +23,26 @@ public override bool SetAttributes() if (!base.SetAttributes()) return false; - var positionLocation = (uint)Shader!.GetAttribLocation(ShaderAttributes.Pos); - Window.GL.EnableVertexAttribArray(positionLocation); - Window.GL.VertexAttribPointer(positionLocation, VertexData.VerticesSize, VertexAttribPointerType.Float, false, VertexData.Stride, 0); - - var normalLocation = (uint)Shader.GetAttribLocation(ShaderAttributes.Normal); - Window.GL.EnableVertexAttribArray(normalLocation); - Window.GL.VertexAttribPointer(normalLocation, VertexData.NormalsSize, VertexAttribPointerType.Float, false, VertexData.Stride, VertexData.NormalsOffset); + if (!Shader!.TryGetAttribLocation(ShaderAttributes.Pos, out int positionLocation)) + return false; - var texCoordLocation = (uint)Shader.GetAttribLocation(ShaderAttributes.TexCoords); - Window.GL.EnableVertexAttribArray(texCoordLocation); - Window.GL.VertexAttribPointer(texCoordLocation, VertexData.TexCoordsSize, VertexAttribPointerType.Float, false, VertexData.Stride, VertexData.TexCoordsOffset); + 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.Normal, 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/Core/Shaders/Shader.cs b/Core/Shaders/Shader.cs index 4c7b94a..fb02337 100644 --- a/Core/Shaders/Shader.cs +++ b/Core/Shaders/Shader.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Collections.Generic; @@ -166,14 +166,18 @@ public void Use() /// Checks if the shader attribute exists within the current shader. /// /// The name of the attribute that's being looked for. - /// If the attribute exists, the location of the attribute in the shader; otherwise -1. - public int GetAttribLocation(string attribName) + /// Outputs the location of the attribute in the shader if found; otherwise -1. + /// If the attribute exists, ; otherwise, . + public bool TryGetAttribLocation(string attribName, out int location) { - int location = Window.GL.GetAttribLocation(Handle, attribName); - if (location == -1) + location = Window.GL.GetAttribLocation(Handle, attribName); + if (location == ShaderAttributes.AttributeLocationNotFound) + { Console.WriteLine($"Attribute '{attribName}' not found in shader program."); + return false; + } - return location; + return true; } // Uniform setters diff --git a/Core/Shaders/UIShader.cs b/Core/Shaders/UIShader.cs index 9e049a1..126b2fe 100644 --- a/Core/Shaders/UIShader.cs +++ b/Core/Shaders/UIShader.cs @@ -14,10 +14,9 @@ public UIShader() public override bool SetAttributes() { if (!base.SetAttributes()) - return false; + return false; - var vertexLocation = Shader!.GetAttribLocation(ShaderAttributes.Pos); - if (vertexLocation == ShaderAttributes.AttributeLocationNotFound) + if (!Shader!.TryGetAttribLocation(ShaderAttributes.Pos, out int vertexLocation)) return false; uint vertexLocationUInt = (uint)vertexLocation; diff --git a/Core/SilkWindow.cs b/Core/SilkWindow.cs index 23989da..cbb0cb8 100644 --- a/Core/SilkWindow.cs +++ b/Core/SilkWindow.cs @@ -1,20 +1,24 @@ -using SharpEngine.Core.Enums; -using Silk.NET.Core; +using Silk.NET.Core; using Silk.NET.Core.Contexts; using Silk.NET.Input; using Silk.NET.Maths; using Silk.NET.Windowing; +using MouseButton = Silk.NET.Input.MouseButton; + using StbImageSharp; + using System; using System.IO; using System.Numerics; -using MouseButton = Silk.NET.Input.MouseButton; namespace SharpEngine.Core; /// -/// Represents a class abstraction for the interface. +/// Represents an abstraction for the interface. /// +/// +/// For window initialization, see . +/// public abstract class SilkWindow : IWindow { /// @@ -154,6 +158,9 @@ public string Title /// public event Action? Render; + /// Raised after the scene has been rendered. + public event Action? OnAfterRender; + /// An event executed when the window has loaded. public event Action? OnLoaded; @@ -173,12 +180,25 @@ public IWindow CurrentWindow } /// + // [Obsolete("Use the 'Create' implementation instead.")] public IWindow CreateWindow(WindowOptions opts) { + if (CurrentWindow is not null) + throw new InvalidOperationException("Window already created for this instance."); + CurrentWindow = Silk.NET.Windowing.Window.Create(opts); return CurrentWindow; } + public static T Create(WindowOptions opts) where T : SilkWindow, new() + { + var instance = new T(); + var winndow = instance.CreateWindow(opts); + + instance.CurrentWindow = winndow; + return instance; + } + /// protected virtual void Dispose(bool disposing) { } @@ -260,7 +280,7 @@ public virtual void OnLoad() /// Handles operations needed to be executed after the renderers are finished. /// /// Time since the last frame. - protected virtual void AfterRender(double deltaTime) { } + protected virtual void AfterRender(double deltaTime) => OnAfterRender?.Invoke(deltaTime); /// /// Handles operations needed to be executed before the renderers are executed. diff --git a/Core/Textures/TextureService.cs b/Core/Textures/TextureService.cs index ae0e056..89b4bcf 100644 --- a/Core/Textures/TextureService.cs +++ b/Core/Textures/TextureService.cs @@ -1,4 +1,4 @@ -using StbImageSharp; +using StbImageSharp; using System.IO; using System.Collections.Generic; diff --git a/Core/Window.cs b/Core/Window.cs index 29e9936..a26cfe0 100644 --- a/Core/Window.cs +++ b/Core/Window.cs @@ -1,4 +1,4 @@ -using SharpEngine.Core.Entities.Properties.Meshes; +using SharpEngine.Core.Entities.Properties.Meshes; using SharpEngine.Core.Entities.Views; using SharpEngine.Core.Entities.Views.Settings; using SharpEngine.Core.Enums; @@ -7,23 +7,20 @@ using SharpEngine.Core.Renderers; using SharpEngine.Core.Scenes; using SharpEngine.Core.Shaders; -using Silk.NET.Core; -using Silk.NET.GLFW; +using Shader = SharpEngine.Core.Shaders.Shader; + using Silk.NET.Input; using Silk.NET.Maths; using Silk.NET.OpenGL; using Silk.NET.OpenGL.Extensions.ImGui; using Silk.NET.Windowing; -using StbImageSharp; +using MouseButton = Silk.NET.Input.MouseButton; + using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Numerics; -using System.Runtime.InteropServices; using System.Threading.Tasks; -using MouseButton = Silk.NET.Input.MouseButton; -using Shader = SharpEngine.Core.Shaders.Shader; namespace SharpEngine.Core; @@ -32,7 +29,7 @@ namespace SharpEngine.Core; /// public class Window : SilkWindow { - private readonly ISettings _settings; + private readonly IViewSettings _settings; private readonly CameraView _camera; private bool _initialized; @@ -69,6 +66,7 @@ public class Window : SilkWindow /// The OpenGL context for this window. public static GL GetGL() => GL; private static void SetGL(GL gl) => GL = gl; + public Window() { } /// /// Initializes a new instance of . @@ -81,8 +79,6 @@ public Window(CameraView camera, Scene scene, IViewSettings settings) Scene = scene; _settings = settings; _camera = camera; - - Initialize(settings.WindowOptions); } /// @@ -94,14 +90,14 @@ public Window(Scene scene, IViewSettings settings) { Scene = scene; _settings = settings; - _camera = new(Vector3.One, new DefaultViewSettings()); - - Initialize(settings.WindowOptions); + _camera = new(Vector3.One, settings); } - private void Initialize(WindowOptions options) + private bool _windowInitialized; + + public void Initialize() where T : SilkWindow, new() { - CurrentWindow = CreateWindow(options); + CurrentWindow = SilkWindow.Create(_settings.WindowOptions); CurrentWindow.Update += OnUpdateFrame; CurrentWindow.Render += RenderFrame; CurrentWindow.Resize += OnResize; @@ -112,6 +108,9 @@ private void Initialize(WindowOptions options) /// public override void Run(Action onFrame) { + if (!_windowInitialized) + throw new Exception("Window not been initialized for this instance. Try calling 'window.Initialize()' first."); + try { base.Run(onFrame); diff --git a/Editor/EditorWindow.cs b/Editor/EditorWindow.cs index 92fe757..f5bc365 100644 --- a/Editor/EditorWindow.cs +++ b/Editor/EditorWindow.cs @@ -24,6 +24,8 @@ public class EditorWindow : Window private ContextMenuWindow? _contextMenuWindow; private ActionsMenuWindow? _actionsMenuWindow; + public EditorWindow() { } + /// /// Initializes an editor window with a specified scene and view settings. /// @@ -40,48 +42,55 @@ public override void OnLoad() { base.OnLoad(); - // Test only: remove later. - var cube = PrimitiveFactory.Create(PrimitiveType.Cube, new Vector3(3, 1, 1)); - cube.Name = "test"; - - Scene.Root.Children.Add(cube); - - // Get all types that inherit from ImGuiWindowBase - var windowTypes = Assembly.GetExecutingAssembly() - .GetTypes() - .Where(t => t.IsSubclassOf(typeof(ImGuiWindowBase)) && !t.IsAbstract) - .ToArray(); - - // Initialize all ImGuiWindowBase implementations - for (int i = 0; i < windowTypes.Length; i++) + try { - try - { - var type = windowTypes[i]; - var window = Activator.CreateInstance(type) ?? - throw new InvalidOperationException($"Error initializing window: {type}"); + // Test only: remove later. + var cube = PrimitiveFactory.Create(PrimitiveType.Cube, new Vector3(3, 1, 1)); + cube.Name = "test"; - var windowBase = (ImGuiWindowBase)window; - windowBase.SetScene(Scene); - windowBase.SetProject(_project); + Scene.Root.Children.Add(cube); - _windows.Add(windowBase); - } - catch (Exception e) + // Get all types that inherit from ImGuiWindowBase + var windowTypes = Assembly.GetExecutingAssembly() + .GetTypes() + .Where(t => t.IsSubclassOf(typeof(ImGuiWindowBase)) && !t.IsAbstract) + .ToArray(); + + // Initialize all ImGuiWindowBase implementations + for (int i = 0; i < windowTypes.Length; i++) { - Debug.LogInformation(e.Message, e); + try + { + var type = windowTypes[i]; + var window = Activator.CreateInstance(type) ?? + throw new InvalidOperationException($"Error initializing window: {type}"); + + var windowBase = (ImGuiWindowBase)window; + windowBase.SetScene(Scene); + windowBase.SetProject(_project); + + _windows.Add(windowBase); + } + catch (Exception e) + { + Debug.LogInformation(e.Message, e); + } } - } - _contextMenuWindow = (ContextMenuWindow?)_windows.FirstOrDefault(w => w.GetType() == typeof(ContextMenuWindow)); - if (_contextMenuWindow is null) - Debug.LogInformation("ContextMenuWindow not found."); + _contextMenuWindow = (ContextMenuWindow?)_windows.FirstOrDefault(w => w.GetType() == typeof(ContextMenuWindow)); + if (_contextMenuWindow is null) + Debug.LogInformation("ContextMenuWindow not found."); - _actionsMenuWindow = (ActionsMenuWindow?)_windows.FirstOrDefault(w => w.GetType() == typeof(ActionsMenuWindow)); - if (_actionsMenuWindow is null) - Debug.LogInformation("ActionsMenuWindow not found."); - else - _actionsMenuWindow.OnSceneLoaded += SetScene; + _actionsMenuWindow = (ActionsMenuWindow?)_windows.FirstOrDefault(w => w.GetType() == typeof(ActionsMenuWindow)); + if (_actionsMenuWindow is null) + Debug.LogInformation("ActionsMenuWindow not found."); + else + _actionsMenuWindow.OnSceneLoaded += SetScene; + } + catch (Exception e) + { + Debug.LogInformation(e.Message, e); + } } /// diff --git a/Editor/Windows/ImGuiWindowBase.cs b/Editor/Windows/ImGuiWindowBase.cs index d1579bb..c48c182 100644 --- a/Editor/Windows/ImGuiWindowBase.cs +++ b/Editor/Windows/ImGuiWindowBase.cs @@ -1,7 +1,13 @@ using ImGuiNET; using Launcher.UI; +using SharpEngine.Core.Entities.Views.Settings; using SharpEngine.Core.Scenes; +using Silk.NET.Input; +using Silk.NET.Maths; +using Silk.NET.OpenGL; +using Silk.NET.OpenGL.Extensions.ImGui; using Silk.NET.Windowing; +using System.Threading; namespace SharpEngine.Editor.Windows { @@ -56,14 +62,8 @@ public void RenderWindow() // Check docking state bool isDocked = ImGui.IsWindowDocked(); - if (_previousDockingStates.TryGetValue(Name, out bool wasDocked)) - { - if (wasDocked && !isDocked) - { - // Window was undocked - OnWindowUndocked(); - } - } + if (_previousDockingStates.TryGetValue(Name, out bool wasDocked) && wasDocked && !isDocked) + OnWindowUndocked(); // Update previous docking state _previousDockingStates[Name] = isDocked; @@ -82,20 +82,30 @@ protected virtual void OnWindowUndocked() private void CreateSilkWindow() { - // TODO: Use the Core window. - var window = Window.Create(WindowOptions.Default with + try { - Title = Name - }); + var thread = new Thread(() => + { - window.Load += () => - { - // TODO: Initialize the ImGui context like we do in the Core window. - }; + var window = new Core.Window(new(), new DefaultViewSettings()); - window.Render += delta => Render(); + window.Closing += () => _previousDockingStates[Name] = false; + window.OnAfterRender += deltaTime => + { + ImGui.Begin(Name, ImGuiWindowFlags); + Render(); + ImGui.End(); + }; - window.Run(); + window.Run(); + }); + + thread.Start(); + } + catch (Exception ex) + { + Console.WriteLine($"Failed to create window: {ex.Message}"); + } } /// diff --git a/Examples/MultipleWindows/MultipleWindows.csproj b/Examples/MultipleWindows/MultipleWindows.csproj new file mode 100644 index 0000000..f87a3eb --- /dev/null +++ b/Examples/MultipleWindows/MultipleWindows.csproj @@ -0,0 +1,17 @@ + + + + Exe + net8.0 + enable + enable + true + + + + + + + + + diff --git a/Examples/MultipleWindows/Program.cs b/Examples/MultipleWindows/Program.cs new file mode 100644 index 0000000..73a0908 --- /dev/null +++ b/Examples/MultipleWindows/Program.cs @@ -0,0 +1,45 @@ +using Silk.NET.Core.Native; +using Silk.NET.GLFW; +using Silk.NET.OpenGL; +using Silk.NET.Windowing; + +internal class Program +{ + static void Main() + { + var options1 = WindowOptions.Default with { Title = "Window 1", WindowClass = "MyWindowClass1" }; + var options2 = WindowOptions.Default with { Title = "Window 2", WindowClass = "MyWindowClass2" }; + + var window1 = Window.Create(options1); + var window2 = Window.Create(options2); + + StartWindow(window1); + StartWindow(window2); + } + + static void StartWindow(IWindow window) + { + var thread = new Thread(() => + { + window.Load += () => + { + Console.WriteLine($"Hello from window: " + window.Title); + + var gl = GL.GetApi(window); + + unsafe + { + var versionPtr = gl.GetString(StringName.Version); + string? version = SilkMarshal.PtrToString((nint)versionPtr); + Console.WriteLine($"OpenGL version: {version}"); + } + + }; + + window.Run(); + }); + + thread.SetApartmentState(ApartmentState.STA); + thread.Start(); + } +} diff --git a/SharpEngine.sln b/SharpEngine.sln index 71f591f..8989e1a 100644 --- a/SharpEngine.sln +++ b/SharpEngine.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 -VisualStudioVersion = 17.14.35906.104 d17.14 +VisualStudioVersion = 17.14.35906.104 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpEngine.Core", "Core\SharpEngine.Core.csproj", "{9A1984BA-6D84-374A-8BF0-A26A6493FEA9}" EndProject @@ -24,6 +24,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution README.md = README.md EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MultipleWindows", "Examples\MultipleWindows\MultipleWindows.csproj", "{0AF16D15-5BD2-4FED-9C6A-227DE6A56C5E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -70,6 +72,12 @@ Global {1BEC06D8-094D-8BC2-288E-E2C4C13F3D2E}.LauncherNonWindows|Any CPU.Build.0 = Debug|Any CPU {1BEC06D8-094D-8BC2-288E-E2C4C13F3D2E}.Release|Any CPU.ActiveCfg = Release|Any CPU {1BEC06D8-094D-8BC2-288E-E2C4C13F3D2E}.Release|Any CPU.Build.0 = Release|Any CPU + {0AF16D15-5BD2-4FED-9C6A-227DE6A56C5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0AF16D15-5BD2-4FED-9C6A-227DE6A56C5E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0AF16D15-5BD2-4FED-9C6A-227DE6A56C5E}.LauncherNonWindows|Any CPU.ActiveCfg = Release|Any CPU + {0AF16D15-5BD2-4FED-9C6A-227DE6A56C5E}.LauncherNonWindows|Any CPU.Build.0 = Release|Any CPU + {0AF16D15-5BD2-4FED-9C6A-227DE6A56C5E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0AF16D15-5BD2-4FED-9C6A-227DE6A56C5E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -77,5 +85,6 @@ Global GlobalSection(NestedProjects) = preSolution {E8A75C3B-1D82-8B30-C854-AD35FB123CDC} = {B36A84DF-456D-A817-6EDD-3EC3E7F6E11F} {1BEC06D8-094D-8BC2-288E-E2C4C13F3D2E} = {B36A84DF-456D-A817-6EDD-3EC3E7F6E11F} + {0AF16D15-5BD2-4FED-9C6A-227DE6A56C5E} = {B36A84DF-456D-A817-6EDD-3EC3E7F6E11F} EndGlobalSection EndGlobal From fce8dcfcf51f7bc35029cbb9db9bcf8d70b33aa3 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Mon, 24 Mar 2025 23:55:55 +0200 Subject: [PATCH 02/92] Fix --- Core/Shaders/LightingShader.cs | 2 +- Core/Window.cs | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Core/Shaders/LightingShader.cs b/Core/Shaders/LightingShader.cs index 5ab80f1..8ddd2af 100644 --- a/Core/Shaders/LightingShader.cs +++ b/Core/Shaders/LightingShader.cs @@ -37,7 +37,7 @@ public override bool SetAttributes() Window.GL.EnableVertexAttribArray(normalLocationUint); Window.GL.VertexAttribPointer(normalLocationUint, VertexData.NormalsSize, VertexAttribPointerType.Float, false, VertexData.Stride, VertexData.NormalsOffset); - if (!Shader!.TryGetAttribLocation(ShaderAttributes.Normal, out int texCoordLocation)) + if (!Shader!.TryGetAttribLocation(ShaderAttributes.TexCoords, out int texCoordLocation)) return false; var texCoordLocationUint = (uint)texCoordLocation; diff --git a/Core/Window.cs b/Core/Window.cs index a26cfe0..af4cd49 100644 --- a/Core/Window.cs +++ b/Core/Window.cs @@ -79,6 +79,7 @@ public Window(CameraView camera, Scene scene, IViewSettings settings) Scene = scene; _settings = settings; _camera = camera; + Initialize(); } /// @@ -91,13 +92,15 @@ public Window(Scene scene, IViewSettings settings) Scene = scene; _settings = settings; _camera = new(Vector3.One, settings); + Initialize(); } private bool _windowInitialized; - public void Initialize() where T : SilkWindow, new() + // public void Initialize() where T : SilkWindow, new() + private void Initialize() { - CurrentWindow = SilkWindow.Create(_settings.WindowOptions); + CurrentWindow = CreateWindow(_settings.WindowOptions); CurrentWindow.Update += OnUpdateFrame; CurrentWindow.Render += RenderFrame; CurrentWindow.Resize += OnResize; From 54339fbaffdfd1906d4cfd6c8a8e6d7a2adeae6f Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Tue, 25 Mar 2025 11:35:59 +0200 Subject: [PATCH 03/92] Fix UI element rendering --- Core/Entities/UIElement.cs | 37 +++++++++++++++++++++++------------- Core/Renderers/Renderer.cs | 2 ++ Core/Renderers/UIRenderer.cs | 8 +++++++- Core/SharpEngine.Core.csproj | 1 + 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/Core/Entities/UIElement.cs b/Core/Entities/UIElement.cs index 2ba6372..d7dd921 100644 --- a/Core/Entities/UIElement.cs +++ b/Core/Entities/UIElement.cs @@ -20,7 +20,7 @@ public class UIElement : SceneNode public UIElement(string name) { Name = name; - Mesh = MeshService.Instance.LoadMesh("plane", Primitives.Plane.Mesh); + // Mesh = MeshService.Instance.LoadMesh("plane", Primitives.Plane.Mesh); } private readonly UIShader _uIShader = new(); @@ -33,7 +33,7 @@ public UIElement(string name) // TODO: Use actual mesh /// Gets or sets the mesh of the UI element. - public Mesh Mesh { get; set; } = new(); + public Mesh Mesh { get; set; } // = new(); private readonly float[] _vertices = [ @@ -56,33 +56,44 @@ public UIElement(string name) public void Initialize() { _vertexArrayObject = Window.GL.GenVertexArray(); - Window.GL.BindVertexArray(_vertexArrayObject); + Bind(); InitializeBuffers(); } - private void InitializeBuffers() + public void Bind() + { + Window.GL.BindVertexArray(_vertexArrayObject); + } + + private unsafe void InitializeBuffers() { - var vertexBufferObject = Window.GL.GenBuffer(); - Window.GL.BindBuffer(GLEnum.ArrayBuffer, vertexBufferObject); - Window.GL.BufferData(GLEnum.ArrayBuffer, (uint)_vertices.Length * sizeof(float), _vertices, GLEnum.StaticDraw); + fixed (float* vertexDataPtr = &_vertices[0]) + { + var vertexBufferObject = Window.GL.GenBuffer(); + Window.GL.BindBuffer(GLEnum.ArrayBuffer, vertexBufferObject); + Window.GL.BufferData(GLEnum.ArrayBuffer, (nuint)(_vertices.Length * sizeof(float)), vertexDataPtr, GLEnum.StaticDraw); + } + + fixed (void* indicieDataPtr = &_indices[0]) + { + var elementBufferObject = Window.GL.GenBuffer(); + Window.GL.BindBuffer(GLEnum.ElementArrayBuffer, elementBufferObject); + Window.GL.BufferData(GLEnum.ElementArrayBuffer, (nuint)(_indices.Length * sizeof(uint)), indicieDataPtr, GLEnum.StaticDraw); + } - var elementBufferObject = Window.GL.GenBuffer(); - Window.GL.BindBuffer(GLEnum.ElementArrayBuffer, elementBufferObject); - Window.GL.BufferData(GLEnum.ElementArrayBuffer, (uint)_indices.Length * sizeof(uint), _indices, GLEnum.StaticDraw); } /// /// Render the UI element. /// - public override Task Render() + public unsafe override Task Render() { Window.GL.BindVertexArray(_vertexArrayObject); _uIShader.Shader.SetMatrix4(ShaderAttributes.Model, Transform.ModelMatrix); - uint a = 0; - Window.GL.DrawElements(PrimitiveType.Triangles, (uint)_indices.Length, DrawElementsType.UnsignedInt, ref a); + Window.GL.DrawElements(PrimitiveType.Triangles, (uint)_indices.Length, DrawElementsType.UnsignedInt, null); return Task.CompletedTask; } diff --git a/Core/Renderers/Renderer.cs b/Core/Renderers/Renderer.cs index ae52bed..def92a7 100644 --- a/Core/Renderers/Renderer.cs +++ b/Core/Renderers/Renderer.cs @@ -49,6 +49,8 @@ public Renderer(CameraView camera, ISettings settings, Scene scene) : base(setti /// public override Task Render() { + return Task.CompletedTask; + try { Window.GL.Enable(EnableCap.DepthTest); diff --git a/Core/Renderers/UIRenderer.cs b/Core/Renderers/UIRenderer.cs index 11e2165..6a99c4d 100644 --- a/Core/Renderers/UIRenderer.cs +++ b/Core/Renderers/UIRenderer.cs @@ -41,7 +41,7 @@ public override void Initialize() _uiShader.Shader.Use(); - //_scene.UIElements.Add(new UIElement("uiElement")); + _scene.UIElements.Add(new UIElement("uiElement")); _scene.Iterate(_scene.UIElements, elem => elem.Initialize()); @@ -61,9 +61,15 @@ public override Task Render() Window.GL.Disable(EnableCap.DepthTest); Window.GL.DepthFunc(DepthFunction.Less); + foreach (var item in _scene.UIElements) + { + item.Bind(); + } + _uiShader.Shader.Use(); var uiElementRenderTasks = _scene.IterateAsync(_scene.UIElements, elem => elem.Render()); + return Task.WhenAll(uiElementRenderTasks); } catch (Exception ex) diff --git a/Core/SharpEngine.Core.csproj b/Core/SharpEngine.Core.csproj index e93fd8f..869bade 100644 --- a/Core/SharpEngine.Core.csproj +++ b/Core/SharpEngine.Core.csproj @@ -16,6 +16,7 @@ $(AssemblyName).NET Debug;Release;LauncherNonWindows + true From 8cbc8a4b2d084f59c65414581ff0a325d281570a Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Tue, 25 Mar 2025 11:41:28 +0200 Subject: [PATCH 04/92] Use safe code --- Core/Entities/UIElement.cs | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/Core/Entities/UIElement.cs b/Core/Entities/UIElement.cs index d7dd921..7728510 100644 --- a/Core/Entities/UIElement.cs +++ b/Core/Entities/UIElement.cs @@ -66,22 +66,15 @@ public void Bind() Window.GL.BindVertexArray(_vertexArrayObject); } - private unsafe void InitializeBuffers() + private void InitializeBuffers() { - fixed (float* vertexDataPtr = &_vertices[0]) - { - var vertexBufferObject = Window.GL.GenBuffer(); - Window.GL.BindBuffer(GLEnum.ArrayBuffer, vertexBufferObject); - Window.GL.BufferData(GLEnum.ArrayBuffer, (nuint)(_vertices.Length * sizeof(float)), vertexDataPtr, GLEnum.StaticDraw); - } - - fixed (void* indicieDataPtr = &_indices[0]) - { - var elementBufferObject = Window.GL.GenBuffer(); - Window.GL.BindBuffer(GLEnum.ElementArrayBuffer, elementBufferObject); - Window.GL.BufferData(GLEnum.ElementArrayBuffer, (nuint)(_indices.Length * sizeof(uint)), indicieDataPtr, GLEnum.StaticDraw); - } + var vertexBufferObject = Window.GL.GenBuffer(); + Window.GL.BindBuffer(GLEnum.ArrayBuffer, vertexBufferObject); + Window.GL.BufferData(GLEnum.ArrayBuffer, _vertices, GLEnum.StaticDraw); + var elementBufferObject = Window.GL.GenBuffer(); + Window.GL.BindBuffer(GLEnum.ElementArrayBuffer, elementBufferObject); + Window.GL.BufferData(GLEnum.ElementArrayBuffer, _indices, GLEnum.StaticDraw); } /// From 77e8b05e36755d1d88dc8120f9b9d88bdc8e913b Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Tue, 25 Mar 2025 11:49:05 +0200 Subject: [PATCH 05/92] One more unsafe fix --- Core/Entities/UIElement.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Core/Entities/UIElement.cs b/Core/Entities/UIElement.cs index 7728510..1664569 100644 --- a/Core/Entities/UIElement.cs +++ b/Core/Entities/UIElement.cs @@ -4,6 +4,7 @@ using SharpEngine.Core.Shaders; using Silk.NET.OpenGL; +using System; using System.Threading.Tasks; namespace SharpEngine.Core.Entities; @@ -80,13 +81,13 @@ private void InitializeBuffers() /// /// Render the UI element. /// - public unsafe override Task Render() + public override Task Render() { Window.GL.BindVertexArray(_vertexArrayObject); _uIShader.Shader.SetMatrix4(ShaderAttributes.Model, Transform.ModelMatrix); - Window.GL.DrawElements(PrimitiveType.Triangles, (uint)_indices.Length, DrawElementsType.UnsignedInt, null); + Window.GL.DrawElements(PrimitiveType.Triangles, (uint)_indices.Length, DrawElementsType.UnsignedInt, []); return Task.CompletedTask; } From f543d945271128db494d09abf46a78e3a23af00d Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Tue, 25 Mar 2025 12:00:08 +0200 Subject: [PATCH 06/92] Added error logging --- Core/Renderers/Renderer.cs | 2 -- Core/Renderers/UIRenderer.cs | 2 ++ Core/Shaders/Shader.cs | 49 ++++++++++++++++++++++++++---------- Core/SharpEngine.Core.csproj | 8 +----- 4 files changed, 39 insertions(+), 22 deletions(-) diff --git a/Core/Renderers/Renderer.cs b/Core/Renderers/Renderer.cs index def92a7..ae52bed 100644 --- a/Core/Renderers/Renderer.cs +++ b/Core/Renderers/Renderer.cs @@ -49,8 +49,6 @@ public Renderer(CameraView camera, ISettings settings, Scene scene) : base(setti /// public override Task Render() { - return Task.CompletedTask; - try { Window.GL.Enable(EnableCap.DepthTest); diff --git a/Core/Renderers/UIRenderer.cs b/Core/Renderers/UIRenderer.cs index 6a99c4d..47a6e4c 100644 --- a/Core/Renderers/UIRenderer.cs +++ b/Core/Renderers/UIRenderer.cs @@ -56,6 +56,8 @@ private void InitializeVertexArrays() /// public override Task Render() { + return Task.CompletedTask; + try { Window.GL.Disable(EnableCap.DepthTest); diff --git a/Core/Shaders/Shader.cs b/Core/Shaders/Shader.cs index fb02337..0ae4049 100644 --- a/Core/Shaders/Shader.cs +++ b/Core/Shaders/Shader.cs @@ -31,7 +31,7 @@ public class Shader /// /// The vertex shader full path. /// The fragment shader full path. - /// The identfier name of the shader. + /// The identifier name of the shader. public Shader(string vertPath, string fragPath, string name) { Name = name; @@ -44,10 +44,16 @@ public Shader(string vertPath, string fragPath, string name) // Load and compile shader if (!LoadShader(ShaderType.VertexShader, vertPath, out uint vertexShader)) + { + Console.WriteLine("Unable to load vertex shader."); return; + } if (!LoadShader(ShaderType.FragmentShader, fragPath, out uint fragmentShader)) + { + Console.WriteLine("Unable to load fragment shader."); return; + } // These two shaders must then be merged into a shader program, which can then be used by OpenGL. // To do this, create a program... @@ -59,7 +65,11 @@ public Shader(string vertPath, string fragPath, string name) Window.GL.AttachShader(Handle, fragmentShader); // And then link them together. - LinkProgram(Handle); + if (!LinkProgram(Handle)) + { + Console.WriteLine("Unable to link shader program."); + return; + } // When the shader program is linked, it no longer needs the individual shaders attached to it; the compiled code is copied into the shader program. // Detach them, and then delete them. @@ -91,7 +101,12 @@ private static bool LoadShader(ShaderType shaderType, string shaderPath, out uin // GL.CreateShader will create an empty shader (obviously). The ShaderType enum denotes which type of shader will be created. shader = Window.GL.CreateShader(shaderType); Window.GL.ShaderSource(shader, shaderSource); - CompileShader(shader); + + if (!CompileShader(shader)) + { + Console.WriteLine($"Unable to load {shaderType} shader from '{shaderPath}'."); + return false; + } return true; } @@ -102,7 +117,7 @@ private void GetUniformLocations() Window.GL.GetProgram(Handle, GLEnum.ActiveUniforms, out var numberOfUniforms); // Next, allocate the dictionary to hold the locations. - _uniformLocations = new Dictionary(); + _uniformLocations = []; // Loop over all the uniforms, for (uint i = 0; i < numberOfUniforms; i++) @@ -129,31 +144,39 @@ private static string ProcessIncludes(string shaderCode, string directory) }); } - private static void CompileShader(uint shader) + private static bool CompileShader(uint shader) { // Try to compile the shader Window.GL.CompileShader(shader); // Check for compilation errors - Window.GL.GetShader(shader, GLEnum.CompileStatus, out var code); - if (code != (int)GLEnum.True) + Window.GL.GetShader(shader, GLEnum.CompileStatus, out var statusCode); + if (statusCode != (int)GLEnum.True) { // We can use `GL.GetShaderInfoLog(shader)` to get information about the error. var infoLog = Window.GL.GetShaderInfoLog(shader); - throw new InvalidOperationException($"Error occurred whilst compiling Shader({shader}).\n\n{infoLog}"); + Console.WriteLine($"Error occurred whilst compiling Shader({shader}).\n\n{infoLog}"); + + return false; } + + return true; } - private static void LinkProgram(uint program) + private static bool LinkProgram(uint program) { Window.GL.LinkProgram(program); - - Window.GL.GetProgram(program, GLEnum.LinkStatus, out var code); - if (code != (int)GLEnum.True) + Window.GL.GetProgram(program, GLEnum.LinkStatus, out var statusCode); + + if (statusCode != (int)GLEnum.True) { string infoLog = Window.GL.GetProgramInfoLog(program); - throw new InvalidOperationException($"Error occurred whilst linking Program({program}): {infoLog}"); + Console.WriteLine($"Error occurred whilst linking Program({program}): {infoLog}"); + + return false; } + + return true; } /// diff --git a/Core/SharpEngine.Core.csproj b/Core/SharpEngine.Core.csproj index 869bade..1489ce2 100644 --- a/Core/SharpEngine.Core.csproj +++ b/Core/SharpEngine.Core.csproj @@ -3,10 +3,6 @@ Everything needed to build games using a purely C# game engine. - AnyCPU;x64;x86 $(GenerateNuGetPackages) https://github.com/Av3boy/SharpEngine @@ -15,9 +11,7 @@ $(AssemblyName).NET - Debug;Release;LauncherNonWindows - true - + Debug;Release;LauncherNonWindows From 9b3a3981a2ae6eb5f5013ad47decee94012d5ae5 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Tue, 25 Mar 2025 20:40:30 +0200 Subject: [PATCH 07/92] Basic OpenAL implementation --- Core/Audio/Audio.cs | 28 +++ Core/Audio/AudioBuffer.cs | 43 ++++ Core/Audio/AudioDevice.cs | 46 +++++ Core/Audio/AudioPlayerBase.cs | 67 ++++++ Core/Audio/AudioProperties.cs | 36 ++++ Core/Audio/AudioSource.cs | 47 +++++ Core/Audio/WavData.cs | 22 ++ Core/Audio/WavPlayer.cs | 115 +++++++++++ Core/SharpEngine.Core.csproj | 21 +- Core/SilkWindow.cs | 16 +- Editor/Windows/ActionsMenuWindow.cs | 23 ++- Examples/AudioPlayer/AudioPlayer.csproj | 15 ++ Examples/AudioPlayer/Program.cs | 190 ++++++++++++++++++ .../Properties/launchSettings.json | 8 + SharpEngine.sln | 9 + 15 files changed, 668 insertions(+), 18 deletions(-) create mode 100644 Core/Audio/Audio.cs create mode 100644 Core/Audio/AudioBuffer.cs create mode 100644 Core/Audio/AudioDevice.cs create mode 100644 Core/Audio/AudioPlayerBase.cs create mode 100644 Core/Audio/AudioProperties.cs create mode 100644 Core/Audio/AudioSource.cs create mode 100644 Core/Audio/WavData.cs create mode 100644 Core/Audio/WavPlayer.cs create mode 100644 Examples/AudioPlayer/AudioPlayer.csproj create mode 100644 Examples/AudioPlayer/Program.cs create mode 100644 Examples/AudioPlayer/Properties/launchSettings.json diff --git a/Core/Audio/Audio.cs b/Core/Audio/Audio.cs new file mode 100644 index 0000000..7d9d171 --- /dev/null +++ b/Core/Audio/Audio.cs @@ -0,0 +1,28 @@ +using System; +using System.IO; + +namespace SharpEngine.Core.Audio; + +/// +/// Handles Audio related operations. +/// +public static class Audio +{ + /// + /// Plays an audio file if it is in the WAV format. + /// + /// Specifies the location of the audio file to be played. + /// Thrown when the file format is not supported, such as when it is not a WAV file. + public static void Play(string filePath) + { + switch (Path.GetExtension(filePath)) + { + case ".wav": + new WavPlayer().Play(filePath); + break; + + default: + throw new NotSupportedException("Unsupported file format."); + } + } +} diff --git a/Core/Audio/AudioBuffer.cs b/Core/Audio/AudioBuffer.cs new file mode 100644 index 0000000..506f426 --- /dev/null +++ b/Core/Audio/AudioBuffer.cs @@ -0,0 +1,43 @@ +using Silk.NET.OpenAL; +using System; + +namespace SharpEngine.Core.Audio; + +/// +/// Represents an audio buffer with a unique identifier. +/// +public class AudioBuffer +{ + /// Gets the identifier to the audio buffer. + public uint BufferId => _buffer; + + private readonly uint _buffer; + private readonly AL _al; + + /// + /// Initializes a new instance of . + /// + /// The OpenAL API context. + public AudioBuffer(AL al) + { + _al = al; + _buffer = _al.GenBuffer(); + } + + /// + /// Loads the given into the buffer. + /// + /// The data to be loaded into the buffer. + /// Details about the data. + public void LoadData(ReadOnlySpan data, WavData wavData) + { + unsafe + { + fixed (byte* pData = data) + { + _al.BufferData(_buffer, wavData.Format, pData, data.Length, wavData.SampleRate); + } + } + } + +} \ No newline at end of file diff --git a/Core/Audio/AudioDevice.cs b/Core/Audio/AudioDevice.cs new file mode 100644 index 0000000..aa0560d --- /dev/null +++ b/Core/Audio/AudioDevice.cs @@ -0,0 +1,46 @@ +using Silk.NET.OpenAL; +using System; + +namespace SharpEngine.Core.Audio; + +/// +/// Manages an audio device and its context for audio operations. +/// +public unsafe class AudioDevice : IDisposable +{ + /// Gets the OpenAL context. + public AL Al { get; } + + private readonly ALContext _alc; + private readonly Device* _device; + private readonly Context* _context; + + /// + /// Initializes a new instance of . + /// + /// Thrown when unable to create the audio device. + public AudioDevice() + { + _alc = ALContext.GetApi(); + Al = AL.GetApi(); + _device = _alc.OpenDevice(""); + + if (_device == null) + throw new InvalidOperationException("Could not create device."); + + _context = _alc.CreateContext(_device, null); + _alc.MakeContextCurrent(_context); + Al.GetError(); + } + + /// + public void Dispose() + { + _alc.DestroyContext(_context); + _alc.CloseDevice(_device); + Al.Dispose(); + _alc.Dispose(); + + GC.SuppressFinalize(this); + } +} diff --git a/Core/Audio/AudioPlayerBase.cs b/Core/Audio/AudioPlayerBase.cs new file mode 100644 index 0000000..5778672 --- /dev/null +++ b/Core/Audio/AudioPlayerBase.cs @@ -0,0 +1,67 @@ +using SharpEngine.Core.Scenes; + +using System; +using System.IO; + +namespace SharpEngine.Core.Audio; + +/// +/// Represents a base class for all audio players. +/// +public abstract class AudioPlayerBase : SceneNode +{ + /// Gets the extension accepted by the audio player. + protected abstract string FileExtension { get; } + + /// Gets or sets the properties for the player. + public AudioProperties AudioProperties { get; set; } + + /// Contains the audio data of the media file. + protected readonly WavData Data; + + /// Represents a container for the . + protected readonly AudioBuffer AudioBuffer; + + /// The source of the audio. + protected readonly AudioSource AudioSource; + + /// + /// Initializes a new instance of . + /// + protected AudioPlayerBase() + { + Data = new WavData(); + + var audioDevice = new AudioDevice(); + AudioBuffer = new AudioBuffer(audioDevice.Al); + AudioSource = new AudioSource(audioDevice.Al); + + AudioProperties = new AudioProperties(audioDevice.Al, AudioSource); + } + + /// + /// Plays a media file specified by the given path. + /// + /// The location of the media file to be played. + public abstract void Play(string filePath); + + /// + /// Validates the specified file by checking its extension and existence. + /// + /// The path to the file that needs to be validated for its type and existence. + /// Thrown when the file does not have the allowed extension. + /// Thrown when the specified file does not exist in the file system. + protected virtual void ValidateFile(string filePath) + { + if (Path.GetExtension(filePath) != FileExtension) + throw new ArgumentException($"Given file is not a {FileExtension} file", nameof(filePath)); + + if (!File.Exists(filePath)) + throw new FileNotFoundException("Given file does not exist", filePath); + } + + /// + /// Stops the audio playback of the associated AudioSource. + /// + public virtual void Stop() => AudioSource.Stop(); +} diff --git a/Core/Audio/AudioProperties.cs b/Core/Audio/AudioProperties.cs new file mode 100644 index 0000000..8a57383 --- /dev/null +++ b/Core/Audio/AudioProperties.cs @@ -0,0 +1,36 @@ +using Silk.NET.OpenAL; + +namespace SharpEngine.Core.Audio; + +/// +/// Contains properties used to control how the audio should be played. +/// +public class AudioProperties +{ + private readonly AL _al; + private readonly uint _audioSourceId; + + /// + /// Initializes a new instance of . + /// + /// The context where the audio should be played. + /// The source at which the audio should be played. + public AudioProperties(AL al, AudioSource audioSource) + { + _al = al; + _audioSourceId = audioSource.Get(); + } + + /// Gets or sets whether the audio should be looping. + public bool IsLooping + { + get => _isLooping; + set + { + _isLooping = value; + _al.SetSourceProperty(_audioSourceId, SourceBoolean.Looping, value); + } + } + + private bool _isLooping; +} diff --git a/Core/Audio/AudioSource.cs b/Core/Audio/AudioSource.cs new file mode 100644 index 0000000..9e59179 --- /dev/null +++ b/Core/Audio/AudioSource.cs @@ -0,0 +1,47 @@ +using Silk.NET.OpenAL; + +namespace SharpEngine.Core.Audio; + +/// +/// Represents a source for audio +/// +public class AudioSource +{ + private readonly uint _source; + private readonly AL _al; + + /// + /// Initializes a new instance of . + /// + /// An accessor to the OpenAL context. + public AudioSource(AL al) + { + _al = al; + _source = _al.GenSource(); + } + + /// + /// Gets the source identifier. + /// + /// The identifier to the source. + public uint Get() => _source; + + /// + /// Plays the given audio from the . + /// + /// A buffer containing the audio data. + public void Play(AudioBuffer buffer) + { + _al.SetSourceProperty(_source, SourceInteger.Buffer, buffer.BufferId); + _al.SourcePlay(_source); + } + + /// + /// Stops playing the audio. + /// + public void Stop() + { + _al.SourceStop(_source); + _al.DeleteSource(_source); + } +} \ No newline at end of file diff --git a/Core/Audio/WavData.cs b/Core/Audio/WavData.cs new file mode 100644 index 0000000..80ac937 --- /dev/null +++ b/Core/Audio/WavData.cs @@ -0,0 +1,22 @@ +using Silk.NET.OpenAL; + +namespace SharpEngine.Core.Audio; + +/// +/// Represents audio data in WAV format. +/// +public class WavData +{ + /// Gets or sets the number of channels used in the data. + public short NumChannels { get; set; } + + /// Gets or sets the sample rate of the data. + public int SampleRate { get; set; } + + /// Gets or sets the number of bits per sample. + public short BitsPerSample { get; set; } + + /// Gets or sets the format of the buffer. + /// Defines how data is organized in the buffer. + public BufferFormat Format { get; set; } +} \ No newline at end of file diff --git a/Core/Audio/WavPlayer.cs b/Core/Audio/WavPlayer.cs new file mode 100644 index 0000000..02f9ed7 --- /dev/null +++ b/Core/Audio/WavPlayer.cs @@ -0,0 +1,115 @@ +using Silk.NET.OpenAL; + +using System; +using System.Buffers.Binary; +using System.IO; + +namespace SharpEngine.Core.Audio; + +/// +/// Represents a player for .wav files. +/// +public class WavPlayer : AudioPlayerBase +{ + /// + protected override string FileExtension => ".wav"; + + private static class WavConstants + { + public static ReadOnlySpan RiffHeader => "RIFF"u8; + public static ReadOnlySpan WaveHeader => "WAVE"u8; + public static ReadOnlySpan FmtHeader => "fmt "u8; + public static ReadOnlySpan DataHeader => "data"u8; + + public const int ChunkSizeLength = 4; + public const int HeaderLength = 4; + public const int FormatChunkSkipLength = 6; + public const int AudioFormatLength = 2; + public const int NumChannelsLength = 2; + public const int SampleRateLength = 4; + public const int BitsPerSampleLength = 2; + } + + /// + public override void Play(string filePath) + { + ValidateFile(filePath); + + ReadOnlySpan file = File.ReadAllBytes(filePath); + int index = 0; + + if (!CheckHeader(file, ref index, WavConstants.RiffHeader)) + { + Console.WriteLine("Given file is not in RIFF format"); + return; + } + + index += WavConstants.ChunkSizeLength; // Skip chunk size + + if (!CheckHeader(file, ref index, WavConstants.WaveHeader)) + { + Console.WriteLine("Given file is not in WAVE format"); + return; + } + + while (index + WavConstants.HeaderLength <= file.Length) + { + var identifier = file.Slice(index, WavConstants.HeaderLength); + index += WavConstants.HeaderLength; + + var size = BinaryPrimitives.ReadInt32LittleEndian(file.Slice(index, WavConstants.ChunkSizeLength)); + index += WavConstants.ChunkSizeLength; + + var data = file.Slice(index, size); + switch (identifier) + { + case var id when id.SequenceEqual(WavConstants.FmtHeader): + ParseFormat(data, Data); + break; + + case var id when id.SequenceEqual(WavConstants.DataHeader): + AudioBuffer.LoadData(data, Data); + break; + } + + index += size; + } + + AudioSource.Play(AudioBuffer); + } + + private static bool CheckHeader(ReadOnlySpan file, ref int index, ReadOnlySpan header) + { + if (!file.Slice(index, header.Length).SequenceEqual(header)) + return false; + + index += header.Length; + return true; + } + + private static void ParseFormat(ReadOnlySpan formatChunk, WavData wavData) + { + int index = 0; + var audioFormat = BinaryPrimitives.ReadInt16LittleEndian(formatChunk.Slice(index, WavConstants.AudioFormatLength)); + index += WavConstants.AudioFormatLength; + + if (audioFormat != 1) + throw new InvalidOperationException($"Unknown Audio Format with ID {audioFormat}"); + + wavData.NumChannels = BinaryPrimitives.ReadInt16LittleEndian(formatChunk.Slice(index, WavConstants.NumChannelsLength)); + index += WavConstants.NumChannelsLength; + + wavData.SampleRate = BinaryPrimitives.ReadInt32LittleEndian(formatChunk.Slice(index, WavConstants.SampleRateLength)); + index += WavConstants.SampleRateLength; + + index += WavConstants.FormatChunkSkipLength; // Skip byteRate and blockAlign + wavData.BitsPerSample = BinaryPrimitives.ReadInt16LittleEndian(formatChunk.Slice(index, WavConstants.BitsPerSampleLength)); + + wavData.Format = wavData.NumChannels switch + { + 1 => wavData.BitsPerSample == 8 ? BufferFormat.Mono8 : BufferFormat.Mono16, + 2 => wavData.BitsPerSample == 8 ? BufferFormat.Stereo8 : BufferFormat.Stereo16, + _ => throw new InvalidOperationException($"Can't play audio with {wavData.NumChannels} channels") + }; + } +} diff --git a/Core/SharpEngine.Core.csproj b/Core/SharpEngine.Core.csproj index 1489ce2..5ec1e72 100644 --- a/Core/SharpEngine.Core.csproj +++ b/Core/SharpEngine.Core.csproj @@ -1,4 +1,4 @@ - + Everything needed to build games using a purely C# game engine. @@ -11,18 +11,23 @@ $(AssemblyName).NET - Debug;Release;LauncherNonWindows + Debug;Release;LauncherNonWindows + true + + + + 2.22.0 - - - - - - + + + + + + diff --git a/Core/SilkWindow.cs b/Core/SilkWindow.cs index cbb0cb8..bcc1936 100644 --- a/Core/SilkWindow.cs +++ b/Core/SilkWindow.cs @@ -190,14 +190,14 @@ public IWindow CreateWindow(WindowOptions opts) return CurrentWindow; } - public static T Create(WindowOptions opts) where T : SilkWindow, new() - { - var instance = new T(); - var winndow = instance.CreateWindow(opts); - - instance.CurrentWindow = winndow; - return instance; - } + // public static T Create(WindowOptions opts) where T : SilkWindow, new() + // { + // var instance = new T(); + // var winndow = instance.CreateWindow(opts); + // + // instance.CurrentWindow = winndow; + // return instance; + // } /// protected virtual void Dispose(bool disposing) { } diff --git a/Editor/Windows/ActionsMenuWindow.cs b/Editor/Windows/ActionsMenuWindow.cs index 7fb73bd..af5e223 100644 --- a/Editor/Windows/ActionsMenuWindow.cs +++ b/Editor/Windows/ActionsMenuWindow.cs @@ -1,6 +1,7 @@ using ImGuiNET; using Launcher.UI; using SharpEngine.Core; +using SharpEngine.Core.Audio; using SharpEngine.Core.Scenes; using SharpEngine.Shared; @@ -22,8 +23,6 @@ public class ActionsMenuWindow : ImGuiWindowBase /// public override void Render() { - ImGui.Text("some text"); - if (ImGui.Button("Save")) SaveScene(Scene); @@ -32,6 +31,26 @@ public override void Render() if (ImGui.Button("Play")) StartGame(); + + if (ImGui.Button("Test audio")) + PlayTestAudio(); + } + + private void PlayTestAudio() + { + try + { + string filePath = ""; // TODO: Replace with absolute path to .wav file. + + var audioPlayer = new WavPlayer(); + audioPlayer.AudioProperties.IsLooping = false; + + audioPlayer.Play(filePath); + } + catch (Exception ex) + { + Debug.LogInformation($"Error during audio playback: {ex.Message}"); + } } private void StartGame() diff --git a/Examples/AudioPlayer/AudioPlayer.csproj b/Examples/AudioPlayer/AudioPlayer.csproj new file mode 100644 index 0000000..36f9cff --- /dev/null +++ b/Examples/AudioPlayer/AudioPlayer.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + enable + enable + true + + + + + + + diff --git a/Examples/AudioPlayer/Program.cs b/Examples/AudioPlayer/Program.cs new file mode 100644 index 0000000..7b92084 --- /dev/null +++ b/Examples/AudioPlayer/Program.cs @@ -0,0 +1,190 @@ +using System; +using System.Buffers.Binary; +using System.IO; +using System.Text; +using Silk.NET.OpenAL; + +namespace WavePlayer +{ + class Program + { + static void Main(string[] args) + { + if (args.Length != 1) + { + Console.WriteLine("Exactly one argument should be given: the path to the .wav file that should be played."); + return; + } + + var filePath = args[0]; + var audioPlayer = new AudioPlayer(); + audioPlayer.Play(filePath); + } + } + + public class AudioPlayer + { + public void Play(string filePath) + { + ReadOnlySpan file = File.ReadAllBytes(filePath); + int index = 0; + if (file[index++] != 'R' || file[index++] != 'I' || file[index++] != 'F' || file[index++] != 'F') + { + Console.WriteLine("Given file is not in RIFF format"); + return; + } + + var chunkSize = BinaryPrimitives.ReadInt32LittleEndian(file.Slice(index, 4)); + index += 4; + + if (file[index++] != 'W' || file[index++] != 'A' || file[index++] != 'V' || file[index++] != 'E') + { + Console.WriteLine("Given file is not in WAVE format"); + return; + } + + var wavData = new WavData(); + var audioDevice = new AudioDevice(); + var audioBuffer = new AudioBuffer(audioDevice.Al); + var audioSource = new AudioSource(audioDevice.Al); + + while (index + 4 < file.Length) + { + var identifier = "" + (char)file[index++] + (char)file[index++] + (char)file[index++] + (char)file[index++]; + var size = BinaryPrimitives.ReadInt32LittleEndian(file.Slice(index, 4)); + index += 4; + if (identifier == "fmt ") + { + wavData.ParseFormat(file.Slice(index, size)); + index += size; + } + else if (identifier == "data") + { + var data = file.Slice(index, size); + index += size; + audioBuffer.LoadData(data, wavData); + } + else + { + index += size; + } + } + + audioSource.Play(audioBuffer); + Console.WriteLine("Press Enter to Exit..."); + Console.ReadLine(); + audioSource.Stop(); + } + } + + public class WavData + { + public short NumChannels { get; private set; } + public int SampleRate { get; private set; } + public short BitsPerSample { get; private set; } + public BufferFormat Format { get; private set; } + + public void ParseFormat(ReadOnlySpan formatChunk) + { + int index = 0; + var audioFormat = BinaryPrimitives.ReadInt16LittleEndian(formatChunk.Slice(index, 2)); + index += 2; + if (audioFormat != 1) + { + throw new InvalidOperationException($"Unknown Audio Format with ID {audioFormat}"); + } + + NumChannels = BinaryPrimitives.ReadInt16LittleEndian(formatChunk.Slice(index, 2)); + index += 2; + SampleRate = BinaryPrimitives.ReadInt32LittleEndian(formatChunk.Slice(index, 4)); + index += 4; + index += 6; // Skip byteRate and blockAlign + BitsPerSample = BinaryPrimitives.ReadInt16LittleEndian(formatChunk.Slice(index, 2)); + index += 2; + + Format = NumChannels switch + { + 1 => BitsPerSample == 8 ? BufferFormat.Mono8 : BufferFormat.Mono16, + 2 => BitsPerSample == 8 ? BufferFormat.Stereo8 : BufferFormat.Stereo16, + _ => throw new InvalidOperationException($"Can't play audio with {NumChannels} channels") + }; + } + } + + public unsafe class AudioDevice : IDisposable + { + public AL Al { get; } + private readonly ALContext _alc; + private readonly Device* _device; + private readonly Context* _context; + + public AudioDevice() + { + _alc = ALContext.GetApi(); + Al = AL.GetApi(); + _device = _alc.OpenDevice(""); + if (_device == null) + { + throw new InvalidOperationException("Could not create device"); + } + + _context = _alc.CreateContext(_device, null); + _alc.MakeContextCurrent(_context); + Al.GetError(); + } + + public void Dispose() + { + _alc.DestroyContext(_context); + _alc.CloseDevice(_device); + Al.Dispose(); + _alc.Dispose(); + } + } + + public class AudioBuffer + { + private readonly uint _buffer; + + public AudioBuffer(AL al) + { + _buffer = al.GenBuffer(); + } + + public void LoadData(ReadOnlySpan data, WavData wavData) + { + unsafe + { + fixed (byte* pData = data) + { + AL.GetApi().BufferData(_buffer, wavData.Format, pData, data.Length, wavData.SampleRate); + } + } + } + + public uint BufferId => _buffer; + } + + public class AudioSource + { + private readonly uint _source; + + public AudioSource(AL al) + { + _source = al.GenSource(); + al.SetSourceProperty(_source, SourceBoolean.Looping, true); + } + + public void Play(AudioBuffer buffer) + { + AL.GetApi().SetSourceProperty(_source, SourceInteger.Buffer, buffer.BufferId); + AL.GetApi().SourcePlay(_source); + } + + public void Stop() + { + AL.GetApi().SourceStop(_source); + AL.GetApi().DeleteSource(_source); + } + } +} diff --git a/Examples/AudioPlayer/Properties/launchSettings.json b/Examples/AudioPlayer/Properties/launchSettings.json new file mode 100644 index 0000000..f2b2301 --- /dev/null +++ b/Examples/AudioPlayer/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "AudioPlayer": { + "commandName": "Project", + "commandLineArgs": "\"F:\\downloads\\What is Love ( Meme Sound Effect ) #EP14.wav\"" + } + } +} \ No newline at end of file diff --git a/SharpEngine.sln b/SharpEngine.sln index 8989e1a..f61170a 100644 --- a/SharpEngine.sln +++ b/SharpEngine.sln @@ -26,6 +26,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MultipleWindows", "Examples\MultipleWindows\MultipleWindows.csproj", "{0AF16D15-5BD2-4FED-9C6A-227DE6A56C5E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AudioPlayer", "Examples\AudioPlayer\AudioPlayer.csproj", "{BE62A8C9-E83E-4D68-B3BC-BE8099BD66A2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -78,6 +80,12 @@ Global {0AF16D15-5BD2-4FED-9C6A-227DE6A56C5E}.LauncherNonWindows|Any CPU.Build.0 = Release|Any CPU {0AF16D15-5BD2-4FED-9C6A-227DE6A56C5E}.Release|Any CPU.ActiveCfg = Release|Any CPU {0AF16D15-5BD2-4FED-9C6A-227DE6A56C5E}.Release|Any CPU.Build.0 = Release|Any CPU + {BE62A8C9-E83E-4D68-B3BC-BE8099BD66A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BE62A8C9-E83E-4D68-B3BC-BE8099BD66A2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BE62A8C9-E83E-4D68-B3BC-BE8099BD66A2}.LauncherNonWindows|Any CPU.ActiveCfg = Release|Any CPU + {BE62A8C9-E83E-4D68-B3BC-BE8099BD66A2}.LauncherNonWindows|Any CPU.Build.0 = Release|Any CPU + {BE62A8C9-E83E-4D68-B3BC-BE8099BD66A2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BE62A8C9-E83E-4D68-B3BC-BE8099BD66A2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -86,5 +94,6 @@ Global {E8A75C3B-1D82-8B30-C854-AD35FB123CDC} = {B36A84DF-456D-A817-6EDD-3EC3E7F6E11F} {1BEC06D8-094D-8BC2-288E-E2C4C13F3D2E} = {B36A84DF-456D-A817-6EDD-3EC3E7F6E11F} {0AF16D15-5BD2-4FED-9C6A-227DE6A56C5E} = {B36A84DF-456D-A817-6EDD-3EC3E7F6E11F} + {BE62A8C9-E83E-4D68-B3BC-BE8099BD66A2} = {B36A84DF-456D-A817-6EDD-3EC3E7F6E11F} EndGlobalSection EndGlobal From ae376e56665d4ccbed7a797ef009e9f415386bb3 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Tue, 25 Mar 2025 20:41:21 +0200 Subject: [PATCH 08/92] #16 Remove unnecessary tester project --- Examples/AudioPlayer/AudioPlayer.csproj | 15 -- Examples/AudioPlayer/Program.cs | 190 ------------------ .../Properties/launchSettings.json | 8 - 3 files changed, 213 deletions(-) delete mode 100644 Examples/AudioPlayer/AudioPlayer.csproj delete mode 100644 Examples/AudioPlayer/Program.cs delete mode 100644 Examples/AudioPlayer/Properties/launchSettings.json diff --git a/Examples/AudioPlayer/AudioPlayer.csproj b/Examples/AudioPlayer/AudioPlayer.csproj deleted file mode 100644 index 36f9cff..0000000 --- a/Examples/AudioPlayer/AudioPlayer.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - Exe - net8.0 - enable - enable - true - - - - - - - diff --git a/Examples/AudioPlayer/Program.cs b/Examples/AudioPlayer/Program.cs deleted file mode 100644 index 7b92084..0000000 --- a/Examples/AudioPlayer/Program.cs +++ /dev/null @@ -1,190 +0,0 @@ -using System; -using System.Buffers.Binary; -using System.IO; -using System.Text; -using Silk.NET.OpenAL; - -namespace WavePlayer -{ - class Program - { - static void Main(string[] args) - { - if (args.Length != 1) - { - Console.WriteLine("Exactly one argument should be given: the path to the .wav file that should be played."); - return; - } - - var filePath = args[0]; - var audioPlayer = new AudioPlayer(); - audioPlayer.Play(filePath); - } - } - - public class AudioPlayer - { - public void Play(string filePath) - { - ReadOnlySpan file = File.ReadAllBytes(filePath); - int index = 0; - if (file[index++] != 'R' || file[index++] != 'I' || file[index++] != 'F' || file[index++] != 'F') - { - Console.WriteLine("Given file is not in RIFF format"); - return; - } - - var chunkSize = BinaryPrimitives.ReadInt32LittleEndian(file.Slice(index, 4)); - index += 4; - - if (file[index++] != 'W' || file[index++] != 'A' || file[index++] != 'V' || file[index++] != 'E') - { - Console.WriteLine("Given file is not in WAVE format"); - return; - } - - var wavData = new WavData(); - var audioDevice = new AudioDevice(); - var audioBuffer = new AudioBuffer(audioDevice.Al); - var audioSource = new AudioSource(audioDevice.Al); - - while (index + 4 < file.Length) - { - var identifier = "" + (char)file[index++] + (char)file[index++] + (char)file[index++] + (char)file[index++]; - var size = BinaryPrimitives.ReadInt32LittleEndian(file.Slice(index, 4)); - index += 4; - if (identifier == "fmt ") - { - wavData.ParseFormat(file.Slice(index, size)); - index += size; - } - else if (identifier == "data") - { - var data = file.Slice(index, size); - index += size; - audioBuffer.LoadData(data, wavData); - } - else - { - index += size; - } - } - - audioSource.Play(audioBuffer); - Console.WriteLine("Press Enter to Exit..."); - Console.ReadLine(); - audioSource.Stop(); - } - } - - public class WavData - { - public short NumChannels { get; private set; } - public int SampleRate { get; private set; } - public short BitsPerSample { get; private set; } - public BufferFormat Format { get; private set; } - - public void ParseFormat(ReadOnlySpan formatChunk) - { - int index = 0; - var audioFormat = BinaryPrimitives.ReadInt16LittleEndian(formatChunk.Slice(index, 2)); - index += 2; - if (audioFormat != 1) - { - throw new InvalidOperationException($"Unknown Audio Format with ID {audioFormat}"); - } - - NumChannels = BinaryPrimitives.ReadInt16LittleEndian(formatChunk.Slice(index, 2)); - index += 2; - SampleRate = BinaryPrimitives.ReadInt32LittleEndian(formatChunk.Slice(index, 4)); - index += 4; - index += 6; // Skip byteRate and blockAlign - BitsPerSample = BinaryPrimitives.ReadInt16LittleEndian(formatChunk.Slice(index, 2)); - index += 2; - - Format = NumChannels switch - { - 1 => BitsPerSample == 8 ? BufferFormat.Mono8 : BufferFormat.Mono16, - 2 => BitsPerSample == 8 ? BufferFormat.Stereo8 : BufferFormat.Stereo16, - _ => throw new InvalidOperationException($"Can't play audio with {NumChannels} channels") - }; - } - } - - public unsafe class AudioDevice : IDisposable - { - public AL Al { get; } - private readonly ALContext _alc; - private readonly Device* _device; - private readonly Context* _context; - - public AudioDevice() - { - _alc = ALContext.GetApi(); - Al = AL.GetApi(); - _device = _alc.OpenDevice(""); - if (_device == null) - { - throw new InvalidOperationException("Could not create device"); - } - - _context = _alc.CreateContext(_device, null); - _alc.MakeContextCurrent(_context); - Al.GetError(); - } - - public void Dispose() - { - _alc.DestroyContext(_context); - _alc.CloseDevice(_device); - Al.Dispose(); - _alc.Dispose(); - } - } - - public class AudioBuffer - { - private readonly uint _buffer; - - public AudioBuffer(AL al) - { - _buffer = al.GenBuffer(); - } - - public void LoadData(ReadOnlySpan data, WavData wavData) - { - unsafe - { - fixed (byte* pData = data) - { - AL.GetApi().BufferData(_buffer, wavData.Format, pData, data.Length, wavData.SampleRate); - } - } - } - - public uint BufferId => _buffer; - } - - public class AudioSource - { - private readonly uint _source; - - public AudioSource(AL al) - { - _source = al.GenSource(); - al.SetSourceProperty(_source, SourceBoolean.Looping, true); - } - - public void Play(AudioBuffer buffer) - { - AL.GetApi().SetSourceProperty(_source, SourceInteger.Buffer, buffer.BufferId); - AL.GetApi().SourcePlay(_source); - } - - public void Stop() - { - AL.GetApi().SourceStop(_source); - AL.GetApi().DeleteSource(_source); - } - } -} diff --git a/Examples/AudioPlayer/Properties/launchSettings.json b/Examples/AudioPlayer/Properties/launchSettings.json deleted file mode 100644 index f2b2301..0000000 --- a/Examples/AudioPlayer/Properties/launchSettings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "profiles": { - "AudioPlayer": { - "commandName": "Project", - "commandLineArgs": "\"F:\\downloads\\What is Love ( Meme Sound Effect ) #EP14.wav\"" - } - } -} \ No newline at end of file From 09da0a2d26c1b5e69c38c56703f7a64dc468a0ea Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Wed, 26 Mar 2025 00:00:37 +0200 Subject: [PATCH 09/92] #26 Editor enhancements --- Core/Audio/AudioFileExtensions.cs | 16 ++++++ Core/Entities/Views/CameraView.cs | 14 ----- .../Views/Settings/DefaultViewSettings.cs | 10 +++- Core/Entities/Views/Settings/ViewSettings.cs | 11 +++- Core/Entities/Views/View.cs | 31 ++++++++++ Core/Interfaces/ISettings.cs | 10 ++++ Core/Ray.cs | 16 ++---- Core/Window.cs | 32 ++++++----- Editor/EditorSettings.cs | 7 +++ Editor/EditorWindow.cs | 35 ++++++++++-- Editor/Windows/ContextMenuWindow.cs | 56 ++++++++++++++----- Editor/Windows/ImGuiWindowBase.cs | 5 ++ Editor/Windows/PropertiesWindow.cs | 26 ++++----- Editor/Windows/SceneWindow.cs | 1 - Examples/MinecraftClone/Minecraft.cs | 16 +----- Examples/MultipleWindows/Program.cs | 28 ++++------ SharpEngine.sln | 12 +--- 17 files changed, 207 insertions(+), 119 deletions(-) create mode 100644 Core/Audio/AudioFileExtensions.cs diff --git a/Core/Audio/AudioFileExtensions.cs b/Core/Audio/AudioFileExtensions.cs new file mode 100644 index 0000000..93160e2 --- /dev/null +++ b/Core/Audio/AudioFileExtensions.cs @@ -0,0 +1,16 @@ +namespace SharpEngine.Core.Audio; + +/// +/// Contains all the supported audio file extensions. +/// +public static class AudioFileExtensions +{ + /// The file extension of the Waveform audio file. + public const string WavExtension = ".wav"; + + /// The file extension of the MPEG-1 Audio Layer III or MPEG-2 Audio Layer III (MP3) file. + public const string Mp3Extension = ".mp3"; + + /// The file extension of the MPEG-4 (MP4) file. + public const string Mp4Extension = ".mp4"; +} diff --git a/Core/Entities/Views/CameraView.cs b/Core/Entities/Views/CameraView.cs index f3eb785..69af67c 100644 --- a/Core/Entities/Views/CameraView.cs +++ b/Core/Entities/Views/CameraView.cs @@ -24,20 +24,6 @@ public CameraView(Vector3 position, IViewSettings settings) : base(settings) AspectRatio = settings.WindowOptions.Size.X / (float)settings.WindowOptions.Size.Y; } - // Those vectors are directions pointing outwards from the camera to define how it rotated. - private Vector3 _front = -Vector3.UnitZ; - private Vector3 _up = Vector3.UnitY; - private Vector3 _right = Vector3.UnitX; - - /// Gets the front vector of the camera. - public Vector3 Front => _front; - - /// Gets the up vector of the camera. - public Vector3 Up => _up; - - /// Gets the right vector of the camera. - public Vector3 Right => _right; - // Rotation around the X axis (radians) private float _pitch; diff --git a/Core/Entities/Views/Settings/DefaultViewSettings.cs b/Core/Entities/Views/Settings/DefaultViewSettings.cs index 5a777e1..cef7852 100644 --- a/Core/Entities/Views/Settings/DefaultViewSettings.cs +++ b/Core/Entities/Views/Settings/DefaultViewSettings.cs @@ -1,5 +1,5 @@ using SharpEngine.Core.Renderers; - +using Silk.NET.Input; using Silk.NET.Maths; using Silk.NET.Windowing; @@ -19,7 +19,7 @@ public DefaultViewSettings() } /// - /// Convenience wrapper around creating a new WindowProperties with sensible defaults. + /// Convenience wrapper around creating a new WindowProperties with sensible defaults. /// public static ViewSettings Default { get; private set; } @@ -41,4 +41,10 @@ public DefaultViewSettings() Title = "SharpEngine", Size = new Vector2D(1280, 720), }; + + /// + public MouseButton PrimaryButton { get; set; } = MouseButton.Left; + + /// + public MouseButton SecondaryButton { get; set; } = MouseButton.Right; } diff --git a/Core/Entities/Views/Settings/ViewSettings.cs b/Core/Entities/Views/Settings/ViewSettings.cs index a28ffe3..09c65cb 100644 --- a/Core/Entities/Views/Settings/ViewSettings.cs +++ b/Core/Entities/Views/Settings/ViewSettings.cs @@ -1,6 +1,5 @@ -using SharpEngine.Core.Interfaces; -using SharpEngine.Core.Renderers; -using Silk.NET.Maths; +using SharpEngine.Core.Renderers; +using Silk.NET.Input; using Silk.NET.Windowing; namespace SharpEngine.Core.Entities.Views.Settings; @@ -47,4 +46,10 @@ public ViewSettings() /// public WindowOptions WindowOptions { get; set; } + + /// + public MouseButton PrimaryButton { get; set; } = MouseButton.Left; + + /// + public MouseButton SecondaryButton { get; set; } = MouseButton.Right; } diff --git a/Core/Entities/Views/View.cs b/Core/Entities/Views/View.cs index a6f5bf6..8f78b02 100644 --- a/Core/Entities/Views/View.cs +++ b/Core/Entities/Views/View.cs @@ -1,5 +1,8 @@ using SharpEngine.Core.Entities.Views.Settings; +using SharpEngine.Core.Scenes; using SharpEngine.Core.Shaders; +using System; +using System.Collections.Generic; using System.Numerics; namespace SharpEngine.Core.Entities.Views; @@ -18,6 +21,20 @@ public View(IViewSettings settings) Settings = settings; } + // Those vectors are directions pointing outwards from the camera to define how it rotated. + protected Vector3 _front = -Vector3.UnitZ; + protected Vector3 _up = Vector3.UnitY; + protected Vector3 _right = Vector3.UnitX; + + /// Gets the front vector of the camera. + public Vector3 Front => _front; + + /// Gets the up vector of the camera. + public Vector3 Up => _up; + + /// Gets the right vector of the camera. + public Vector3 Right => _right; + /// Gets or sets the settings for the view. public IViewSettings Settings { get; set; } @@ -65,4 +82,18 @@ public virtual void UpdateMousePosition(Vector2 mousePosition) firstMove = false; } } + + /// + /// Checks whether a game object is in view of the camera. + /// + /// + /// Uses a step based ray marching algorithm to check if any object is in view of the camera. + /// + /// The scene where the check should be applied to. + /// The types that are allowed to be hit. + /// The first object that the ray intersected. + /// The position where the object was hit. + /// if any object was hit; otherwise, . + public bool IsInView(Scene scene, out GameObject? intersectingObject, out Vector3 hitPosition, params Type[] allowedTypes) + => new Ray(Position, Front).IsGameObjectInView(scene, out intersectingObject, out hitPosition, allowedTypes); } \ No newline at end of file diff --git a/Core/Interfaces/ISettings.cs b/Core/Interfaces/ISettings.cs index e2ee475..17aa676 100644 --- a/Core/Interfaces/ISettings.cs +++ b/Core/Interfaces/ISettings.cs @@ -1,4 +1,5 @@ using SharpEngine.Core.Renderers; +using Silk.NET.Input; using Silk.NET.Windowing; namespace SharpEngine.Core.Interfaces; @@ -20,6 +21,9 @@ public interface ISettings /// Gets or sets which renderer should be enabled for the current window. public RenderFlags RendererFlags { get; set; } + + public MouseButton PrimaryButton { get; set; } + public MouseButton SecondaryButton { get; set; } } /// @@ -33,4 +37,10 @@ public class DefaultSettings : ISettings /// public RenderFlags RendererFlags { get; set; } = RenderFlags.All; + + /// + public MouseButton PrimaryButton { get; set; } = MouseButton.Left; + + /// + public MouseButton SecondaryButton { get; set; } = MouseButton.Right; } diff --git a/Core/Ray.cs b/Core/Ray.cs index 68f1dee..42bae6e 100644 --- a/Core/Ray.cs +++ b/Core/Ray.cs @@ -13,14 +13,10 @@ namespace SharpEngine.Core; /// public class Ray { - /// - /// Gets or sets the ray origin. - /// + /// Gets or sets the ray origin. public Vector3 Origin { get; set; } - /// - /// Gets or sets the ray direction. - /// + /// Gets or sets the ray direction. public Vector3 Direction { get; set; } /// @@ -35,7 +31,7 @@ public Ray(Vector3 origin, Vector3 direction) } /// - /// Checks if the ray intersects with any objects in the scene. + /// Checks if the ray intersects with any objects in the scene. /// /// The scene to check for intersections. /// The intersecting object; if the ray did not intersect an object. @@ -49,7 +45,7 @@ public bool IsGameObjectInView(Scene scene, out GameObject? intersectingObject, var sceneNodes = scene.GetAllGameObjects(); - if (allowedTypes.Any()) + if (allowedTypes.Length != 0) sceneNodes = [.. sceneNodes.Where(go => allowedTypes.Any(type => type.IsInstanceOfType(go)))]; for (float t = 0; t < maxDistance; t += stepSize) @@ -70,7 +66,7 @@ public bool IsGameObjectInView(Scene scene, out GameObject? intersectingObject, } /// - /// Determines if a point is inside a given object. + /// Determines if a point is inside a given object. /// /// The point to check. /// The object to check against. @@ -86,7 +82,7 @@ public static bool IsPointInsideObject(Vector3 point, GameObject obj) } /// - /// Gets the normal of the closest face of an object to a given point. + /// Gets the normal of the closest face of an object to a given point. /// /// The point to check. /// The object to check against. diff --git a/Core/Window.cs b/Core/Window.cs index af4cd49..cb1d7e3 100644 --- a/Core/Window.cs +++ b/Core/Window.cs @@ -29,13 +29,14 @@ namespace SharpEngine.Core; /// public class Window : SilkWindow { - private readonly IViewSettings _settings; - private readonly CameraView _camera; - private bool _initialized; private IEnumerable _renderers = []; private ImGuiController? _imGuiController; + public readonly CameraView Camera; + + public IViewSettings Settings; + /// The event executed when mouse events are executed. public event Action? OnHandleMouse; @@ -77,8 +78,8 @@ public Window() { } public Window(CameraView camera, Scene scene, IViewSettings settings) { Scene = scene; - _settings = settings; - _camera = camera; + Settings = settings; + Camera = camera; Initialize(); } @@ -90,8 +91,9 @@ public Window(CameraView camera, Scene scene, IViewSettings settings) public Window(Scene scene, IViewSettings settings) { Scene = scene; - _settings = settings; - _camera = new(Vector3.One, settings); + Settings = settings; + Camera = new(Vector3.One, settings); + Initialize(); } @@ -100,7 +102,7 @@ public Window(Scene scene, IViewSettings settings) // public void Initialize() where T : SilkWindow, new() private void Initialize() { - CurrentWindow = CreateWindow(_settings.WindowOptions); + CurrentWindow = CreateWindow(Settings.WindowOptions); CurrentWindow.Update += OnUpdateFrame; CurrentWindow.Render += RenderFrame; CurrentWindow.Resize += OnResize; @@ -157,7 +159,7 @@ public override void OnLoad() { // Make sure the renderer has the correct constructor parameters! // TODO: 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, _settings, Scene }; + var requiredArguments = new object[] { Camera, Settings, Scene }; var renderer = (RendererBase)Activator.CreateInstance(type, requiredArguments)!; _renderers = _renderers.Append(renderer); @@ -197,11 +199,11 @@ protected void RenderFrame(double deltaTime) GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); - ToggleWireFrame(_settings.UseWireFrame); + ToggleWireFrame(Settings.UseWireFrame); UseShaders(); - var renderTasks = _renderers.Where(renderer => _settings.RendererFlags.HasFlag(renderer.RenderFlag)) + var renderTasks = _renderers.Where(renderer => Settings.RendererFlags.HasFlag(renderer.RenderFlag)) .Select(renderer => renderer.Render()) .ToList(); @@ -249,14 +251,14 @@ protected void OnUpdateFrame(double deltaTime) // if (!_window.IsFocused) // return; - if (_settings.PrintFrameRate) + if (Settings.PrintFrameRate) Console.WriteLine($"FPS: {1f / deltaTime}"); // TODO: Handle multiple mice? var mouse = Input?.Mice[0]; if (mouse is not null) { - _camera.UpdateMousePosition(mouse.Position); + Camera.UpdateMousePosition(mouse.Position); OnHandleMouse?.Invoke(mouse); } @@ -311,14 +313,14 @@ protected void OnMouseWheel(IMouse mouse, ScrollWheel sw) }; HandleMouseWheel?.Invoke(direction, sw); - _camera.Fov -= sw.Y; + Camera.Fov -= sw.Y; } /// protected void OnResize(Vector2D size) { GL.Viewport(size); - _camera.AspectRatio = size.X / size.Y; + Camera.AspectRatio = size.X / size.Y; } /// diff --git a/Editor/EditorSettings.cs b/Editor/EditorSettings.cs index 12e447e..6b92693 100644 --- a/Editor/EditorSettings.cs +++ b/Editor/EditorSettings.cs @@ -1,5 +1,6 @@ using SharpEngine.Core.Entities.Views.Settings; using SharpEngine.Core.Renderers; +using Silk.NET.Input; namespace SharpEngine.Editor; @@ -22,4 +23,10 @@ public class EditorSettings : IViewSettings /// public float MouseSensitivity { get; set; } + + /// + public MouseButton PrimaryButton { get; set; } = MouseButton.Left; + + /// + public MouseButton SecondaryButton { get; set; } = MouseButton.Right; } \ No newline at end of file diff --git a/Editor/EditorWindow.cs b/Editor/EditorWindow.cs index f5bc365..d46c5b5 100644 --- a/Editor/EditorWindow.cs +++ b/Editor/EditorWindow.cs @@ -1,13 +1,16 @@ using ImGuiNET; using Launcher.UI; -using Silk.NET.Input; using SharpEngine.Core; using SharpEngine.Core.Entities.Views.Settings; using SharpEngine.Core.Primitives; using SharpEngine.Core.Scenes; +using SharpEngine.Core.Entities; + using SharpEngine.Editor.Windows; +using Silk.NET.Input; + using System.Numerics; using System.Reflection; @@ -24,8 +27,6 @@ public class EditorWindow : Window private ContextMenuWindow? _contextMenuWindow; private ActionsMenuWindow? _actionsMenuWindow; - public EditorWindow() { } - /// /// Initializes an editor window with a specified scene and view settings. /// @@ -132,7 +133,31 @@ public override void OnMouseClick(IMouse mouse, MouseButton button, Vector2 vect { base.OnMouseClick(mouse, button, vector); - if (button == MouseButton.Right) - _contextMenuWindow?.ShowContextMenu(); + if (button == Settings.PrimaryButton) + { + if (ImGui.IsAnyItemHovered()) + { + // TODO: Right-clicked on an ImGui component + } + else + { + // TODO: Right-clicked outside of ImGui components + Camera.IsInView(Scene, out GameObject? intersectingObject, out Vector3 hitPosition); + _contextMenuWindow?.ShowContextMenu(intersectingObject); + } + } + + if (button == Settings.SecondaryButton) + { + if (ImGui.IsAnyItemHovered()) + { + // TODO: Left-clicked on an ImGui component + } + else + { + Camera.IsInView(Scene, out GameObject? intersectingObject, out Vector3 hitPosition); + Scene.ActiveElement = intersectingObject; + } + } } } diff --git a/Editor/Windows/ContextMenuWindow.cs b/Editor/Windows/ContextMenuWindow.cs index d7ea5ad..6911d49 100644 --- a/Editor/Windows/ContextMenuWindow.cs +++ b/Editor/Windows/ContextMenuWindow.cs @@ -1,5 +1,6 @@ using ImGuiNET; using Launcher.UI; +using SharpEngine.Core.Entities; using SharpEngine.Core.Primitives; using SharpEngine.Core.Scenes; using System.Numerics; @@ -13,6 +14,7 @@ public class ContextMenuWindow : ImGuiWindowBase { private bool _showContextMenu; private bool _updateContextMenuLocation; + private GameObject? IntersectedObject; /// public override string Name => "Context Menu"; @@ -23,39 +25,63 @@ public class ContextMenuWindow : ImGuiWindowBase /// /// Shows the context menu. /// - public void ShowContextMenu() + /// The object the cursor right-clicked on. + public void ShowContextMenu(GameObject? intersectedObject = null) { + IntersectedObject = intersectedObject; _updateContextMenuLocation = true; _showContextMenu = true; } + /// + public override void PreRender() + { + if (_updateContextMenuLocation) + { + ImGui.SetNextWindowPos(ImGui.GetMousePos()); + _updateContextMenuLocation = false; + } + } + /// public override void Render() { if (!_showContextMenu) + { + IntersectedObject = null; return; + } - if (Scene is null) - throw new InvalidOperationException("Scene is not set."); + if (Scene is not null) + RenderSceneActions(); - if (_updateContextMenuLocation) + if (IntersectedObject is not null) + RenderIntersectedObjectActions(); + } + + private void RenderIntersectedObjectActions() + { + if (ImGui.Button("Delete")) { - ImGui.SetNextWindowPos(ImGui.GetMousePos()); - _updateContextMenuLocation = false; + Scene.Root.RemoveChild(IntersectedObject); + IntersectedObject = null; } + } - ImGui.Begin("Context Menu", ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove); - - if (ImGui.Button("Create cube")) + private void RenderSceneActions() + { + var values = Enum.GetValues(); + foreach (var value in values) { - var cube = PrimitiveFactory.Create(PrimitiveType.Cube, new Vector3(0, 0, 0)); - cube.Name = "Cube" + Scene.Root.Children.Count; + if (ImGui.Button($"Create {value}")) + { + var cube = PrimitiveFactory.Create(value, new Vector3(0, 0, 0)); + cube.Name = value.ToString() + Scene.Root.Children.Count; - Scene.ActiveElement = cube; - Scene.Root.AddChild(cube); + Scene.ActiveElement = cube; + Scene.Root.AddChild(cube); + } } - - ImGui.End(); } } } diff --git a/Editor/Windows/ImGuiWindowBase.cs b/Editor/Windows/ImGuiWindowBase.cs index c48c182..b393243 100644 --- a/Editor/Windows/ImGuiWindowBase.cs +++ b/Editor/Windows/ImGuiWindowBase.cs @@ -7,6 +7,7 @@ using Silk.NET.OpenGL; using Silk.NET.OpenGL.Extensions.ImGui; using Silk.NET.Windowing; +using System.Reflection.PortableExecutable; using System.Threading; namespace SharpEngine.Editor.Windows @@ -51,11 +52,15 @@ public ImGuiWindowBase() /// The new project. public void SetProject(Project project) => Project = project; + public virtual void PreRender() { } + /// /// Renders a new ImGui window to the main window. /// public void RenderWindow() { + PreRender(); + ImGui.Begin(Name, ImGuiWindowFlags); Render(); diff --git a/Editor/Windows/PropertiesWindow.cs b/Editor/Windows/PropertiesWindow.cs index 9faf495..6f998ff 100644 --- a/Editor/Windows/PropertiesWindow.cs +++ b/Editor/Windows/PropertiesWindow.cs @@ -11,13 +11,20 @@ namespace SharpEngine.Editor.Windows; public class PropertiesWindow : ImGuiWindowBase { /// - public override string Name => "Properties"; + public override string Name => Scene.ActiveElement is null ? "Properties" : Scene.ActiveElement!.Name + " properties"; /// public override void Render() { if (Scene.ActiveElement is not null) RenderActiveElementProperties(Scene.ActiveElement); + + if (Scene.ActiveElement is null) + { + ImGui.Text("No properties to display."); + ImGui.End(); + return; + } } /// @@ -28,16 +35,6 @@ public override void Render() /// Marks the starting level or the currently rendered level of properties. public void RenderActiveElementProperties(object obj, int maxRecursionDepth = 5, int currentDepth = 0) { - if (currentDepth == 0) - ImGui.Begin(obj is null ? "Properties" : Scene.ActiveElement!.Name + " properties"); - - if (obj is null) - { - ImGui.Text("No properties to display."); - ImGui.End(); - return; - } - if (currentDepth > maxRecursionDepth) return; @@ -49,6 +46,10 @@ public void RenderActiveElementProperties(object obj, int maxRecursionDepth = 5, foreach (var property in properties) { + // Skip properties with index parameters + if (property.GetIndexParameters().Length > 0) + continue; + var inspectorAttribute = property.GetCustomAttribute(); if (inspectorAttribute != null && !inspectorAttribute.DisplayInInspector) { @@ -83,8 +84,5 @@ public void RenderActiveElementProperties(object obj, int maxRecursionDepth = 5, { Console.WriteLine(e); } - - if (currentDepth == 0) - ImGui.End(); } } diff --git a/Editor/Windows/SceneWindow.cs b/Editor/Windows/SceneWindow.cs index aa4275c..e47065a 100644 --- a/Editor/Windows/SceneWindow.cs +++ b/Editor/Windows/SceneWindow.cs @@ -1,5 +1,4 @@ using ImGuiNET; -using Launcher.UI; using SharpEngine.Core.Scenes; namespace SharpEngine.Editor.Windows diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index 4c6ebf7..e1311bd 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -209,7 +209,7 @@ public override void HandleMouseDown(IMouse mouse, MouseButton button) private BlockType DestroyBlock() { - if (!IsBlockInView(out GameObject? intersectingObject, out Vector3 _)) + if (!Camera.IsInView(_scene, out GameObject? intersectingObject, out Vector3 _, allowedTypes: typeof(BlockBase))) return BlockType.None; var block = (BlockBase)intersectingObject!; @@ -220,7 +220,7 @@ private BlockType DestroyBlock() private void PlaceBlock() { - if (!IsBlockInView(out GameObject? intersectingObject, out Vector3 hitPosition)) + if (!Camera.IsInView(_scene, out GameObject? intersectingObject, out Vector3 hitPosition, allowedTypes: typeof(BlockBase))) return; var newBlockPosition = GetNewBlockPosition(hitPosition, intersectingObject!); @@ -240,18 +240,6 @@ private static Vector3 GetNewBlockPosition(Vector3 hitPosition, GameObject inter return intersectingObject.Transform.Position + (normal * intersectingObject.Transform.Scale); } - /// - /// Checks whether a block is in view of the camera. - /// - /// - /// - /// - public bool IsBlockInView(out GameObject? intersectingObject, out Vector3 hitPosition) - { - Ray ray = new Ray(Camera.Position, Camera.Front); - return ray.IsGameObjectInView(_scene, out intersectingObject, out hitPosition, allowedTypes: typeof(BlockBase)); - } - /// public override void HandleMouseWheel(MouseWheelScrollDirection direction, ScrollWheel scrollWheel) { diff --git a/Examples/MultipleWindows/Program.cs b/Examples/MultipleWindows/Program.cs index 73a0908..0f3a748 100644 --- a/Examples/MultipleWindows/Program.cs +++ b/Examples/MultipleWindows/Program.cs @@ -19,27 +19,21 @@ static void Main() static void StartWindow(IWindow window) { - var thread = new Thread(() => + window.Load += () => { - window.Load += () => - { - Console.WriteLine($"Hello from window: " + window.Title); - - var gl = GL.GetApi(window); + Console.WriteLine($"Hello from window: " + window.Title); - unsafe - { - var versionPtr = gl.GetString(StringName.Version); - string? version = SilkMarshal.PtrToString((nint)versionPtr); - Console.WriteLine($"OpenGL version: {version}"); - } + var gl = GL.GetApi(window); - }; + unsafe + { + var versionPtr = gl.GetString(StringName.Version); + string? version = SilkMarshal.PtrToString((nint)versionPtr); + Console.WriteLine($"OpenGL version: {version}"); + } - window.Run(); - }); + }; - thread.SetApartmentState(ApartmentState.STA); - thread.Start(); + window.Run(); } } diff --git a/SharpEngine.sln b/SharpEngine.sln index f61170a..3c5d13b 100644 --- a/SharpEngine.sln +++ b/SharpEngine.sln @@ -26,8 +26,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MultipleWindows", "Examples\MultipleWindows\MultipleWindows.csproj", "{0AF16D15-5BD2-4FED-9C6A-227DE6A56C5E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AudioPlayer", "Examples\AudioPlayer\AudioPlayer.csproj", "{BE62A8C9-E83E-4D68-B3BC-BE8099BD66A2}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -80,12 +78,6 @@ Global {0AF16D15-5BD2-4FED-9C6A-227DE6A56C5E}.LauncherNonWindows|Any CPU.Build.0 = Release|Any CPU {0AF16D15-5BD2-4FED-9C6A-227DE6A56C5E}.Release|Any CPU.ActiveCfg = Release|Any CPU {0AF16D15-5BD2-4FED-9C6A-227DE6A56C5E}.Release|Any CPU.Build.0 = Release|Any CPU - {BE62A8C9-E83E-4D68-B3BC-BE8099BD66A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BE62A8C9-E83E-4D68-B3BC-BE8099BD66A2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BE62A8C9-E83E-4D68-B3BC-BE8099BD66A2}.LauncherNonWindows|Any CPU.ActiveCfg = Release|Any CPU - {BE62A8C9-E83E-4D68-B3BC-BE8099BD66A2}.LauncherNonWindows|Any CPU.Build.0 = Release|Any CPU - {BE62A8C9-E83E-4D68-B3BC-BE8099BD66A2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BE62A8C9-E83E-4D68-B3BC-BE8099BD66A2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -94,6 +86,8 @@ Global {E8A75C3B-1D82-8B30-C854-AD35FB123CDC} = {B36A84DF-456D-A817-6EDD-3EC3E7F6E11F} {1BEC06D8-094D-8BC2-288E-E2C4C13F3D2E} = {B36A84DF-456D-A817-6EDD-3EC3E7F6E11F} {0AF16D15-5BD2-4FED-9C6A-227DE6A56C5E} = {B36A84DF-456D-A817-6EDD-3EC3E7F6E11F} - {BE62A8C9-E83E-4D68-B3BC-BE8099BD66A2} = {B36A84DF-456D-A817-6EDD-3EC3E7F6E11F} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {AA03EC4B-4E7B-4B73-BEA4-60C539332773} EndGlobalSection EndGlobal From a203ca0d77369b59ecdeff9894ff94b6ce0ab135 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Wed, 26 Mar 2025 00:08:27 +0200 Subject: [PATCH 10/92] #26 Context menu size fix and documentation --- Editor/Windows/AssetsWindow.cs | 2 -- Editor/Windows/ContextMenuWindow.cs | 2 +- Editor/Windows/ImGuiWindowBase.cs | 16 ++++++++-------- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Editor/Windows/AssetsWindow.cs b/Editor/Windows/AssetsWindow.cs index d8f3dd9..b9b7051 100644 --- a/Editor/Windows/AssetsWindow.cs +++ b/Editor/Windows/AssetsWindow.cs @@ -1,7 +1,5 @@ using ImGuiNET; using Launcher.UI; -using SharpEngine.Core; -using SharpEngine.Core.Scenes; namespace SharpEngine.Editor.Windows { diff --git a/Editor/Windows/ContextMenuWindow.cs b/Editor/Windows/ContextMenuWindow.cs index 6911d49..8b10d97 100644 --- a/Editor/Windows/ContextMenuWindow.cs +++ b/Editor/Windows/ContextMenuWindow.cs @@ -20,7 +20,7 @@ public class ContextMenuWindow : ImGuiWindowBase public override string Name => "Context Menu"; /// - public override ImGuiWindowFlags ImGuiWindowFlags => ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove; + public override ImGuiWindowFlags ImGuiWindowFlags => ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove | ImGuiWindowFlags.AlwaysAutoResize; /// /// Shows the context menu. diff --git a/Editor/Windows/ImGuiWindowBase.cs b/Editor/Windows/ImGuiWindowBase.cs index b393243..a75b2b3 100644 --- a/Editor/Windows/ImGuiWindowBase.cs +++ b/Editor/Windows/ImGuiWindowBase.cs @@ -1,14 +1,8 @@ using ImGuiNET; using Launcher.UI; + using SharpEngine.Core.Entities.Views.Settings; using SharpEngine.Core.Scenes; -using Silk.NET.Input; -using Silk.NET.Maths; -using Silk.NET.OpenGL; -using Silk.NET.OpenGL.Extensions.ImGui; -using Silk.NET.Windowing; -using System.Reflection.PortableExecutable; -using System.Threading; namespace SharpEngine.Editor.Windows { @@ -52,6 +46,9 @@ public ImGuiWindowBase() /// The new project. public void SetProject(Project project) => Project = project; + /// + /// Executes operations required before rendering the ImGui window. + /// public virtual void PreRender() { } /// @@ -82,7 +79,10 @@ public void RenderWindow() protected virtual void OnWindowUndocked() { Console.WriteLine($"Window {Name} was undocked."); - CreateSilkWindow(); + + // TODO: This method of doing this does not work (at least in .Net 8). + // See issue #44 for more information. + //CreateSilkWindow(); } private void CreateSilkWindow() From a3d39af85c0ab27950a2b6f81788eb49c45a639f Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Wed, 26 Mar 2025 01:15:46 +0200 Subject: [PATCH 11/92] #26 Editor improvements --- Editor/EditorWindow.cs | 78 ++++++++++++++++++++++++++++- Editor/Windows/ContextMenuWindow.cs | 6 ++- Editor/Windows/ImGuiWindowBase.cs | 24 +++++---- 3 files changed, 96 insertions(+), 12 deletions(-) diff --git a/Editor/EditorWindow.cs b/Editor/EditorWindow.cs index d46c5b5..b943caa 100644 --- a/Editor/EditorWindow.cs +++ b/Editor/EditorWindow.cs @@ -99,6 +99,31 @@ protected override void AfterRender(double deltaTime) { base.AfterRender(deltaTime); + EnableDocking(); + RenderMenuBar(); + + bool visible = true; + ImGui.Begin("Unsaved changes", ref visible, ImGuiWindowFlags.NoResize | ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoMove); + ImGui.Text("There are unsaved changes in the project. Are you sure you want to exist without saving?"); + + if (ImGui.Button("Save")) + { + // Save the scene and exit + } + + if (ImGui.Button("Exit without saving")) + { + // TODO: shut down the application + } + + ImGui.End(); + + foreach (var window in _windows) + window.RenderWindow(); + } + + private static void EnableDocking() + { // Enable docking ImGui.GetIO().ConfigFlags |= ImGuiConfigFlags.DockingEnable; @@ -123,9 +148,58 @@ protected override void AfterRender(double deltaTime) ImGui.DockSpace(dockSpaceId, Vector2.Zero, ImGuiDockNodeFlags.PassthruCentralNode); ImGui.End(); + } - foreach (var window in _windows) - window.RenderWindow(); + private void RenderMenuBar() + { + // Add a main menu bar + if (ImGui.BeginMainMenuBar()) + { + RenderFileMenu(); + + if (ImGui.BeginMenu("Edit")) + { + ImGui.EndMenu(); + } + + if (ImGui.BeginMenu("Windows")) + { + foreach (var window in _windows) + { + if (ImGui.MenuItem(window.Name)) + window.Open(); + } + + ImGui.EndMenu(); + } + + ImGui.EndMainMenuBar(); + } + } + + private static void RenderFileMenu() + { + if (ImGui.BeginMenu("File")) + { + if (ImGui.MenuItem("New")) + { + // Handle New action + } + if (ImGui.MenuItem("Open")) + { + // Handle Open action + } + if (ImGui.MenuItem("Save")) + { + // Handle Save action + } + if (ImGui.MenuItem("Exit")) + { + // Handle Exit action + } + + ImGui.EndMenu(); + } } /// diff --git a/Editor/Windows/ContextMenuWindow.cs b/Editor/Windows/ContextMenuWindow.cs index 8b10d97..01005fe 100644 --- a/Editor/Windows/ContextMenuWindow.cs +++ b/Editor/Windows/ContextMenuWindow.cs @@ -20,7 +20,11 @@ public class ContextMenuWindow : ImGuiWindowBase public override string Name => "Context Menu"; /// - public override ImGuiWindowFlags ImGuiWindowFlags => ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove | ImGuiWindowFlags.AlwaysAutoResize; + public override ImGuiWindowFlags ImGuiWindowFlags => ImGuiWindowFlags.NoTitleBar | + ImGuiWindowFlags.NoResize | + ImGuiWindowFlags.NoMove | + ImGuiWindowFlags.AlwaysAutoResize | + ImGuiWindowFlags.NoDocking; /// /// Shows the context menu. diff --git a/Editor/Windows/ImGuiWindowBase.cs b/Editor/Windows/ImGuiWindowBase.cs index a75b2b3..7b3e369 100644 --- a/Editor/Windows/ImGuiWindowBase.cs +++ b/Editor/Windows/ImGuiWindowBase.cs @@ -17,6 +17,15 @@ public abstract class ImGuiWindowBase /// Gets or sets the currently active scene. public Scene Scene { get; private set; } + /// Gets the name of the window. + public abstract string Name { get; } + + /// + public virtual ImGuiWindowFlags ImGuiWindowFlags => ImGuiWindowFlags.None; + + private readonly Dictionary _previousDockingStates = []; + private bool _isVisible = true; + /// /// Initializes a new instance of . /// @@ -26,14 +35,6 @@ public ImGuiWindowBase() Project = new Project(); } - private readonly Dictionary _previousDockingStates = []; - - /// Gets the name of the window. - public abstract string Name { get; } - - /// - public virtual ImGuiWindowFlags ImGuiWindowFlags => ImGuiWindowFlags.None; - /// /// Sets the current scene. /// @@ -46,6 +47,8 @@ public ImGuiWindowBase() /// The new project. public void SetProject(Project project) => Project = project; + public void Open() => _isVisible = true; + /// /// Executes operations required before rendering the ImGui window. /// @@ -56,9 +59,12 @@ public virtual void PreRender() { } /// public void RenderWindow() { + if (!_isVisible) + return; + PreRender(); - ImGui.Begin(Name, ImGuiWindowFlags); + ImGui.Begin(Name, ref _isVisible, ImGuiWindowFlags); Render(); From 661113fa172e89cb4894b34438facb34573b9248 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Thu, 27 Mar 2025 17:54:17 +0200 Subject: [PATCH 12/92] Method for opening multiple windows --- Examples/MultipleWindows/Program.cs | 95 +++++++++++++++++++++++------ 1 file changed, 77 insertions(+), 18 deletions(-) diff --git a/Examples/MultipleWindows/Program.cs b/Examples/MultipleWindows/Program.cs index 0f3a748..b6ad037 100644 --- a/Examples/MultipleWindows/Program.cs +++ b/Examples/MultipleWindows/Program.cs @@ -1,39 +1,98 @@ using Silk.NET.Core.Native; using Silk.NET.GLFW; +using Silk.NET.Input; +using Silk.NET.Maths; using Silk.NET.OpenGL; using Silk.NET.Windowing; +using System.Collections.Concurrent; -internal class Program +// An example provided a lovely person in this thread: +// https://github.com/dotnet/Silk.NET/issues/2436#issuecomment-2752966073 +public static partial class Program { - static void Main() + private static readonly List _windows = []; + private static readonly List _inputContexts = []; + private static readonly ConcurrentQueue _windowQueue = []; + private static readonly CancellationTokenSource _cancellationTokenSource = new(); + + public static void Main(string[] _) { - var options1 = WindowOptions.Default with { Title = "Window 1", WindowClass = "MyWindowClass1" }; - var options2 = WindowOptions.Default with { Title = "Window 2", WindowClass = "MyWindowClass2" }; + StartWindowQueue(); - var window1 = Window.Create(options1); - var window2 = Window.Create(options2); + while (!_cancellationTokenSource.IsCancellationRequested) + { + for (int i = 0; i < _windows.Count; i++) + UpdateWindow(ref i); - StartWindow(window1); - StartWindow(window2); + DequeueWindows(); + } } - static void StartWindow(IWindow window) + private static void UpdateWindow(ref int i) { - window.Load += () => + var window = _windows[i]; + if (window is null) + return; + + window.DoEvents(); + window.DoUpdate(); + window.DoRender(); + + if (window.IsClosing) { - Console.WriteLine($"Hello from window: " + window.Title); + window.Reset(); + window.Dispose(); - var gl = GL.GetApi(window); + i--; // Adjust the index to account for the removed item + _windows.RemoveAt(i); + + if (_windows.Count == 0) + _cancellationTokenSource.Cancel(); + } + } + + private static void DequeueWindows() + { + if (_cancellationTokenSource.IsCancellationRequested) + return; + + while (_windowQueue.TryDequeue(out var options)) + CreateWindow(options); + } - unsafe + private static void StartWindowQueue() + => Task.Run(async () => + { + _windowQueue.Enqueue(WindowOptions.Default); + while (!_cancellationTokenSource.IsCancellationRequested) { - var versionPtr = gl.GetString(StringName.Version); - string? version = SilkMarshal.PtrToString((nint)versionPtr); - Console.WriteLine($"OpenGL version: {version}"); + await Task.Delay(1000); + Console.WriteLine("Running loop on background thread..."); } + }); + + private static void CreateWindow(WindowOptions options) + { + options.Title = "Window" + _windows.Count; + + // This is to make sure the windows don't overlap + options.Position = new Vector2D( + x: 500 + (50 * _windows.Count), + y: 400 + (50 * _windows.Count)); - }; + var window = Window.Create(options); + window.Initialize(); - window.Run(); + var inputContext = window.CreateInput(); + foreach (var mouse in inputContext.Mice) + mouse.Click += Mouse_Click; + + _inputContexts.Add(inputContext); + _windows.Add(window); + } + + private static void Mouse_Click(IMouse args1, Silk.NET.Input.MouseButton arg2, System.Numerics.Vector2 arg3) + { + _windowQueue.Enqueue(WindowOptions.Default); } } From dd0838e484f7dbb710a1bb278afc7dd1c2f9e3d5 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Thu, 27 Mar 2025 19:43:36 +0200 Subject: [PATCH 13/92] Small refactoring --- Examples/MultipleWindows/Program.cs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/Examples/MultipleWindows/Program.cs b/Examples/MultipleWindows/Program.cs index b6ad037..e270b17 100644 --- a/Examples/MultipleWindows/Program.cs +++ b/Examples/MultipleWindows/Program.cs @@ -43,8 +43,8 @@ private static void UpdateWindow(ref int i) window.Reset(); window.Dispose(); - i--; // Adjust the index to account for the removed item _windows.RemoveAt(i); + i--; // Adjust the index to account for the removed item if (_windows.Count == 0) _cancellationTokenSource.Cancel(); @@ -71,18 +71,27 @@ private static void StartWindowQueue() } }); - private static void CreateWindow(WindowOptions options) + private static IWindow CreateWindow() { - options.Title = "Window" + _windows.Count; + var options = WindowOptions.Default with + { + Title = "Window" + _windows.Count, - // This is to make sure the windows don't overlap - options.Position = new Vector2D( + // This is to make sure the windows don't overlap + Position = new Vector2D( x: 500 + (50 * _windows.Count), - y: 400 + (50 * _windows.Count)); + y: 400 + (50 * _windows.Count)) + }; var window = Window.Create(options); window.Initialize(); + return window; + } + + private static void CreateWindow(WindowOptions options) + { + var window = CreateWindow(); var inputContext = window.CreateInput(); foreach (var mouse in inputContext.Mice) mouse.Click += Mouse_Click; From f2b9534018897139dd6fe6bfec6fb910fe79633d Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Thu, 27 Mar 2025 19:59:36 +0200 Subject: [PATCH 14/92] Opening SharpEngine windows works --- Core/SilkWindow.cs | 40 +++++++++++++++---- .../MultipleWindows/MultipleWindows.csproj | 4 ++ Examples/MultipleWindows/Program.cs | 27 ++++++++----- 3 files changed, 52 insertions(+), 19 deletions(-) diff --git a/Core/SilkWindow.cs b/Core/SilkWindow.cs index bcc1936..a166a2f 100644 --- a/Core/SilkWindow.cs +++ b/Core/SilkWindow.cs @@ -28,22 +28,38 @@ public abstract class SilkWindow : IWindow public IMonitor? Monitor { get; set; } /// - public bool IsClosing { get; set; } + public bool IsClosing + { + get => CurrentWindow.IsClosing; + set => CurrentWindow.IsClosing = value; + } /// Gets or sets the input context for the window. public IInputContext? Input { get; protected set; } /// - public virtual Rectangle BorderSize { get; } + public virtual Rectangle BorderSize => CurrentWindow.BorderSize; /// - public bool IsVisible { get; set; } + public bool IsVisible + { + get => CurrentWindow.IsVisible; + set => CurrentWindow.IsVisible = value; + } /// - public Vector2D Position { get; set; } + public Vector2D Position + { + get => CurrentWindow.Position; + set => CurrentWindow.Position = value; + } /// - public Vector2D Size { get; set; } + public Vector2D Size + { + get => CurrentWindow.Size; + set => CurrentWindow.Size = value; + } /// public string Title @@ -56,13 +72,21 @@ public string Title public WindowState WindowState { get; set; } /// - public WindowBorder WindowBorder { get; set; } + public WindowBorder WindowBorder + { + get => CurrentWindow.WindowBorder; + set => CurrentWindow.WindowBorder = value; + } /// - public bool TransparentFramebuffer { get; } + public bool TransparentFramebuffer => CurrentWindow.TransparentFramebuffer; /// - public bool TopMost { get; set; } + public bool TopMost + { + get => CurrentWindow.TopMost; + set => CurrentWindow.TopMost = value; + } /// public IGLContext? SharedContext => CurrentWindow.SharedContext; diff --git a/Examples/MultipleWindows/MultipleWindows.csproj b/Examples/MultipleWindows/MultipleWindows.csproj index f87a3eb..c40ef83 100644 --- a/Examples/MultipleWindows/MultipleWindows.csproj +++ b/Examples/MultipleWindows/MultipleWindows.csproj @@ -14,4 +14,8 @@ + + + + diff --git a/Examples/MultipleWindows/Program.cs b/Examples/MultipleWindows/Program.cs index e270b17..e847c53 100644 --- a/Examples/MultipleWindows/Program.cs +++ b/Examples/MultipleWindows/Program.cs @@ -5,6 +5,8 @@ using Silk.NET.OpenGL; using Silk.NET.Windowing; using System.Collections.Concurrent; +using SharpEngine.Core; +using SharpEngine.Core.Entities.Views.Settings; // An example provided a lovely person in this thread: // https://github.com/dotnet/Silk.NET/issues/2436#issuecomment-2752966073 @@ -71,19 +73,23 @@ private static void StartWindowQueue() } }); - private static IWindow CreateWindow() + private static SharpEngine.Core.Window CreateWindow() { - var options = WindowOptions.Default with + var options = new DefaultViewSettings() with { - Title = "Window" + _windows.Count, + WindowOptions = WindowOptions.Default with + { + Title = "Window" + _windows.Count, - // This is to make sure the windows don't overlap - Position = new Vector2D( - x: 500 + (50 * _windows.Count), - y: 400 + (50 * _windows.Count)) + // This is to make sure the windows don't overlap + Position = new Vector2D( + x: 500 + (50 * _windows.Count), + y: 400 + (50 * _windows.Count)) + } }; - var window = Window.Create(options); + //var window = Window.Create(options); + var window = new SharpEngine.Core.Window(new(), options); window.Initialize(); return window; @@ -92,11 +98,10 @@ private static IWindow CreateWindow() private static void CreateWindow(WindowOptions options) { var window = CreateWindow(); - var inputContext = window.CreateInput(); - foreach (var mouse in inputContext.Mice) + foreach (var mouse in window.Input.Mice) mouse.Click += Mouse_Click; - _inputContexts.Add(inputContext); + _inputContexts.Add(window.Input); _windows.Add(window); } From 7b2e0ab372630cee1c7ac6b543111751581f42e7 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Fri, 28 Mar 2025 01:52:51 +0200 Subject: [PATCH 15/92] UI improvements (WIP) A lot of stuff is unfinished. Context menu locations, launcher styling, xml documentation missing etc. Functionality should be working tho --- Core/Entities/GameObject.cs | 2 +- .../Entities/Properties/Meshes/MeshService.cs | 3 +- Core/Entities/UIElement.cs | 2 +- Core/GlobalSuppressions.cs | 8 --- Core/Math.cs | 2 +- Core/Renderers/Renderer.cs | 2 +- Core/Renderers/UIRenderer.cs | 1 + Core/Shaders/LampShader.cs | 1 + Core/Shaders/LightingShader.cs | 1 + Core/Shaders/Shader.cs | 7 +++ Core/Shaders/UIShader.cs | 1 + Core/Textures/Texture.cs | 3 +- Core/Textures/TextureService.cs | 1 + Core/{ => Windowing}/SilkWindow.cs | 2 +- Core/{ => Windowing}/Window.cs | 2 +- Editor/EditorWindow.cs | 26 +++++++-- Editor/Windows/AssetsWindow.cs | 3 ++ Editor/Windows/ImGuiWindowBase.cs | 2 +- Examples/MultipleWindows/Program.cs | 25 ++++----- Launcher/Services/EditorService.cs | 3 ++ Launcher/TestData/TestData.cs | 17 ++++++ Launcher/UI/Components/ContextMenu.razor | 46 ++++++++++++++++ Launcher/UI/Components/DiscardIcon.razor | 2 +- Launcher/UI/Components/Flyouts/Flyout.razor | 41 ++++++++++++++ .../UI/Components/Flyouts/Flyout.razor.scss | 0 Launcher/UI/Components/Flyouts/FlyoutBase.cs | 21 ++++++++ .../Components/Flyouts/SettingsFlyout.razor | 12 +++++ Launcher/UI/Components/Icon.razor | 51 ++++++++++++++++++ Launcher/UI/Components/Layout.razor | 24 +++++++-- .../Components/Navigation/SideBarItem.razor | 12 +++++ .../Navigation/SideBarItem.razor.scss | 3 ++ .../UI/Components/Navigation/Sidebar.razor | 10 ++++ Launcher/UI/Components/Searchbox.razor | 28 ++++++++++ Launcher/UI/Enums/SvgIcon.cs | 10 ++++ Launcher/UI/Home.razor | 23 ++++++-- Launcher/UI/Home.razor.cs | 53 +++++++++++++++++-- Launcher/UI/_Imports.razor | 3 +- Launcher/wwwroot/css/app.css | 4 +- 38 files changed, 410 insertions(+), 47 deletions(-) delete mode 100644 Core/GlobalSuppressions.cs rename Core/{ => Windowing}/SilkWindow.cs (99%) rename Core/{ => Windowing}/Window.cs (99%) create mode 100644 Launcher/TestData/TestData.cs create mode 100644 Launcher/UI/Components/ContextMenu.razor create mode 100644 Launcher/UI/Components/Flyouts/Flyout.razor create mode 100644 Launcher/UI/Components/Flyouts/Flyout.razor.scss create mode 100644 Launcher/UI/Components/Flyouts/FlyoutBase.cs create mode 100644 Launcher/UI/Components/Flyouts/SettingsFlyout.razor create mode 100644 Launcher/UI/Components/Icon.razor create mode 100644 Launcher/UI/Components/Navigation/SideBarItem.razor create mode 100644 Launcher/UI/Components/Navigation/SideBarItem.razor.scss create mode 100644 Launcher/UI/Components/Navigation/Sidebar.razor create mode 100644 Launcher/UI/Components/Searchbox.razor create mode 100644 Launcher/UI/Enums/SvgIcon.cs diff --git a/Core/Entities/GameObject.cs b/Core/Entities/GameObject.cs index b69e257..0dbb25f 100644 --- a/Core/Entities/GameObject.cs +++ b/Core/Entities/GameObject.cs @@ -5,7 +5,7 @@ using SharpEngine.Core.Scenes; using SharpEngine.Core.Shaders; using SharpEngine.Core.Textures; - +using SharpEngine.Core.Windowing; using Silk.NET.OpenGL; using System.Collections.Generic; using System.IO; diff --git a/Core/Entities/Properties/Meshes/MeshService.cs b/Core/Entities/Properties/Meshes/MeshService.cs index 67e5300..7f7ed06 100644 --- a/Core/Entities/Properties/Meshes/MeshService.cs +++ b/Core/Entities/Properties/Meshes/MeshService.cs @@ -1,4 +1,5 @@ -using Silk.NET.OpenGL; +using SharpEngine.Core.Windowing; +using Silk.NET.OpenGL; using System.Collections.Generic; namespace SharpEngine.Core.Entities.Properties.Meshes; diff --git a/Core/Entities/UIElement.cs b/Core/Entities/UIElement.cs index 1664569..f367df0 100644 --- a/Core/Entities/UIElement.cs +++ b/Core/Entities/UIElement.cs @@ -2,7 +2,7 @@ using SharpEngine.Core.Entities.Properties.Meshes; using SharpEngine.Core.Scenes; using SharpEngine.Core.Shaders; - +using SharpEngine.Core.Windowing; using Silk.NET.OpenGL; using System; using System.Threading.Tasks; diff --git a/Core/GlobalSuppressions.cs b/Core/GlobalSuppressions.cs deleted file mode 100644 index b944386..0000000 --- a/Core/GlobalSuppressions.cs +++ /dev/null @@ -1,8 +0,0 @@ -// This file is used by Code Analysis to maintain SuppressMessage -// attributes that are applied to this project. -// Project-level suppressions either have no target or are given -// a specific target and scoped to a namespace, type, member, etc. - -using System.Diagnostics.CodeAnalysis; - -[assembly: SuppressMessage("Minor Code Smell", "S2344:Enumeration type names should not have \"Flags\" or \"Enum\" suffixes", Justification = "", Scope = "type", Target = "~T:SharpEngine.Core.Renderers.RenderFlags")] diff --git a/Core/Math.cs b/Core/Math.cs index 5006ec2..102f871 100644 --- a/Core/Math.cs +++ b/Core/Math.cs @@ -27,7 +27,7 @@ public static ReadOnlySpan ToSpan(this Matrix4x4 matrix) /// /// Converts a value in to radians. /// - /// The degress to be converted + /// The degrees to be converted. /// The given in radians. public static double DegreesToRadians(double degrees) => System.Math.PI / 180 * degrees; diff --git a/Core/Renderers/Renderer.cs b/Core/Renderers/Renderer.cs index ae52bed..5fd0a5d 100644 --- a/Core/Renderers/Renderer.cs +++ b/Core/Renderers/Renderer.cs @@ -4,7 +4,7 @@ using SharpEngine.Core.Interfaces; using SharpEngine.Core.Scenes; using SharpEngine.Core.Shaders; - +using SharpEngine.Core.Windowing; using Silk.NET.OpenGL; using System; diff --git a/Core/Renderers/UIRenderer.cs b/Core/Renderers/UIRenderer.cs index 47a6e4c..3cb617a 100644 --- a/Core/Renderers/UIRenderer.cs +++ b/Core/Renderers/UIRenderer.cs @@ -3,6 +3,7 @@ using SharpEngine.Core.Interfaces; using SharpEngine.Core.Scenes; using SharpEngine.Core.Shaders; +using SharpEngine.Core.Windowing; using Silk.NET.OpenGL; using System; diff --git a/Core/Shaders/LampShader.cs b/Core/Shaders/LampShader.cs index aa63ddb..b28730f 100644 --- a/Core/Shaders/LampShader.cs +++ b/Core/Shaders/LampShader.cs @@ -1,5 +1,6 @@ using SharpEngine.Core.Entities.Properties; using SharpEngine.Core.Extensions; +using SharpEngine.Core.Windowing; using Silk.NET.OpenGL; namespace SharpEngine.Core.Shaders; diff --git a/Core/Shaders/LightingShader.cs b/Core/Shaders/LightingShader.cs index 8ddd2af..17e7a9f 100644 --- a/Core/Shaders/LightingShader.cs +++ b/Core/Shaders/LightingShader.cs @@ -1,5 +1,6 @@ using SharpEngine.Core.Entities.Properties; using SharpEngine.Core.Extensions; +using SharpEngine.Core.Windowing; using Silk.NET.OpenGL; using System; diff --git a/Core/Shaders/Shader.cs b/Core/Shaders/Shader.cs index 0ae4049..1ea1e8d 100644 --- a/Core/Shaders/Shader.cs +++ b/Core/Shaders/Shader.cs @@ -6,6 +6,7 @@ using System.Numerics; using Silk.NET.OpenGL; +using SharpEngine.Core.Windowing; namespace SharpEngine.Core.Shaders; @@ -42,6 +43,12 @@ public Shader(string vertPath, string fragPath, string name) // The fragment shader is responsible for then converting the vertices to "fragments", which represent all the data OpenGL needs to draw a pixel. // The fragment shader is what we'll be using the most here. + if (!vertPath.EndsWith(".vert")) + Console.WriteLine("Vertex shaders should have the file extension '.vert' for easier manageability."); + + if (!fragPath.EndsWith(".frag")) + Console.WriteLine("Fragment shaders should have the file extension '.frag' for easier manageability."); + // Load and compile shader if (!LoadShader(ShaderType.VertexShader, vertPath, out uint vertexShader)) { diff --git a/Core/Shaders/UIShader.cs b/Core/Shaders/UIShader.cs index 126b2fe..de44857 100644 --- a/Core/Shaders/UIShader.cs +++ b/Core/Shaders/UIShader.cs @@ -1,4 +1,5 @@ using SharpEngine.Core.Extensions; +using SharpEngine.Core.Windowing; using Silk.NET.OpenGL; namespace SharpEngine.Core.Shaders; diff --git a/Core/Textures/Texture.cs b/Core/Textures/Texture.cs index 689b1a7..a947e3e 100644 --- a/Core/Textures/Texture.cs +++ b/Core/Textures/Texture.cs @@ -1,4 +1,5 @@ -using Silk.NET.OpenGL; +using SharpEngine.Core.Windowing; +using Silk.NET.OpenGL; namespace SharpEngine.Core.Textures; diff --git a/Core/Textures/TextureService.cs b/Core/Textures/TextureService.cs index 89b4bcf..05b1775 100644 --- a/Core/Textures/TextureService.cs +++ b/Core/Textures/TextureService.cs @@ -5,6 +5,7 @@ using System; using Silk.NET.OpenGL; +using SharpEngine.Core.Windowing; namespace SharpEngine.Core.Textures; diff --git a/Core/SilkWindow.cs b/Core/Windowing/SilkWindow.cs similarity index 99% rename from Core/SilkWindow.cs rename to Core/Windowing/SilkWindow.cs index a166a2f..4dc8267 100644 --- a/Core/SilkWindow.cs +++ b/Core/Windowing/SilkWindow.cs @@ -11,7 +11,7 @@ using System.IO; using System.Numerics; -namespace SharpEngine.Core; +namespace SharpEngine.Core.Windowing; /// /// Represents an abstraction for the interface. diff --git a/Core/Window.cs b/Core/Windowing/Window.cs similarity index 99% rename from Core/Window.cs rename to Core/Windowing/Window.cs index cb1d7e3..6be21ca 100644 --- a/Core/Window.cs +++ b/Core/Windowing/Window.cs @@ -22,7 +22,7 @@ using System.Numerics; using System.Threading.Tasks; -namespace SharpEngine.Core; +namespace SharpEngine.Core.Windowing; /// /// Represents the game window. diff --git a/Editor/EditorWindow.cs b/Editor/EditorWindow.cs index b943caa..beb1ef4 100644 --- a/Editor/EditorWindow.cs +++ b/Editor/EditorWindow.cs @@ -13,6 +13,7 @@ using System.Numerics; using System.Reflection; +using SharpEngine.Core.Windowing; namespace SharpEngine.Editor; @@ -159,6 +160,17 @@ private void RenderMenuBar() if (ImGui.BeginMenu("Edit")) { + if (ImGui.MenuItem("Settings")) + { + // Handle New action + + // TODO: Select preferred editor + // Required fields: + // radio button, each defined editor (store as json) + // textbox,Path to executable + // textbox, cli argument to open a file + } + ImGui.EndMenu(); } @@ -209,13 +221,15 @@ public override void OnMouseClick(IMouse mouse, MouseButton button, Vector2 vect if (button == Settings.PrimaryButton) { - if (ImGui.IsAnyItemHovered()) + // TODO: This probably isn't doable using ImGui. Figure out a new way or wait until UI is written using the Core 2D renderer. + if (ImGui.IsItemClicked((ImGuiMouseButton)button)) { - // TODO: Right-clicked on an ImGui component + // Clicked on an ImGui component + uint hoveredItemId = ImGui.GetID(""); + Debug.LogInformation($"Clicked on ImGui component with ID: {hoveredItemId}"); } else { - // TODO: Right-clicked outside of ImGui components Camera.IsInView(Scene, out GameObject? intersectingObject, out Vector3 hitPosition); _contextMenuWindow?.ShowContextMenu(intersectingObject); } @@ -223,9 +237,11 @@ public override void OnMouseClick(IMouse mouse, MouseButton button, Vector2 vect if (button == Settings.SecondaryButton) { - if (ImGui.IsAnyItemHovered()) + if (ImGui.IsItemClicked((ImGuiMouseButton)button)) { - // TODO: Left-clicked on an ImGui component + // Clicked on an ImGui component + uint hoveredItemId = ImGui.GetID(""); + Debug.LogInformation($"Clicked on ImGui component with ID: {hoveredItemId}"); } else { diff --git a/Editor/Windows/AssetsWindow.cs b/Editor/Windows/AssetsWindow.cs index b9b7051..ad5d876 100644 --- a/Editor/Windows/AssetsWindow.cs +++ b/Editor/Windows/AssetsWindow.cs @@ -33,6 +33,9 @@ private static void RenderDirectory(string path) foreach (var file in files) if (ImGui.Selectable(Path.GetFileName(file))) { + // TODO: Open the file in the IDE + // Process.Start(Settings.PreferredIDE.Name + Settings.PreferredIDE.CLIArguments + file); + // Scene.ActiveElement = file; // Set the file as the active element } } diff --git a/Editor/Windows/ImGuiWindowBase.cs b/Editor/Windows/ImGuiWindowBase.cs index 7b3e369..841e030 100644 --- a/Editor/Windows/ImGuiWindowBase.cs +++ b/Editor/Windows/ImGuiWindowBase.cs @@ -98,7 +98,7 @@ private void CreateSilkWindow() var thread = new Thread(() => { - var window = new Core.Window(new(), new DefaultViewSettings()); + var window = new Core.Windowing.Window(new(), new DefaultViewSettings()); window.Closing += () => _previousDockingStates[Name] = false; window.OnAfterRender += deltaTime => diff --git a/Examples/MultipleWindows/Program.cs b/Examples/MultipleWindows/Program.cs index e847c53..83caac5 100644 --- a/Examples/MultipleWindows/Program.cs +++ b/Examples/MultipleWindows/Program.cs @@ -1,11 +1,8 @@ -using Silk.NET.Core.Native; -using Silk.NET.GLFW; -using Silk.NET.Input; +using Silk.NET.Input; using Silk.NET.Maths; -using Silk.NET.OpenGL; using Silk.NET.Windowing; + using System.Collections.Concurrent; -using SharpEngine.Core; using SharpEngine.Core.Entities.Views.Settings; // An example provided a lovely person in this thread: @@ -17,9 +14,13 @@ public static partial class Program private static readonly ConcurrentQueue _windowQueue = []; private static readonly CancellationTokenSource _cancellationTokenSource = new(); + /// + /// The main entry point of the application. + /// + /// Arguments discarded. public static void Main(string[] _) { - StartWindowQueue(); + StartWindowQueueTask(); while (!_cancellationTokenSource.IsCancellationRequested) { @@ -59,10 +60,10 @@ private static void DequeueWindows() return; while (_windowQueue.TryDequeue(out var options)) - CreateWindow(options); + EnqueueWindow(options); } - private static void StartWindowQueue() + private static void StartWindowQueueTask() => Task.Run(async () => { _windowQueue.Enqueue(WindowOptions.Default); @@ -73,7 +74,7 @@ private static void StartWindowQueue() } }); - private static SharpEngine.Core.Window CreateWindow() + private static SharpEngine.Core.Windowing.Window CreateWindow() { var options = new DefaultViewSettings() with { @@ -89,16 +90,16 @@ private static SharpEngine.Core.Window CreateWindow() }; //var window = Window.Create(options); - var window = new SharpEngine.Core.Window(new(), options); + var window = new SharpEngine.Core.Windowing.Window(new(), options); window.Initialize(); return window; } - private static void CreateWindow(WindowOptions options) + private static void EnqueueWindow(WindowOptions options) { var window = CreateWindow(); - foreach (var mouse in window.Input.Mice) + foreach (var mouse in window!.Input!.Mice) mouse.Click += Mouse_Click; _inputContexts.Add(window.Input); diff --git a/Launcher/Services/EditorService.cs b/Launcher/Services/EditorService.cs index 22142f6..a503ff3 100644 --- a/Launcher/Services/EditorService.cs +++ b/Launcher/Services/EditorService.cs @@ -159,7 +159,10 @@ public List LoadProjects(string projectsFile) var projects = System.Text.Json.JsonSerializer.Deserialize>(json); if (projects is not null) + { + // TOOD: Resolve last modified return projects; + } _notificationService.Show($"Unable to load projects.", false, json, projects?.ToArray()); return []; diff --git a/Launcher/TestData/TestData.cs b/Launcher/TestData/TestData.cs new file mode 100644 index 0000000..44036eb --- /dev/null +++ b/Launcher/TestData/TestData.cs @@ -0,0 +1,17 @@ +using Launcher.UI; + +namespace Launcher.TestData; +public static class TestData +{ + public const bool LoadTestData = true; + + public const bool SimulateLoading = false; + + public static IEnumerable Projects = Enumerable.Range(0, 3).Select(i => + { + return new Project() + { + Name = $"Project {i}", + }; + }); +} diff --git a/Launcher/UI/Components/ContextMenu.razor b/Launcher/UI/Components/ContextMenu.razor new file mode 100644 index 0000000..3e59bc2 --- /dev/null +++ b/Launcher/UI/Components/ContextMenu.razor @@ -0,0 +1,46 @@ +@if (showMenu) +{ +
+ @ChildContent(Context) +
+} + + + +@code { + [Inject] + private IJSRuntime JS { get; set; } + + [Parameter] + public RenderFragment ChildContent { get; set; } + + public object Context { get; set; } + + private bool showMenu = false; + private int menuX, menuY; + + private string menuXpx => $"{menuX}px"; + private string menuYpx => $"{menuY}px"; + + public void Open(MouseEventArgs e, object context) + { + menuX = (int)e.ClientX; + menuY = (int)e.ClientY; + showMenu = true; + + Context = context; + + // Prevent the default browser context menu + JS.InvokeVoidAsync("preventContextMenu"); + } +} diff --git a/Launcher/UI/Components/DiscardIcon.razor b/Launcher/UI/Components/DiscardIcon.razor index 0b36549..62597d0 100644 --- a/Launcher/UI/Components/DiscardIcon.razor +++ b/Launcher/UI/Components/DiscardIcon.razor @@ -1,4 +1,4 @@ -✖ + @code { diff --git a/Launcher/UI/Components/Flyouts/Flyout.razor b/Launcher/UI/Components/Flyouts/Flyout.razor new file mode 100644 index 0000000..c7abf26 --- /dev/null +++ b/Launcher/UI/Components/Flyouts/Flyout.razor @@ -0,0 +1,41 @@ +@inherits FlyoutBase + +
+
+
+ @if (Header is not null) + { + @Header + } + else + { +

@Title

+ } +
+
+ +
+
+
+ @Content +
+ +
+ +@code { + [Parameter] + public RenderFragment Header { get; set; } + + [Parameter] + public RenderFragment Content { get; set; } + + [Parameter] + public RenderFragment Footer { get; set; } + + [Parameter] + public string Title { get; set; } = default!; + + private string _isVisibleStyle => IsVisible ? "visible" : "hidden"; +} diff --git a/Launcher/UI/Components/Flyouts/Flyout.razor.scss b/Launcher/UI/Components/Flyouts/Flyout.razor.scss new file mode 100644 index 0000000..e69de29 diff --git a/Launcher/UI/Components/Flyouts/FlyoutBase.cs b/Launcher/UI/Components/Flyouts/FlyoutBase.cs new file mode 100644 index 0000000..18e5a85 --- /dev/null +++ b/Launcher/UI/Components/Flyouts/FlyoutBase.cs @@ -0,0 +1,21 @@ +using Microsoft.AspNetCore.Components; + +namespace Launcher.UI.Components.Flyouts; + +public class FlyoutBase : ComponentBase +{ + [Parameter] + public bool IsVisible { get; set; } + + [Parameter] + public EventCallback IsVisibleChanged { get; set; } + + [Parameter] + public EventCallback OnClose { get; set; } + + public virtual async Task OnIsVisibleChangedAsync(bool visibility) + { + IsVisible = visibility; + await IsVisibleChanged.InvokeAsync(visibility); + } +} diff --git a/Launcher/UI/Components/Flyouts/SettingsFlyout.razor b/Launcher/UI/Components/Flyouts/SettingsFlyout.razor new file mode 100644 index 0000000..2326ad2 --- /dev/null +++ b/Launcher/UI/Components/Flyouts/SettingsFlyout.razor @@ -0,0 +1,12 @@ +@inherits FlyoutBase + + +
+ + +
+
+ +@code { + +} diff --git a/Launcher/UI/Components/Icon.razor b/Launcher/UI/Components/Icon.razor new file mode 100644 index 0000000..8d0dcce --- /dev/null +++ b/Launcher/UI/Components/Icon.razor @@ -0,0 +1,51 @@ +@switch (IconType) +{ + case SvgIcon.Home: + + + + + + + + break; + case SvgIcon.Cog: + + + + + + + + break; + case SvgIcon.Lens: + + + + + + + break; + case SvgIcon.Discard: + ✖ + break; + case SvgIcon.Close: + + + + + + + + break; + default: + break; +} + +@code { + [Parameter] + public SvgIcon IconType { get; set; } + + [Parameter] + public int SizePx { get; set; } = 16; +} diff --git a/Launcher/UI/Components/Layout.razor b/Launcher/UI/Components/Layout.razor index 21adf40..21bba39 100644 --- a/Launcher/UI/Components/Layout.razor +++ b/Launcher/UI/Components/Layout.razor @@ -1,5 +1,23 @@ -@inherits LayoutComponentBase +@using Launcher.UI.Components.Navigation +@using Launcher.UI.Components.Flyouts + +@inherits LayoutComponentBase
-@Body -
\ No newline at end of file + + + + +
+ @Body +
+ + + + +@code { + private bool _settingsVisible; + + private void OpenSettingsFlyout() + => _settingsVisible = true; +} \ No newline at end of file diff --git a/Launcher/UI/Components/Navigation/SideBarItem.razor b/Launcher/UI/Components/Navigation/SideBarItem.razor new file mode 100644 index 0000000..a34d252 --- /dev/null +++ b/Launcher/UI/Components/Navigation/SideBarItem.razor @@ -0,0 +1,12 @@ + + +@code { + [Parameter] + public SvgIcon Icon { get; set; } + + [Parameter] + public EventCallback OnClick { get; set; } + + private async Task OnItemClicked() + => await OnClick.InvokeAsync(); +} diff --git a/Launcher/UI/Components/Navigation/SideBarItem.razor.scss b/Launcher/UI/Components/Navigation/SideBarItem.razor.scss new file mode 100644 index 0000000..0d97a28 --- /dev/null +++ b/Launcher/UI/Components/Navigation/SideBarItem.razor.scss @@ -0,0 +1,3 @@ +.sidebar-item { + +} \ No newline at end of file diff --git a/Launcher/UI/Components/Navigation/Sidebar.razor b/Launcher/UI/Components/Navigation/Sidebar.razor new file mode 100644 index 0000000..19ae0d8 --- /dev/null +++ b/Launcher/UI/Components/Navigation/Sidebar.razor @@ -0,0 +1,10 @@ + + +@code { + [Parameter, EditorRequired] + public RenderFragment ChildContent { get; set; } +} diff --git a/Launcher/UI/Components/Searchbox.razor b/Launcher/UI/Components/Searchbox.razor new file mode 100644 index 0000000..0490ea2 --- /dev/null +++ b/Launcher/UI/Components/Searchbox.razor @@ -0,0 +1,28 @@ +
+ + +
+ +@code { + [Parameter] + public string Value { get; set; } = default!; + + [Parameter] + public EventCallback ValueChanged { get; set; } + + [Parameter] + public int DebounceDelayMilliseconds { get; set; } = 1000; + + private CancellationTokenSource _tokenSource { get; set; } = new(); + + private async Task OnChangeAsync(ChangeEventArgs e) + { + _tokenSource = new CancellationTokenSource(); + var token = _tokenSource.Token; + + await Task.Delay(DebounceDelayMilliseconds, token); + + Value = e.Value?.ToString() ?? string.Empty; + await ValueChanged.InvokeAsync(Value); + } +} diff --git a/Launcher/UI/Enums/SvgIcon.cs b/Launcher/UI/Enums/SvgIcon.cs new file mode 100644 index 0000000..1b432f7 --- /dev/null +++ b/Launcher/UI/Enums/SvgIcon.cs @@ -0,0 +1,10 @@ +namespace Launcher.UI.Enums; + +public enum SvgIcon +{ + Home, + Cog, + Discard, + Lens, + Close +} diff --git a/Launcher/UI/Home.razor b/Launcher/UI/Home.razor index 35fb873..f47f962 100644 --- a/Launcher/UI/Home.razor +++ b/Launcher/UI/Home.razor @@ -17,15 +17,32 @@ + + +
- + @context.Name @context.LastModified - + -
\ No newline at end of file + + + + @{ + var project = (Project)context; + + + + + } + + +@code { + private ContextMenu? _contextMenu; +} \ No newline at end of file diff --git a/Launcher/UI/Home.razor.cs b/Launcher/UI/Home.razor.cs index 71c52fb..99af3c2 100644 --- a/Launcher/UI/Home.razor.cs +++ b/Launcher/UI/Home.razor.cs @@ -1,7 +1,7 @@ using Launcher.Services; using Microsoft.AspNetCore.Components; +using System.Diagnostics; using System.Text.Json; -using System.Text.Json.Serialization; namespace Launcher.UI { @@ -17,12 +17,24 @@ public partial class Home : ComponentBase private bool _showConfirmDelete; private bool _showCreateProjectDialog; - private List Projects { get; set; } = []; + private List Projects + { + get => _allProjects; + set + { + _allProjects = value; + _filteredProjects = value; + } + } + + private List _allProjects = []; + private List _filteredProjects = []; + private Project _selectedProject = new(); private const string _projectsFile = "projects.json"; private static readonly string[] _sharpProjectFilePickerExtension = [".sharpproject"]; -#if DEBUG +#if !DEBUG private readonly string _projectsFilePath = Path.Join(Path.GetTempPath(), _projectsFile); #else private readonly string _projectsFilePath = Path.Join(AppContext.BaseDirectory, _projectsFile); @@ -35,14 +47,32 @@ protected override async Task OnInitializedAsync() // TODO: Get current launcher version // TODO: Check if GitHub has a new version released. +#if DEBUG + if (TestData.TestData.SimulateLoading) + { + _notificationService.Show("Simulating loading projects."); + await Task.Delay(10000); + } + + if (TestData.TestData.LoadTestData) + { + _notificationService.Show("Using test data."); + Projects = [.. TestData.TestData.Projects]; + return; + } +#endif + var projects = _editorService.LoadProjects(_projectsFilePath); - + if (projects is not null) Projects.AddRange(projects); else _notificationService.Show($"Unable to load project file.", false, projects); } + private void SearchProjects(string searchValue) + => _filteredProjects = [.. Projects.Where(p => p.Name!.Contains(searchValue, StringComparison.OrdinalIgnoreCase))]; + private void OnCreateProjectClicked() => _showCreateProjectDialog = true; @@ -113,5 +143,20 @@ private void SetProjects(Project project) string json = JsonSerializer.Serialize(Projects); File.WriteAllText(_projectsFilePath, json); } + + private static void OpenInExplorer(string projectPath) + => Process.Start("explorer.exe", projectPath); + + private void RemoveFromList(Project project) + { + var foundProject = Projects.Find(p => p.Id == project.Id); + if (foundProject is null) + { + _notificationService.Show($"Unable to remove project '{project.Name}', project not found.", false, project); + return; + } + + Projects.Remove(foundProject); + } } } diff --git a/Launcher/UI/_Imports.razor b/Launcher/UI/_Imports.razor index 464f868..5047218 100644 --- a/Launcher/UI/_Imports.razor +++ b/Launcher/UI/_Imports.razor @@ -9,4 +9,5 @@ @using Launcher @using Launcher.UI -@using Launcher.Services \ No newline at end of file +@using Launcher.Services +@using Launcher.UI.Enums diff --git a/Launcher/wwwroot/css/app.css b/Launcher/wwwroot/css/app.css index aad5a54..a257aed 100644 --- a/Launcher/wwwroot/css/app.css +++ b/Launcher/wwwroot/css/app.css @@ -100,5 +100,7 @@ p, h1, h4, a, td, tr, div, .prevent-select { .page { height: 100%; - display: flow-root; + display: grid; + grid-template-rows: 1fr; + grid-template-columns: 50px auto; } \ No newline at end of file From 5adf7b13d09fd17bc619927ed8667706daa2858b Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sat, 29 Mar 2025 00:21:10 +0200 Subject: [PATCH 16/92] Launcher UI improvements --- Editor/EditorWindow.cs | 2 +- Editor/Program.cs | 4 +- Editor/Windows/ActionsMenuWindow.cs | 2 +- Editor/Windows/ImGuiWindowBase.cs | 2 +- Launcher/Enums/FilterMode.cs | 19 +++++ Launcher/Enums/SvgIcon.cs | 13 +++ Launcher/Services/EditorService.cs | 5 +- Launcher/TestData/TestData.cs | 5 +- .../Dialogs/CreateProjectDialog.razor.cs | 1 + .../UI/Components/Dialogs/Notification.razor | 21 +++-- Launcher/UI/Components/DiscardIcon.razor | 11 --- Launcher/UI/Components/DiscardIcon.razor.css | 6 -- .../UI/Components/DiscardIcon.razor.min.css | 1 - Launcher/UI/Components/DiscardIcon.razor.scss | 7 -- Launcher/UI/Components/Flyouts/Flyout.razor | 21 +++-- .../UI/Components/Flyouts/Flyout.razor.css | 38 +++++++++ .../Components/Flyouts/Flyout.razor.min.css | 1 + .../UI/Components/Flyouts/Flyout.razor.scss | 39 +++++++++ Launcher/UI/Components/Flyouts/FlyoutBase.cs | 6 ++ .../Components/Flyouts/SettingsFlyout.razor | 13 ++- Launcher/UI/Components/Grid.razor | 35 -------- Launcher/UI/Components/Grid/Grid.razor | 83 +++++++++++++++++++ Launcher/UI/Components/Grid/Grid.razor.css | 19 +++++ .../UI/Components/Grid/Grid.razor.min.css | 1 + Launcher/UI/Components/Grid/Grid.razor.scss | 19 +++++ Launcher/UI/Components/Grid/GridHeader.cs | 13 +++ Launcher/UI/Components/Grid/GridHeader.razor | 48 +++++++++++ .../UI/Components/Grid/GridHeader.razor.css | 15 ++++ .../Components/Grid/GridHeader.razor.min.css | 1 + .../UI/Components/Grid/GridHeader.razor.scss | 15 ++++ .../UI/Components/{ => Grid}/GridRow.razor | 0 Launcher/UI/Components/Icon.razor | 21 ++++- Launcher/UI/Components/Layout.razor | 9 +- .../Components/Navigation/SideBarItem.razor | 3 +- .../Navigation/SideBarItem.razor.css | 1 + .../Navigation/SideBarItem.razor.min.css | 1 + .../UI/Components/Navigation/Sidebar.razor | 4 +- Launcher/UI/Components/Searchbox.razor | 6 +- Launcher/UI/Enums/SvgIcon.cs | 10 --- Launcher/UI/Home.razor | 19 +++-- Launcher/UI/Home.razor.cs | 9 ++ Launcher/UI/Home.razor.css | 2 +- Launcher/UI/Home.razor.min.css | 2 +- Launcher/UI/Home.razor.scss | 2 +- Launcher/UI/NaturalStringComparer.cs | 67 +++++++++++++++ Launcher/UI/OrderedEnumerableExtensions.cs | 37 +++++++++ Launcher/UI/_Imports.razor | 2 +- Launcher/compilerconfig.json | 20 ++++- Launcher/wwwroot/css/app.css | 4 + .../Attributes/FilterAttribute.cs | 12 +++ SharpEngine.Shared/{ => Dto}/Project.cs | 8 +- .../{ => Extensions}/ProcessExtensions.cs | 4 +- .../Extensions/ReflectionExtensions.cs | 18 ++++ 53 files changed, 604 insertions(+), 123 deletions(-) create mode 100644 Launcher/Enums/FilterMode.cs create mode 100644 Launcher/Enums/SvgIcon.cs delete mode 100644 Launcher/UI/Components/DiscardIcon.razor delete mode 100644 Launcher/UI/Components/DiscardIcon.razor.css delete mode 100644 Launcher/UI/Components/DiscardIcon.razor.min.css delete mode 100644 Launcher/UI/Components/DiscardIcon.razor.scss create mode 100644 Launcher/UI/Components/Flyouts/Flyout.razor.css create mode 100644 Launcher/UI/Components/Flyouts/Flyout.razor.min.css delete mode 100644 Launcher/UI/Components/Grid.razor create mode 100644 Launcher/UI/Components/Grid/Grid.razor create mode 100644 Launcher/UI/Components/Grid/Grid.razor.css create mode 100644 Launcher/UI/Components/Grid/Grid.razor.min.css create mode 100644 Launcher/UI/Components/Grid/Grid.razor.scss create mode 100644 Launcher/UI/Components/Grid/GridHeader.cs create mode 100644 Launcher/UI/Components/Grid/GridHeader.razor create mode 100644 Launcher/UI/Components/Grid/GridHeader.razor.css create mode 100644 Launcher/UI/Components/Grid/GridHeader.razor.min.css create mode 100644 Launcher/UI/Components/Grid/GridHeader.razor.scss rename Launcher/UI/Components/{ => Grid}/GridRow.razor (100%) create mode 100644 Launcher/UI/Components/Navigation/SideBarItem.razor.css create mode 100644 Launcher/UI/Components/Navigation/SideBarItem.razor.min.css delete mode 100644 Launcher/UI/Enums/SvgIcon.cs create mode 100644 Launcher/UI/NaturalStringComparer.cs create mode 100644 Launcher/UI/OrderedEnumerableExtensions.cs create mode 100644 SharpEngine.Shared/Attributes/FilterAttribute.cs rename SharpEngine.Shared/{ => Dto}/Project.cs (85%) rename SharpEngine.Shared/{ => Extensions}/ProcessExtensions.cs (97%) create mode 100644 SharpEngine.Shared/Extensions/ReflectionExtensions.cs diff --git a/Editor/EditorWindow.cs b/Editor/EditorWindow.cs index beb1ef4..807a5b4 100644 --- a/Editor/EditorWindow.cs +++ b/Editor/EditorWindow.cs @@ -1,5 +1,4 @@ using ImGuiNET; -using Launcher.UI; using SharpEngine.Core; using SharpEngine.Core.Entities.Views.Settings; @@ -14,6 +13,7 @@ using System.Numerics; using System.Reflection; using SharpEngine.Core.Windowing; +using SharpEngine.Shared.Dto; namespace SharpEngine.Editor; diff --git a/Editor/Program.cs b/Editor/Program.cs index 1dd9670..e899d16 100644 --- a/Editor/Program.cs +++ b/Editor/Program.cs @@ -1,9 +1,9 @@ -using Launcher.UI; -using SharpEngine.Core; +using SharpEngine.Core; using SharpEngine.Core.Entities.Views.Settings; using SharpEngine.Core.Scenes; using SharpEngine.Editor.Windows; using SharpEngine.Shared; +using SharpEngine.Shared.Dto; using System.Reflection; namespace SharpEngine.Editor; diff --git a/Editor/Windows/ActionsMenuWindow.cs b/Editor/Windows/ActionsMenuWindow.cs index af5e223..f6471ab 100644 --- a/Editor/Windows/ActionsMenuWindow.cs +++ b/Editor/Windows/ActionsMenuWindow.cs @@ -3,7 +3,7 @@ using SharpEngine.Core; using SharpEngine.Core.Audio; using SharpEngine.Core.Scenes; -using SharpEngine.Shared; +using SharpEngine.Shared.Extensions; namespace SharpEngine.Editor.Windows { diff --git a/Editor/Windows/ImGuiWindowBase.cs b/Editor/Windows/ImGuiWindowBase.cs index 841e030..8e62aa9 100644 --- a/Editor/Windows/ImGuiWindowBase.cs +++ b/Editor/Windows/ImGuiWindowBase.cs @@ -1,8 +1,8 @@ using ImGuiNET; -using Launcher.UI; using SharpEngine.Core.Entities.Views.Settings; using SharpEngine.Core.Scenes; +using SharpEngine.Shared.Dto; namespace SharpEngine.Editor.Windows { diff --git a/Launcher/Enums/FilterMode.cs b/Launcher/Enums/FilterMode.cs new file mode 100644 index 0000000..06c4bb2 --- /dev/null +++ b/Launcher/Enums/FilterMode.cs @@ -0,0 +1,19 @@ +namespace Launcher.Enums; + +public enum FilterMode +{ + /// + /// No filter applied. + /// + None, + + /// + /// Filter in ascending order. + /// + Ascending, + + /// + /// Filter in descending order. + /// + Descending +} diff --git a/Launcher/Enums/SvgIcon.cs b/Launcher/Enums/SvgIcon.cs new file mode 100644 index 0000000..d2ce8f4 --- /dev/null +++ b/Launcher/Enums/SvgIcon.cs @@ -0,0 +1,13 @@ +namespace Launcher.Enums; + +public enum SvgIcon +{ + None, + Home, + Cog, + Discard, + Lens, + Close, + ChevronDown, + ChevronUp, +} diff --git a/Launcher/Services/EditorService.cs b/Launcher/Services/EditorService.cs index a503ff3..0f8f10a 100644 --- a/Launcher/Services/EditorService.cs +++ b/Launcher/Services/EditorService.cs @@ -1,5 +1,6 @@ -using Launcher.UI; -using SharpEngine.Shared; +using SharpEngine.Shared; +using SharpEngine.Shared.Dto; +using SharpEngine.Shared.Extensions; using System.Diagnostics; using System.Runtime.InteropServices; diff --git a/Launcher/TestData/TestData.cs b/Launcher/TestData/TestData.cs index 44036eb..18344e6 100644 --- a/Launcher/TestData/TestData.cs +++ b/Launcher/TestData/TestData.cs @@ -1,4 +1,4 @@ -using Launcher.UI; +using SharpEngine.Shared.Dto; namespace Launcher.TestData; public static class TestData @@ -7,11 +7,12 @@ public static class TestData public const bool SimulateLoading = false; - public static IEnumerable Projects = Enumerable.Range(0, 3).Select(i => + public static IEnumerable Projects = Enumerable.Range(0, 25).Select(i => { return new Project() { Name = $"Project {i}", + Path = @"C:\test", }; }); } diff --git a/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.cs b/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.cs index ad2eaff..7d1b324 100644 --- a/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.cs +++ b/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Components; using Launcher.Services; using CommunityToolkit.Maui.Storage; +using SharpEngine.Shared.Dto; namespace Launcher.UI.Components.Dialogs { diff --git a/Launcher/UI/Components/Dialogs/Notification.razor b/Launcher/UI/Components/Dialogs/Notification.razor index 8a40e57..78b9225 100644 --- a/Launcher/UI/Components/Dialogs/Notification.razor +++ b/Launcher/UI/Components/Dialogs/Notification.razor @@ -1,17 +1,22 @@ -@using Launcher.Services +@using Launcher.Enums +@using Launcher.Services @inherits DialogBase @inject INotificationService NotificationService
- @foreach (var notification in NotificationService.Notifications) - { - - } + + @foreach (var notification in NotificationService.Notifications) + { + + } +
diff --git a/Launcher/UI/Components/DiscardIcon.razor b/Launcher/UI/Components/DiscardIcon.razor deleted file mode 100644 index 62597d0..0000000 --- a/Launcher/UI/Components/DiscardIcon.razor +++ /dev/null @@ -1,11 +0,0 @@ - - -@code { - - /// Gets or sets the event executed when the discard icon is clicked. - [Parameter] - public EventCallback DiscardClicked { get; set; } - - private async Task OnDiscardClicked() - => await DiscardClicked.InvokeAsync(); -} diff --git a/Launcher/UI/Components/DiscardIcon.razor.css b/Launcher/UI/Components/DiscardIcon.razor.css deleted file mode 100644 index 301f29c..0000000 --- a/Launcher/UI/Components/DiscardIcon.razor.css +++ /dev/null @@ -1,6 +0,0 @@ -span { - cursor: pointer; -} -span:hover { - filter: brightness(0.8); -} diff --git a/Launcher/UI/Components/DiscardIcon.razor.min.css b/Launcher/UI/Components/DiscardIcon.razor.min.css deleted file mode 100644 index 6048a35..0000000 --- a/Launcher/UI/Components/DiscardIcon.razor.min.css +++ /dev/null @@ -1 +0,0 @@ -span{cursor:pointer;}span:hover{filter:brightness(.8);} \ No newline at end of file diff --git a/Launcher/UI/Components/DiscardIcon.razor.scss b/Launcher/UI/Components/DiscardIcon.razor.scss deleted file mode 100644 index f5cb62a..0000000 --- a/Launcher/UI/Components/DiscardIcon.razor.scss +++ /dev/null @@ -1,7 +0,0 @@ -span { - cursor: pointer; - - &:hover { - filter: brightness(0.8); - } -} diff --git a/Launcher/UI/Components/Flyouts/Flyout.razor b/Launcher/UI/Components/Flyouts/Flyout.razor index c7abf26..efb293e 100644 --- a/Launcher/UI/Components/Flyouts/Flyout.razor +++ b/Launcher/UI/Components/Flyouts/Flyout.razor @@ -1,5 +1,4 @@ -@inherits FlyoutBase - +@using Launcher.Enums
@@ -12,9 +11,7 @@

@Title

}
-
- -
+
@Content @@ -37,5 +34,17 @@ [Parameter] public string Title { get; set; } = default!; - private string _isVisibleStyle => IsVisible ? "visible" : "hidden"; + [Parameter] + public bool IsVisible { get; set; } + + [Parameter] + public EventCallback IsVisibleChanged { get; set; } + + private string _isVisibleStyle => IsVisible ? "grid" : "none"; + + private async Task Close() + { + IsVisible = false; + await IsVisibleChanged.InvokeAsync(IsVisible); + } } diff --git a/Launcher/UI/Components/Flyouts/Flyout.razor.css b/Launcher/UI/Components/Flyouts/Flyout.razor.css new file mode 100644 index 0000000..82882fa --- /dev/null +++ b/Launcher/UI/Components/Flyouts/Flyout.razor.css @@ -0,0 +1,38 @@ +.flyout { + display: none; + position: absolute; + top: 0; + width: 50%; + height: 100vh; + z-index: 9999; + background: white; + border-right: 1px solid black; + left: 50px; + grid-template-rows: 70px auto 70px; +} + +.flyout-header { + display: flex; + justify-content: space-between; +} +.flyout-header button { + border: none; + background: none; +} + +.flyout-content { + overflow-y: scroll; + padding-left: 1em; +} + +.flyout-footer { + border-top: 1px solid black; + padding: 5px; + display: flex; + justify-content: end; + gap: 8px; +} + +.flyout-footer, .flyout-header, .flyout-content { + padding: 1em; +} diff --git a/Launcher/UI/Components/Flyouts/Flyout.razor.min.css b/Launcher/UI/Components/Flyouts/Flyout.razor.min.css new file mode 100644 index 0000000..f1bb45f --- /dev/null +++ b/Launcher/UI/Components/Flyouts/Flyout.razor.min.css @@ -0,0 +1 @@ +.flyout{display:none;position:absolute;top:0;width:50%;height:100vh;z-index:9999;background:#fff;border-right:1px solid #000;left:50px;grid-template-rows:70px auto 70px;}.flyout-header{display:flex;justify-content:space-between;}.flyout-header button{border:0;background:none;}.flyout-content{overflow-y:scroll;padding-left:1em;}.flyout-footer{border-top:1px solid #000;padding:5px;display:flex;justify-content:end;gap:8px;}.flyout-footer,.flyout-header,.flyout-content{padding:1em;} \ No newline at end of file diff --git a/Launcher/UI/Components/Flyouts/Flyout.razor.scss b/Launcher/UI/Components/Flyouts/Flyout.razor.scss index e69de29..decc8e0 100644 --- a/Launcher/UI/Components/Flyouts/Flyout.razor.scss +++ b/Launcher/UI/Components/Flyouts/Flyout.razor.scss @@ -0,0 +1,39 @@ +.flyout { + display: none; + position: absolute; + top: 0; + width: 50%; + height: 100vh; + z-index: 9999; + background: white; + border-right: 1px solid black; + left: 50px; + grid-template-rows: 70px auto 70px; +} + +.flyout-header { + display: flex; + justify-content: space-between; + + button { + border: none; + background: none; + } +} + +.flyout-content { + overflow-y: scroll; + padding-left: 1em; +} + +.flyout-footer { + border-top: 1px solid black; + padding: 5px; + display: flex; + justify-content: end; + gap: 8px; +} + +.flyout-footer, .flyout-header, .flyout-content { + padding: 1em; +} \ No newline at end of file diff --git a/Launcher/UI/Components/Flyouts/FlyoutBase.cs b/Launcher/UI/Components/Flyouts/FlyoutBase.cs index 18e5a85..ed720a2 100644 --- a/Launcher/UI/Components/Flyouts/FlyoutBase.cs +++ b/Launcher/UI/Components/Flyouts/FlyoutBase.cs @@ -18,4 +18,10 @@ public virtual async Task OnIsVisibleChangedAsync(bool visibility) IsVisible = visibility; await IsVisibleChanged.InvokeAsync(visibility); } + + public virtual async Task Close() + { + await OnClose.InvokeAsync(); + await OnIsVisibleChangedAsync(false); + } } diff --git a/Launcher/UI/Components/Flyouts/SettingsFlyout.razor b/Launcher/UI/Components/Flyouts/SettingsFlyout.razor index 2326ad2..e8c7930 100644 --- a/Launcher/UI/Components/Flyouts/SettingsFlyout.razor +++ b/Launcher/UI/Components/Flyouts/SettingsFlyout.razor @@ -1,12 +1,19 @@ @inherits FlyoutBase - +
- - + +
@code { + [Inject] + private INotificationService _notificationService { get; init; } = default!; + private async Task SaveSettings() + { + _notificationService.Show("Settings saved."); + await Close(); + } } diff --git a/Launcher/UI/Components/Grid.razor b/Launcher/UI/Components/Grid.razor deleted file mode 100644 index a65a5ef..0000000 --- a/Launcher/UI/Components/Grid.razor +++ /dev/null @@ -1,35 +0,0 @@ -@typeparam TItem - - - - - - - - - - - @foreach (var item in Items) - { - - - @Row(item) - - - } - -
NameLast ModifiedActions
- -@code { - /// - /// Gets or sets the items to be rendered onto the grid. - /// - [Parameter] - public List Items { get; set; } - - /// - /// Gets or sets a template by which each row should be rendered. - /// - [Parameter] - public RenderFragment Row { get; set; } -} \ No newline at end of file diff --git a/Launcher/UI/Components/Grid/Grid.razor b/Launcher/UI/Components/Grid/Grid.razor new file mode 100644 index 0000000..5050b38 --- /dev/null +++ b/Launcher/UI/Components/Grid/Grid.razor @@ -0,0 +1,83 @@ +@using System.ComponentModel +@using SharpEngine.Shared.Attributes + +@typeparam TItem + +
+ + + + @foreach (var header in _headers) + { + + } + + +
+
+ + +
+ + + @foreach (var item in Items) + { + + + @GridRowTemplate(item) + + + } + +
+
+ +@code { + /// + /// Gets or sets the items to be rendered onto the grid. + /// + [Parameter] + public List Items { get; set; } = []; + + /// + /// Gets or sets a template by which each row should be rendered. + /// + [Parameter] + public RenderFragment GridRowTemplate { get; set; } + + [Parameter] + public EventCallback> FilterChanged { get; set; } + + private List _headers { get; set; } = []; + private Dictionary _filterModes { get; set; } = new(); + + protected override Task OnInitializedAsync() + { + GetHeaders(); + return base.OnInitializedAsync(); + } + + private void GetHeaders() + { + var props = typeof(TItem).GetProperties(); + var headers = props.Select(prop => + { + var displayNameAttribute = (DisplayNameAttribute?)prop.GetCustomAttributes(typeof(DisplayNameAttribute), false).FirstOrDefault(); + var filterAttribute = (FilterAttribute?)prop.GetCustomAttributes(typeof(FilterAttribute), false).FirstOrDefault(); + + return new GridHeaderInfo(displayNameAttribute?.DisplayName ?? prop.Name, filterAttribute?.IsFilterable ?? true); + }); + + _headers = headers.ToList(); + } + + private async Task OnFilterChanged(FilterMode filterMode, string header) + { + if (_filterModes.TryGetValue(header, out var mode)) + _filterModes[header] = filterMode; + else + _filterModes.Add(header, filterMode); + + await FilterChanged.InvokeAsync(_filterModes); + } +} \ No newline at end of file diff --git a/Launcher/UI/Components/Grid/Grid.razor.css b/Launcher/UI/Components/Grid/Grid.razor.css new file mode 100644 index 0000000..96e0633 --- /dev/null +++ b/Launcher/UI/Components/Grid/Grid.razor.css @@ -0,0 +1,19 @@ +.auto-width-table { + table-layout: auto; + width: 100%; +} + +.auto-width-table th, .auto-width-table td { + white-space: nowrap; + padding: 8px; + text-align: left; +} + +.table-header { + border-bottom: 1px solid black; +} + +.table-content { + overflow-y: scroll; + height: 250px; +} diff --git a/Launcher/UI/Components/Grid/Grid.razor.min.css b/Launcher/UI/Components/Grid/Grid.razor.min.css new file mode 100644 index 0000000..74f740a --- /dev/null +++ b/Launcher/UI/Components/Grid/Grid.razor.min.css @@ -0,0 +1 @@ +.auto-width-table{table-layout:auto;width:100%;}.auto-width-table th,.auto-width-table td{white-space:nowrap;padding:8px;text-align:left;}.table-header{border-bottom:1px solid #000;}.table-content{overflow-y:scroll;height:250px;} \ No newline at end of file diff --git a/Launcher/UI/Components/Grid/Grid.razor.scss b/Launcher/UI/Components/Grid/Grid.razor.scss new file mode 100644 index 0000000..daf24c1 --- /dev/null +++ b/Launcher/UI/Components/Grid/Grid.razor.scss @@ -0,0 +1,19 @@ +.auto-width-table { + table-layout: auto; + width: 100%; +} + +.auto-width-table th, .auto-width-table td { + white-space: nowrap; + padding: 8px; + text-align: left; +} + +.table-header { + border-bottom: 1px solid black; +} + +.table-content { + overflow-y: scroll; + height: 250px; +} \ No newline at end of file diff --git a/Launcher/UI/Components/Grid/GridHeader.cs b/Launcher/UI/Components/Grid/GridHeader.cs new file mode 100644 index 0000000..4c8a9de --- /dev/null +++ b/Launcher/UI/Components/Grid/GridHeader.cs @@ -0,0 +1,13 @@ +namespace Launcher.UI.Components.Grid; + +public class GridHeaderInfo +{ + public string Title { get; set; } + public bool AllowFiltering { get; set; } + + public GridHeaderInfo(string title, bool allowFiltering) + { + Title = title; + AllowFiltering = allowFiltering; + } +} diff --git a/Launcher/UI/Components/Grid/GridHeader.razor b/Launcher/UI/Components/Grid/GridHeader.razor new file mode 100644 index 0000000..00c7563 --- /dev/null +++ b/Launcher/UI/Components/Grid/GridHeader.razor @@ -0,0 +1,48 @@ +@using Launcher.Enums + + + + + +@code { + /// + /// Gets or sets the contents of the grid row header. + /// + [Parameter] + public string Title { get; set; } = default!; + + [Parameter] + public bool AllowFiltering { get; set; } + + [Parameter] + public EventCallback FilterChanged { get; set; } + + [Parameter] + public FilterMode FilterMode { get; set; } = FilterMode.None; + + private string _filterClass => AllowFiltering ? "filter-btn" : "filter-disabled"; + + private SvgIcon _icon => this.FilterMode switch + { + FilterMode.Ascending => SvgIcon.ChevronUp, + FilterMode.Descending => SvgIcon.ChevronDown, + _ => SvgIcon.None + }; + + private async Task OnFilterClicked() + { + FilterMode = FilterMode switch + { + FilterMode.None => FilterMode.Ascending, + FilterMode.Ascending => FilterMode.Descending, + FilterMode.Descending => FilterMode.None, + _ => FilterMode.None + }; + + if (AllowFiltering) + await FilterChanged.InvokeAsync(FilterMode); + } +} diff --git a/Launcher/UI/Components/Grid/GridHeader.razor.css b/Launcher/UI/Components/Grid/GridHeader.razor.css new file mode 100644 index 0000000..642257e --- /dev/null +++ b/Launcher/UI/Components/Grid/GridHeader.razor.css @@ -0,0 +1,15 @@ +.btn { + background: transparent; + border: none; + padding: 0; +} + +.filter-btn { + display: flex; + align-items: center; +} + +.filter-disabled { + cursor: none; + pointer-events: none; +} diff --git a/Launcher/UI/Components/Grid/GridHeader.razor.min.css b/Launcher/UI/Components/Grid/GridHeader.razor.min.css new file mode 100644 index 0000000..b5f165e --- /dev/null +++ b/Launcher/UI/Components/Grid/GridHeader.razor.min.css @@ -0,0 +1 @@ +.btn{background:transparent;border:0;padding:0;}.filter-btn{display:flex;align-items:center;}.filter-disabled{cursor:none;pointer-events:none;} \ No newline at end of file diff --git a/Launcher/UI/Components/Grid/GridHeader.razor.scss b/Launcher/UI/Components/Grid/GridHeader.razor.scss new file mode 100644 index 0000000..e0f25a0 --- /dev/null +++ b/Launcher/UI/Components/Grid/GridHeader.razor.scss @@ -0,0 +1,15 @@ +.btn { + background: transparent; + border: none; + padding: 0; +} + +.filter-btn { + display: flex; + align-items: center; +} + +.filter-disabled { + cursor: none; + pointer-events: none; +} \ No newline at end of file diff --git a/Launcher/UI/Components/GridRow.razor b/Launcher/UI/Components/Grid/GridRow.razor similarity index 100% rename from Launcher/UI/Components/GridRow.razor rename to Launcher/UI/Components/Grid/GridRow.razor diff --git a/Launcher/UI/Components/Icon.razor b/Launcher/UI/Components/Icon.razor index 8d0dcce..ee88315 100644 --- a/Launcher/UI/Components/Icon.razor +++ b/Launcher/UI/Components/Icon.razor @@ -1,4 +1,6 @@ -@switch (IconType) +@using Launcher.Enums + +@switch (IconType) { case SvgIcon.Home: @@ -38,6 +40,23 @@ break; + case SvgIcon.ChevronDown: + + + + + + + break; + case SvgIcon.ChevronUp: + + + + + + + + break; default: break; } diff --git a/Launcher/UI/Components/Layout.razor b/Launcher/UI/Components/Layout.razor index 21bba39..5979b20 100644 --- a/Launcher/UI/Components/Layout.razor +++ b/Launcher/UI/Components/Layout.razor @@ -1,14 +1,19 @@ -@using Launcher.UI.Components.Navigation +@using Launcher.Enums +@using Launcher.UI.Components.Dialogs @using Launcher.UI.Components.Flyouts +@using Launcher.UI.Components.Navigation @inherits LayoutComponentBase
+ + -
+ +
@Body
diff --git a/Launcher/UI/Components/Navigation/SideBarItem.razor b/Launcher/UI/Components/Navigation/SideBarItem.razor index a34d252..7d324f4 100644 --- a/Launcher/UI/Components/Navigation/SideBarItem.razor +++ b/Launcher/UI/Components/Navigation/SideBarItem.razor @@ -1,4 +1,5 @@ - +@using Launcher.Enums + @code { [Parameter] diff --git a/Launcher/UI/Components/Navigation/SideBarItem.razor.css b/Launcher/UI/Components/Navigation/SideBarItem.razor.css new file mode 100644 index 0000000..5f28270 --- /dev/null +++ b/Launcher/UI/Components/Navigation/SideBarItem.razor.css @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Launcher/UI/Components/Navigation/SideBarItem.razor.min.css b/Launcher/UI/Components/Navigation/SideBarItem.razor.min.css new file mode 100644 index 0000000..5f28270 --- /dev/null +++ b/Launcher/UI/Components/Navigation/SideBarItem.razor.min.css @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Launcher/UI/Components/Navigation/Sidebar.razor b/Launcher/UI/Components/Navigation/Sidebar.razor index 19ae0d8..58495a2 100644 --- a/Launcher/UI/Components/Navigation/Sidebar.razor +++ b/Launcher/UI/Components/Navigation/Sidebar.razor @@ -1,5 +1,5 @@ - - -
- - - @context.Name + + + + +

@context.Name

+

@context.Path

+ @context.LastModified -
+
diff --git a/Launcher/UI/Home.razor.cs b/Launcher/UI/Home.razor.cs index 99af3c2..5e33d0b 100644 --- a/Launcher/UI/Home.razor.cs +++ b/Launcher/UI/Home.razor.cs @@ -1,8 +1,11 @@ using Launcher.Services; using Microsoft.AspNetCore.Components; +using SharpEngine.Shared.Dto; using System.Diagnostics; using System.Text.Json; +using FilterMode = Launcher.Enums.FilterMode; + namespace Launcher.UI { /// Represents the home page of the launcher. @@ -158,5 +161,11 @@ private void RemoveFromList(Project project) Projects.Remove(foundProject); } + + private void OnFiltersChanged(Dictionary filters) + { + _filteredProjects = [.. Projects.FilterBy(filters)]; + StateHasChanged(); + } } } diff --git a/Launcher/UI/Home.razor.css b/Launcher/UI/Home.razor.css index ffb5a06..dfc3ab4 100644 --- a/Launcher/UI/Home.razor.css +++ b/Launcher/UI/Home.razor.css @@ -34,7 +34,7 @@ display: flex; justify-content: space-between; align-items: center; - margin: 25px; + margin: 25px 0; } .alert-header { diff --git a/Launcher/UI/Home.razor.min.css b/Launcher/UI/Home.razor.min.css index 384ee6f..cb60f75 100644 --- a/Launcher/UI/Home.razor.min.css +++ b/Launcher/UI/Home.razor.min.css @@ -1 +1 @@ -.toast{right:0;transition:transform .5s ease-in-out;}.dialog{left:0;right:0;margin-left:auto;margin-right:auto;width:auto;max-width:90%;}.toast,.dialog{position:absolute;top:50px;}.notification-visible{transform:translateX(0);}.notification-hidden{transform:translateX(100%);}.create-project-dialog-hidden,.confirm-delete-hidden{display:none;}.header{display:flex;justify-content:space-between;align-items:center;margin:25px;}.alert-header{display:flex;justify-content:space-between;}.alert-header h4{padding:0;}.flex-end{justify-content:end;display:flex;gap:8px;}.custom-file-upload{display:inline-block;padding:8px 12px;background-color:#007bff;color:#fff;border-radius:4px;cursor:pointer;}.hidden-input{position:absolute;width:0;height:0;opacity:0;} \ No newline at end of file +.toast{right:0;transition:transform .5s ease-in-out;}.dialog{left:0;right:0;margin-left:auto;margin-right:auto;width:auto;max-width:90%;}.toast,.dialog{position:absolute;top:50px;}.notification-visible{transform:translateX(0);}.notification-hidden{transform:translateX(100%);}.create-project-dialog-hidden,.confirm-delete-hidden{display:none;}.header{display:flex;justify-content:space-between;align-items:center;margin:25px 0;}.alert-header{display:flex;justify-content:space-between;}.alert-header h4{padding:0;}.flex-end{justify-content:end;display:flex;gap:8px;}.custom-file-upload{display:inline-block;padding:8px 12px;background-color:#007bff;color:#fff;border-radius:4px;cursor:pointer;}.hidden-input{position:absolute;width:0;height:0;opacity:0;} \ No newline at end of file diff --git a/Launcher/UI/Home.razor.scss b/Launcher/UI/Home.razor.scss index be215ee..bbdf065 100644 --- a/Launcher/UI/Home.razor.scss +++ b/Launcher/UI/Home.razor.scss @@ -34,7 +34,7 @@ display: flex; justify-content: space-between; align-items: center; - margin: 25px; + margin: 25px 0 ; } .alert-header { diff --git a/Launcher/UI/NaturalStringComparer.cs b/Launcher/UI/NaturalStringComparer.cs new file mode 100644 index 0000000..248c3f5 --- /dev/null +++ b/Launcher/UI/NaturalStringComparer.cs @@ -0,0 +1,67 @@ +using System.Globalization; + +namespace Launcher.UI; + +public class NaturalStringComparer : IComparer +{ + /// + public int Compare(string? s1, string? s2) + { + if (s1 == s2) + return 0; + if (s1 == null) + return -1; + if (s2 == null) + return 1; + + int i = 0, j = 0; + int len1 = s1.Length, len2 = s2.Length; + + while (i < len1 && j < len2) + { + int result = CompareCharacters(s1, s2, ref i, ref j); + if (result != 0) + return result; + } + + // If one string has remaining characters, it is greater + return (len1 - i).CompareTo(len2 - j); + } + + private int CompareCharacters(string s1, string s2, ref int i, ref int j) + { + char c1 = s1[i]; + char c2 = s2[j]; + + // If both characters are digits, compare as numbers + if (char.IsDigit(c1) && char.IsDigit(c2)) + { + int start1 = i; + while (i < s1.Length && char.IsDigit(s1[i])) i++; + int start2 = j; + while (j < s2.Length && char.IsDigit(s2[j])) j++; + + string numStr1 = s1.Substring(start1, i - start1); + string numStr2 = s2.Substring(start2, j - start2); + + // Parse numbers ignoring leading zeros + int num1 = int.Parse(numStr1, CultureInfo.InvariantCulture); + int num2 = int.Parse(numStr2, CultureInfo.InvariantCulture); + + if (num1 != num2) + return num1.CompareTo(num2); + + return 0; + } + + // Compare characters case-insensitively + int result = char.ToUpperInvariant(c1).CompareTo(char.ToUpperInvariant(c2)); + if (result != 0) + return result; + + i++; + j++; + + return 0; + } +} diff --git a/Launcher/UI/OrderedEnumerableExtensions.cs b/Launcher/UI/OrderedEnumerableExtensions.cs new file mode 100644 index 0000000..ba8ac20 --- /dev/null +++ b/Launcher/UI/OrderedEnumerableExtensions.cs @@ -0,0 +1,37 @@ +using Launcher.UI; +using SharpEngine.Shared.Dto; +using SharpEngine.Shared.Extensions; + +using FilterMode = Launcher.Enums.FilterMode; + +public static class OrderedEnumerableExtensions +{ + /// + /// Filters and orders a collection of projects based on specified criteria. + /// + /// The collection of projects to be filtered and ordered. + /// The names of properties and their corresponding filter modes. + /// A filtered collection of projects based on the applied filters. + public static IEnumerable FilterBy(this IEnumerable toFilter, Dictionary filters) + { + var stringComparer = new NaturalStringComparer(); + IOrderedEnumerable? ordered = null; + + foreach (var filter in filters) + { + string keySelector(Project p) => p.GetPropertyValue(filter.Key)?.ToString() ?? string.Empty; + + if (ordered == null) + ordered = filter.Value == FilterMode.Ascending + ? toFilter.OrderBy(keySelector, stringComparer) + : toFilter.OrderByDescending(keySelector, stringComparer); + + else + ordered = filter.Value == FilterMode.Ascending + ? ordered.ThenBy(keySelector, stringComparer) + : ordered.ThenByDescending(keySelector, stringComparer); + } + + return ordered ?? toFilter; + } +} diff --git a/Launcher/UI/_Imports.razor b/Launcher/UI/_Imports.razor index 5047218..a51eaed 100644 --- a/Launcher/UI/_Imports.razor +++ b/Launcher/UI/_Imports.razor @@ -10,4 +10,4 @@ @using Launcher @using Launcher.UI @using Launcher.Services -@using Launcher.UI.Enums +@using Launcher.Enums diff --git a/Launcher/compilerconfig.json b/Launcher/compilerconfig.json index 9fe060d..99824cb 100644 --- a/Launcher/compilerconfig.json +++ b/Launcher/compilerconfig.json @@ -7,10 +7,6 @@ "outputFile": "UI/Home.razor.css", "inputFile": "UI/Home.razor.scss" }, - { - "outputFile": "UI/Components/DiscardIcon.razor.css", - "inputFile": "UI/Components/DiscardIcon.razor.scss" - }, { "outputFile": "wwwroot/css/additional.razor.css", "inputFile": "wwwroot/css/additional.razor.scss" @@ -22,5 +18,21 @@ { "outputFile": "UI/Components/Dialogs/ConfirmDeleteDialog.razor.css", "inputFile": "UI/Components/Dialogs/ConfirmDeleteDialog.razor.scss" + }, + { + "outputFile": "UI/Components/Navigation/SideBarItem.razor.css", + "inputFile": "UI/Components/Navigation/SideBarItem.razor.scss" + }, + { + "outputFile": "UI/Components/Flyouts/Flyout.razor.css", + "inputFile": "UI/Components/Flyouts/Flyout.razor.scss" + }, + { + "outputFile": "UI/Components/Grid.razor.css", + "inputFile": "UI/Components/Grid.razor.scss" + }, + { + "outputFile": "UI/Components/Grid/GridHeader.razor.css", + "inputFile": "UI/Components/Grid/GridHeader.razor.scss" } ] \ No newline at end of file diff --git a/Launcher/wwwroot/css/app.css b/Launcher/wwwroot/css/app.css index a257aed..2196041 100644 --- a/Launcher/wwwroot/css/app.css +++ b/Launcher/wwwroot/css/app.css @@ -103,4 +103,8 @@ p, h1, h4, a, td, tr, div, .prevent-select { display: grid; grid-template-rows: 1fr; grid-template-columns: 50px auto; +} + +p { + margin: 0; } \ No newline at end of file diff --git a/SharpEngine.Shared/Attributes/FilterAttribute.cs b/SharpEngine.Shared/Attributes/FilterAttribute.cs new file mode 100644 index 0000000..4cfd400 --- /dev/null +++ b/SharpEngine.Shared/Attributes/FilterAttribute.cs @@ -0,0 +1,12 @@ +namespace SharpEngine.Shared.Attributes; + +[AttributeUsage(AttributeTargets.Property)] +public class FilterAttribute : Attribute +{ + public bool IsFilterable { get; set; } + + public FilterAttribute(bool isFilterable = true) + { + IsFilterable = isFilterable; + } +} diff --git a/SharpEngine.Shared/Project.cs b/SharpEngine.Shared/Dto/Project.cs similarity index 85% rename from SharpEngine.Shared/Project.cs rename to SharpEngine.Shared/Dto/Project.cs index 5cac973..cf6b427 100644 --- a/SharpEngine.Shared/Project.cs +++ b/SharpEngine.Shared/Dto/Project.cs @@ -1,8 +1,10 @@ -using System.ComponentModel.DataAnnotations; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; using System.Text.Json; using System.Text.Json.Serialization; +using SharpEngine.Shared.Attributes; -namespace Launcher.UI; +namespace SharpEngine.Shared.Dto; /// /// Represents a SharpEngine project. @@ -30,6 +32,8 @@ public class Project /// Gets or sets when the project was last modified. /// [JsonIgnore] + [DisplayName("Last Modified")] + [Filter(false)] public DateTime LastModified { get; set; } = DateTime.Now; /// diff --git a/SharpEngine.Shared/ProcessExtensions.cs b/SharpEngine.Shared/Extensions/ProcessExtensions.cs similarity index 97% rename from SharpEngine.Shared/ProcessExtensions.cs rename to SharpEngine.Shared/Extensions/ProcessExtensions.cs index 00cb0bc..f8d2a36 100644 --- a/SharpEngine.Shared/ProcessExtensions.cs +++ b/SharpEngine.Shared/Extensions/ProcessExtensions.cs @@ -1,7 +1,7 @@ using System.Diagnostics; using System.Runtime.InteropServices; -namespace SharpEngine.Shared; +namespace SharpEngine.Shared.Extensions; /// /// Contains extensions for handling processes. @@ -68,7 +68,7 @@ void SendMessage(string? msg) } }); - Thread thread = new Thread(start); + var thread = new Thread(start); thread.Start(); SendMessage("Editor launched."); diff --git a/SharpEngine.Shared/Extensions/ReflectionExtensions.cs b/SharpEngine.Shared/Extensions/ReflectionExtensions.cs new file mode 100644 index 0000000..081cdc9 --- /dev/null +++ b/SharpEngine.Shared/Extensions/ReflectionExtensions.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpEngine.Shared.Extensions; +public static class ReflectionExtensions +{ + public static object? GetPropertyValue(this T obj, string propertyName) + { + var property = typeof(T).GetProperty(propertyName); + if (property == null) + return null; + + return property.GetValue(obj); + } +} From c66594d962dde0fae20f979706c002b42c6b6465 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sat, 29 Mar 2025 01:49:32 +0200 Subject: [PATCH 17/92] Cleanup --- Core/Entities/GameObject.cs | 8 ++--- Core/Entities/Lights/DirectionalLight.cs | 1 + Core/Entities/Lights/PointLight.cs | 1 + Core/Entities/Lights/SpotLight.cs | 1 + Core/Entities/Properties/Meshes/Mesh.cs | 2 +- Core/Entities/UIElement.cs | 5 ++- Core/Entities/Views/View.cs | 7 ++-- Core/Extensions/CollectionExtensions.cs | 2 +- Core/Math.cs | 2 +- Core/Primitives/PrimitiveFactory.cs | 1 + Core/Scenes/SceneNode.cs | 2 +- Core/Shaders/LampShader.cs | 3 ++ Core/Shaders/LightingShader.cs | 4 ++- Core/Shaders/ShaderService.cs | 4 +-- Core/Shaders/UIShader.cs | 3 ++ Core/Windowing/SilkWindow.cs | 4 +-- Core/Windowing/Window.cs | 11 ++++--- Editor/Windows/ActionsMenuWindow.cs | 18 ++++++++--- Editor/Windows/AssetsWindow.cs | 1 - Editor/Windows/ContextMenuWindow.cs | 1 - Examples/MinecraftClone/Program.cs | 2 +- Examples/Minimal/Program.cs | 2 +- Launcher/Attributes/FileAttribute.cs | 2 +- Launcher/Enums/FilterMode.cs | 19 ----------- Launcher/Enums/SvgIcon.cs | 18 +++++++++++ Launcher/TestData/TestData.cs | 16 ++++++---- Launcher/UI/Components/ContextMenu.razor | 21 +++--------- Launcher/UI/Components/ContextMenu.razor.css | 9 ++++++ .../UI/Components/ContextMenu.razor.min.css | 1 + Launcher/UI/Components/ContextMenu.razor.scss | 9 ++++++ .../Dialogs/ConfirmDeleteDialog.razor | 2 +- .../Dialogs/CreateProjectDialog.razor | 4 +-- .../Dialogs/CreateProjectDialog.razor.css | 9 ++++++ .../Dialogs/CreateProjectDialog.razor.min.css | 1 + .../Dialogs/CreateProjectDialog.razor.scss | 9 ++++++ Launcher/UI/Components/Flyouts/Flyout.razor | 6 ++++ Launcher/UI/Components/Flyouts/FlyoutBase.cs | 19 +++++++++++ Launcher/UI/Components/Grid/Grid.razor | 1 + Launcher/UI/Components/Grid/GridHeader.cs | 11 +++++++ Launcher/UI/Components/Grid/GridHeader.razor | 11 +++---- .../UI/Components/Icons/DiscardIcon.razor | 10 ++++++ Launcher/UI/Components/{ => Icons}/Icon.razor | 3 ++ Launcher/UI/Components/Layout.razor | 9 ++---- Launcher/UI/Components/Layout.razor.css | 6 ++++ Launcher/UI/Components/Layout.razor.min.css | 1 + Launcher/UI/Components/Layout.razor.scss | 6 ++++ .../Components/Navigation/SideBarItem.razor | 5 +-- .../Navigation/SideBarItem.razor.css | 6 +++- .../Navigation/SideBarItem.razor.min.css | 2 +- .../Navigation/SideBarItem.razor.scss | 6 ++-- .../UI/Components/Navigation/Sidebar.razor | 5 +-- .../Components/Navigation/Sidebar.razor.css | 6 ++++ .../Navigation/Sidebar.razor.min.css | 1 + .../Components/Navigation/Sidebar.razor.scss | 7 ++++ .../Notification.razor | 14 +++----- .../Notification/Notification.razor.css | 18 +++++++++++ .../Notification/Notification.razor.min.css | 1 + .../Notification/Notification.razor.scss | 18 +++++++++++ .../Notification/NotificationType.cs | 32 +++++++++++++++++++ .../NotificationTypeExtensions.cs} | 32 +------------------ Launcher/UI/Components/Searchbox.razor | 11 ++++--- Launcher/UI/Components/Searchbox.razor.css | 14 ++++++++ .../UI/Components/Searchbox.razor.min.css | 1 + Launcher/UI/Components/Searchbox.razor.scss | 14 ++++++++ Launcher/UI/Home.razor | 14 ++------ Launcher/UI/Home.razor.cs | 5 ++- Launcher/UI/_Imports.razor | 14 +++++++- Launcher/compilerconfig.json | 24 ++++++++++++++ .../Attributes/FilterAttribute.cs | 8 +++++ SharpEngine.Shared/Enums/FilterMode.cs | 16 ++++++++++ .../OrderedEnumerableExtensions.cs | 6 ++-- .../Extensions/ReflectionExtensions.cs | 17 ++++++---- .../NaturalStringComparer.cs | 12 +++++-- 73 files changed, 430 insertions(+), 167 deletions(-) delete mode 100644 Launcher/Enums/FilterMode.cs create mode 100644 Launcher/UI/Components/ContextMenu.razor.css create mode 100644 Launcher/UI/Components/ContextMenu.razor.min.css create mode 100644 Launcher/UI/Components/ContextMenu.razor.scss create mode 100644 Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.css create mode 100644 Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.min.css create mode 100644 Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.scss create mode 100644 Launcher/UI/Components/Icons/DiscardIcon.razor rename Launcher/UI/Components/{ => Icons}/Icon.razor (97%) create mode 100644 Launcher/UI/Components/Layout.razor.css create mode 100644 Launcher/UI/Components/Layout.razor.min.css create mode 100644 Launcher/UI/Components/Layout.razor.scss create mode 100644 Launcher/UI/Components/Navigation/Sidebar.razor.css create mode 100644 Launcher/UI/Components/Navigation/Sidebar.razor.min.css create mode 100644 Launcher/UI/Components/Navigation/Sidebar.razor.scss rename Launcher/UI/Components/{Dialogs => Notification}/Notification.razor (55%) create mode 100644 Launcher/UI/Components/Notification/Notification.razor.css create mode 100644 Launcher/UI/Components/Notification/Notification.razor.min.css create mode 100644 Launcher/UI/Components/Notification/Notification.razor.scss create mode 100644 Launcher/UI/Components/Notification/NotificationType.cs rename Launcher/UI/Components/{Dialogs/NotificationType.cs => Notification/NotificationTypeExtensions.cs} (59%) create mode 100644 Launcher/UI/Components/Searchbox.razor.css create mode 100644 Launcher/UI/Components/Searchbox.razor.min.css create mode 100644 Launcher/UI/Components/Searchbox.razor.scss create mode 100644 SharpEngine.Shared/Enums/FilterMode.cs rename {Launcher/UI => SharpEngine.Shared/Extensions}/OrderedEnumerableExtensions.cs (93%) rename {Launcher/UI => SharpEngine.Shared}/NaturalStringComparer.cs (83%) diff --git a/Core/Entities/GameObject.cs b/Core/Entities/GameObject.cs index 0dbb25f..ba5bdae 100644 --- a/Core/Entities/GameObject.cs +++ b/Core/Entities/GameObject.cs @@ -6,16 +6,16 @@ using SharpEngine.Core.Shaders; using SharpEngine.Core.Textures; using SharpEngine.Core.Windowing; + using Silk.NET.OpenGL; + using System.Collections.Generic; -using System.IO; -using System.Reflection; using System.Threading.Tasks; namespace SharpEngine.Core.Entities; /// -/// Represents a game object in the scene. +/// Represents a game object in the scene. /// public class GameObject : SceneNode { @@ -32,7 +32,7 @@ public GameObject() } /// - /// Initializes a new instance of the with specified textures and shaders. + /// 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. diff --git a/Core/Entities/Lights/DirectionalLight.cs b/Core/Entities/Lights/DirectionalLight.cs index 4fcb63b..d320965 100644 --- a/Core/Entities/Lights/DirectionalLight.cs +++ b/Core/Entities/Lights/DirectionalLight.cs @@ -1,6 +1,7 @@ using SharpEngine.Core.Entities.Properties; using SharpEngine.Core.Extensions; using SharpEngine.Core.Shaders; + using System.Numerics; using System.Threading.Tasks; diff --git a/Core/Entities/Lights/PointLight.cs b/Core/Entities/Lights/PointLight.cs index 858dbf8..0dcdeff 100644 --- a/Core/Entities/Lights/PointLight.cs +++ b/Core/Entities/Lights/PointLight.cs @@ -1,5 +1,6 @@ using SharpEngine.Core.Extensions; using SharpEngine.Core.Shaders; + using System.Numerics; using System.Threading.Tasks; diff --git a/Core/Entities/Lights/SpotLight.cs b/Core/Entities/Lights/SpotLight.cs index 502952d..4a839f0 100644 --- a/Core/Entities/Lights/SpotLight.cs +++ b/Core/Entities/Lights/SpotLight.cs @@ -1,5 +1,6 @@ using SharpEngine.Core.Extensions; using SharpEngine.Core.Shaders; + using System.Numerics; using System.Threading.Tasks; diff --git a/Core/Entities/Properties/Meshes/Mesh.cs b/Core/Entities/Properties/Meshes/Mesh.cs index 5685204..aea061c 100644 --- a/Core/Entities/Properties/Meshes/Mesh.cs +++ b/Core/Entities/Properties/Meshes/Mesh.cs @@ -7,7 +7,7 @@ namespace SharpEngine.Core.Entities.Properties.Meshes; /// public class Mesh { - /// Gets or sets a indetifying name for the mesh. + /// Gets or sets a identifying name for the mesh. public string Name { get; set; } = "New Mesh"; /// diff --git a/Core/Entities/UIElement.cs b/Core/Entities/UIElement.cs index f367df0..2e777b0 100644 --- a/Core/Entities/UIElement.cs +++ b/Core/Entities/UIElement.cs @@ -3,8 +3,8 @@ using SharpEngine.Core.Scenes; using SharpEngine.Core.Shaders; using SharpEngine.Core.Windowing; + using Silk.NET.OpenGL; -using System; using System.Threading.Tasks; namespace SharpEngine.Core.Entities; @@ -62,6 +62,9 @@ public void Initialize() InitializeBuffers(); } + /// + /// Binds the VAO to the current context. + /// public void Bind() { Window.GL.BindVertexArray(_vertexArrayObject); diff --git a/Core/Entities/Views/View.cs b/Core/Entities/Views/View.cs index 8f78b02..88992a0 100644 --- a/Core/Entities/Views/View.cs +++ b/Core/Entities/Views/View.cs @@ -21,7 +21,6 @@ public View(IViewSettings settings) Settings = settings; } - // Those vectors are directions pointing outwards from the camera to define how it rotated. protected Vector3 _front = -Vector3.UnitZ; protected Vector3 _up = Vector3.UnitY; protected Vector3 _right = Vector3.UnitX; @@ -35,15 +34,15 @@ public View(IViewSettings settings) /// Gets the right vector of the camera. public Vector3 Right => _right; + /// Gets or sets the position of the camera. + public Vector3 Position { get; set; } + /// Gets or sets the settings for the view. public IViewSettings Settings { get; set; } /// Gets or sets the aspect ratio of the viewport, used for the projection matrix. public float AspectRatio { get; set; } - /// Gets or sets the position of the camera. - public Vector3 Position { get; set; } - private protected bool firstMove; private protected Vector2 lastPos; diff --git a/Core/Extensions/CollectionExtensions.cs b/Core/Extensions/CollectionExtensions.cs index aab5eb9..fa8686d 100644 --- a/Core/Extensions/CollectionExtensions.cs +++ b/Core/Extensions/CollectionExtensions.cs @@ -13,7 +13,7 @@ public static class CollectionExtensions /// /// The type of the item. /// The item which is being checked if it's in the collection. - /// The collection where the item's existance is being checked. + /// The collection where the item's existence is being checked. /// if the item is in the collection; otherwise, . public static bool IsAnyOf(this T item, params T[] items) => items.Contains(item); diff --git a/Core/Math.cs b/Core/Math.cs index 102f871..7b74cad 100644 --- a/Core/Math.cs +++ b/Core/Math.cs @@ -40,7 +40,7 @@ public static float DegreesToRadians(float degrees) /// Converts a value in to degrees. /// /// The radians to convert. - /// The given as degress. + /// The given as degrees. public static float RadiansToDegrees(float radians) => radians * (180 / MathF.PI); } diff --git a/Core/Primitives/PrimitiveFactory.cs b/Core/Primitives/PrimitiveFactory.cs index 38ec50e..2c9e437 100644 --- a/Core/Primitives/PrimitiveFactory.cs +++ b/Core/Primitives/PrimitiveFactory.cs @@ -1,6 +1,7 @@ using SharpEngine.Core.Entities; using SharpEngine.Core.Entities.Properties; using SharpEngine.Core.Extensions; + using System; using System.Numerics; diff --git a/Core/Scenes/SceneNode.cs b/Core/Scenes/SceneNode.cs index 5644ac3..1fdcee6 100644 --- a/Core/Scenes/SceneNode.cs +++ b/Core/Scenes/SceneNode.cs @@ -16,7 +16,7 @@ public class SceneNode /// /// Gets or sets the children of the node. /// - public List Children { get; set; } = new(); + public List Children { get; set; } = []; /// /// Initializes a new empty . diff --git a/Core/Shaders/LampShader.cs b/Core/Shaders/LampShader.cs index b28730f..844141e 100644 --- a/Core/Shaders/LampShader.cs +++ b/Core/Shaders/LampShader.cs @@ -7,6 +7,9 @@ namespace SharpEngine.Core.Shaders; internal class LampShader : ShaderBase { + /// + /// Initializes a new instance of . + /// public LampShader() { Shader = ShaderService.Instance.LoadShader(PathExtensions.GetAssemblyPath("Shaders/shader.vert"), PathExtensions.GetAssemblyPath("Shaders/shader.frag"), "lamp"); diff --git a/Core/Shaders/LightingShader.cs b/Core/Shaders/LightingShader.cs index 17e7a9f..4701d04 100644 --- a/Core/Shaders/LightingShader.cs +++ b/Core/Shaders/LightingShader.cs @@ -2,12 +2,14 @@ using SharpEngine.Core.Extensions; using SharpEngine.Core.Windowing; using Silk.NET.OpenGL; -using System; namespace SharpEngine.Core.Shaders; internal class LightingShader : ShaderBase { + /// + /// Initializes a new instance of . + /// public LightingShader() { Shader = ShaderService.Instance.LoadShader(PathExtensions.GetAssemblyPath("Shaders/shader.vert"), PathExtensions.GetAssemblyPath("Shaders/lighting.frag"), "lighting"); diff --git a/Core/Shaders/ShaderService.cs b/Core/Shaders/ShaderService.cs index db685b3..6a27cb8 100644 --- a/Core/Shaders/ShaderService.cs +++ b/Core/Shaders/ShaderService.cs @@ -15,7 +15,7 @@ public class ShaderService public static ShaderService Instance { get; } = new ShaderService(); // TODO: Cache data is never set - private readonly Dictionary _shaderCache = new(); + private readonly Dictionary _shaderCache = []; /// /// Gets or sets whether there are shaders to load. @@ -34,7 +34,7 @@ private ShaderService() { } public List GetAll() { HasShadersToLoad = false; - return new(_shaderCache.Values); + return [.. _shaderCache.Values]; } /// diff --git a/Core/Shaders/UIShader.cs b/Core/Shaders/UIShader.cs index de44857..a72a726 100644 --- a/Core/Shaders/UIShader.cs +++ b/Core/Shaders/UIShader.cs @@ -6,6 +6,9 @@ namespace SharpEngine.Core.Shaders; internal class UIShader : ShaderBase { + /// + /// Initializes a new instance of . + /// public UIShader() { Shader = new Shader(PathExtensions.GetAssemblyPath("Shaders/uiShader.vert"), PathExtensions.GetAssemblyPath("Shaders/uiShader.frag"), "ui"); diff --git a/Core/Windowing/SilkWindow.cs b/Core/Windowing/SilkWindow.cs index 4dc8267..64ae012 100644 --- a/Core/Windowing/SilkWindow.cs +++ b/Core/Windowing/SilkWindow.cs @@ -217,9 +217,9 @@ public IWindow CreateWindow(WindowOptions opts) // public static T Create(WindowOptions opts) where T : SilkWindow, new() // { // var instance = new T(); - // var winndow = instance.CreateWindow(opts); + // var window = instance.CreateWindow(opts); // - // instance.CurrentWindow = winndow; + // instance.CurrentWindow = window; // return instance; // } diff --git a/Core/Windowing/Window.cs b/Core/Windowing/Window.cs index 6be21ca..f4ebdee 100644 --- a/Core/Windowing/Window.cs +++ b/Core/Windowing/Window.cs @@ -3,7 +3,6 @@ using SharpEngine.Core.Entities.Views.Settings; using SharpEngine.Core.Enums; using SharpEngine.Core.Extensions; -using SharpEngine.Core.Interfaces; using SharpEngine.Core.Renderers; using SharpEngine.Core.Scenes; using SharpEngine.Core.Shaders; @@ -33,8 +32,14 @@ public class Window : SilkWindow private IEnumerable _renderers = []; private ImGuiController? _imGuiController; + /// + /// Gets or sets the view for the window. + /// public readonly CameraView Camera; + /// + /// Gets the settings for the current window. + /// public IViewSettings Settings; /// The event executed when mouse events are executed. @@ -67,8 +72,7 @@ public class Window : SilkWindow /// The OpenGL context for this window. public static GL GetGL() => GL; private static void SetGL(GL gl) => GL = gl; - public Window() { } - + /// /// Initializes a new instance of . /// @@ -99,7 +103,6 @@ public Window(Scene scene, IViewSettings settings) private bool _windowInitialized; - // public void Initialize() where T : SilkWindow, new() private void Initialize() { CurrentWindow = CreateWindow(Settings.WindowOptions); diff --git a/Editor/Windows/ActionsMenuWindow.cs b/Editor/Windows/ActionsMenuWindow.cs index f6471ab..a0e356e 100644 --- a/Editor/Windows/ActionsMenuWindow.cs +++ b/Editor/Windows/ActionsMenuWindow.cs @@ -1,9 +1,9 @@ using ImGuiNET; -using Launcher.UI; using SharpEngine.Core; using SharpEngine.Core.Audio; using SharpEngine.Core.Scenes; using SharpEngine.Shared.Extensions; +using System.Text; namespace SharpEngine.Editor.Windows { @@ -32,16 +32,24 @@ public override void Render() if (ImGui.Button("Play")) StartGame(); + const uint size = 256; + var buffer = new byte[size]; + + ImGui.InputText("Audio path", buffer, size); if (ImGui.Button("Test audio")) - PlayTestAudio(); + PlayTestAudio(Encoding.Default.GetString(buffer)); } - private void PlayTestAudio() + private void PlayTestAudio(string filePath) { - try + if (!File.Exists(filePath)) { - string filePath = ""; // TODO: Replace with absolute path to .wav file. + Debug.LogInformation($"Audio file '{filePath}' does not exist."); + return; + } + try + { var audioPlayer = new WavPlayer(); audioPlayer.AudioProperties.IsLooping = false; diff --git a/Editor/Windows/AssetsWindow.cs b/Editor/Windows/AssetsWindow.cs index ad5d876..9f6f531 100644 --- a/Editor/Windows/AssetsWindow.cs +++ b/Editor/Windows/AssetsWindow.cs @@ -1,5 +1,4 @@ using ImGuiNET; -using Launcher.UI; namespace SharpEngine.Editor.Windows { diff --git a/Editor/Windows/ContextMenuWindow.cs b/Editor/Windows/ContextMenuWindow.cs index 01005fe..ed19afa 100644 --- a/Editor/Windows/ContextMenuWindow.cs +++ b/Editor/Windows/ContextMenuWindow.cs @@ -1,5 +1,4 @@ using ImGuiNET; -using Launcher.UI; using SharpEngine.Core.Entities; using SharpEngine.Core.Primitives; using SharpEngine.Core.Scenes; diff --git a/Examples/MinecraftClone/Program.cs b/Examples/MinecraftClone/Program.cs index 376ee7a..481bbbb 100644 --- a/Examples/MinecraftClone/Program.cs +++ b/Examples/MinecraftClone/Program.cs @@ -18,7 +18,7 @@ private static void Main() Scene scene = new Scene(); Minecraft game = new Minecraft(scene, gameSettings); - using var window = new SharpEngine.Core.Window(game.Camera, scene, game.Camera.Settings); + using var window = new SharpEngine.Core.Windowing.Window(game.Camera, scene, game.Camera.Settings); window.OnLoaded += () => game.Initialize(); window.OnHandleMouse += game.HandleMouse; window.OnUpdate += game.Update; diff --git a/Examples/Minimal/Program.cs b/Examples/Minimal/Program.cs index b3c78f4..dd6f183 100644 --- a/Examples/Minimal/Program.cs +++ b/Examples/Minimal/Program.cs @@ -19,7 +19,7 @@ public static void Main(string[] _) var game = new Minimal(new DefaultSettings()); var scene = new Scene(); - using var window = new SharpEngine.Core.Window(game.Camera, scene, game.Camera.Settings); + using var window = new SharpEngine.Core.Windowing.Window(game.Camera, scene, game.Camera.Settings); window.Run(); } } diff --git a/Launcher/Attributes/FileAttribute.cs b/Launcher/Attributes/FileAttribute.cs index 0c748ea..fe43381 100644 --- a/Launcher/Attributes/FileAttribute.cs +++ b/Launcher/Attributes/FileAttribute.cs @@ -12,7 +12,7 @@ public class FileAttribute : ValidationAttribute public override bool IsValid(object? value) { if (value is string path) - return System.IO.File.Exists(path); + return File.Exists(path); return false; } diff --git a/Launcher/Enums/FilterMode.cs b/Launcher/Enums/FilterMode.cs deleted file mode 100644 index 06c4bb2..0000000 --- a/Launcher/Enums/FilterMode.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Launcher.Enums; - -public enum FilterMode -{ - /// - /// No filter applied. - /// - None, - - /// - /// Filter in ascending order. - /// - Ascending, - - /// - /// Filter in descending order. - /// - Descending -} diff --git a/Launcher/Enums/SvgIcon.cs b/Launcher/Enums/SvgIcon.cs index d2ce8f4..650ac01 100644 --- a/Launcher/Enums/SvgIcon.cs +++ b/Launcher/Enums/SvgIcon.cs @@ -1,13 +1,31 @@ namespace Launcher.Enums; +/// +/// Contains the supported SVG icons. +/// public enum SvgIcon { + /// Indicates no icon. None, + + /// Indicates the home icon. Home, + + /// Indicates the settings icon. Cog, + + /// Indicates the plus icon. Discard, + + /// Indicates the search lens icon. Lens, + + /// Indicates the close 'x' icon. Close, + + /// Indicates the chevron '<' down icon. ChevronDown, + + /// Indicates the chevron '<' up icon. ChevronUp, } diff --git a/Launcher/TestData/TestData.cs b/Launcher/TestData/TestData.cs index 18344e6..0643b85 100644 --- a/Launcher/TestData/TestData.cs +++ b/Launcher/TestData/TestData.cs @@ -1,18 +1,22 @@ using SharpEngine.Shared.Dto; namespace Launcher.TestData; + +/// +/// Contains test data for the launcher. +/// public static class TestData { + /// Indicates whether test data should be loaded. public const bool LoadTestData = true; + /// Indicates whether to simulate loading. public const bool SimulateLoading = false; - public static IEnumerable Projects = Enumerable.Range(0, 25).Select(i => + /// A collection of test data projects. + public static IEnumerable Projects = Enumerable.Range(0, 25).Select(i => new Project() { - return new Project() - { - Name = $"Project {i}", - Path = @"C:\test", - }; + Name = $"Project {i}", + Path = @"C:\test", }); } diff --git a/Launcher/UI/Components/ContextMenu.razor b/Launcher/UI/Components/ContextMenu.razor index 3e59bc2..6f3d22f 100644 --- a/Launcher/UI/Components/ContextMenu.razor +++ b/Launcher/UI/Components/ContextMenu.razor @@ -1,31 +1,18 @@ @if (showMenu) {
- @ChildContent(Context) + @ChildContent(_context!)
} - - @code { [Inject] - private IJSRuntime JS { get; set; } + private IJSRuntime JS { get; init; } = default!; [Parameter] public RenderFragment ChildContent { get; set; } - public object Context { get; set; } - + private object? _context; private bool showMenu = false; private int menuX, menuY; @@ -38,7 +25,7 @@ menuY = (int)e.ClientY; showMenu = true; - Context = context; + _context = context; // Prevent the default browser context menu JS.InvokeVoidAsync("preventContextMenu"); diff --git a/Launcher/UI/Components/ContextMenu.razor.css b/Launcher/UI/Components/ContextMenu.razor.css new file mode 100644 index 0000000..d0f597f --- /dev/null +++ b/Launcher/UI/Components/ContextMenu.razor.css @@ -0,0 +1,9 @@ +.context-menu { + position: absolute; + z-index: 1000; + background-color: white; + border: 1px solid #ccc; + border-radius: 4px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + padding: 8px; +} diff --git a/Launcher/UI/Components/ContextMenu.razor.min.css b/Launcher/UI/Components/ContextMenu.razor.min.css new file mode 100644 index 0000000..c5c1a48 --- /dev/null +++ b/Launcher/UI/Components/ContextMenu.razor.min.css @@ -0,0 +1 @@ +.context-menu{position:absolute;z-index:1000;background-color:#fff;border:1px solid #ccc;border-radius:4px;box-shadow:0 2px 4px rgba(0,0,0,.1);padding:8px;} \ No newline at end of file diff --git a/Launcher/UI/Components/ContextMenu.razor.scss b/Launcher/UI/Components/ContextMenu.razor.scss new file mode 100644 index 0000000..580b5a7 --- /dev/null +++ b/Launcher/UI/Components/ContextMenu.razor.scss @@ -0,0 +1,9 @@ +.context-menu { + position: absolute; + z-index: 1000; + background-color: white; + border: 1px solid #ccc; + border-radius: 4px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + padding: 8px; +} diff --git a/Launcher/UI/Components/Dialogs/ConfirmDeleteDialog.razor b/Launcher/UI/Components/Dialogs/ConfirmDeleteDialog.razor index 52ed7ad..53bdec2 100644 --- a/Launcher/UI/Components/Dialogs/ConfirmDeleteDialog.razor +++ b/Launcher/UI/Components/Dialogs/ConfirmDeleteDialog.razor @@ -22,7 +22,7 @@ @code { private string _confirmDeleteVisibleClass => Visible ? "confirm-delete-visible" : "confirm-delete-hidden"; - /// Gets or sets the event exectued when the project deletion is confirmed. + /// Gets or sets the event executed when the project deletion is confirmed. [Parameter] public EventCallback OnDeleteProjectConfirmed { get; set; } diff --git a/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor b/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor index 27d5313..5f3275d 100644 --- a/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor +++ b/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor @@ -10,7 +10,7 @@ -
+
@@ -18,7 +18,7 @@
-
+
diff --git a/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.css b/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.css new file mode 100644 index 0000000..a76d394 --- /dev/null +++ b/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.css @@ -0,0 +1,9 @@ +.field-path-container { + display: flex; + align-items: center; + gap: 8px; +} + +.field-name-container { + margin-bottom: 8px; +} diff --git a/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.min.css b/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.min.css new file mode 100644 index 0000000..0ee1ee3 --- /dev/null +++ b/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.min.css @@ -0,0 +1 @@ +.field-path-container{display:flex;align-items:center;gap:8px;}.field-name-container{margin-bottom:8px;} \ No newline at end of file diff --git a/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.scss b/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.scss new file mode 100644 index 0000000..6457dd0 --- /dev/null +++ b/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.scss @@ -0,0 +1,9 @@ +.field-path-container { + display: flex; + align-items: center; + gap: 8px; +} + +.field-name-container { + margin-bottom: 8px; +} \ No newline at end of file diff --git a/Launcher/UI/Components/Flyouts/Flyout.razor b/Launcher/UI/Components/Flyouts/Flyout.razor index efb293e..5fca179 100644 --- a/Launcher/UI/Components/Flyouts/Flyout.razor +++ b/Launcher/UI/Components/Flyouts/Flyout.razor @@ -22,21 +22,27 @@
@code { + /// Gets or sets the header content. [Parameter] public RenderFragment Header { get; set; } + /// Gets or sets the main content. [Parameter] public RenderFragment Content { get; set; } + /// Gets or sets the footer content. [Parameter] public RenderFragment Footer { get; set; } + /// Gets or sets the title. [Parameter] public string Title { get; set; } = default!; + /// Gets or sets whether the flyout is visible. [Parameter] public bool IsVisible { get; set; } + /// Gets or sets the event executed when the visibility changes. [Parameter] public EventCallback IsVisibleChanged { get; set; } diff --git a/Launcher/UI/Components/Flyouts/FlyoutBase.cs b/Launcher/UI/Components/Flyouts/FlyoutBase.cs index ed720a2..0d0d302 100644 --- a/Launcher/UI/Components/Flyouts/FlyoutBase.cs +++ b/Launcher/UI/Components/Flyouts/FlyoutBase.cs @@ -2,23 +2,42 @@ namespace Launcher.UI.Components.Flyouts; +/// +/// Represents a base class for flyout components. +/// public class FlyoutBase : ComponentBase { + /// Gets or sets whether the flyout is visible. [Parameter] public bool IsVisible { get; set; } + /// Gets or sets the event executed when the visibility changes. [Parameter] public EventCallback IsVisibleChanged { get; set; } + /// Gets or sets the event executed when the flyout is closed. [Parameter] public EventCallback OnClose { get; set; } + /// + /// Handles changes in visibility asynchronously and updates the visibility state. + /// + /// Indicates whether the element is currently visible or not. + /// + /// A representing an asynchronous operation. + /// public virtual async Task OnIsVisibleChangedAsync(bool visibility) { IsVisible = visibility; await IsVisibleChanged.InvokeAsync(visibility); } + /// + /// Closes the flyout. + /// + /// + /// A representing an asynchronous operation. + /// public virtual async Task Close() { await OnClose.InvokeAsync(); diff --git a/Launcher/UI/Components/Grid/Grid.razor b/Launcher/UI/Components/Grid/Grid.razor index 5050b38..2b23f84 100644 --- a/Launcher/UI/Components/Grid/Grid.razor +++ b/Launcher/UI/Components/Grid/Grid.razor @@ -51,6 +51,7 @@ private List _headers { get; set; } = []; private Dictionary _filterModes { get; set; } = new(); + /// protected override Task OnInitializedAsync() { GetHeaders(); diff --git a/Launcher/UI/Components/Grid/GridHeader.cs b/Launcher/UI/Components/Grid/GridHeader.cs index 4c8a9de..91e07ec 100644 --- a/Launcher/UI/Components/Grid/GridHeader.cs +++ b/Launcher/UI/Components/Grid/GridHeader.cs @@ -1,10 +1,21 @@ namespace Launcher.UI.Components.Grid; +/// +/// Contains information about a grid header. +/// public class GridHeaderInfo { + /// Gets or sets the title of the column. public string Title { get; set; } + + /// Gets or sets whether the column allows filtering. public bool AllowFiltering { get; set; } + /// + /// Initializes a new instance of the . + /// + /// Specifies the header title for the grid. + /// Indicates whether filtering is permitted on the grid header. public GridHeaderInfo(string title, bool allowFiltering) { Title = title; diff --git a/Launcher/UI/Components/Grid/GridHeader.razor b/Launcher/UI/Components/Grid/GridHeader.razor index 00c7563..e5a8481 100644 --- a/Launcher/UI/Components/Grid/GridHeader.razor +++ b/Launcher/UI/Components/Grid/GridHeader.razor @@ -1,6 +1,4 @@ -@using Launcher.Enums - - + - + @code { + /// Gets or sets the value of the search box. [Parameter] public string Value { get; set; } = default!; + /// Gets or sets the event executed when the value of the search box changes. [Parameter] public EventCallback ValueChanged { get; set; } + /// Gets or sets the delay in milliseconds before the value is updated after the user stops typing. [Parameter] public int DebounceDelayMilliseconds { get; set; } = 1000; + /// Gets or sets any extra CSS classes to apply to the search box. [Parameter] public string? CssClass { get; set; } diff --git a/Launcher/UI/Components/Searchbox.razor.css b/Launcher/UI/Components/Searchbox.razor.css new file mode 100644 index 0000000..9f2bc34 --- /dev/null +++ b/Launcher/UI/Components/Searchbox.razor.css @@ -0,0 +1,14 @@ +.searchbox { + border: 1px solid black; + width: 40%; + justify-self: end; +} + +.searchbox-btn { + border: none; + background: none; +} + +.searchbox-input { + border: none; +} diff --git a/Launcher/UI/Components/Searchbox.razor.min.css b/Launcher/UI/Components/Searchbox.razor.min.css new file mode 100644 index 0000000..2641fc8 --- /dev/null +++ b/Launcher/UI/Components/Searchbox.razor.min.css @@ -0,0 +1 @@ +.searchbox{border:1px solid #000;width:40%;justify-self:end;}.searchbox-btn{border:0;background:none;}.searchbox-input{border:0;} \ No newline at end of file diff --git a/Launcher/UI/Components/Searchbox.razor.scss b/Launcher/UI/Components/Searchbox.razor.scss new file mode 100644 index 0000000..4dd8607 --- /dev/null +++ b/Launcher/UI/Components/Searchbox.razor.scss @@ -0,0 +1,14 @@ +.searchbox { + border: 1px solid black; + width: 40%; + justify-self: end; +} + +.searchbox-btn { + border: none; + background: none; +} + +.searchbox-input { + border: none; +} \ No newline at end of file diff --git a/Launcher/UI/Home.razor b/Launcher/UI/Home.razor index 1a8c2bb..0eae1e4 100644 --- a/Launcher/UI/Home.razor +++ b/Launcher/UI/Home.razor @@ -1,11 +1,5 @@ @page "/" -@using System.Diagnostics -@using Launcher.UI.Components -@using Launcher.UI.Components.Dialogs -@using Launcher.UI.Components.Grid -@using SharpEngine.Shared.Dto - @@ -30,7 +24,7 @@ @context.LastModified - + @@ -44,8 +38,4 @@ } - - -@code { - private ContextMenu? _contextMenu; -} \ No newline at end of file + \ No newline at end of file diff --git a/Launcher/UI/Home.razor.cs b/Launcher/UI/Home.razor.cs index 5e33d0b..73ff595 100644 --- a/Launcher/UI/Home.razor.cs +++ b/Launcher/UI/Home.razor.cs @@ -1,10 +1,11 @@ using Launcher.Services; +using Launcher.UI.Components; using Microsoft.AspNetCore.Components; using SharpEngine.Shared.Dto; using System.Diagnostics; using System.Text.Json; -using FilterMode = Launcher.Enums.FilterMode; +using FilterMode = SharpEngine.Shared.Enums.FilterMode; namespace Launcher.UI { @@ -20,6 +21,8 @@ public partial class Home : ComponentBase private bool _showConfirmDelete; private bool _showCreateProjectDialog; + private ContextMenu? _contextMenu; + private List Projects { get => _allProjects; diff --git a/Launcher/UI/_Imports.razor b/Launcher/UI/_Imports.razor index a51eaed..ea37d20 100644 --- a/Launcher/UI/_Imports.razor +++ b/Launcher/UI/_Imports.razor @@ -1,5 +1,6 @@ @using System.Net.Http @using System.Net.Http.Json +@using System.Diagnostics @using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Routing @@ -8,6 +9,17 @@ @using Microsoft.JSInterop @using Launcher -@using Launcher.UI @using Launcher.Services @using Launcher.Enums + +@using Launcher.UI +@using Launcher.UI.Components +@using Launcher.UI.Components.Grid +@using Launcher.UI.Components.Notification +@using Launcher.UI.Components.Icons +@using Launcher.UI.Components.Dialogs +@using Launcher.UI.Components.Flyouts +@using Launcher.UI.Components.Navigation + +@using SharpEngine.Shared.Dto +@using SharpEngine.Shared.Enums \ No newline at end of file diff --git a/Launcher/compilerconfig.json b/Launcher/compilerconfig.json index 99824cb..fa73a0f 100644 --- a/Launcher/compilerconfig.json +++ b/Launcher/compilerconfig.json @@ -34,5 +34,29 @@ { "outputFile": "UI/Components/Grid/GridHeader.razor.css", "inputFile": "UI/Components/Grid/GridHeader.razor.scss" + }, + { + "outputFile": "UI/Components/Dialogs/CreateProjectDialog.razor.css", + "inputFile": "UI/Components/Dialogs/CreateProjectDialog.razor.scss" + }, + { + "outputFile": "UI/Components/Navigation/Sidebar.razor.css", + "inputFile": "UI/Components/Navigation/Sidebar.razor.scss" + }, + { + "outputFile": "UI/Components/Notification/Notification.razor.css", + "inputFile": "UI/Components/Notification/Notification.razor.scss" + }, + { + "outputFile": "UI/Components/ContextMenu.razor.css", + "inputFile": "UI/Components/ContextMenu.razor.scss" + }, + { + "outputFile": "UI/Components/Layout.razor.css", + "inputFile": "UI/Components/Layout.razor.scss" + }, + { + "outputFile": "UI/Components/Searchbox.razor.css", + "inputFile": "UI/Components/Searchbox.razor.scss" } ] \ No newline at end of file diff --git a/SharpEngine.Shared/Attributes/FilterAttribute.cs b/SharpEngine.Shared/Attributes/FilterAttribute.cs index 4cfd400..f37af87 100644 --- a/SharpEngine.Shared/Attributes/FilterAttribute.cs +++ b/SharpEngine.Shared/Attributes/FilterAttribute.cs @@ -1,10 +1,18 @@ namespace SharpEngine.Shared.Attributes; +/// +/// Represents a attribute that indicates if a property is filterable. +/// [AttributeUsage(AttributeTargets.Property)] public class FilterAttribute : Attribute { + /// Gets or sets whether the property is filterable in collections. public bool IsFilterable { get; set; } + /// + /// Initializes a new instance of . + /// + /// Determines whether the target property is filterable. public FilterAttribute(bool isFilterable = true) { IsFilterable = isFilterable; diff --git a/SharpEngine.Shared/Enums/FilterMode.cs b/SharpEngine.Shared/Enums/FilterMode.cs new file mode 100644 index 0000000..71d1da1 --- /dev/null +++ b/SharpEngine.Shared/Enums/FilterMode.cs @@ -0,0 +1,16 @@ +namespace SharpEngine.Shared.Enums; + +/// +/// Contains the possible ways to filter a collection. +/// +public enum FilterMode +{ + /// No filter applied. + None, + + /// Filter in ascending order. + Ascending, + + /// Filter in descending order. + Descending +} diff --git a/Launcher/UI/OrderedEnumerableExtensions.cs b/SharpEngine.Shared/Extensions/OrderedEnumerableExtensions.cs similarity index 93% rename from Launcher/UI/OrderedEnumerableExtensions.cs rename to SharpEngine.Shared/Extensions/OrderedEnumerableExtensions.cs index ba8ac20..d6f93d6 100644 --- a/Launcher/UI/OrderedEnumerableExtensions.cs +++ b/SharpEngine.Shared/Extensions/OrderedEnumerableExtensions.cs @@ -1,9 +1,11 @@ using Launcher.UI; using SharpEngine.Shared.Dto; +using SharpEngine.Shared.Enums; using SharpEngine.Shared.Extensions; -using FilterMode = Launcher.Enums.FilterMode; - +/// +/// Handles ordering collections. +/// public static class OrderedEnumerableExtensions { /// diff --git a/SharpEngine.Shared/Extensions/ReflectionExtensions.cs b/SharpEngine.Shared/Extensions/ReflectionExtensions.cs index 081cdc9..a663bf7 100644 --- a/SharpEngine.Shared/Extensions/ReflectionExtensions.cs +++ b/SharpEngine.Shared/Extensions/ReflectionExtensions.cs @@ -1,12 +1,17 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace SharpEngine.Shared.Extensions; -namespace SharpEngine.Shared.Extensions; +/// +/// Contains extensions for reflection. +/// public static class ReflectionExtensions { + /// + /// Gets the value of a property from the given . + /// + /// The type of the object. + /// The object whose property value is being retrieved. + /// The name of the property whose values is being retrieved. + /// The value of the property, if not found. public static object? GetPropertyValue(this T obj, string propertyName) { var property = typeof(T).GetProperty(propertyName); diff --git a/Launcher/UI/NaturalStringComparer.cs b/SharpEngine.Shared/NaturalStringComparer.cs similarity index 83% rename from Launcher/UI/NaturalStringComparer.cs rename to SharpEngine.Shared/NaturalStringComparer.cs index 248c3f5..50b10b7 100644 --- a/Launcher/UI/NaturalStringComparer.cs +++ b/SharpEngine.Shared/NaturalStringComparer.cs @@ -2,6 +2,9 @@ namespace Launcher.UI; +/// +/// Checks if two strings are equal in a natural way. +/// public class NaturalStringComparer : IComparer { /// @@ -28,7 +31,7 @@ public int Compare(string? s1, string? s2) return (len1 - i).CompareTo(len2 - j); } - private int CompareCharacters(string s1, string s2, ref int i, ref int j) + private static int CompareCharacters(string s1, string s2, ref int i, ref int j) { char c1 = s1[i]; char c2 = s2[j]; @@ -37,9 +40,12 @@ private int CompareCharacters(string s1, string s2, ref int i, ref int j) if (char.IsDigit(c1) && char.IsDigit(c2)) { int start1 = i; - while (i < s1.Length && char.IsDigit(s1[i])) i++; + while (i < s1.Length && char.IsDigit(s1[i])) + i++; + int start2 = j; - while (j < s2.Length && char.IsDigit(s2[j])) j++; + while (j < s2.Length && char.IsDigit(s2[j])) + j++; string numStr1 = s1.Substring(start1, i - start1); string numStr2 = s2.Substring(start2, j - start2); From ea21cc98ee15c137c39e670205761dcc2b8a781a Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sat, 29 Mar 2025 18:54:04 +0200 Subject: [PATCH 18/92] Cleanup UIElement mesh data --- Core/Entities/Properties/Meshes/Mesh.cs | 3 ++ .../Entities/Properties/Meshes/MeshService.cs | 6 ++++ .../Properties/{ => Meshes}/VertexData.cs | 4 +-- Core/Entities/UIElement.cs | 29 +++++-------------- Core/Primitives/Cube.cs | 26 +++++++++++++++++ Core/Primitives/Plane.cs | 27 ++++++++++------- Core/Renderers/UIRenderer.cs | 2 -- Core/Shaders/LampShader.cs | 2 +- Core/Shaders/LightingShader.cs | 2 +- Core/Shaders/UIShader.cs | 27 +++++++++++++++-- Core/Shaders/uiShader.frag | 5 ++++ Core/Shaders/uiShader.vert | 12 ++++++-- Editor/Windows/ContextMenuWindow.cs | 6 ++++ Examples/MinecraftClone/Minecraft.cs | 2 +- 14 files changed, 109 insertions(+), 44 deletions(-) rename Core/Entities/Properties/{ => Meshes}/VertexData.cs (90%) diff --git a/Core/Entities/Properties/Meshes/Mesh.cs b/Core/Entities/Properties/Meshes/Mesh.cs index aea061c..88ca01c 100644 --- a/Core/Entities/Properties/Meshes/Mesh.cs +++ b/Core/Entities/Properties/Meshes/Mesh.cs @@ -27,4 +27,7 @@ public class Mesh /// [Inspector(DisplayInInspector = false)] public float[] TextureCoordinates { get; set; } = []; + + [Inspector(DisplayInInspector = false)] + public uint[] Indices { get; set; } = []; } \ No newline at end of file diff --git a/Core/Entities/Properties/Meshes/MeshService.cs b/Core/Entities/Properties/Meshes/MeshService.cs index 7f7ed06..d50b576 100644 --- a/Core/Entities/Properties/Meshes/MeshService.cs +++ b/Core/Entities/Properties/Meshes/MeshService.cs @@ -1,5 +1,6 @@ using SharpEngine.Core.Windowing; using Silk.NET.OpenGL; +using System; using System.Collections.Generic; namespace SharpEngine.Core.Entities.Properties.Meshes; @@ -37,5 +38,10 @@ public Mesh LoadMesh(string identifier, Mesh mesh) return mesh; } + public Mesh LoadMesh(string identifier, string meshFilePath) + { + throw new NotImplementedException("Loading meshes from files is not currently supported."); + } + // TODO: #3 & #2 Load mesh from file } \ No newline at end of file diff --git a/Core/Entities/Properties/VertexData.cs b/Core/Entities/Properties/Meshes/VertexData.cs similarity index 90% rename from Core/Entities/Properties/VertexData.cs rename to Core/Entities/Properties/Meshes/VertexData.cs index c25e5d4..f9172c2 100644 --- a/Core/Entities/Properties/VertexData.cs +++ b/Core/Entities/Properties/Meshes/VertexData.cs @@ -1,11 +1,11 @@ -namespace SharpEngine.Core.Entities.Properties; +namespace SharpEngine.Core.Entities.Properties.Meshes; /// /// Represents the data of a vertex. /// public struct VertexData { - /// The stride or lenght of the vertex data object. + /// The stride or length of the vertex data object. public const int Stride = 8 * sizeof(float); /// The size of the vertices in the vertex data object. diff --git a/Core/Entities/UIElement.cs b/Core/Entities/UIElement.cs index 2e777b0..592180e 100644 --- a/Core/Entities/UIElement.cs +++ b/Core/Entities/UIElement.cs @@ -21,7 +21,7 @@ public class UIElement : SceneNode public UIElement(string name) { Name = name; - // Mesh = MeshService.Instance.LoadMesh("plane", Primitives.Plane.Mesh); + Mesh = MeshService.Instance.LoadMesh(nameof(Primitives.Plane), Primitives.Plane.Mesh); } private readonly UIShader _uIShader = new(); @@ -29,27 +29,12 @@ public UIElement(string name) /// Gets or sets the 2D space transformation of the UI element. public Transform2D Transform { get; set; } = new() { - Rotation = 180 + //Rotation = 180 + Scale = new System.Numerics.Vector2(0.5f, 0.5f) }; - // TODO: Use actual mesh /// Gets or sets the mesh of the UI element. - public Mesh Mesh { get; set; } // = new(); - - private readonly float[] _vertices = - [ - // Position Texture coordinates - 0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, // top right - 0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom right - -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom left - -0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, // top left - ]; - - private readonly uint[] _indices = - [ - 0, 1, 3, - 1, 2, 3 - ]; + public Mesh Mesh { get; set; } private uint _vertexArrayObject; @@ -74,11 +59,11 @@ private void InitializeBuffers() { var vertexBufferObject = Window.GL.GenBuffer(); Window.GL.BindBuffer(GLEnum.ArrayBuffer, vertexBufferObject); - Window.GL.BufferData(GLEnum.ArrayBuffer, _vertices, GLEnum.StaticDraw); + 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, _indices, GLEnum.StaticDraw); + Window.GL.BufferData(GLEnum.ElementArrayBuffer, Mesh.Indices, GLEnum.StaticDraw); } /// @@ -90,7 +75,7 @@ public override Task Render() _uIShader.Shader.SetMatrix4(ShaderAttributes.Model, Transform.ModelMatrix); - Window.GL.DrawElements(PrimitiveType.Triangles, (uint)_indices.Length, DrawElementsType.UnsignedInt, []); + Window.GL.DrawElements(PrimitiveType.Triangles, (uint)Mesh.Indices.Length, DrawElementsType.UnsignedInt, []); return Task.CompletedTask; } diff --git a/Core/Primitives/Cube.cs b/Core/Primitives/Cube.cs index 6db45cc..7a82896 100644 --- a/Core/Primitives/Cube.cs +++ b/Core/Primitives/Cube.cs @@ -141,6 +141,32 @@ public static class Cube 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f + ], + 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/Core/Primitives/Plane.cs b/Core/Primitives/Plane.cs index 1468423..b7c6911 100644 --- a/Core/Primitives/Plane.cs +++ b/Core/Primitives/Plane.cs @@ -12,24 +12,29 @@ public static class Plane { Vertices = [ - 0.5f, 0.5f, 0.0f, // top right - 0.5f, -0.5f, 0.0f, // bottom right - -0.5f, -0.5f, 0.0f, // bottom left - -0.5f, 0.5f, 0.0f, // top left + 1f, 1f, 0.0f, // top right + 1f, -1f, 0.0f, // bottom right + -1f, -1f, 0.0f, // bottom left + -1f, 1f, 0.0f, // top left ], Normals = - [ - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - ], - TextureCoordinates = [ 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, + ], + TextureCoordinates = + [ + 1.0f, 0.0f, + 1.0f, 0.0f, + 0.0f, 1.0f, + 0.0f, 1.0f, + ], + Indices = + [ + 0, 1, 3, // first triangle + 1, 2, 3, // second triangle ] }; } diff --git a/Core/Renderers/UIRenderer.cs b/Core/Renderers/UIRenderer.cs index 3cb617a..4ae061d 100644 --- a/Core/Renderers/UIRenderer.cs +++ b/Core/Renderers/UIRenderer.cs @@ -57,8 +57,6 @@ private void InitializeVertexArrays() /// public override Task Render() { - return Task.CompletedTask; - try { Window.GL.Disable(EnableCap.DepthTest); diff --git a/Core/Shaders/LampShader.cs b/Core/Shaders/LampShader.cs index 844141e..465ab1c 100644 --- a/Core/Shaders/LampShader.cs +++ b/Core/Shaders/LampShader.cs @@ -1,4 +1,4 @@ -using SharpEngine.Core.Entities.Properties; +using SharpEngine.Core.Entities.Properties.Meshes; using SharpEngine.Core.Extensions; using SharpEngine.Core.Windowing; using Silk.NET.OpenGL; diff --git a/Core/Shaders/LightingShader.cs b/Core/Shaders/LightingShader.cs index 4701d04..e7ee010 100644 --- a/Core/Shaders/LightingShader.cs +++ b/Core/Shaders/LightingShader.cs @@ -1,4 +1,4 @@ -using SharpEngine.Core.Entities.Properties; +using SharpEngine.Core.Entities.Properties.Meshes; using SharpEngine.Core.Extensions; using SharpEngine.Core.Windowing; using Silk.NET.OpenGL; diff --git a/Core/Shaders/UIShader.cs b/Core/Shaders/UIShader.cs index a72a726..99c7b4a 100644 --- a/Core/Shaders/UIShader.cs +++ b/Core/Shaders/UIShader.cs @@ -1,4 +1,5 @@ -using SharpEngine.Core.Extensions; +using SharpEngine.Core.Entities.Properties.Meshes; +using SharpEngine.Core.Extensions; using SharpEngine.Core.Windowing; using Silk.NET.OpenGL; @@ -25,7 +26,29 @@ public override bool SetAttributes() uint vertexLocationUInt = (uint)vertexLocation; Window.GL.EnableVertexAttribArray(vertexLocationUInt); - Window.GL.VertexAttribPointer(vertexLocationUInt, 3, VertexAttribPointerType.Float, false, 6 * sizeof(float), 0); + Window.GL.VertexAttribPointer(vertexLocationUInt, 3, VertexAttribPointerType.Float, false, 8 * sizeof(float), 0); + + /*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/Core/Shaders/uiShader.frag b/Core/Shaders/uiShader.frag index fe3175f..36a7e45 100644 --- a/Core/Shaders/uiShader.frag +++ b/Core/Shaders/uiShader.frag @@ -1,7 +1,12 @@ #version 330 core + +in vec2 TexCoord; out vec4 FragColor; +uniform sampler2D texture1; + void main() { FragColor = vec4(1.0, 0.0, 0.0, 1.0); // set all 4 vector values to 1.0 + // FragColor = texture(texture1, TexCoord); } \ No newline at end of file diff --git a/Core/Shaders/uiShader.vert b/Core/Shaders/uiShader.vert index aa9fdcc..8d97e16 100644 --- a/Core/Shaders/uiShader.vert +++ b/Core/Shaders/uiShader.vert @@ -1,15 +1,23 @@ #version 330 core layout (location = 0) in vec3 aPos; +// layout (location = 1) in vec3 aNormal; +// layout (location = 2) in vec2 aTexCoord; uniform mat4 model; +// uniform mat4 view; +// uniform mat4 projection; out vec3 FragPos; void main() { vec4 pos = vec4(aPos, 1.0); - gl_Position = model * pos; - FragPos = vec3(model * pos); + + // gl_Position = vec4(aPos, 1.0) * model * view * projection; + // FragPos = vec3(vec4(aPos, 1.0) * model); + // TexCoord = aTexCoord; + // Normal = aNormal * mat3(transpose(inverse(model))); + // TexCoords = aTexCoords; } \ No newline at end of file diff --git a/Editor/Windows/ContextMenuWindow.cs b/Editor/Windows/ContextMenuWindow.cs index ed19afa..603b8dc 100644 --- a/Editor/Windows/ContextMenuWindow.cs +++ b/Editor/Windows/ContextMenuWindow.cs @@ -85,6 +85,12 @@ private void RenderSceneActions() Scene.Root.AddChild(cube); } } + + if (ImGui.Button("Empty")) + { + var element = Scene.ActiveElement ?? Scene.Root; + element.AddChild(new SceneNode("Empty")); + } } } } diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index e1311bd..eb102c9 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -136,7 +136,7 @@ private void GenerateChunk(int chunkSize, Vector3 chunkPos) /// public override void Update(double deltaTime, IInputContext input) { - UpdateUI(); + // UpdateUI(); _input.HandleKeyboard(input.Keyboards[0], (float)deltaTime); } From 4b5cf13a1bea2b0d60822581193f8763170e6284 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sat, 29 Mar 2025 19:53:39 +0200 Subject: [PATCH 19/92] Cleanup --- Core/Primitives/PrimitiveFactory.cs | 8 ++--- Core/_Resources/Default.cs | 14 ++++++++ Editor/EditorWindow.cs | 4 +++ Examples/MinecraftClone/Block/Dirt.cs | 8 ++--- Examples/MinecraftClone/Block/Stone.cs | 8 ++--- SharpEngine.Shared/Dto/UserProfile.cs | 47 ++++++++++++++++++++++++++ 6 files changed, 75 insertions(+), 14 deletions(-) create mode 100644 Core/_Resources/Default.cs create mode 100644 SharpEngine.Shared/Dto/UserProfile.cs diff --git a/Core/Primitives/PrimitiveFactory.cs b/Core/Primitives/PrimitiveFactory.cs index 2c9e437..9a63da5 100644 --- a/Core/Primitives/PrimitiveFactory.cs +++ b/Core/Primitives/PrimitiveFactory.cs @@ -12,17 +12,13 @@ namespace SharpEngine.Core.Primitives; /// public static class PrimitiveFactory { - private static string DebugTexture => PathExtensions.GetAssemblyPath("Textures/DefaultTextures/debug.JPG"); - private static string DefaultVertexShader => PathExtensions.GetAssemblyPath("Shaders/shader.vert"); - private static string DefaultFragmentShader => PathExtensions.GetAssemblyPath("Shaders/lighting.frag"); - /// /// Creates a new by the given primitive type. /// /// The type of primitive to create. /// Where the game object should be placed. public static GameObject Create(PrimitiveType primitiveType, Vector3 position) - => Create(primitiveType, position, DebugTexture); + => Create(primitiveType, position, _Resources.Default.DebugTexture); /// /// The type of primitive to be created. @@ -34,7 +30,7 @@ public static GameObject Create(PrimitiveType primitiveType, Vector3 position) /// A new game object. /// Thrown when the specified primitive type does not exist. public static GameObject Create(PrimitiveType primitiveType, Vector3 position, string diffuseMapFile, string? specularMapFile = null, string? vertShaderFile = null, string? fragShaderFile = null) - => new(diffuseMapFile, specularMapFile ?? DebugTexture, vertShaderFile ?? DefaultVertexShader, fragShaderFile ?? DefaultFragmentShader) + => new(diffuseMapFile, specularMapFile ?? _Resources.Default.DebugTexture, vertShaderFile ?? _Resources.Default.VertexShader, fragShaderFile ?? _Resources.Default.FragmentShader) { Transform = new Transform { Position = position }, Mesh = primitiveType switch diff --git a/Core/_Resources/Default.cs b/Core/_Resources/Default.cs new file mode 100644 index 0000000..77dced2 --- /dev/null +++ b/Core/_Resources/Default.cs @@ -0,0 +1,14 @@ +using SharpEngine.Core.Extensions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpEngine.Core._Resources; +public struct Default +{ + public static string DebugTexture => PathExtensions.GetAssemblyPath("Textures\\DefaultTextures\\debug.JPG"); + public static string VertexShader => PathExtensions.GetAssemblyPath("Shaders\\shader.vert"); + public static string FragmentShader => PathExtensions.GetAssemblyPath("Shaders\\lighting.frag"); +} diff --git a/Editor/EditorWindow.cs b/Editor/EditorWindow.cs index 807a5b4..87d99de 100644 --- a/Editor/EditorWindow.cs +++ b/Editor/EditorWindow.cs @@ -209,6 +209,10 @@ private static void RenderFileMenu() { // Handle Exit action } + if (ImGui.MenuItem("Publish")) + { + // Handle Publish action + } ImGui.EndMenu(); } diff --git a/Examples/MinecraftClone/Block/Dirt.cs b/Examples/MinecraftClone/Block/Dirt.cs index 8aada39..edcb5bb 100644 --- a/Examples/MinecraftClone/Block/Dirt.cs +++ b/Examples/MinecraftClone/Block/Dirt.cs @@ -13,10 +13,10 @@ internal class Dirt : BlockBase /// /// The position where the block should be initialized. /// The name of the block to initialize. - public Dirt(Vector3 position, string name) : base(position, name, PathExtensions.GetAssemblyPath("Resources/grass.jpg"), - PathExtensions.GetAssemblyPath("Resources/container2_specular.png"), - PathExtensions.GetAssemblyPath("Shaders/shader.vert"), - PathExtensions.GetAssemblyPath("Shaders/lighting.frag")) { } + public Dirt(Vector3 position, string name) : base(position, name, PathExtensions.GetAssemblyPath("Resources\\grass.jpg"), + PathExtensions.GetAssemblyPath("Resources\\container2_specular.png"), + PathExtensions.GetAssemblyPath("Shaders\\shader.vert"), + PathExtensions.GetAssemblyPath("Shaders\\lighting.frag")) { } /// public override BlockType BlockType => BlockType.Dirt; diff --git a/Examples/MinecraftClone/Block/Stone.cs b/Examples/MinecraftClone/Block/Stone.cs index 08dc773..599c086 100644 --- a/Examples/MinecraftClone/Block/Stone.cs +++ b/Examples/MinecraftClone/Block/Stone.cs @@ -13,10 +13,10 @@ internal class Stone : BlockBase /// /// The position where the block is created. /// The name of the object in the scene. - public Stone(Vector3 position, string name) : base(position, name, PathExtensions.GetAssemblyPath("Resources/container2.png"), - PathExtensions.GetAssemblyPath("Resources/container2_specular.png"), - PathExtensions.GetAssemblyPath("Shaders/shader.vert"), - PathExtensions.GetAssemblyPath("Shaders/lighting.frag")) { } + public Stone(Vector3 position, string name) : base(position, name, PathExtensions.GetAssemblyPath("Resources\\container2.png"), + PathExtensions.GetAssemblyPath("Resources\\container2_specular.png"), + PathExtensions.GetAssemblyPath("Shaders\\shader.vert"), + PathExtensions.GetAssemblyPath("Shaders\\lighting.frag")) { } /// public override BlockType BlockType => BlockType.Stone; diff --git a/SharpEngine.Shared/Dto/UserProfile.cs b/SharpEngine.Shared/Dto/UserProfile.cs new file mode 100644 index 0000000..6235570 --- /dev/null +++ b/SharpEngine.Shared/Dto/UserProfile.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpEngine.Shared.Dto; + +public class UserProfile +{ + public string Username { get; set; } = default!; + public string Email { get; set; } = default!; + public string Password + { + get => _password; + set => SetPassword(value); + } + + private string _password; + + public List LinkedSocialMedia { get; set; } = []; + + public List Projects { get; set; } = []; + + public List Achievements { get; set; } = []; + + private void SetPassword(string pwd) + { + // TODO: Figure out a good way to handle encryption + _password = pwd; + } +} + +public class SocialMedia +{ + public string Name { get; set; } + public string Url { get; set; } +} + +public class Achievement +{ + public string Name { get; set; } + public string Description { get; set; } + public DateTime? DateAchieved { get; set; } + + public bool IsAchieved => DateAchieved.HasValue; +} From 8bd4c98f50417e4f15425b602e3ab9395296d4d4 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sat, 29 Mar 2025 20:04:14 +0200 Subject: [PATCH 20/92] Texturing improvements --- Core/Entities/GameObject.cs | 30 +++++++++++++++------------- Core/Entities/Properties/Material.cs | 7 +++++-- Core/Primitives/PrimitiveFactory.cs | 2 +- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/Core/Entities/GameObject.cs b/Core/Entities/GameObject.cs index ba5bdae..7f8b0d6 100644 --- a/Core/Entities/GameObject.cs +++ b/Core/Entities/GameObject.cs @@ -1,7 +1,6 @@ using SharpEngine.Core.Attributes; using SharpEngine.Core.Entities.Properties; using SharpEngine.Core.Entities.Properties.Meshes; -using SharpEngine.Core.Extensions; using SharpEngine.Core.Scenes; using SharpEngine.Core.Shaders; using SharpEngine.Core.Textures; @@ -24,8 +23,9 @@ public class GameObject : SceneNode /// public GameObject() { - var shader = ShaderService.Instance.LoadShader(PathExtensions.GetAssemblyPath("Shaders/shader.vert"), PathExtensions.GetAssemblyPath("Shaders/lighting.frag"), "lighting"); - var diffuse = TextureService.Instance.LoadTexture(PathExtensions.GetAssemblyPath("Textures/DefaultTextures/debug.JPG")); + // TODO: Using lightning shader here will most likely break stuff, it needs to be refactored out. + var shader = ShaderService.Instance.LoadShader(_Resources.Default.VertexShader, _Resources.Default.FragmentShader, "lighting"); + var diffuse = TextureService.Instance.LoadTexture(_Resources.Default.DebugTexture); Material = new(shader, diffuse); BoundingBox = BoundingBox.CalculateBoundingBox(Transform); @@ -38,16 +38,12 @@ public GameObject() /// The file path of the specular map texture. /// The file path of the vertex shader. /// The file path of the fragment shader. - public GameObject(string diffuseMapFile, string specularMapFile, string vertShaderFile, string fragShaderFile) + public GameObject(string? diffuseMapFile = null, string? specularMapFile = null, string? vertShaderFile = null, string? fragShaderFile = null) { - var diffuse = TextureService.Instance.LoadTexture(diffuseMapFile); - var specularMap = TextureService.Instance.LoadTexture(specularMapFile); - var shader = ShaderService.Instance.LoadShader(vertShaderFile, fragShaderFile, "lighting"); - - Material = new Material(shader, diffuse) - { - SpecularMap = specularMap - }; + var shader = ShaderService.Instance.LoadShader(vertShaderFile ?? _Resources.Default.VertexShader, fragShaderFile ?? _Resources.Default.FragmentShader, "lighting"); + var diffuse = TextureService.Instance.LoadTexture(diffuseMapFile ?? _Resources.Default.DebugTexture); + var specular = string.IsNullOrEmpty(specularMapFile) ? null : TextureService.Instance.LoadTexture(specularMapFile!); + Material = new Material(shader, diffuse, specular); BoundingBox = BoundingBox.CalculateBoundingBox(Transform); } @@ -90,15 +86,21 @@ public override Task Render() Material.DiffuseMap.Use(TextureUnit.Texture0); Material.Shader.SetInt("material.diffuse", Material.diffuseUnit); - if (Material.SpecularMap is not null) + if (Material.UseSpecularMap) { Material.SpecularMap.Use(TextureUnit.Texture1); Material.Shader.SetInt("material.specular", Material.specularUnit); Material.Shader.SetVector3("material.specular", Material.Specular); Material.Shader.SetFloat("material.shininess", Material.Shininess); } + else + { + Material.Shader.SetInt("material.specular", 0); + Material.Shader.SetVector3("material.specular", new System.Numerics.Vector3(0)); + Material.Shader.SetFloat("material.shininess", 0); + } - Material.Shader.SetMatrix4(ShaderAttributes.Model, Transform.ModelMatrix); + Material.Shader.SetMatrix4(ShaderAttributes.Model, Transform.ModelMatrix); Window.GL.DrawArrays(PrimitiveType.Triangles, 0, 36); return Task.CompletedTask; diff --git a/Core/Entities/Properties/Material.cs b/Core/Entities/Properties/Material.cs index b30f02b..b744d51 100644 --- a/Core/Entities/Properties/Material.cs +++ b/Core/Entities/Properties/Material.cs @@ -12,10 +12,11 @@ public class Material /// /// Initializes a new instance of . /// - public Material(Shader shader, Texture diffuseMap) + public Material(Shader shader, Texture diffuseMap, Texture? specularMap = null) { Shader = shader; DiffuseMap = diffuseMap; + SpecularMap = specularMap ?? diffuseMap; Specular = new(0.5f, 0.5f, 0.5f); Shininess = 32.0f; @@ -29,7 +30,9 @@ public Material(Shader shader, Texture diffuseMap) /// /// Gets or sets the specular map texture. /// - public Texture? SpecularMap { get; set; } + public Texture SpecularMap { get; set; } + + public bool UseSpecularMap => SpecularMap.Handle != DiffuseMap.Handle; /// /// Gets or sets the shader used to render the material. diff --git a/Core/Primitives/PrimitiveFactory.cs b/Core/Primitives/PrimitiveFactory.cs index 9a63da5..497861e 100644 --- a/Core/Primitives/PrimitiveFactory.cs +++ b/Core/Primitives/PrimitiveFactory.cs @@ -30,7 +30,7 @@ public static GameObject Create(PrimitiveType primitiveType, Vector3 position) /// A new game object. /// Thrown when the specified primitive type does not exist. public static GameObject Create(PrimitiveType primitiveType, Vector3 position, string diffuseMapFile, string? specularMapFile = null, string? vertShaderFile = null, string? fragShaderFile = null) - => new(diffuseMapFile, specularMapFile ?? _Resources.Default.DebugTexture, vertShaderFile ?? _Resources.Default.VertexShader, fragShaderFile ?? _Resources.Default.FragmentShader) + => new(diffuseMapFile, specularMapFile, vertShaderFile ?? _Resources.Default.VertexShader, fragShaderFile ?? _Resources.Default.FragmentShader) { Transform = new Transform { Position = position }, Mesh = primitiveType switch From 93c02b6302143b6d5773ea27642b62884bb4bbed Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sun, 30 Mar 2025 00:22:01 +0200 Subject: [PATCH 21/92] Add basic layout placeholders --- Core/Entities/UI/Layouts/FlexLayout.cs | 21 ++++++++ Core/Entities/UI/Layouts/GridLayout.cs | 72 ++++++++++++++++++++++++++ Core/Entities/UI/Layouts/LayoutBase.cs | 24 +++++++++ 3 files changed, 117 insertions(+) create mode 100644 Core/Entities/UI/Layouts/FlexLayout.cs create mode 100644 Core/Entities/UI/Layouts/GridLayout.cs create mode 100644 Core/Entities/UI/Layouts/LayoutBase.cs diff --git a/Core/Entities/UI/Layouts/FlexLayout.cs b/Core/Entities/UI/Layouts/FlexLayout.cs new file mode 100644 index 0000000..62f9528 --- /dev/null +++ b/Core/Entities/UI/Layouts/FlexLayout.cs @@ -0,0 +1,21 @@ +using System; +using System.Numerics; + +namespace SharpEngine.Core.Entities.UI.Layouts; + +/// +/// Represents a layout that dynamically distributes items in a flex layout. +/// +/// The type of items in the collection. +public class FlexLayout : LayoutBase +{ + public int Gap { get; set; } + + public int ContentSize { get; set; } + + public Vector2 ContentAreaSize { get; set; } + + /// + /// + public override T[][] GetValues() => throw new NotImplementedException(); +} diff --git a/Core/Entities/UI/Layouts/GridLayout.cs b/Core/Entities/UI/Layouts/GridLayout.cs new file mode 100644 index 0000000..cc0cde2 --- /dev/null +++ b/Core/Entities/UI/Layouts/GridLayout.cs @@ -0,0 +1,72 @@ +using System; + +namespace SharpEngine.Core.Entities.UI.Layouts; + +/// +/// Represents a grid layout. +/// +/// The type of items that can be stored and retrieved within the grid. +public class GridLayout : LayoutBase +{ + /// Gets or sets the amount of rows in the grid. + public uint Rows { get; set; } = 2; + + /// Gets or sets the amount of columns in the grid. + public uint Columns { get; set; } = 3; + + /// + /// Retrieves the item at [, ]. + /// + /// The row where the items should be retrieved. + /// The column where the item should be retrieved. + /// The item at [, ]. + public T this[uint row, uint column] + { + get + { + uint index = GetIndex(row, column); + return Items[(int)index]; + } + set + { + uint index = GetIndex(row, column); + Items[(int)index] = value; + } + } + + /// + /// Calculates the index in the flat list based on row and column. + /// + /// The row where the items should be retrieved. + /// The column where the item should be retrieved. + /// The index of the item at [, ]. + /// + private uint GetIndex(uint row, uint column) + { + if (row < 0 || column < 0 || column >= Columns) + throw new ArgumentOutOfRangeException(nameof(row), "Invalid row or column index."); + + var index = row * Columns + column; + if (index >= Items.Count) + throw new ArgumentOutOfRangeException(nameof(row), "Index exceeds the number of items."); + + return index; + } + + /// + public override T[][] GetValues() + { + var values = new T[Rows][]; + for (uint i = 0; i < Rows; i++) + { + values[i] = new T[Columns]; + for (uint j = 0; j < Columns; j++) + { + var item = this[i, j]; + values[i][j] = item; + } + } + + return values; + } +} diff --git a/Core/Entities/UI/Layouts/LayoutBase.cs b/Core/Entities/UI/Layouts/LayoutBase.cs new file mode 100644 index 0000000..be69994 --- /dev/null +++ b/Core/Entities/UI/Layouts/LayoutBase.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpEngine.Core.Entities.UI.Layouts; + +public abstract class LayoutBase +{ + public List Items; + + public virtual void AddItem(T item) + { + Items.Add(item); + } + + public virtual bool RemoveItem(T item) + { + return Items.Remove(item); + } + + public abstract T[][] GetValues(); +} From d21d76a7610c6328f63b360f6e60ca1323c30cee Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sun, 30 Mar 2025 00:22:18 +0200 Subject: [PATCH 22/92] UI shader testing (WIP) --- Core/Entities/Properties/Transform2D.cs | 14 +++++++------- Core/Entities/{ => UI}/UIElement.cs | 13 +++++++------ Core/Renderers/Renderer.cs | 1 + Core/Renderers/UIRenderer.cs | 8 ++++++-- Core/Scenes/Scene.cs | 2 +- Core/Shaders/Shader.cs | 21 ++++++++++++++++----- Core/Shaders/UIShader.cs | 12 ++---------- Core/SharpEngine.Core.csproj | 2 +- Examples/MinecraftClone/Minecraft.cs | 1 + 9 files changed, 42 insertions(+), 32 deletions(-) rename Core/Entities/{ => UI}/UIElement.cs (87%) diff --git a/Core/Entities/Properties/Transform2D.cs b/Core/Entities/Properties/Transform2D.cs index cbcbbee..7c6ea06 100644 --- a/Core/Entities/Properties/Transform2D.cs +++ b/Core/Entities/Properties/Transform2D.cs @@ -5,27 +5,27 @@ namespace SharpEngine.Core.Entities.Properties; /// /// Represents a game object transformation in 2D space. /// -public class Transform2D +public class Transform2D : Transform { /// /// Gets or sets the position of the game object. /// - public Vector2 Position { get; set; } + public new Vector2 Position { get; set; } /// /// Gets or sets the scale of the game object. /// - public Vector2 Scale { get; set; } = new(1, 1); + public new Vector2 Scale { get; set; } = new(1, 1); /// /// Gets or sets the rotation of the game object. /// - public float Rotation { get; set; } + public new float Rotation { get; set; } /// /// Gets the transformation of the game object as a model matrix. /// - public Matrix4x4 ModelMatrix => Matrix4x4.CreateScale(new Vector3(Scale.X, Scale.Y, 0)) * - Matrix4x4.CreateRotationZ(Rotation) * - Matrix4x4.CreateTranslation(new Vector3(Position.X, Position.Y, 0)); + public new Matrix4x4 ModelMatrix => Matrix4x4.CreateScale(new Vector3(Scale.X, Scale.Y, 0)) * + Matrix4x4.CreateRotationZ(Rotation) * + Matrix4x4.CreateTranslation(new Vector3(Position.X, Position.Y, 0)); } \ No newline at end of file diff --git a/Core/Entities/UIElement.cs b/Core/Entities/UI/UIElement.cs similarity index 87% rename from Core/Entities/UIElement.cs rename to Core/Entities/UI/UIElement.cs index 592180e..f45df13 100644 --- a/Core/Entities/UIElement.cs +++ b/Core/Entities/UI/UIElement.cs @@ -7,12 +7,12 @@ using Silk.NET.OpenGL; using System.Threading.Tasks; -namespace SharpEngine.Core.Entities; +namespace SharpEngine.Core.Entities.UI; /// /// Represents a User Interface entity. /// -public class UIElement : SceneNode +public class UIElement : GameObject { /// /// Initializes a new instance of . @@ -27,14 +27,15 @@ public UIElement(string name) private readonly UIShader _uIShader = new(); /// Gets or sets the 2D space transformation of the UI element. - public Transform2D Transform { get; set; } = new() + public new Transform2D Transform { get; set; } = new() { - //Rotation = 180 - Scale = new System.Numerics.Vector2(0.5f, 0.5f) + //Rotation = 180, + Scale = new System.Numerics.Vector2(0.5f, 0.5f), + //Position = new System.Numerics.Vector2(1, 0), }; /// Gets or sets the mesh of the UI element. - public Mesh Mesh { get; set; } + public new Mesh Mesh { get; set; } private uint _vertexArrayObject; diff --git a/Core/Renderers/Renderer.cs b/Core/Renderers/Renderer.cs index 5fd0a5d..0e80c7d 100644 --- a/Core/Renderers/Renderer.cs +++ b/Core/Renderers/Renderer.cs @@ -49,6 +49,7 @@ public Renderer(CameraView camera, ISettings settings, Scene scene) : base(setti /// public override Task Render() { + return Task.CompletedTask; try { Window.GL.Enable(EnableCap.DepthTest); diff --git a/Core/Renderers/UIRenderer.cs b/Core/Renderers/UIRenderer.cs index 4ae061d..4c5ca18 100644 --- a/Core/Renderers/UIRenderer.cs +++ b/Core/Renderers/UIRenderer.cs @@ -1,4 +1,4 @@ -using SharpEngine.Core.Entities; +using SharpEngine.Core.Entities.UI; using SharpEngine.Core.Entities.Views; using SharpEngine.Core.Interfaces; using SharpEngine.Core.Scenes; @@ -18,6 +18,7 @@ public class UIRenderer : RendererBase { private readonly Scene _scene; private readonly UIShader _uiShader; + private readonly CameraView _camera; /// public override RenderFlags RenderFlag => RenderFlags.UIRenderer; @@ -25,10 +26,11 @@ public class UIRenderer : RendererBase /// /// Initializes a new instance of . /// - public UIRenderer(CameraView _, ISettings settings, Scene scene) : base(settings) + public UIRenderer(CameraView camera, ISettings settings, Scene scene) : base(settings) { _scene = scene; _uiShader = new UIShader(); + _camera = camera; } /// @@ -62,6 +64,8 @@ public override Task Render() Window.GL.Disable(EnableCap.DepthTest); Window.GL.DepthFunc(DepthFunction.Less); + _camera.SetShaderUniforms(_uiShader.Shader!); + foreach (var item in _scene.UIElements) { item.Bind(); diff --git a/Core/Scenes/Scene.cs b/Core/Scenes/Scene.cs index 0370af4..852f9dd 100644 --- a/Core/Scenes/Scene.cs +++ b/Core/Scenes/Scene.cs @@ -1,5 +1,5 @@ using SharpEngine.Core.Entities; - +using SharpEngine.Core.Entities.UI; using System; using System.Collections.Generic; using System.Linq; diff --git a/Core/Shaders/Shader.cs b/Core/Shaders/Shader.cs index 1ea1e8d..259d0bd 100644 --- a/Core/Shaders/Shader.cs +++ b/Core/Shaders/Shader.cs @@ -88,7 +88,6 @@ public Shader(string vertPath, string fragPath, string name) // The shader is now ready to go, but first, we're going to cache all the shader uniform locations. // Querying this from the shader is very slow, so we do it once on initialization and reuse those values // later. - GetUniformLocations(); } @@ -219,6 +218,18 @@ public bool TryGetAttribLocation(string attribName, out int location) // 2. Get a handle to the location of the uniform with GL.GetUniformLocation. // 3. Use the appropriate GL.Uniform* function to set the uniform. + private bool TrySetUniform(string name, T data, Action setter) + { + if (!_uniformLocations.TryGetValue(name, out int uniform)) + { + Console.WriteLine($"Uniform '{name}' not found in shader program."); + return false; + } + + setter(uniform, data); + return true; + } + /// /// Set a uniform int on this shader. /// @@ -227,7 +238,7 @@ public bool TryGetAttribLocation(string attribName, out int location) public void SetInt(string name, int data) { Window.GL.UseProgram(Handle); - Window.GL.Uniform1(_uniformLocations[name], data); + TrySetUniform(name, data, Window.GL.Uniform1); } /// @@ -238,7 +249,7 @@ public void SetInt(string name, int data) public void SetFloat(string name, float data) { Window.GL.UseProgram(Handle); - Window.GL.Uniform1(_uniformLocations[name], data); + TrySetUniform(name, data, Window.GL.Uniform1); } /// @@ -255,7 +266,7 @@ public void SetFloat(string name, float data) public void SetMatrix4(string name, Matrix4x4 data, bool transpose = true) { Window.GL.UseProgram(Handle); - Window.GL.UniformMatrix4(_uniformLocations[name], transpose, data.ToSpan()); + TrySetUniform(name, data, (uniform, d) => Window.GL.UniformMatrix4(uniform, transpose, d.ToSpan())); } /// @@ -266,6 +277,6 @@ public void SetMatrix4(string name, Matrix4x4 data, bool transpose = true) public void SetVector3(string name, Vector3 data) { Window.GL.UseProgram(Handle); - Window.GL.Uniform3(_uniformLocations[name], data); + TrySetUniform(name, data, Window.GL.Uniform3); } } diff --git a/Core/Shaders/UIShader.cs b/Core/Shaders/UIShader.cs index 99c7b4a..4c5e675 100644 --- a/Core/Shaders/UIShader.cs +++ b/Core/Shaders/UIShader.cs @@ -12,7 +12,7 @@ internal class UIShader : ShaderBase /// public UIShader() { - Shader = new Shader(PathExtensions.GetAssemblyPath("Shaders/uiShader.vert"), PathExtensions.GetAssemblyPath("Shaders/uiShader.frag"), "ui"); + Shader = new Shader(PathExtensions.GetAssemblyPath("Shaders\\uiShader.vert"), PathExtensions.GetAssemblyPath("Shaders\\uiShader.frag"), "ui"); } /// @@ -21,14 +21,7 @@ public override bool SetAttributes() if (!base.SetAttributes()) return false; - if (!Shader!.TryGetAttribLocation(ShaderAttributes.Pos, out int vertexLocation)) - return false; - - uint vertexLocationUInt = (uint)vertexLocation; - Window.GL.EnableVertexAttribArray(vertexLocationUInt); - Window.GL.VertexAttribPointer(vertexLocationUInt, 3, VertexAttribPointerType.Float, false, 8 * sizeof(float), 0); - - /*if (!Shader!.TryGetAttribLocation(ShaderAttributes.Pos, out int positionLocation)) + if (!Shader!.TryGetAttribLocation(ShaderAttributes.Pos, out int positionLocation)) return false; var positionLocationUint = (uint)positionLocation; @@ -48,7 +41,6 @@ public override bool SetAttributes() 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/Core/SharpEngine.Core.csproj b/Core/SharpEngine.Core.csproj index 5ec1e72..2fda018 100644 --- a/Core/SharpEngine.Core.csproj +++ b/Core/SharpEngine.Core.csproj @@ -41,7 +41,7 @@ - + Always diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index eb102c9..efb3807 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -10,6 +10,7 @@ using System; using System.Numerics; +using SharpEngine.Core.Entities.UI; namespace Minecraft; From 1f50cff5b92e6859c55ead7b0618b49614658bfc Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sun, 30 Mar 2025 01:03:01 +0200 Subject: [PATCH 23/92] UI rendering works --- Core/Entities/Properties/Transform2D.cs | 2 +- Core/Entities/UI/UIElement.cs | 18 ++++++++++---- Core/Renderers/UIRenderer.cs | 4 +--- Core/Shaders/Shader.cs | 17 +++++++++----- Core/Shaders/uiShader.frag | 9 ++++--- Core/Shaders/uiShader.vert | 31 +++++++++++++++---------- 6 files changed, 49 insertions(+), 32 deletions(-) diff --git a/Core/Entities/Properties/Transform2D.cs b/Core/Entities/Properties/Transform2D.cs index 7c6ea06..f23f1ee 100644 --- a/Core/Entities/Properties/Transform2D.cs +++ b/Core/Entities/Properties/Transform2D.cs @@ -27,5 +27,5 @@ public class Transform2D : Transform /// public new Matrix4x4 ModelMatrix => Matrix4x4.CreateScale(new Vector3(Scale.X, Scale.Y, 0)) * Matrix4x4.CreateRotationZ(Rotation) * - Matrix4x4.CreateTranslation(new Vector3(Position.X, Position.Y, 0)); + Matrix4x4.CreateTranslation(new Vector3(Position.X * 0.01f, Position.Y * 0.01f, 0)); } \ No newline at end of file diff --git a/Core/Entities/UI/UIElement.cs b/Core/Entities/UI/UIElement.cs index f45df13..45576ed 100644 --- a/Core/Entities/UI/UIElement.cs +++ b/Core/Entities/UI/UIElement.cs @@ -29,9 +29,9 @@ public UIElement(string name) /// Gets or sets the 2D space transformation of the UI element. public new Transform2D Transform { get; set; } = new() { - //Rotation = 180, + Rotation = 50, Scale = new System.Numerics.Vector2(0.5f, 0.5f), - //Position = new System.Numerics.Vector2(1, 0), + Position = new System.Numerics.Vector2(0, 20), }; /// Gets or sets the mesh of the UI element. @@ -73,9 +73,17 @@ private void InitializeBuffers() public override Task Render() { Window.GL.BindVertexArray(_vertexArrayObject); - - _uIShader.Shader.SetMatrix4(ShaderAttributes.Model, Transform.ModelMatrix); - + + // Extract position, rotation, and scale from Transform + var position = Transform.Position; + var rotation = Transform.Rotation; + var scale = Transform.Scale; + + // Set the position, rotation, and scale uniforms in the shader + _uIShader.Shader.SetVector2("position", position); + _uIShader.Shader.SetFloat("rotation", rotation); + _uIShader.Shader.SetVector2("scale", scale); + Window.GL.DrawElements(PrimitiveType.Triangles, (uint)Mesh.Indices.Length, DrawElementsType.UnsignedInt, []); return Task.CompletedTask; diff --git a/Core/Renderers/UIRenderer.cs b/Core/Renderers/UIRenderer.cs index 4c5ca18..212ab19 100644 --- a/Core/Renderers/UIRenderer.cs +++ b/Core/Renderers/UIRenderer.cs @@ -61,11 +61,9 @@ public override Task Render() { try { - Window.GL.Disable(EnableCap.DepthTest); + Window.GL.Enable(EnableCap.DepthTest); Window.GL.DepthFunc(DepthFunction.Less); - _camera.SetShaderUniforms(_uiShader.Shader!); - foreach (var item in _scene.UIElements) { item.Bind(); diff --git a/Core/Shaders/Shader.cs b/Core/Shaders/Shader.cs index 259d0bd..1b7b160 100644 --- a/Core/Shaders/Shader.cs +++ b/Core/Shaders/Shader.cs @@ -1,12 +1,11 @@ +using SharpEngine.Core.Windowing; +using Silk.NET.OpenGL; using System; -using System.IO; using System.Collections.Generic; - -using System.Text.RegularExpressions; +using System.IO; using System.Numerics; - -using Silk.NET.OpenGL; -using SharpEngine.Core.Windowing; +using System.Text.RegularExpressions; +using static System.Runtime.InteropServices.JavaScript.JSType; namespace SharpEngine.Core.Shaders; @@ -279,4 +278,10 @@ public void SetVector3(string name, Vector3 data) Window.GL.UseProgram(Handle); TrySetUniform(name, data, Window.GL.Uniform3); } + + public void SetVector2(string name, Vector2 data) + { + Window.GL.UseProgram(Handle); + TrySetUniform(name, data, Window.GL.Uniform2); + } } diff --git a/Core/Shaders/uiShader.frag b/Core/Shaders/uiShader.frag index 36a7e45..8e4b912 100644 --- a/Core/Shaders/uiShader.frag +++ b/Core/Shaders/uiShader.frag @@ -1,12 +1,11 @@ #version 330 core -in vec2 TexCoord; -out vec4 FragColor; - uniform sampler2D texture1; +out vec4 FragColor; +in vec2 TexCoords; void main() { - FragColor = vec4(1.0, 0.0, 0.0, 1.0); // set all 4 vector values to 1.0 - // FragColor = texture(texture1, TexCoord); + // FragColor = vec4(1.0, 0.0, 0.0, 1.0); // set all 4 vector values to 1.0 + FragColor = texture(texture1, TexCoords); } \ No newline at end of file diff --git a/Core/Shaders/uiShader.vert b/Core/Shaders/uiShader.vert index 8d97e16..707a1f7 100644 --- a/Core/Shaders/uiShader.vert +++ b/Core/Shaders/uiShader.vert @@ -1,23 +1,30 @@ #version 330 core layout (location = 0) in vec3 aPos; -// layout (location = 1) in vec3 aNormal; -// layout (location = 2) in vec2 aTexCoord; +layout (location = 1) in vec3 aNormal; +layout (location = 2) in vec2 aTexCoords; -uniform mat4 model; -// uniform mat4 view; -// uniform mat4 projection; +uniform vec2 position; +uniform float rotation; +uniform vec2 scale; +out vec3 Normal; out vec3 FragPos; +out vec2 TexCoords; void main() { - vec4 pos = vec4(aPos, 1.0); - gl_Position = model * pos; + // Create a 2D rotation matrix + mat2 rot = mat2(cos(rotation), -sin(rotation), + sin(rotation), cos(rotation)); - // gl_Position = vec4(aPos, 1.0) * model * view * projection; - // FragPos = vec3(vec4(aPos, 1.0) * model); - // TexCoord = aTexCoord; - // Normal = aNormal * mat3(transpose(inverse(model))); - // TexCoords = aTexCoords; + // Apply the rotation, scaling, and translation + vec2 transformedPos = (rot * aPos.xy) * scale + (position * 0.01); + + // Set the final position in clip space + gl_Position = vec4(transformedPos, aPos.z, 1.0); + + FragPos = vec3(transformedPos, aPos.z); + Normal = aNormal; // No need to transform normals for 2D UI elements + TexCoords = aTexCoords; } \ No newline at end of file From abafdd9f9fac0134265e7fc99e116d7396c47426 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sun, 30 Mar 2025 01:39:02 +0200 Subject: [PATCH 24/92] Actual fix --- Core/Entities/UI/UIElement.cs | 26 ++++++++++---------------- Core/Renderers/UIRenderer.cs | 23 ----------------------- Examples/MinecraftClone/Minecraft.cs | 17 +++++++---------- 3 files changed, 17 insertions(+), 49 deletions(-) diff --git a/Core/Entities/UI/UIElement.cs b/Core/Entities/UI/UIElement.cs index 45576ed..7a17eff 100644 --- a/Core/Entities/UI/UIElement.cs +++ b/Core/Entities/UI/UIElement.cs @@ -22,17 +22,14 @@ public UIElement(string name) { Name = name; Mesh = MeshService.Instance.LoadMesh(nameof(Primitives.Plane), Primitives.Plane.Mesh); + + Initialize(); } - private readonly UIShader _uIShader = new(); + private readonly UIShader _uiShader = new(); /// Gets or sets the 2D space transformation of the UI element. - public new Transform2D Transform { get; set; } = new() - { - Rotation = 50, - Scale = new System.Numerics.Vector2(0.5f, 0.5f), - Position = new System.Numerics.Vector2(0, 20), - }; + public new Transform2D Transform { get; set; } = new(); /// Gets or sets the mesh of the UI element. public new Mesh Mesh { get; set; } @@ -46,6 +43,9 @@ public void Initialize() Bind(); InitializeBuffers(); + + _uiShader.Shader.Use(); + _uiShader.SetAttributes(); } /// @@ -74,15 +74,9 @@ public override Task Render() { Window.GL.BindVertexArray(_vertexArrayObject); - // Extract position, rotation, and scale from Transform - var position = Transform.Position; - var rotation = Transform.Rotation; - var scale = Transform.Scale; - - // Set the position, rotation, and scale uniforms in the shader - _uIShader.Shader.SetVector2("position", position); - _uIShader.Shader.SetFloat("rotation", rotation); - _uIShader.Shader.SetVector2("scale", scale); + _uiShader.Shader.SetVector2("position", Transform.Position); + _uiShader.Shader.SetFloat("rotation", Transform.Rotation); + _uiShader.Shader.SetVector2("scale", Transform.Scale); Window.GL.DrawElements(PrimitiveType.Triangles, (uint)Mesh.Indices.Length, DrawElementsType.UnsignedInt, []); diff --git a/Core/Renderers/UIRenderer.cs b/Core/Renderers/UIRenderer.cs index 212ab19..ffa8f8a 100644 --- a/Core/Renderers/UIRenderer.cs +++ b/Core/Renderers/UIRenderer.cs @@ -33,29 +33,6 @@ public UIRenderer(CameraView camera, ISettings settings, Scene scene) : base(set _camera = camera; } - /// - public override void Initialize() - { - if (_uiShader.Shader is null) - { - Console.WriteLine("The UI shader is null. This is broken mostly when the exe is started outside the solution. This needs to be fixed later."); - return; - } - - _uiShader.Shader.Use(); - - _scene.UIElements.Add(new UIElement("uiElement")); - - _scene.Iterate(_scene.UIElements, elem => elem.Initialize()); - - InitializeVertexArrays(); - } - - private void InitializeVertexArrays() - { - _uiShader.SetAttributes(); - } - /// public override Task Render() { diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index efb3807..b173bea 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -29,7 +29,7 @@ public class Minecraft : Game private Input _input; private readonly Inventory _inventory; - private UIElement uiElem; + private UIElement _uiElem; /// /// Initializes a new instance of the . @@ -56,8 +56,10 @@ public override void Initialize() _blocksNode = _scene.Root.AddChild("blocks"); // TODO: Fix UI renderer - uiElem = new UIElement("uiElement"); - _scene.UIElements.Add(uiElem); + _uiElem = new UIElement("uiElement"); + _uiElem.Transform.Scale = new Vector2(0.5f, 0.5f); + + _scene.UIElements.Add(_uiElem); InitializeWorld(); } @@ -90,11 +92,6 @@ private void InitializeLights() Diffuse = new Vector3(1.0f, 1.0f, 1.0f), Specular = new Vector3(1.0f, 1.0f, 1.0f), }); - - // var _lightingShader = ShaderService.Instance.LoadShader("Shaders/shader.vert", "Shaders/lighting.frag", "lighting"); - // _lightingShader.SetInt("numDirLights", 1); - // _lightingShader.SetInt("numPointLights", 4); - // _lightingShader.SetInt("numSpotLights", 1); } private void InitializeChunks() @@ -137,12 +134,12 @@ private void GenerateChunk(int chunkSize, Vector3 chunkPos) /// public override void Update(double deltaTime, IInputContext input) { - // UpdateUI(); + UpdateUI(); _input.HandleKeyboard(input.Keyboards[0], (float)deltaTime); } private void UpdateUI() - => uiElem.Transform.Rotation += 0.01f; + => _uiElem.Transform.Rotation += 0.01f; // TODO: Input system to let users change change key bindings? /// From 95fbe33e0d5487cc3c87b70533df7cc2b86e9f0e Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sun, 30 Mar 2025 16:14:49 +0300 Subject: [PATCH 25/92] Generalize functions --- Core/Entities/UI/Layouts/FlexLayout.cs | 5 +++-- Core/Entities/UI/Layouts/GridLayout.cs | 17 +++++++++++++++-- Core/Entities/UI/Layouts/LayoutBase.cs | 17 ++++++++++++++--- Core/Ray.cs | 2 +- Core/Renderers/Renderer.cs | 2 +- Core/Renderers/UIRenderer.cs | 8 +++++--- Core/Scenes/Scene.cs | 23 ++++++++++++----------- Core/Windowing/Window.cs | 4 +++- Examples/MinecraftClone/Minecraft.cs | 20 +++++++++++++++++--- Examples/MinecraftClone/Program.cs | 6 +++++- 10 files changed, 76 insertions(+), 28 deletions(-) diff --git a/Core/Entities/UI/Layouts/FlexLayout.cs b/Core/Entities/UI/Layouts/FlexLayout.cs index 62f9528..6768311 100644 --- a/Core/Entities/UI/Layouts/FlexLayout.cs +++ b/Core/Entities/UI/Layouts/FlexLayout.cs @@ -1,4 +1,5 @@ -using System; +using SharpEngine.Core.Scenes; +using System; using System.Numerics; namespace SharpEngine.Core.Entities.UI.Layouts; @@ -7,7 +8,7 @@ namespace SharpEngine.Core.Entities.UI.Layouts; /// Represents a layout that dynamically distributes items in a flex layout. /// /// The type of items in the collection. -public class FlexLayout : LayoutBase +public class FlexLayout : LayoutBase where T : SceneNode { public int Gap { get; set; } diff --git a/Core/Entities/UI/Layouts/GridLayout.cs b/Core/Entities/UI/Layouts/GridLayout.cs index cc0cde2..365323e 100644 --- a/Core/Entities/UI/Layouts/GridLayout.cs +++ b/Core/Entities/UI/Layouts/GridLayout.cs @@ -1,4 +1,5 @@ -using System; +using SharpEngine.Core.Scenes; +using System; namespace SharpEngine.Core.Entities.UI.Layouts; @@ -6,7 +7,7 @@ namespace SharpEngine.Core.Entities.UI.Layouts; /// Represents a grid layout. /// /// The type of items that can be stored and retrieved within the grid. -public class GridLayout : LayoutBase +public class GridLayout : LayoutBase where T : GameObject { /// Gets or sets the amount of rows in the grid. public uint Rows { get; set; } = 2; @@ -34,6 +35,18 @@ public class GridLayout : LayoutBase } } + public override void AddItem(T item) + { + base.AddItem(item); + + var offset = -100; // TODO: Fix this, this is just a temporary solution. + + if (Items.Count % Columns != 0) + offset = offset + (Items.Count * 30); + + item.Transform.Position = new System.Numerics.Vector3(offset, 0, 0); + } + /// /// Calculates the index in the flat list based on row and column. /// diff --git a/Core/Entities/UI/Layouts/LayoutBase.cs b/Core/Entities/UI/Layouts/LayoutBase.cs index be69994..d8ec1cc 100644 --- a/Core/Entities/UI/Layouts/LayoutBase.cs +++ b/Core/Entities/UI/Layouts/LayoutBase.cs @@ -1,4 +1,5 @@ -using System; +using SharpEngine.Core.Scenes; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -6,9 +7,19 @@ namespace SharpEngine.Core.Entities.UI.Layouts; -public abstract class LayoutBase +public abstract class LayoutBase : SceneNode where T : SceneNode { - public List Items; + public List Items { get; set; } = []; + + public override SceneNode AddChild(params SceneNode[] nodes) + { + base.AddChild(nodes); + + foreach (var node in nodes) + AddItem((T)node); + + return this; + } public virtual void AddItem(T item) { diff --git a/Core/Ray.cs b/Core/Ray.cs index 42bae6e..942346b 100644 --- a/Core/Ray.cs +++ b/Core/Ray.cs @@ -43,7 +43,7 @@ public bool IsGameObjectInView(Scene scene, out GameObject? intersectingObject, const float maxDistance = 100.0f; // Maximum distance to check for intersections const float stepSize = 0.1f; // Step size for ray marching - var sceneNodes = scene.GetAllGameObjects(); + var sceneNodes = scene.GetObjectsOfType(); if (allowedTypes.Length != 0) sceneNodes = [.. sceneNodes.Where(go => allowedTypes.Any(type => type.IsInstanceOfType(go)))]; diff --git a/Core/Renderers/Renderer.cs b/Core/Renderers/Renderer.cs index 0e80c7d..a6f0401 100644 --- a/Core/Renderers/Renderer.cs +++ b/Core/Renderers/Renderer.cs @@ -49,7 +49,7 @@ public Renderer(CameraView camera, ISettings settings, Scene scene) : base(setti /// public override Task Render() { - return Task.CompletedTask; + //return Task.CompletedTask; try { Window.GL.Enable(EnableCap.DepthTest); diff --git a/Core/Renderers/UIRenderer.cs b/Core/Renderers/UIRenderer.cs index ffa8f8a..55513ef 100644 --- a/Core/Renderers/UIRenderer.cs +++ b/Core/Renderers/UIRenderer.cs @@ -7,6 +7,7 @@ using Silk.NET.OpenGL; using System; +using System.Linq; using System.Threading.Tasks; namespace SharpEngine.Core.Renderers; @@ -41,13 +42,14 @@ public override Task Render() Window.GL.Enable(EnableCap.DepthTest); Window.GL.DepthFunc(DepthFunction.Less); - foreach (var item in _scene.UIElements) + _uiShader.Shader.Use(); + + var objects = _scene.GetObjectsOfType(); // TODO: This is really unoptimized, need to figure out a better solution. + foreach (var item in objects) { item.Bind(); } - _uiShader.Shader.Use(); - var uiElementRenderTasks = _scene.IterateAsync(_scene.UIElements, elem => elem.Render()); return Task.WhenAll(uiElementRenderTasks); diff --git a/Core/Scenes/Scene.cs b/Core/Scenes/Scene.cs index 852f9dd..3f46da7 100644 --- a/Core/Scenes/Scene.cs +++ b/Core/Scenes/Scene.cs @@ -47,7 +47,7 @@ public Scene(string sceneFile) private List Nodes { get; set; } = []; /// Gets or sets the UI elements in the scene. - public List UIElements { get; private set; } = []; + public List UIElements { get; private set; } = []; /// Gets or sets the active element in the scene. /// Editor only. @@ -104,26 +104,27 @@ public virtual void RemoveNode(SceneNode node) } /// - /// Gets all game objects in the scene. + /// Gets all the objects in the scene of type . /// + /// The type of the objects to be retrieved. /// All the game objects in the current scene. - public List GetAllGameObjects() + public List GetObjectsOfType(SceneNode? root = null) { // TODO: Can we make this async? - var gameObjects = new List(); - static void FindGameObjects(SceneNode node, List gameObjects) + var result = new List(); + static void FindsObjects(SceneNode node, List result) { - if (node is GameObject gameObject) - gameObjects.Add(gameObject); + if (node is T obj) + result.Add(obj); foreach (var child in node.Children) - FindGameObjects(child, gameObjects); + FindsObjects(child, result); } - foreach (var node in Root.Children) - FindGameObjects(node, gameObjects); + foreach (var node in root?.Children ?? Root.Children) + FindsObjects(node, result); - return gameObjects; + return result; } /// diff --git a/Core/Windowing/Window.cs b/Core/Windowing/Window.cs index f4ebdee..85f9c97 100644 --- a/Core/Windowing/Window.cs +++ b/Core/Windowing/Window.cs @@ -323,7 +323,9 @@ protected void OnMouseWheel(IMouse mouse, ScrollWheel sw) protected void OnResize(Vector2D size) { GL.Viewport(size); - Camera.AspectRatio = size.X / size.Y; + + if (size != Vector2D.Zero) + Camera.AspectRatio = size.X / size.Y; } /// diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index b173bea..11785e3 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -11,6 +11,8 @@ using System; using System.Numerics; using SharpEngine.Core.Entities.UI; +using SharpEngine.Core.Windowing; +using SharpEngine.Core.Entities.UI.Layouts; namespace Minecraft; @@ -31,6 +33,8 @@ public class Minecraft : Game private UIElement _uiElem; + public Window Window { get; set; } + /// /// Initializes a new instance of the . /// @@ -55,12 +59,22 @@ public override void Initialize() _lightsNode = _scene.Root.AddChild("lights"); _blocksNode = _scene.Root.AddChild("blocks"); + var gridLayout = new GridLayout(); + // TODO: Fix UI renderer _uiElem = new UIElement("uiElement"); - _uiElem.Transform.Scale = new Vector2(0.5f, 0.5f); - + _uiElem.Transform.Scale = new Vector2(0.2f, 0.2f); + //_uiElem.Transform.Position = new Vector2(-30, 0); _scene.UIElements.Add(_uiElem); + var uiElem2 = new UIElement("uiElement"); + uiElem2.Transform.Scale = new Vector2(0.2f, 0.2f); + //uiElem2.Transform.Position = new Vector2(30, 0); + + //gridLayout.AddChild(_uiElem, uiElem2); + + _scene.UIElements.Add(gridLayout); + InitializeWorld(); } catch (Exception ex) @@ -134,7 +148,7 @@ private void GenerateChunk(int chunkSize, Vector3 chunkPos) /// public override void Update(double deltaTime, IInputContext input) { - UpdateUI(); + //UpdateUI(); _input.HandleKeyboard(input.Keyboards[0], (float)deltaTime); } diff --git a/Examples/MinecraftClone/Program.cs b/Examples/MinecraftClone/Program.cs index 481bbbb..a753b62 100644 --- a/Examples/MinecraftClone/Program.cs +++ b/Examples/MinecraftClone/Program.cs @@ -19,12 +19,16 @@ private static void Main() Minecraft game = new Minecraft(scene, gameSettings); using var window = new SharpEngine.Core.Windowing.Window(game.Camera, scene, game.Camera.Settings); - window.OnLoaded += () => game.Initialize(); + window.OnLoaded += game.Initialize; window.OnHandleMouse += game.HandleMouse; window.OnUpdate += game.Update; window.OnHandleKeyboard += game.HandleKeyboard; window.OnButtonMouseDown += game.HandleMouseDown; window.HandleMouseWheel += game.HandleMouseWheel; + + // TODO: This needs to be streamlined. + game.Window = window; + window.Run(); } } From 90e9a872dcbdb5c25cd94e1abd0467efb15f7714 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Fri, 4 Apr 2025 00:41:46 +0300 Subject: [PATCH 26/92] Fiddle with Transforms and types (WIP) --- Core/Entities/BezierCurve.cs | 54 +++ Core/Entities/GameObject.cs | 8 +- Core/Entities/Properties/ITransform.cs | 11 + Core/Entities/Properties/Transform.cs | 16 +- Core/Entities/Properties/Transform2D.cs | 13 +- Core/Entities/UI/Layouts/GridLayout.cs | 9 +- Core/Entities/UI/Layouts/LayoutBase.cs | 7 +- Core/Entities/UI/UIElement.cs | 7 +- Core/Numerics/HashCodeHelper.cs | 17 + Core/Numerics/IVector.cs | 5 + Core/Numerics/JitIntrinsicAttribute.cs | 16 + Core/Numerics/Vector2.cs | 458 +++++++++++++++++++++++ Core/Numerics/Vector2_Intrinsics.cs | 298 +++++++++++++++ Core/Numerics/Vector3.cs | 477 ++++++++++++++++++++++++ Core/Numerics/Vector3_Intrinsics.cs | 324 ++++++++++++++++ Core/Scenes/SceneNode.cs | 47 ++- Examples/MinecraftClone/Minecraft.cs | 9 +- 17 files changed, 1733 insertions(+), 43 deletions(-) create mode 100644 Core/Entities/BezierCurve.cs create mode 100644 Core/Entities/Properties/ITransform.cs create mode 100644 Core/Numerics/HashCodeHelper.cs create mode 100644 Core/Numerics/IVector.cs create mode 100644 Core/Numerics/JitIntrinsicAttribute.cs create mode 100644 Core/Numerics/Vector2.cs create mode 100644 Core/Numerics/Vector2_Intrinsics.cs create mode 100644 Core/Numerics/Vector3.cs create mode 100644 Core/Numerics/Vector3_Intrinsics.cs diff --git a/Core/Entities/BezierCurve.cs b/Core/Entities/BezierCurve.cs new file mode 100644 index 0000000..aba3b70 --- /dev/null +++ b/Core/Entities/BezierCurve.cs @@ -0,0 +1,54 @@ +using Silk.NET.Maths; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; + +namespace SharpEngine.Core.Entities; +public class BezierCurve +{ + private Vector3D P0, P1, P2, P3; + public Vector3D Start => P0; + public Vector3D End => P3; + + public List> Points { get; set; } + + public BezierCurve(Vector3D initializationPosition) + { + const float defaultWidth = 1; + + P0 = initializationPosition; + P1 = new Vector3D(initializationPosition.X + defaultWidth, initializationPosition.Y + defaultWidth, initializationPosition.Z); + P2 = new Vector3D(initializationPosition.X + defaultWidth, initializationPosition.Y - defaultWidth, initializationPosition.Z); + P3 = new Vector3D(initializationPosition.X + defaultWidth, initializationPosition.Y, initializationPosition.Z); + + Points = GetPoints(20); + } + + public List> GetPoints(int resolution) + { + var points = new List>(); + for (var i = 0; i <= resolution; i++) + { + var t = i / (float)resolution; + points.Add(GetPointAt(t)); + } + return points; + } + + private Vector3D GetPointAt(float t) + { + var x = GetCoordinateAt(t, P0.X, P1.X, P2.X, P3.X); + var y = GetCoordinateAt(t, P0.Y, P1.Y, P2.Y, P3.Y); + var z = GetCoordinateAt(t, P0.Z, P1.Z, P2.Z, P3.Z); + return new(x, y, z); + } + + private static float GetCoordinateAt(float t, float p0, float p1, float p2, float p3) + { + float u = 1 - t; + return MathF.Pow(u, 3) * p0 + 3 * MathF.Pow(u, 2) * t * p1 + 3 * u * MathF.Pow(t, 2) * p2 + MathF.Pow(t, 3) * p3; + } +} diff --git a/Core/Entities/GameObject.cs b/Core/Entities/GameObject.cs index 7f8b0d6..415a490 100644 --- a/Core/Entities/GameObject.cs +++ b/Core/Entities/GameObject.cs @@ -16,7 +16,7 @@ namespace SharpEngine.Core.Entities; /// /// Represents a game object in the scene. /// -public class GameObject : SceneNode +public class GameObject : SceneNode { /// /// Initializes a new instance of the . @@ -59,12 +59,10 @@ public GameObject(string? diffuseMapFile = null, string? specularMapFile = null, [Inspector(DisplayInInspector = false)] public Material Material { get; set; } - private Transform _transform = new(); - /// /// Gets or sets the transform of the game object. /// - public Transform Transform + public override Transform Transform { get => _transform; set @@ -74,6 +72,8 @@ public Transform Transform } } + private Transform _transform; + /// /// Gets the bounding box of the game object. /// diff --git a/Core/Entities/Properties/ITransform.cs b/Core/Entities/Properties/ITransform.cs new file mode 100644 index 0000000..65108b0 --- /dev/null +++ b/Core/Entities/Properties/ITransform.cs @@ -0,0 +1,11 @@ +using System.Numerics; + +namespace SharpEngine.Core.Entities.Properties; + +public interface ITransform +{ + public abstract IVector Position { get; set; } + public abstract IVector Scale { get; set; } + public abstract Quaternion Rotation { get; set; } + public abstract Matrix4x4 ModelMatrix { get; } +} \ No newline at end of file diff --git a/Core/Entities/Properties/Transform.cs b/Core/Entities/Properties/Transform.cs index 50b8bea..7370aea 100644 --- a/Core/Entities/Properties/Transform.cs +++ b/Core/Entities/Properties/Transform.cs @@ -1,12 +1,20 @@ -using System.Numerics; +using Silk.NET.Maths; +using SharpEngine.Core.Entities; +using System.Numerics; + +using Vector3 = SharpEngine.Core.Numerics.Vector3; namespace SharpEngine.Core.Entities.Properties; /// /// Represents a game object transformation in 3D space. /// -public class Transform +public class Transform : ITransform { + public Transform() + { + } + /// /// Gets or sets the position of the game object. /// @@ -25,7 +33,7 @@ public class Transform /// /// Gets the transformation of the game object as a model matrix. /// - public Matrix4x4 ModelMatrix => Matrix4x4.CreateScale(Scale) * + public Matrix4x4 ModelMatrix => Matrix4x4.CreateScale(new System.Numerics.Vector3(Scale.X, Scale.Y, Scale.Z)) * Matrix4x4.CreateFromAxisAngle(Rotation.Axis, Math.DegreesToRadians(Rotation.Angle)) * - Matrix4x4.CreateTranslation(Position); + Matrix4x4.CreateTranslation(new System.Numerics.Vector3(Position.X, Position.Y, Position.Z)); } diff --git a/Core/Entities/Properties/Transform2D.cs b/Core/Entities/Properties/Transform2D.cs index f23f1ee..413226c 100644 --- a/Core/Entities/Properties/Transform2D.cs +++ b/Core/Entities/Properties/Transform2D.cs @@ -1,31 +1,32 @@ using System.Numerics; +using Vector2 = SharpEngine.Core.Numerics.Vector2; namespace SharpEngine.Core.Entities.Properties; /// /// Represents a game object transformation in 2D space. /// -public class Transform2D : Transform +public class Transform2D : ITransform { /// /// Gets or sets the position of the game object. /// - public new Vector2 Position { get; set; } + public Vector2 Position { get; set; } /// /// Gets or sets the scale of the game object. /// - public new Vector2 Scale { get; set; } = new(1, 1); + public Vector2 Scale { get; set; } = new(1, 1); /// /// Gets or sets the rotation of the game object. /// - public new float Rotation { get; set; } + public Quaternion Rotation { get; set; } = new(); /// /// Gets the transformation of the game object as a model matrix. /// - public new Matrix4x4 ModelMatrix => Matrix4x4.CreateScale(new Vector3(Scale.X, Scale.Y, 0)) * - Matrix4x4.CreateRotationZ(Rotation) * + public Matrix4x4 ModelMatrix => Matrix4x4.CreateScale(new Vector3(Scale.X, Scale.Y, 0)) * + Matrix4x4.CreateRotationZ(Rotation.Angle) * Matrix4x4.CreateTranslation(new Vector3(Position.X * 0.01f, Position.Y * 0.01f, 0)); } \ No newline at end of file diff --git a/Core/Entities/UI/Layouts/GridLayout.cs b/Core/Entities/UI/Layouts/GridLayout.cs index 365323e..20bd9b3 100644 --- a/Core/Entities/UI/Layouts/GridLayout.cs +++ b/Core/Entities/UI/Layouts/GridLayout.cs @@ -1,4 +1,6 @@ -using SharpEngine.Core.Scenes; +using SharpEngine.Core.Entities.Properties; +using SharpEngine.Core.Numerics; +using SharpEngine.Core.Scenes; using System; namespace SharpEngine.Core.Entities.UI.Layouts; @@ -7,7 +9,7 @@ namespace SharpEngine.Core.Entities.UI.Layouts; /// Represents a grid layout. /// /// The type of items that can be stored and retrieved within the grid. -public class GridLayout : LayoutBase where T : GameObject +public class GridLayout : LayoutBase where T : SceneNode> { /// Gets or sets the amount of rows in the grid. public uint Rows { get; set; } = 2; @@ -35,6 +37,7 @@ public class GridLayout : LayoutBase where T : GameObject } } + /// public override void AddItem(T item) { base.AddItem(item); @@ -44,7 +47,7 @@ public override void AddItem(T item) if (Items.Count % Columns != 0) offset = offset + (Items.Count * 30); - item.Transform.Position = new System.Numerics.Vector3(offset, 0, 0); + item.Transform.Position.X = offset; } /// diff --git a/Core/Entities/UI/Layouts/LayoutBase.cs b/Core/Entities/UI/Layouts/LayoutBase.cs index d8ec1cc..e21404e 100644 --- a/Core/Entities/UI/Layouts/LayoutBase.cs +++ b/Core/Entities/UI/Layouts/LayoutBase.cs @@ -1,4 +1,5 @@ -using SharpEngine.Core.Scenes; +using SharpEngine.Core.Entities.Properties; +using SharpEngine.Core.Scenes; using System; using System.Collections.Generic; using System.Linq; @@ -7,11 +8,11 @@ namespace SharpEngine.Core.Entities.UI.Layouts; -public abstract class LayoutBase : SceneNode where T : SceneNode +public abstract class LayoutBase : EmptyNode where T : SceneNode, new() { public List Items { get; set; } = []; - public override SceneNode AddChild(params SceneNode[] nodes) + public override SceneNode AddChild(params SceneNode[] nodes) { base.AddChild(nodes); diff --git a/Core/Entities/UI/UIElement.cs b/Core/Entities/UI/UIElement.cs index 7a17eff..ec90445 100644 --- a/Core/Entities/UI/UIElement.cs +++ b/Core/Entities/UI/UIElement.cs @@ -12,7 +12,7 @@ namespace SharpEngine.Core.Entities.UI; /// /// Represents a User Interface entity. /// -public class UIElement : GameObject +public class UIElement : SceneNode { /// /// Initializes a new instance of . @@ -29,10 +29,11 @@ public UIElement(string name) private readonly UIShader _uiShader = new(); /// Gets or sets the 2D space transformation of the UI element. - public new Transform2D Transform { get; set; } = new(); + public override Transform2D Transform { get; set; } = new(); /// Gets or sets the mesh of the UI element. public new Mesh Mesh { get; set; } + //public override Transform2D Transform { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } private uint _vertexArrayObject; @@ -75,7 +76,7 @@ public override Task Render() Window.GL.BindVertexArray(_vertexArrayObject); _uiShader.Shader.SetVector2("position", Transform.Position); - _uiShader.Shader.SetFloat("rotation", Transform.Rotation); + _uiShader.Shader.SetFloat("rotation", Transform.Rotation.Angle); _uiShader.Shader.SetVector2("scale", Transform.Scale); Window.GL.DrawElements(PrimitiveType.Triangles, (uint)Mesh.Indices.Length, DrawElementsType.UnsignedInt, []); diff --git a/Core/Numerics/HashCodeHelper.cs b/Core/Numerics/HashCodeHelper.cs new file mode 100644 index 0000000..8731224 --- /dev/null +++ b/Core/Numerics/HashCodeHelper.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// https://github.com/microsoft/referencesource/blob/master/System.Numerics/System/Numerics/HashCodeHelper.cs + +namespace SharpEngine.Core.Numerics +{ + internal static class HashCodeHelper + { + /// + /// Combines two hash codes, useful for combining hash codes of individual vector elements + /// + internal static int CombineHashCodes(int h1, int h2) + { + return (((h1 << 5) + h1) ^ h2); + } + } +} \ No newline at end of file diff --git a/Core/Numerics/IVector.cs b/Core/Numerics/IVector.cs new file mode 100644 index 0000000..9fe8509 --- /dev/null +++ b/Core/Numerics/IVector.cs @@ -0,0 +1,5 @@ +namespace SharpEngine.Core.Numerics; + +public interface IVector +{ +} \ No newline at end of file diff --git a/Core/Numerics/JitIntrinsicAttribute.cs b/Core/Numerics/JitIntrinsicAttribute.cs new file mode 100644 index 0000000..0e53d20 --- /dev/null +++ b/Core/Numerics/JitIntrinsicAttribute.cs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// https://github.com/microsoft/referencesource/blob/master/System.Numerics/System/Numerics/JITIntrinsicAttribute.cs + +using System; + +namespace SharpEngine.Core.Numerics +{ + /// + /// An attribute that can be attached to JIT Intrinsic methods/properties + /// + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property)] + internal class JitIntrinsicAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/Core/Numerics/Vector2.cs b/Core/Numerics/Vector2.cs new file mode 100644 index 0000000..7956d9f --- /dev/null +++ b/Core/Numerics/Vector2.cs @@ -0,0 +1,458 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// https://github.com/microsoft/referencesource/blob/master/System.Numerics/System/Numerics/Vector2.cs + +using System; +using System.Globalization; +using System.Runtime.CompilerServices; +using System.Text; + +using Vector = System.Numerics.Vector; +using Matrix4x4 = System.Numerics.Matrix4x4; +using Matrix3x2 = System.Numerics.Matrix3x2; +using Quaternion = System.Numerics.Quaternion; + +namespace SharpEngine.Core.Numerics +{ + /// + /// A structure encapsulating two single precision floating point values and provides hardware accelerated methods. + /// + public partial struct Vector2 : IVector, IEquatable, IFormattable + { + #region Public Static Properties + /// + /// Returns the vector (0,0). + /// + public static Vector2 Zero => new(); + /// + /// Returns the vector (1,1). + /// + public static Vector2 One => new Vector2(1.0f, 1.0f); + /// + /// Returns the vector (1,0). + /// + public static Vector2 UnitX { get { return new Vector2(1.0f, 0.0f); } } + /// + /// Returns the vector (0,1). + /// + public static Vector2 UnitY { get { return new Vector2(0.0f, 1.0f); } } + #endregion Public Static Properties + + #region Public instance methods + /// + /// Returns the hash code for this instance. + /// + /// The hash code. + public override int GetHashCode() + { + int hash = this.X.GetHashCode(); + hash = HashCodeHelper.CombineHashCodes(hash, this.Y.GetHashCode()); + return hash; + } + + /// + /// Returns a boolean indicating whether the given Object is equal to this Vector2 instance. + /// + /// The Object to compare against. + /// True if the Object is equal to this Vector2; False otherwise. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override bool Equals(object obj) + { + if (!(obj is Vector2)) + return false; + return Equals((Vector2)obj); + } + + /// + /// Returns a String representing this Vector2 instance. + /// + /// The string representation. + public override string ToString() + { + return ToString("G", CultureInfo.CurrentCulture); + } + + /// + /// Returns a String representing this Vector2 instance, using the specified format to format individual elements. + /// + /// The format of individual elements. + /// The string representation. + public string ToString(string format) + { + return ToString(format, CultureInfo.CurrentCulture); + } + + /// + /// Returns a String representing this Vector2 instance, using the specified format to format individual elements + /// and the given IFormatProvider. + /// + /// The format of individual elements. + /// The format provider to use when formatting elements. + /// The string representation. + public string ToString(string format, IFormatProvider formatProvider) + { + StringBuilder sb = new StringBuilder(); + string separator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator; + sb.Append('<'); + sb.Append(this.X.ToString(format, formatProvider)); + sb.Append(separator); + sb.Append(' '); + sb.Append(this.Y.ToString(format, formatProvider)); + sb.Append('>'); + return sb.ToString(); + } + + /// + /// Returns the length of the vector. + /// + /// The vector's length. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public float Length() + { + if (Vector.IsHardwareAccelerated) + { + float ls = Vector2.Dot(this, this); + return (float)MathF.Sqrt(ls); + } + else + { + float ls = X * X + Y * Y; + return MathF.Sqrt(ls); + } + } + + /// + /// Returns the length of the vector squared. This operation is cheaper than Length(). + /// + /// The vector's length squared. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public float LengthSquared() + { + if (Vector.IsHardwareAccelerated) + { + return Vector2.Dot(this, this); + } + else + { + return X * X + Y * Y; + } + } + #endregion Public Instance Methods + + #region Public Static Methods + /// + /// Returns the Euclidean distance between the two given points. + /// + /// The first point. + /// The second point. + /// The distance. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Distance(Vector2 value1, Vector2 value2) + { + if (Vector.IsHardwareAccelerated) + { + Vector2 difference = value1 - value2; + float ls = Vector2.Dot(difference, difference); + return (float)System.MathF.Sqrt(ls); + } + else + { + float dx = value1.X - value2.X; + float dy = value1.Y - value2.Y; + + float ls = dx * dx + dy * dy; + + return MathF.Sqrt(ls); + } + } + + /// + /// Returns the Euclidean distance squared between the two given points. + /// + /// The first point. + /// The second point. + /// The distance squared. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float DistanceSquared(Vector2 value1, Vector2 value2) + { + if (Vector.IsHardwareAccelerated) + { + Vector2 difference = value1 - value2; + return Vector2.Dot(difference, difference); + } + else + { + float dx = value1.X - value2.X; + float dy = value1.Y - value2.Y; + + return dx * dx + dy * dy; + } + } + + /// + /// Returns a vector with the same direction as the given vector, but with a length of 1. + /// + /// The vector to normalize. + /// The normalized vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Normalize(Vector2 value) + { + if (Vector.IsHardwareAccelerated) + { + float length = value.Length(); + return value / length; + } + else + { + float ls = value.X * value.X + value.Y * value.Y; + float invNorm = 1.0f / MathF.Sqrt(ls); + + return new Vector2( + value.X * invNorm, + value.Y * invNorm); + } + } + + /// + /// Returns the reflection of a vector off a surface that has the specified normal. + /// + /// The source vector. + /// The normal of the surface being reflected off. + /// The reflected vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Reflect(Vector2 vector, Vector2 normal) + { + if (Vector.IsHardwareAccelerated) + { + float dot = Vector2.Dot(vector, normal); + return vector - (2 * dot * normal); + } + else + { + float dot = vector.X * normal.X + vector.Y * normal.Y; + + return new Vector2( + vector.X - 2.0f * dot * normal.X, + vector.Y - 2.0f * dot * normal.Y); + } + } + + /// + /// Restricts a vector between a min and max value. + /// + /// The source vector. + /// The minimum value. + /// The maximum value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Clamp(Vector2 value1, Vector2 min, Vector2 max) + { + // This compare order is very important!!! + // We must follow HLSL behavior in the case user specified min value is bigger than max value. + float x = value1.X; + x = (x > max.X) ? max.X : x; + x = (x < min.X) ? min.X : x; + + float y = value1.Y; + y = (y > max.Y) ? max.Y : y; + y = (y < min.Y) ? min.Y : y; + + return new Vector2(x, y); + } + + /// + /// Linearly interpolates between two vectors based on the given weighting. + /// + /// The first source vector. + /// The second source vector. + /// Value between 0 and 1 indicating the weight of the second source vector. + /// The interpolated vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Lerp(Vector2 value1, Vector2 value2, float amount) + { + return new Vector2( + value1.X + (value2.X - value1.X) * amount, + value1.Y + (value2.Y - value1.Y) * amount); + } + + /// + /// Transforms a vector by the given matrix. + /// + /// The source vector. + /// The transformation matrix. + /// The transformed vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Transform(Vector2 position, Matrix3x2 matrix) + { + return new Vector2( + position.X * matrix.M11 + position.Y * matrix.M21 + matrix.M31, + position.X * matrix.M12 + position.Y * matrix.M22 + matrix.M32); + } + + /// + /// Transforms a vector by the given matrix. + /// + /// The source vector. + /// The transformation matrix. + /// The transformed vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Transform(Vector2 position, Matrix4x4 matrix) + { + return new Vector2( + position.X * matrix.M11 + position.Y * matrix.M21 + matrix.M41, + position.X * matrix.M12 + position.Y * matrix.M22 + matrix.M42); + } + + /// + /// Transforms a vector normal by the given matrix. + /// + /// The source vector. + /// The transformation matrix. + /// The transformed vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 TransformNormal(Vector2 normal, Matrix3x2 matrix) + { + return new Vector2( + normal.X * matrix.M11 + normal.Y * matrix.M21, + normal.X * matrix.M12 + normal.Y * matrix.M22); + } + + /// + /// Transforms a vector normal by the given matrix. + /// + /// The source vector. + /// The transformation matrix. + /// The transformed vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 TransformNormal(Vector2 normal, Matrix4x4 matrix) + { + return new Vector2( + normal.X * matrix.M11 + normal.Y * matrix.M21, + normal.X * matrix.M12 + normal.Y * matrix.M22); + } + + /// + /// Transforms a vector by the given Quaternion rotation value. + /// + /// The source vector to be rotated. + /// The rotation to apply. + /// The transformed vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Transform(Vector2 value, Quaternion rotation) + { + float x2 = rotation.X + rotation.X; + float y2 = rotation.Y + rotation.Y; + float z2 = rotation.Z + rotation.Z; + + float wz2 = rotation.W * z2; + float xx2 = rotation.X * x2; + float xy2 = rotation.X * y2; + float yy2 = rotation.Y * y2; + float zz2 = rotation.Z * z2; + + return new Vector2( + value.X * (1.0f - yy2 - zz2) + value.Y * (xy2 - wz2), + value.X * (xy2 + wz2) + value.Y * (1.0f - xx2 - zz2)); + } + #endregion Public Static Methods + + #region Public operator methods + // all the below methods should be inlined as they are + // implemented over JIT intrinsics + + /// + /// Adds two vectors together. + /// + /// The first source vector. + /// The second source vector. + /// The summed vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Add(Vector2 left, Vector2 right) + { + return left + right; + } + + /// + /// Subtracts the second vector from the first. + /// + /// The first source vector. + /// The second source vector. + /// The difference vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Subtract(Vector2 left, Vector2 right) + { + return left - right; + } + + /// + /// Multiplies two vectors together. + /// + /// The first source vector. + /// The second source vector. + /// The product vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Multiply(Vector2 left, Vector2 right) + { + return left * right; + } + + /// + /// Multiplies a vector by the given scalar. + /// + /// The source vector. + /// The scalar value. + /// The scaled vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Multiply(Vector2 left, Single right) + { + return left * right; + } + + /// + /// Multiplies a vector by the given scalar. + /// + /// The scalar value. + /// The source vector. + /// The scaled vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Multiply(Single left, Vector2 right) + { + return left * right; + } + + /// + /// Divides the first vector by the second. + /// + /// The first source vector. + /// The second source vector. + /// The vector resulting from the division. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Divide(Vector2 left, Vector2 right) + { + return left / right; + } + + /// + /// Divides the vector by the given scalar. + /// + /// The source vector. + /// The scalar value. + /// The result of the division. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Divide(Vector2 left, Single divisor) + { + return left / divisor; + } + + /// + /// Negates a given vector. + /// + /// The source vector. + /// The negated vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Negate(Vector2 value) + { + return -value; + } + #endregion Public operator methods + } +} \ No newline at end of file diff --git a/Core/Numerics/Vector2_Intrinsics.cs b/Core/Numerics/Vector2_Intrinsics.cs new file mode 100644 index 0000000..f9c06bc --- /dev/null +++ b/Core/Numerics/Vector2_Intrinsics.cs @@ -0,0 +1,298 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using SharpEngine.Core.Numerics; +using System; +using System.Runtime.CompilerServices; + +namespace SharpEngine.Core.Numerics +{ + // This file contains the definitions for all of the JIT intrinsic methods and properties that are recognized by the current x64 JIT compiler. + // The implementation defined here is used in any circumstance where the JIT fails to recognize these members as intrinsic. + // The JIT recognizes these methods and properties by name and signature: if either is changed, the JIT will no longer recognize the member. + // Some methods declared here are not strictly intrinsic, but delegate to an intrinsic method. For example, only one overload of CopyTo() + + public partial struct Vector2 + { + /// + /// The X component of the vector. + /// + public Single X; + /// + /// The Y component of the vector. + /// + public Single Y; + + #region Constructors + /// + /// Constructs a vector whose elements are all the single specified value. + /// + /// The element to fill the vector with. + [JitIntrinsic] + public Vector2(Single value) : this(value, value) { } + + /// + /// Constructs a vector with the given individual elements. + /// + /// The X component. + /// The Y component. + [JitIntrinsic] + public Vector2(Single x, Single y) + { + X = x; + Y = y; + } + #endregion Constructors + + #region Public Instance Methods + /// + /// Copies the contents of the vector into the given array. + /// + /// The destination array. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyTo(Single[] array) + { + CopyTo(array, 0); + } + + /// + /// Copies the contents of the vector into the given array, starting from the given index. + /// + /// If array is null. + /// If array is multidimensional. + /// If index is greater than end of the array or index is less than zero. + /// If number of elements in source vector is greater than those available in destination array + /// or if there are not enough elements to copy. + public void CopyTo(Single[] array, int index) + { + if (array == null) + { + // Match the JIT's exception type here. For perf, a NullReference is thrown instead of an ArgumentNull. + throw new NullReferenceException(); + } + if (index < 0 || index >= array.Length) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + if ((array.Length - index) < 2) + { + throw new ArgumentException(nameof(index)); + } + array[index] = X; + array[index + 1] = Y; + } + + /// + /// Returns a boolean indicating whether the given Vector2 is equal to this Vector2 instance. + /// + /// The Vector2 to compare this instance to. + /// True if the other Vector2 is equal to this instance; False otherwise. + [JitIntrinsic] + public bool Equals(Vector2 other) + { + return this.X == other.X && this.Y == other.Y; + } + #endregion Public Instance Methods + + #region Public Static Methods + /// + /// Returns the dot product of two vectors. + /// + /// The first vector. + /// The second vector. + /// The dot product. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Dot(Vector2 value1, Vector2 value2) + { + return value1.X * value2.X + + value1.Y * value2.Y; + } + + /// + /// Returns a vector whose elements are the minimum of each of the pairs of elements in the two source vectors. + /// + /// The first source vector. + /// The second source vector. + /// The minimized vector. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Min(Vector2 value1, Vector2 value2) + { + return new Vector2( + (value1.X < value2.X) ? value1.X : value2.X, + (value1.Y < value2.Y) ? value1.Y : value2.Y); + } + + /// + /// Returns a vector whose elements are the maximum of each of the pairs of elements in the two source vectors + /// + /// The first source vector + /// The second source vector + /// The maximized vector + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Max(Vector2 value1, Vector2 value2) + { + return new Vector2( + (value1.X > value2.X) ? value1.X : value2.X, + (value1.Y > value2.Y) ? value1.Y : value2.Y); + } + + /// + /// Returns a vector whose elements are the absolute values of each of the source vector's elements. + /// + /// The source vector. + /// The absolute value vector. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Abs(Vector2 value) + { + return new Vector2(MathF.Abs(value.X), MathF.Abs(value.Y)); + } + + /// + /// Returns a vector whose elements are the square root of each of the source vector's elements. + /// + /// The source vector. + /// The square root vector. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 SquareRoot(Vector2 value) + { + return new Vector2((Single)MathF.Sqrt(value.X), (Single)MathF.Sqrt(value.Y)); + } + #endregion Public Static Methods + + #region Public Static Operators + /// + /// Adds two vectors together. + /// + /// The first source vector. + /// The second source vector. + /// The summed vector. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 operator +(Vector2 left, Vector2 right) + { + return new Vector2(left.X + right.X, left.Y + right.Y); + } + + /// + /// Subtracts the second vector from the first. + /// + /// The first source vector. + /// The second source vector. + /// The difference vector. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 operator -(Vector2 left, Vector2 right) + { + return new Vector2(left.X - right.X, left.Y - right.Y); + } + + /// + /// Multiplies two vectors together. + /// + /// The first source vector. + /// The second source vector. + /// The product vector. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 operator *(Vector2 left, Vector2 right) + { + return new Vector2(left.X * right.X, left.Y * right.Y); + } + + /// + /// Multiplies a vector by the given scalar. + /// + /// The scalar value. + /// The source vector. + /// The scaled vector. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 operator *(Single left, Vector2 right) + { + return new Vector2(left, left) * right; + } + + /// + /// Multiplies a vector by the given scalar. + /// + /// The source vector. + /// The scalar value. + /// The scaled vector. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 operator *(Vector2 left, Single right) + { + return left * new Vector2(right, right); + } + + /// + /// Divides the first vector by the second. + /// + /// The first source vector. + /// The second source vector. + /// The vector resulting from the division. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 operator /(Vector2 left, Vector2 right) + { + return new Vector2(left.X / right.X, left.Y / right.Y); + } + + /// + /// Divides the vector by the given scalar. + /// + /// The source vector. + /// The scalar value. + /// The result of the division. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 operator /(Vector2 value1, float value2) + { + float invDiv = 1.0f / value2; + return new Vector2( + value1.X * invDiv, + value1.Y * invDiv); + } + + /// + /// Negates a given vector. + /// + /// The source vector. + /// The negated vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 operator -(Vector2 value) + { + return Zero - value; + } + + /// + /// Returns a boolean indicating whether the two given vectors are equal. + /// + /// The first vector to compare. + /// The second vector to compare. + /// True if the vectors are equal; False otherwise. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(Vector2 left, Vector2 right) + { + return left.Equals(right); + } + + /// + /// Returns a boolean indicating whether the two given vectors are not equal. + /// + /// The first vector to compare. + /// The second vector to compare. + /// True if the vectors are not equal; False if they are equal. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(Vector2 left, Vector2 right) + { + return !(left == right); + } + #endregion Public Static Operators + } +} \ No newline at end of file diff --git a/Core/Numerics/Vector3.cs b/Core/Numerics/Vector3.cs new file mode 100644 index 0000000..bb289f8 --- /dev/null +++ b/Core/Numerics/Vector3.cs @@ -0,0 +1,477 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// https://github.com/microsoft/referencesource/blob/master/System.Numerics/System/Numerics/Vector3.cs + +using System; +using System.Globalization; +using System.Runtime.CompilerServices; +using System.Text; + +using Vector = System.Numerics.Vector; +using Matrix4x4 = System.Numerics.Matrix4x4; +using Quaternion = System.Numerics.Quaternion; + +namespace SharpEngine.Core.Numerics +{ + /// + /// A structure encapsulating three single precision floating point values and provides hardware accelerated methods. + /// + public partial struct Vector3 : IVector, IEquatable, IFormattable + { + #region Public Static Properties + /// + /// Returns the vector (0,0,0). + /// + public static Vector3 Zero { get { return new Vector3(); } } + /// + /// Returns the vector (1,1,1). + /// + public static Vector3 One { get { return new Vector3(1.0f, 1.0f, 1.0f); } } + /// + /// Returns the vector (1,0,0). + /// + public static Vector3 UnitX { get { return new Vector3(1.0f, 0.0f, 0.0f); } } + /// + /// Returns the vector (0,1,0). + /// + public static Vector3 UnitY { get { return new Vector3(0.0f, 1.0f, 0.0f); } } + /// + /// Returns the vector (0,0,1). + /// + public static Vector3 UnitZ { get { return new Vector3(0.0f, 0.0f, 1.0f); } } + #endregion Public Static Properties + + #region Public Instance Methods + + /// + /// Returns the hash code for this instance. + /// + /// The hash code. + public override int GetHashCode() + { + int hash = this.X.GetHashCode(); + hash = HashCodeHelper.CombineHashCodes(hash, this.Y.GetHashCode()); + hash = HashCodeHelper.CombineHashCodes(hash, this.Z.GetHashCode()); + return hash; + } + + /// + /// Returns a boolean indicating whether the given Object is equal to this Vector3 instance. + /// + /// The Object to compare against. + /// True if the Object is equal to this Vector3; False otherwise. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override bool Equals(object obj) + { + if (!(obj is Vector3)) + return false; + return Equals((Vector3)obj); + } + + /// + /// Returns a String representing this Vector3 instance. + /// + /// The string representation. + public override string ToString() + { + return ToString("G", CultureInfo.CurrentCulture); + } + + /// + /// Returns a String representing this Vector3 instance, using the specified format to format individual elements. + /// + /// The format of individual elements. + /// The string representation. + public string ToString(string format) + { + return ToString(format, CultureInfo.CurrentCulture); + } + + /// + /// Returns a String representing this Vector3 instance, using the specified format to format individual elements + /// and the given IFormatProvider. + /// + /// The format of individual elements. + /// The format provider to use when formatting elements. + /// The string representation. + public string ToString(string format, IFormatProvider formatProvider) + { + StringBuilder sb = new StringBuilder(); + string separator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator; + sb.Append('<'); + sb.Append(((IFormattable)this.X).ToString(format, formatProvider)); + sb.Append(separator); + sb.Append(' '); + sb.Append(((IFormattable)this.Y).ToString(format, formatProvider)); + sb.Append(separator); + sb.Append(' '); + sb.Append(((IFormattable)this.Z).ToString(format, formatProvider)); + sb.Append('>'); + return sb.ToString(); + } + + /// + /// Returns the length of the vector. + /// + /// The vector's length. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public float Length() + { + if (Vector.IsHardwareAccelerated) + { + float ls = Vector3.Dot(this, this); + return (float)System.Math.Sqrt(ls); + } + else + { + float ls = X * X + Y * Y + Z * Z; + return (float)System.Math.Sqrt(ls); + } + } + + /// + /// Returns the length of the vector squared. This operation is cheaper than Length(). + /// + /// The vector's length squared. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public float LengthSquared() + { + if (Vector.IsHardwareAccelerated) + { + return Vector3.Dot(this, this); + } + else + { + return X * X + Y * Y + Z * Z; + } + } + #endregion Public Instance Methods + + #region Public Static Methods + /// + /// Returns the Euclidean distance between the two given points. + /// + /// The first point. + /// The second point. + /// The distance. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Distance(Vector3 value1, Vector3 value2) + { + if (Vector.IsHardwareAccelerated) + { + Vector3 difference = value1 - value2; + float ls = Vector3.Dot(difference, difference); + return (float)System.Math.Sqrt(ls); + } + else + { + float dx = value1.X - value2.X; + float dy = value1.Y - value2.Y; + float dz = value1.Z - value2.Z; + + float ls = dx * dx + dy * dy + dz * dz; + + return (float)System.Math.Sqrt((double)ls); + } + } + + /// + /// Returns the Euclidean distance squared between the two given points. + /// + /// The first point. + /// The second point. + /// The distance squared. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float DistanceSquared(Vector3 value1, Vector3 value2) + { + if (Vector.IsHardwareAccelerated) + { + Vector3 difference = value1 - value2; + return Vector3.Dot(difference, difference); + } + else + { + float dx = value1.X - value2.X; + float dy = value1.Y - value2.Y; + float dz = value1.Z - value2.Z; + + return dx * dx + dy * dy + dz * dz; + } + } + + /// + /// Returns a vector with the same direction as the given vector, but with a length of 1. + /// + /// The vector to normalize. + /// The normalized vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Normalize(Vector3 value) + { + if (Vector.IsHardwareAccelerated) + { + float length = value.Length(); + return value / length; + } + else + { + float ls = value.X * value.X + value.Y * value.Y + value.Z * value.Z; + float length = (float)System.Math.Sqrt(ls); + return new Vector3(value.X / length, value.Y / length, value.Z / length); + } + } + + /// + /// Computes the cross product of two vectors. + /// + /// The first vector. + /// The second vector. + /// The cross product. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Cross(Vector3 vector1, Vector3 vector2) + { + return new Vector3( + vector1.Y * vector2.Z - vector1.Z * vector2.Y, + vector1.Z * vector2.X - vector1.X * vector2.Z, + vector1.X * vector2.Y - vector1.Y * vector2.X); + } + + /// + /// Returns the reflection of a vector off a surface that has the specified normal. + /// + /// The source vector. + /// The normal of the surface being reflected off. + /// The reflected vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Reflect(Vector3 vector, Vector3 normal) + { + if (System.Numerics.Vector.IsHardwareAccelerated) + { + float dot = Vector3.Dot(vector, normal); + Vector3 temp = normal * dot * 2f; + return vector - temp; + } + else + { + float dot = vector.X * normal.X + vector.Y * normal.Y + vector.Z * normal.Z; + float tempX = normal.X * dot * 2f; + float tempY = normal.Y * dot * 2f; + float tempZ = normal.Z * dot * 2f; + return new Vector3(vector.X - tempX, vector.Y - tempY, vector.Z - tempZ); + } + } + + /// + /// Restricts a vector between a min and max value. + /// + /// The source vector. + /// The minimum value. + /// The maximum value. + /// The restricted vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Clamp(Vector3 value1, Vector3 min, Vector3 max) + { + // This compare order is very important!!! + // We must follow HLSL behavior in the case user specified min value is bigger than max value. + + float x = value1.X; + x = (x > max.X) ? max.X : x; + x = (x < min.X) ? min.X : x; + + float y = value1.Y; + y = (y > max.Y) ? max.Y : y; + y = (y < min.Y) ? min.Y : y; + + float z = value1.Z; + z = (z > max.Z) ? max.Z : z; + z = (z < min.Z) ? min.Z : z; + + return new Vector3(x, y, z); + } + + /// + /// Linearly interpolates between two vectors based on the given weighting. + /// + /// The first source vector. + /// The second source vector. + /// Value between 0 and 1 indicating the weight of the second source vector. + /// The interpolated vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Lerp(Vector3 value1, Vector3 value2, float amount) + { + if (Vector.IsHardwareAccelerated) + { + Vector3 firstInfluence = value1 * (1f - amount); + Vector3 secondInfluence = value2 * amount; + return firstInfluence + secondInfluence; + } + else + { + return new Vector3( + value1.X + (value2.X - value1.X) * amount, + value1.Y + (value2.Y - value1.Y) * amount, + value1.Z + (value2.Z - value1.Z) * amount); + } + } + + /// + /// Transforms a vector by the given matrix. + /// + /// The source vector. + /// The transformation matrix. + /// The transformed vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Transform(Vector3 position, Matrix4x4 matrix) + { + return new Vector3( + position.X * matrix.M11 + position.Y * matrix.M21 + position.Z * matrix.M31 + matrix.M41, + 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) + { + return new Vector3( + 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. + /// + /// The source vector to be rotated. + /// The rotation to apply. + /// The transformed vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Transform(Vector3 value, Quaternion rotation) + { + float x2 = rotation.X + rotation.X; + float y2 = rotation.Y + rotation.Y; + float z2 = rotation.Z + rotation.Z; + + float wx2 = rotation.W * x2; + float wy2 = rotation.W * y2; + float wz2 = rotation.W * z2; + float xx2 = rotation.X * x2; + float xy2 = rotation.X * y2; + float xz2 = rotation.X * z2; + float yy2 = rotation.Y * y2; + float yz2 = rotation.Y * z2; + float zz2 = rotation.Z * z2; + + return new Vector3( + value.X * (1.0f - yy2 - zz2) + value.Y * (xy2 - wz2) + value.Z * (xz2 + wy2), + 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)); + } + #endregion Public Static Methods + + #region Public operator methods + + // All these methods should be inlined as they are implemented + // over JIT intrinsics + + /// + /// Adds two vectors together. + /// + /// The first source vector. + /// The second source vector. + /// The summed vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Add(Vector3 left, Vector3 right) + { + return left + right; + } + + /// + /// Subtracts the second vector from the first. + /// + /// The first source vector. + /// The second source vector. + /// The difference vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Subtract(Vector3 left, Vector3 right) + { + return left - right; + } + + /// + /// Multiplies two vectors together. + /// + /// The first source vector. + /// The second source vector. + /// The product vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Multiply(Vector3 left, Vector3 right) + { + return left * right; + } + + /// + /// Multiplies a vector by the given scalar. + /// + /// The source vector. + /// The scalar value. + /// The scaled vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Multiply(Vector3 left, Single right) + { + return left * right; + } + + /// + /// Multiplies a vector by the given scalar. + /// + /// The scalar value. + /// The source vector. + /// The scaled vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Multiply(Single left, Vector3 right) + { + return left * right; + } + + /// + /// Divides the first vector by the second. + /// + /// The first source vector. + /// The second source vector. + /// The vector resulting from the division. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Divide(Vector3 left, Vector3 right) + { + return left / right; + } + + /// + /// Divides the vector by the given scalar. + /// + /// The source vector. + /// The scalar value. + /// The result of the division. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Divide(Vector3 left, Single divisor) + { + return left / divisor; + } + + /// + /// Negates a given vector. + /// + /// The source vector. + /// The negated vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Negate(Vector3 value) + { + return -value; + } + #endregion Public operator methods + } +} \ No newline at end of file diff --git a/Core/Numerics/Vector3_Intrinsics.cs b/Core/Numerics/Vector3_Intrinsics.cs new file mode 100644 index 0000000..40146ad --- /dev/null +++ b/Core/Numerics/Vector3_Intrinsics.cs @@ -0,0 +1,324 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Runtime.CompilerServices; + +namespace SharpEngine.Core.Numerics +{ + // This file contains the definitions for all of the JIT intrinsic methods and properties that are recognized by the current x64 JIT compiler. + // The implementation defined here is used in any circumstance where the JIT fails to recognize these members as intrinsic. + // The JIT recognizes these methods and properties by name and signature: if either is changed, the JIT will no longer recognize the member. + // Some methods declared here are not strictly intrinsic, but delegate to an intrinsic method. For example, only one overload of CopyTo() + // is actually recognized by the JIT, but both are here for simplicity. + + public partial struct Vector3 + { + /// + /// The X component of the vector. + /// + public Single X; + /// + /// The Y component of the vector. + /// + public Single Y; + /// + /// The Z component of the vector. + /// + public Single Z; + + #region Constructors + /// + /// Constructs a vector whose elements are all the single specified value. + /// + /// The element to fill the vector with. + [JitIntrinsic] + public Vector3(Single value) : this(value, value, value) { } + + /// + /// Constructs a Vector3 from the given Vector2 and a third value. + /// + /// The Vector to extract X and Y components from. + /// The Z component. + public Vector3(Vector2 value, float z) : this(value.X, value.Y, z) { } + + /// + /// Constructs a vector with the given individual elements. + /// + /// The X component. + /// The Y component. + /// The Z component. + [JitIntrinsic] + public Vector3(Single x, Single y, Single z) + { + X = x; + Y = y; + Z = z; + } + #endregion Constructors + + #region Public Instance Methods + /// + /// Copies the contents of the vector into the given array. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyTo(Single[] array) + { + CopyTo(array, 0); + } + + /// + /// Copies the contents of the vector into the given array, starting from index. + /// + /// If array is null. + /// If array is multidimensional. + /// If index is greater than end of the array or index is less than zero. + /// If number of elements in source vector is greater than those available in destination array. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyTo(Single[] array, int index) + { + if (array == null) + { + // Match the JIT's exception type here. For perf, a NullReference is thrown instead of an ArgumentNull. + throw new NullReferenceException(); + } + if (index < 0 || index >= array.Length) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + if ((array.Length - index) < 3) + { + throw new ArgumentException("", nameof(index)); + } + + array[index] = X; + array[index + 1] = Y; + array[index + 2] = Z; + } + + /// + /// Returns a boolean indicating whether the given Vector3 is equal to this Vector3 instance. + /// + /// The Vector3 to compare this instance to. + /// True if the other Vector3 is equal to this instance; False otherwise. + [JitIntrinsic] + public bool Equals(Vector3 other) + { + return X == other.X && + Y == other.Y && + Z == other.Z; + } + #endregion Public Instance Methods + + #region Public Static Methods + /// + /// Returns the dot product of two vectors. + /// + /// The first vector. + /// The second vector. + /// The dot product. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Dot(Vector3 vector1, Vector3 vector2) + { + return vector1.X * vector2.X + + vector1.Y * vector2.Y + + vector1.Z * vector2.Z; + } + + /// + /// Returns a vector whose elements are the minimum of each of the pairs of elements in the two source vectors. + /// + /// The first source vector. + /// The second source vector. + /// The minimized vector. + [JitIntrinsic] + public static Vector3 Min(Vector3 value1, Vector3 value2) + { + return new Vector3( + (value1.X < value2.X) ? value1.X : value2.X, + (value1.Y < value2.Y) ? value1.Y : value2.Y, + (value1.Z < value2.Z) ? value1.Z : value2.Z); + } + + /// + /// Returns a vector whose elements are the maximum of each of the pairs of elements in the two source vectors. + /// + /// The first source vector. + /// The second source vector. + /// The maximized vector. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Max(Vector3 value1, Vector3 value2) + { + return new Vector3( + (value1.X > value2.X) ? value1.X : value2.X, + (value1.Y > value2.Y) ? value1.Y : value2.Y, + (value1.Z > value2.Z) ? value1.Z : value2.Z); + } + + /// + /// Returns a vector whose elements are the absolute values of each of the source vector's elements. + /// + /// The source vector. + /// The absolute value vector. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Abs(Vector3 value) + { + return new Vector3(MathF.Abs(value.X), MathF.Abs(value.Y), MathF.Abs(value.Z)); + } + + /// + /// Returns a vector whose elements are the square root of each of the source vector's elements. + /// + /// The source vector. + /// The square root vector. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 SquareRoot(Vector3 value) + { + return new Vector3((Single)MathF.Sqrt(value.X), (Single)MathF.Sqrt(value.Y), (Single)MathF.Sqrt(value.Z)); + } + #endregion Public Static Methods + + #region Public Static Operators + /// + /// Adds two vectors together. + /// + /// The first source vector. + /// The second source vector. + /// The summed vector. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 operator +(Vector3 left, Vector3 right) + { + return new Vector3(left.X + right.X, left.Y + right.Y, left.Z + right.Z); + } + + /// + /// Subtracts the second vector from the first. + /// + /// The first source vector. + /// The second source vector. + /// The difference vector. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 operator -(Vector3 left, Vector3 right) + { + return new Vector3(left.X - right.X, left.Y - right.Y, left.Z - right.Z); + } + + /// + /// Multiplies two vectors together. + /// + /// The first source vector. + /// The second source vector. + /// The product vector. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 operator *(Vector3 left, Vector3 right) + { + return new Vector3(left.X * right.X, left.Y * right.Y, left.Z * right.Z); + } + + /// + /// Multiplies a vector by the given scalar. + /// + /// The source vector. + /// The scalar value. + /// The scaled vector. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 operator *(Vector3 left, Single right) + { + return left * new Vector3(right); + } + + /// + /// Multiplies a vector by the given scalar. + /// + /// The scalar value. + /// The source vector. + /// The scaled vector. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 operator *(Single left, Vector3 right) + { + return new Vector3(left) * right; + } + + /// + /// Divides the first vector by the second. + /// + /// The first source vector. + /// The second source vector. + /// The vector resulting from the division. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 operator /(Vector3 left, Vector3 right) + { + return new Vector3(left.X / right.X, left.Y / right.Y, left.Z / right.Z); + } + + /// + /// Divides the vector by the given scalar. + /// + /// The source vector. + /// The scalar value. + /// The result of the division. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 operator /(Vector3 value1, float value2) + { + float invDiv = 1.0f / value2; + + return new Vector3( + value1.X * invDiv, + value1.Y * invDiv, + value1.Z * invDiv); + } + + /// + /// Negates a given vector. + /// + /// The source vector. + /// The negated vector. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 operator -(Vector3 value) + { + return Zero - value; + } + + /// + /// Returns a boolean indicating whether the two given vectors are equal. + /// + /// The first vector to compare. + /// The second vector to compare. + /// True if the vectors are equal; False otherwise. + [JitIntrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(Vector3 left, Vector3 right) + { + return (left.X == right.X && + left.Y == right.Y && + left.Z == right.Z); + } + + /// + /// Returns a boolean indicating whether the two given vectors are not equal. + /// + /// The first vector to compare. + /// The second vector to compare. + /// True if the vectors are not equal; False if they are equal. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(Vector3 left, Vector3 right) + { + return (left.X != right.X || + left.Y != right.Y || + left.Z != right.Z); + } + #endregion Public Static Operators + } +} \ No newline at end of file diff --git a/Core/Scenes/SceneNode.cs b/Core/Scenes/SceneNode.cs index 1fdcee6..106f45e 100644 --- a/Core/Scenes/SceneNode.cs +++ b/Core/Scenes/SceneNode.cs @@ -1,13 +1,28 @@ -using System.Collections.Generic; +using SharpEngine.Core.Entities; +using SharpEngine.Core.Entities.Properties; +using SharpEngine.Core.Numerics; +using System.Collections.Generic; using System.Threading.Tasks; namespace SharpEngine.Core.Scenes; +public class EmptyNode : SceneNode where TTransform : ITransform, new() +{ + public EmptyNode(string name) : base(name) { } + + public override TTransform Transform { get; set; } = new(); + +} + /// /// Represents a node in the scene. /// -public class SceneNode +public abstract class SceneNode where TTransform : ITransform, new() { + public abstract TTransform Transform { get; set; } + + public static SceneNode Empty => new EmptyNode("Empty Node"); + /// /// Gets or sets the name of the node. /// @@ -16,15 +31,15 @@ public class SceneNode /// /// Gets or sets the children of the node. /// - public List Children { get; set; } = []; + public List> Children { get; set; } = []; /// - /// Initializes a new empty . + /// Initializes a new empty . /// public SceneNode() { } /// - /// Initializes a new instance of the with the specified . + /// Initializes a new instance of the with the specified . /// /// The name of the new empty node. public SceneNode(string name) @@ -37,20 +52,20 @@ public SceneNode(string name) /// /// The name of the empty node to be added. /// The created node. - public SceneNode AddChild(string name) + public virtual SceneNode AddChild(string name) { - var node = new SceneNode(name); - Children.Add(node); + var node = new EmptyNode(name) as SceneNode; + Children.Add(node!); - return node; + return node!; } - /// - /// Adds a child node to this node. - /// - /// The nodes to be added. - /// The current node. - public virtual SceneNode AddChild(params SceneNode[] nodes) + /// + /// Adds a child node to this node. + /// + /// The nodes to be added. + /// The current node. + public virtual SceneNode AddChild(params SceneNode[] nodes) { foreach (var node in nodes) Children.Add(node); @@ -62,7 +77,7 @@ public virtual SceneNode AddChild(params SceneNode[] nodes) /// Removes a child node from this node. /// /// The node to be removed. - public void RemoveChild(SceneNode node) + public void RemoveChild(SceneNode node) { Children.Remove(node); } diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index 11785e3..136e55a 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -13,6 +13,7 @@ using SharpEngine.Core.Entities.UI; using SharpEngine.Core.Windowing; using SharpEngine.Core.Entities.UI.Layouts; +using SharpEngine.Core.Entities.Properties; namespace Minecraft; @@ -25,8 +26,8 @@ public class Minecraft : Game { private readonly Scene _scene; - private SceneNode _lightsNode; - private SceneNode _blocksNode; + private SceneNode _lightsNode; + private SceneNode _blocksNode; private Input _input; private readonly Inventory _inventory; @@ -71,7 +72,7 @@ public override void Initialize() uiElem2.Transform.Scale = new Vector2(0.2f, 0.2f); //uiElem2.Transform.Position = new Vector2(30, 0); - //gridLayout.AddChild(_uiElem, uiElem2); + gridLayout.AddChild(_uiElem, uiElem2); _scene.UIElements.Add(gridLayout); @@ -153,7 +154,7 @@ public override void Update(double deltaTime, IInputContext input) } private void UpdateUI() - => _uiElem.Transform.Rotation += 0.01f; + => _uiElem.Transform.Rotation.Angle += 0.01f; // TODO: Input system to let users change change key bindings? /// From be73f35bf9cc7ad1c37aa397bc3cd9486feda660 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Fri, 4 Apr 2025 20:57:08 +0300 Subject: [PATCH 27/92] Midway solution (Not finished) --- Core/Entities/GameObject.cs | 6 ++--- Core/Entities/Lights/PointLight.cs | 8 +++---- Core/Entities/Lights/SpotLight.cs | 2 +- Core/Entities/Properties/BoundingBox.cs | 2 +- Core/Entities/Properties/ITransform.cs | 13 +++++----- .../Entities/Properties/Meshes/MeshService.cs | 22 +++++++++++++++-- Core/Entities/Properties/Transform.cs | 11 ++------- Core/Entities/UI/Layouts/FlexLayout.cs | 2 +- Core/Entities/UI/Layouts/GridLayout.cs | 4 ++-- Core/Entities/UI/Layouts/LayoutBase.cs | 7 +++--- Core/Entities/UI/UIElement.cs | 10 ++++---- Core/Numerics/Vector2.cs | 1 + Core/Numerics/Vector2_Intrinsics.cs | 7 ++++++ Core/Numerics/Vector3_Intrinsics.cs | 7 ++++++ Core/Primitives/PrimitiveFactory.cs | 2 +- Core/Renderers/RenderFlags.cs | 3 ++- Core/Renderers/TextRenderer.cs | 20 ++++++++++++++++ Core/Scenes/Scene.cs | 5 ++-- Core/Scenes/SceneNode.cs | 24 +++++++++---------- Editor/Windows/ContextMenuWindow.cs | 2 +- Examples/MinecraftClone/Minecraft.cs | 10 ++++---- 21 files changed, 108 insertions(+), 60 deletions(-) create mode 100644 Core/Renderers/TextRenderer.cs diff --git a/Core/Entities/GameObject.cs b/Core/Entities/GameObject.cs index 415a490..4c58dd8 100644 --- a/Core/Entities/GameObject.cs +++ b/Core/Entities/GameObject.cs @@ -16,7 +16,7 @@ namespace SharpEngine.Core.Entities; /// /// Represents a game object in the scene. /// -public class GameObject : SceneNode +public class GameObject : SceneNode { /// /// Initializes a new instance of the . @@ -62,7 +62,7 @@ public GameObject(string? diffuseMapFile = null, string? specularMapFile = null, /// /// Gets or sets the transform of the game object. /// - public override Transform Transform + public Transform Transform { get => _transform; set @@ -72,7 +72,7 @@ public override Transform Transform } } - private Transform _transform; + private Transform _transform = new(); /// /// Gets the bounding box of the game object. diff --git a/Core/Entities/Lights/PointLight.cs b/Core/Entities/Lights/PointLight.cs index 0dcdeff..e63d141 100644 --- a/Core/Entities/Lights/PointLight.cs +++ b/Core/Entities/Lights/PointLight.cs @@ -19,7 +19,7 @@ public class PointLight : Light public PointLight(Vector3 position, int index) { Transform.Scale = new(0.2f, 0.2f, 0.2f); - Transform.Position = position; + Transform.Position = (SharpEngine.Core.Numerics.Vector3)position; Constant = 1.0f; Linear = 0.09f; Quadratic = 0.032f; @@ -53,7 +53,7 @@ public PointLight(Vector3 position, int index) /// public override Task Render() { - Material.Shader.SetVector3($"pointLights[{_index}].position", Transform.Position); + Material.Shader.SetVector3($"pointLights[{_index}].position", (System.Numerics.Vector3)Transform.Position); Material.Shader.SetVector3($"pointLights[{_index}].ambient", Ambient); Material.Shader.SetVector3($"pointLights[{_index}].diffuse", Diffuse); Material.Shader.SetVector3($"pointLights[{_index}].specular", Specular); @@ -61,8 +61,8 @@ public override Task Render() Material.Shader.SetFloat($"pointLights[{_index}].linear", Linear); Material.Shader.SetFloat($"pointLights[{_index}].quadratic", Quadratic); - var lampMatrix = Matrix4x4.CreateScale(Transform.Scale); - lampMatrix *= Matrix4x4.CreateTranslation(Transform.Position); + var lampMatrix = Matrix4x4.CreateScale((System.Numerics.Vector3)Transform.Scale); + lampMatrix *= Matrix4x4.CreateTranslation((System.Numerics.Vector3)Transform.Position); LampShader.Shader?.SetMatrix4(ShaderAttributes.Model, lampMatrix); diff --git a/Core/Entities/Lights/SpotLight.cs b/Core/Entities/Lights/SpotLight.cs index 4a839f0..e63597d 100644 --- a/Core/Entities/Lights/SpotLight.cs +++ b/Core/Entities/Lights/SpotLight.cs @@ -59,7 +59,7 @@ public SpotLight() /// public override Task Render() { - Material.Shader.SetVector3("spotLight.position", Transform.Position); + Material.Shader.SetVector3("spotLight.position", (System.Numerics.Vector3)Transform.Position); Material.Shader.SetVector3("spotLight.direction", Direction); Material.Shader.SetVector3("spotLight.ambient", Ambient); Material.Shader.SetVector3("spotLight.diffuse", Diffuse); diff --git a/Core/Entities/Properties/BoundingBox.cs b/Core/Entities/Properties/BoundingBox.cs index 1119c28..598d519 100644 --- a/Core/Entities/Properties/BoundingBox.cs +++ b/Core/Entities/Properties/BoundingBox.cs @@ -36,6 +36,6 @@ public static BoundingBox CalculateBoundingBox(Transform transform) { var min = transform.Position - (transform.Scale / 2); var max = transform.Position + (transform.Scale / 2); - return new BoundingBox(min, max); + return new BoundingBox((Vector3)min, (Vector3)max); } } diff --git a/Core/Entities/Properties/ITransform.cs b/Core/Entities/Properties/ITransform.cs index 65108b0..5685511 100644 --- a/Core/Entities/Properties/ITransform.cs +++ b/Core/Entities/Properties/ITransform.cs @@ -1,11 +1,12 @@ -using System.Numerics; +using SharpEngine.Core.Numerics; +using System.Numerics; namespace SharpEngine.Core.Entities.Properties; -public interface ITransform +public interface ITransform where TVector : IVector { - public abstract IVector Position { get; set; } - public abstract IVector Scale { get; set; } - public abstract Quaternion Rotation { get; set; } - public abstract Matrix4x4 ModelMatrix { get; } + public TVector Position { get; set; } + public TVector Scale { get; set; } + public Quaternion Rotation { get; set; } + public Matrix4x4 ModelMatrix { get; } } \ No newline at end of file diff --git a/Core/Entities/Properties/Meshes/MeshService.cs b/Core/Entities/Properties/Meshes/MeshService.cs index d50b576..e884bf7 100644 --- a/Core/Entities/Properties/Meshes/MeshService.cs +++ b/Core/Entities/Properties/Meshes/MeshService.cs @@ -2,6 +2,7 @@ using Silk.NET.OpenGL; using System; using System.Collections.Generic; +using System.IO; namespace SharpEngine.Core.Entities.Properties.Meshes; @@ -38,10 +39,27 @@ public Mesh LoadMesh(string identifier, Mesh mesh) return mesh; } + const string FbxExtension = ".fbx"; + const string ObjExtension = ".obj"; + public Mesh LoadMesh(string identifier, string meshFilePath) + => Path.GetExtension(meshFilePath) switch + { + FbxExtension => LoadFbxMesh(identifier, meshFilePath), + ObjExtension => LoadObjMesh(identifier, meshFilePath), + _ => throw new NotSupportedException($"The file extension {Path.GetExtension(meshFilePath)} is not a supported mesh file.") + }; + + // TODO: #2 Load obj mesh from file + private Mesh LoadObjMesh(string identifier, string meshFilePath) + { + throw new NotImplementedException(); + } + + // TODO: #3 Load fbx mesh from file + private Mesh LoadFbxMesh(string identifier, string meshFilePath) { - throw new NotImplementedException("Loading meshes from files is not currently supported."); + throw new NotImplementedException(); } - // TODO: #3 & #2 Load mesh from file } \ No newline at end of file diff --git a/Core/Entities/Properties/Transform.cs b/Core/Entities/Properties/Transform.cs index 7370aea..c934172 100644 --- a/Core/Entities/Properties/Transform.cs +++ b/Core/Entities/Properties/Transform.cs @@ -1,8 +1,5 @@ -using Silk.NET.Maths; -using SharpEngine.Core.Entities; -using System.Numerics; - -using Vector3 = SharpEngine.Core.Numerics.Vector3; +using SharpEngine.Core.Numerics; +using Matrix4x4 = System.Numerics.Matrix4x4; namespace SharpEngine.Core.Entities.Properties; @@ -11,10 +8,6 @@ namespace SharpEngine.Core.Entities.Properties; /// public class Transform : ITransform { - public Transform() - { - } - /// /// Gets or sets the position of the game object. /// diff --git a/Core/Entities/UI/Layouts/FlexLayout.cs b/Core/Entities/UI/Layouts/FlexLayout.cs index 6768311..d65776e 100644 --- a/Core/Entities/UI/Layouts/FlexLayout.cs +++ b/Core/Entities/UI/Layouts/FlexLayout.cs @@ -8,7 +8,7 @@ namespace SharpEngine.Core.Entities.UI.Layouts; /// Represents a layout that dynamically distributes items in a flex layout. /// /// The type of items in the collection. -public class FlexLayout : LayoutBase where T : SceneNode +public class FlexLayout : LayoutBase where T : SceneNode, new() { public int Gap { get; set; } diff --git a/Core/Entities/UI/Layouts/GridLayout.cs b/Core/Entities/UI/Layouts/GridLayout.cs index 20bd9b3..b542bcf 100644 --- a/Core/Entities/UI/Layouts/GridLayout.cs +++ b/Core/Entities/UI/Layouts/GridLayout.cs @@ -9,7 +9,7 @@ namespace SharpEngine.Core.Entities.UI.Layouts; /// Represents a grid layout. /// /// The type of items that can be stored and retrieved within the grid. -public class GridLayout : LayoutBase where T : SceneNode> +public class GridLayout : LayoutBase where T : SceneNode, new() { /// Gets or sets the amount of rows in the grid. public uint Rows { get; set; } = 2; @@ -47,7 +47,7 @@ public override void AddItem(T item) if (Items.Count % Columns != 0) offset = offset + (Items.Count * 30); - item.Transform.Position.X = offset; + // item.Transform.Position.X = offset; } /// diff --git a/Core/Entities/UI/Layouts/LayoutBase.cs b/Core/Entities/UI/Layouts/LayoutBase.cs index e21404e..cdb5f8d 100644 --- a/Core/Entities/UI/Layouts/LayoutBase.cs +++ b/Core/Entities/UI/Layouts/LayoutBase.cs @@ -1,4 +1,5 @@ using SharpEngine.Core.Entities.Properties; +using SharpEngine.Core.Numerics; using SharpEngine.Core.Scenes; using System; using System.Collections.Generic; @@ -8,14 +9,12 @@ namespace SharpEngine.Core.Entities.UI.Layouts; -public abstract class LayoutBase : EmptyNode where T : SceneNode, new() +public abstract class LayoutBase : SceneNode where T : SceneNode, new() { public List Items { get; set; } = []; - public override SceneNode AddChild(params SceneNode[] nodes) + public override LayoutBase AddChild(params SceneNode[] nodes) { - base.AddChild(nodes); - foreach (var node in nodes) AddItem((T)node); diff --git a/Core/Entities/UI/UIElement.cs b/Core/Entities/UI/UIElement.cs index ec90445..2e0a549 100644 --- a/Core/Entities/UI/UIElement.cs +++ b/Core/Entities/UI/UIElement.cs @@ -12,8 +12,10 @@ namespace SharpEngine.Core.Entities.UI; /// /// Represents a User Interface entity. /// -public class UIElement : SceneNode +public class UIElement : SceneNode { + public UIElement() : this("UIElement") { } + /// /// Initializes a new instance of . /// @@ -29,7 +31,7 @@ public UIElement(string name) private readonly UIShader _uiShader = new(); /// Gets or sets the 2D space transformation of the UI element. - public override Transform2D Transform { get; set; } = new(); + public Transform2D Transform { get; set; } = new(); /// Gets or sets the mesh of the UI element. public new Mesh Mesh { get; set; } @@ -75,9 +77,9 @@ public override Task Render() { Window.GL.BindVertexArray(_vertexArrayObject); - _uiShader.Shader.SetVector2("position", Transform.Position); + _uiShader.Shader.SetVector2("position", (System.Numerics.Vector2)Transform.Position); _uiShader.Shader.SetFloat("rotation", Transform.Rotation.Angle); - _uiShader.Shader.SetVector2("scale", Transform.Scale); + _uiShader.Shader.SetVector2("scale", (System.Numerics.Vector2)Transform.Scale); Window.GL.DrawElements(PrimitiveType.Triangles, (uint)Mesh.Indices.Length, DrawElementsType.UnsignedInt, []); diff --git a/Core/Numerics/Vector2.cs b/Core/Numerics/Vector2.cs index 7956d9f..231abec 100644 --- a/Core/Numerics/Vector2.cs +++ b/Core/Numerics/Vector2.cs @@ -453,6 +453,7 @@ public static Vector2 Negate(Vector2 value) { return -value; } + #endregion Public operator methods } } \ No newline at end of file diff --git a/Core/Numerics/Vector2_Intrinsics.cs b/Core/Numerics/Vector2_Intrinsics.cs index f9c06bc..6619057 100644 --- a/Core/Numerics/Vector2_Intrinsics.cs +++ b/Core/Numerics/Vector2_Intrinsics.cs @@ -293,6 +293,13 @@ public static Vector2 SquareRoot(Vector2 value) { return !(left == right); } + + public static explicit operator System.Numerics.Vector2(Vector2 value) + => new(value.X, value.Y); + + public static explicit operator Vector2(System.Numerics.Vector2 value) + => new(value.X, value.Y); + #endregion Public Static Operators } } \ No newline at end of file diff --git a/Core/Numerics/Vector3_Intrinsics.cs b/Core/Numerics/Vector3_Intrinsics.cs index 40146ad..71456df 100644 --- a/Core/Numerics/Vector3_Intrinsics.cs +++ b/Core/Numerics/Vector3_Intrinsics.cs @@ -319,6 +319,13 @@ public static Vector3 SquareRoot(Vector3 value) left.Y != right.Y || left.Z != right.Z); } + + public static explicit operator System.Numerics.Vector3(Vector3 value) + => new(value.X, value.Y, value.Z); + + public static explicit operator Vector3(System.Numerics.Vector3 value) + => new(value.X, value.Y, value.Z); + #endregion Public Static Operators } } \ No newline at end of file diff --git a/Core/Primitives/PrimitiveFactory.cs b/Core/Primitives/PrimitiveFactory.cs index 497861e..51f03d0 100644 --- a/Core/Primitives/PrimitiveFactory.cs +++ b/Core/Primitives/PrimitiveFactory.cs @@ -32,7 +32,7 @@ public static GameObject Create(PrimitiveType primitiveType, Vector3 position) public static GameObject Create(PrimitiveType primitiveType, Vector3 position, string diffuseMapFile, string? specularMapFile = null, string? vertShaderFile = null, string? fragShaderFile = null) => new(diffuseMapFile, specularMapFile, vertShaderFile ?? _Resources.Default.VertexShader, fragShaderFile ?? _Resources.Default.FragmentShader) { - Transform = new Transform { Position = position }, + Transform = new Transform { Position = (SharpEngine.Core.Numerics.Vector3)position }, Mesh = primitiveType switch { PrimitiveType.Cube => [Cube.Mesh], diff --git a/Core/Renderers/RenderFlags.cs b/Core/Renderers/RenderFlags.cs index 68d5137..2e208a2 100644 --- a/Core/Renderers/RenderFlags.cs +++ b/Core/Renderers/RenderFlags.cs @@ -22,5 +22,6 @@ public enum RenderFlags /// /// Enables all renderers. /// - All = 3 + All = 3, + Text = 4 } diff --git a/Core/Renderers/TextRenderer.cs b/Core/Renderers/TextRenderer.cs new file mode 100644 index 0000000..eff8504 --- /dev/null +++ b/Core/Renderers/TextRenderer.cs @@ -0,0 +1,20 @@ +using SharpEngine.Core.Entities.Views; +using SharpEngine.Core.Interfaces; +using SharpEngine.Core.Scenes; +using System.Threading.Tasks; + +namespace SharpEngine.Core.Renderers; +internal class TextRenderer : RendererBase +{ + 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/Core/Scenes/Scene.cs b/Core/Scenes/Scene.cs index 3f46da7..80f71ab 100644 --- a/Core/Scenes/Scene.cs +++ b/Core/Scenes/Scene.cs @@ -1,4 +1,5 @@ using SharpEngine.Core.Entities; +using SharpEngine.Core.Entities.Properties; using SharpEngine.Core.Entities.UI; using System; using System.Collections.Generic; @@ -41,7 +42,7 @@ public Scene(string sceneFile) /// /// Gets or sets the root node of the scene. /// - public SceneNode Root { get; set; } = new SceneNode("Root"); + public SceneNode Root { get; set; } = new EmptyNode("Root"); /// Gets or sets the nodes in the scene. private List Nodes { get; set; } = []; @@ -59,7 +60,7 @@ public Scene(string sceneFile) /// The name of the new empty node. public void AddNode(string name) { - var node = new SceneNode(name); + var node = new EmptyNode(name); Nodes.Add(node); Root.Children.Add(node); } diff --git a/Core/Scenes/SceneNode.cs b/Core/Scenes/SceneNode.cs index 106f45e..792bd9d 100644 --- a/Core/Scenes/SceneNode.cs +++ b/Core/Scenes/SceneNode.cs @@ -6,22 +6,20 @@ namespace SharpEngine.Core.Scenes; -public class EmptyNode : SceneNode where TTransform : ITransform, new() +public class EmptyNode : SceneNode { public EmptyNode(string name) : base(name) { } - public override TTransform Transform { get; set; } = new(); + public Transform Transform { get; set; } } /// /// Represents a node in the scene. /// -public abstract class SceneNode where TTransform : ITransform, new() +public abstract class SceneNode { - public abstract TTransform Transform { get; set; } - - public static SceneNode Empty => new EmptyNode("Empty Node"); + public static SceneNode Empty => new EmptyNode("Empty Node"); /// /// Gets or sets the name of the node. @@ -31,15 +29,15 @@ public EmptyNode(string name) : base(name) { } /// /// Gets or sets the children of the node. /// - public List> Children { get; set; } = []; + public List Children { get; set; } = []; /// - /// Initializes a new empty . + /// Initializes a new empty . /// public SceneNode() { } /// - /// Initializes a new instance of the with the specified . + /// Initializes a new instance of the with the specified . /// /// The name of the new empty node. public SceneNode(string name) @@ -52,9 +50,9 @@ public SceneNode(string name) /// /// The name of the empty node to be added. /// The created node. - public virtual SceneNode AddChild(string name) + public virtual SceneNode AddChild(string name) { - var node = new EmptyNode(name) as SceneNode; + var node = new EmptyNode(name) as SceneNode; Children.Add(node!); return node!; @@ -65,7 +63,7 @@ public virtual SceneNode AddChild(string name) /// /// The nodes to be added. /// The current node. - public virtual SceneNode AddChild(params SceneNode[] nodes) + public virtual SceneNode AddChild(params SceneNode[] nodes) { foreach (var node in nodes) Children.Add(node); @@ -77,7 +75,7 @@ public virtual SceneNode AddChild(params SceneNode[] nod /// Removes a child node from this node. /// /// The node to be removed. - public void RemoveChild(SceneNode node) + public void RemoveChild(SceneNode node) { Children.Remove(node); } diff --git a/Editor/Windows/ContextMenuWindow.cs b/Editor/Windows/ContextMenuWindow.cs index 603b8dc..cba5351 100644 --- a/Editor/Windows/ContextMenuWindow.cs +++ b/Editor/Windows/ContextMenuWindow.cs @@ -89,7 +89,7 @@ private void RenderSceneActions() if (ImGui.Button("Empty")) { var element = Scene.ActiveElement ?? Scene.Root; - element.AddChild(new SceneNode("Empty")); + element.AddChild(SceneNode.Empty); } } } diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index 136e55a..4f6fe91 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -26,8 +26,8 @@ public class Minecraft : Game { private readonly Scene _scene; - private SceneNode _lightsNode; - private SceneNode _blocksNode; + private SceneNode _lightsNode; + private SceneNode _blocksNode; private Input _input; private readonly Inventory _inventory; @@ -64,12 +64,12 @@ public override void Initialize() // TODO: Fix UI renderer _uiElem = new UIElement("uiElement"); - _uiElem.Transform.Scale = new Vector2(0.2f, 0.2f); + _uiElem.Transform.Scale = new SharpEngine.Core.Numerics.Vector2(0.2f, 0.2f); //_uiElem.Transform.Position = new Vector2(-30, 0); _scene.UIElements.Add(_uiElem); var uiElem2 = new UIElement("uiElement"); - uiElem2.Transform.Scale = new Vector2(0.2f, 0.2f); + uiElem2.Transform.Scale = new SharpEngine.Core.Numerics.Vector2(0.2f, 0.2f); //uiElem2.Transform.Position = new Vector2(30, 0); gridLayout.AddChild(_uiElem, uiElem2); @@ -250,7 +250,7 @@ private void PlaceBlock() private static Vector3 GetNewBlockPosition(Vector3 hitPosition, GameObject intersectingObject) { Vector3 normal = Ray.GetClosestFaceNormal(hitPosition, intersectingObject); - return intersectingObject.Transform.Position + (normal * intersectingObject.Transform.Scale); + return (System.Numerics.Vector3)intersectingObject.Transform.Position + (normal * (System.Numerics.Vector3)intersectingObject.Transform.Scale); } /// From 9c01d8a5c9844dc78fbbaee0276c828b06948529 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Fri, 4 Apr 2025 21:16:49 +0300 Subject: [PATCH 28/92] Getting there --- Core/Entities/GameObject.cs | 7 ++++--- Core/Entities/UI/Layouts/GridLayout.cs | 14 +++++++------- Core/Entities/UI/Layouts/LayoutBase.cs | 14 +++++++------- Core/Entities/UI/UIElement.cs | 6 +++--- Core/Scenes/Scene.cs | 4 ++-- Core/Scenes/SceneNode.cs | 23 +++++++++++++---------- 6 files changed, 36 insertions(+), 32 deletions(-) diff --git a/Core/Entities/GameObject.cs b/Core/Entities/GameObject.cs index 4c58dd8..3ea4adc 100644 --- a/Core/Entities/GameObject.cs +++ b/Core/Entities/GameObject.cs @@ -1,6 +1,7 @@ using SharpEngine.Core.Attributes; using SharpEngine.Core.Entities.Properties; using SharpEngine.Core.Entities.Properties.Meshes; +using SharpEngine.Core.Numerics; using SharpEngine.Core.Scenes; using SharpEngine.Core.Shaders; using SharpEngine.Core.Textures; @@ -16,12 +17,12 @@ namespace SharpEngine.Core.Entities; /// /// Represents a game object in the scene. /// -public class GameObject : SceneNode +public class GameObject : EmptyNode { /// /// Initializes a new instance of the . /// - public GameObject() + public GameObject() : base(string.Empty) { // TODO: Using lightning shader here will most likely break stuff, it needs to be refactored out. var shader = ShaderService.Instance.LoadShader(_Resources.Default.VertexShader, _Resources.Default.FragmentShader, "lighting"); @@ -38,7 +39,7 @@ public GameObject() /// The file path of the specular map texture. /// The file path of the vertex shader. /// The file path of the fragment shader. - public GameObject(string? diffuseMapFile = null, string? specularMapFile = null, string? vertShaderFile = null, string? fragShaderFile = null) + public GameObject(string? diffuseMapFile = null, string? specularMapFile = null, string? vertShaderFile = null, string? fragShaderFile = null) : base(string.Empty) { var shader = ShaderService.Instance.LoadShader(vertShaderFile ?? _Resources.Default.VertexShader, fragShaderFile ?? _Resources.Default.FragmentShader, "lighting"); var diffuse = TextureService.Instance.LoadTexture(diffuseMapFile ?? _Resources.Default.DebugTexture); diff --git a/Core/Entities/UI/Layouts/GridLayout.cs b/Core/Entities/UI/Layouts/GridLayout.cs index b542bcf..993a73c 100644 --- a/Core/Entities/UI/Layouts/GridLayout.cs +++ b/Core/Entities/UI/Layouts/GridLayout.cs @@ -8,8 +8,8 @@ namespace SharpEngine.Core.Entities.UI.Layouts; /// /// Represents a grid layout. /// -/// The type of items that can be stored and retrieved within the grid. -public class GridLayout : LayoutBase where T : SceneNode, new() +/// The type of items that can be stored and retrieved within the grid. +public class GridLayout : LayoutBase where TItem : SceneNode, new() { /// Gets or sets the amount of rows in the grid. public uint Rows { get; set; } = 2; @@ -23,7 +23,7 @@ namespace SharpEngine.Core.Entities.UI.Layouts; /// The row where the items should be retrieved. /// The column where the item should be retrieved. /// The item at [, ]. - public T this[uint row, uint column] + public TItem this[uint row, uint column] { get { @@ -38,7 +38,7 @@ namespace SharpEngine.Core.Entities.UI.Layouts; } /// - public override void AddItem(T item) + public override void AddItem(TItem item) { base.AddItem(item); @@ -70,12 +70,12 @@ private uint GetIndex(uint row, uint column) } /// - public override T[][] GetValues() + public override TItem[][] GetValues() { - var values = new T[Rows][]; + var values = new TItem[Rows][]; for (uint i = 0; i < Rows; i++) { - values[i] = new T[Columns]; + values[i] = new TItem[Columns]; for (uint j = 0; j < Columns; j++) { var item = this[i, j]; diff --git a/Core/Entities/UI/Layouts/LayoutBase.cs b/Core/Entities/UI/Layouts/LayoutBase.cs index cdb5f8d..948f425 100644 --- a/Core/Entities/UI/Layouts/LayoutBase.cs +++ b/Core/Entities/UI/Layouts/LayoutBase.cs @@ -9,27 +9,27 @@ namespace SharpEngine.Core.Entities.UI.Layouts; -public abstract class LayoutBase : SceneNode where T : SceneNode, new() +public abstract class LayoutBase : SceneNode where TItem : SceneNode, new() { - public List Items { get; set; } = []; + public List Items { get; set; } = []; - public override LayoutBase AddChild(params SceneNode[] nodes) + public override LayoutBase AddChild(params SceneNode[] nodes) { foreach (var node in nodes) - AddItem((T)node); + AddItem((TItem)node); return this; } - public virtual void AddItem(T item) + public virtual void AddItem(TItem item) { Items.Add(item); } - public virtual bool RemoveItem(T item) + public virtual bool RemoveItem(TItem item) { return Items.Remove(item); } - public abstract T[][] GetValues(); + public abstract TItem[][] GetValues(); } diff --git a/Core/Entities/UI/UIElement.cs b/Core/Entities/UI/UIElement.cs index 2e0a549..de5a9cb 100644 --- a/Core/Entities/UI/UIElement.cs +++ b/Core/Entities/UI/UIElement.cs @@ -1,5 +1,6 @@ using SharpEngine.Core.Entities.Properties; using SharpEngine.Core.Entities.Properties.Meshes; +using SharpEngine.Core.Numerics; using SharpEngine.Core.Scenes; using SharpEngine.Core.Shaders; using SharpEngine.Core.Windowing; @@ -12,7 +13,7 @@ namespace SharpEngine.Core.Entities.UI; /// /// Represents a User Interface entity. /// -public class UIElement : SceneNode +public class UIElement : EmptyNode { public UIElement() : this("UIElement") { } @@ -20,9 +21,8 @@ public UIElement() : this("UIElement") { } /// Initializes a new instance of . /// /// The name of the UI element. - public UIElement(string name) + public UIElement(string name) : base(name) { - Name = name; Mesh = MeshService.Instance.LoadMesh(nameof(Primitives.Plane), Primitives.Plane.Mesh); Initialize(); diff --git a/Core/Scenes/Scene.cs b/Core/Scenes/Scene.cs index 80f71ab..5d9dd5b 100644 --- a/Core/Scenes/Scene.cs +++ b/Core/Scenes/Scene.cs @@ -42,7 +42,7 @@ public Scene(string sceneFile) /// /// Gets or sets the root node of the scene. /// - public SceneNode Root { get; set; } = new EmptyNode("Root"); + public SceneNode Root { get; set; } = new EmptyNode("Root"); /// Gets or sets the nodes in the scene. private List Nodes { get; set; } = []; @@ -60,7 +60,7 @@ public Scene(string sceneFile) /// The name of the new empty node. public void AddNode(string name) { - var node = new EmptyNode(name); + var node = new EmptyNode(name); Nodes.Add(node); Root.Children.Add(node); } diff --git a/Core/Scenes/SceneNode.cs b/Core/Scenes/SceneNode.cs index 792bd9d..2ed0e80 100644 --- a/Core/Scenes/SceneNode.cs +++ b/Core/Scenes/SceneNode.cs @@ -6,11 +6,11 @@ namespace SharpEngine.Core.Scenes; -public class EmptyNode : SceneNode +public class EmptyNode : SceneNode where TVector : IVector { public EmptyNode(string name) : base(name) { } - public Transform Transform { get; set; } + public ITransform Transform { get; set; } } @@ -19,7 +19,7 @@ public EmptyNode(string name) : base(name) { } /// public abstract class SceneNode { - public static SceneNode Empty => new EmptyNode("Empty Node"); + public static SceneNode Empty => new EmptyNode("Empty Node"); /// /// Gets or sets the name of the node. @@ -45,24 +45,27 @@ public SceneNode(string name) Name = name; } + public virtual SceneNode AddChild(string name) + => AddChild(name); + /// /// Adds an empty child node to this node by the given . /// /// The name of the empty node to be added. /// The created node. - public virtual SceneNode AddChild(string name) + public virtual SceneNode AddChild(string name) where TVector : IVector { - var node = new EmptyNode(name) as SceneNode; + var node = new EmptyNode(name) as SceneNode; Children.Add(node!); return node!; } - /// - /// Adds a child node to this node. - /// - /// The nodes to be added. - /// The current node. + /// + /// Adds a child node to this node. + /// + /// The nodes to be added. + /// The current node. public virtual SceneNode AddChild(params SceneNode[] nodes) { foreach (var node in nodes) From fc04807669f27abd0e75bc1965032367d588895b Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Fri, 4 Apr 2025 21:37:35 +0300 Subject: [PATCH 29/92] Transform abstraction --- Core/Entities/GameObject.cs | 6 +++--- Core/Entities/Properties/BoundingBox.cs | 2 +- Core/Entities/Properties/ITransform.cs | 2 +- Core/Entities/Properties/Transform.cs | 2 ++ Core/Entities/UI/UIElement.cs | 7 ++----- Core/Scenes/Scene.cs | 4 ++-- Core/Scenes/SceneNode.cs | 13 ++++++------- 7 files changed, 17 insertions(+), 19 deletions(-) diff --git a/Core/Entities/GameObject.cs b/Core/Entities/GameObject.cs index 3ea4adc..7f61043 100644 --- a/Core/Entities/GameObject.cs +++ b/Core/Entities/GameObject.cs @@ -17,7 +17,7 @@ namespace SharpEngine.Core.Entities; /// /// Represents a game object in the scene. /// -public class GameObject : EmptyNode +public class GameObject : EmptyNode { /// /// Initializes a new instance of the . @@ -63,7 +63,7 @@ public GameObject(string? diffuseMapFile = null, string? specularMapFile = null, /// /// Gets or sets the transform of the game object. /// - public Transform Transform + public override Transform Transform { get => _transform; set @@ -72,7 +72,7 @@ public Transform Transform BoundingBox = BoundingBox.CalculateBoundingBox(_transform); } } - + private Transform _transform = new(); /// diff --git a/Core/Entities/Properties/BoundingBox.cs b/Core/Entities/Properties/BoundingBox.cs index 598d519..f2a9bf6 100644 --- a/Core/Entities/Properties/BoundingBox.cs +++ b/Core/Entities/Properties/BoundingBox.cs @@ -32,7 +32,7 @@ public BoundingBox(Vector3 min, Vector3 max) /// Calculates the bounding box of the game object. /// /// The bounding box of the game object. - public static BoundingBox CalculateBoundingBox(Transform transform) + public static BoundingBox CalculateBoundingBox(ITransform transform) { var min = transform.Position - (transform.Scale / 2); var max = transform.Position + (transform.Scale / 2); diff --git a/Core/Entities/Properties/ITransform.cs b/Core/Entities/Properties/ITransform.cs index 5685511..7f2cb89 100644 --- a/Core/Entities/Properties/ITransform.cs +++ b/Core/Entities/Properties/ITransform.cs @@ -3,7 +3,7 @@ namespace SharpEngine.Core.Entities.Properties; -public interface ITransform where TVector : IVector +public interface ITransform where TVector : IVector, new() { public TVector Position { get; set; } public TVector Scale { get; set; } diff --git a/Core/Entities/Properties/Transform.cs b/Core/Entities/Properties/Transform.cs index c934172..92dc88c 100644 --- a/Core/Entities/Properties/Transform.cs +++ b/Core/Entities/Properties/Transform.cs @@ -8,6 +8,8 @@ namespace SharpEngine.Core.Entities.Properties; /// public class Transform : ITransform { + public Transform() { } + /// /// Gets or sets the position of the game object. /// diff --git a/Core/Entities/UI/UIElement.cs b/Core/Entities/UI/UIElement.cs index de5a9cb..a01e899 100644 --- a/Core/Entities/UI/UIElement.cs +++ b/Core/Entities/UI/UIElement.cs @@ -13,7 +13,7 @@ namespace SharpEngine.Core.Entities.UI; /// /// Represents a User Interface entity. /// -public class UIElement : EmptyNode +public class UIElement : EmptyNode { public UIElement() : this("UIElement") { } @@ -30,11 +30,8 @@ public UIElement(string name) : base(name) private readonly UIShader _uiShader = new(); - /// Gets or sets the 2D space transformation of the UI element. - public Transform2D Transform { get; set; } = new(); - /// Gets or sets the mesh of the UI element. - public new Mesh Mesh { get; set; } + public Mesh Mesh { get; set; } //public override Transform2D Transform { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } private uint _vertexArrayObject; diff --git a/Core/Scenes/Scene.cs b/Core/Scenes/Scene.cs index 5d9dd5b..6e4706f 100644 --- a/Core/Scenes/Scene.cs +++ b/Core/Scenes/Scene.cs @@ -42,7 +42,7 @@ public Scene(string sceneFile) /// /// Gets or sets the root node of the scene. /// - public SceneNode Root { get; set; } = new EmptyNode("Root"); + public SceneNode Root { get; set; } = new EmptyNode("Root"); /// Gets or sets the nodes in the scene. private List Nodes { get; set; } = []; @@ -60,7 +60,7 @@ public Scene(string sceneFile) /// The name of the new empty node. public void AddNode(string name) { - var node = new EmptyNode(name); + var node = new EmptyNode(name); Nodes.Add(node); Root.Children.Add(node); } diff --git a/Core/Scenes/SceneNode.cs b/Core/Scenes/SceneNode.cs index 2ed0e80..55d3538 100644 --- a/Core/Scenes/SceneNode.cs +++ b/Core/Scenes/SceneNode.cs @@ -6,12 +6,11 @@ namespace SharpEngine.Core.Scenes; -public class EmptyNode : SceneNode where TVector : IVector +public class EmptyNode : SceneNode where TTransform : ITransform, new() where TVector : IVector, new() { public EmptyNode(string name) : base(name) { } - public ITransform Transform { get; set; } - + public virtual TTransform Transform { get; set; } = new(); } /// @@ -19,7 +18,7 @@ public EmptyNode(string name) : base(name) { } /// public abstract class SceneNode { - public static SceneNode Empty => new EmptyNode("Empty Node"); + public static SceneNode Empty => new EmptyNode("Empty Node"); /// /// Gets or sets the name of the node. @@ -46,16 +45,16 @@ public SceneNode(string name) } public virtual SceneNode AddChild(string name) - => AddChild(name); + => AddChild(name); /// /// Adds an empty child node to this node by the given . /// /// The name of the empty node to be added. /// The created node. - public virtual SceneNode AddChild(string name) where TVector : IVector + public virtual SceneNode AddChild(string name) where TTransform : ITransform, new() where TVector : IVector, new() { - var node = new EmptyNode(name) as SceneNode; + var node = new EmptyNode(name) as SceneNode; Children.Add(node!); return node!; From 4877f4618222b06ef48ab056dad1f84e8b0d0f0d Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sat, 5 Apr 2025 13:08:23 +0300 Subject: [PATCH 30/92] UI element ortographic projection --- Core/Entities/GameObject.cs | 5 +-- Core/Entities/Lights/DirectionalLight.cs | 3 +- Core/Entities/Lights/PointLight.cs | 5 +-- Core/Entities/Lights/SpotLight.cs | 5 +-- Core/Entities/Properties/Transform2D.cs | 6 ++-- Core/Entities/UI/Layouts/LayoutBase.cs | 2 ++ Core/Entities/UI/UIElement.cs | 39 +++++++++++++++++++++++- Core/Numerics/IVector.cs | 6 +++- Core/Numerics/Vector2.cs | 2 +- Core/Numerics/Vector2_Intrinsics.cs | 7 +++-- Core/Numerics/Vector3.cs | 2 +- Core/Numerics/Vector3_Intrinsics.cs | 10 +++--- Core/Renderers/Renderer.cs | 4 +-- Core/Renderers/RendererBase.cs | 1 + Core/Renderers/UIRenderer.cs | 18 ++++++----- Core/Scenes/SceneNode.cs | 3 +- Core/Shaders/Shader.cs | 15 +++++++-- Core/Shaders/uiShader.frag | 1 - Core/Shaders/uiShader.vert | 25 +++++++++------ Examples/MinecraftClone/Minecraft.cs | 14 +++++---- 20 files changed, 122 insertions(+), 51 deletions(-) diff --git a/Core/Entities/GameObject.cs b/Core/Entities/GameObject.cs index 7f61043..d355d7b 100644 --- a/Core/Entities/GameObject.cs +++ b/Core/Entities/GameObject.cs @@ -1,6 +1,7 @@ using SharpEngine.Core.Attributes; using SharpEngine.Core.Entities.Properties; using SharpEngine.Core.Entities.Properties.Meshes; +using SharpEngine.Core.Entities.Views; using SharpEngine.Core.Numerics; using SharpEngine.Core.Scenes; using SharpEngine.Core.Shaders; @@ -82,7 +83,7 @@ public override Transform Transform public BoundingBox BoundingBox { get; set; } /// - public override Task Render() + public override Task Render(CameraView camera) { Material.DiffuseMap.Use(TextureUnit.Texture0); Material.Shader.SetInt("material.diffuse", Material.diffuseUnit); @@ -101,7 +102,7 @@ public override Task Render() Material.Shader.SetFloat("material.shininess", 0); } - Material.Shader.SetMatrix4(ShaderAttributes.Model, Transform.ModelMatrix); + Material.Shader.SetMatrix4(ShaderAttributes.Model, Transform.ModelMatrix); Window.GL.DrawArrays(PrimitiveType.Triangles, 0, 36); return Task.CompletedTask; diff --git a/Core/Entities/Lights/DirectionalLight.cs b/Core/Entities/Lights/DirectionalLight.cs index d320965..7b4a495 100644 --- a/Core/Entities/Lights/DirectionalLight.cs +++ b/Core/Entities/Lights/DirectionalLight.cs @@ -1,4 +1,5 @@ using SharpEngine.Core.Entities.Properties; +using SharpEngine.Core.Entities.Views; using SharpEngine.Core.Extensions; using SharpEngine.Core.Shaders; @@ -29,7 +30,7 @@ public DirectionalLight() } /// - public override Task Render() + public override Task Render(CameraView camera) { Material.Shader.SetVector3("dirLight.direction", Direction); Material.Shader.SetVector3("dirLight.ambient", Ambient); diff --git a/Core/Entities/Lights/PointLight.cs b/Core/Entities/Lights/PointLight.cs index e63d141..85dbade 100644 --- a/Core/Entities/Lights/PointLight.cs +++ b/Core/Entities/Lights/PointLight.cs @@ -1,4 +1,5 @@ -using SharpEngine.Core.Extensions; +using SharpEngine.Core.Entities.Views; +using SharpEngine.Core.Extensions; using SharpEngine.Core.Shaders; using System.Numerics; @@ -51,7 +52,7 @@ public PointLight(Vector3 position, int index) public float Quadratic { get; set; } /// - public override Task Render() + public override Task Render(CameraView camera) { Material.Shader.SetVector3($"pointLights[{_index}].position", (System.Numerics.Vector3)Transform.Position); Material.Shader.SetVector3($"pointLights[{_index}].ambient", Ambient); diff --git a/Core/Entities/Lights/SpotLight.cs b/Core/Entities/Lights/SpotLight.cs index e63597d..f66bc55 100644 --- a/Core/Entities/Lights/SpotLight.cs +++ b/Core/Entities/Lights/SpotLight.cs @@ -1,4 +1,5 @@ -using SharpEngine.Core.Extensions; +using SharpEngine.Core.Entities.Views; +using SharpEngine.Core.Extensions; using SharpEngine.Core.Shaders; using System.Numerics; @@ -57,7 +58,7 @@ public SpotLight() public float Quadratic { get; set; } /// - public override Task Render() + public override Task Render(CameraView camera) { Material.Shader.SetVector3("spotLight.position", (System.Numerics.Vector3)Transform.Position); Material.Shader.SetVector3("spotLight.direction", Direction); diff --git a/Core/Entities/Properties/Transform2D.cs b/Core/Entities/Properties/Transform2D.cs index 413226c..14c1078 100644 --- a/Core/Entities/Properties/Transform2D.cs +++ b/Core/Entities/Properties/Transform2D.cs @@ -11,7 +11,7 @@ public class Transform2D : ITransform /// /// Gets or sets the position of the game object. /// - public Vector2 Position { get; set; } + public Vector2 Position { get; set; } = new(0, 0); /// /// Gets or sets the scale of the game object. @@ -27,6 +27,6 @@ public class Transform2D : ITransform /// Gets the transformation of the game object as a model matrix. /// public Matrix4x4 ModelMatrix => Matrix4x4.CreateScale(new Vector3(Scale.X, Scale.Y, 0)) * - Matrix4x4.CreateRotationZ(Rotation.Angle) * - Matrix4x4.CreateTranslation(new Vector3(Position.X * 0.01f, Position.Y * 0.01f, 0)); + Matrix4x4.CreateRotationZ(Rotation.Angle) * + Matrix4x4.CreateTranslation(new Vector3(Position.X, Position.Y, 0)); } \ No newline at end of file diff --git a/Core/Entities/UI/Layouts/LayoutBase.cs b/Core/Entities/UI/Layouts/LayoutBase.cs index 948f425..3b584d4 100644 --- a/Core/Entities/UI/Layouts/LayoutBase.cs +++ b/Core/Entities/UI/Layouts/LayoutBase.cs @@ -15,6 +15,8 @@ namespace SharpEngine.Core.Entities.UI.Layouts; public override LayoutBase AddChild(params SceneNode[] nodes) { + base.AddChild(nodes); + foreach (var node in nodes) AddItem((TItem)node); diff --git a/Core/Entities/UI/UIElement.cs b/Core/Entities/UI/UIElement.cs index a01e899..0fc185c 100644 --- a/Core/Entities/UI/UIElement.cs +++ b/Core/Entities/UI/UIElement.cs @@ -1,12 +1,16 @@ using SharpEngine.Core.Entities.Properties; using SharpEngine.Core.Entities.Properties.Meshes; +using SharpEngine.Core.Entities.Views; using SharpEngine.Core.Numerics; 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; +using Vector3 = System.Numerics.Vector3; namespace SharpEngine.Core.Entities.UI; @@ -70,16 +74,49 @@ private void InitializeBuffers() /// /// Render the UI element. /// - public override Task Render() + public override Task Render(CameraView camera) { Window.GL.BindVertexArray(_vertexArrayObject); + // TODO: These should come from somewhere else. + const float screenWidth = 1280; + const float screenHeight = 720; + + var orthoMatrix = Matrix4x4.CreateOrthographicOffCenter(0, screenWidth, screenHeight, 0, -1, 1); + + + _uiShader.Shader.SetVector2("screenSize", new System.Numerics.Vector2(screenWidth, screenHeight)); _uiShader.Shader.SetVector2("position", (System.Numerics.Vector2)Transform.Position); _uiShader.Shader.SetFloat("rotation", Transform.Rotation.Angle); _uiShader.Shader.SetVector2("scale", (System.Numerics.Vector2)Transform.Scale); + _uiShader.Shader.SetMatrix4(ShaderAttributes.Model, Transform.ModelMatrix); + _uiShader.Shader.SetMatrix4("orthoMatrix", orthoMatrix); // Pass the orthographic matrix to the shader + + _uiShader.Shader!.SetMatrix4("view", camera.GetViewMatrix()); + _uiShader.Shader!.SetMatrix4("projection", camera.GetProjectionMatrix()); + _uiShader.Shader!.SetVector3("viewPos", camera.Position); + + + var pos = new Vector3(Transform.Position.X, Transform.Position.Y, 0); + var clipSpace = WorldToClipSpace(pos, Transform.ModelMatrix, camera.GetViewMatrix(), camera.GetProjectionMatrix()); + _uiShader.Shader.SetVector4("clipSpace", clipSpace); Window.GL.DrawElements(PrimitiveType.Triangles, (uint)Mesh.Indices.Length, DrawElementsType.UnsignedInt, []); return Task.CompletedTask; } + + public static Vector4 WorldToClipSpace(Vector3 position, Matrix4x4 model, Matrix4x4 view, Matrix4x4 projection) + { + // Combine all transforms into MVP + Matrix4x4 mvp = model * view * projection; + + // Convert Vector3 to Vector4 for matrix multiplication + Vector4 worldPos = new Vector4(position, 1.0f); + + // Transform to clip space (i.e., ready to assign to gl_Position) + Vector4 clipSpacePos = Vector4.Transform(worldPos, mvp); + + return clipSpacePos; + } } diff --git a/Core/Numerics/IVector.cs b/Core/Numerics/IVector.cs index 9fe8509..b6f41dd 100644 --- a/Core/Numerics/IVector.cs +++ b/Core/Numerics/IVector.cs @@ -1,5 +1,9 @@ -namespace SharpEngine.Core.Numerics; +using System; + +namespace SharpEngine.Core.Numerics; public interface IVector { + public Single X { get; set; } + public Single Y { get; set; } } \ No newline at end of file diff --git a/Core/Numerics/Vector2.cs b/Core/Numerics/Vector2.cs index 231abec..6423d16 100644 --- a/Core/Numerics/Vector2.cs +++ b/Core/Numerics/Vector2.cs @@ -17,7 +17,7 @@ namespace SharpEngine.Core.Numerics /// /// A structure encapsulating two single precision floating point values and provides hardware accelerated methods. /// - public partial struct Vector2 : IVector, IEquatable, IFormattable + public partial struct Vector2 : IEquatable, IFormattable { #region Public Static Properties /// diff --git a/Core/Numerics/Vector2_Intrinsics.cs b/Core/Numerics/Vector2_Intrinsics.cs index 6619057..6a04d6c 100644 --- a/Core/Numerics/Vector2_Intrinsics.cs +++ b/Core/Numerics/Vector2_Intrinsics.cs @@ -12,16 +12,17 @@ namespace SharpEngine.Core.Numerics // The JIT recognizes these methods and properties by name and signature: if either is changed, the JIT will no longer recognize the member. // Some methods declared here are not strictly intrinsic, but delegate to an intrinsic method. For example, only one overload of CopyTo() - public partial struct Vector2 + public partial struct Vector2 : IVector { /// /// The X component of the vector. /// - public Single X; + public Single X { get; set; } + /// /// The Y component of the vector. /// - public Single Y; + public Single Y { get; set; } #region Constructors /// diff --git a/Core/Numerics/Vector3.cs b/Core/Numerics/Vector3.cs index bb289f8..1a1e2b7 100644 --- a/Core/Numerics/Vector3.cs +++ b/Core/Numerics/Vector3.cs @@ -16,7 +16,7 @@ namespace SharpEngine.Core.Numerics /// /// A structure encapsulating three single precision floating point values and provides hardware accelerated methods. /// - public partial struct Vector3 : IVector, IEquatable, IFormattable + public partial struct Vector3 : IEquatable, IFormattable { #region Public Static Properties /// diff --git a/Core/Numerics/Vector3_Intrinsics.cs b/Core/Numerics/Vector3_Intrinsics.cs index 71456df..6a6e7f5 100644 --- a/Core/Numerics/Vector3_Intrinsics.cs +++ b/Core/Numerics/Vector3_Intrinsics.cs @@ -12,20 +12,22 @@ namespace SharpEngine.Core.Numerics // Some methods declared here are not strictly intrinsic, but delegate to an intrinsic method. For example, only one overload of CopyTo() // is actually recognized by the JIT, but both are here for simplicity. - public partial struct Vector3 + public partial struct Vector3 : IVector { /// /// The X component of the vector. /// - public Single X; + public Single X { get; set; } + /// /// The Y component of the vector. /// - public Single Y; + public Single Y { get; set; } + /// /// The Z component of the vector. /// - public Single Z; + public Single Z { get; set; } #region Constructors /// diff --git a/Core/Renderers/Renderer.cs b/Core/Renderers/Renderer.cs index a6f0401..77752ad 100644 --- a/Core/Renderers/Renderer.cs +++ b/Core/Renderers/Renderer.cs @@ -49,7 +49,7 @@ public Renderer(CameraView camera, ISettings settings, Scene scene) : base(setti /// public override Task Render() { - //return Task.CompletedTask; + return Task.CompletedTask; try { Window.GL.Enable(EnableCap.DepthTest); @@ -82,7 +82,7 @@ private Task RenderGameObject(SceneNode node) return Task.CompletedTask; // TODO: Skip blocks that are behind others relative to the camera - return gameObject.Render(); + return gameObject.Render(_camera); } private static bool IsInViewFrustum(BoundingBox boundingBox, CameraView camera) diff --git a/Core/Renderers/RendererBase.cs b/Core/Renderers/RendererBase.cs index c36bd03..1491fab 100644 --- a/Core/Renderers/RendererBase.cs +++ b/Core/Renderers/RendererBase.cs @@ -1,3 +1,4 @@ +using SharpEngine.Core.Entities.Views; using SharpEngine.Core.Interfaces; using System; using System.Threading.Tasks; diff --git a/Core/Renderers/UIRenderer.cs b/Core/Renderers/UIRenderer.cs index 55513ef..ff9c067 100644 --- a/Core/Renderers/UIRenderer.cs +++ b/Core/Renderers/UIRenderer.cs @@ -1,14 +1,18 @@ -using SharpEngine.Core.Entities.UI; +using SharpEngine.Core.Entities.Properties; +using SharpEngine.Core.Entities.UI; using SharpEngine.Core.Entities.Views; using SharpEngine.Core.Interfaces; using SharpEngine.Core.Scenes; using SharpEngine.Core.Shaders; using SharpEngine.Core.Windowing; +using Silk.NET.Input; using Silk.NET.OpenGL; using System; using System.Linq; +using System.Numerics; using System.Threading.Tasks; +using static Silk.NET.Core.Native.WinString; namespace SharpEngine.Core.Renderers; @@ -42,15 +46,13 @@ public override Task Render() Window.GL.Enable(EnableCap.DepthTest); Window.GL.DepthFunc(DepthFunction.Less); - _uiShader.Shader.Use(); + // Disable face culling to render both sides of the quad + Window.GL.Disable(EnableCap.CullFace); - var objects = _scene.GetObjectsOfType(); // TODO: This is really unoptimized, need to figure out a better solution. - foreach (var item in objects) - { - item.Bind(); - } + // _camera.SetShaderUniforms(_uiShader.Shader!); + _uiShader.Shader.Use(); - var uiElementRenderTasks = _scene.IterateAsync(_scene.UIElements, elem => elem.Render()); + var uiElementRenderTasks = _scene.IterateAsync(_scene.UIElements, elem => elem.Render(_camera)); return Task.WhenAll(uiElementRenderTasks); } diff --git a/Core/Scenes/SceneNode.cs b/Core/Scenes/SceneNode.cs index 55d3538..a0ce9b8 100644 --- a/Core/Scenes/SceneNode.cs +++ b/Core/Scenes/SceneNode.cs @@ -1,5 +1,6 @@ using SharpEngine.Core.Entities; using SharpEngine.Core.Entities.Properties; +using SharpEngine.Core.Entities.Views; using SharpEngine.Core.Numerics; using System.Collections.Generic; using System.Threading.Tasks; @@ -86,5 +87,5 @@ public void RemoveChild(SceneNode node) /// Renders the current object to the screen. /// /// A representing an asynchronous operation. - public virtual Task Render() => Task.CompletedTask; + public virtual Task Render(CameraView camera) => Task.CompletedTask; } diff --git a/Core/Shaders/Shader.cs b/Core/Shaders/Shader.cs index 1b7b160..0197abb 100644 --- a/Core/Shaders/Shader.cs +++ b/Core/Shaders/Shader.cs @@ -268,6 +268,12 @@ public void SetMatrix4(string name, Matrix4x4 data, bool transpose = true) TrySetUniform(name, data, (uniform, d) => Window.GL.UniformMatrix4(uniform, transpose, d.ToSpan())); } + public void SetVector2(string name, Vector2 data) + { + Window.GL.UseProgram(Handle); + TrySetUniform(name, data, Window.GL.Uniform2); + } + /// /// Set a uniform Vector3 on this shader. /// @@ -279,9 +285,14 @@ public void SetVector3(string name, Vector3 data) TrySetUniform(name, data, Window.GL.Uniform3); } - public void SetVector2(string name, Vector2 data) + /// + /// Set a uniform Vector3 on this shader. + /// + /// The name of the uniform. + /// The data to set. + public void SetVector4(string name, Vector4 data) { Window.GL.UseProgram(Handle); - TrySetUniform(name, data, Window.GL.Uniform2); + TrySetUniform(name, data, Window.GL.Uniform4); } } diff --git a/Core/Shaders/uiShader.frag b/Core/Shaders/uiShader.frag index 8e4b912..1cc0a9e 100644 --- a/Core/Shaders/uiShader.frag +++ b/Core/Shaders/uiShader.frag @@ -6,6 +6,5 @@ in vec2 TexCoords; void main() { - // FragColor = vec4(1.0, 0.0, 0.0, 1.0); // set all 4 vector values to 1.0 FragColor = texture(texture1, TexCoords); } \ No newline at end of file diff --git a/Core/Shaders/uiShader.vert b/Core/Shaders/uiShader.vert index 707a1f7..dd21a8d 100644 --- a/Core/Shaders/uiShader.vert +++ b/Core/Shaders/uiShader.vert @@ -7,6 +7,14 @@ layout (location = 2) in vec2 aTexCoords; uniform vec2 position; uniform float rotation; uniform vec2 scale; +uniform vec2 screenSize; +uniform mat4 clipSpace; +uniform mat4 orthoMatrix; + +uniform mat4 view; +uniform mat4 projection; +uniform mat4 model; +uniform vec3 viewPos; out vec3 Normal; out vec3 FragPos; @@ -14,17 +22,14 @@ out vec2 TexCoords; void main() { - // Create a 2D rotation matrix - mat2 rot = mat2(cos(rotation), -sin(rotation), - sin(rotation), cos(rotation)); - - // Apply the rotation, scaling, and translation - vec2 transformedPos = (rot * aPos.xy) * scale + (position * 0.01); + // Calculate the model-view-projection matrix using the orthographic projection matrix + mat4 mvp = projection * view * model; - // Set the final position in clip space - gl_Position = vec4(transformedPos, aPos.z, 1.0); + // Apply the MVP matrix to the vertex position with scaling + gl_Position = model * orthoMatrix * vec4(aPos, 1); - FragPos = vec3(transformedPos, aPos.z); - Normal = aNormal; // No need to transform normals for 2D UI elements + // Pass through other attributes + Normal = mat3(model) * aNormal; // Transform the normal + FragPos = vec3(model * vec4(aPos, 1.0)); // Transform the fragment position TexCoords = aTexCoords; } \ No newline at end of file diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index 4f6fe91..70e4481 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -64,17 +64,19 @@ public override void Initialize() // TODO: Fix UI renderer _uiElem = new UIElement("uiElement"); - _uiElem.Transform.Scale = new SharpEngine.Core.Numerics.Vector2(0.2f, 0.2f); - //_uiElem.Transform.Position = new Vector2(-30, 0); + _uiElem.Transform.Scale = new SharpEngine.Core.Numerics.Vector2(0.5f, 0.5f); + _uiElem.Transform.Position = new SharpEngine.Core.Numerics.Vector2(0.5f, 0); _scene.UIElements.Add(_uiElem); - var uiElem2 = new UIElement("uiElement"); - uiElem2.Transform.Scale = new SharpEngine.Core.Numerics.Vector2(0.2f, 0.2f); + //var uiElem2 = new UIElement("uiElement"); + //uiElem2.Transform.Scale = new SharpEngine.Core.Numerics.Vector2(0.2f, 0.2f); //uiElem2.Transform.Position = new Vector2(30, 0); - gridLayout.AddChild(_uiElem, uiElem2); + // gridLayout.AddChild(_uiElem, uiElem2); + _scene.UIElements.Add(_uiElem); + // _scene.UIElements.Add(uiElem2); - _scene.UIElements.Add(gridLayout); + //_scene.UIElements.Add(gridLayout); InitializeWorld(); } From b64d9174c11d345310c250eedb0bc27c0c7ba415 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sat, 5 Apr 2025 14:18:27 +0300 Subject: [PATCH 31/92] Translating somewhat works --- Core/Entities/Properties/Transform2D.cs | 5 +++-- Core/Entities/UI/UIElement.cs | 2 +- Core/Shaders/uiShader.vert | 7 +++++-- Examples/MinecraftClone/Minecraft.cs | 25 +++++++++++++++++++++++-- Examples/MinecraftClone/Program.cs | 1 + 5 files changed, 33 insertions(+), 7 deletions(-) diff --git a/Core/Entities/Properties/Transform2D.cs b/Core/Entities/Properties/Transform2D.cs index 14c1078..b1339d8 100644 --- a/Core/Entities/Properties/Transform2D.cs +++ b/Core/Entities/Properties/Transform2D.cs @@ -21,12 +21,13 @@ public class Transform2D : ITransform /// /// Gets or sets the rotation of the game object. /// - public Quaternion Rotation { get; set; } = new(); + public Quaternion Rotation { get; set; } = new() { Angle = 0 }; /// /// Gets the transformation of the game object as a model matrix. /// public Matrix4x4 ModelMatrix => Matrix4x4.CreateScale(new Vector3(Scale.X, Scale.Y, 0)) * Matrix4x4.CreateRotationZ(Rotation.Angle) * - Matrix4x4.CreateTranslation(new Vector3(Position.X, Position.Y, 0)); + //Matrix4x4.CreateTranslation(new Vector3(Position.X, Position.Y, 0)); + Matrix4x4.CreateTranslation(new Vector3(0, 0, 0)); } \ No newline at end of file diff --git a/Core/Entities/UI/UIElement.cs b/Core/Entities/UI/UIElement.cs index 0fc185c..a2af4ec 100644 --- a/Core/Entities/UI/UIElement.cs +++ b/Core/Entities/UI/UIElement.cs @@ -82,7 +82,7 @@ public override Task Render(CameraView camera) const float screenWidth = 1280; const float screenHeight = 720; - var orthoMatrix = Matrix4x4.CreateOrthographicOffCenter(0, screenWidth, screenHeight, 0, -1, 1); + var orthoMatrix = Matrix4x4.CreateOrthographicOffCenter(-1, 1, -1, 1, -1, 1); _uiShader.Shader.SetVector2("screenSize", new System.Numerics.Vector2(screenWidth, screenHeight)); diff --git a/Core/Shaders/uiShader.vert b/Core/Shaders/uiShader.vert index dd21a8d..ae38486 100644 --- a/Core/Shaders/uiShader.vert +++ b/Core/Shaders/uiShader.vert @@ -22,11 +22,14 @@ out vec2 TexCoords; void main() { + float reciprScaleOnscreen = 0.001f; + // Calculate the model-view-projection matrix using the orthographic projection matrix - mat4 mvp = projection * view * model; + //mat4 mvp = projection * view * model; + vec4 mvp = model * vec4(1.0) * orthoMatrix; // Apply the MVP matrix to the vertex position with scaling - gl_Position = model * orthoMatrix * vec4(aPos, 1); + gl_Position = mvp * vec4(aPos.x + (position.x * reciprScaleOnscreen), aPos.y + (position.y * reciprScaleOnscreen), aPos.z, 1); // Pass through other attributes Normal = mat3(model) * aNormal; // Transform the normal diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index 70e4481..b84ede9 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -14,6 +14,7 @@ using SharpEngine.Core.Windowing; using SharpEngine.Core.Entities.UI.Layouts; using SharpEngine.Core.Entities.Properties; +using ImGuiNET; namespace Minecraft; @@ -34,7 +35,7 @@ public class Minecraft : Game private UIElement _uiElem; - public Window Window { get; set; } + public Window? Window { get; set; } /// /// Initializes a new instance of the . @@ -45,6 +46,7 @@ public Minecraft(Scene scene, ISettings settings) CoreSettings = settings; _inventory = new Inventory(); + } /// @@ -65,7 +67,8 @@ public override void Initialize() // TODO: Fix UI renderer _uiElem = new UIElement("uiElement"); _uiElem.Transform.Scale = new SharpEngine.Core.Numerics.Vector2(0.5f, 0.5f); - _uiElem.Transform.Position = new SharpEngine.Core.Numerics.Vector2(0.5f, 0); + _uiElem.Transform.Position = new SharpEngine.Core.Numerics.Vector2(2000, 0); + _uiElem.Transform.Rotation.Angle = 90; _scene.UIElements.Add(_uiElem); //var uiElem2 = new UIElement("uiElement"); @@ -86,6 +89,24 @@ public override void Initialize() } } + public void OnAfterRender(double frameTime) + { + var x = _uiElem.Transform.Position.X; + var y = _uiElem.Transform.Position.Y; + + ImGui.Begin("Debug"); + ImGui.Text($"FPS: {frameTime }"); + ImGui.Text($"Camera position: {Camera.Position}"); + ImGui.Text($"UI Element position: {_uiElem.Transform.Position}"); + + ImGui.SliderFloat("X", ref x, -1000, 1000); + ImGui.SliderFloat("Y", ref y, -1000, 1000); + + ImGui.End(); + + _uiElem.Transform.Position = new SharpEngine.Core.Numerics.Vector2(x, y); + } + private void InitializeWorld() { InitializeLights(); diff --git a/Examples/MinecraftClone/Program.cs b/Examples/MinecraftClone/Program.cs index a753b62..46a0d1b 100644 --- a/Examples/MinecraftClone/Program.cs +++ b/Examples/MinecraftClone/Program.cs @@ -25,6 +25,7 @@ private static void Main() window.OnHandleKeyboard += game.HandleKeyboard; window.OnButtonMouseDown += game.HandleMouseDown; window.HandleMouseWheel += game.HandleMouseWheel; + window.OnAfterRender += game.OnAfterRender; // TODO: This needs to be streamlined. game.Window = window; From 7793ffcb0d70b301758f77920964a0c440c0b504 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sat, 5 Apr 2025 16:15:35 +0300 Subject: [PATCH 32/92] UI transform behaving correctly? --- Core/Entities/Properties/Transform2D.cs | 5 +++-- Core/Entities/UI/UIElement.cs | 2 +- Core/Shaders/uiShader.vert | 27 +++++++++++++++++++------ Core/Windowing/Frame.cs | 18 +++++++++++++++++ Examples/MinecraftClone/Minecraft.cs | 24 ++++++++++++++++------ 5 files changed, 61 insertions(+), 15 deletions(-) create mode 100644 Core/Windowing/Frame.cs diff --git a/Core/Entities/Properties/Transform2D.cs b/Core/Entities/Properties/Transform2D.cs index b1339d8..8a44d56 100644 --- a/Core/Entities/Properties/Transform2D.cs +++ b/Core/Entities/Properties/Transform2D.cs @@ -27,7 +27,8 @@ public class Transform2D : ITransform /// Gets the transformation of the game object as a model matrix. /// public Matrix4x4 ModelMatrix => Matrix4x4.CreateScale(new Vector3(Scale.X, Scale.Y, 0)) * - Matrix4x4.CreateRotationZ(Rotation.Angle) * - //Matrix4x4.CreateTranslation(new Vector3(Position.X, Position.Y, 0)); + // Matrix4x4.CreateRotationZ(Math.DegreesToRadians(Rotation.Angle)) * + Matrix4x4.CreateRotationZ(0) * + // Matrix4x4.CreateTranslation(new Vector3(Position.X, Position.Y, 0)); Matrix4x4.CreateTranslation(new Vector3(0, 0, 0)); } \ No newline at end of file diff --git a/Core/Entities/UI/UIElement.cs b/Core/Entities/UI/UIElement.cs index a2af4ec..3f3fecd 100644 --- a/Core/Entities/UI/UIElement.cs +++ b/Core/Entities/UI/UIElement.cs @@ -87,7 +87,7 @@ public override Task Render(CameraView camera) _uiShader.Shader.SetVector2("screenSize", new System.Numerics.Vector2(screenWidth, screenHeight)); _uiShader.Shader.SetVector2("position", (System.Numerics.Vector2)Transform.Position); - _uiShader.Shader.SetFloat("rotation", Transform.Rotation.Angle); + _uiShader.Shader.SetFloat("rotation", Math.DegreesToRadians(Transform.Rotation.Angle)); _uiShader.Shader.SetVector2("scale", (System.Numerics.Vector2)Transform.Scale); _uiShader.Shader.SetMatrix4(ShaderAttributes.Model, Transform.ModelMatrix); _uiShader.Shader.SetMatrix4("orthoMatrix", orthoMatrix); // Pass the orthographic matrix to the shader diff --git a/Core/Shaders/uiShader.vert b/Core/Shaders/uiShader.vert index ae38486..36a425e 100644 --- a/Core/Shaders/uiShader.vert +++ b/Core/Shaders/uiShader.vert @@ -22,14 +22,29 @@ out vec2 TexCoords; void main() { - float reciprScaleOnscreen = 0.001f; + float reciprScaleOnscreen = 0.005f; - // Calculate the model-view-projection matrix using the orthographic projection matrix - //mat4 mvp = projection * view * model; - vec4 mvp = model * vec4(1.0) * orthoMatrix; + // Calculate the aspect ratio + float aspectRatio = screenSize.x / screenSize.y; + + // Create the rotation matrix for the z-axis + mat4 rotationMatrix = mat4( + cos(rotation), -sin(rotation), 0.0, 0.0, + sin(rotation), cos(rotation), 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 + ); - // Apply the MVP matrix to the vertex position with scaling - gl_Position = mvp * vec4(aPos.x + (position.x * reciprScaleOnscreen), aPos.y + (position.y * reciprScaleOnscreen), aPos.z, 1); + // Calculate the model-view-projection matrix using the orthographic projection matrix + mat4 mvp = orthoMatrix * rotationMatrix * model; + + // Apply the MVP matrix to the vertex position with scaling and aspect ratio + gl_Position = mvp * vec4( + (aPos.x + (position.x * reciprScaleOnscreen)) * aspectRatio, + aPos.y + (position.y * reciprScaleOnscreen), + aPos.z, + 1 + ); // Pass through other attributes Normal = mat3(model) * aNormal; // Transform the normal diff --git a/Core/Windowing/Frame.cs b/Core/Windowing/Frame.cs new file mode 100644 index 0000000..a15969a --- /dev/null +++ b/Core/Windowing/Frame.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpEngine.Core.Windowing; + +public class Frame +{ + public Frame(double frameTime) + { + FrameTime = frameTime; + } + + public double FrameTime { get; set; } + public float FrameRate => (float)(1 / FrameTime); +} diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index b84ede9..d917363 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -66,9 +66,6 @@ public override void Initialize() // TODO: Fix UI renderer _uiElem = new UIElement("uiElement"); - _uiElem.Transform.Scale = new SharpEngine.Core.Numerics.Vector2(0.5f, 0.5f); - _uiElem.Transform.Position = new SharpEngine.Core.Numerics.Vector2(2000, 0); - _uiElem.Transform.Rotation.Angle = 90; _scene.UIElements.Add(_uiElem); //var uiElem2 = new UIElement("uiElement"); @@ -94,17 +91,32 @@ public void OnAfterRender(double frameTime) var x = _uiElem.Transform.Position.X; var y = _uiElem.Transform.Position.Y; + var sx = _uiElem.Transform.Scale.X; + var sy = _uiElem.Transform.Scale.Y; + + var rotation = _uiElem.Transform.Rotation.Angle; + ImGui.Begin("Debug"); ImGui.Text($"FPS: {frameTime }"); ImGui.Text($"Camera position: {Camera.Position}"); ImGui.Text($"UI Element position: {_uiElem.Transform.Position}"); - - ImGui.SliderFloat("X", ref x, -1000, 1000); - ImGui.SliderFloat("Y", ref y, -1000, 1000); + + ImGui.SliderFloat("X", ref x, -2000, 2000); + ImGui.SliderFloat("Y", ref y, -2000, 2000); + + ImGui.Text($"UI Element scale: {_uiElem.Transform.Scale}"); + + ImGui.SliderFloat("sX", ref sx, 0, 1); + ImGui.SliderFloat("sY", ref sy, 0, 1); + + ImGui.Text($"UI Element scale: {_uiElem.Transform.Scale}"); + ImGui.SliderFloat("rotation", ref rotation, 0, 360); ImGui.End(); _uiElem.Transform.Position = new SharpEngine.Core.Numerics.Vector2(x, y); + _uiElem.Transform.Scale = new SharpEngine.Core.Numerics.Vector2(sx, sy); + _uiElem.Transform.Rotation.Angle = rotation; } private void InitializeWorld() From 0ba636e0082b2904fc89d5eeeac22033a3817ffe Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sun, 6 Apr 2025 21:04:50 +0300 Subject: [PATCH 33/92] Add documentation / general enhancements --- Core/{Interfaces => Abstractions}/IGame.cs | 0 Core/Abstractions/IRenderable.cs | 28 +++++++ .../{Interfaces => Abstractions}/ISettings.cs | 3 + Core/Entities/BezierCurve.cs | 29 ++++--- Core/Entities/Properties/BoundingBox.cs | 1 + Core/Entities/Properties/ITransform.cs | 11 +++ Core/Entities/Properties/Material.cs | 1 + Core/Entities/Properties/Meshes/Mesh.cs | 3 + .../Entities/Properties/Meshes/MeshService.cs | 77 +++++++++++++++++-- .../Entities/Properties/Meshes/ObjMeshData.cs | 22 ++++++ Core/Entities/Properties/Transform.cs | 3 + Core/Entities/UI/Layouts/FlexLayout.cs | 12 +-- Core/Entities/UI/Layouts/LayoutBase.cs | 31 +++++--- Core/Numerics/IVector.cs | 6 ++ Core/Numerics/Vector2.cs | 6 +- Core/Numerics/Vector2_Intrinsics.cs | 8 ++ Core/Numerics/Vector3.cs | 4 +- Core/Numerics/Vector3_Intrinsics.cs | 8 ++ Core/Renderers/Renderer.cs | 2 +- Core/Scenes/SceneNode.cs | 20 ++++- Core/Shaders/Shader.cs | 5 ++ Core/Shaders/uiShader.vert | 5 -- Core/Windowing/Frame.cs | 18 +++-- Core/_Resources/Default.cs | 14 ++-- Editor/EditorWindow.cs | 48 +++++++----- Editor/Windows/ContextMenuWindow.cs | 2 +- Editor/Windows/ImGuiWindowBase.cs | 3 + Examples/MinecraftClone/Minecraft.cs | 21 ++++- Examples/MinecraftClone/Program.cs | 3 +- 29 files changed, 314 insertions(+), 80 deletions(-) rename Core/{Interfaces => Abstractions}/IGame.cs (100%) create mode 100644 Core/Abstractions/IRenderable.cs rename Core/{Interfaces => Abstractions}/ISettings.cs (90%) create mode 100644 Core/Entities/Properties/Meshes/ObjMeshData.cs diff --git a/Core/Interfaces/IGame.cs b/Core/Abstractions/IGame.cs similarity index 100% rename from Core/Interfaces/IGame.cs rename to Core/Abstractions/IGame.cs diff --git a/Core/Abstractions/IRenderable.cs b/Core/Abstractions/IRenderable.cs new file mode 100644 index 0000000..6b00f6f --- /dev/null +++ b/Core/Abstractions/IRenderable.cs @@ -0,0 +1,28 @@ +using SharpEngine.Core.Entities.Properties.Meshes; + +namespace SharpEngine.Core.Interfaces; + +// TODO: Make an abstract class and move Render method here? + +/// +/// Contains definitions for rendering objects. +/// +public interface IRenderable +{ + /// + /// Gets or sets the vertex array object of the object. + /// + public uint VAO { get; set; } + + /// + /// Initializes the necessary buffers for the object. + /// + /// The mesh that should the buffers should be initialized with. + public void InitializeBuffers(Mesh mesh); + + /// + /// Binds the VAO to the current context. + /// + public void Bind(); + +} diff --git a/Core/Interfaces/ISettings.cs b/Core/Abstractions/ISettings.cs similarity index 90% rename from Core/Interfaces/ISettings.cs rename to Core/Abstractions/ISettings.cs index 17aa676..23888d2 100644 --- a/Core/Interfaces/ISettings.cs +++ b/Core/Abstractions/ISettings.cs @@ -22,7 +22,10 @@ public interface ISettings /// Gets or sets which renderer should be enabled for the current window. public RenderFlags RendererFlags { get; set; } + /// Gets or sets the primary mouse button. public MouseButton PrimaryButton { get; set; } + + /// Gets or sets the secondary mouse button. public MouseButton SecondaryButton { get; set; } } diff --git a/Core/Entities/BezierCurve.cs b/Core/Entities/BezierCurve.cs index aba3b70..cd2547c 100644 --- a/Core/Entities/BezierCurve.cs +++ b/Core/Entities/BezierCurve.cs @@ -1,20 +1,27 @@ using Silk.NET.Maths; using System; using System.Collections.Generic; -using System.Linq; -using System.Numerics; -using System.Text; -using System.Threading.Tasks; namespace SharpEngine.Core.Entities; + +/// +/// Represents a cubic Bezier curve. +/// public class BezierCurve { private Vector3D P0, P1, P2, P3; + + /// Gets the start point of the curve. public Vector3D Start => P0; - public Vector3D End => P3; - public List> Points { get; set; } + /// Gets the end point of the curve. + public Vector3D End => P3; + + /// + /// Initializes a new instance of . + /// + /// The point where the curve should be created. public BezierCurve(Vector3D initializationPosition) { const float defaultWidth = 1; @@ -23,11 +30,14 @@ public BezierCurve(Vector3D initializationPosition) P1 = new Vector3D(initializationPosition.X + defaultWidth, initializationPosition.Y + defaultWidth, initializationPosition.Z); P2 = new Vector3D(initializationPosition.X + defaultWidth, initializationPosition.Y - defaultWidth, initializationPosition.Z); P3 = new Vector3D(initializationPosition.X + defaultWidth, initializationPosition.Y, initializationPosition.Z); - - Points = GetPoints(20); } - public List> GetPoints(int resolution) + /// + /// Gets the points of the curve. + /// + /// The distance between each point, defines the roughness of the curve. + /// The points for the curve with the given . + public List> GetPoints(uint resolution) { var points = new List>(); for (var i = 0; i <= resolution; i++) @@ -35,6 +45,7 @@ public List> GetPoints(int resolution) var t = i / (float)resolution; points.Add(GetPointAt(t)); } + return points; } diff --git a/Core/Entities/Properties/BoundingBox.cs b/Core/Entities/Properties/BoundingBox.cs index f2a9bf6..e0a4e67 100644 --- a/Core/Entities/Properties/BoundingBox.cs +++ b/Core/Entities/Properties/BoundingBox.cs @@ -28,6 +28,7 @@ public BoundingBox(Vector3 min, Vector3 max) Max = max; } + // TODO: This should be calculated by the mesh. /// /// Calculates the bounding box of the game object. /// diff --git a/Core/Entities/Properties/ITransform.cs b/Core/Entities/Properties/ITransform.cs index 7f2cb89..a3b5dbd 100644 --- a/Core/Entities/Properties/ITransform.cs +++ b/Core/Entities/Properties/ITransform.cs @@ -3,10 +3,21 @@ namespace SharpEngine.Core.Entities.Properties; +/// +/// Represents the transform of an object in dimensions. +/// +/// public interface ITransform where TVector : IVector, new() { + /// Gets or set the the position of the object. public TVector Position { get; set; } + + /// Gets or set the the scale of the object. public TVector Scale { get; set; } + + /// Gets or set the the rotation of the object. public Quaternion Rotation { get; set; } + + /// Gets or set the the model matrix of the object. public Matrix4x4 ModelMatrix { get; } } \ No newline at end of file diff --git a/Core/Entities/Properties/Material.cs b/Core/Entities/Properties/Material.cs index b744d51..5f9083e 100644 --- a/Core/Entities/Properties/Material.cs +++ b/Core/Entities/Properties/Material.cs @@ -32,6 +32,7 @@ public Material(Shader shader, Texture diffuseMap, Texture? specularMap = null) /// public Texture SpecularMap { get; set; } + /// Gets whether the material uses a specular map. public bool UseSpecularMap => SpecularMap.Handle != DiffuseMap.Handle; /// diff --git a/Core/Entities/Properties/Meshes/Mesh.cs b/Core/Entities/Properties/Meshes/Mesh.cs index 88ca01c..dcd8d94 100644 --- a/Core/Entities/Properties/Meshes/Mesh.cs +++ b/Core/Entities/Properties/Meshes/Mesh.cs @@ -28,6 +28,9 @@ public class Mesh [Inspector(DisplayInInspector = false)] public float[] TextureCoordinates { get; set; } = []; + /// + /// Gets or sets the indicies of the mesh. + /// [Inspector(DisplayInInspector = false)] public uint[] Indices { get; set; } = []; } \ No newline at end of file diff --git a/Core/Entities/Properties/Meshes/MeshService.cs b/Core/Entities/Properties/Meshes/MeshService.cs index e884bf7..9b34f87 100644 --- a/Core/Entities/Properties/Meshes/MeshService.cs +++ b/Core/Entities/Properties/Meshes/MeshService.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; namespace SharpEngine.Core.Entities.Properties.Meshes; @@ -42,22 +43,86 @@ public Mesh LoadMesh(string identifier, Mesh mesh) const string FbxExtension = ".fbx"; const string ObjExtension = ".obj"; - public Mesh LoadMesh(string identifier, string meshFilePath) + /// + /// Loads a mesh based on the file extension of the provided path. + /// + /// Used to specify the unique identifier for the mesh being loaded. + /// Specifies the file path of the mesh to be loaded, which determines the loading method based on its extension. + /// A collection of objects loaded from the specified file. + /// Thrown when the file extension of the provided path is not recognized as a supported mesh format. + public IEnumerable LoadMesh(string identifier, string meshFilePath) => Path.GetExtension(meshFilePath) switch { - FbxExtension => LoadFbxMesh(identifier, meshFilePath), - ObjExtension => LoadObjMesh(identifier, meshFilePath), + FbxExtension => LoadFbx(identifier, meshFilePath), + ObjExtension => LoadObj(identifier, meshFilePath), _ => throw new NotSupportedException($"The file extension {Path.GetExtension(meshFilePath)} is not a supported mesh file.") }; // TODO: #2 Load obj mesh from file - private Mesh LoadObjMesh(string identifier, string meshFilePath) + private IEnumerable LoadObj(string identifier, string meshFilePath) { - throw new NotImplementedException(); + var vertices = new List(); + var normals = new List(); + var textureCoordinates = new List(); + var indices = new List(); + + Mesh LoadMeshIntoBuffer() + { + var mesh = LoadMesh(identifier, new Mesh + { + Vertices = [.. vertices], + Normals = [.. normals], + TextureCoordinates = [.. textureCoordinates], + Indices = [.. indices] + }); + + vertices.Clear(); + normals.Clear(); + textureCoordinates.Clear(); + indices.Clear(); + + return mesh; + } + + static IEnumerable GetData(string[] parts) => parts.Skip(1).Select(float.Parse); + + var contents = File.ReadAllLines(meshFilePath); + foreach (var line in contents) + { + var parts = line.Split(' ', StringSplitOptions.RemoveEmptyEntries); + if (parts.Length == 0) continue; + + switch (parts[0]) + { + case ObjMeshData.VERTEX: + vertices.AddRange(GetData(parts)); + break; + case ObjMeshData.VERTEX_NORMAL: + normals.AddRange(GetData(parts)); + break; + case ObjMeshData.VERTEX_TEXTURE: + textureCoordinates.AddRange(GetData(parts)); + break; + case ObjMeshData.FACE: // OBJ faces are defined as a list of vertex indices + foreach (var part in parts.Skip(1)) + { + var indicesParts = part.Split('/'); + indices.Add(uint.Parse(indicesParts[0]) - 1); // OBJ indices are 1-based + } + break; + case ObjMeshData.OBJECT: + if (vertices.Count > 0) + yield return LoadMeshIntoBuffer(); + break; + } + } + + if (vertices.Count > 0) + yield return LoadMeshIntoBuffer(); } // TODO: #3 Load fbx mesh from file - private Mesh LoadFbxMesh(string identifier, string meshFilePath) + private IEnumerable LoadFbx(string identifier, string meshFilePath) { throw new NotImplementedException(); } diff --git a/Core/Entities/Properties/Meshes/ObjMeshData.cs b/Core/Entities/Properties/Meshes/ObjMeshData.cs new file mode 100644 index 0000000..e1e45de --- /dev/null +++ b/Core/Entities/Properties/Meshes/ObjMeshData.cs @@ -0,0 +1,22 @@ +namespace SharpEngine.Core.Entities.Properties.Meshes; + +/// +/// Contains the different types of data the .obj file contains. +/// +public static class ObjMeshData +{ + /// Represents a line of vertex data. + public const string VERTEX = "v"; + + /// Represents a line of vertex normal data. + public const string VERTEX_NORMAL = "vn"; + + /// Represents a line of uv coordinate data. + public const string VERTEX_TEXTURE = "vt"; + + /// Represents a line of vertex indicie data. + public const string FACE = "f"; + + /// Represents that a new object begins. + public const string OBJECT = "o"; +} \ No newline at end of file diff --git a/Core/Entities/Properties/Transform.cs b/Core/Entities/Properties/Transform.cs index 92dc88c..81f0467 100644 --- a/Core/Entities/Properties/Transform.cs +++ b/Core/Entities/Properties/Transform.cs @@ -8,6 +8,9 @@ namespace SharpEngine.Core.Entities.Properties; /// public class Transform : ITransform { + /// + /// Initializes a new instance of the class. + /// public Transform() { } /// diff --git a/Core/Entities/UI/Layouts/FlexLayout.cs b/Core/Entities/UI/Layouts/FlexLayout.cs index d65776e..b0dded0 100644 --- a/Core/Entities/UI/Layouts/FlexLayout.cs +++ b/Core/Entities/UI/Layouts/FlexLayout.cs @@ -1,4 +1,5 @@ -using SharpEngine.Core.Scenes; +using SharpEngine.Core.Numerics; +using SharpEngine.Core.Scenes; using System; using System.Numerics; @@ -8,13 +9,14 @@ namespace SharpEngine.Core.Entities.UI.Layouts; /// Represents a layout that dynamically distributes items in a flex layout. /// /// The type of items in the collection. -public class FlexLayout : LayoutBase where T : SceneNode, new() +/// The amount of dimensions in the content area. +public class FlexLayout : LayoutBase where T : SceneNode, new() where TVector : IVector, new() { + /// Gets or sets the gap between each object. public int Gap { get; set; } - public int ContentSize { get; set; } - - public Vector2 ContentAreaSize { get; set; } + /// Gets or sets the dimensions of the content area. + public required IVector ContentAreaSize { get; set; } /// /// diff --git a/Core/Entities/UI/Layouts/LayoutBase.cs b/Core/Entities/UI/Layouts/LayoutBase.cs index 3b584d4..bb65554 100644 --- a/Core/Entities/UI/Layouts/LayoutBase.cs +++ b/Core/Entities/UI/Layouts/LayoutBase.cs @@ -1,18 +1,22 @@ -using SharpEngine.Core.Entities.Properties; -using SharpEngine.Core.Numerics; -using SharpEngine.Core.Scenes; -using System; +using SharpEngine.Core.Scenes; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace SharpEngine.Core.Entities.UI.Layouts; +/// +/// Represents the base class for all layout types. +/// +/// public abstract class LayoutBase : SceneNode where TItem : SceneNode, new() { + /// Represents the items in the layout. public List Items { get; set; } = []; + /// + /// Adds a new item to the layout. + /// + /// The items to be added. + /// The object itself. public override LayoutBase AddChild(params SceneNode[] nodes) { base.AddChild(nodes); @@ -23,15 +27,18 @@ public override LayoutBase AddChild(params SceneNode[] nodes) return this; } + /// + /// Adds and item to the container. + /// + /// The item to be added. public virtual void AddItem(TItem item) { Items.Add(item); } - public virtual bool RemoveItem(TItem item) - { - return Items.Remove(item); - } - + /// + /// Gets the items in the container. + /// + /// The items as a 2D array representation. public abstract TItem[][] GetValues(); } diff --git a/Core/Numerics/IVector.cs b/Core/Numerics/IVector.cs index b6f41dd..c581a9b 100644 --- a/Core/Numerics/IVector.cs +++ b/Core/Numerics/IVector.cs @@ -2,8 +2,14 @@ namespace SharpEngine.Core.Numerics; +/// +/// An abstraction of the different vector types. +/// public interface IVector { + /// public Single X { get; set; } + + /// public Single Y { get; set; } } \ No newline at end of file diff --git a/Core/Numerics/Vector2.cs b/Core/Numerics/Vector2.cs index 6423d16..70b52ef 100644 --- a/Core/Numerics/Vector2.cs +++ b/Core/Numerics/Vector2.cs @@ -56,9 +56,9 @@ public override int GetHashCode() /// The Object to compare against. /// True if the Object is equal to this Vector2; False otherwise. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override bool Equals(object obj) + public override bool Equals(object? obj) { - if (!(obj is Vector2)) + if (obj is not Vector2) return false; return Equals((Vector2)obj); } @@ -89,7 +89,7 @@ public string ToString(string format) /// The format of individual elements. /// The format provider to use when formatting elements. /// The string representation. - public string ToString(string format, IFormatProvider formatProvider) + public string ToString(string? format, IFormatProvider? formatProvider) { StringBuilder sb = new StringBuilder(); string separator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator; diff --git a/Core/Numerics/Vector2_Intrinsics.cs b/Core/Numerics/Vector2_Intrinsics.cs index 6a04d6c..2ac4fb6 100644 --- a/Core/Numerics/Vector2_Intrinsics.cs +++ b/Core/Numerics/Vector2_Intrinsics.cs @@ -295,9 +295,17 @@ public static Vector2 SquareRoot(Vector2 value) return !(left == right); } + /// + /// Converts the SharpEngine representation to a System.Numerics representation. + /// + /// The value to convert public static explicit operator System.Numerics.Vector2(Vector2 value) => new(value.X, value.Y); + /// + /// Converts the System.Numerics representation to a SharpEngine representation. + /// + /// The value to convert public static explicit operator Vector2(System.Numerics.Vector2 value) => new(value.X, value.Y); diff --git a/Core/Numerics/Vector3.cs b/Core/Numerics/Vector3.cs index 1a1e2b7..f34601a 100644 --- a/Core/Numerics/Vector3.cs +++ b/Core/Numerics/Vector3.cs @@ -61,7 +61,7 @@ public override int GetHashCode() /// The Object to compare against. /// True if the Object is equal to this Vector3; False otherwise. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (!(obj is Vector3)) return false; @@ -94,7 +94,7 @@ public string ToString(string format) /// The format of individual elements. /// The format provider to use when formatting elements. /// The string representation. - public string ToString(string format, IFormatProvider formatProvider) + public string ToString(string? format, IFormatProvider? formatProvider) { StringBuilder sb = new StringBuilder(); string separator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator; diff --git a/Core/Numerics/Vector3_Intrinsics.cs b/Core/Numerics/Vector3_Intrinsics.cs index 6a6e7f5..5cccbcc 100644 --- a/Core/Numerics/Vector3_Intrinsics.cs +++ b/Core/Numerics/Vector3_Intrinsics.cs @@ -322,9 +322,17 @@ public static Vector3 SquareRoot(Vector3 value) left.Z != right.Z); } + /// + /// Converts the SharpEngine representation to a System.Numerics representation. + /// + /// The value to convert public static explicit operator System.Numerics.Vector3(Vector3 value) => new(value.X, value.Y, value.Z); + /// + /// Converts the System.Numerics representation to a SharpEngine representation. + /// + /// The value to convert public static explicit operator Vector3(System.Numerics.Vector3 value) => new(value.X, value.Y, value.Z); diff --git a/Core/Renderers/Renderer.cs b/Core/Renderers/Renderer.cs index 77752ad..fcbc7c7 100644 --- a/Core/Renderers/Renderer.cs +++ b/Core/Renderers/Renderer.cs @@ -49,7 +49,7 @@ public Renderer(CameraView camera, ISettings settings, Scene scene) : base(setti /// public override Task Render() { - return Task.CompletedTask; + // return Task.CompletedTask; try { Window.GL.Enable(EnableCap.DepthTest); diff --git a/Core/Scenes/SceneNode.cs b/Core/Scenes/SceneNode.cs index a0ce9b8..bf49421 100644 --- a/Core/Scenes/SceneNode.cs +++ b/Core/Scenes/SceneNode.cs @@ -1,16 +1,28 @@ -using SharpEngine.Core.Entities; using SharpEngine.Core.Entities.Properties; using SharpEngine.Core.Entities.Views; using SharpEngine.Core.Numerics; + using System.Collections.Generic; using System.Threading.Tasks; namespace SharpEngine.Core.Scenes; +/// +/// Represents a empty node in a scene. +/// +/// Specifies the type used for transformations. +/// Defines vector used by the transform. public class EmptyNode : SceneNode where TTransform : ITransform, new() where TVector : IVector, new() { + /// + /// Initializes a new instance of . + /// + /// public EmptyNode(string name) : base(name) { } + /// + /// Gets or sets the transform of the node. + /// public virtual TTransform Transform { get; set; } = new(); } @@ -19,6 +31,7 @@ public EmptyNode(string name) : base(name) { } /// public abstract class SceneNode { + /// Gets a new empty node. public static SceneNode Empty => new EmptyNode("Empty Node"); /// @@ -45,6 +58,11 @@ public SceneNode(string name) Name = name; } + /// + /// Adds an empty child node to this node by the given . + /// + /// The name of the empty node to be added. + /// The created node. public virtual SceneNode AddChild(string name) => AddChild(name); diff --git a/Core/Shaders/Shader.cs b/Core/Shaders/Shader.cs index 0197abb..9b117c0 100644 --- a/Core/Shaders/Shader.cs +++ b/Core/Shaders/Shader.cs @@ -268,6 +268,11 @@ public void SetMatrix4(string name, Matrix4x4 data, bool transpose = true) TrySetUniform(name, data, (uniform, d) => Window.GL.UniformMatrix4(uniform, transpose, d.ToSpan())); } + /// + /// Set a uniform Vector2 on this shader. + /// + /// The name of the uniform. + /// The data to set. public void SetVector2(string name, Vector2 data) { Window.GL.UseProgram(Handle); diff --git a/Core/Shaders/uiShader.vert b/Core/Shaders/uiShader.vert index 36a425e..959393c 100644 --- a/Core/Shaders/uiShader.vert +++ b/Core/Shaders/uiShader.vert @@ -6,15 +6,10 @@ layout (location = 2) in vec2 aTexCoords; uniform vec2 position; uniform float rotation; -uniform vec2 scale; uniform vec2 screenSize; -uniform mat4 clipSpace; uniform mat4 orthoMatrix; -uniform mat4 view; -uniform mat4 projection; uniform mat4 model; -uniform vec3 viewPos; out vec3 Normal; out vec3 FragPos; diff --git a/Core/Windowing/Frame.cs b/Core/Windowing/Frame.cs index a15969a..9b43fbf 100644 --- a/Core/Windowing/Frame.cs +++ b/Core/Windowing/Frame.cs @@ -1,18 +1,22 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SharpEngine.Core.Windowing; +namespace SharpEngine.Core.Windowing; +/// +/// Represents a frame with a specific duration in time. +/// public class Frame { + /// + /// Initializes a new instance of . + /// + /// Represents the duration of the frame in seconds. public Frame(double frameTime) { FrameTime = frameTime; } + /// Gets or sets the time taken to handle the previous frame. public double FrameTime { get; set; } + + /// Gets the frame rate based on the frame time. public float FrameRate => (float)(1 / FrameTime); } diff --git a/Core/_Resources/Default.cs b/Core/_Resources/Default.cs index 77dced2..fb078fb 100644 --- a/Core/_Resources/Default.cs +++ b/Core/_Resources/Default.cs @@ -1,14 +1,18 @@ using SharpEngine.Core.Extensions; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace SharpEngine.Core._Resources; + +/// +/// Contains default resources used by the engine. +/// public struct Default { + /// Gets the path to the debug texture. public static string DebugTexture => PathExtensions.GetAssemblyPath("Textures\\DefaultTextures\\debug.JPG"); + + /// Gets the path to the default vertex shader. public static string VertexShader => PathExtensions.GetAssemblyPath("Shaders\\shader.vert"); + + /// Gets the path to the lighting fragment shader. public static string FragmentShader => PathExtensions.GetAssemblyPath("Shaders\\lighting.frag"); } diff --git a/Editor/EditorWindow.cs b/Editor/EditorWindow.cs index 87d99de..6c11873 100644 --- a/Editor/EditorWindow.cs +++ b/Editor/EditorWindow.cs @@ -95,34 +95,43 @@ public override void OnLoad() } } + private bool showUnsavedChangesDialog = true; + /// - protected override void AfterRender(double deltaTime) + protected override void AfterRender(double frame) { - base.AfterRender(deltaTime); + base.AfterRender(frame); EnableDocking(); RenderMenuBar(); - bool visible = true; - ImGui.Begin("Unsaved changes", ref visible, ImGuiWindowFlags.NoResize | ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoMove); + ImGui.Begin("Unsaved changes", ref showUnsavedChangesDialog, ImGuiWindowFlags.NoResize | ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoMove); ImGui.Text("There are unsaved changes in the project. Are you sure you want to exist without saving?"); - if (ImGui.Button("Save")) - { - // Save the scene and exit - } + bool cancelled = false; + if (ImGui.Button("Cancel")) + cancelled = true; - if (ImGui.Button("Exit without saving")) + if (!cancelled && ImGui.Button("Save & close")) { - // TODO: shut down the application + Save(); + CurrentWindow.Close(); } + if (!cancelled && ImGui.Button("Exit without saving")) + CurrentWindow.Close(); + ImGui.End(); foreach (var window in _windows) window.RenderWindow(); } + private void Save() + { + // TODO: Save all changes. + } + private static void EnableDocking() { // Enable docking @@ -189,29 +198,31 @@ private void RenderMenuBar() } } - private static void RenderFileMenu() + private void RenderFileMenu() { if (ImGui.BeginMenu("File")) { if (ImGui.MenuItem("New")) { - // Handle New action + // TODO: Handle New action } + if (ImGui.MenuItem("Open")) { - // Handle Open action + // TODO: Handle Open action } + if (ImGui.MenuItem("Save")) - { - // Handle Save action - } + Save(); + if (ImGui.MenuItem("Exit")) { - // Handle Exit action + // TODO: Handle Exit action } + if (ImGui.MenuItem("Publish")) { - // Handle Publish action + // TODO: Handle Publish action } ImGui.EndMenu(); @@ -241,6 +252,7 @@ public override void OnMouseClick(IMouse mouse, MouseButton button, Vector2 vect if (button == Settings.SecondaryButton) { + // TODO: Make this work. if (ImGui.IsItemClicked((ImGuiMouseButton)button)) { // Clicked on an ImGui component diff --git a/Editor/Windows/ContextMenuWindow.cs b/Editor/Windows/ContextMenuWindow.cs index cba5351..1233710 100644 --- a/Editor/Windows/ContextMenuWindow.cs +++ b/Editor/Windows/ContextMenuWindow.cs @@ -66,7 +66,7 @@ private void RenderIntersectedObjectActions() { if (ImGui.Button("Delete")) { - Scene.Root.RemoveChild(IntersectedObject); + Scene.Root.RemoveChild(IntersectedObject!); IntersectedObject = null; } } diff --git a/Editor/Windows/ImGuiWindowBase.cs b/Editor/Windows/ImGuiWindowBase.cs index 8e62aa9..5fabc93 100644 --- a/Editor/Windows/ImGuiWindowBase.cs +++ b/Editor/Windows/ImGuiWindowBase.cs @@ -47,6 +47,9 @@ public ImGuiWindowBase() /// The new project. public void SetProject(Project project) => Project = project; + /// + /// Makes the ImGui window visible. + /// public void Open() => _isVisible = true; /// diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index d917363..12ae347 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -15,6 +15,8 @@ using SharpEngine.Core.Entities.UI.Layouts; using SharpEngine.Core.Entities.Properties; using ImGuiNET; +using SharpEngine.Core.Entities.Properties.Meshes; +using System.Linq; namespace Minecraft; @@ -35,6 +37,9 @@ public class Minecraft : Game private UIElement _uiElem; + /// + /// Gets the main window. + /// public Window? Window { get; set; } /// @@ -66,14 +71,14 @@ public override void Initialize() // TODO: Fix UI renderer _uiElem = new UIElement("uiElement"); - _scene.UIElements.Add(_uiElem); + //_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); // gridLayout.AddChild(_uiElem, uiElem2); - _scene.UIElements.Add(_uiElem); + // _scene.UIElements.Add(_uiElem); // _scene.UIElements.Add(uiElem2); //_scene.UIElements.Add(gridLayout); @@ -86,7 +91,11 @@ public override void Initialize() } } - public void OnAfterRender(double frameTime) + /// + /// Handles rendering after the frame is drawn. + /// + /// Information about the frame. + public void OnAfterRender(Frame frame) { var x = _uiElem.Transform.Position.X; var y = _uiElem.Transform.Position.Y; @@ -97,7 +106,7 @@ public void OnAfterRender(double frameTime) var rotation = _uiElem.Transform.Rotation.Angle; ImGui.Begin("Debug"); - ImGui.Text($"FPS: {frameTime }"); + ImGui.Text($"FPS: {frame.FrameRate}"); ImGui.Text($"Camera position: {Camera.Position}"); ImGui.Text($"UI Element position: {_uiElem.Transform.Position}"); @@ -123,6 +132,10 @@ private void InitializeWorld() { InitializeLights(); InitializeChunks(); + + // var torus = MeshService.Instance.LoadMesh("torus", @"C:\Users\antti\Documents\Untitled2.obj"); + // var go = new GameObject(); + // go.Meshes.Add(torus.First()); } private void InitializeLights() diff --git a/Examples/MinecraftClone/Program.cs b/Examples/MinecraftClone/Program.cs index 46a0d1b..0c5de89 100644 --- a/Examples/MinecraftClone/Program.cs +++ b/Examples/MinecraftClone/Program.cs @@ -1,5 +1,6 @@ using SharpEngine.Core.Interfaces; using SharpEngine.Core.Scenes; +using SharpEngine.Core.Windowing; namespace Minecraft; @@ -25,7 +26,7 @@ private static void Main() window.OnHandleKeyboard += game.HandleKeyboard; window.OnButtonMouseDown += game.HandleMouseDown; window.HandleMouseWheel += game.HandleMouseWheel; - window.OnAfterRender += game.OnAfterRender; + window.OnAfterRender += deltaTime => game.OnAfterRender(new Frame(deltaTime)); // TODO: This needs to be streamlined. game.Window = window; From c6d7764e03e49eb947e218ec50624715d59e399c Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sun, 6 Apr 2025 21:13:19 +0300 Subject: [PATCH 34/92] #2 Framing and rendering changes --- Core/Entities/GameObject.cs | 45 +++++++++++++- Core/Entities/Lights/DirectionalLight.cs | 2 +- Core/Entities/Lights/PointLight.cs | 2 +- Core/Entities/Lights/SpotLight.cs | 2 +- Core/Entities/UI/UIElement.cs | 70 ++++++++-------------- Core/Primitives/PrimitiveFactory.cs | 2 +- Core/Renderers/Renderer.cs | 6 +- Core/Renderers/TextRenderer.cs | 3 +- Core/Renderers/UIRenderer.cs | 13 ++-- Core/Scenes/SceneNode.cs | 4 +- Core/Windowing/SilkWindow.cs | 4 +- Core/Windowing/Window.cs | 30 +++++----- Editor/EditorWindow.cs | 2 +- Examples/MinecraftClone/Block/BlockBase.cs | 2 +- Examples/MinecraftClone/Minecraft.cs | 1 + 15 files changed, 104 insertions(+), 84 deletions(-) diff --git a/Core/Entities/GameObject.cs b/Core/Entities/GameObject.cs index d355d7b..c228615 100644 --- a/Core/Entities/GameObject.cs +++ b/Core/Entities/GameObject.cs @@ -2,6 +2,7 @@ using SharpEngine.Core.Entities.Properties; using SharpEngine.Core.Entities.Properties.Meshes; using SharpEngine.Core.Entities.Views; +using SharpEngine.Core.Interfaces; using SharpEngine.Core.Numerics; using SharpEngine.Core.Scenes; using SharpEngine.Core.Shaders; @@ -18,7 +19,7 @@ namespace SharpEngine.Core.Entities; /// /// Represents a game object in the scene. /// -public class GameObject : EmptyNode +public class GameObject : EmptyNode, IRenderable { /// /// Initializes a new instance of the . @@ -53,8 +54,9 @@ public GameObject(string? diffuseMapFile = null, string? specularMapFile = null, /// /// Gets or sets the mesh of the game object. /// - public List Mesh { get; set; } = []; + public List Meshes { get; set; } = []; + // TODO: Each mesh should have its own material. /// /// Gets or sets the material of the game object. /// @@ -83,7 +85,40 @@ public override Transform Transform public BoundingBox BoundingBox { get; set; } /// - public override Task Render(CameraView camera) + public uint VAO { get; set; } + + /// + public void Initialize() + { + VAO = Window.GL.GenVertexArray(); + Bind(); + + foreach (var mesh in Meshes) + InitializeBuffers(mesh); + + Material.Shader.Use(); + } + + /// + public void Bind() + { + Window.GL.BindVertexArray(VAO); + } + + /// + public void InitializeBuffers(Mesh mesh) + { + 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); + } + + /// + public override Task Render(CameraView camera, Window window) { Material.DiffuseMap.Use(TextureUnit.Texture0); Material.Shader.SetInt("material.diffuse", Material.diffuseUnit); @@ -103,8 +138,12 @@ public override Task Render(CameraView camera) } Material.Shader.SetMatrix4(ShaderAttributes.Model, Transform.ModelMatrix); + Window.GL.DrawArrays(PrimitiveType.Triangles, 0, 36); + // foreach (var mesh in Meshes) + // Window.GL.DrawElements(PrimitiveType.Triangles, (uint)mesh.Indices.Length, DrawElementsType.UnsignedInt, []); + return Task.CompletedTask; } } diff --git a/Core/Entities/Lights/DirectionalLight.cs b/Core/Entities/Lights/DirectionalLight.cs index 7b4a495..b5d0367 100644 --- a/Core/Entities/Lights/DirectionalLight.cs +++ b/Core/Entities/Lights/DirectionalLight.cs @@ -30,7 +30,7 @@ public DirectionalLight() } /// - public override Task Render(CameraView camera) + public override Task Render(CameraView camera, Windowing.Window window) { Material.Shader.SetVector3("dirLight.direction", Direction); Material.Shader.SetVector3("dirLight.ambient", Ambient); diff --git a/Core/Entities/Lights/PointLight.cs b/Core/Entities/Lights/PointLight.cs index 85dbade..4ce5537 100644 --- a/Core/Entities/Lights/PointLight.cs +++ b/Core/Entities/Lights/PointLight.cs @@ -52,7 +52,7 @@ public PointLight(Vector3 position, int index) public float Quadratic { get; set; } /// - public override Task Render(CameraView camera) + public override Task Render(CameraView camera, Windowing.Window window) { Material.Shader.SetVector3($"pointLights[{_index}].position", (System.Numerics.Vector3)Transform.Position); Material.Shader.SetVector3($"pointLights[{_index}].ambient", Ambient); diff --git a/Core/Entities/Lights/SpotLight.cs b/Core/Entities/Lights/SpotLight.cs index f66bc55..085d382 100644 --- a/Core/Entities/Lights/SpotLight.cs +++ b/Core/Entities/Lights/SpotLight.cs @@ -58,7 +58,7 @@ public SpotLight() public float Quadratic { get; set; } /// - public override Task Render(CameraView camera) + public override Task Render(CameraView camera, Windowing.Window window) { Material.Shader.SetVector3("spotLight.position", (System.Numerics.Vector3)Transform.Position); Material.Shader.SetVector3("spotLight.direction", Direction); diff --git a/Core/Entities/UI/UIElement.cs b/Core/Entities/UI/UIElement.cs index 3f3fecd..2bbf712 100644 --- a/Core/Entities/UI/UIElement.cs +++ b/Core/Entities/UI/UIElement.cs @@ -1,7 +1,7 @@ using SharpEngine.Core.Entities.Properties; using SharpEngine.Core.Entities.Properties.Meshes; using SharpEngine.Core.Entities.Views; -using SharpEngine.Core.Numerics; +using SharpEngine.Core.Interfaces; using SharpEngine.Core.Scenes; using SharpEngine.Core.Shaders; using SharpEngine.Core.Windowing; @@ -10,15 +10,17 @@ using System.Numerics; using System.Threading.Tasks; using Vector2 = SharpEngine.Core.Numerics.Vector2; -using Vector3 = System.Numerics.Vector3; namespace SharpEngine.Core.Entities.UI; /// /// Represents a User Interface entity. /// -public class UIElement : EmptyNode +public class UIElement : EmptyNode, IRenderable { + /// + /// Initializes a new instance of . + /// public UIElement() : this("UIElement") { } /// @@ -27,6 +29,7 @@ public UIElement() : this("UIElement") { } /// The name of the UI element. public UIElement(string name) : base(name) { + // TODO: Support custom meshes? Mesh = MeshService.Instance.LoadMesh(nameof(Primitives.Plane), Primitives.Plane.Mesh); Initialize(); @@ -36,87 +39,64 @@ public UIElement(string name) : base(name) /// Gets or sets the mesh of the UI element. public Mesh Mesh { get; set; } - //public override Transform2D Transform { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } - private uint _vertexArrayObject; + /// + public uint VAO { get; set; } /// public void Initialize() { - _vertexArrayObject = Window.GL.GenVertexArray(); + VAO = Window.GL.GenVertexArray(); Bind(); - InitializeBuffers(); + InitializeBuffers(Mesh); - _uiShader.Shader.Use(); + _uiShader.Shader?.Use(); _uiShader.SetAttributes(); } - /// - /// Binds the VAO to the current context. - /// + /// public void Bind() { - Window.GL.BindVertexArray(_vertexArrayObject); + Window.GL.BindVertexArray(VAO); } - private void InitializeBuffers() + /// + public void InitializeBuffers(Mesh mesh) { var vertexBufferObject = Window.GL.GenBuffer(); Window.GL.BindBuffer(GLEnum.ArrayBuffer, vertexBufferObject); - Window.GL.BufferData(GLEnum.ArrayBuffer, Mesh.GetVertices(), GLEnum.StaticDraw); + 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); + 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) + public override Task Render(CameraView camera, Window window) { - Window.GL.BindVertexArray(_vertexArrayObject); + if (_uiShader.Shader is null) + return Task.CompletedTask; + + Bind(); // TODO: These should come from somewhere else. const float screenWidth = 1280; const float screenHeight = 720; - var orthoMatrix = Matrix4x4.CreateOrthographicOffCenter(-1, 1, -1, 1, -1, 1); - - _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.SetVector2("scale", (System.Numerics.Vector2)Transform.Scale); _uiShader.Shader.SetMatrix4(ShaderAttributes.Model, Transform.ModelMatrix); - _uiShader.Shader.SetMatrix4("orthoMatrix", orthoMatrix); // Pass the orthographic matrix to the shader - - _uiShader.Shader!.SetMatrix4("view", camera.GetViewMatrix()); - _uiShader.Shader!.SetMatrix4("projection", camera.GetProjectionMatrix()); - _uiShader.Shader!.SetVector3("viewPos", camera.Position); - - - var pos = new Vector3(Transform.Position.X, Transform.Position.Y, 0); - var clipSpace = WorldToClipSpace(pos, Transform.ModelMatrix, camera.GetViewMatrix(), camera.GetProjectionMatrix()); - _uiShader.Shader.SetVector4("clipSpace", clipSpace); + _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; } - - public static Vector4 WorldToClipSpace(Vector3 position, Matrix4x4 model, Matrix4x4 view, Matrix4x4 projection) - { - // Combine all transforms into MVP - Matrix4x4 mvp = model * view * projection; - - // Convert Vector3 to Vector4 for matrix multiplication - Vector4 worldPos = new Vector4(position, 1.0f); - - // Transform to clip space (i.e., ready to assign to gl_Position) - Vector4 clipSpacePos = Vector4.Transform(worldPos, mvp); - - return clipSpacePos; - } } diff --git a/Core/Primitives/PrimitiveFactory.cs b/Core/Primitives/PrimitiveFactory.cs index 51f03d0..8dd935e 100644 --- a/Core/Primitives/PrimitiveFactory.cs +++ b/Core/Primitives/PrimitiveFactory.cs @@ -33,7 +33,7 @@ public static GameObject Create(PrimitiveType primitiveType, Vector3 position, s => new(diffuseMapFile, specularMapFile, vertShaderFile ?? _Resources.Default.VertexShader, fragShaderFile ?? _Resources.Default.FragmentShader) { Transform = new Transform { Position = (SharpEngine.Core.Numerics.Vector3)position }, - Mesh = primitiveType switch + Meshes = primitiveType switch { PrimitiveType.Cube => [Cube.Mesh], PrimitiveType.Plane => [Plane.Mesh], diff --git a/Core/Renderers/Renderer.cs b/Core/Renderers/Renderer.cs index fcbc7c7..62a889f 100644 --- a/Core/Renderers/Renderer.cs +++ b/Core/Renderers/Renderer.cs @@ -23,6 +23,7 @@ public class Renderer : RendererBase private readonly CameraView _camera; private readonly Scene _scene; + private readonly Window _window; // Read only once, load into OpenGL buffer once. // TODO: Multiple meshes @@ -36,10 +37,11 @@ public class Renderer : RendererBase /// The game the renderer is being used for. /// The settings for the renderer. /// The game scene to be rendered. - public Renderer(CameraView camera, ISettings settings, Scene scene) : base(settings) + public Renderer(CameraView camera, Window window, ISettings settings, Scene scene) : base(settings) { _camera = camera; _scene = scene; + _window = window; // TODO: These should be refactored out. The minimum build shouldn't need to use these. _lightingShader = new LightingShader(); @@ -82,7 +84,7 @@ private Task RenderGameObject(SceneNode node) return Task.CompletedTask; // TODO: Skip blocks that are behind others relative to the camera - return gameObject.Render(_camera); + return gameObject.Render(_camera, _window); } private static bool IsInViewFrustum(BoundingBox boundingBox, CameraView camera) diff --git a/Core/Renderers/TextRenderer.cs b/Core/Renderers/TextRenderer.cs index eff8504..e8bef69 100644 --- a/Core/Renderers/TextRenderer.cs +++ b/Core/Renderers/TextRenderer.cs @@ -1,12 +1,13 @@ 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, ISettings settings, Scene scene) : base(settings) + public TextRenderer(CameraView camera, Window window, ISettings settings, Scene scene) : base(settings) { } diff --git a/Core/Renderers/UIRenderer.cs b/Core/Renderers/UIRenderer.cs index ff9c067..67d3166 100644 --- a/Core/Renderers/UIRenderer.cs +++ b/Core/Renderers/UIRenderer.cs @@ -1,18 +1,13 @@ -using SharpEngine.Core.Entities.Properties; -using SharpEngine.Core.Entities.UI; +using SharpEngine.Core.Entities.UI; using SharpEngine.Core.Entities.Views; using SharpEngine.Core.Interfaces; using SharpEngine.Core.Scenes; using SharpEngine.Core.Shaders; using SharpEngine.Core.Windowing; -using Silk.NET.Input; using Silk.NET.OpenGL; using System; -using System.Linq; -using System.Numerics; using System.Threading.Tasks; -using static Silk.NET.Core.Native.WinString; namespace SharpEngine.Core.Renderers; @@ -24,6 +19,7 @@ public class UIRenderer : RendererBase private readonly Scene _scene; private readonly UIShader _uiShader; private readonly CameraView _camera; + private readonly Window _window; /// public override RenderFlags RenderFlag => RenderFlags.UIRenderer; @@ -31,11 +27,12 @@ public class UIRenderer : RendererBase /// /// Initializes a new instance of . /// - public UIRenderer(CameraView camera, ISettings settings, Scene scene) : base(settings) + public UIRenderer(CameraView camera, Window window, ISettings settings, Scene scene) : base(settings) { _scene = scene; _uiShader = new UIShader(); _camera = camera; + _window = window; } /// @@ -52,7 +49,7 @@ public override Task Render() // _camera.SetShaderUniforms(_uiShader.Shader!); _uiShader.Shader.Use(); - var uiElementRenderTasks = _scene.IterateAsync(_scene.UIElements, elem => elem.Render(_camera)); + var uiElementRenderTasks = _scene.IterateAsync(_scene.UIElements, elem => elem.Render(_camera, _window)); return Task.WhenAll(uiElementRenderTasks); } diff --git a/Core/Scenes/SceneNode.cs b/Core/Scenes/SceneNode.cs index bf49421..89f25a3 100644 --- a/Core/Scenes/SceneNode.cs +++ b/Core/Scenes/SceneNode.cs @@ -1,7 +1,7 @@ using SharpEngine.Core.Entities.Properties; using SharpEngine.Core.Entities.Views; using SharpEngine.Core.Numerics; - +using SharpEngine.Core.Windowing; using System.Collections.Generic; using System.Threading.Tasks; @@ -105,5 +105,5 @@ public void RemoveChild(SceneNode node) /// Renders the current object to the screen. /// /// A representing an asynchronous operation. - public virtual Task Render(CameraView camera) => Task.CompletedTask; + public virtual Task Render(CameraView camera, Window window) => Task.CompletedTask; } diff --git a/Core/Windowing/SilkWindow.cs b/Core/Windowing/SilkWindow.cs index 64ae012..aacfd26 100644 --- a/Core/Windowing/SilkWindow.cs +++ b/Core/Windowing/SilkWindow.cs @@ -304,13 +304,13 @@ public virtual void OnLoad() /// Handles operations needed to be executed after the renderers are finished. /// /// Time since the last frame. - protected virtual void AfterRender(double deltaTime) => OnAfterRender?.Invoke(deltaTime); + protected virtual void AfterRender(Frame frame) => OnAfterRender?.Invoke(frame.FrameTime); /// /// Handles operations needed to be executed before the renderers are executed. /// /// Time since the last frame. - protected virtual void PreRender(double deltaTime) { } + protected virtual void PreRender(Frame frame) { } // TODO: Scene unsaved changes warning. /// diff --git a/Core/Windowing/Window.cs b/Core/Windowing/Window.cs index 85f9c97..3d4f44f 100644 --- a/Core/Windowing/Window.cs +++ b/Core/Windowing/Window.cs @@ -84,7 +84,7 @@ public Window(CameraView camera, Scene scene, IViewSettings settings) Scene = scene; Settings = settings; Camera = camera; - Initialize(); + InitializeWindow(); } /// @@ -98,16 +98,16 @@ public Window(Scene scene, IViewSettings settings) Settings = settings; Camera = new(Vector3.One, settings); - Initialize(); + InitializeWindow(); } private bool _windowInitialized; - private void Initialize() + private void InitializeWindow() { CurrentWindow = CreateWindow(Settings.WindowOptions); - CurrentWindow.Update += OnUpdateFrame; - CurrentWindow.Render += RenderFrame; + CurrentWindow.Update += deltaTime => OnUpdateFrame(new Frame(deltaTime)); + CurrentWindow.Render += deltaTime => RenderFrame(new Frame(deltaTime)); CurrentWindow.Resize += OnResize; CurrentWindow.Load += OnLoad; CurrentWindow.Closing += OnClosing; @@ -162,7 +162,7 @@ public override void OnLoad() { // Make sure the renderer has the correct constructor parameters! // TODO: 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, Settings, Scene }; + var requiredArguments = new object[] { Camera, this, Settings, Scene }; var renderer = (RendererBase)Activator.CreateInstance(type, requiredArguments)!; _renderers = _renderers.Append(renderer); @@ -186,8 +186,8 @@ public override void OnLoad() /// /// Renders the current view and all specified renderers. /// - /// The time since the last frame. - protected void RenderFrame(double deltaTime) + /// Contains information about the previous frame. + protected void RenderFrame(Frame frame) { while (!_initialized) { @@ -196,9 +196,9 @@ protected void RenderFrame(double deltaTime) try { - PreRender(deltaTime); + PreRender(frame); - _imGuiController?.Update((float)deltaTime); + _imGuiController?.Update((float)frame.FrameTime); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); @@ -215,7 +215,7 @@ protected void RenderFrame(double deltaTime) // TODO: This call causes flickering in the new framework. Investigate why. // _window.SwapBuffers(); - AfterRender(deltaTime); + AfterRender(frame); _imGuiController?.Render(); } @@ -243,7 +243,7 @@ private void UseShaders() } /// - protected void OnUpdateFrame(double deltaTime) + protected void OnUpdateFrame(Frame frame) { while (!_initialized) { @@ -255,7 +255,7 @@ protected void OnUpdateFrame(double deltaTime) // return; if (Settings.PrintFrameRate) - Console.WriteLine($"FPS: {1f / deltaTime}"); + Console.WriteLine($"FPS: {frame.FrameRate}"); // TODO: Handle multiple mice? var mouse = Input?.Mice[0]; @@ -271,11 +271,11 @@ protected void OnUpdateFrame(double deltaTime) if (keyboard.IsKeyPressed(Key.Escape)) CurrentWindow.Close(); - OnHandleKeyboard?.Invoke(keyboard, deltaTime); + OnHandleKeyboard?.Invoke(keyboard, frame.FrameTime); } if (Input is not null) - OnUpdate?.Invoke(deltaTime, Input); + OnUpdate?.Invoke(frame.FrameTime, Input); } // TODO: #21 Input system diff --git a/Editor/EditorWindow.cs b/Editor/EditorWindow.cs index 6c11873..4746b74 100644 --- a/Editor/EditorWindow.cs +++ b/Editor/EditorWindow.cs @@ -98,7 +98,7 @@ public override void OnLoad() private bool showUnsavedChangesDialog = true; /// - protected override void AfterRender(double frame) + protected override void AfterRender(Frame frame) { base.AfterRender(frame); diff --git a/Examples/MinecraftClone/Block/BlockBase.cs b/Examples/MinecraftClone/Block/BlockBase.cs index 15c7a93..7f06016 100644 --- a/Examples/MinecraftClone/Block/BlockBase.cs +++ b/Examples/MinecraftClone/Block/BlockBase.cs @@ -57,6 +57,6 @@ private void AssignProperties(GameObject cube, string name) Name = name; Material = cube.Material; - Mesh = cube.Mesh; + Meshes = cube.Meshes; } } diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index 12ae347..ce99a91 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -133,6 +133,7 @@ private void InitializeWorld() InitializeLights(); InitializeChunks(); + // TODO: Does not work yet. // var torus = MeshService.Instance.LoadMesh("torus", @"C:\Users\antti\Documents\Untitled2.obj"); // var go = new GameObject(); // go.Meshes.Add(torus.First()); From f3090984ebcc8835b922825a446168acd77876ae Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sun, 6 Apr 2025 21:16:09 +0300 Subject: [PATCH 35/92] Pop stash --- Core/Entities/Lights/DirectionalLight.cs | 6 +- Core/Entities/Lights/PointLight.cs | 12 ++-- Core/Entities/Lights/SpotLight.cs | 8 +-- Core/Renderers/RenderFlags.cs | 14 ++--- Core/Renderers/Renderer.cs | 1 + Core/Renderers/TextRenderer.cs | 3 +- Core/Renderers/UIRenderer.cs | 8 ++- Core/Scenes/SceneNode.cs | 1 + Core/Windowing/SilkWindow.cs | 75 +++++++++++++++++------- 9 files changed, 82 insertions(+), 46 deletions(-) diff --git a/Core/Entities/Lights/DirectionalLight.cs b/Core/Entities/Lights/DirectionalLight.cs index b5d0367..432f980 100644 --- a/Core/Entities/Lights/DirectionalLight.cs +++ b/Core/Entities/Lights/DirectionalLight.cs @@ -1,8 +1,8 @@ -using SharpEngine.Core.Entities.Properties; +using SharpEngine.Core.Entities.Properties; using SharpEngine.Core.Entities.Views; using SharpEngine.Core.Extensions; using SharpEngine.Core.Shaders; - +using SharpEngine.Core.Windowing; using System.Numerics; using System.Threading.Tasks; @@ -30,7 +30,7 @@ public DirectionalLight() } /// - public override Task Render(CameraView camera, Windowing.Window window) + public override Task Render(CameraView camera, Window window) { Material.Shader.SetVector3("dirLight.direction", Direction); Material.Shader.SetVector3("dirLight.ambient", Ambient); diff --git a/Core/Entities/Lights/PointLight.cs b/Core/Entities/Lights/PointLight.cs index 4ce5537..970d32b 100644 --- a/Core/Entities/Lights/PointLight.cs +++ b/Core/Entities/Lights/PointLight.cs @@ -1,7 +1,7 @@ -using SharpEngine.Core.Entities.Views; +using SharpEngine.Core.Entities.Views; using SharpEngine.Core.Extensions; using SharpEngine.Core.Shaders; - +using SharpEngine.Core.Windowing; using System.Numerics; using System.Threading.Tasks; @@ -52,9 +52,9 @@ public PointLight(Vector3 position, int index) public float Quadratic { get; set; } /// - public override Task Render(CameraView camera, Windowing.Window window) + public override Task Render(CameraView camera, Window window) { - Material.Shader.SetVector3($"pointLights[{_index}].position", (System.Numerics.Vector3)Transform.Position); + Material.Shader.SetVector3($"pointLights[{_index}].position", (Vector3)Transform.Position); Material.Shader.SetVector3($"pointLights[{_index}].ambient", Ambient); Material.Shader.SetVector3($"pointLights[{_index}].diffuse", Diffuse); Material.Shader.SetVector3($"pointLights[{_index}].specular", Specular); @@ -62,8 +62,8 @@ public override Task Render(CameraView camera, Windowing.Window window) Material.Shader.SetFloat($"pointLights[{_index}].linear", Linear); Material.Shader.SetFloat($"pointLights[{_index}].quadratic", Quadratic); - var lampMatrix = Matrix4x4.CreateScale((System.Numerics.Vector3)Transform.Scale); - lampMatrix *= Matrix4x4.CreateTranslation((System.Numerics.Vector3)Transform.Position); + var lampMatrix = Matrix4x4.CreateScale((Vector3)Transform.Scale); + lampMatrix *= Matrix4x4.CreateTranslation((Vector3)Transform.Position); LampShader.Shader?.SetMatrix4(ShaderAttributes.Model, lampMatrix); diff --git a/Core/Entities/Lights/SpotLight.cs b/Core/Entities/Lights/SpotLight.cs index 085d382..b2ef9c9 100644 --- a/Core/Entities/Lights/SpotLight.cs +++ b/Core/Entities/Lights/SpotLight.cs @@ -1,7 +1,7 @@ -using SharpEngine.Core.Entities.Views; +using SharpEngine.Core.Entities.Views; using SharpEngine.Core.Extensions; using SharpEngine.Core.Shaders; - +using SharpEngine.Core.Windowing; using System.Numerics; using System.Threading.Tasks; @@ -58,9 +58,9 @@ public SpotLight() public float Quadratic { get; set; } /// - public override Task Render(CameraView camera, Windowing.Window window) + public override Task Render(CameraView camera, Window window) { - Material.Shader.SetVector3("spotLight.position", (System.Numerics.Vector3)Transform.Position); + Material.Shader.SetVector3("spotLight.position", (Vector3)Transform.Position); Material.Shader.SetVector3("spotLight.direction", Direction); Material.Shader.SetVector3("spotLight.ambient", Ambient); Material.Shader.SetVector3("spotLight.diffuse", Diffuse); diff --git a/Core/Renderers/RenderFlags.cs b/Core/Renderers/RenderFlags.cs index 2e208a2..ac45eb1 100644 --- a/Core/Renderers/RenderFlags.cs +++ b/Core/Renderers/RenderFlags.cs @@ -14,14 +14,12 @@ public enum RenderFlags /// All the vertices will for the mesh will be rendered. Renderer3D = 1, - /// - /// The front face of the mesh will be rendered. - /// + /// The front face of the mesh will be rendered. UIRenderer = 2, - /// - /// Enables all renderers. - /// - All = 3, - Text = 4 + /// Text components will be rendered. + Text = 3, + + /// Enables all renderers. + All = 4, } diff --git a/Core/Renderers/Renderer.cs b/Core/Renderers/Renderer.cs index 62a889f..3768c84 100644 --- a/Core/Renderers/Renderer.cs +++ b/Core/Renderers/Renderer.cs @@ -35,6 +35,7 @@ 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) diff --git a/Core/Renderers/TextRenderer.cs b/Core/Renderers/TextRenderer.cs index e8bef69..5787fc5 100644 --- a/Core/Renderers/TextRenderer.cs +++ b/Core/Renderers/TextRenderer.cs @@ -1,7 +1,8 @@ -using SharpEngine.Core.Entities.Views; +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; diff --git a/Core/Renderers/UIRenderer.cs b/Core/Renderers/UIRenderer.cs index 67d3166..6c0e29e 100644 --- a/Core/Renderers/UIRenderer.cs +++ b/Core/Renderers/UIRenderer.cs @@ -1,9 +1,10 @@ -using SharpEngine.Core.Entities.UI; +using SharpEngine.Core.Entities.UI; 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; @@ -38,6 +39,9 @@ public UIRenderer(CameraView camera, Window window, ISettings settings, Scene sc /// public override Task Render() { + if (_uiShader.Shader is null) + return Task.CompletedTask; + try { Window.GL.Enable(EnableCap.DepthTest); @@ -47,7 +51,7 @@ public override Task Render() Window.GL.Disable(EnableCap.CullFace); // _camera.SetShaderUniforms(_uiShader.Shader!); - _uiShader.Shader.Use(); + _uiShader.Shader?.Use(); var uiElementRenderTasks = _scene.IterateAsync(_scene.UIElements, elem => elem.Render(_camera, _window)); diff --git a/Core/Scenes/SceneNode.cs b/Core/Scenes/SceneNode.cs index 89f25a3..13b3526 100644 --- a/Core/Scenes/SceneNode.cs +++ b/Core/Scenes/SceneNode.cs @@ -2,6 +2,7 @@ using SharpEngine.Core.Entities.Views; using SharpEngine.Core.Numerics; using SharpEngine.Core.Windowing; + using System.Collections.Generic; using System.Threading.Tasks; diff --git a/Core/Windowing/SilkWindow.cs b/Core/Windowing/SilkWindow.cs index aacfd26..3cae2f5 100644 --- a/Core/Windowing/SilkWindow.cs +++ b/Core/Windowing/SilkWindow.cs @@ -1,4 +1,4 @@ -using Silk.NET.Core; +using Silk.NET.Core; using Silk.NET.Core.Contexts; using Silk.NET.Input; using Silk.NET.Maths; @@ -22,10 +22,14 @@ namespace SharpEngine.Core.Windowing; public abstract class SilkWindow : IWindow { /// - public virtual IWindowHost? Parent { get; } + public virtual IWindowHost? Parent => CurrentWindow.Parent; /// - public IMonitor? Monitor { get; set; } + public IMonitor? Monitor + { + get => CurrentWindow.Monitor; + set => CurrentWindow.Monitor = value; + } /// public bool IsClosing @@ -69,7 +73,11 @@ public string Title } /// - public WindowState WindowState { get; set; } + public WindowState WindowState + { + get => CurrentWindow.WindowState; + set => CurrentWindow.WindowState = value; + } /// public WindowBorder WindowBorder @@ -107,25 +115,49 @@ public bool TopMost public bool IsInitialized => CurrentWindow.IsInitialized; /// - public bool ShouldSwapAutomatically { get; set; } + public bool ShouldSwapAutomatically + { + get => CurrentWindow.ShouldSwapAutomatically; + set => CurrentWindow.ShouldSwapAutomatically = value; + } /// - public bool IsEventDriven { get; set; } - + public bool IsEventDriven + { + get => CurrentWindow.ShouldSwapAutomatically; + set => CurrentWindow.ShouldSwapAutomatically = value; + } + /// - public bool IsContextControlDisabled { get; set; } + public bool IsContextControlDisabled + { + get => CurrentWindow.ShouldSwapAutomatically; + set => CurrentWindow.ShouldSwapAutomatically = value; + } /// - public double FramesPerSecond { get; set; } - + public double FramesPerSecond + { + get => CurrentWindow.FramesPerSecond; + set => CurrentWindow.FramesPerSecond = value; + } + /// - public double UpdatesPerSecond { get; set; } + public double UpdatesPerSecond + { + get => CurrentWindow.UpdatesPerSecond; + set => CurrentWindow.UpdatesPerSecond = value; + } /// - public GraphicsAPI API { get; } + public GraphicsAPI API => CurrentWindow.API; /// - public bool VSync { get; set; } + public bool VSync + { + get => CurrentWindow.ShouldSwapAutomatically; + set => CurrentWindow.ShouldSwapAutomatically = value; + } /// public VideoMode VideoMode => CurrentWindow.VideoMode; @@ -183,7 +215,7 @@ public bool TopMost public event Action? Render; /// Raised after the scene has been rendered. - public event Action? OnAfterRender; + public event Action? OnAfterRender; /// An event executed when the window has loaded. public event Action? OnLoaded; @@ -249,16 +281,16 @@ public void Dispose() public virtual void Initialize() => CurrentWindow.Initialize(); /// - public virtual object Invoke(Delegate d, params object[] args) => new(); + public virtual object Invoke(Delegate d, params object[] args) => CurrentWindow.Invoke(d, args); /// - public virtual Vector2D PointToClient(Vector2D point) => throw new NotImplementedException(); + public virtual Vector2D PointToClient(Vector2D point) => CurrentWindow.PointToClient(point); /// - public virtual Vector2D PointToFramebuffer(Vector2D point) => throw new NotImplementedException(); + public virtual Vector2D PointToFramebuffer(Vector2D point) => CurrentWindow.PointToFramebuffer(point); /// - public virtual Vector2D PointToScreen(Vector2D point) => throw new NotImplementedException(); + public virtual Vector2D PointToScreen(Vector2D point) => CurrentWindow.PointToScreen(point); /// public virtual void Reset() => CurrentWindow.Reset(); @@ -303,16 +335,15 @@ public virtual void OnLoad() /// /// Handles operations needed to be executed after the renderers are finished. /// - /// Time since the last frame. - protected virtual void AfterRender(Frame frame) => OnAfterRender?.Invoke(frame.FrameTime); + /// Contains information about the previous frame. + protected virtual void AfterRender(Frame frame) => OnAfterRender?.Invoke(frame); /// /// Handles operations needed to be executed before the renderers are executed. /// - /// Time since the last frame. + /// Contains information about the previous frame. protected virtual void PreRender(Frame frame) { } - // TODO: Scene unsaved changes warning. /// /// Handles closing the application. /// From a0c2105c2c0d0e3dcc480233d1a8d81a9846624c Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Tue, 8 Apr 2025 20:48:01 +0300 Subject: [PATCH 36/92] #26 Fix build --- Core/Entities/UI/UIElement.cs | 8 ++++++++ Examples/MinecraftClone/Minecraft.cs | 2 +- Examples/MinecraftClone/Program.cs | 4 ++-- Examples/Minimal/Program.cs | 6 ++---- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Core/Entities/UI/UIElement.cs b/Core/Entities/UI/UIElement.cs index 2bbf712..85596c4 100644 --- a/Core/Entities/UI/UIElement.cs +++ b/Core/Entities/UI/UIElement.cs @@ -37,6 +37,12 @@ public UIElement(string name) : base(name) private readonly UIShader _uiShader = new(); + /// Gets or sets the width of the ui element. + public float Width { get; set; } + + /// Gets or sets the height of the ui element. + public float Height { get; set; } + /// Gets or sets the mesh of the UI element. public Mesh Mesh { get; set; } @@ -89,6 +95,8 @@ public override Task Render(CameraView camera, Window window) 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)); diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index ce99a91..3b3bfeb 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -71,7 +71,7 @@ public override void Initialize() // TODO: Fix UI renderer _uiElem = new UIElement("uiElement"); - //_scene.UIElements.Add(_uiElem); + _scene.UIElements.Add(_uiElem); //var uiElem2 = new UIElement("uiElement"); //uiElem2.Transform.Scale = new SharpEngine.Core.Numerics.Vector2(0.2f, 0.2f); diff --git a/Examples/MinecraftClone/Program.cs b/Examples/MinecraftClone/Program.cs index 0c5de89..bf3e6a3 100644 --- a/Examples/MinecraftClone/Program.cs +++ b/Examples/MinecraftClone/Program.cs @@ -19,14 +19,14 @@ private static void Main() Scene scene = new Scene(); Minecraft game = new Minecraft(scene, gameSettings); - using var window = new SharpEngine.Core.Windowing.Window(game.Camera, scene, game.Camera.Settings); + 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 += deltaTime => game.OnAfterRender(new Frame(deltaTime)); + window.OnAfterRender += frame => game.OnAfterRender(frame); // TODO: This needs to be streamlined. game.Window = window; diff --git a/Examples/Minimal/Program.cs b/Examples/Minimal/Program.cs index dd6f183..9751459 100644 --- a/Examples/Minimal/Program.cs +++ b/Examples/Minimal/Program.cs @@ -1,8 +1,6 @@ using SharpEngine.Core.Interfaces; using SharpEngine.Core.Scenes; - -using Silk.NET.Maths; -using Silk.NET.Windowing; +using SharpEngine.Core.Windowing; namespace Minimal; @@ -19,7 +17,7 @@ public static void Main(string[] _) var game = new Minimal(new DefaultSettings()); var scene = new Scene(); - using var window = new SharpEngine.Core.Windowing.Window(game.Camera, scene, game.Camera.Settings); + using var window = new Window(game.Camera, scene, game.Camera.Settings); window.Run(); } } From 4f76569a9e3fe30862864d4d3dba2708b37f72e0 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Tue, 8 Apr 2025 21:30:37 +0300 Subject: [PATCH 37/92] #26 Fix flags --- Core/Renderers/RenderFlags.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/Renderers/RenderFlags.cs b/Core/Renderers/RenderFlags.cs index ac45eb1..005999b 100644 --- a/Core/Renderers/RenderFlags.cs +++ b/Core/Renderers/RenderFlags.cs @@ -18,8 +18,8 @@ public enum RenderFlags UIRenderer = 2, /// Text components will be rendered. - Text = 3, + Text = 4, /// Enables all renderers. - All = 4, + All = 7, } From 48652aa255676e2ebc41444c2cc7fe6d16aef488 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Tue, 8 Apr 2025 21:37:43 +0300 Subject: [PATCH 38/92] #26 Use width and height --- Core/Entities/UI/UIElement.cs | 4 ++-- Core/Shaders/uiShader.vert | 18 ++++++++++++++---- Examples/MinecraftClone/Minecraft.cs | 12 ++++++++++++ 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/Core/Entities/UI/UIElement.cs b/Core/Entities/UI/UIElement.cs index 85596c4..068a40f 100644 --- a/Core/Entities/UI/UIElement.cs +++ b/Core/Entities/UI/UIElement.cs @@ -38,10 +38,10 @@ public UIElement(string name) : base(name) private readonly UIShader _uiShader = new(); /// Gets or sets the width of the ui element. - public float Width { get; set; } + public float Width { get; set; } = 10; /// Gets or sets the height of the ui element. - public float Height { get; set; } + public float Height { get; set; } = 10; /// Gets or sets the mesh of the UI element. public Mesh Mesh { get; set; } diff --git a/Core/Shaders/uiShader.vert b/Core/Shaders/uiShader.vert index 959393c..2967764 100644 --- a/Core/Shaders/uiShader.vert +++ b/Core/Shaders/uiShader.vert @@ -4,6 +4,9 @@ layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aNormal; layout (location = 2) in vec2 aTexCoords; +uniform float width; +uniform float height; + uniform vec2 position; uniform float rotation; uniform vec2 screenSize; @@ -30,14 +33,21 @@ void main() 0.0, 0.0, 0.0, 1.0 ); + // Scale the vertex position using width and height + vec3 scaledPos = vec3( + aPos.x * width * reciprScaleOnscreen, + aPos.y * height * reciprScaleOnscreen, + aPos.z + ); + // Calculate the model-view-projection matrix using the orthographic projection matrix mat4 mvp = orthoMatrix * rotationMatrix * model; - // Apply the MVP matrix to the vertex position with scaling and aspect ratio + // Apply the MVP matrix to the scaled vertex position with aspect ratio gl_Position = mvp * vec4( - (aPos.x + (position.x * reciprScaleOnscreen)) * aspectRatio, - aPos.y + (position.y * reciprScaleOnscreen), - aPos.z, + (scaledPos.x + (position.x * reciprScaleOnscreen)) * aspectRatio, + scaledPos.y + (position.y * reciprScaleOnscreen), + scaledPos.z, 1 ); diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index 3b3bfeb..036d8c7 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -105,6 +105,9 @@ public void OnAfterRender(Frame frame) var rotation = _uiElem.Transform.Rotation.Angle; + var height = _uiElem.Height; + var width = _uiElem.Width; + ImGui.Begin("Debug"); ImGui.Text($"FPS: {frame.FrameRate}"); ImGui.Text($"Camera position: {Camera.Position}"); @@ -121,11 +124,20 @@ public void OnAfterRender(Frame frame) ImGui.Text($"UI Element scale: {_uiElem.Transform.Scale}"); ImGui.SliderFloat("rotation", ref rotation, 0, 360); + ImGui.Text($"UI Element width: {_uiElem.Width}"); + ImGui.SliderFloat("width", ref width, 0, 100); + + ImGui.Text($"UI Element height: {_uiElem.Height}"); + ImGui.SliderFloat("height", ref height, 0, 100); + ImGui.End(); _uiElem.Transform.Position = new SharpEngine.Core.Numerics.Vector2(x, y); _uiElem.Transform.Scale = new SharpEngine.Core.Numerics.Vector2(sx, sy); _uiElem.Transform.Rotation.Angle = rotation; + + _uiElem.Height = height; + _uiElem.Width = width; } private void InitializeWorld() From 924dbddeefd0d150f57ac14948286718837a9045 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Wed, 9 Apr 2025 21:52:35 +0300 Subject: [PATCH 39/92] #2 Temp --- Core/Entities/GameObject.cs | 8 +++++--- Core/Entities/Properties/Meshes/MeshService.cs | 14 +++++++++++--- Core/Primitives/PrimitiveFactory.cs | 10 +++++++--- Examples/MinecraftClone/Minecraft.cs | 3 +++ 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/Core/Entities/GameObject.cs b/Core/Entities/GameObject.cs index c228615..5ab18e8 100644 --- a/Core/Entities/GameObject.cs +++ b/Core/Entities/GameObject.cs @@ -120,6 +120,8 @@ public void InitializeBuffers(Mesh mesh) /// public override Task Render(CameraView camera, Window window) { + Bind(); + Material.DiffuseMap.Use(TextureUnit.Texture0); Material.Shader.SetInt("material.diffuse", Material.diffuseUnit); @@ -139,10 +141,10 @@ public override Task Render(CameraView camera, Window window) Material.Shader.SetMatrix4(ShaderAttributes.Model, Transform.ModelMatrix); - Window.GL.DrawArrays(PrimitiveType.Triangles, 0, 36); + // Window.GL.DrawArrays(PrimitiveType.Triangles, 0, 36); - // foreach (var mesh in Meshes) - // Window.GL.DrawElements(PrimitiveType.Triangles, (uint)mesh.Indices.Length, DrawElementsType.UnsignedInt, []); + foreach (var mesh in Meshes) + Window.GL.DrawElements(PrimitiveType.Triangles, (uint)mesh.Indices.Length, DrawElementsType.UnsignedInt, []); return Task.CompletedTask; } diff --git a/Core/Entities/Properties/Meshes/MeshService.cs b/Core/Entities/Properties/Meshes/MeshService.cs index 9b34f87..1ef1c98 100644 --- a/Core/Entities/Properties/Meshes/MeshService.cs +++ b/Core/Entities/Properties/Meshes/MeshService.cs @@ -104,10 +104,18 @@ Mesh LoadMeshIntoBuffer() textureCoordinates.AddRange(GetData(parts)); break; case ObjMeshData.FACE: // OBJ faces are defined as a list of vertex indices - foreach (var part in parts.Skip(1)) + var faceVertices = parts.Skip(1).ToArray(); + for (int i = 1; i < faceVertices.Length - 1; i++) { - var indicesParts = part.Split('/'); - indices.Add(uint.Parse(indicesParts[0]) - 1); // OBJ indices are 1-based + // Triangle 1: Vertex 1, Vertex i, Vertex i+1 + var indicesParts1 = faceVertices[0].Split('/'); + var indicesParts2 = faceVertices[i].Split('/'); + var indicesParts3 = faceVertices[i + 1].Split('/'); + + // OBJ indices are 1-based so we need to subtract 1 to convert to 0-based + indices.Add(uint.Parse(indicesParts1[0]) - 1); + indices.Add(uint.Parse(indicesParts2[0]) - 1); + indices.Add(uint.Parse(indicesParts3[0]) - 1); } break; case ObjMeshData.OBJECT: diff --git a/Core/Primitives/PrimitiveFactory.cs b/Core/Primitives/PrimitiveFactory.cs index 8dd935e..cbcd671 100644 --- a/Core/Primitives/PrimitiveFactory.cs +++ b/Core/Primitives/PrimitiveFactory.cs @@ -1,6 +1,5 @@ using SharpEngine.Core.Entities; using SharpEngine.Core.Entities.Properties; -using SharpEngine.Core.Extensions; using System; using System.Numerics; @@ -30,9 +29,10 @@ public static GameObject Create(PrimitiveType primitiveType, Vector3 position) /// A new game object. /// Thrown when the specified primitive type does not exist. public static GameObject Create(PrimitiveType primitiveType, Vector3 position, string diffuseMapFile, string? specularMapFile = null, string? vertShaderFile = null, string? fragShaderFile = null) - => new(diffuseMapFile, specularMapFile, vertShaderFile ?? _Resources.Default.VertexShader, fragShaderFile ?? _Resources.Default.FragmentShader) + { + var primitive = new GameObject(diffuseMapFile, specularMapFile, vertShaderFile ?? _Resources.Default.VertexShader, fragShaderFile ?? _Resources.Default.FragmentShader) { - Transform = new Transform { Position = (SharpEngine.Core.Numerics.Vector3)position }, + Transform = new Transform { Position = (Numerics.Vector3)position }, Meshes = primitiveType switch { PrimitiveType.Cube => [Cube.Mesh], @@ -41,4 +41,8 @@ public static GameObject Create(PrimitiveType primitiveType, Vector3 position, s } }; + primitive.Initialize(); + return primitive; + } + } diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index 036d8c7..b1d9577 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -149,6 +149,9 @@ private void InitializeWorld() // var torus = MeshService.Instance.LoadMesh("torus", @"C:\Users\antti\Documents\Untitled2.obj"); // var go = new GameObject(); // go.Meshes.Add(torus.First()); + + // go.Initialize(); + // _scene.Root.AddChild(go); } private void InitializeLights() From 03a43617e3745199660c9168cdc36f10665638ea Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Wed, 9 Apr 2025 22:19:11 +0300 Subject: [PATCH 40/92] #2 loop working --- Core/Entities/GameObject.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Core/Entities/GameObject.cs b/Core/Entities/GameObject.cs index 5ab18e8..7905038 100644 --- a/Core/Entities/GameObject.cs +++ b/Core/Entities/GameObject.cs @@ -120,7 +120,7 @@ public void InitializeBuffers(Mesh mesh) /// public override Task Render(CameraView camera, Window window) { - Bind(); + // Bind(); Material.DiffuseMap.Use(TextureUnit.Texture0); Material.Shader.SetInt("material.diffuse", Material.diffuseUnit); @@ -141,10 +141,9 @@ public override Task Render(CameraView camera, Window window) Material.Shader.SetMatrix4(ShaderAttributes.Model, Transform.ModelMatrix); - // Window.GL.DrawArrays(PrimitiveType.Triangles, 0, 36); - foreach (var mesh in Meshes) - Window.GL.DrawElements(PrimitiveType.Triangles, (uint)mesh.Indices.Length, DrawElementsType.UnsignedInt, []); + Window.GL.DrawArrays(PrimitiveType.Triangles, 0, (uint)mesh.Vertices.Length); + // Window.GL.DrawElements(PrimitiveType.Triangles, (uint)mesh.Indices.Length, DrawElementsType.UnsignedInt, []); return Task.CompletedTask; } From a15ba0d5dd5292340c3c09b3b82b16a9d77960c8 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Thu, 10 Apr 2025 00:21:28 +0300 Subject: [PATCH 41/92] #2 Refactoring Introduced obj loader, abstracted some functionality into separate projects, added placeholders for test projects --- Directory.Build.props | 5 + Editor/SharpEngine.Editor.csproj | 2 +- Examples/MinecraftClone/Minecraft.cs | 46 +++-- Examples/MinecraftClone/Minecraft.csproj | 4 +- Examples/Minimal/Minimal.csproj | 3 +- .../MultipleWindows/MultipleWindows.csproj | 2 +- ObjLoader/Data/DataStore/DataStore.cs | 68 +++++++ ObjLoader/Data/DataStore/IDataStore.cs | 15 ++ ObjLoader/Data/DataStore/IElementGroup.cs | 7 + ObjLoader/Loaders/IMaterialLibraryLoader.cs | 9 + .../Loaders/IMaterialLibraryLoaderFacade.cs | 7 + ObjLoader/Loaders/IObjLoader.cs | 9 + ObjLoader/Loaders/IObjLoaderFactory.cs | 8 + ObjLoader/Loaders/LoadResult.cs | 16 ++ ObjLoader/Loaders/LoaderBase.cs | 35 ++++ ObjLoader/Loaders/MaterialLibraryLoader.cs | 91 +++++++++ .../Loaders/MaterialLibraryLoaderFacade.cs | 22 +++ ObjLoader/Loaders/MaterialStreamProvider.cs | 20 ++ ObjLoader/Loaders/ObjLoader.cs | 78 ++++++++ ObjLoader/Loaders/ObjLoaderFactory.cs | 35 ++++ ObjLoader/ObjLoader.csproj | 11 ++ ObjLoader/TypeParsers/FaceParser.cs | 57 ++++++ ObjLoader/TypeParsers/GroupParser.cs | 19 ++ .../TypeParsers/Interfaces/IFaceParser.cs | 6 + .../TypeParsers/Interfaces/IGroupParser.cs | 6 + .../Interfaces/IMaterialLibraryParser.cs | 6 + .../TypeParsers/Interfaces/INormalParser.cs | 6 + .../TypeParsers/Interfaces/ITextureParser.cs | 6 + .../TypeParsers/Interfaces/ITypeParser.cs | 8 + .../Interfaces/IUseMaterialParser.cs | 6 + .../TypeParsers/Interfaces/IVertexParser.cs | 6 + .../TypeParsers/MaterialLibraryParser.cs | 19 ++ ObjLoader/TypeParsers/NormalParser.cs | 31 +++ ObjLoader/TypeParsers/TextureParser.cs | 30 +++ ObjLoader/TypeParsers/TypeParserBase.cs | 14 ++ ObjLoader/TypeParsers/UseMaterialParser.cs | 19 ++ ObjLoader/TypeParsers/VertexParser.cs | 32 +++ SharpEngine.Core.Components/IComponent.cs | 13 ++ .../ObjLoader/DataStore/IFaceGroup.cs | 9 + .../ObjLoader/DataStore/IGroupDataStore.cs | 7 + .../ObjLoader/DataStore/IMaterialLibrary.cs | 9 + .../ObjLoader/DataStore/INormalDataStore.cs | 9 + .../ObjLoader/DataStore/ITextureDataStore.cs | 9 + .../ObjLoader/DataStore/IVertexDataStore.cs | 9 + .../Properties/BoundingBox.cs | 0 .../Properties/ITransform.cs | 0 .../Properties/Material.cs | 35 ++++ .../Properties/Meshes/Mesh.cs | 0 .../Properties/Meshes/MeshData/Face.cs | 38 ++++ .../Properties/Meshes/MeshData/Group.cs | 25 +++ .../Meshes/MeshData/VertexData/Normal.cs | 16 ++ .../Meshes/MeshData/VertexData/Texture.cs | 14 ++ .../Meshes/MeshData/VertexData/Vertex.cs | 16 ++ .../Properties/Meshes/MeshExtensions.cs | 0 .../Properties/Meshes/ObjMeshData.cs | 0 .../Properties/Meshes/VertexData.cs | 0 .../Properties/Quaternion.cs | 0 .../Properties/Transform.cs | 0 .../Properties/Transform2D.cs | 0 .../SharpEngine.Core.Components.csproj | 22 +++ .../HashCodeHelper.cs | 0 .../IVector.cs | 0 .../JitIntrinsicAttribute.cs | 0 .../SharpEngine.Core.Numerics.csproj | 14 ++ .../Vector2.cs | 0 .../Vector2_Intrinsics.cs | 0 .../Vector3.cs | 0 .../Vector3_Intrinsics.cs | 0 .../Abstractions/IGame.cs | 0 .../Abstractions/IRenderable.cs | 0 .../Abstractions/ISettings.cs | 0 {Core => SharpEngine.Core}/Audio/Audio.cs | 0 .../Audio/AudioBuffer.cs | 0 .../Audio/AudioDevice.cs | 0 .../Audio/AudioFileExtensions.cs | 0 .../Audio/AudioPlayerBase.cs | 0 .../Audio/AudioProperties.cs | 0 .../Audio/AudioSource.cs | 0 {Core => SharpEngine.Core}/Audio/WavData.cs | 0 {Core => SharpEngine.Core}/Audio/WavPlayer.cs | 0 {Core => SharpEngine.Core}/Debug.cs | 0 .../Entities/BezierCurve.cs | 0 .../Entities/GameObject.cs | 0 .../Entities/Lights/DirectionalLight.cs | 0 .../Entities/Lights/Light.cs | 0 .../Entities/Lights/PointLight.cs | 0 .../Entities/Lights/SpotLight.cs | 0 .../Entities}/Material.cs | 0 .../Entities}/MeshService.cs | 0 .../Entities/UI/Layouts/FlexLayout.cs | 0 .../Entities/UI/Layouts/GridLayout.cs | 0 .../Entities/UI/Layouts/LayoutBase.cs | 0 .../Entities/UI/UIElement.cs | 0 .../Entities/Views/CameraView.cs | 0 .../Views/Settings/DefaultViewSettings.cs | 0 .../Entities/Views/Settings/IViewSettings.cs | 0 .../Entities/Views/Settings/ViewSettings.cs | 0 .../Entities/Views/View.cs | 0 .../Enums/MouseWheelScrollDirection.cs | 0 .../Extensions/CollectionExtensions.cs | 0 .../Extensions/PathExtensions.cs | 0 {Core => SharpEngine.Core}/Primitives/Cube.cs | 0 .../Primitives/Plane.cs | 0 .../Primitives/PrimitiveFactory.cs | 0 .../Primitives/PrimitiveType.cs | 0 {Core => SharpEngine.Core}/Ray.cs | 0 .../Renderers/RenderFlags.cs | 0 .../Renderers/Renderer.cs | 0 .../Renderers/RendererBase.cs | 0 .../Renderers/TextRenderer.cs | 0 .../Renderers/UIRenderer.cs | 0 {Core => SharpEngine.Core}/Scenes/Scene.cs | 0 .../Scenes/SceneNode.cs | 0 .../Shaders/LampShader.cs | 0 .../Shaders/Light/DirectionalLight.glsl | 0 .../Shaders/Light/PointLight.glsl | 0 .../Shaders/Light/SpotLight.glsl | 0 .../Shaders/LightingShader.cs | 0 .../Shaders/Material.glsl | 0 {Core => SharpEngine.Core}/Shaders/Shader.cs | 0 .../Shaders/ShaderAttributes.cs | 0 .../Shaders/ShaderBase.cs | 0 .../Shaders/ShaderService.cs | 0 .../Shaders/UIShader.cs | 0 .../Shaders/lighting.frag | 0 .../Shaders/shader.frag | 0 .../Shaders/shader.vert | 0 .../Shaders/uiShader.frag | 0 .../Shaders/uiShader.vert | 0 .../SharpEngine.Core.csproj | 13 +- .../Textures/DefaultTextures/debug.jpg | Bin .../Textures/Texture.cs | 0 .../Textures/TextureService.cs | 0 {Core => SharpEngine.Core}/Windowing/Frame.cs | 0 .../Windowing/SilkWindow.cs | 0 .../Windowing/Window.cs | 0 .../_Resources/Default.cs | 0 .../_Resources/icon.png | Bin SharpEngine.Shared.Net8/Class1.cs | 6 + .../SharpEngine.Shared.Net8.csproj | 9 + .../Attributes/InspectorAttribute.cs | 0 .../Extensions/StringExtensions.cs | 28 +++ {Core => SharpEngine.Shared}/Math.cs | 0 SharpEngine.sln | 81 +++++++- .../Loaders/MaterialLibraryLoaderTests.cs | 146 ++++++++++++++ .../ObjLoader.Test/Loaders/ObjLoaderTests.cs | 185 ++++++++++++++++++ Tests/ObjLoader.Test/ObjLoader.Tests.csproj | 14 ++ .../TypeParsers/FaceParserTests.cs | 147 ++++++++++++++ .../TypeParsers/GroupParserTests.cs | 61 ++++++ .../TypeParsers/MaterialLibraryParserTests.cs | 58 ++++++ .../TypeParsers/NormalParserTests.cs | 68 +++++++ .../TypeParsers/TextureParserTests.cs | 67 +++++++ .../TypeParsers/UseMaterialParserTests.cs | 59 ++++++ .../TypeParsers/VertexParserTests.cs | 69 +++++++ Tests/SharpEngine.Core.Tests/Class1.cs | 6 + .../SharpEngine.Core.Tests.csproj | 9 + Tests/SharpEngine.Editor.Tests/Class1.cs | 6 + .../SharpEngine.Editor.Tests.csproj | 9 + Tests/SharpEngine.Shared.Tests/Class1.cs | 6 + .../SharpEngine.Shared.Tests.csproj | 9 + Tests/Test.Directory.Build.props | 6 + 161 files changed, 2036 insertions(+), 35 deletions(-) create mode 100644 ObjLoader/Data/DataStore/DataStore.cs create mode 100644 ObjLoader/Data/DataStore/IDataStore.cs create mode 100644 ObjLoader/Data/DataStore/IElementGroup.cs create mode 100644 ObjLoader/Loaders/IMaterialLibraryLoader.cs create mode 100644 ObjLoader/Loaders/IMaterialLibraryLoaderFacade.cs create mode 100644 ObjLoader/Loaders/IObjLoader.cs create mode 100644 ObjLoader/Loaders/IObjLoaderFactory.cs create mode 100644 ObjLoader/Loaders/LoadResult.cs create mode 100644 ObjLoader/Loaders/LoaderBase.cs create mode 100644 ObjLoader/Loaders/MaterialLibraryLoader.cs create mode 100644 ObjLoader/Loaders/MaterialLibraryLoaderFacade.cs create mode 100644 ObjLoader/Loaders/MaterialStreamProvider.cs create mode 100644 ObjLoader/Loaders/ObjLoader.cs create mode 100644 ObjLoader/Loaders/ObjLoaderFactory.cs create mode 100644 ObjLoader/ObjLoader.csproj create mode 100644 ObjLoader/TypeParsers/FaceParser.cs create mode 100644 ObjLoader/TypeParsers/GroupParser.cs create mode 100644 ObjLoader/TypeParsers/Interfaces/IFaceParser.cs create mode 100644 ObjLoader/TypeParsers/Interfaces/IGroupParser.cs create mode 100644 ObjLoader/TypeParsers/Interfaces/IMaterialLibraryParser.cs create mode 100644 ObjLoader/TypeParsers/Interfaces/INormalParser.cs create mode 100644 ObjLoader/TypeParsers/Interfaces/ITextureParser.cs create mode 100644 ObjLoader/TypeParsers/Interfaces/ITypeParser.cs create mode 100644 ObjLoader/TypeParsers/Interfaces/IUseMaterialParser.cs create mode 100644 ObjLoader/TypeParsers/Interfaces/IVertexParser.cs create mode 100644 ObjLoader/TypeParsers/MaterialLibraryParser.cs create mode 100644 ObjLoader/TypeParsers/NormalParser.cs create mode 100644 ObjLoader/TypeParsers/TextureParser.cs create mode 100644 ObjLoader/TypeParsers/TypeParserBase.cs create mode 100644 ObjLoader/TypeParsers/UseMaterialParser.cs create mode 100644 ObjLoader/TypeParsers/VertexParser.cs create mode 100644 SharpEngine.Core.Components/IComponent.cs create mode 100644 SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IFaceGroup.cs create mode 100644 SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IGroupDataStore.cs create mode 100644 SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IMaterialLibrary.cs create mode 100644 SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/INormalDataStore.cs create mode 100644 SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/ITextureDataStore.cs create mode 100644 SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IVertexDataStore.cs rename {Core/Entities => SharpEngine.Core.Components}/Properties/BoundingBox.cs (100%) rename {Core/Entities => SharpEngine.Core.Components}/Properties/ITransform.cs (100%) create mode 100644 SharpEngine.Core.Components/Properties/Material.cs rename {Core/Entities => SharpEngine.Core.Components}/Properties/Meshes/Mesh.cs (100%) create mode 100644 SharpEngine.Core.Components/Properties/Meshes/MeshData/Face.cs create mode 100644 SharpEngine.Core.Components/Properties/Meshes/MeshData/Group.cs create mode 100644 SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/Normal.cs create mode 100644 SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/Texture.cs create mode 100644 SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/Vertex.cs rename {Core/Entities => SharpEngine.Core.Components}/Properties/Meshes/MeshExtensions.cs (100%) rename {Core/Entities => SharpEngine.Core.Components}/Properties/Meshes/ObjMeshData.cs (100%) rename {Core/Entities => SharpEngine.Core.Components}/Properties/Meshes/VertexData.cs (100%) rename {Core/Entities => SharpEngine.Core.Components}/Properties/Quaternion.cs (100%) rename {Core/Entities => SharpEngine.Core.Components}/Properties/Transform.cs (100%) rename {Core/Entities => SharpEngine.Core.Components}/Properties/Transform2D.cs (100%) create mode 100644 SharpEngine.Core.Components/SharpEngine.Core.Components.csproj rename {Core/Numerics => SharpEngine.Core.Numerics}/HashCodeHelper.cs (100%) rename {Core/Numerics => SharpEngine.Core.Numerics}/IVector.cs (100%) rename {Core/Numerics => SharpEngine.Core.Numerics}/JitIntrinsicAttribute.cs (100%) create mode 100644 SharpEngine.Core.Numerics/SharpEngine.Core.Numerics.csproj rename {Core/Numerics => SharpEngine.Core.Numerics}/Vector2.cs (100%) rename {Core/Numerics => SharpEngine.Core.Numerics}/Vector2_Intrinsics.cs (100%) rename {Core/Numerics => SharpEngine.Core.Numerics}/Vector3.cs (100%) rename {Core/Numerics => SharpEngine.Core.Numerics}/Vector3_Intrinsics.cs (100%) rename {Core => SharpEngine.Core}/Abstractions/IGame.cs (100%) rename {Core => SharpEngine.Core}/Abstractions/IRenderable.cs (100%) rename {Core => SharpEngine.Core}/Abstractions/ISettings.cs (100%) rename {Core => SharpEngine.Core}/Audio/Audio.cs (100%) rename {Core => SharpEngine.Core}/Audio/AudioBuffer.cs (100%) rename {Core => SharpEngine.Core}/Audio/AudioDevice.cs (100%) rename {Core => SharpEngine.Core}/Audio/AudioFileExtensions.cs (100%) rename {Core => SharpEngine.Core}/Audio/AudioPlayerBase.cs (100%) rename {Core => SharpEngine.Core}/Audio/AudioProperties.cs (100%) rename {Core => SharpEngine.Core}/Audio/AudioSource.cs (100%) rename {Core => SharpEngine.Core}/Audio/WavData.cs (100%) rename {Core => SharpEngine.Core}/Audio/WavPlayer.cs (100%) rename {Core => SharpEngine.Core}/Debug.cs (100%) rename {Core => SharpEngine.Core}/Entities/BezierCurve.cs (100%) rename {Core => SharpEngine.Core}/Entities/GameObject.cs (100%) rename {Core => SharpEngine.Core}/Entities/Lights/DirectionalLight.cs (100%) rename {Core => SharpEngine.Core}/Entities/Lights/Light.cs (100%) rename {Core => SharpEngine.Core}/Entities/Lights/PointLight.cs (100%) rename {Core => SharpEngine.Core}/Entities/Lights/SpotLight.cs (100%) rename {Core/Entities/Properties => SharpEngine.Core/Entities}/Material.cs (100%) rename {Core/Entities/Properties/Meshes => SharpEngine.Core/Entities}/MeshService.cs (100%) rename {Core => SharpEngine.Core}/Entities/UI/Layouts/FlexLayout.cs (100%) rename {Core => SharpEngine.Core}/Entities/UI/Layouts/GridLayout.cs (100%) rename {Core => SharpEngine.Core}/Entities/UI/Layouts/LayoutBase.cs (100%) rename {Core => SharpEngine.Core}/Entities/UI/UIElement.cs (100%) rename {Core => SharpEngine.Core}/Entities/Views/CameraView.cs (100%) rename {Core => SharpEngine.Core}/Entities/Views/Settings/DefaultViewSettings.cs (100%) rename {Core => SharpEngine.Core}/Entities/Views/Settings/IViewSettings.cs (100%) rename {Core => SharpEngine.Core}/Entities/Views/Settings/ViewSettings.cs (100%) rename {Core => SharpEngine.Core}/Entities/Views/View.cs (100%) rename {Core => SharpEngine.Core}/Enums/MouseWheelScrollDirection.cs (100%) rename {Core => SharpEngine.Core}/Extensions/CollectionExtensions.cs (100%) rename {Core => SharpEngine.Core}/Extensions/PathExtensions.cs (100%) rename {Core => SharpEngine.Core}/Primitives/Cube.cs (100%) rename {Core => SharpEngine.Core}/Primitives/Plane.cs (100%) rename {Core => SharpEngine.Core}/Primitives/PrimitiveFactory.cs (100%) rename {Core => SharpEngine.Core}/Primitives/PrimitiveType.cs (100%) rename {Core => SharpEngine.Core}/Ray.cs (100%) rename {Core => SharpEngine.Core}/Renderers/RenderFlags.cs (100%) rename {Core => SharpEngine.Core}/Renderers/Renderer.cs (100%) rename {Core => SharpEngine.Core}/Renderers/RendererBase.cs (100%) rename {Core => SharpEngine.Core}/Renderers/TextRenderer.cs (100%) rename {Core => SharpEngine.Core}/Renderers/UIRenderer.cs (100%) rename {Core => SharpEngine.Core}/Scenes/Scene.cs (100%) rename {Core => SharpEngine.Core}/Scenes/SceneNode.cs (100%) rename {Core => SharpEngine.Core}/Shaders/LampShader.cs (100%) rename {Core => SharpEngine.Core}/Shaders/Light/DirectionalLight.glsl (100%) rename {Core => SharpEngine.Core}/Shaders/Light/PointLight.glsl (100%) rename {Core => SharpEngine.Core}/Shaders/Light/SpotLight.glsl (100%) rename {Core => SharpEngine.Core}/Shaders/LightingShader.cs (100%) rename {Core => SharpEngine.Core}/Shaders/Material.glsl (100%) rename {Core => SharpEngine.Core}/Shaders/Shader.cs (100%) rename {Core => SharpEngine.Core}/Shaders/ShaderAttributes.cs (100%) rename {Core => SharpEngine.Core}/Shaders/ShaderBase.cs (100%) rename {Core => SharpEngine.Core}/Shaders/ShaderService.cs (100%) rename {Core => SharpEngine.Core}/Shaders/UIShader.cs (100%) rename {Core => SharpEngine.Core}/Shaders/lighting.frag (100%) rename {Core => SharpEngine.Core}/Shaders/shader.frag (100%) rename {Core => SharpEngine.Core}/Shaders/shader.vert (100%) rename {Core => SharpEngine.Core}/Shaders/uiShader.frag (100%) rename {Core => SharpEngine.Core}/Shaders/uiShader.vert (100%) rename {Core => SharpEngine.Core}/SharpEngine.Core.csproj (88%) rename {Core => SharpEngine.Core}/Textures/DefaultTextures/debug.jpg (100%) rename {Core => SharpEngine.Core}/Textures/Texture.cs (100%) rename {Core => SharpEngine.Core}/Textures/TextureService.cs (100%) rename {Core => SharpEngine.Core}/Windowing/Frame.cs (100%) rename {Core => SharpEngine.Core}/Windowing/SilkWindow.cs (100%) rename {Core => SharpEngine.Core}/Windowing/Window.cs (100%) rename {Core => SharpEngine.Core}/_Resources/Default.cs (100%) rename {Core => SharpEngine.Core}/_Resources/icon.png (100%) create mode 100644 SharpEngine.Shared.Net8/Class1.cs create mode 100644 SharpEngine.Shared.Net8/SharpEngine.Shared.Net8.csproj rename {Core => SharpEngine.Shared}/Attributes/InspectorAttribute.cs (100%) create mode 100644 SharpEngine.Shared/Extensions/StringExtensions.cs rename {Core => SharpEngine.Shared}/Math.cs (100%) create mode 100644 Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs create mode 100644 Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs create mode 100644 Tests/ObjLoader.Test/ObjLoader.Tests.csproj create mode 100644 Tests/ObjLoader.Test/TypeParsers/FaceParserTests.cs create mode 100644 Tests/ObjLoader.Test/TypeParsers/GroupParserTests.cs create mode 100644 Tests/ObjLoader.Test/TypeParsers/MaterialLibraryParserTests.cs create mode 100644 Tests/ObjLoader.Test/TypeParsers/NormalParserTests.cs create mode 100644 Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs create mode 100644 Tests/ObjLoader.Test/TypeParsers/UseMaterialParserTests.cs create mode 100644 Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs create mode 100644 Tests/SharpEngine.Core.Tests/Class1.cs create mode 100644 Tests/SharpEngine.Core.Tests/SharpEngine.Core.Tests.csproj create mode 100644 Tests/SharpEngine.Editor.Tests/Class1.cs create mode 100644 Tests/SharpEngine.Editor.Tests/SharpEngine.Editor.Tests.csproj create mode 100644 Tests/SharpEngine.Shared.Tests/Class1.cs create mode 100644 Tests/SharpEngine.Shared.Tests/SharpEngine.Shared.Tests.csproj create mode 100644 Tests/Test.Directory.Build.props diff --git a/Directory.Build.props b/Directory.Build.props index ca5e202..b453701 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -23,6 +23,11 @@ True + + 2.22.0 + + + True diff --git a/Editor/SharpEngine.Editor.csproj b/Editor/SharpEngine.Editor.csproj index 2fc55d0..46b99e1 100644 --- a/Editor/SharpEngine.Editor.csproj +++ b/Editor/SharpEngine.Editor.csproj @@ -33,7 +33,7 @@ - + diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index b1d9577..0f47fa7 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -1,22 +1,22 @@ +using ImGuiNET; +using Minecraft.Block; +using ObjLoader.Loader.Loaders; 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.Entities; -using SharpEngine.Core.Entities.Lights; - -using Minecraft.Block; +using SharpEngine.Core.Windowing; using Silk.NET.Input; - using System; -using System.Numerics; -using SharpEngine.Core.Entities.UI; -using SharpEngine.Core.Windowing; -using SharpEngine.Core.Entities.UI.Layouts; -using SharpEngine.Core.Entities.Properties; -using ImGuiNET; -using SharpEngine.Core.Entities.Properties.Meshes; +using System.IO; using System.Linq; +using System.Numerics; namespace Minecraft; @@ -147,11 +147,27 @@ private void InitializeWorld() // TODO: Does not work yet. // var torus = MeshService.Instance.LoadMesh("torus", @"C:\Users\antti\Documents\Untitled2.obj"); - // var go = new GameObject(); + + // This should be simplified to something like this: + // new ObjLoaderFactory().Load(); + + var objLoaderFactory = new ObjLoaderFactory(); + var objLoader = objLoaderFactory.Create(); + + // TODO: There is a bug that an exception is thrown if no mtl file is not found. This should be just a warning. + var fileStream = new FileStream("Untitled2.obj", FileMode.Open); + var result = objLoader.Load(fileStream); + // var mesh = new Mesh() + // { + // Vertices = result.Vertices.ToArray(), + // }; + + var go = new GameObject(); // go.Meshes.Add(torus.First()); - // go.Initialize(); - // _scene.Root.AddChild(go); + go.Initialize(); + _scene.Root.AddChild(go); + } private void InitializeLights() diff --git a/Examples/MinecraftClone/Minecraft.csproj b/Examples/MinecraftClone/Minecraft.csproj index 89889c9..95af1dc 100644 --- a/Examples/MinecraftClone/Minecraft.csproj +++ b/Examples/MinecraftClone/Minecraft.csproj @@ -3,11 +3,11 @@ Exe AnyCPU;x64;x86 - Debug;Release;LauncherNonWindows - + + diff --git a/Examples/Minimal/Minimal.csproj b/Examples/Minimal/Minimal.csproj index 2821290..8bbdf5a 100644 --- a/Examples/Minimal/Minimal.csproj +++ b/Examples/Minimal/Minimal.csproj @@ -5,11 +5,10 @@ net8.0 enable enable - Debug;Release;LauncherNonWindows - + diff --git a/Examples/MultipleWindows/MultipleWindows.csproj b/Examples/MultipleWindows/MultipleWindows.csproj index c40ef83..e48ece3 100644 --- a/Examples/MultipleWindows/MultipleWindows.csproj +++ b/Examples/MultipleWindows/MultipleWindows.csproj @@ -15,7 +15,7 @@ - + diff --git a/ObjLoader/Data/DataStore/DataStore.cs b/ObjLoader/Data/DataStore/DataStore.cs new file mode 100644 index 0000000..745e75a --- /dev/null +++ b/ObjLoader/Data/DataStore/DataStore.cs @@ -0,0 +1,68 @@ +using ObjLoader.Loader.Common; +using ObjLoader.Loader.Data.Elements; + +using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; +using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; + +using System.Collections.Generic; +using System.Linq; + +namespace ObjLoader.Loader.Data.DataStore +{ + public class DataStore : IDataStore, IGroupDataStore, IVertexDataStore, ITextureDataStore, INormalDataStore, + IFaceGroup, IMaterialLibrary, IElementGroup + { + private Group _currentGroup; + + private readonly List _groups = []; + private readonly List _materials = []; + + private readonly List _vertices = []; + private readonly List _textures = []; + private readonly List _normals = []; + + public IList Vertices => _vertices; + + public IList Textures => _textures; + + public IList Normals => _normals; + + public IList Materials => _materials; + + public IList Groups => _groups; + + public void AddFace(Face face) + { + PushGroupIfNeeded(); + + _currentGroup.AddFace(face); + } + + public void PushGroup(string groupName) + { + _currentGroup = new Group(groupName); + _groups.Add(_currentGroup); + } + + private void PushGroupIfNeeded() + { + if (_currentGroup == null) + PushGroup("default"); + } + + public void AddVertex(Vertex vertex) => _vertices.Add(vertex); + + public void AddTexture(Texture texture) => _textures.Add(texture); + + public void AddNormal(Normal normal) => _normals.Add(normal); + + public void Push(Material material) => _materials.Add(material); + + public void SetMaterial(string materialName) + { + var material = _materials.SingleOrDefault(x => x.Name.EqualsOrdinalIgnoreCase(materialName)); + PushGroupIfNeeded(); + _currentGroup.Material = material; + } + } +} \ No newline at end of file diff --git a/ObjLoader/Data/DataStore/IDataStore.cs b/ObjLoader/Data/DataStore/IDataStore.cs new file mode 100644 index 0000000..271475a --- /dev/null +++ b/ObjLoader/Data/DataStore/IDataStore.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using ObjLoader.Loader.Data.Elements; +using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; + +namespace ObjLoader.Loader.Data.DataStore +{ + public interface IDataStore + { + IList Vertices { get; } + IList Textures { get; } + IList Normals { get; } + IList Materials { get; } + IList Groups { get; } + } +} \ No newline at end of file diff --git a/ObjLoader/Data/DataStore/IElementGroup.cs b/ObjLoader/Data/DataStore/IElementGroup.cs new file mode 100644 index 0000000..f828800 --- /dev/null +++ b/ObjLoader/Data/DataStore/IElementGroup.cs @@ -0,0 +1,7 @@ +namespace ObjLoader.Loader.Data.DataStore +{ + public interface IElementGroup + { + void SetMaterial(string materialName); + } +} \ No newline at end of file diff --git a/ObjLoader/Loaders/IMaterialLibraryLoader.cs b/ObjLoader/Loaders/IMaterialLibraryLoader.cs new file mode 100644 index 0000000..52d4cc3 --- /dev/null +++ b/ObjLoader/Loaders/IMaterialLibraryLoader.cs @@ -0,0 +1,9 @@ +using System.IO; + +namespace ObjLoader.Loader.Loaders +{ + public interface IMaterialLibraryLoader + { + void Load(Stream lineStream); + } +} \ No newline at end of file diff --git a/ObjLoader/Loaders/IMaterialLibraryLoaderFacade.cs b/ObjLoader/Loaders/IMaterialLibraryLoaderFacade.cs new file mode 100644 index 0000000..c1c8781 --- /dev/null +++ b/ObjLoader/Loaders/IMaterialLibraryLoaderFacade.cs @@ -0,0 +1,7 @@ +namespace ObjLoader.Loader.Loaders +{ + public interface IMaterialLibraryLoaderFacade + { + void Load(string materialFileName); + } +} \ No newline at end of file diff --git a/ObjLoader/Loaders/IObjLoader.cs b/ObjLoader/Loaders/IObjLoader.cs new file mode 100644 index 0000000..298e1dc --- /dev/null +++ b/ObjLoader/Loaders/IObjLoader.cs @@ -0,0 +1,9 @@ +using System.IO; + +namespace ObjLoader.Loader.Loaders +{ + public interface IObjLoader + { + LoadResult Load(Stream lineStream); + } +} \ No newline at end of file diff --git a/ObjLoader/Loaders/IObjLoaderFactory.cs b/ObjLoader/Loaders/IObjLoaderFactory.cs new file mode 100644 index 0000000..2123ff9 --- /dev/null +++ b/ObjLoader/Loaders/IObjLoaderFactory.cs @@ -0,0 +1,8 @@ +namespace ObjLoader.Loader.Loaders +{ + public interface IObjLoaderFactory + { + IObjLoader Create(IMaterialStreamProvider materialStreamProvider); + IObjLoader Create(); + } +} \ No newline at end of file diff --git a/ObjLoader/Loaders/LoadResult.cs b/ObjLoader/Loaders/LoadResult.cs new file mode 100644 index 0000000..b9413fa --- /dev/null +++ b/ObjLoader/Loaders/LoadResult.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using ObjLoader.Loader.Data; +using ObjLoader.Loader.Data.Elements; +using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; + +namespace ObjLoader.Loader.Loaders +{ + public class LoadResult + { + public IList Vertices { get; set; } + public IList Textures { get; set; } + public IList Normals { get; set; } + public IList Groups { get; set; } + public IList Materials { get; set; } + } +} \ No newline at end of file diff --git a/ObjLoader/Loaders/LoaderBase.cs b/ObjLoader/Loaders/LoaderBase.cs new file mode 100644 index 0000000..42f5bbc --- /dev/null +++ b/ObjLoader/Loaders/LoaderBase.cs @@ -0,0 +1,35 @@ +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) || 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/ObjLoader/Loaders/MaterialLibraryLoader.cs b/ObjLoader/Loaders/MaterialLibraryLoader.cs new file mode 100644 index 0000000..3e0a6e6 --- /dev/null +++ b/ObjLoader/Loaders/MaterialLibraryLoader.cs @@ -0,0 +1,91 @@ +using ObjLoader.Loader.Common; +using ObjLoader.Loader.Data; +using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; +using System; +using System.Collections.Generic; +using System.IO; +using System.Numerics; + +namespace ObjLoader.Loader.Loaders +{ + public class MaterialLibraryLoader : LoaderBase, IMaterialLibraryLoader + { + private readonly IMaterialLibrary _materialLibrary; + private readonly Dictionary> _parseActionDictionary = []; + private readonly List _unrecognizedLines = []; + + public MaterialLibraryLoader(IMaterialLibrary materialLibrary) + { + _materialLibrary = materialLibrary; + + 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 Material CurrentMaterial { get; set; } + + 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); + _materialLibrary.Push(CurrentMaterial); + } + + private 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); + } +} \ No newline at end of file diff --git a/ObjLoader/Loaders/MaterialLibraryLoaderFacade.cs b/ObjLoader/Loaders/MaterialLibraryLoaderFacade.cs new file mode 100644 index 0000000..c1c23a3 --- /dev/null +++ b/ObjLoader/Loaders/MaterialLibraryLoaderFacade.cs @@ -0,0 +1,22 @@ +namespace ObjLoader.Loader.Loaders +{ + public class MaterialLibraryLoaderFacade : IMaterialLibraryLoaderFacade + { + private readonly IMaterialLibraryLoader _loader; + private readonly IMaterialStreamProvider _materialStreamProvider; + + public MaterialLibraryLoaderFacade(IMaterialLibraryLoader loader, IMaterialStreamProvider materialStreamProvider) + { + _loader = loader; + _materialStreamProvider = materialStreamProvider; + } + + public void Load(string materialFileName) + { + using var stream = _materialStreamProvider.Open(materialFileName); + + if (stream != null) + _loader.Load(stream); + } + } +} \ No newline at end of file diff --git a/ObjLoader/Loaders/MaterialStreamProvider.cs b/ObjLoader/Loaders/MaterialStreamProvider.cs new file mode 100644 index 0000000..7c74e54 --- /dev/null +++ b/ObjLoader/Loaders/MaterialStreamProvider.cs @@ -0,0 +1,20 @@ +using System.IO; + +namespace ObjLoader.Loader.Loaders +{ + public class MaterialStreamProvider : IMaterialStreamProvider + { + public Stream Open(string materialFilePath) + { + return File.Open(materialFilePath, FileMode.Open, FileAccess.Read); + } + } + + public class MaterialNullStreamProvider : IMaterialStreamProvider + { + public Stream Open(string materialFilePath) + { + return null; + } + } +} \ No newline at end of file diff --git a/ObjLoader/Loaders/ObjLoader.cs b/ObjLoader/Loaders/ObjLoader.cs new file mode 100644 index 0000000..9670ca4 --- /dev/null +++ b/ObjLoader/Loaders/ObjLoader.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using System.IO; +using ObjLoader.Loader.Data.DataStore; +using ObjLoader.Loader.TypeParsers.Interfaces; + +namespace ObjLoader.Loader.Loaders +{ + public class ObjLoader : LoaderBase, IObjLoader + { + private readonly IDataStore _dataStore; + private readonly List _typeParsers = new List(); + + private readonly List _unrecognizedLines = new List(); + + public ObjLoader( + IDataStore dataStore, + IFaceParser faceParser, + IGroupParser groupParser, + INormalParser normalParser, + ITextureParser textureParser, + IVertexParser vertexParser, + IMaterialLibraryParser materialLibraryParser, + IUseMaterialParser useMaterialParser) + { + _dataStore = dataStore; + SetupTypeParsers( + vertexParser, + faceParser, + normalParser, + textureParser, + groupParser, + materialLibraryParser, + useMaterialParser); + } + + private void SetupTypeParsers(params ITypeParser[] parsers) + { + foreach (var parser in parsers) + { + _typeParsers.Add(parser); + } + } + + protected override void ParseLine(string keyword, string data) + { + foreach (var typeParser in _typeParsers) + { + if (typeParser.CanParse(keyword)) + { + typeParser.Parse(data); + return; + } + } + + _unrecognizedLines.Add(keyword + " " + data); + } + + public LoadResult Load(Stream lineStream) + { + StartLoad(lineStream); + + return CreateResult(); + } + + private LoadResult CreateResult() + { + var result = new LoadResult + { + Vertices = _dataStore.Vertices, + Textures = _dataStore.Textures, + Normals = _dataStore.Normals, + Groups = _dataStore.Groups, + Materials = _dataStore.Materials + }; + return result; + } + } +} \ No newline at end of file diff --git a/ObjLoader/Loaders/ObjLoaderFactory.cs b/ObjLoader/Loaders/ObjLoaderFactory.cs new file mode 100644 index 0000000..d99d1ca --- /dev/null +++ b/ObjLoader/Loaders/ObjLoaderFactory.cs @@ -0,0 +1,35 @@ +using System.IO; +using ObjLoader.Loader.Data.DataStore; +using ObjLoader.Loader.TypeParsers; + +namespace ObjLoader.Loader.Loaders +{ + public interface IMaterialStreamProvider + { + Stream Open(string materialFilePath); + } + + public class ObjLoaderFactory : IObjLoaderFactory + { + public IObjLoader Create() + => Create(new MaterialStreamProvider()); + + public IObjLoader Create(IMaterialStreamProvider materialStreamProvider) + { + var dataStore = new DataStore(); + + var faceParser = new FaceParser(dataStore); + var groupParser = new GroupParser(dataStore); + var normalParser = new NormalParser(dataStore); + var textureParser = new TextureParser(dataStore); + var vertexParser = new VertexParser(dataStore); + + var materialLibraryLoader = new MaterialLibraryLoader(dataStore); + var materialLibraryLoaderFacade = new MaterialLibraryLoaderFacade(materialLibraryLoader, materialStreamProvider); + var materialLibraryParser = new MaterialLibraryParser(materialLibraryLoaderFacade); + var useMaterialParser = new UseMaterialParser(dataStore); + + return new ObjLoader(dataStore, faceParser, groupParser, normalParser, textureParser, vertexParser, materialLibraryParser, useMaterialParser); + } + } +} \ No newline at end of file diff --git a/ObjLoader/ObjLoader.csproj b/ObjLoader/ObjLoader.csproj new file mode 100644 index 0000000..fecacdb --- /dev/null +++ b/ObjLoader/ObjLoader.csproj @@ -0,0 +1,11 @@ + + + + net8.0 + + + + + + + \ No newline at end of file diff --git a/ObjLoader/TypeParsers/FaceParser.cs b/ObjLoader/TypeParsers/FaceParser.cs new file mode 100644 index 0000000..04ef3d2 --- /dev/null +++ b/ObjLoader/TypeParsers/FaceParser.cs @@ -0,0 +1,57 @@ +using ObjLoader.Loader.Common; +using ObjLoader.Loader.Data.Elements; +using ObjLoader.Loader.TypeParsers.Interfaces; +using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; +using System; + +namespace ObjLoader.Loader.TypeParsers +{ + public class FaceParser : TypeParserBase, IFaceParser + { + private readonly IFaceGroup _faceGroup; + + public FaceParser(IFaceGroup faceGroup) + { + _faceGroup = faceGroup; + } + + protected override string Keyword => "f"; + + public override void Parse(string line) + { + string[] vertices = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + + var face = new Face(); + + foreach (string vertexString in vertices) + { + var faceVertex = ParseFaceVertex(vertexString); + face.AddVertex(faceVertex); + } + + _faceGroup.AddFace(face); + } + + private FaceVertex ParseFaceVertex(string vertexString) + { + string[] fields = vertexString.Split(new[] { '/' }, StringSplitOptions.None); + + int vertexIndex = fields[0].ParseInvariantInt(); + var faceVertex = new FaceVertex(vertexIndex, 0, 0); + + if (fields.Length > 1) + { + int textureIndex = fields[1].Length == 0 ? 0 : fields[1].ParseInvariantInt(); + faceVertex.TextureIndex = textureIndex; + } + + if (fields.Length > 2) + { + int normalIndex = fields.Length > 2 && fields[2].Length == 0 ? 0 : fields[2].ParseInvariantInt(); + faceVertex.NormalIndex = normalIndex; + } + + return faceVertex; + } + } +} \ No newline at end of file diff --git a/ObjLoader/TypeParsers/GroupParser.cs b/ObjLoader/TypeParsers/GroupParser.cs new file mode 100644 index 0000000..babb7b4 --- /dev/null +++ b/ObjLoader/TypeParsers/GroupParser.cs @@ -0,0 +1,19 @@ +using ObjLoader.Loader.TypeParsers.Interfaces; +using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; + +namespace ObjLoader.Loader.TypeParsers +{ + public class GroupParser : TypeParserBase, IGroupParser + { + private readonly IGroupDataStore _groupDataStore; + + public GroupParser(IGroupDataStore groupDataStore) + { + _groupDataStore = groupDataStore; + } + + protected override string Keyword => "g"; + + public override void Parse(string line) => _groupDataStore.PushGroup(line); + } +} \ No newline at end of file diff --git a/ObjLoader/TypeParsers/Interfaces/IFaceParser.cs b/ObjLoader/TypeParsers/Interfaces/IFaceParser.cs new file mode 100644 index 0000000..a78fa13 --- /dev/null +++ b/ObjLoader/TypeParsers/Interfaces/IFaceParser.cs @@ -0,0 +1,6 @@ +namespace ObjLoader.Loader.TypeParsers.Interfaces +{ + public interface IFaceParser : ITypeParser + { + } +} \ No newline at end of file diff --git a/ObjLoader/TypeParsers/Interfaces/IGroupParser.cs b/ObjLoader/TypeParsers/Interfaces/IGroupParser.cs new file mode 100644 index 0000000..0755d05 --- /dev/null +++ b/ObjLoader/TypeParsers/Interfaces/IGroupParser.cs @@ -0,0 +1,6 @@ +namespace ObjLoader.Loader.TypeParsers.Interfaces +{ + public interface IGroupParser : ITypeParser + { + } +} \ No newline at end of file diff --git a/ObjLoader/TypeParsers/Interfaces/IMaterialLibraryParser.cs b/ObjLoader/TypeParsers/Interfaces/IMaterialLibraryParser.cs new file mode 100644 index 0000000..f2df760 --- /dev/null +++ b/ObjLoader/TypeParsers/Interfaces/IMaterialLibraryParser.cs @@ -0,0 +1,6 @@ +namespace ObjLoader.Loader.TypeParsers.Interfaces +{ + public interface IMaterialLibraryParser : ITypeParser + { + } +} \ No newline at end of file diff --git a/ObjLoader/TypeParsers/Interfaces/INormalParser.cs b/ObjLoader/TypeParsers/Interfaces/INormalParser.cs new file mode 100644 index 0000000..0a9f993 --- /dev/null +++ b/ObjLoader/TypeParsers/Interfaces/INormalParser.cs @@ -0,0 +1,6 @@ +namespace ObjLoader.Loader.TypeParsers.Interfaces +{ + public interface INormalParser : ITypeParser + { + } +} \ No newline at end of file diff --git a/ObjLoader/TypeParsers/Interfaces/ITextureParser.cs b/ObjLoader/TypeParsers/Interfaces/ITextureParser.cs new file mode 100644 index 0000000..68aed32 --- /dev/null +++ b/ObjLoader/TypeParsers/Interfaces/ITextureParser.cs @@ -0,0 +1,6 @@ +namespace ObjLoader.Loader.TypeParsers.Interfaces +{ + public interface ITextureParser : ITypeParser + { + } +} \ No newline at end of file diff --git a/ObjLoader/TypeParsers/Interfaces/ITypeParser.cs b/ObjLoader/TypeParsers/Interfaces/ITypeParser.cs new file mode 100644 index 0000000..07dbb74 --- /dev/null +++ b/ObjLoader/TypeParsers/Interfaces/ITypeParser.cs @@ -0,0 +1,8 @@ +namespace ObjLoader.Loader.TypeParsers.Interfaces +{ + public interface ITypeParser + { + bool CanParse(string keyword); + void Parse(string line); + } +} \ No newline at end of file diff --git a/ObjLoader/TypeParsers/Interfaces/IUseMaterialParser.cs b/ObjLoader/TypeParsers/Interfaces/IUseMaterialParser.cs new file mode 100644 index 0000000..84b2116 --- /dev/null +++ b/ObjLoader/TypeParsers/Interfaces/IUseMaterialParser.cs @@ -0,0 +1,6 @@ +namespace ObjLoader.Loader.TypeParsers.Interfaces +{ + public interface IUseMaterialParser : ITypeParser + { + } +} \ No newline at end of file diff --git a/ObjLoader/TypeParsers/Interfaces/IVertexParser.cs b/ObjLoader/TypeParsers/Interfaces/IVertexParser.cs new file mode 100644 index 0000000..2ea2059 --- /dev/null +++ b/ObjLoader/TypeParsers/Interfaces/IVertexParser.cs @@ -0,0 +1,6 @@ +namespace ObjLoader.Loader.TypeParsers.Interfaces +{ + public interface IVertexParser : ITypeParser + { + } +} \ No newline at end of file diff --git a/ObjLoader/TypeParsers/MaterialLibraryParser.cs b/ObjLoader/TypeParsers/MaterialLibraryParser.cs new file mode 100644 index 0000000..10a27cf --- /dev/null +++ b/ObjLoader/TypeParsers/MaterialLibraryParser.cs @@ -0,0 +1,19 @@ +using ObjLoader.Loader.Loaders; +using ObjLoader.Loader.TypeParsers.Interfaces; + +namespace ObjLoader.Loader.TypeParsers +{ + public class MaterialLibraryParser : TypeParserBase, IMaterialLibraryParser + { + private readonly IMaterialLibraryLoaderFacade _libraryLoaderFacade; + + public MaterialLibraryParser(IMaterialLibraryLoaderFacade libraryLoaderFacade) + { + _libraryLoaderFacade = libraryLoaderFacade; + } + + 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..4180846 --- /dev/null +++ b/ObjLoader/TypeParsers/NormalParser.cs @@ -0,0 +1,31 @@ +using ObjLoader.Loader.Common; +using ObjLoader.Loader.TypeParsers.Interfaces; +using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; +using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; + +namespace ObjLoader.Loader.TypeParsers +{ + public class NormalParser : TypeParserBase, INormalParser + { + private readonly INormalDataStore _normalDataStore; + + public NormalParser(INormalDataStore normalDataStore) + { + _normalDataStore = normalDataStore; + } + + 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); + _normalDataStore.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..cefa002 --- /dev/null +++ b/ObjLoader/TypeParsers/TextureParser.cs @@ -0,0 +1,30 @@ +using ObjLoader.Loader.Common; +using ObjLoader.Loader.TypeParsers.Interfaces; +using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; +using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; + +namespace ObjLoader.Loader.TypeParsers +{ + public class TextureParser : TypeParserBase, ITextureParser + { + private readonly ITextureDataStore _textureDataStore; + + public TextureParser(ITextureDataStore textureDataStore) + { + _textureDataStore = textureDataStore; + } + + 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 Texture(x, y); + _textureDataStore.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..5441855 --- /dev/null +++ b/ObjLoader/TypeParsers/TypeParserBase.cs @@ -0,0 +1,14 @@ +using ObjLoader.Loader.Common; +using ObjLoader.Loader.TypeParsers.Interfaces; + +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/ObjLoader/TypeParsers/UseMaterialParser.cs b/ObjLoader/TypeParsers/UseMaterialParser.cs new file mode 100644 index 0000000..2df7f4b --- /dev/null +++ b/ObjLoader/TypeParsers/UseMaterialParser.cs @@ -0,0 +1,19 @@ +using ObjLoader.Loader.Data.DataStore; +using ObjLoader.Loader.TypeParsers.Interfaces; + +namespace ObjLoader.Loader.TypeParsers +{ + public class UseMaterialParser : TypeParserBase, IUseMaterialParser + { + private readonly IElementGroup _elementGroup; + + public UseMaterialParser(IElementGroup elementGroup) + { + _elementGroup = elementGroup; + } + + protected override string Keyword => "usemtl"; + + public override void Parse(string line) => _elementGroup.SetMaterial(line); + } +} \ No newline at end of file diff --git a/ObjLoader/TypeParsers/VertexParser.cs b/ObjLoader/TypeParsers/VertexParser.cs new file mode 100644 index 0000000..d3195e0 --- /dev/null +++ b/ObjLoader/TypeParsers/VertexParser.cs @@ -0,0 +1,32 @@ +using ObjLoader.Loader.Common; +using ObjLoader.Loader.TypeParsers.Interfaces; +using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; +using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; +using System; + +namespace ObjLoader.Loader.TypeParsers +{ + public class VertexParser : TypeParserBase, IVertexParser + { + private readonly IVertexDataStore _vertexDataStore; + + public VertexParser(IVertexDataStore vertexDataStore) + { + _vertexDataStore = vertexDataStore; + } + + protected override string Keyword => "v"; + + public override void Parse(string line) + { + string[] parts = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + + float x = parts[0].ParseInvariantFloat(); + float y = parts[1].ParseInvariantFloat(); + float z = parts[2].ParseInvariantFloat(); + + var vertex = new Vertex(x, y, z); + _vertexDataStore.AddVertex(vertex); + } + } +} \ No newline at end of file diff --git a/SharpEngine.Core.Components/IComponent.cs b/SharpEngine.Core.Components/IComponent.cs new file mode 100644 index 0000000..fdeaa85 --- /dev/null +++ b/SharpEngine.Core.Components/IComponent.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpEngine.Core.Components; + +// TODO: #53 Entity Component System + +internal interface IComponent +{ +} diff --git a/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IFaceGroup.cs b/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IFaceGroup.cs new file mode 100644 index 0000000..e6c0922 --- /dev/null +++ b/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IFaceGroup.cs @@ -0,0 +1,9 @@ +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/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IGroupDataStore.cs b/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IGroupDataStore.cs new file mode 100644 index 0000000..3fe9d69 --- /dev/null +++ b/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IGroupDataStore.cs @@ -0,0 +1,7 @@ +namespace SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore +{ + public interface IGroupDataStore + { + void PushGroup(string groupName); + } +} \ No newline at end of file diff --git a/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IMaterialLibrary.cs b/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IMaterialLibrary.cs new file mode 100644 index 0000000..6758502 --- /dev/null +++ b/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IMaterialLibrary.cs @@ -0,0 +1,9 @@ +using ObjLoader.Loader.Data; + +namespace SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore +{ + public interface IMaterialLibrary + { + void Push(Material material); + } +} \ No newline at end of file diff --git a/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/INormalDataStore.cs b/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/INormalDataStore.cs new file mode 100644 index 0000000..cc990e2 --- /dev/null +++ b/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/INormalDataStore.cs @@ -0,0 +1,9 @@ +using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; + +namespace SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore +{ + public interface INormalDataStore + { + void AddNormal(Normal normal); + } +} \ No newline at end of file diff --git a/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/ITextureDataStore.cs b/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/ITextureDataStore.cs new file mode 100644 index 0000000..81bf5ae --- /dev/null +++ b/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/ITextureDataStore.cs @@ -0,0 +1,9 @@ +using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; + +namespace SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore +{ + public interface ITextureDataStore + { + void AddTexture(Texture texture); + } +} \ No newline at end of file diff --git a/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IVertexDataStore.cs b/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IVertexDataStore.cs new file mode 100644 index 0000000..b6f88b1 --- /dev/null +++ b/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IVertexDataStore.cs @@ -0,0 +1,9 @@ +using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; + +namespace SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore +{ + public interface IVertexDataStore + { + void AddVertex(Vertex vertex); + } +} \ No newline at end of file diff --git a/Core/Entities/Properties/BoundingBox.cs b/SharpEngine.Core.Components/Properties/BoundingBox.cs similarity index 100% rename from Core/Entities/Properties/BoundingBox.cs rename to SharpEngine.Core.Components/Properties/BoundingBox.cs diff --git a/Core/Entities/Properties/ITransform.cs b/SharpEngine.Core.Components/Properties/ITransform.cs similarity index 100% rename from Core/Entities/Properties/ITransform.cs rename to SharpEngine.Core.Components/Properties/ITransform.cs diff --git a/SharpEngine.Core.Components/Properties/Material.cs b/SharpEngine.Core.Components/Properties/Material.cs new file mode 100644 index 0000000..5938053 --- /dev/null +++ b/SharpEngine.Core.Components/Properties/Material.cs @@ -0,0 +1,35 @@ +using System.Numerics; + +namespace ObjLoader.Loader.Data +{ + public class Material + { + public Material(string materialName) + { + Name = materialName; + } + + public string Name { get; set; } + + public Vector3 AmbientColor { get; set; } + public Vector3 DiffuseColor { get; set; } + public Vector3 SpecularColor { get; set; } + public float SpecularCoefficient { get; set; } + + public float Transparency { get; set; } + + public int IlluminationModel { get; set; } + + public string AmbientTextureMap { get; set; } + public string DiffuseTextureMap { get; set; } + + public string SpecularTextureMap { get; set; } + public string SpecularHighlightTextureMap { get; set; } + + public string BumpMap { get; set; } + public string DisplacementMap { get; set; } + public string StencilDecalMap { get; set; } + + public string AlphaTextureMap { get; set; } + } +} \ No newline at end of file diff --git a/Core/Entities/Properties/Meshes/Mesh.cs b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs similarity index 100% rename from Core/Entities/Properties/Meshes/Mesh.cs rename to SharpEngine.Core.Components/Properties/Meshes/Mesh.cs 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..9524a15 --- /dev/null +++ b/SharpEngine.Core.Components/Properties/Meshes/MeshData/Face.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; + +namespace ObjLoader.Loader.Data.Elements +{ + public class Face + { + private readonly List _vertices = new List(); + + public void AddVertex(FaceVertex vertex) + { + _vertices.Add(vertex); + } + + public FaceVertex this[int i] + { + get { return _vertices[i]; } + } + + public int Count + { + get { return _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/SharpEngine.Core.Components/Properties/Meshes/MeshData/Group.cs b/SharpEngine.Core.Components/Properties/Meshes/MeshData/Group.cs new file mode 100644 index 0000000..19d682f --- /dev/null +++ b/SharpEngine.Core.Components/Properties/Meshes/MeshData/Group.cs @@ -0,0 +1,25 @@ +using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; +using System.Collections.Generic; + +namespace ObjLoader.Loader.Data.Elements +{ + public class Group : IFaceGroup + { + private readonly List _faces = new List(); + + public Group(string name) + { + Name = name; + } + + public string Name { get; private set; } + public Material Material { get; set; } + + public IList Faces { get { return _faces; } } + + public void AddFace(Face face) + { + _faces.Add(face); + } + } +} \ No newline at end of file diff --git a/SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/Normal.cs b/SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/Normal.cs new file mode 100644 index 0000000..6d325c3 --- /dev/null +++ b/SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/Normal.cs @@ -0,0 +1,16 @@ +namespace SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData +{ + 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/SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/Texture.cs b/SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/Texture.cs new file mode 100644 index 0000000..3e580da --- /dev/null +++ b/SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/Texture.cs @@ -0,0 +1,14 @@ +namespace SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData +{ + public struct Texture + { + public Texture(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/SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/Vertex.cs b/SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/Vertex.cs new file mode 100644 index 0000000..87a7a03 --- /dev/null +++ b/SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/Vertex.cs @@ -0,0 +1,16 @@ +namespace SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData +{ + public struct Vertex + { + public Vertex(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/Core/Entities/Properties/Meshes/MeshExtensions.cs b/SharpEngine.Core.Components/Properties/Meshes/MeshExtensions.cs similarity index 100% rename from Core/Entities/Properties/Meshes/MeshExtensions.cs rename to SharpEngine.Core.Components/Properties/Meshes/MeshExtensions.cs diff --git a/Core/Entities/Properties/Meshes/ObjMeshData.cs b/SharpEngine.Core.Components/Properties/Meshes/ObjMeshData.cs similarity index 100% rename from Core/Entities/Properties/Meshes/ObjMeshData.cs rename to SharpEngine.Core.Components/Properties/Meshes/ObjMeshData.cs diff --git a/Core/Entities/Properties/Meshes/VertexData.cs b/SharpEngine.Core.Components/Properties/Meshes/VertexData.cs similarity index 100% rename from Core/Entities/Properties/Meshes/VertexData.cs rename to SharpEngine.Core.Components/Properties/Meshes/VertexData.cs diff --git a/Core/Entities/Properties/Quaternion.cs b/SharpEngine.Core.Components/Properties/Quaternion.cs similarity index 100% rename from Core/Entities/Properties/Quaternion.cs rename to SharpEngine.Core.Components/Properties/Quaternion.cs diff --git a/Core/Entities/Properties/Transform.cs b/SharpEngine.Core.Components/Properties/Transform.cs similarity index 100% rename from Core/Entities/Properties/Transform.cs rename to SharpEngine.Core.Components/Properties/Transform.cs diff --git a/Core/Entities/Properties/Transform2D.cs b/SharpEngine.Core.Components/Properties/Transform2D.cs similarity index 100% rename from Core/Entities/Properties/Transform2D.cs rename to SharpEngine.Core.Components/Properties/Transform2D.cs diff --git a/SharpEngine.Core.Components/SharpEngine.Core.Components.csproj b/SharpEngine.Core.Components/SharpEngine.Core.Components.csproj new file mode 100644 index 0000000..73e5562 --- /dev/null +++ b/SharpEngine.Core.Components/SharpEngine.Core.Components.csproj @@ -0,0 +1,22 @@ + + + + net8.0 + enable + enable + + + + $(GenerateNuGetPackages) + + + + + + + + + + + + diff --git a/Core/Numerics/HashCodeHelper.cs b/SharpEngine.Core.Numerics/HashCodeHelper.cs similarity index 100% rename from Core/Numerics/HashCodeHelper.cs rename to SharpEngine.Core.Numerics/HashCodeHelper.cs diff --git a/Core/Numerics/IVector.cs b/SharpEngine.Core.Numerics/IVector.cs similarity index 100% rename from Core/Numerics/IVector.cs rename to SharpEngine.Core.Numerics/IVector.cs diff --git a/Core/Numerics/JitIntrinsicAttribute.cs b/SharpEngine.Core.Numerics/JitIntrinsicAttribute.cs similarity index 100% rename from Core/Numerics/JitIntrinsicAttribute.cs rename to SharpEngine.Core.Numerics/JitIntrinsicAttribute.cs diff --git a/SharpEngine.Core.Numerics/SharpEngine.Core.Numerics.csproj b/SharpEngine.Core.Numerics/SharpEngine.Core.Numerics.csproj new file mode 100644 index 0000000..3082977 --- /dev/null +++ b/SharpEngine.Core.Numerics/SharpEngine.Core.Numerics.csproj @@ -0,0 +1,14 @@ + + + + net8.0 + enable + enable + + + + $(GenerateNuGetPackages) + + + + diff --git a/Core/Numerics/Vector2.cs b/SharpEngine.Core.Numerics/Vector2.cs similarity index 100% rename from Core/Numerics/Vector2.cs rename to SharpEngine.Core.Numerics/Vector2.cs diff --git a/Core/Numerics/Vector2_Intrinsics.cs b/SharpEngine.Core.Numerics/Vector2_Intrinsics.cs similarity index 100% rename from Core/Numerics/Vector2_Intrinsics.cs rename to SharpEngine.Core.Numerics/Vector2_Intrinsics.cs diff --git a/Core/Numerics/Vector3.cs b/SharpEngine.Core.Numerics/Vector3.cs similarity index 100% rename from Core/Numerics/Vector3.cs rename to SharpEngine.Core.Numerics/Vector3.cs diff --git a/Core/Numerics/Vector3_Intrinsics.cs b/SharpEngine.Core.Numerics/Vector3_Intrinsics.cs similarity index 100% rename from Core/Numerics/Vector3_Intrinsics.cs rename to SharpEngine.Core.Numerics/Vector3_Intrinsics.cs diff --git a/Core/Abstractions/IGame.cs b/SharpEngine.Core/Abstractions/IGame.cs similarity index 100% rename from Core/Abstractions/IGame.cs rename to SharpEngine.Core/Abstractions/IGame.cs diff --git a/Core/Abstractions/IRenderable.cs b/SharpEngine.Core/Abstractions/IRenderable.cs similarity index 100% rename from Core/Abstractions/IRenderable.cs rename to SharpEngine.Core/Abstractions/IRenderable.cs diff --git a/Core/Abstractions/ISettings.cs b/SharpEngine.Core/Abstractions/ISettings.cs similarity index 100% rename from Core/Abstractions/ISettings.cs rename to SharpEngine.Core/Abstractions/ISettings.cs diff --git a/Core/Audio/Audio.cs b/SharpEngine.Core/Audio/Audio.cs similarity index 100% rename from Core/Audio/Audio.cs rename to SharpEngine.Core/Audio/Audio.cs diff --git a/Core/Audio/AudioBuffer.cs b/SharpEngine.Core/Audio/AudioBuffer.cs similarity index 100% rename from Core/Audio/AudioBuffer.cs rename to SharpEngine.Core/Audio/AudioBuffer.cs diff --git a/Core/Audio/AudioDevice.cs b/SharpEngine.Core/Audio/AudioDevice.cs similarity index 100% rename from Core/Audio/AudioDevice.cs rename to SharpEngine.Core/Audio/AudioDevice.cs diff --git a/Core/Audio/AudioFileExtensions.cs b/SharpEngine.Core/Audio/AudioFileExtensions.cs similarity index 100% rename from Core/Audio/AudioFileExtensions.cs rename to SharpEngine.Core/Audio/AudioFileExtensions.cs diff --git a/Core/Audio/AudioPlayerBase.cs b/SharpEngine.Core/Audio/AudioPlayerBase.cs similarity index 100% rename from Core/Audio/AudioPlayerBase.cs rename to SharpEngine.Core/Audio/AudioPlayerBase.cs diff --git a/Core/Audio/AudioProperties.cs b/SharpEngine.Core/Audio/AudioProperties.cs similarity index 100% rename from Core/Audio/AudioProperties.cs rename to SharpEngine.Core/Audio/AudioProperties.cs diff --git a/Core/Audio/AudioSource.cs b/SharpEngine.Core/Audio/AudioSource.cs similarity index 100% rename from Core/Audio/AudioSource.cs rename to SharpEngine.Core/Audio/AudioSource.cs diff --git a/Core/Audio/WavData.cs b/SharpEngine.Core/Audio/WavData.cs similarity index 100% rename from Core/Audio/WavData.cs rename to SharpEngine.Core/Audio/WavData.cs diff --git a/Core/Audio/WavPlayer.cs b/SharpEngine.Core/Audio/WavPlayer.cs similarity index 100% rename from Core/Audio/WavPlayer.cs rename to SharpEngine.Core/Audio/WavPlayer.cs diff --git a/Core/Debug.cs b/SharpEngine.Core/Debug.cs similarity index 100% rename from Core/Debug.cs rename to SharpEngine.Core/Debug.cs diff --git a/Core/Entities/BezierCurve.cs b/SharpEngine.Core/Entities/BezierCurve.cs similarity index 100% rename from Core/Entities/BezierCurve.cs rename to SharpEngine.Core/Entities/BezierCurve.cs diff --git a/Core/Entities/GameObject.cs b/SharpEngine.Core/Entities/GameObject.cs similarity index 100% rename from Core/Entities/GameObject.cs rename to SharpEngine.Core/Entities/GameObject.cs diff --git a/Core/Entities/Lights/DirectionalLight.cs b/SharpEngine.Core/Entities/Lights/DirectionalLight.cs similarity index 100% rename from Core/Entities/Lights/DirectionalLight.cs rename to SharpEngine.Core/Entities/Lights/DirectionalLight.cs diff --git a/Core/Entities/Lights/Light.cs b/SharpEngine.Core/Entities/Lights/Light.cs similarity index 100% rename from Core/Entities/Lights/Light.cs rename to SharpEngine.Core/Entities/Lights/Light.cs diff --git a/Core/Entities/Lights/PointLight.cs b/SharpEngine.Core/Entities/Lights/PointLight.cs similarity index 100% rename from Core/Entities/Lights/PointLight.cs rename to SharpEngine.Core/Entities/Lights/PointLight.cs diff --git a/Core/Entities/Lights/SpotLight.cs b/SharpEngine.Core/Entities/Lights/SpotLight.cs similarity index 100% rename from Core/Entities/Lights/SpotLight.cs rename to SharpEngine.Core/Entities/Lights/SpotLight.cs diff --git a/Core/Entities/Properties/Material.cs b/SharpEngine.Core/Entities/Material.cs similarity index 100% rename from Core/Entities/Properties/Material.cs rename to SharpEngine.Core/Entities/Material.cs diff --git a/Core/Entities/Properties/Meshes/MeshService.cs b/SharpEngine.Core/Entities/MeshService.cs similarity index 100% rename from Core/Entities/Properties/Meshes/MeshService.cs rename to SharpEngine.Core/Entities/MeshService.cs diff --git a/Core/Entities/UI/Layouts/FlexLayout.cs b/SharpEngine.Core/Entities/UI/Layouts/FlexLayout.cs similarity index 100% rename from Core/Entities/UI/Layouts/FlexLayout.cs rename to SharpEngine.Core/Entities/UI/Layouts/FlexLayout.cs diff --git a/Core/Entities/UI/Layouts/GridLayout.cs b/SharpEngine.Core/Entities/UI/Layouts/GridLayout.cs similarity index 100% rename from Core/Entities/UI/Layouts/GridLayout.cs rename to SharpEngine.Core/Entities/UI/Layouts/GridLayout.cs diff --git a/Core/Entities/UI/Layouts/LayoutBase.cs b/SharpEngine.Core/Entities/UI/Layouts/LayoutBase.cs similarity index 100% rename from Core/Entities/UI/Layouts/LayoutBase.cs rename to SharpEngine.Core/Entities/UI/Layouts/LayoutBase.cs diff --git a/Core/Entities/UI/UIElement.cs b/SharpEngine.Core/Entities/UI/UIElement.cs similarity index 100% rename from Core/Entities/UI/UIElement.cs rename to SharpEngine.Core/Entities/UI/UIElement.cs diff --git a/Core/Entities/Views/CameraView.cs b/SharpEngine.Core/Entities/Views/CameraView.cs similarity index 100% rename from Core/Entities/Views/CameraView.cs rename to SharpEngine.Core/Entities/Views/CameraView.cs diff --git a/Core/Entities/Views/Settings/DefaultViewSettings.cs b/SharpEngine.Core/Entities/Views/Settings/DefaultViewSettings.cs similarity index 100% rename from Core/Entities/Views/Settings/DefaultViewSettings.cs rename to SharpEngine.Core/Entities/Views/Settings/DefaultViewSettings.cs diff --git a/Core/Entities/Views/Settings/IViewSettings.cs b/SharpEngine.Core/Entities/Views/Settings/IViewSettings.cs similarity index 100% rename from Core/Entities/Views/Settings/IViewSettings.cs rename to SharpEngine.Core/Entities/Views/Settings/IViewSettings.cs diff --git a/Core/Entities/Views/Settings/ViewSettings.cs b/SharpEngine.Core/Entities/Views/Settings/ViewSettings.cs similarity index 100% rename from Core/Entities/Views/Settings/ViewSettings.cs rename to SharpEngine.Core/Entities/Views/Settings/ViewSettings.cs diff --git a/Core/Entities/Views/View.cs b/SharpEngine.Core/Entities/Views/View.cs similarity index 100% rename from Core/Entities/Views/View.cs rename to SharpEngine.Core/Entities/Views/View.cs diff --git a/Core/Enums/MouseWheelScrollDirection.cs b/SharpEngine.Core/Enums/MouseWheelScrollDirection.cs similarity index 100% rename from Core/Enums/MouseWheelScrollDirection.cs rename to SharpEngine.Core/Enums/MouseWheelScrollDirection.cs diff --git a/Core/Extensions/CollectionExtensions.cs b/SharpEngine.Core/Extensions/CollectionExtensions.cs similarity index 100% rename from Core/Extensions/CollectionExtensions.cs rename to SharpEngine.Core/Extensions/CollectionExtensions.cs diff --git a/Core/Extensions/PathExtensions.cs b/SharpEngine.Core/Extensions/PathExtensions.cs similarity index 100% rename from Core/Extensions/PathExtensions.cs rename to SharpEngine.Core/Extensions/PathExtensions.cs diff --git a/Core/Primitives/Cube.cs b/SharpEngine.Core/Primitives/Cube.cs similarity index 100% rename from Core/Primitives/Cube.cs rename to SharpEngine.Core/Primitives/Cube.cs diff --git a/Core/Primitives/Plane.cs b/SharpEngine.Core/Primitives/Plane.cs similarity index 100% rename from Core/Primitives/Plane.cs rename to SharpEngine.Core/Primitives/Plane.cs diff --git a/Core/Primitives/PrimitiveFactory.cs b/SharpEngine.Core/Primitives/PrimitiveFactory.cs similarity index 100% rename from Core/Primitives/PrimitiveFactory.cs rename to SharpEngine.Core/Primitives/PrimitiveFactory.cs diff --git a/Core/Primitives/PrimitiveType.cs b/SharpEngine.Core/Primitives/PrimitiveType.cs similarity index 100% rename from Core/Primitives/PrimitiveType.cs rename to SharpEngine.Core/Primitives/PrimitiveType.cs diff --git a/Core/Ray.cs b/SharpEngine.Core/Ray.cs similarity index 100% rename from Core/Ray.cs rename to SharpEngine.Core/Ray.cs diff --git a/Core/Renderers/RenderFlags.cs b/SharpEngine.Core/Renderers/RenderFlags.cs similarity index 100% rename from Core/Renderers/RenderFlags.cs rename to SharpEngine.Core/Renderers/RenderFlags.cs diff --git a/Core/Renderers/Renderer.cs b/SharpEngine.Core/Renderers/Renderer.cs similarity index 100% rename from Core/Renderers/Renderer.cs rename to SharpEngine.Core/Renderers/Renderer.cs diff --git a/Core/Renderers/RendererBase.cs b/SharpEngine.Core/Renderers/RendererBase.cs similarity index 100% rename from Core/Renderers/RendererBase.cs rename to SharpEngine.Core/Renderers/RendererBase.cs diff --git a/Core/Renderers/TextRenderer.cs b/SharpEngine.Core/Renderers/TextRenderer.cs similarity index 100% rename from Core/Renderers/TextRenderer.cs rename to SharpEngine.Core/Renderers/TextRenderer.cs diff --git a/Core/Renderers/UIRenderer.cs b/SharpEngine.Core/Renderers/UIRenderer.cs similarity index 100% rename from Core/Renderers/UIRenderer.cs rename to SharpEngine.Core/Renderers/UIRenderer.cs diff --git a/Core/Scenes/Scene.cs b/SharpEngine.Core/Scenes/Scene.cs similarity index 100% rename from Core/Scenes/Scene.cs rename to SharpEngine.Core/Scenes/Scene.cs diff --git a/Core/Scenes/SceneNode.cs b/SharpEngine.Core/Scenes/SceneNode.cs similarity index 100% rename from Core/Scenes/SceneNode.cs rename to SharpEngine.Core/Scenes/SceneNode.cs diff --git a/Core/Shaders/LampShader.cs b/SharpEngine.Core/Shaders/LampShader.cs similarity index 100% rename from Core/Shaders/LampShader.cs rename to SharpEngine.Core/Shaders/LampShader.cs diff --git a/Core/Shaders/Light/DirectionalLight.glsl b/SharpEngine.Core/Shaders/Light/DirectionalLight.glsl similarity index 100% rename from Core/Shaders/Light/DirectionalLight.glsl rename to SharpEngine.Core/Shaders/Light/DirectionalLight.glsl diff --git a/Core/Shaders/Light/PointLight.glsl b/SharpEngine.Core/Shaders/Light/PointLight.glsl similarity index 100% rename from Core/Shaders/Light/PointLight.glsl rename to SharpEngine.Core/Shaders/Light/PointLight.glsl diff --git a/Core/Shaders/Light/SpotLight.glsl b/SharpEngine.Core/Shaders/Light/SpotLight.glsl similarity index 100% rename from Core/Shaders/Light/SpotLight.glsl rename to SharpEngine.Core/Shaders/Light/SpotLight.glsl diff --git a/Core/Shaders/LightingShader.cs b/SharpEngine.Core/Shaders/LightingShader.cs similarity index 100% rename from Core/Shaders/LightingShader.cs rename to SharpEngine.Core/Shaders/LightingShader.cs diff --git a/Core/Shaders/Material.glsl b/SharpEngine.Core/Shaders/Material.glsl similarity index 100% rename from Core/Shaders/Material.glsl rename to SharpEngine.Core/Shaders/Material.glsl diff --git a/Core/Shaders/Shader.cs b/SharpEngine.Core/Shaders/Shader.cs similarity index 100% rename from Core/Shaders/Shader.cs rename to SharpEngine.Core/Shaders/Shader.cs diff --git a/Core/Shaders/ShaderAttributes.cs b/SharpEngine.Core/Shaders/ShaderAttributes.cs similarity index 100% rename from Core/Shaders/ShaderAttributes.cs rename to SharpEngine.Core/Shaders/ShaderAttributes.cs diff --git a/Core/Shaders/ShaderBase.cs b/SharpEngine.Core/Shaders/ShaderBase.cs similarity index 100% rename from Core/Shaders/ShaderBase.cs rename to SharpEngine.Core/Shaders/ShaderBase.cs diff --git a/Core/Shaders/ShaderService.cs b/SharpEngine.Core/Shaders/ShaderService.cs similarity index 100% rename from Core/Shaders/ShaderService.cs rename to SharpEngine.Core/Shaders/ShaderService.cs diff --git a/Core/Shaders/UIShader.cs b/SharpEngine.Core/Shaders/UIShader.cs similarity index 100% rename from Core/Shaders/UIShader.cs rename to SharpEngine.Core/Shaders/UIShader.cs diff --git a/Core/Shaders/lighting.frag b/SharpEngine.Core/Shaders/lighting.frag similarity index 100% rename from Core/Shaders/lighting.frag rename to SharpEngine.Core/Shaders/lighting.frag diff --git a/Core/Shaders/shader.frag b/SharpEngine.Core/Shaders/shader.frag similarity index 100% rename from Core/Shaders/shader.frag rename to SharpEngine.Core/Shaders/shader.frag diff --git a/Core/Shaders/shader.vert b/SharpEngine.Core/Shaders/shader.vert similarity index 100% rename from Core/Shaders/shader.vert rename to SharpEngine.Core/Shaders/shader.vert diff --git a/Core/Shaders/uiShader.frag b/SharpEngine.Core/Shaders/uiShader.frag similarity index 100% rename from Core/Shaders/uiShader.frag rename to SharpEngine.Core/Shaders/uiShader.frag diff --git a/Core/Shaders/uiShader.vert b/SharpEngine.Core/Shaders/uiShader.vert similarity index 100% rename from Core/Shaders/uiShader.vert rename to SharpEngine.Core/Shaders/uiShader.vert diff --git a/Core/SharpEngine.Core.csproj b/SharpEngine.Core/SharpEngine.Core.csproj similarity index 88% rename from Core/SharpEngine.Core.csproj rename to SharpEngine.Core/SharpEngine.Core.csproj index 2fda018..a0cb0a8 100644 --- a/Core/SharpEngine.Core.csproj +++ b/SharpEngine.Core/SharpEngine.Core.csproj @@ -11,14 +11,9 @@ $(AssemblyName).NET - Debug;Release;LauncherNonWindows true - - - 2.22.0 - - + @@ -33,6 +28,12 @@ + + + + + + diff --git a/Core/Textures/DefaultTextures/debug.jpg b/SharpEngine.Core/Textures/DefaultTextures/debug.jpg similarity index 100% rename from Core/Textures/DefaultTextures/debug.jpg rename to SharpEngine.Core/Textures/DefaultTextures/debug.jpg diff --git a/Core/Textures/Texture.cs b/SharpEngine.Core/Textures/Texture.cs similarity index 100% rename from Core/Textures/Texture.cs rename to SharpEngine.Core/Textures/Texture.cs diff --git a/Core/Textures/TextureService.cs b/SharpEngine.Core/Textures/TextureService.cs similarity index 100% rename from Core/Textures/TextureService.cs rename to SharpEngine.Core/Textures/TextureService.cs diff --git a/Core/Windowing/Frame.cs b/SharpEngine.Core/Windowing/Frame.cs similarity index 100% rename from Core/Windowing/Frame.cs rename to SharpEngine.Core/Windowing/Frame.cs diff --git a/Core/Windowing/SilkWindow.cs b/SharpEngine.Core/Windowing/SilkWindow.cs similarity index 100% rename from Core/Windowing/SilkWindow.cs rename to SharpEngine.Core/Windowing/SilkWindow.cs diff --git a/Core/Windowing/Window.cs b/SharpEngine.Core/Windowing/Window.cs similarity index 100% rename from Core/Windowing/Window.cs rename to SharpEngine.Core/Windowing/Window.cs diff --git a/Core/_Resources/Default.cs b/SharpEngine.Core/_Resources/Default.cs similarity index 100% rename from Core/_Resources/Default.cs rename to SharpEngine.Core/_Resources/Default.cs diff --git a/Core/_Resources/icon.png b/SharpEngine.Core/_Resources/icon.png similarity index 100% rename from Core/_Resources/icon.png rename to SharpEngine.Core/_Resources/icon.png diff --git a/SharpEngine.Shared.Net8/Class1.cs b/SharpEngine.Shared.Net8/Class1.cs new file mode 100644 index 0000000..e8f6eff --- /dev/null +++ b/SharpEngine.Shared.Net8/Class1.cs @@ -0,0 +1,6 @@ +namespace SharpEngine.Shared.Net8; + +public class Class1 +{ + +} diff --git a/SharpEngine.Shared.Net8/SharpEngine.Shared.Net8.csproj b/SharpEngine.Shared.Net8/SharpEngine.Shared.Net8.csproj new file mode 100644 index 0000000..fa71b7a --- /dev/null +++ b/SharpEngine.Shared.Net8/SharpEngine.Shared.Net8.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/Core/Attributes/InspectorAttribute.cs b/SharpEngine.Shared/Attributes/InspectorAttribute.cs similarity index 100% rename from Core/Attributes/InspectorAttribute.cs rename to SharpEngine.Shared/Attributes/InspectorAttribute.cs diff --git a/SharpEngine.Shared/Extensions/StringExtensions.cs b/SharpEngine.Shared/Extensions/StringExtensions.cs new file mode 100644 index 0000000..f9d5e36 --- /dev/null +++ b/SharpEngine.Shared/Extensions/StringExtensions.cs @@ -0,0 +1,28 @@ +using System; +using System.Globalization; + +namespace ObjLoader.Loader.Common +{ + public static class StringExtensions + { + public static float ParseInvariantFloat(this string floatString) + { + return float.Parse(floatString, CultureInfo.InvariantCulture.NumberFormat); + } + + public static int ParseInvariantInt(this string intString) + { + return int.Parse(intString, CultureInfo.InvariantCulture.NumberFormat); + } + + public static bool EqualsOrdinalIgnoreCase(this string str, string s) + { + return str.Equals(s, StringComparison.OrdinalIgnoreCase); + } + + public static bool IsNullOrEmpty(this string str) + { + return string.IsNullOrEmpty(str); + } + } +} \ No newline at end of file diff --git a/Core/Math.cs b/SharpEngine.Shared/Math.cs similarity index 100% rename from Core/Math.cs rename to SharpEngine.Shared/Math.cs diff --git a/SharpEngine.sln b/SharpEngine.sln index 3c5d13b..92cd999 100644 --- a/SharpEngine.sln +++ b/SharpEngine.sln @@ -3,8 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.14.35906.104 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpEngine.Core", "Core\SharpEngine.Core.csproj", "{9A1984BA-6D84-374A-8BF0-A26A6493FEA9}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpEngine.Editor", "Editor\SharpEngine.Editor.csproj", "{F72A74DC-54F9-0C76-2D40-32D2524683F8}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Launcher", "Launcher\Launcher.csproj", "{3751B661-BE0E-9CD7-CA51-361A34450372}" @@ -26,6 +24,27 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MultipleWindows", "Examples\MultipleWindows\MultipleWindows.csproj", "{0AF16D15-5BD2-4FED-9C6A-227DE6A56C5E}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" + ProjectSection(SolutionItems) = preProject + Test.Directory.Build.props = Test.Directory.Build.props + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpEngine.Core.Tests", "Tests\SharpEngine.Core.Tests\SharpEngine.Core.Tests.csproj", "{60B90F0B-14B8-4FA5-8482-B09EDEC46BF8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpEngine.Shared.Tests", "Tests\SharpEngine.Shared.Tests\SharpEngine.Shared.Tests.csproj", "{385CCB8D-CA17-4B58-8DA6-D3E9210CE49B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpEngine.Editor.Tests", "Tests\SharpEngine.Editor.Tests\SharpEngine.Editor.Tests.csproj", "{D374B8A7-51F6-4688-BD99-74EB0E159079}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpEngine.Core.Numerics", "SharpEngine.Core.Numerics\SharpEngine.Core.Numerics.csproj", "{C5A54BE1-00E6-43F5-B0DB-41C6C1F47DDF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpEngine.Core.Components", "SharpEngine.Core.Components\SharpEngine.Core.Components.csproj", "{94482B3A-4230-45C3-A899-689DA882942E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpEngine.Core", "SharpEngine.Core\SharpEngine.Core.csproj", "{52043A27-E9FF-3216-A026-E241F706D49B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ObjLoader", "ObjLoader\ObjLoader.csproj", "{9D23A8B2-C143-B170-10B8-069D9FA119FD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ObjLoader.Tests", "Tests\ObjLoader.Test\ObjLoader.Tests.csproj", "{1807AD4A-C310-4BD8-9542-07D3D3EAE617}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -33,12 +52,6 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9A1984BA-6D84-374A-8BF0-A26A6493FEA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9A1984BA-6D84-374A-8BF0-A26A6493FEA9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9A1984BA-6D84-374A-8BF0-A26A6493FEA9}.LauncherNonWindows|Any CPU.ActiveCfg = LauncherNonWindows|Any CPU - {9A1984BA-6D84-374A-8BF0-A26A6493FEA9}.LauncherNonWindows|Any CPU.Build.0 = LauncherNonWindows|Any CPU - {9A1984BA-6D84-374A-8BF0-A26A6493FEA9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9A1984BA-6D84-374A-8BF0-A26A6493FEA9}.Release|Any CPU.Build.0 = Release|Any CPU {F72A74DC-54F9-0C76-2D40-32D2524683F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F72A74DC-54F9-0C76-2D40-32D2524683F8}.Debug|Any CPU.Build.0 = Debug|Any CPU {F72A74DC-54F9-0C76-2D40-32D2524683F8}.LauncherNonWindows|Any CPU.ActiveCfg = Debug|Any CPU @@ -78,6 +91,54 @@ Global {0AF16D15-5BD2-4FED-9C6A-227DE6A56C5E}.LauncherNonWindows|Any CPU.Build.0 = Release|Any CPU {0AF16D15-5BD2-4FED-9C6A-227DE6A56C5E}.Release|Any CPU.ActiveCfg = Release|Any CPU {0AF16D15-5BD2-4FED-9C6A-227DE6A56C5E}.Release|Any CPU.Build.0 = Release|Any CPU + {60B90F0B-14B8-4FA5-8482-B09EDEC46BF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {60B90F0B-14B8-4FA5-8482-B09EDEC46BF8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {60B90F0B-14B8-4FA5-8482-B09EDEC46BF8}.LauncherNonWindows|Any CPU.ActiveCfg = Release|Any CPU + {60B90F0B-14B8-4FA5-8482-B09EDEC46BF8}.LauncherNonWindows|Any CPU.Build.0 = Release|Any CPU + {60B90F0B-14B8-4FA5-8482-B09EDEC46BF8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {60B90F0B-14B8-4FA5-8482-B09EDEC46BF8}.Release|Any CPU.Build.0 = Release|Any CPU + {385CCB8D-CA17-4B58-8DA6-D3E9210CE49B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {385CCB8D-CA17-4B58-8DA6-D3E9210CE49B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {385CCB8D-CA17-4B58-8DA6-D3E9210CE49B}.LauncherNonWindows|Any CPU.ActiveCfg = Release|Any CPU + {385CCB8D-CA17-4B58-8DA6-D3E9210CE49B}.LauncherNonWindows|Any CPU.Build.0 = Release|Any CPU + {385CCB8D-CA17-4B58-8DA6-D3E9210CE49B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {385CCB8D-CA17-4B58-8DA6-D3E9210CE49B}.Release|Any CPU.Build.0 = Release|Any CPU + {D374B8A7-51F6-4688-BD99-74EB0E159079}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D374B8A7-51F6-4688-BD99-74EB0E159079}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D374B8A7-51F6-4688-BD99-74EB0E159079}.LauncherNonWindows|Any CPU.ActiveCfg = Release|Any CPU + {D374B8A7-51F6-4688-BD99-74EB0E159079}.LauncherNonWindows|Any CPU.Build.0 = Release|Any CPU + {D374B8A7-51F6-4688-BD99-74EB0E159079}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D374B8A7-51F6-4688-BD99-74EB0E159079}.Release|Any CPU.Build.0 = Release|Any CPU + {C5A54BE1-00E6-43F5-B0DB-41C6C1F47DDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C5A54BE1-00E6-43F5-B0DB-41C6C1F47DDF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C5A54BE1-00E6-43F5-B0DB-41C6C1F47DDF}.LauncherNonWindows|Any CPU.ActiveCfg = Release|Any CPU + {C5A54BE1-00E6-43F5-B0DB-41C6C1F47DDF}.LauncherNonWindows|Any CPU.Build.0 = Release|Any CPU + {C5A54BE1-00E6-43F5-B0DB-41C6C1F47DDF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C5A54BE1-00E6-43F5-B0DB-41C6C1F47DDF}.Release|Any CPU.Build.0 = Release|Any CPU + {94482B3A-4230-45C3-A899-689DA882942E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {94482B3A-4230-45C3-A899-689DA882942E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {94482B3A-4230-45C3-A899-689DA882942E}.LauncherNonWindows|Any CPU.ActiveCfg = Release|Any CPU + {94482B3A-4230-45C3-A899-689DA882942E}.LauncherNonWindows|Any CPU.Build.0 = Release|Any CPU + {94482B3A-4230-45C3-A899-689DA882942E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {94482B3A-4230-45C3-A899-689DA882942E}.Release|Any CPU.Build.0 = Release|Any CPU + {52043A27-E9FF-3216-A026-E241F706D49B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {52043A27-E9FF-3216-A026-E241F706D49B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {52043A27-E9FF-3216-A026-E241F706D49B}.LauncherNonWindows|Any CPU.ActiveCfg = LauncherNonWindows|Any CPU + {52043A27-E9FF-3216-A026-E241F706D49B}.LauncherNonWindows|Any CPU.Build.0 = LauncherNonWindows|Any CPU + {52043A27-E9FF-3216-A026-E241F706D49B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {52043A27-E9FF-3216-A026-E241F706D49B}.Release|Any CPU.Build.0 = Release|Any CPU + {9D23A8B2-C143-B170-10B8-069D9FA119FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9D23A8B2-C143-B170-10B8-069D9FA119FD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9D23A8B2-C143-B170-10B8-069D9FA119FD}.LauncherNonWindows|Any CPU.ActiveCfg = Release|Any CPU + {9D23A8B2-C143-B170-10B8-069D9FA119FD}.LauncherNonWindows|Any CPU.Build.0 = Release|Any CPU + {9D23A8B2-C143-B170-10B8-069D9FA119FD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9D23A8B2-C143-B170-10B8-069D9FA119FD}.Release|Any CPU.Build.0 = Release|Any CPU + {1807AD4A-C310-4BD8-9542-07D3D3EAE617}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1807AD4A-C310-4BD8-9542-07D3D3EAE617}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1807AD4A-C310-4BD8-9542-07D3D3EAE617}.LauncherNonWindows|Any CPU.ActiveCfg = Release|Any CPU + {1807AD4A-C310-4BD8-9542-07D3D3EAE617}.LauncherNonWindows|Any CPU.Build.0 = Release|Any CPU + {1807AD4A-C310-4BD8-9542-07D3D3EAE617}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1807AD4A-C310-4BD8-9542-07D3D3EAE617}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -86,6 +147,10 @@ Global {E8A75C3B-1D82-8B30-C854-AD35FB123CDC} = {B36A84DF-456D-A817-6EDD-3EC3E7F6E11F} {1BEC06D8-094D-8BC2-288E-E2C4C13F3D2E} = {B36A84DF-456D-A817-6EDD-3EC3E7F6E11F} {0AF16D15-5BD2-4FED-9C6A-227DE6A56C5E} = {B36A84DF-456D-A817-6EDD-3EC3E7F6E11F} + {60B90F0B-14B8-4FA5-8482-B09EDEC46BF8} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {385CCB8D-CA17-4B58-8DA6-D3E9210CE49B} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {D374B8A7-51F6-4688-BD99-74EB0E159079} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {1807AD4A-C310-4BD8-9542-07D3D3EAE617} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AA03EC4B-4E7B-4B73-BEA4-60C539332773} diff --git a/Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs b/Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs new file mode 100644 index 0000000..f51b6e1 --- /dev/null +++ b/Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs @@ -0,0 +1,146 @@ +using System.Collections.Generic; +using System.IO; +using System.Text; +using NUnit.Framework; +using ObjLoader.Loader.Data; +using System.Linq; +using FluentAssertions; +using ObjLoader.Loader.Loaders; +using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; + +namespace ObjLoader.Test.Loaders +{ + [TestFixture] + public class MaterialLibraryLoaderTests + { + private MaterialLibrarySpy _materialLibrarySpy; + private Material _firstMaterial; + private Material _secondMaterial; + private const float Epsilon = 0.000001f; + + private MaterialLibraryLoader _materialLibraryLoader; + + [SetUp] + public void SetUp() + { + _materialLibrarySpy = new MaterialLibrarySpy(); + _materialLibraryLoader = new MaterialLibraryLoader(_materialLibrarySpy); + } + + [Test] + public void Adds_correct_materials() + { + LoadMaterial(); + + _materialLibrarySpy.Materials.Count().Should().Be(2); + _firstMaterial.Name.Should().BeEquivalentTo("wire_134110008"); + _secondMaterial.Name.Should().BeEquivalentTo("second_material"); + } + + [Test] + public void Sets_correct_ambient_color() + { + LoadMaterial(); + + _firstMaterial.AmbientColor.X.Should().BeApproximately(1, Epsilon); + _firstMaterial.AmbientColor.Y.Should().BeApproximately(2, Epsilon); + _firstMaterial.AmbientColor.Z.Should().BeApproximately(3, Epsilon); + } + + [Test] + public void Sets_correct_diffuse_color() + { + LoadMaterial(); + + _firstMaterial.DiffuseColor.X.Should().BeApproximately(0.5255f, Epsilon); + _firstMaterial.DiffuseColor.Y.Should().BeApproximately(0.4314f, Epsilon); + _firstMaterial.DiffuseColor.Z.Should().BeApproximately(0.0314f, Epsilon); + } + + [Test] + public void Sets_correct_specular() + { + LoadMaterial(); + + _firstMaterial.SpecularColor.X.Should().BeApproximately(0.3500f, Epsilon); + _firstMaterial.SpecularColor.Y.Should().BeApproximately(0.3600f, Epsilon); + _firstMaterial.SpecularColor.Z.Should().BeApproximately(0.3700f, Epsilon); + + _firstMaterial.SpecularCoefficient.Should().BeApproximately(32, Epsilon); + } + + [Test] + public void Sets_correct_transparency() + { + LoadMaterial(); + + _firstMaterial.Transparency.Should().BeApproximately(0.5f, Epsilon); + } + + [Test] + public void Sets_correct_illumination_model() + { + LoadMaterial(); + + _firstMaterial.IlluminationModel.Should().Be(2); + } + + [Test] + public void Sets_correct_texure_maps() + { + LoadMaterial(); + + _firstMaterial.AmbientTextureMap.Should().BeEquivalentTo("lenna1.tga"); + _firstMaterial.DiffuseTextureMap.Should().BeEquivalentTo("lenna2.tga"); + _firstMaterial.SpecularTextureMap.Should().BeEquivalentTo("lenna3.tga"); + _firstMaterial.SpecularHighlightTextureMap.Should().BeEquivalentTo("lenna_spec.tga"); + _firstMaterial.AlphaTextureMap.Should().BeEquivalentTo("lenna_alpha.tga"); + _firstMaterial.BumpMap.Should().BeEquivalentTo("lenna_bump.tga"); + _firstMaterial.DisplacementMap.Should().BeEquivalentTo("lenna_disp.tga"); + _firstMaterial.StencilDecalMap.Should().BeEquivalentTo("lenna_stencil.tga"); + } + + private void LoadMaterial() + { + var data = Encoding.ASCII.GetBytes(MaterialLibrary); + var materialStream = new MemoryStream(data); + + _materialLibraryLoader.Load(materialStream); + _firstMaterial = _materialLibrarySpy.Materials.First(); + _secondMaterial = _materialLibrarySpy.Materials.ElementAt(1); + } + + private const string MaterialLibrary = + "newmtl wire_134110008\r\n" + +"\tNs\t32\r\n" + +@"Tr 0.5 +illum 2 +Ka 1.0000 2.0000 3.0000 +Kd 0.5255 0.4314 0.0314 +Ks 0.3500 0.3600 0.3700 +map_Ka lenna1.tga +map_Kd lenna2.tga +map_Ks lenna3.tga +map_Ns lenna_spec.tga +map_d lenna_alpha.tga +map_bump lenna_bump.tga +disp lenna_disp.tga +decal lenna_stencil.tga +newmtl second_material"; + + private class MaterialLibrarySpy : IMaterialLibrary + { + public List Materials { get; private set; } + + public MaterialLibrarySpy() + { + Materials = new List(); + } + + public void Push(Material material) + { + Materials.Add(material); + } + } + } +} \ No newline at end of file diff --git a/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs b/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs new file mode 100644 index 0000000..eb3e441 --- /dev/null +++ b/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs @@ -0,0 +1,185 @@ +using System.IO; +using System.Text; +using NUnit.Framework; +using ObjLoader.Loader.Data.DataStore; +using ObjLoader.Loader.Loaders; +using ObjLoader.Loader.TypeParsers; +using System.Linq; +using FluentAssertions; + +namespace ObjLoader.Test.Loaders +{ + [TestFixture] + public class ObjLoaderTests + { + private class MaterialStreamProviderSpy : IMaterialStreamProvider + { + public string RequestedMaterialFilePath { get; private set; } + public Stream StreamToReturn { get; set; } + + public Stream Open(string materialFilePath) + { + RequestedMaterialFilePath = materialFilePath; + return StreamToReturn; + } + } + + private Loader.Loaders.ObjLoader _loader; + + private LoadResult _loadResult; + private DataStore _textureDataStore; + private FaceParser _faceParser; + private GroupParser _groupParser; + private NormalParser _normalParser; + private TextureParser _textureParser; + private VertexParser _vertexParser; + private MaterialLibraryLoader _materialLibraryLoader; + private MaterialLibraryParser _materialLibraryParser; + private UseMaterialParser _useMaterialParser; + private MaterialLibraryLoaderFacade _materialLibraryLoaderFacade; + private MaterialStreamProviderSpy _materialStreamProviderSpy; + + [SetUp] + public void SetUp() + { + _textureDataStore = new DataStore(); + + _faceParser = new FaceParser(_textureDataStore); + _groupParser = new GroupParser(_textureDataStore); + _normalParser = new NormalParser(_textureDataStore); + _textureParser = new TextureParser(_textureDataStore); + _vertexParser = new VertexParser(_textureDataStore); + _materialStreamProviderSpy = new MaterialStreamProviderSpy(); + _materialStreamProviderSpy.StreamToReturn = CreateMemoryStreamFromString(MaterialLibraryString); + + _materialLibraryLoader = new MaterialLibraryLoader(_textureDataStore); + _materialLibraryLoaderFacade = new MaterialLibraryLoaderFacade(_materialLibraryLoader, _materialStreamProviderSpy); + _materialLibraryParser = new MaterialLibraryParser(_materialLibraryLoaderFacade); + _useMaterialParser = new UseMaterialParser(_textureDataStore); + + _loader = new Loader.Loaders.ObjLoader(_textureDataStore, _faceParser, _groupParser, _normalParser, _textureParser, _vertexParser, _materialLibraryParser, _useMaterialParser); + } + + [Test] + public void Loads_object_and_material_correctly() + { + Load(); + + _loadResult.Vertices.Should().HaveCount(8); + _loadResult.Textures.Should().HaveCount(14); + _loadResult.Normals.Should().HaveCount(8); + _loadResult.Materials.Should().HaveCount(1); + + _materialStreamProviderSpy.RequestedMaterialFilePath.Should().BeEquivalentTo("cube.mtl"); + + _loadResult.Groups.Should().HaveCount(1); + + var group = _loadResult.Groups.First(); + group.Faces.Should().HaveCount(12); + 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, _materialStreamProviderSpy); + var materialLibraryParser = new MaterialLibraryParser(materialLibraryLoaderFacade); + + _loader = new Loader.Loaders.ObjLoader(_textureDataStore, _faceParser, _groupParser, _normalParser, _textureParser, _vertexParser, materialLibraryParser, _useMaterialParser); + + Load(); + + _loadResult.Vertices.Should().HaveCount(8); + _loadResult.Textures.Should().HaveCount(14); + _loadResult.Normals.Should().HaveCount(8); + _loadResult.Materials.Should().HaveCount(0); + + _loadResult.Groups.Should().HaveCount(1); + + var group = _loadResult.Groups.First(); + group.Faces.Should().HaveCount(12); + group.Material.Should().BeNull(); + } + + private void Load() + { + var objectStream = CreateMemoryStreamFromString(ObjectFileString); + + _loadResult = _loader.Load(objectStream); + } + + private Stream CreateMemoryStreamFromString(string str) + { + var data = Encoding.ASCII.GetBytes(str); + return new MemoryStream(data); + } + + private const string ObjectFileString = +"#Comment\r\n" + +"mtllib\tcube.mtl\r\n" + +@"v 1.000000 -1.000000 -1.000000 +v 1.000000 -1.000000 1.000000 +v -1.000000 -1.000000 1.000000 +v -1.000000 -1.000000 -1.000000 +v 1.000000 1.000000 -1.000000 +v 0.999999 1.000000 1.000001 +v -1.000000 1.000000 1.000000 +v -1.000000 1.000000 -1.000000 +vt 0.748573 0.750412 +vt 0.749279 0.501284 +vt 0.999110 0.501077 +vt 0.999455 0.750380 +vt 0.250471 0.500702 +vt 0.249682 0.749677 +vt 0.001085 0.750380 +vt 0.001517 0.499994 +vt 0.499422 0.500239 +vt 0.500149 0.750166 +vt 0.748355 0.998230 +vt 0.500193 0.998728 +vt 0.498993 0.250415 +vt 0.748953 0.250920 + + +vn 0.000000 0.000000 -1.000000 +vn -1.000000 -0.000000 -0.000000 +vn -0.000000 -0.000000 1.000000 +vn -0.000001 0.000000 1.000000 +vn 1.000000 -0.000000 0.000000 +vn 1.000000 0.000000 0.000001 +vn 0.000000 1.000000 -0.000000 +vn -0.000000 -1.000000 0.000000 +usemtl cube_material +s off +f 5/1/1 1/2/1 4/3/1 +f 5/1/1 4/3/1 8/4/1 +f 3/5/2 7/6/2 8/7/2 +f 3/5/2 8/7/2 4/8/2 +f 2/9/3 6/10/3 3/5/3 +f 6/10/4 7/6/4 3/5/4 +f 1/2/5 5/1/5 2/9/5 +f 5/1/6 6/10/6 2/9/6 +f 5/1/7 8/11/7 6/10/7 +f 8/11/7 7/12/7 6/10/7 +f 1/2/8 2/9/8 3/13/8 +f 1/2/8 3/13/8 4/14/8"; + + private const string MaterialLibraryString = +@"newmtl cube_material +Ns 32 +Tr 0.5 +illum 2 +Ka 1.0000 2.0000 3.0000 +Kd 0.5255 0.4314 0.0314 +Ks 0.3500 0.3600 0.3700 +map_Ka lenna1.tga +map_Kd lenna2.tga +map_Ks lenna3.tga +map_Ns lenna_spec.tga +map_d lenna_alpha.tga +map_bump lenna_bump.tga +disp lenna_disp.tga +decal lenna_stencil.tga"; + } +} \ No newline at end of file diff --git a/Tests/ObjLoader.Test/ObjLoader.Tests.csproj b/Tests/ObjLoader.Test/ObjLoader.Tests.csproj new file mode 100644 index 0000000..bf131cc --- /dev/null +++ b/Tests/ObjLoader.Test/ObjLoader.Tests.csproj @@ -0,0 +1,14 @@ + + + net8.0 + + + + + + + + + + + \ No newline at end of file diff --git a/Tests/ObjLoader.Test/TypeParsers/FaceParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/FaceParserTests.cs new file mode 100644 index 0000000..64ba447 --- /dev/null +++ b/Tests/ObjLoader.Test/TypeParsers/FaceParserTests.cs @@ -0,0 +1,147 @@ +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 +{ + [TestFixture] + public class FaceParserTests + { + private FaceGroupSpy _faceGroupSpy; + private FaceParser _faceParser; + + [SetUp] + public void SetUp() + { + _faceGroupSpy = new FaceGroupSpy(); + + _faceParser = new FaceParser(_faceGroupSpy); + } + + [Test] + public void CanParse_returns_true_on_face_line() + { + const string groupKeyword = "f"; + + bool canParse = _faceParser.CanParse(groupKeyword); + canParse.Should().BeTrue(); + } + + [Test] + public void CanParse_returns_false_on_non_normal_line() + { + const string invalidKeyword = "vt"; + + bool canParse = _faceParser.CanParse(invalidKeyword); + canParse.Should().BeFalse(); + } + + [Test] + public void Parses_normal_line_correctly_1() + { + const string faceLine = "1 2 3"; + _faceParser.Parse(faceLine); + + var parsedFace = _faceGroupSpy.ParsedFace; + + parsedFace[0].VertexIndex.Should().Be(1); + parsedFace[0].TextureIndex.Should().Be(0); + parsedFace[0].NormalIndex.Should().Be(0); + + parsedFace[1].VertexIndex.Should().Be(2); + parsedFace[1].TextureIndex.Should().Be(0); + parsedFace[1].NormalIndex.Should().Be(0); + + parsedFace[2].VertexIndex.Should().Be(3); + parsedFace[2].TextureIndex.Should().Be(0); + parsedFace[2].NormalIndex.Should().Be(0); + } + + [Test] + public void Parses_normal_line_correctly_2() + { + const string faceLine = "3/1 4/2 5/3"; + _faceParser.Parse(faceLine); + + var parsedFace = _faceGroupSpy.ParsedFace; + + parsedFace.Count.Should().Be(3); + + parsedFace[0].VertexIndex.Should().Be(3); + parsedFace[0].TextureIndex.Should().Be(1); + parsedFace[0].NormalIndex.Should().Be(0); + + parsedFace[1].VertexIndex.Should().Be(4); + parsedFace[1].TextureIndex.Should().Be(2); + parsedFace[1].NormalIndex.Should().Be(0); + + parsedFace[2].VertexIndex.Should().Be(5); + parsedFace[2].TextureIndex.Should().Be(3); + parsedFace[2].NormalIndex.Should().Be(0); + } + + [Test] + public void Parses_normal_line_correctly_3() + { + const string faceLine = "6/4/1 3/5/3 7/6/5"; + _faceParser.Parse(faceLine); + + var parsedFace = _faceGroupSpy.ParsedFace; + + parsedFace.Count.Should().Be(3); + + parsedFace[0].VertexIndex.Should().Be(6); + parsedFace[0].TextureIndex.Should().Be(4); + parsedFace[0].NormalIndex.Should().Be(1); + + parsedFace[1].VertexIndex.Should().Be(3); + parsedFace[1].TextureIndex.Should().Be(5); + parsedFace[1].NormalIndex.Should().Be(3); + + parsedFace[2].VertexIndex.Should().Be(7); + parsedFace[2].TextureIndex.Should().Be(6); + parsedFace[2].NormalIndex.Should().Be(5); + } + + [Test] + public void Parses_normal_line_correctly_4() + { + const string faceLine = "6//1 3//3 7//5"; + _faceParser.Parse(faceLine); + + var parsedFace = _faceGroupSpy.ParsedFace; + + parsedFace.Count.Should().Be(3); + + parsedFace[0].VertexIndex.Should().Be(6); + parsedFace[0].TextureIndex.Should().Be(0); + parsedFace[0].NormalIndex.Should().Be(1); + + parsedFace[1].VertexIndex.Should().Be(3); + parsedFace[1].TextureIndex.Should().Be(0); + parsedFace[1].NormalIndex.Should().Be(3); + + parsedFace[2].VertexIndex.Should().Be(7); + parsedFace[2].TextureIndex.Should().Be(0); + parsedFace[2].NormalIndex.Should().Be(5); + } + } + + public class FaceGroupSpy : IFaceGroup + { + public Face ParsedFace { get; private set; } + + public Face GetFace(int i) + { + throw new System.NotImplementedException(); + } + + public void AddFace(Face face) + { + ParsedFace = face; + } + } +} \ No newline at end of file diff --git a/Tests/ObjLoader.Test/TypeParsers/GroupParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/GroupParserTests.cs new file mode 100644 index 0000000..6b94478 --- /dev/null +++ b/Tests/ObjLoader.Test/TypeParsers/GroupParserTests.cs @@ -0,0 +1,61 @@ +using FluentAssertions; +using NUnit.Framework; +using ObjLoader.Loader.Data; +using ObjLoader.Loader.TypeParsers; +using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; + +namespace ObjLoader.Test.TypeParsers +{ + [TestFixture] + public class GroupParserTests + { + private GroupDataStoreMock _groupDataStoreMock; + private GroupParser _groupParser; + + [SetUp] + public void SetUp() + { + _groupDataStoreMock = new GroupDataStoreMock(); + + _groupParser = new GroupParser(_groupDataStoreMock); + } + + [Test] + public void CanParse_returns_true_on_normal_line() + { + const string groupKeyword = "g"; + + bool canParse = _groupParser.CanParse(groupKeyword); + canParse.Should().BeTrue(); + } + + [Test] + public void CanParse_returns_false_on_non_normal_line() + { + const string invalidKeyword = "vt"; + + bool canParse = _groupParser.CanParse(invalidKeyword); + canParse.Should().BeFalse(); + } + + [Test] + public void Parses_normal_line_correctly() + { + const string normalLine = "test group"; + _groupParser.Parse(normalLine); + + var parsedGroupName = _groupDataStoreMock.ParsedGroupName; + parsedGroupName.Should().Be("test group"); + } + } + + class GroupDataStoreMock : IGroupDataStore + { + public string ParsedGroupName { get; set; } + + public void PushGroup(string groupName) + { + ParsedGroupName = groupName; + } + } +} \ No newline at end of file diff --git a/Tests/ObjLoader.Test/TypeParsers/MaterialLibraryParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/MaterialLibraryParserTests.cs new file mode 100644 index 0000000..387e0db --- /dev/null +++ b/Tests/ObjLoader.Test/TypeParsers/MaterialLibraryParserTests.cs @@ -0,0 +1,58 @@ +using FluentAssertions; +using NUnit.Framework; +using ObjLoader.Loader.Loaders; +using ObjLoader.Loader.TypeParsers; + +namespace ObjLoader.Test.TypeParsers +{ + [TestFixture] + public class MaterialLibraryParserTests + { + private MaterialLibraryLoaderFacadeSpy _materialLibraryLoaderFacadeSpy; + private MaterialLibraryParser _parser; + + [SetUp] + public void SetUp() + { + _materialLibraryLoaderFacadeSpy = new MaterialLibraryLoaderFacadeSpy(); + _parser = new MaterialLibraryParser(_materialLibraryLoaderFacadeSpy); + } + + [Test] + public void CanParse_returns_true_on_mtlib_line() + { + const string groupKeyword = "mtllib"; + + bool canParse = _parser.CanParse(groupKeyword); + canParse.Should().BeTrue(); + } + + [Test] + public void CanParse_returns_false_on_non_mtlib_line() + { + const string invalidKeyword = "vt"; + + bool canParse = _parser.CanParse(invalidKeyword); + canParse.Should().BeFalse(); + } + + [Test] + public void Parses_mtlib_line_correctly() + { + const string faceLine = "cube.mtl"; + _parser.Parse(faceLine); + + _materialLibraryLoaderFacadeSpy.RequestedLoadFileName.Should().BeEquivalentTo("cube.mtl"); + } + + private class MaterialLibraryLoaderFacadeSpy : IMaterialLibraryLoaderFacade + { + public string RequestedLoadFileName { get; set; } + + public void Load(string materialFileName) + { + RequestedLoadFileName = materialFileName; + } + } + } +} \ No newline at end of file diff --git a/Tests/ObjLoader.Test/TypeParsers/NormalParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/NormalParserTests.cs new file mode 100644 index 0000000..90b12ae --- /dev/null +++ b/Tests/ObjLoader.Test/TypeParsers/NormalParserTests.cs @@ -0,0 +1,68 @@ +using FluentAssertions; +using NUnit.Framework; +using ObjLoader.Loader.TypeParsers; +using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; +using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; + +namespace ObjLoader.Test.TypeParsers +{ + [TestFixture] + public class NormalParserTests + { + private NormalParser _normalParser; + private NormalDataStoreMock _normalDataStoreMock; + + [SetUp] + public void SetUp() + { + _normalDataStoreMock = new NormalDataStoreMock(); + + _normalParser = new NormalParser(_normalDataStoreMock); + } + + [Test] + public void CanParse_returns_true_on_normal_line() + { + const string normalLine = "vn"; + + bool canParse = _normalParser.CanParse(normalLine); + canParse.Should().BeTrue(); + } + + [Test] + public void CanParse_returns_false_on_non_normal_line() + { + const string invalidNormal = "vt"; + + bool canParse = _normalParser.CanParse(invalidNormal); + canParse.Should().BeFalse(); + } + + [Test] + public void Parses_normal_line_correctly() + { + const string normalLine = "1.000000 2.000000 -1.000000"; + _normalParser.Parse(normalLine); + + var parsedNormal = _normalDataStoreMock.ParsedNormal; + parsedNormal.X.Should().BeApproximately(1, 0.000001f); + parsedNormal.Y.Should().BeApproximately(2, 0.000001f); + parsedNormal.Z.Should().BeApproximately(-1, 0.000001f); + } + } + + class NormalDataStoreMock : INormalDataStore + { + public Normal ParsedNormal { get; set; } + + public Normal GetNormal(int i) + { + throw new System.NotImplementedException(); + } + + public void AddNormal(Normal normal) + { + ParsedNormal = normal; + } + } +} \ No newline at end of file diff --git a/Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs new file mode 100644 index 0000000..4349771 --- /dev/null +++ b/Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs @@ -0,0 +1,67 @@ +using FluentAssertions; +using NUnit.Framework; +using ObjLoader.Loader.TypeParsers; +using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; +using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; + +namespace ObjLoader.Test.TypeParsers +{ + [TestFixture] + public class TextureParserTests + { + private TextureDataStoreMock _textureDataStoreMock; + private TextureParser _textureParser; + + [SetUp] + public void SetUp() + { + _textureDataStoreMock = new TextureDataStoreMock(); + + _textureParser = new TextureParser(_textureDataStoreMock); + } + + [Test] + public void CanParse_returns_true_on_normal_line() + { + const string textureKeyword = "vt"; + + bool canParse = _textureParser.CanParse(textureKeyword); + canParse.Should().BeTrue(); + } + + [Test] + public void CanParse_returns_false_on_non_normal_line() + { + const string invalidKeyword = "vn"; + + bool canParse = _textureParser.CanParse(invalidKeyword); + canParse.Should().BeFalse(); + } + + [Test] + public void Parses_normal_line_correctly() + { + const string textureLine = "0.500 -1.352"; + _textureParser.Parse(textureLine); + + var parsedNormal = _textureDataStoreMock.ParsedTexture; + parsedNormal.X.Should().BeApproximately(0.5f, 0.000001f); + parsedNormal.Y.Should().BeApproximately(-1.352f, 0.000001f); + } + + class TextureDataStoreMock : ITextureDataStore + { + public Texture ParsedTexture { get; private set; } + + public Texture GetTexture(int i) + { + throw new System.NotImplementedException(); + } + + public void AddTexture(Texture texture) + { + ParsedTexture = texture; + } + } + } +} \ No newline at end of file diff --git a/Tests/ObjLoader.Test/TypeParsers/UseMaterialParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/UseMaterialParserTests.cs new file mode 100644 index 0000000..b22345e --- /dev/null +++ b/Tests/ObjLoader.Test/TypeParsers/UseMaterialParserTests.cs @@ -0,0 +1,59 @@ +using FluentAssertions; +using NUnit.Framework; +using ObjLoader.Loader.Data; +using ObjLoader.Loader.Data.DataStore; +using ObjLoader.Loader.TypeParsers; + +namespace ObjLoader.Test.TypeParsers +{ + [TestFixture] + public class UseMaterialParserTests + { + private ElementGroupSpy _elementGroupSpy; + private UseMaterialParser _parser; + + [SetUp] + public void SetUp() + { + _elementGroupSpy = new ElementGroupSpy(); + _parser = new UseMaterialParser(_elementGroupSpy); + } + + [Test] + public void CanParse_returns_true_on_usemtl_line() + { + const string groupKeyword = "usemtl"; + + bool canParse = _parser.CanParse(groupKeyword); + canParse.Should().BeTrue(); + } + + [Test] + public void CanParse_returns_false_on_non_usemtl_line() + { + const string invalidKeyword = "vt"; + + bool canParse = _parser.CanParse(invalidKeyword); + canParse.Should().BeFalse(); + } + + [Test] + public void Parses_usemtl_line_correctly_1() + { + const string useMtlLine = "materialName"; + _parser.Parse(useMtlLine); + + _elementGroupSpy.MaterialName.Should().BeEquivalentTo("materialName"); + } + + private class ElementGroupSpy : IElementGroup + { + public string MaterialName { get; private set; } + + public void SetMaterial(string materialName) + { + MaterialName = materialName; + } + } + } +} \ No newline at end of file diff --git a/Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs new file mode 100644 index 0000000..5a4f180 --- /dev/null +++ b/Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs @@ -0,0 +1,69 @@ +using FluentAssertions; +using NUnit.Framework; +using ObjLoader.Loader.TypeParsers; +using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; +using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; + +namespace ObjLoader.Test.TypeParsers +{ + [TestFixture] + public class VertexParserTests + { + private VertexDataStoreMock _vertexDataStoreMock; + private VertexParser _vertexParser; + + [SetUp] + public void SetUp() + { + _vertexDataStoreMock = new VertexDataStoreMock(); + + _vertexParser = new VertexParser(_vertexDataStoreMock); + } + + [Test] + public void CanParse_returns_false_on_non_vertex_line() + { + const string invalidVertex = "vt"; + + bool canParse = _vertexParser.CanParse(invalidVertex); + canParse.Should().BeFalse(); + } + + [Test] + public void CanParse_returns_true_on_vertex_line() + { + const string vertexLine = "v"; + + bool canParse = _vertexParser.CanParse(vertexLine); + canParse.Should().BeTrue(); + } + + [Test] + public void Parses_vertex_line_correctly() + { + const string vertexLine = "0.123 0.234 0.345"; + _vertexParser.Parse(vertexLine); + + var parsedNormal = _vertexDataStoreMock.ParsedVertex; + parsedNormal.X.Should().BeApproximately(0.123f, 0.000001f); + parsedNormal.Y.Should().BeApproximately(0.234f, 0.000001f); + parsedNormal.Z.Should().BeApproximately(0.345f, 0.000001f); + } + + class VertexDataStoreMock : IVertexDataStore + { + public Vertex ParsedVertex { get; set; } + + public Vertex GetVertex(int i) + { + throw new System.NotImplementedException(); + } + + public void AddVertex(Vertex vertex) + { + ParsedVertex = vertex; + } + } + + } +} \ No newline at end of file diff --git a/Tests/SharpEngine.Core.Tests/Class1.cs b/Tests/SharpEngine.Core.Tests/Class1.cs new file mode 100644 index 0000000..ff34b98 --- /dev/null +++ b/Tests/SharpEngine.Core.Tests/Class1.cs @@ -0,0 +1,6 @@ +namespace SharpEngine.Core.Tests; + +public class Class1 +{ + +} diff --git a/Tests/SharpEngine.Core.Tests/SharpEngine.Core.Tests.csproj b/Tests/SharpEngine.Core.Tests/SharpEngine.Core.Tests.csproj new file mode 100644 index 0000000..fa71b7a --- /dev/null +++ b/Tests/SharpEngine.Core.Tests/SharpEngine.Core.Tests.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/Tests/SharpEngine.Editor.Tests/Class1.cs b/Tests/SharpEngine.Editor.Tests/Class1.cs new file mode 100644 index 0000000..2ae551d --- /dev/null +++ b/Tests/SharpEngine.Editor.Tests/Class1.cs @@ -0,0 +1,6 @@ +namespace SharpEngine.Editor.Tests; + +public class Class1 +{ + +} diff --git a/Tests/SharpEngine.Editor.Tests/SharpEngine.Editor.Tests.csproj b/Tests/SharpEngine.Editor.Tests/SharpEngine.Editor.Tests.csproj new file mode 100644 index 0000000..fa71b7a --- /dev/null +++ b/Tests/SharpEngine.Editor.Tests/SharpEngine.Editor.Tests.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/Tests/SharpEngine.Shared.Tests/Class1.cs b/Tests/SharpEngine.Shared.Tests/Class1.cs new file mode 100644 index 0000000..f2af683 --- /dev/null +++ b/Tests/SharpEngine.Shared.Tests/Class1.cs @@ -0,0 +1,6 @@ +namespace SharpEngine.Shared.Tests; + +public class Class1 +{ + +} diff --git a/Tests/SharpEngine.Shared.Tests/SharpEngine.Shared.Tests.csproj b/Tests/SharpEngine.Shared.Tests/SharpEngine.Shared.Tests.csproj new file mode 100644 index 0000000..fa71b7a --- /dev/null +++ b/Tests/SharpEngine.Shared.Tests/SharpEngine.Shared.Tests.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/Tests/Test.Directory.Build.props b/Tests/Test.Directory.Build.props new file mode 100644 index 0000000..a52359c --- /dev/null +++ b/Tests/Test.Directory.Build.props @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file From 9463f8f70530ae6533ceee32306435d908a6a2f4 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Thu, 10 Apr 2025 22:06:59 +0300 Subject: [PATCH 42/92] #2 Cleanup --- Examples/MinecraftClone/Minecraft.cs | 1 + ObjLoader/Loaders/LoaderBase.cs | 5 +- ObjLoader/Loaders/MaterialLibraryLoader.cs | 3 +- ObjLoader/Loaders/ObjLoader.cs | 42 ++- .../Properties/Meshes/MeshData/Group.cs | 12 +- SharpEngine.Core.Numerics/HashCodeHelper.cs | 4 +- SharpEngine.Core.Numerics/IVector.cs | 8 +- .../JitIntrinsicAttribute.cs | 2 - SharpEngine.Core.Numerics/Vector2.cs | 188 +++++-------- .../Vector2_Intrinsics.cs | 160 ++++------- SharpEngine.Core.Numerics/Vector3.cs | 262 +++++++----------- .../Vector3_Intrinsics.cs | 186 ++++++------- Tests/ObjLoader.Test/ObjLoader.Tests.csproj | 4 + 13 files changed, 355 insertions(+), 522 deletions(-) diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index 0f47fa7..7b970ce 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -155,6 +155,7 @@ private void InitializeWorld() var objLoader = objLoaderFactory.Create(); // TODO: There is a bug that an exception is thrown if no mtl file is not found. This should be just a warning. + // TODO: This should be able to load from an absolute and a relative path. var fileStream = new FileStream("Untitled2.obj", FileMode.Open); var result = objLoader.Load(fileStream); // var mesh = new Mesh() diff --git a/ObjLoader/Loaders/LoaderBase.cs b/ObjLoader/Loaders/LoaderBase.cs index 42f5bbc..0de39a2 100644 --- a/ObjLoader/Loaders/LoaderBase.cs +++ b/ObjLoader/Loaders/LoaderBase.cs @@ -20,7 +20,10 @@ private void ParseLine() { var currentLine = _lineStreamReader.ReadLine(); - if (string.IsNullOrWhiteSpace(currentLine) || currentLine[0] == '#') + if (string.IsNullOrWhiteSpace(currentLine)) + return; + + if (currentLine[0] == '#') return; var fields = currentLine.Trim().Split(null, 2); diff --git a/ObjLoader/Loaders/MaterialLibraryLoader.cs b/ObjLoader/Loaders/MaterialLibraryLoader.cs index 3e0a6e6..69362e6 100644 --- a/ObjLoader/Loaders/MaterialLibraryLoader.cs +++ b/ObjLoader/Loaders/MaterialLibraryLoader.cs @@ -49,6 +49,7 @@ public MaterialLibraryLoader(IMaterialLibrary materialLibrary) private void AddParseAction(string key, Action action) => _parseActionDictionary.Add(key.ToLowerInvariant(), action); + /// protected override void ParseLine(string keyword, string data) { var parseAction = GetKeywordAction(keyword); @@ -75,7 +76,7 @@ private void PushMaterial(string materialName) _materialLibrary.Push(CurrentMaterial); } - private Vector3 ParseVec3(string data) + private static Vector3 ParseVec3(string data) { string[] parts = data.Split(' '); diff --git a/ObjLoader/Loaders/ObjLoader.cs b/ObjLoader/Loaders/ObjLoader.cs index 9670ca4..f37115b 100644 --- a/ObjLoader/Loaders/ObjLoader.cs +++ b/ObjLoader/Loaders/ObjLoader.cs @@ -1,25 +1,25 @@ -using System.Collections.Generic; -using System.IO; -using ObjLoader.Loader.Data.DataStore; +using ObjLoader.Loader.Data.DataStore; using ObjLoader.Loader.TypeParsers.Interfaces; +using System.Collections.Generic; +using System.IO; namespace ObjLoader.Loader.Loaders { public class ObjLoader : LoaderBase, IObjLoader { private readonly IDataStore _dataStore; - private readonly List _typeParsers = new List(); + private readonly List _typeParsers = []; - private readonly List _unrecognizedLines = new List(); + private readonly List _unrecognizedLines = []; public ObjLoader( - IDataStore dataStore, - IFaceParser faceParser, + IDataStore dataStore, + IFaceParser faceParser, IGroupParser groupParser, - INormalParser normalParser, - ITextureParser textureParser, + INormalParser normalParser, + ITextureParser textureParser, IVertexParser vertexParser, - IMaterialLibraryParser materialLibraryParser, + IMaterialLibraryParser materialLibraryParser, IUseMaterialParser useMaterialParser) { _dataStore = dataStore; @@ -59,20 +59,14 @@ public LoadResult Load(Stream lineStream) { StartLoad(lineStream); - return CreateResult(); - } - - private LoadResult CreateResult() - { - var result = new LoadResult - { - Vertices = _dataStore.Vertices, - Textures = _dataStore.Textures, - Normals = _dataStore.Normals, - Groups = _dataStore.Groups, - Materials = _dataStore.Materials - }; - return result; + return new() + { + Vertices = _dataStore.Vertices, + Textures = _dataStore.Textures, + Normals = _dataStore.Normals, + Groups = _dataStore.Groups, + Materials = _dataStore.Materials + }; } } } \ 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 index 19d682f..fcabc14 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/MeshData/Group.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/MeshData/Group.cs @@ -1,12 +1,11 @@ using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; -using System.Collections.Generic; namespace ObjLoader.Loader.Data.Elements { public class Group : IFaceGroup { - private readonly List _faces = new List(); - + private readonly List _faces = []; + public Group(string name) { Name = name; @@ -15,11 +14,8 @@ public Group(string name) public string Name { get; private set; } public Material Material { get; set; } - public IList Faces { get { return _faces; } } + public IList Faces => _faces; - public void AddFace(Face face) - { - _faces.Add(face); - } + public void AddFace(Face face) => _faces.Add(face); } } \ No newline at end of file diff --git a/SharpEngine.Core.Numerics/HashCodeHelper.cs b/SharpEngine.Core.Numerics/HashCodeHelper.cs index 8731224..601d499 100644 --- a/SharpEngine.Core.Numerics/HashCodeHelper.cs +++ b/SharpEngine.Core.Numerics/HashCodeHelper.cs @@ -10,8 +10,6 @@ internal static class HashCodeHelper /// Combines two hash codes, useful for combining hash codes of individual vector elements /// internal static int CombineHashCodes(int h1, int h2) - { - return (((h1 << 5) + h1) ^ h2); - } + => (((h1 << 5) + h1) ^ h2); } } \ No newline at end of file diff --git a/SharpEngine.Core.Numerics/IVector.cs b/SharpEngine.Core.Numerics/IVector.cs index c581a9b..939cf80 100644 --- a/SharpEngine.Core.Numerics/IVector.cs +++ b/SharpEngine.Core.Numerics/IVector.cs @@ -1,6 +1,4 @@ -using System; - -namespace SharpEngine.Core.Numerics; +namespace SharpEngine.Core.Numerics; /// /// An abstraction of the different vector types. @@ -8,8 +6,8 @@ namespace SharpEngine.Core.Numerics; public interface IVector { /// - public Single X { get; set; } + float X { get; set; } /// - public Single Y { get; set; } + float Y { get; set; } } \ No newline at end of file diff --git a/SharpEngine.Core.Numerics/JitIntrinsicAttribute.cs b/SharpEngine.Core.Numerics/JitIntrinsicAttribute.cs index 0e53d20..0f6846a 100644 --- a/SharpEngine.Core.Numerics/JitIntrinsicAttribute.cs +++ b/SharpEngine.Core.Numerics/JitIntrinsicAttribute.cs @@ -2,8 +2,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // https://github.com/microsoft/referencesource/blob/master/System.Numerics/System/Numerics/JITIntrinsicAttribute.cs -using System; - namespace SharpEngine.Core.Numerics { /// diff --git a/SharpEngine.Core.Numerics/Vector2.cs b/SharpEngine.Core.Numerics/Vector2.cs index 70b52ef..0e94630 100644 --- a/SharpEngine.Core.Numerics/Vector2.cs +++ b/SharpEngine.Core.Numerics/Vector2.cs @@ -2,15 +2,13 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // https://github.com/microsoft/referencesource/blob/master/System.Numerics/System/Numerics/Vector2.cs -using System; using System.Globalization; using System.Runtime.CompilerServices; using System.Text; - -using Vector = System.Numerics.Vector; -using Matrix4x4 = System.Numerics.Matrix4x4; using Matrix3x2 = System.Numerics.Matrix3x2; +using Matrix4x4 = System.Numerics.Matrix4x4; using Quaternion = System.Numerics.Quaternion; +using Vector = System.Numerics.Vector; namespace SharpEngine.Core.Numerics { @@ -20,35 +18,29 @@ namespace SharpEngine.Core.Numerics public partial struct Vector2 : IEquatable, IFormattable { #region Public Static Properties - /// - /// Returns the vector (0,0). - /// + + /// Returns the vector (0,0). public static Vector2 Zero => new(); - /// - /// Returns the vector (1,1). - /// - public static Vector2 One => new Vector2(1.0f, 1.0f); - /// - /// Returns the vector (1,0). - /// - public static Vector2 UnitX { get { return new Vector2(1.0f, 0.0f); } } - /// - /// Returns the vector (0,1). - /// - public static Vector2 UnitY { get { return new Vector2(0.0f, 1.0f); } } + + /// Returns the vector (1,1). + public static Vector2 One => new(1.0f, 1.0f); + + /// Returns the vector (1,0). + public static Vector2 UnitX => new(1.0f, 0.0f); + + /// Returns the vector (0,1). + public static Vector2 UnitY => new(0.0f, 1.0f); + #endregion Public Static Properties #region Public instance methods + /// - /// Returns the hash code for this instance. + /// Returns the hash code for this instance. /// /// The hash code. - public override int GetHashCode() - { - int hash = this.X.GetHashCode(); - hash = HashCodeHelper.CombineHashCodes(hash, this.Y.GetHashCode()); - return hash; - } + public override readonly int GetHashCode() + => HashCodeHelper.CombineHashCodes(X.GetHashCode(), Y.GetHashCode()); /// /// Returns a boolean indicating whether the given Object is equal to this Vector2 instance. @@ -58,56 +50,51 @@ public override int GetHashCode() [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object? obj) { - if (obj is not Vector2) + if (obj is not Vector2 vec2) return false; - return Equals((Vector2)obj); + + return Equals(vec2); } /// - /// Returns a String representing this Vector2 instance. + /// Returns a String representing this Vector2 instance. /// /// The string representation. - public override string ToString() - { - return ToString("G", CultureInfo.CurrentCulture); - } + public override readonly string ToString() => ToString("G", CultureInfo.CurrentCulture); /// - /// Returns a String representing this Vector2 instance, using the specified format to format individual elements. + /// Returns a String representing this Vector2 instance, using the specified format to format individual elements. /// /// The format of individual elements. /// The string representation. - public string ToString(string format) - { - return ToString(format, CultureInfo.CurrentCulture); - } + public readonly string ToString(string format) => ToString(format, CultureInfo.CurrentCulture); /// - /// Returns a String representing this Vector2 instance, using the specified format to format individual elements - /// and the given IFormatProvider. + /// Returns a String representing this Vector2 instance, using the specified format to format individual elements + /// and the given IFormatProvider. /// /// The format of individual elements. /// The format provider to use when formatting elements. /// The string representation. - public string ToString(string? format, IFormatProvider? formatProvider) + public readonly string ToString(string? format, IFormatProvider? formatProvider) { - StringBuilder sb = new StringBuilder(); + var sb = new StringBuilder(); string separator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator; sb.Append('<'); - sb.Append(this.X.ToString(format, formatProvider)); + sb.Append(X.ToString(format, formatProvider)); sb.Append(separator); sb.Append(' '); - sb.Append(this.Y.ToString(format, formatProvider)); + sb.Append(Y.ToString(format, formatProvider)); sb.Append('>'); return sb.ToString(); } /// - /// Returns the length of the vector. + /// Returns the length of the vector. /// /// The vector's length. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public float Length() + public readonly float Length() { if (Vector.IsHardwareAccelerated) { @@ -116,26 +103,23 @@ public float Length() } else { - float ls = X * X + Y * Y; + float ls = (X * X) + (Y * Y); return MathF.Sqrt(ls); } } /// - /// Returns the length of the vector squared. This operation is cheaper than Length(). + /// Returns the length of the vector squared. This operation is cheaper than Length(). /// /// The vector's length squared. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public float LengthSquared() + public readonly float LengthSquared() { if (Vector.IsHardwareAccelerated) - { return Vector2.Dot(this, this); - } + else - { - return X * X + Y * Y; - } + return (X * X) + (Y * Y); } #endregion Public Instance Methods @@ -151,7 +135,7 @@ public static float Distance(Vector2 value1, Vector2 value2) { if (Vector.IsHardwareAccelerated) { - Vector2 difference = value1 - value2; + var difference = value1 - value2; float ls = Vector2.Dot(difference, difference); return (float)System.MathF.Sqrt(ls); } @@ -160,7 +144,7 @@ public static float Distance(Vector2 value1, Vector2 value2) float dx = value1.X - value2.X; float dy = value1.Y - value2.Y; - float ls = dx * dx + dy * dy; + float ls = (dx * dx) + (dy * dy); return MathF.Sqrt(ls); } @@ -177,7 +161,7 @@ public static float DistanceSquared(Vector2 value1, Vector2 value2) { if (Vector.IsHardwareAccelerated) { - Vector2 difference = value1 - value2; + var difference = value1 - value2; return Vector2.Dot(difference, difference); } else @@ -185,7 +169,7 @@ public static float DistanceSquared(Vector2 value1, Vector2 value2) float dx = value1.X - value2.X; float dy = value1.Y - value2.Y; - return dx * dx + dy * dy; + return (dx * dx) + (dy * dy); } } @@ -204,7 +188,7 @@ public static Vector2 Normalize(Vector2 value) } else { - float ls = value.X * value.X + value.Y * value.Y; + float ls = (value.X * value.X) + (value.Y * value.Y); float invNorm = 1.0f / MathF.Sqrt(ls); return new Vector2( @@ -229,11 +213,11 @@ public static Vector2 Reflect(Vector2 vector, Vector2 normal) } else { - float dot = vector.X * normal.X + vector.Y * normal.Y; + float dot = (vector.X * normal.X) + (vector.Y * normal.Y); return new Vector2( - vector.X - 2.0f * dot * normal.X, - vector.Y - 2.0f * dot * normal.Y); + vector.X - (2.0f * dot * normal.X), + vector.Y - (2.0f * dot * normal.Y)); } } @@ -270,8 +254,8 @@ public static Vector2 Clamp(Vector2 value1, Vector2 min, Vector2 max) public static Vector2 Lerp(Vector2 value1, Vector2 value2, float amount) { return new Vector2( - value1.X + (value2.X - value1.X) * amount, - value1.Y + (value2.Y - value1.Y) * amount); + value1.X + ((value2.X - value1.X) * amount), + value1.Y + ((value2.Y - value1.Y) * amount)); } /// @@ -284,8 +268,8 @@ public static Vector2 Lerp(Vector2 value1, Vector2 value2, float amount) public static Vector2 Transform(Vector2 position, Matrix3x2 matrix) { return new Vector2( - position.X * matrix.M11 + position.Y * matrix.M21 + matrix.M31, - position.X * matrix.M12 + position.Y * matrix.M22 + matrix.M32); + (position.X * matrix.M11) + (position.Y * matrix.M21) + matrix.M31, + (position.X * matrix.M12) + (position.Y * matrix.M22) + matrix.M32); } /// @@ -298,8 +282,8 @@ public static Vector2 Transform(Vector2 position, Matrix3x2 matrix) public static Vector2 Transform(Vector2 position, Matrix4x4 matrix) { return new Vector2( - position.X * matrix.M11 + position.Y * matrix.M21 + matrix.M41, - position.X * matrix.M12 + position.Y * matrix.M22 + matrix.M42); + (position.X * matrix.M11) + (position.Y * matrix.M21) + matrix.M41, + (position.X * matrix.M12) + (position.Y * matrix.M22) + matrix.M42); } /// @@ -312,8 +296,8 @@ public static Vector2 Transform(Vector2 position, Matrix4x4 matrix) public static Vector2 TransformNormal(Vector2 normal, Matrix3x2 matrix) { return new Vector2( - normal.X * matrix.M11 + normal.Y * matrix.M21, - normal.X * matrix.M12 + normal.Y * matrix.M22); + (normal.X * matrix.M11) + (normal.Y * matrix.M21), + (normal.X * matrix.M12) + (normal.Y * matrix.M22)); } /// @@ -326,8 +310,8 @@ public static Vector2 TransformNormal(Vector2 normal, Matrix3x2 matrix) public static Vector2 TransformNormal(Vector2 normal, Matrix4x4 matrix) { return new Vector2( - normal.X * matrix.M11 + normal.Y * matrix.M21, - normal.X * matrix.M12 + normal.Y * matrix.M22); + (normal.X * matrix.M11) + (normal.Y * matrix.M21), + (normal.X * matrix.M12) + (normal.Y * matrix.M22)); } /// @@ -350,8 +334,8 @@ public static Vector2 Transform(Vector2 value, Quaternion rotation) float zz2 = rotation.Z * z2; return new Vector2( - value.X * (1.0f - yy2 - zz2) + value.Y * (xy2 - wz2), - value.X * (xy2 + wz2) + value.Y * (1.0f - xx2 - zz2)); + (value.X * (1.0f - yy2 - zz2)) + (value.Y * (xy2 - wz2)), + (value.X * (xy2 + wz2)) + (value.Y * (1.0f - xx2 - zz2))); } #endregion Public Static Methods @@ -360,99 +344,75 @@ public static Vector2 Transform(Vector2 value, Quaternion rotation) // implemented over JIT intrinsics /// - /// Adds two vectors together. + /// Adds two vectors together. /// /// The first source vector. /// The second source vector. /// The summed vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 Add(Vector2 left, Vector2 right) - { - return left + right; - } + public static Vector2 Add(Vector2 left, Vector2 right) => left + right; /// - /// Subtracts the second vector from the first. + /// Subtracts the second vector from the first. /// /// The first source vector. /// The second source vector. /// The difference vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 Subtract(Vector2 left, Vector2 right) - { - return left - right; - } + public static Vector2 Subtract(Vector2 left, Vector2 right) => left - right; /// - /// Multiplies two vectors together. + /// Multiplies two vectors together. /// /// The first source vector. /// The second source vector. /// The product vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 Multiply(Vector2 left, Vector2 right) - { - return left * right; - } + public static Vector2 Multiply(Vector2 left, Vector2 right) => left * right; /// - /// Multiplies a vector by the given scalar. + /// Multiplies a vector by the given scalar. /// /// The source vector. /// The scalar value. /// The scaled vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 Multiply(Vector2 left, Single right) - { - return left * right; - } + public static Vector2 Multiply(Vector2 left, float right) => left * right; /// - /// Multiplies a vector by the given scalar. + /// Multiplies a vector by the given scalar. /// /// The scalar value. /// The source vector. /// The scaled vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 Multiply(Single left, Vector2 right) - { - return left * right; - } + public static Vector2 Multiply(float left, Vector2 right) => left * right; /// - /// Divides the first vector by the second. + /// Divides the first vector by the second. /// /// The first source vector. /// The second source vector. /// The vector resulting from the division. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 Divide(Vector2 left, Vector2 right) - { - return left / right; - } + public static Vector2 Divide(Vector2 left, Vector2 right) => left / right; /// - /// Divides the vector by the given scalar. + /// Divides the vector by the given scalar. /// /// The source vector. /// The scalar value. /// The result of the division. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 Divide(Vector2 left, Single divisor) - { - return left / divisor; - } + public static Vector2 Divide(Vector2 left, float divisor) => left / divisor; /// - /// Negates a given vector. + /// Negates a given vector. /// /// The source vector. /// The negated vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 Negate(Vector2 value) - { - return -value; - } + public static Vector2 Negate(Vector2 value) => -value; #endregion Public operator methods } diff --git a/SharpEngine.Core.Numerics/Vector2_Intrinsics.cs b/SharpEngine.Core.Numerics/Vector2_Intrinsics.cs index 2ac4fb6..3e56847 100644 --- a/SharpEngine.Core.Numerics/Vector2_Intrinsics.cs +++ b/SharpEngine.Core.Numerics/Vector2_Intrinsics.cs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using SharpEngine.Core.Numerics; -using System; using System.Runtime.CompilerServices; namespace SharpEngine.Core.Numerics @@ -14,88 +12,79 @@ namespace SharpEngine.Core.Numerics public partial struct Vector2 : IVector { - /// - /// The X component of the vector. - /// - public Single X { get; set; } + /// + public float X { get; set; } - /// - /// The Y component of the vector. - /// - public Single Y { get; set; } + /// + public float Y { get; set; } #region Constructors + /// - /// Constructs a vector whose elements are all the single specified value. + /// Constructs a vector whose elements are all the single specified value. /// /// The element to fill the vector with. [JitIntrinsic] - public Vector2(Single value) : this(value, value) { } + public Vector2(float value) : this(value, value) { } /// - /// Constructs a vector with the given individual elements. + /// Constructs a vector with the given individual elements. /// /// The X component. /// The Y component. [JitIntrinsic] - public Vector2(Single x, Single y) + public Vector2(float x, float y) { X = x; Y = y; } + #endregion Constructors #region Public Instance Methods /// - /// Copies the contents of the vector into the given array. + /// Copies the contents of the vector into the given array. /// /// The destination array. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyTo(Single[] array) - { - CopyTo(array, 0); - } + public void CopyTo(float[] array) => CopyTo(array, 0); /// - /// Copies the contents of the vector into the given array, starting from the given index. + /// Copies the contents of the vector into the given array, starting from the given index. /// /// If array is null. /// If array is multidimensional. /// If index is greater than end of the array or index is less than zero. /// If number of elements in source vector is greater than those available in destination array /// or if there are not enough elements to copy. - public void CopyTo(Single[] array, int index) + public readonly void CopyTo(float[] array, int index) { + // Match the JIT's exception type here. For perf, a NullReference is thrown instead of an ArgumentNull. if (array == null) - { - // Match the JIT's exception type here. For perf, a NullReference is thrown instead of an ArgumentNull. throw new NullReferenceException(); - } + if (index < 0 || index >= array.Length) - { throw new ArgumentOutOfRangeException(nameof(index)); - } + if ((array.Length - index) < 2) - { throw new ArgumentException(nameof(index)); - } + array[index] = X; array[index + 1] = Y; } /// - /// Returns a boolean indicating whether the given Vector2 is equal to this Vector2 instance. + /// Returns a boolean indicating whether the given Vector2 is equal to this Vector2 instance. /// /// The Vector2 to compare this instance to. /// True if the other Vector2 is equal to this instance; False otherwise. [JitIntrinsic] - public bool Equals(Vector2 other) - { - return this.X == other.X && this.Y == other.Y; - } + public bool Equals(Vector2 other) => X == other.X && Y == other.Y; + #endregion Public Instance Methods #region Public Static Methods + /// /// Returns the dot product of two vectors. /// @@ -105,10 +94,7 @@ public bool Equals(Vector2 other) [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Dot(Vector2 value1, Vector2 value2) - { - return value1.X * value2.X + - value1.Y * value2.Y; - } + => (value1.X * value2.X) + (value1.Y * value2.Y); /// /// Returns a vector whose elements are the minimum of each of the pairs of elements in the two source vectors. @@ -120,13 +106,14 @@ public static float Dot(Vector2 value1, Vector2 value2) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Min(Vector2 value1, Vector2 value2) { - return new Vector2( - (value1.X < value2.X) ? value1.X : value2.X, - (value1.Y < value2.Y) ? value1.Y : value2.Y); + var x = (value1.X < value2.X) ? value1.X : value2.X; + var y = (value1.Y < value2.Y) ? value1.Y : value2.Y; + + return new Vector2(x, y); } /// - /// Returns a vector whose elements are the maximum of each of the pairs of elements in the two source vectors + /// Returns a vector whose elements are the maximum of each of the pairs of elements in the two source vectors /// /// The first source vector /// The second source vector @@ -135,49 +122,43 @@ public static Vector2 Min(Vector2 value1, Vector2 value2) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Max(Vector2 value1, Vector2 value2) { - return new Vector2( - (value1.X > value2.X) ? value1.X : value2.X, - (value1.Y > value2.Y) ? value1.Y : value2.Y); + var x = (value1.X > value2.X) ? value1.X : value2.X; + var y = (value1.Y > value2.Y) ? value1.Y : value2.Y; + + return new Vector2(x, y); } /// - /// Returns a vector whose elements are the absolute values of each of the source vector's elements. + /// Returns a vector whose elements are the absolute values of each of the source vector's elements. /// /// The source vector. /// The absolute value vector. [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 Abs(Vector2 value) - { - return new Vector2(MathF.Abs(value.X), MathF.Abs(value.Y)); - } + public static Vector2 Abs(Vector2 value) => new(MathF.Abs(value.X), MathF.Abs(value.Y)); /// - /// Returns a vector whose elements are the square root of each of the source vector's elements. + /// Returns a vector whose elements are the square root of each of the source vector's elements. /// /// The source vector. /// The square root vector. [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 SquareRoot(Vector2 value) - { - return new Vector2((Single)MathF.Sqrt(value.X), (Single)MathF.Sqrt(value.Y)); - } + public static Vector2 SquareRoot(Vector2 value) => new((float)MathF.Sqrt(value.X), (float)MathF.Sqrt(value.Y)); + #endregion Public Static Methods #region Public Static Operators + /// - /// Adds two vectors together. + /// Adds two vectors together. /// /// The first source vector. /// The second source vector. /// The summed vector. [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 operator +(Vector2 left, Vector2 right) - { - return new Vector2(left.X + right.X, left.Y + right.Y); - } + public static Vector2 operator +(Vector2 left, Vector2 right) => new(left.X + right.X, left.Y + right.Y); /// /// Subtracts the second vector from the first. @@ -187,65 +168,50 @@ public static Vector2 SquareRoot(Vector2 value) /// The difference vector. [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 operator -(Vector2 left, Vector2 right) - { - return new Vector2(left.X - right.X, left.Y - right.Y); - } + public static Vector2 operator -(Vector2 left, Vector2 right) => new(left.X - right.X, left.Y - right.Y); /// - /// Multiplies two vectors together. + /// Multiplies two vectors together. /// /// The first source vector. /// The second source vector. /// The product vector. [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 operator *(Vector2 left, Vector2 right) - { - return new Vector2(left.X * right.X, left.Y * right.Y); - } + public static Vector2 operator *(Vector2 left, Vector2 right) => new(left.X * right.X, left.Y * right.Y); /// - /// Multiplies a vector by the given scalar. + /// Multiplies a vector by the given scalar. /// /// The scalar value. /// The source vector. /// The scaled vector. [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 operator *(Single left, Vector2 right) - { - return new Vector2(left, left) * right; - } + public static Vector2 operator *(float left, Vector2 right) => new Vector2(left, left) * right; /// - /// Multiplies a vector by the given scalar. + /// Multiplies a vector by the given scalar. /// /// The source vector. /// The scalar value. /// The scaled vector. [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 operator *(Vector2 left, Single right) - { - return left * new Vector2(right, right); - } + public static Vector2 operator *(Vector2 left, float right) => left * new Vector2(right, right); /// - /// Divides the first vector by the second. + /// Divides the first vector by the second. /// /// The first source vector. /// The second source vector. /// The vector resulting from the division. [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 operator /(Vector2 left, Vector2 right) - { - return new Vector2(left.X / right.X, left.Y / right.Y); - } + public static Vector2 operator /(Vector2 left, Vector2 right) => new(left.X / right.X, left.Y / right.Y); /// - /// Divides the vector by the given scalar. + /// Divides the vector by the given scalar. /// /// The source vector. /// The scalar value. @@ -255,45 +221,35 @@ public static Vector2 SquareRoot(Vector2 value) public static Vector2 operator /(Vector2 value1, float value2) { float invDiv = 1.0f / value2; - return new Vector2( - value1.X * invDiv, - value1.Y * invDiv); + + return new Vector2(value1.X * invDiv, value1.Y * invDiv); } /// - /// Negates a given vector. + /// Negates a given vector. /// /// The source vector. /// The negated vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 operator -(Vector2 value) - { - return Zero - value; - } + public static Vector2 operator -(Vector2 value) => Zero - value; /// - /// Returns a boolean indicating whether the two given vectors are equal. + /// Returns a boolean indicating whether the two given vectors are equal. /// /// The first vector to compare. /// The second vector to compare. /// True if the vectors are equal; False otherwise. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Vector2 left, Vector2 right) - { - return left.Equals(right); - } + public static bool operator ==(Vector2 left, Vector2 right) => left.Equals(right); /// - /// Returns a boolean indicating whether the two given vectors are not equal. + /// Returns a boolean indicating whether the two given vectors are not equal. /// /// The first vector to compare. /// The second vector to compare. /// True if the vectors are not equal; False if they are equal. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Vector2 left, Vector2 right) - { - return !(left == right); - } + public static bool operator !=(Vector2 left, Vector2 right) => !(left == right); /// /// Converts the SharpEngine representation to a System.Numerics representation. diff --git a/SharpEngine.Core.Numerics/Vector3.cs b/SharpEngine.Core.Numerics/Vector3.cs index f34601a..da6f282 100644 --- a/SharpEngine.Core.Numerics/Vector3.cs +++ b/SharpEngine.Core.Numerics/Vector3.cs @@ -2,14 +2,12 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // https://github.com/microsoft/referencesource/blob/master/System.Numerics/System/Numerics/Vector3.cs -using System; using System.Globalization; using System.Runtime.CompilerServices; using System.Text; - -using Vector = System.Numerics.Vector; using Matrix4x4 = System.Numerics.Matrix4x4; using Quaternion = System.Numerics.Quaternion; +using Vector = System.Numerics.Vector; namespace SharpEngine.Core.Numerics { @@ -19,137 +17,126 @@ namespace SharpEngine.Core.Numerics public partial struct Vector3 : IEquatable, IFormattable { #region Public Static Properties - /// - /// Returns the vector (0,0,0). - /// - public static Vector3 Zero { get { return new Vector3(); } } - /// - /// Returns the vector (1,1,1). - /// - public static Vector3 One { get { return new Vector3(1.0f, 1.0f, 1.0f); } } - /// - /// Returns the vector (1,0,0). - /// - public static Vector3 UnitX { get { return new Vector3(1.0f, 0.0f, 0.0f); } } - /// - /// Returns the vector (0,1,0). - /// - public static Vector3 UnitY { get { return new Vector3(0.0f, 1.0f, 0.0f); } } - /// - /// Returns the vector (0,0,1). - /// - public static Vector3 UnitZ { get { return new Vector3(0.0f, 0.0f, 1.0f); } } + + /// Returns the vector (0,0,0). + public static Vector3 Zero => new(); + + /// Returns the vector (1,1,1). + public static Vector3 One => new(1.0f, 1.0f, 1.0f); + + /// Returns the vector (1,0,0). + public static Vector3 UnitX => new(1.0f, 0.0f, 0.0f); + + /// Returns the vector (0,1,0). + public static Vector3 UnitY => new(0.0f, 1.0f, 0.0f); + + /// Returns the vector (0,0,1). + public static Vector3 UnitZ => new(0.0f, 0.0f, 1.0f); + #endregion Public Static Properties #region Public Instance Methods /// - /// Returns the hash code for this instance. + /// Returns the hash code for this instance. /// /// The hash code. - public override int GetHashCode() + public override readonly int GetHashCode() { - int hash = this.X.GetHashCode(); - hash = HashCodeHelper.CombineHashCodes(hash, this.Y.GetHashCode()); - hash = HashCodeHelper.CombineHashCodes(hash, this.Z.GetHashCode()); + int hash = X.GetHashCode(); + hash = HashCodeHelper.CombineHashCodes(hash, Y.GetHashCode()); + hash = HashCodeHelper.CombineHashCodes(hash, Z.GetHashCode()); return hash; } /// - /// Returns a boolean indicating whether the given Object is equal to this Vector3 instance. + /// Returns a boolean indicating whether the given Object is equal to this Vector3 instance. /// /// The Object to compare against. /// True if the Object is equal to this Vector3; False otherwise. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override bool Equals(object? obj) + public override readonly bool Equals(object? obj) { - if (!(obj is Vector3)) + if (obj is not Vector3 vec3) return false; - return Equals((Vector3)obj); + + return Equals(vec3); } /// - /// Returns a String representing this Vector3 instance. + /// Returns a String representing this Vector3 instance. /// /// The string representation. - public override string ToString() - { - return ToString("G", CultureInfo.CurrentCulture); - } + public override readonly string ToString() => ToString("G", CultureInfo.CurrentCulture); /// - /// Returns a String representing this Vector3 instance, using the specified format to format individual elements. + /// Returns a String representing this Vector3 instance, using the specified format to format individual elements. /// /// The format of individual elements. /// The string representation. - public string ToString(string format) - { - return ToString(format, CultureInfo.CurrentCulture); - } + public readonly string ToString(string format) => ToString(format, CultureInfo.CurrentCulture); /// - /// Returns a String representing this Vector3 instance, using the specified format to format individual elements - /// and the given IFormatProvider. + /// Returns a String representing this Vector3 instance, using the specified format to format individual elements + /// and the given IFormatProvider. /// /// The format of individual elements. /// The format provider to use when formatting elements. /// The string representation. - public string ToString(string? format, IFormatProvider? formatProvider) + public readonly string ToString(string? format, IFormatProvider? formatProvider) { - StringBuilder sb = new StringBuilder(); + var sb = new StringBuilder(); string separator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator; sb.Append('<'); - sb.Append(((IFormattable)this.X).ToString(format, formatProvider)); + sb.Append(X.ToString(format, formatProvider)); sb.Append(separator); sb.Append(' '); - sb.Append(((IFormattable)this.Y).ToString(format, formatProvider)); + sb.Append(Y.ToString(format, formatProvider)); sb.Append(separator); sb.Append(' '); - sb.Append(((IFormattable)this.Z).ToString(format, formatProvider)); + sb.Append(Z.ToString(format, formatProvider)); sb.Append('>'); return sb.ToString(); } /// - /// Returns the length of the vector. + /// Returns the length of the vector. /// /// The vector's length. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public float Length() + public readonly float Length() { if (Vector.IsHardwareAccelerated) { float ls = Vector3.Dot(this, this); - return (float)System.Math.Sqrt(ls); + return System.MathF.Sqrt(ls); } else { - float ls = X * X + Y * Y + Z * Z; - return (float)System.Math.Sqrt(ls); + float ls = (X * X) + (Y * Y) + (Z * Z); + return System.MathF.Sqrt(ls); } } /// - /// Returns the length of the vector squared. This operation is cheaper than Length(). + /// Returns the length of the vector squared. This operation is cheaper than Length(). /// /// The vector's length squared. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public float LengthSquared() + public readonly float LengthSquared() { if (Vector.IsHardwareAccelerated) - { return Vector3.Dot(this, this); - } else - { - return X * X + Y * Y + Z * Z; - } + return (X * X) + (Y * Y) + (Z * Z); } + #endregion Public Instance Methods #region Public Static Methods + /// - /// Returns the Euclidean distance between the two given points. + /// Returns the Euclidean distance between the two given points. /// /// The first point. /// The second point. @@ -159,9 +146,9 @@ public static float Distance(Vector3 value1, Vector3 value2) { if (Vector.IsHardwareAccelerated) { - Vector3 difference = value1 - value2; + var difference = value1 - value2; float ls = Vector3.Dot(difference, difference); - return (float)System.Math.Sqrt(ls); + return System.MathF.Sqrt(ls); } else { @@ -169,14 +156,14 @@ public static float Distance(Vector3 value1, Vector3 value2) float dy = value1.Y - value2.Y; float dz = value1.Z - value2.Z; - float ls = dx * dx + dy * dy + dz * dz; + float ls = (dx * dx) + (dy * dy) + (dz * dz); - return (float)System.Math.Sqrt((double)ls); + return System.MathF.Sqrt(ls); } } /// - /// Returns the Euclidean distance squared between the two given points. + /// Returns the Euclidean distance squared between the two given points. /// /// The first point. /// The second point. @@ -186,21 +173,19 @@ public static float DistanceSquared(Vector3 value1, Vector3 value2) { if (Vector.IsHardwareAccelerated) { - Vector3 difference = value1 - value2; + var difference = value1 - value2; return Vector3.Dot(difference, difference); } - else - { - float dx = value1.X - value2.X; - float dy = value1.Y - value2.Y; - float dz = value1.Z - value2.Z; - return dx * dx + dy * dy + dz * dz; - } + float dx = value1.X - value2.X; + float dy = value1.Y - value2.Y; + float dz = value1.Z - value2.Z; + + return (dx * dx) + (dy * dy) + (dz * dz); } /// - /// Returns a vector with the same direction as the given vector, but with a length of 1. + /// Returns a vector with the same direction as the given vector, but with a length of 1. /// /// The vector to normalize. /// The normalized vector. @@ -214,29 +199,26 @@ public static Vector3 Normalize(Vector3 value) } else { - float ls = value.X * value.X + value.Y * value.Y + value.Z * value.Z; + float ls = (value.X * value.X) + (value.Y * value.Y) + (value.Z * value.Z); float length = (float)System.Math.Sqrt(ls); return new Vector3(value.X / length, value.Y / length, value.Z / length); } } /// - /// Computes the cross product of two vectors. + /// Computes the cross product of two vectors. /// /// The first vector. /// The second vector. /// The cross product. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Cross(Vector3 vector1, Vector3 vector2) - { - return new Vector3( - vector1.Y * vector2.Z - vector1.Z * vector2.Y, - vector1.Z * vector2.X - vector1.X * vector2.Z, - vector1.X * vector2.Y - vector1.Y * vector2.X); - } + => new((vector1.Y * vector2.Z) - (vector1.Z * vector2.Y), + (vector1.Z * vector2.X) - (vector1.X * vector2.Z), + (vector1.X * vector2.Y) - (vector1.Y * vector2.X)); /// - /// Returns the reflection of a vector off a surface that has the specified normal. + /// Returns the reflection of a vector off a surface that has the specified normal. /// /// The source vector. /// The normal of the surface being reflected off. @@ -244,15 +226,15 @@ public static Vector3 Cross(Vector3 vector1, Vector3 vector2) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Reflect(Vector3 vector, Vector3 normal) { - if (System.Numerics.Vector.IsHardwareAccelerated) + if (Vector.IsHardwareAccelerated) { float dot = Vector3.Dot(vector, normal); - Vector3 temp = normal * dot * 2f; + var temp = normal * dot * 2f; return vector - temp; } else { - float dot = vector.X * normal.X + vector.Y * normal.Y + vector.Z * normal.Z; + float dot = (vector.X * normal.X) + (vector.Y * normal.Y) + (vector.Z * normal.Z); float tempX = normal.X * dot * 2f; float tempY = normal.Y * dot * 2f; float tempZ = normal.Z * dot * 2f; @@ -261,7 +243,7 @@ public static Vector3 Reflect(Vector3 vector, Vector3 normal) } /// - /// Restricts a vector between a min and max value. + /// Restricts a vector between a min and max value. /// /// The source vector. /// The minimum value. @@ -289,7 +271,7 @@ public static Vector3 Clamp(Vector3 value1, Vector3 min, Vector3 max) } /// - /// Linearly interpolates between two vectors based on the given weighting. + /// Linearly interpolates between two vectors based on the given weighting. /// /// The first source vector. /// The second source vector. @@ -300,51 +282,42 @@ public static Vector3 Lerp(Vector3 value1, Vector3 value2, float amount) { if (Vector.IsHardwareAccelerated) { - Vector3 firstInfluence = value1 * (1f - amount); - Vector3 secondInfluence = value2 * amount; + var firstInfluence = value1 * (1f - amount); + var secondInfluence = value2 * amount; return firstInfluence + secondInfluence; } - else - { - return new Vector3( - value1.X + (value2.X - value1.X) * amount, - value1.Y + (value2.Y - value1.Y) * amount, - value1.Z + (value2.Z - value1.Z) * amount); - } + + return new Vector3(value1.X + ((value2.X - value1.X) * amount), + value1.Y + ((value2.Y - value1.Y) * amount), + value1.Z + ((value2.Z - value1.Z) * amount)); } /// - /// Transforms a vector by the given matrix. + /// Transforms a vector by the given matrix. /// /// The source vector. /// The transformation matrix. /// The transformed vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Transform(Vector3 position, Matrix4x4 matrix) - { - return new Vector3( - position.X * matrix.M11 + position.Y * matrix.M21 + position.Z * matrix.M31 + matrix.M41, - 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); - } + => new((position.X * matrix.M11) + (position.Y * matrix.M21) + (position.Z * matrix.M31) + matrix.M41, + (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. + /// 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) - { - return new Vector3( - 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); - } + => 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. + /// Transforms a vector by the given Quaternion rotation value. /// /// The source vector to be rotated. /// The rotation to apply. @@ -367,9 +340,9 @@ public static Vector3 Transform(Vector3 value, Quaternion rotation) float zz2 = rotation.Z * z2; return new Vector3( - value.X * (1.0f - yy2 - zz2) + value.Y * (xy2 - wz2) + value.Z * (xz2 + wy2), - 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)); + (value.X * (1.0f - yy2 - zz2)) + (value.Y * (xy2 - wz2)) + (value.Z * (xz2 + wy2)), + (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))); } #endregion Public Static Methods @@ -379,64 +352,49 @@ public static Vector3 Transform(Vector3 value, Quaternion rotation) // over JIT intrinsics /// - /// Adds two vectors together. + /// Adds two vectors together. /// /// The first source vector. /// The second source vector. /// The summed vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 Add(Vector3 left, Vector3 right) - { - return left + right; - } + public static Vector3 Add(Vector3 left, Vector3 right) => left + right; /// - /// Subtracts the second vector from the first. + /// Subtracts the second vector from the first. /// /// The first source vector. /// The second source vector. /// The difference vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 Subtract(Vector3 left, Vector3 right) - { - return left - right; - } + public static Vector3 Subtract(Vector3 left, Vector3 right) => left - right; /// - /// Multiplies two vectors together. + /// Multiplies two vectors together. /// /// The first source vector. /// The second source vector. /// The product vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 Multiply(Vector3 left, Vector3 right) - { - return left * right; - } + public static Vector3 Multiply(Vector3 left, Vector3 right) => left * right; /// - /// Multiplies a vector by the given scalar. + /// Multiplies a vector by the given scalar. /// /// The source vector. /// The scalar value. /// The scaled vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 Multiply(Vector3 left, Single right) - { - return left * right; - } + public static Vector3 Multiply(Vector3 left, float right) => left * right; /// - /// Multiplies a vector by the given scalar. + /// Multiplies a vector by the given scalar. /// /// The scalar value. /// The source vector. /// The scaled vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 Multiply(Single left, Vector3 right) - { - return left * right; - } + public static Vector3 Multiply(float left, Vector3 right) => left * right; /// /// Divides the first vector by the second. @@ -445,33 +403,25 @@ public static Vector3 Multiply(Single left, Vector3 right) /// The second source vector. /// The vector resulting from the division. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 Divide(Vector3 left, Vector3 right) - { - return left / right; - } + public static Vector3 Divide(Vector3 left, Vector3 right) => left / right; /// - /// Divides the vector by the given scalar. + /// Divides the vector by the given scalar. /// /// The source vector. /// The scalar value. /// The result of the division. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 Divide(Vector3 left, Single divisor) - { - return left / divisor; - } + public static Vector3 Divide(Vector3 left, float divisor) => left / divisor; /// - /// Negates a given vector. + /// Negates a given vector. /// /// The source vector. /// The negated vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 Negate(Vector3 value) - { - return -value; - } + public static Vector3 Negate(Vector3 value) => -value; + #endregion Public operator methods } } \ No newline at end of file diff --git a/SharpEngine.Core.Numerics/Vector3_Intrinsics.cs b/SharpEngine.Core.Numerics/Vector3_Intrinsics.cs index 5cccbcc..70f5f06 100644 --- a/SharpEngine.Core.Numerics/Vector3_Intrinsics.cs +++ b/SharpEngine.Core.Numerics/Vector3_Intrinsics.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; using System.Runtime.CompilerServices; namespace SharpEngine.Core.Numerics @@ -14,63 +13,57 @@ namespace SharpEngine.Core.Numerics public partial struct Vector3 : IVector { - /// - /// The X component of the vector. - /// - public Single X { get; set; } - - /// - /// The Y component of the vector. - /// - public Single Y { get; set; } - - /// - /// The Z component of the vector. - /// - public Single Z { get; set; } + /// + public float X { get; set; } + + /// + public float Y { get; set; } + + /// + public float Z { get; set; } #region Constructors + /// - /// Constructs a vector whose elements are all the single specified value. + /// Constructs a vector whose elements are all the single specified value. /// /// The element to fill the vector with. [JitIntrinsic] - public Vector3(Single value) : this(value, value, value) { } + public Vector3(float value) : this(value, value, value) { } /// - /// Constructs a Vector3 from the given Vector2 and a third value. + /// Constructs a Vector3 from the given Vector2 and a third value. /// /// The Vector to extract X and Y components from. /// The Z component. public Vector3(Vector2 value, float z) : this(value.X, value.Y, z) { } /// - /// Constructs a vector with the given individual elements. + /// Constructs a vector with the given individual elements. /// /// The X component. /// The Y component. /// The Z component. [JitIntrinsic] - public Vector3(Single x, Single y, Single z) + public Vector3(float x, float y, float z) { X = x; Y = y; Z = z; } + #endregion Constructors #region Public Instance Methods + /// - /// Copies the contents of the vector into the given array. + /// Copies the contents of the vector into the given array. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyTo(Single[] array) - { - CopyTo(array, 0); - } + public readonly void CopyTo(float[] array) => CopyTo(array, 0); /// - /// Copies the contents of the vector into the given array, starting from index. + /// Copies the contents of the vector into the given array, starting from index. /// /// If array is null. /// If array is multidimensional. @@ -78,21 +71,17 @@ public void CopyTo(Single[] array) /// If number of elements in source vector is greater than those available in destination array. [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyTo(Single[] array, int index) + public readonly void CopyTo(float[] array, int index) { + // Match the JIT's exception type here. For perf, a NullReference is thrown instead of an ArgumentNull. if (array == null) - { - // Match the JIT's exception type here. For perf, a NullReference is thrown instead of an ArgumentNull. throw new NullReferenceException(); - } + if (index < 0 || index >= array.Length) - { throw new ArgumentOutOfRangeException(nameof(index)); - } + if ((array.Length - index) < 3) - { throw new ArgumentException("", nameof(index)); - } array[index] = X; array[index + 1] = Y; @@ -100,22 +89,24 @@ public void CopyTo(Single[] array, int index) } /// - /// Returns a boolean indicating whether the given Vector3 is equal to this Vector3 instance. + /// Returns a boolean indicating whether the given Vector3 is equal to this Vector3 instance. /// /// The Vector3 to compare this instance to. /// True if the other Vector3 is equal to this instance; False otherwise. [JitIntrinsic] - public bool Equals(Vector3 other) + public readonly bool Equals(Vector3 other) { return X == other.X && Y == other.Y && Z == other.Z; } + #endregion Public Instance Methods #region Public Static Methods + /// - /// Returns the dot product of two vectors. + /// Returns the dot product of two vectors. /// /// The first vector. /// The second vector. @@ -124,28 +115,25 @@ public bool Equals(Vector3 other) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Dot(Vector3 vector1, Vector3 vector2) { - return vector1.X * vector2.X + - vector1.Y * vector2.Y + - vector1.Z * vector2.Z; + return (vector1.X * vector2.X) + + (vector1.Y * vector2.Y) + + (vector1.Z * vector2.Z); } /// - /// Returns a vector whose elements are the minimum of each of the pairs of elements in the two source vectors. + /// Returns a vector whose elements are the minimum of each of the pairs of elements in the two source vectors. /// /// The first source vector. /// The second source vector. /// The minimized vector. [JitIntrinsic] public static Vector3 Min(Vector3 value1, Vector3 value2) - { - return new Vector3( - (value1.X < value2.X) ? value1.X : value2.X, - (value1.Y < value2.Y) ? value1.Y : value2.Y, - (value1.Z < value2.Z) ? value1.Z : value2.Z); - } + => new((value1.X < value2.X) ? value1.X : value2.X, + (value1.Y < value2.Y) ? value1.Y : value2.Y, + (value1.Z < value2.Z) ? value1.Z : value2.Z); /// - /// Returns a vector whose elements are the maximum of each of the pairs of elements in the two source vectors. + /// Returns a vector whose elements are the maximum of each of the pairs of elements in the two source vectors. /// /// The first source vector. /// The second source vector. @@ -153,41 +141,40 @@ public static Vector3 Min(Vector3 value1, Vector3 value2) [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Max(Vector3 value1, Vector3 value2) - { - return new Vector3( - (value1.X > value2.X) ? value1.X : value2.X, - (value1.Y > value2.Y) ? value1.Y : value2.Y, - (value1.Z > value2.Z) ? value1.Z : value2.Z); - } + => new((value1.X > value2.X) ? value1.X : value2.X, + (value1.Y > value2.Y) ? value1.Y : value2.Y, + (value1.Z > value2.Z) ? value1.Z : value2.Z); /// - /// Returns a vector whose elements are the absolute values of each of the source vector's elements. + /// Returns a vector whose elements are the absolute values of each of the source vector's elements. /// /// The source vector. /// The absolute value vector. [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Abs(Vector3 value) - { - return new Vector3(MathF.Abs(value.X), MathF.Abs(value.Y), MathF.Abs(value.Z)); - } + => new(MathF.Abs(value.X), + MathF.Abs(value.Y), + MathF.Abs(value.Z)); /// - /// Returns a vector whose elements are the square root of each of the source vector's elements. + /// Returns a vector whose elements are the square root of each of the source vector's elements. /// /// The source vector. /// The square root vector. [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 SquareRoot(Vector3 value) - { - return new Vector3((Single)MathF.Sqrt(value.X), (Single)MathF.Sqrt(value.Y), (Single)MathF.Sqrt(value.Z)); - } + => new(MathF.Sqrt(value.X), + MathF.Sqrt(value.Y), + MathF.Sqrt(value.Z)); + #endregion Public Static Methods #region Public Static Operators + /// - /// Adds two vectors together. + /// Adds two vectors together. /// /// The first source vector. /// The second source vector. @@ -195,12 +182,12 @@ public static Vector3 SquareRoot(Vector3 value) [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 operator +(Vector3 left, Vector3 right) - { - return new Vector3(left.X + right.X, left.Y + right.Y, left.Z + right.Z); - } + => new(left.X + right.X, + left.Y + right.Y, + left.Z + right.Z); /// - /// Subtracts the second vector from the first. + /// Subtracts the second vector from the first. /// /// The first source vector. /// The second source vector. @@ -208,12 +195,12 @@ public static Vector3 SquareRoot(Vector3 value) [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 operator -(Vector3 left, Vector3 right) - { - return new Vector3(left.X - right.X, left.Y - right.Y, left.Z - right.Z); - } + => new(left.X - right.X, + left.Y - right.Y, + left.Z - right.Z); /// - /// Multiplies two vectors together. + /// Multiplies two vectors together. /// /// The first source vector. /// The second source vector. @@ -221,38 +208,32 @@ public static Vector3 SquareRoot(Vector3 value) [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 operator *(Vector3 left, Vector3 right) - { - return new Vector3(left.X * right.X, left.Y * right.Y, left.Z * right.Z); - } + => new(left.X * right.X, + left.Y * right.Y, + left.Z * right.Z); /// - /// Multiplies a vector by the given scalar. + /// Multiplies a vector by the given scalar. /// /// The source vector. /// The scalar value. /// The scaled vector. [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 operator *(Vector3 left, Single right) - { - return left * new Vector3(right); - } + public static Vector3 operator *(Vector3 left, float right) => left * new Vector3(right); /// - /// Multiplies a vector by the given scalar. + /// Multiplies a vector by the given scalar. /// /// The scalar value. /// The source vector. /// The scaled vector. [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 operator *(Single left, Vector3 right) - { - return new Vector3(left) * right; - } + public static Vector3 operator *(float left, Vector3 right) => new Vector3(left) * right; /// - /// Divides the first vector by the second. + /// Divides the first vector by the second. /// /// The first source vector. /// The second source vector. @@ -260,12 +241,12 @@ public static Vector3 SquareRoot(Vector3 value) [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 operator /(Vector3 left, Vector3 right) - { - return new Vector3(left.X / right.X, left.Y / right.Y, left.Z / right.Z); - } + => new(left.X / right.X, + left.Y / right.Y, + left.Z / right.Z); /// - /// Divides the vector by the given scalar. + /// Divides the vector by the given scalar. /// /// The source vector. /// The scalar value. @@ -283,18 +264,15 @@ public static Vector3 SquareRoot(Vector3 value) } /// - /// Negates a given vector. + /// Negates a given vector. /// /// The source vector. /// The negated vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 operator -(Vector3 value) - { - return Zero - value; - } + public static Vector3 operator -(Vector3 value) => Zero - value; /// - /// Returns a boolean indicating whether the two given vectors are equal. + /// Returns a boolean indicating whether the two given vectors are equal. /// /// The first vector to compare. /// The second vector to compare. @@ -302,25 +280,21 @@ public static Vector3 SquareRoot(Vector3 value) [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Vector3 left, Vector3 right) - { - return (left.X == right.X && - left.Y == right.Y && - left.Z == right.Z); - } + => left.X == right.X && + left.Y == right.Y && + left.Z == right.Z; /// - /// Returns a boolean indicating whether the two given vectors are not equal. + /// Returns a boolean indicating whether the two given vectors are not equal. /// /// The first vector to compare. /// The second vector to compare. /// True if the vectors are not equal; False if they are equal. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Vector3 left, Vector3 right) - { - return (left.X != right.X || - left.Y != right.Y || - left.Z != right.Z); - } + => left.X != right.X || + left.Y != right.Y || + left.Z != right.Z; /// /// Converts the SharpEngine representation to a System.Numerics representation. diff --git a/Tests/ObjLoader.Test/ObjLoader.Tests.csproj b/Tests/ObjLoader.Test/ObjLoader.Tests.csproj index bf131cc..a766284 100644 --- a/Tests/ObjLoader.Test/ObjLoader.Tests.csproj +++ b/Tests/ObjLoader.Test/ObjLoader.Tests.csproj @@ -1,13 +1,17 @@  + net8.0 + + + From 4f934e88bf574db6d7b3b0cf2544a1dab18255e4 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Thu, 10 Apr 2025 23:46:03 +0300 Subject: [PATCH 43/92] #2 Separated Shader data container and extension methods --- Editor/SharpEngine.Editor.csproj | 6 - Examples/MinecraftClone/Block/Dirt.cs | 9 +- Examples/MinecraftClone/Block/Stone.cs | 9 +- ObjLoader/Data/DataStore/DataStore.cs | 8 +- ObjLoader/Data/DataStore/IDataStore.cs | 3 +- ObjLoader/Loaders/LoadResult.cs | 4 +- ObjLoader/Loaders/MaterialLibraryLoader.cs | 2 + ObjLoader/TypeParsers/TextureParser.cs | 2 +- .../ObjLoader/DataStore/IMaterialLibrary.cs | 2 +- .../ObjLoader/DataStore/ITextureDataStore.cs | 2 +- .../Properties/Material.cs | 105 ++++++++++---- .../Properties/Meshes/MeshData/Group.cs | 1 + .../{Texture.cs => TextureCoordinate.cs} | 4 +- .../Properties/Shader.cs | 52 +++++++ .../Properties/Texture.cs | 19 +++ SharpEngine.Core/Entities/GameObject.cs | 5 +- .../Entities/Lights/DirectionalLight.cs | 3 +- .../Entities/Lights/PointLight.cs | 5 +- SharpEngine.Core/Entities/Lights/SpotLight.cs | 3 +- SharpEngine.Core/Entities/Material.cs | 55 -------- SharpEngine.Core/Entities/Views/CameraView.cs | 1 + SharpEngine.Core/Entities/Views/View.cs | 3 +- SharpEngine.Core/Shaders/LampShader.cs | 3 +- SharpEngine.Core/Shaders/LightingShader.cs | 3 +- SharpEngine.Core/Shaders/ShaderBase.cs | 3 +- .../{Shader.cs => ShaderExtensions.cs} | 132 +++++++----------- SharpEngine.Core/Shaders/ShaderService.cs | 2 +- SharpEngine.Core/Shaders/UIShader.cs | 5 +- SharpEngine.Core/SharpEngine.Core.csproj | 28 ++-- .../{Texture.cs => TextureExtensions.cs} | 20 +-- SharpEngine.Core/Windowing/Window.cs | 2 +- SharpEngine.Core/_Resources/Default.cs | 11 +- .../Shaders/Light/DirectionalLight.glsl | 0 .../Shaders/Light/PointLight.glsl | 0 .../Shaders/Light/SpotLight.glsl | 0 .../{ => _Resources}/Shaders/Material.glsl | 0 .../{ => _Resources}/Shaders/lighting.frag | 0 .../{ => _Resources}/Shaders/shader.frag | 0 .../{ => _Resources}/Shaders/shader.vert | 0 .../{ => _Resources}/Shaders/uiShader.frag | 0 .../{ => _Resources}/Shaders/uiShader.vert | 0 .../Textures}/debug.jpg | Bin .../Loaders/MaterialLibraryLoaderTests.cs | 2 + .../TypeParsers/TextureParserTests.cs | 6 +- 44 files changed, 279 insertions(+), 241 deletions(-) rename SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/{Texture.cs => TextureCoordinate.cs} (71%) create mode 100644 SharpEngine.Core.Components/Properties/Shader.cs create mode 100644 SharpEngine.Core.Components/Properties/Texture.cs delete mode 100644 SharpEngine.Core/Entities/Material.cs rename SharpEngine.Core/Shaders/{Shader.cs => ShaderExtensions.cs} (63%) rename SharpEngine.Core/Textures/{Texture.cs => TextureExtensions.cs} (52%) rename SharpEngine.Core/{ => _Resources}/Shaders/Light/DirectionalLight.glsl (100%) rename SharpEngine.Core/{ => _Resources}/Shaders/Light/PointLight.glsl (100%) rename SharpEngine.Core/{ => _Resources}/Shaders/Light/SpotLight.glsl (100%) rename SharpEngine.Core/{ => _Resources}/Shaders/Material.glsl (100%) rename SharpEngine.Core/{ => _Resources}/Shaders/lighting.frag (100%) rename SharpEngine.Core/{ => _Resources}/Shaders/shader.frag (100%) rename SharpEngine.Core/{ => _Resources}/Shaders/shader.vert (100%) rename SharpEngine.Core/{ => _Resources}/Shaders/uiShader.frag (100%) rename SharpEngine.Core/{ => _Resources}/Shaders/uiShader.vert (100%) rename SharpEngine.Core/{Textures/DefaultTextures => _Resources/Textures}/debug.jpg (100%) diff --git a/Editor/SharpEngine.Editor.csproj b/Editor/SharpEngine.Editor.csproj index 46b99e1..4045738 100644 --- a/Editor/SharpEngine.Editor.csproj +++ b/Editor/SharpEngine.Editor.csproj @@ -19,12 +19,6 @@ icon.png - - - - - - True diff --git a/Examples/MinecraftClone/Block/Dirt.cs b/Examples/MinecraftClone/Block/Dirt.cs index edcb5bb..183d5d8 100644 --- a/Examples/MinecraftClone/Block/Dirt.cs +++ b/Examples/MinecraftClone/Block/Dirt.cs @@ -1,4 +1,5 @@ -using SharpEngine.Core.Extensions; +using SharpEngine.Core._Resources; +using SharpEngine.Core.Extensions; using System.Numerics; namespace Minecraft.Block; @@ -14,9 +15,9 @@ internal class Dirt : BlockBase /// The position where the block should be initialized. /// The name of the block to initialize. public Dirt(Vector3 position, string name) : base(position, name, PathExtensions.GetAssemblyPath("Resources\\grass.jpg"), - PathExtensions.GetAssemblyPath("Resources\\container2_specular.png"), - PathExtensions.GetAssemblyPath("Shaders\\shader.vert"), - PathExtensions.GetAssemblyPath("Shaders\\lighting.frag")) { } + PathExtensions.GetAssemblyPath("Resources\\container2_specular.png"), + Default.VertexShader, + Default.FragmentShader) { } /// public override BlockType BlockType => BlockType.Dirt; diff --git a/Examples/MinecraftClone/Block/Stone.cs b/Examples/MinecraftClone/Block/Stone.cs index 599c086..d54faf9 100644 --- a/Examples/MinecraftClone/Block/Stone.cs +++ b/Examples/MinecraftClone/Block/Stone.cs @@ -1,4 +1,5 @@ -using SharpEngine.Core.Extensions; +using SharpEngine.Core._Resources; +using SharpEngine.Core.Extensions; using System.Numerics; namespace Minecraft.Block; @@ -14,9 +15,9 @@ internal class Stone : BlockBase /// The position where the block is created. /// The name of the object in the scene. public Stone(Vector3 position, string name) : base(position, name, PathExtensions.GetAssemblyPath("Resources\\container2.png"), - PathExtensions.GetAssemblyPath("Resources\\container2_specular.png"), - PathExtensions.GetAssemblyPath("Shaders\\shader.vert"), - PathExtensions.GetAssemblyPath("Shaders\\lighting.frag")) { } + PathExtensions.GetAssemblyPath("Resources\\container2_specular.png"), + Default.VertexShader, + Default.FragmentShader) { } /// public override BlockType BlockType => BlockType.Stone; diff --git a/ObjLoader/Data/DataStore/DataStore.cs b/ObjLoader/Data/DataStore/DataStore.cs index 745e75a..9a491eb 100644 --- a/ObjLoader/Data/DataStore/DataStore.cs +++ b/ObjLoader/Data/DataStore/DataStore.cs @@ -2,8 +2,8 @@ using ObjLoader.Loader.Data.Elements; using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; +using SharpEngine.Core.Components.Properties; using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; - using System.Collections.Generic; using System.Linq; @@ -18,12 +18,12 @@ public class DataStore : IDataStore, IGroupDataStore, IVertexDataStore, ITexture private readonly List _materials = []; private readonly List _vertices = []; - private readonly List _textures = []; + private readonly List _textures = []; private readonly List _normals = []; public IList Vertices => _vertices; - public IList Textures => _textures; + public IList Textures => _textures; public IList Normals => _normals; @@ -52,7 +52,7 @@ private void PushGroupIfNeeded() public void AddVertex(Vertex vertex) => _vertices.Add(vertex); - public void AddTexture(Texture texture) => _textures.Add(texture); + public void AddTexture(TextureCoordinate texture) => _textures.Add(texture); public void AddNormal(Normal normal) => _normals.Add(normal); diff --git a/ObjLoader/Data/DataStore/IDataStore.cs b/ObjLoader/Data/DataStore/IDataStore.cs index 271475a..447ded5 100644 --- a/ObjLoader/Data/DataStore/IDataStore.cs +++ b/ObjLoader/Data/DataStore/IDataStore.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using ObjLoader.Loader.Data.Elements; +using SharpEngine.Core.Components.Properties; using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; namespace ObjLoader.Loader.Data.DataStore @@ -7,7 +8,7 @@ namespace ObjLoader.Loader.Data.DataStore public interface IDataStore { IList Vertices { get; } - IList Textures { get; } + IList Textures { get; } IList Normals { get; } IList Materials { get; } IList Groups { get; } diff --git a/ObjLoader/Loaders/LoadResult.cs b/ObjLoader/Loaders/LoadResult.cs index b9413fa..1983535 100644 --- a/ObjLoader/Loaders/LoadResult.cs +++ b/ObjLoader/Loaders/LoadResult.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -using ObjLoader.Loader.Data; using ObjLoader.Loader.Data.Elements; +using SharpEngine.Core.Components.Properties; using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; namespace ObjLoader.Loader.Loaders @@ -8,7 +8,7 @@ namespace ObjLoader.Loader.Loaders public class LoadResult { public IList Vertices { get; set; } - public IList Textures { get; set; } + public IList Textures { get; set; } public IList Normals { get; set; } public IList Groups { get; set; } public IList Materials { get; set; } diff --git a/ObjLoader/Loaders/MaterialLibraryLoader.cs b/ObjLoader/Loaders/MaterialLibraryLoader.cs index 69362e6..8277f1c 100644 --- a/ObjLoader/Loaders/MaterialLibraryLoader.cs +++ b/ObjLoader/Loaders/MaterialLibraryLoader.cs @@ -1,6 +1,8 @@ using ObjLoader.Loader.Common; using ObjLoader.Loader.Data; using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; +using SharpEngine.Core.Components.Properties; +using SharpEngine.Core.Entities.Properties; using System; using System.Collections.Generic; using System.IO; diff --git a/ObjLoader/TypeParsers/TextureParser.cs b/ObjLoader/TypeParsers/TextureParser.cs index cefa002..deab7e7 100644 --- a/ObjLoader/TypeParsers/TextureParser.cs +++ b/ObjLoader/TypeParsers/TextureParser.cs @@ -23,7 +23,7 @@ public override void Parse(string line) float x = parts[0].ParseInvariantFloat(); float y = parts[1].ParseInvariantFloat(); - var texture = new Texture(x, y); + var texture = new TextureCoordinate(x, y); _textureDataStore.AddTexture(texture); } } diff --git a/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IMaterialLibrary.cs b/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IMaterialLibrary.cs index 6758502..5652449 100644 --- a/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IMaterialLibrary.cs +++ b/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IMaterialLibrary.cs @@ -1,4 +1,4 @@ -using ObjLoader.Loader.Data; +using SharpEngine.Core.Components.Properties; namespace SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore { diff --git a/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/ITextureDataStore.cs b/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/ITextureDataStore.cs index 81bf5ae..7ddfe47 100644 --- a/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/ITextureDataStore.cs +++ b/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/ITextureDataStore.cs @@ -4,6 +4,6 @@ namespace SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore { public interface ITextureDataStore { - void AddTexture(Texture texture); + void AddTexture(TextureCoordinate texture); } } \ No newline at end of file diff --git a/SharpEngine.Core.Components/Properties/Material.cs b/SharpEngine.Core.Components/Properties/Material.cs index 5938053..47f256c 100644 --- a/SharpEngine.Core.Components/Properties/Material.cs +++ b/SharpEngine.Core.Components/Properties/Material.cs @@ -1,35 +1,88 @@ -using System.Numerics; +using SharpEngine.Core.Components.Properties; +using SharpEngine.Core.Shaders; +using SharpEngine.Core.Textures; +using System.Numerics; -namespace ObjLoader.Loader.Data +namespace SharpEngine.Core.Components.Properties; + +/// +/// Represents the material rendered onto a game object. +/// +public class Material { - public class Material + /// + /// Initializes a new instance of . + /// + public Material(Shader shader, Texture diffuseMap, Texture? specularMap = null) + { + Shader = shader; + DiffuseMap = diffuseMap; + SpecularMap = specularMap ?? diffuseMap; + + Specular = new(0.5f, 0.5f, 0.5f); + Shininess = 32.0f; + } + + /// + /// Initializes a new instance of . + /// + /// The name assigned to the new material. + public Material(string materialName) { - public Material(string materialName) - { - Name = materialName; - } + Name = materialName; + } - public string Name { get; set; } + public string Name { get; set; } - public Vector3 AmbientColor { get; set; } - public Vector3 DiffuseColor { get; set; } - public Vector3 SpecularColor { get; set; } - public float SpecularCoefficient { get; set; } + /// + /// Gets or sets the diffuse map texture. + /// + public Texture DiffuseMap { get; set; } - public float Transparency { get; set; } + /// + /// Gets or sets the specular map texture. + /// + public Texture SpecularMap { get; set; } - public int IlluminationModel { get; set; } + /// Gets whether the material uses a specular map. + public bool UseSpecularMap => SpecularMap.Handle != DiffuseMap.Handle; - public string AmbientTextureMap { get; set; } - public string DiffuseTextureMap { get; set; } - - public string SpecularTextureMap { get; set; } - public string SpecularHighlightTextureMap { get; set; } - - public string BumpMap { get; set; } - public string DisplacementMap { get; set; } - public string StencilDecalMap { get; set; } + /// + /// Gets or sets the shader used to render the material. + /// + public Shader Shader { get; set; } - public string AlphaTextureMap { get; set; } - } -} \ No newline at end of file + public const int DIFFUSE_UNIT = 0; + public const int SPECULAR_UNIT = 1; + + /// + /// Gets or sets the ambient color of the material. + /// + public Vector3 Specular { get; set; } + + /// + /// Gets or sets the shininess of the material. + /// + public float Shininess { get; set; } + + public Vector3 AmbientColor { get; set; } + public Vector3 DiffuseColor { get; set; } + public Vector3 SpecularColor { get; set; } + public float SpecularCoefficient { get; set; } + + public float Transparency { get; set; } + + public int IlluminationModel { get; set; } + + public string AmbientTextureMap { get; set; } + public string DiffuseTextureMap { get; set; } + + public string SpecularTextureMap { get; set; } + public string SpecularHighlightTextureMap { get; set; } + + public string BumpMap { get; set; } + public string DisplacementMap { get; set; } + public string StencilDecalMap { get; set; } + + public string AlphaTextureMap { get; set; } +} diff --git a/SharpEngine.Core.Components/Properties/Meshes/MeshData/Group.cs b/SharpEngine.Core.Components/Properties/Meshes/MeshData/Group.cs index fcabc14..1cd52c9 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/MeshData/Group.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/MeshData/Group.cs @@ -1,4 +1,5 @@ using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; +using SharpEngine.Core.Components.Properties; namespace ObjLoader.Loader.Data.Elements { diff --git a/SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/Texture.cs b/SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/TextureCoordinate.cs similarity index 71% rename from SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/Texture.cs rename to SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/TextureCoordinate.cs index 3e580da..605aa5c 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/Texture.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/TextureCoordinate.cs @@ -1,8 +1,8 @@ namespace SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData { - public struct Texture + public struct TextureCoordinate { - public Texture(float x, float y) : this() + public TextureCoordinate(float x, float y) : this() { X = x; Y = y; diff --git a/SharpEngine.Core.Components/Properties/Shader.cs b/SharpEngine.Core.Components/Properties/Shader.cs new file mode 100644 index 0000000..d8fe831 --- /dev/null +++ b/SharpEngine.Core.Components/Properties/Shader.cs @@ -0,0 +1,52 @@ +namespace SharpEngine.Core.Shaders; + +/// +/// Represents a shader program. +/// +public class Shader +{ + /// Gets the handle to the shader program. + public uint Handle; + + /// Gets or sets the identifying name of the shader. + public string Name { get; set; } + public string VertPath { get; set; } + public string FragPath { get; set; } + + private Dictionary _uniformLocations = []; + + /// + /// Initializes a new instance of . + /// + /// + /// 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 vertex shader full path. + /// The fragment shader full path. + /// The identifier name of the shader. + public Shader(string vertPath, string fragPath, string name) + { + Name = name; + + // 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. + // The vertex shader won't be too important here, but they'll be more important later. + // The fragment shader is responsible for then converting the vertices to "fragments", which represent all the data OpenGL needs to draw a pixel. + // The fragment shader is what we'll be using the most here. + + if (!vertPath.EndsWith(".vert")) + Console.WriteLine("Vertex shaders should have the file extension '.vert' for easier manageability."); + + if (!fragPath.EndsWith(".frag")) + Console.WriteLine("Fragment shaders should have the file extension '.frag' for easier manageability."); + + VertPath = vertPath; + FragPath = fragPath; + } + + public void InitializeUniforms(Dictionary uniforms) + => _uniformLocations = uniforms; + + public Dictionary GetUniformLocations() => _uniformLocations; +} diff --git a/SharpEngine.Core.Components/Properties/Texture.cs b/SharpEngine.Core.Components/Properties/Texture.cs new file mode 100644 index 0000000..364f274 --- /dev/null +++ b/SharpEngine.Core.Components/Properties/Texture.cs @@ -0,0 +1,19 @@ +namespace SharpEngine.Core.Textures; + +/// +/// Represents a texture program. +/// +public class Texture +{ + /// The OpenGL handle for the texture. + public readonly uint Handle; + + /// + /// Initializes a new instance of . + /// + /// The handle to the texture. + public Texture(uint glHandle) + { + Handle = glHandle; + } +} diff --git a/SharpEngine.Core/Entities/GameObject.cs b/SharpEngine.Core/Entities/GameObject.cs index 7905038..3866a36 100644 --- a/SharpEngine.Core/Entities/GameObject.cs +++ b/SharpEngine.Core/Entities/GameObject.cs @@ -1,4 +1,5 @@ using SharpEngine.Core.Attributes; +using SharpEngine.Core.Components.Properties; using SharpEngine.Core.Entities.Properties; using SharpEngine.Core.Entities.Properties.Meshes; using SharpEngine.Core.Entities.Views; @@ -123,12 +124,12 @@ public override Task Render(CameraView camera, Window window) // Bind(); Material.DiffuseMap.Use(TextureUnit.Texture0); - Material.Shader.SetInt("material.diffuse", Material.diffuseUnit); + Material.Shader.SetInt("material.diffuse", Material.DIFFUSE_UNIT); if (Material.UseSpecularMap) { Material.SpecularMap.Use(TextureUnit.Texture1); - Material.Shader.SetInt("material.specular", Material.specularUnit); + Material.Shader.SetInt("material.specular", Material.SPECULAR_UNIT); Material.Shader.SetVector3("material.specular", Material.Specular); Material.Shader.SetFloat("material.shininess", Material.Shininess); } diff --git a/SharpEngine.Core/Entities/Lights/DirectionalLight.cs b/SharpEngine.Core/Entities/Lights/DirectionalLight.cs index 432f980..5653492 100644 --- a/SharpEngine.Core/Entities/Lights/DirectionalLight.cs +++ b/SharpEngine.Core/Entities/Lights/DirectionalLight.cs @@ -1,3 +1,4 @@ +using SharpEngine.Core._Resources; using SharpEngine.Core.Entities.Properties; using SharpEngine.Core.Entities.Views; using SharpEngine.Core.Extensions; @@ -26,7 +27,7 @@ public DirectionalLight() Diffuse = new Vector3(0.4f, 0.4f, 0.4f); Specular = new Vector3(0.5f, 0.5f, 0.5f); - Material.Shader = ShaderService.Instance.LoadShader(PathExtensions.GetAssemblyPath("Shaders/shader.vert"), PathExtensions.GetAssemblyPath("Shaders/lighting.frag"), "lighting"); + Material.Shader = ShaderService.Instance.LoadShader(Default.VertexShader, Default.FragmentShader, "lighting"); } /// diff --git a/SharpEngine.Core/Entities/Lights/PointLight.cs b/SharpEngine.Core/Entities/Lights/PointLight.cs index 970d32b..710f52f 100644 --- a/SharpEngine.Core/Entities/Lights/PointLight.cs +++ b/SharpEngine.Core/Entities/Lights/PointLight.cs @@ -1,3 +1,4 @@ +using SharpEngine.Core._Resources; using SharpEngine.Core.Entities.Views; using SharpEngine.Core.Extensions; using SharpEngine.Core.Shaders; @@ -20,14 +21,14 @@ public class PointLight : Light public PointLight(Vector3 position, int index) { Transform.Scale = new(0.2f, 0.2f, 0.2f); - Transform.Position = (SharpEngine.Core.Numerics.Vector3)position; + Transform.Position = (Numerics.Vector3)position; Constant = 1.0f; Linear = 0.09f; Quadratic = 0.032f; _index = index; - Material.Shader = ShaderService.Instance.LoadShader(PathExtensions.GetAssemblyPath("Shaders/shader.vert"), PathExtensions.GetAssemblyPath("Shaders/lighting.frag"), "lighting"); + Material.Shader = ShaderService.Instance.LoadShader(Default.VertexShader, Default.FragmentShader, "lighting"); LampShader = new LampShader(); } diff --git a/SharpEngine.Core/Entities/Lights/SpotLight.cs b/SharpEngine.Core/Entities/Lights/SpotLight.cs index b2ef9c9..9b244ed 100644 --- a/SharpEngine.Core/Entities/Lights/SpotLight.cs +++ b/SharpEngine.Core/Entities/Lights/SpotLight.cs @@ -1,3 +1,4 @@ +using SharpEngine.Core._Resources; using SharpEngine.Core.Entities.Views; using SharpEngine.Core.Extensions; using SharpEngine.Core.Shaders; @@ -24,7 +25,7 @@ public SpotLight() Linear = 0.09f; Quadratic = 0.032f; - Material.Shader = ShaderService.Instance.LoadShader(PathExtensions.GetAssemblyPath("Shaders/shader.vert"), PathExtensions.GetAssemblyPath("Shaders/lighting.frag"), "lighting"); + Material.Shader = ShaderService.Instance.LoadShader(Default.VertexShader, Default.FragmentShader, "lighting"); } /// diff --git a/SharpEngine.Core/Entities/Material.cs b/SharpEngine.Core/Entities/Material.cs deleted file mode 100644 index 5f9083e..0000000 --- a/SharpEngine.Core/Entities/Material.cs +++ /dev/null @@ -1,55 +0,0 @@ -using SharpEngine.Core.Shaders; -using SharpEngine.Core.Textures; -using System.Numerics; - -namespace SharpEngine.Core.Entities.Properties; - -/// -/// Represents the material rendered onto a game object. -/// -public class Material -{ - /// - /// Initializes a new instance of . - /// - public Material(Shader shader, Texture diffuseMap, Texture? specularMap = null) - { - Shader = shader; - DiffuseMap = diffuseMap; - SpecularMap = specularMap ?? diffuseMap; - - Specular = new(0.5f, 0.5f, 0.5f); - Shininess = 32.0f; - } - - /// - /// Gets or sets the diffuse map texture. - /// - public Texture DiffuseMap { get; set; } - - /// - /// Gets or sets the specular map texture. - /// - public Texture SpecularMap { get; set; } - - /// Gets whether the material uses a specular map. - public bool UseSpecularMap => SpecularMap.Handle != DiffuseMap.Handle; - - /// - /// Gets or sets the shader used to render the material. - /// - public Shader Shader { get; set; } - - internal readonly int diffuseUnit = 0; - internal readonly int specularUnit = 1; - - /// - /// Gets or sets the ambient color of the material. - /// - public Vector3 Specular { get; set; } - - /// - /// Gets or sets the shininess of the material. - /// - public float Shininess { get; set; } -} diff --git a/SharpEngine.Core/Entities/Views/CameraView.cs b/SharpEngine.Core/Entities/Views/CameraView.cs index 69af67c..9a88a2d 100644 --- a/SharpEngine.Core/Entities/Views/CameraView.cs +++ b/SharpEngine.Core/Entities/Views/CameraView.cs @@ -1,3 +1,4 @@ +using SharpEngine.Core.Components.Properties; using SharpEngine.Core.Entities.Views.Settings; using SharpEngine.Core.Shaders; using System.Numerics; diff --git a/SharpEngine.Core/Entities/Views/View.cs b/SharpEngine.Core/Entities/Views/View.cs index 88992a0..02aecba 100644 --- a/SharpEngine.Core/Entities/Views/View.cs +++ b/SharpEngine.Core/Entities/Views/View.cs @@ -1,4 +1,5 @@ -using SharpEngine.Core.Entities.Views.Settings; +using SharpEngine.Core.Components.Properties; +using SharpEngine.Core.Entities.Views.Settings; using SharpEngine.Core.Scenes; using SharpEngine.Core.Shaders; using System; diff --git a/SharpEngine.Core/Shaders/LampShader.cs b/SharpEngine.Core/Shaders/LampShader.cs index 465ab1c..898d08b 100644 --- a/SharpEngine.Core/Shaders/LampShader.cs +++ b/SharpEngine.Core/Shaders/LampShader.cs @@ -1,3 +1,4 @@ +using SharpEngine.Core._Resources; using SharpEngine.Core.Entities.Properties.Meshes; using SharpEngine.Core.Extensions; using SharpEngine.Core.Windowing; @@ -12,7 +13,7 @@ internal class LampShader : ShaderBase /// public LampShader() { - Shader = ShaderService.Instance.LoadShader(PathExtensions.GetAssemblyPath("Shaders/shader.vert"), PathExtensions.GetAssemblyPath("Shaders/shader.frag"), "lamp"); + Shader = ShaderService.Instance.LoadShader(Default.VertexShader, Default.LightShader, "lamp").Initialize(); Vao = Window.GL.GenVertexArray(); Window.GL.BindVertexArray(Vao); diff --git a/SharpEngine.Core/Shaders/LightingShader.cs b/SharpEngine.Core/Shaders/LightingShader.cs index e7ee010..6947bf8 100644 --- a/SharpEngine.Core/Shaders/LightingShader.cs +++ b/SharpEngine.Core/Shaders/LightingShader.cs @@ -1,3 +1,4 @@ +using SharpEngine.Core._Resources; using SharpEngine.Core.Entities.Properties.Meshes; using SharpEngine.Core.Extensions; using SharpEngine.Core.Windowing; @@ -12,7 +13,7 @@ internal class LightingShader : ShaderBase /// public LightingShader() { - Shader = ShaderService.Instance.LoadShader(PathExtensions.GetAssemblyPath("Shaders/shader.vert"), PathExtensions.GetAssemblyPath("Shaders/lighting.frag"), "lighting"); + Shader = ShaderService.Instance.LoadShader(Default.VertexShader, Default.FragmentShader, "lighting").Initialize(); Vao = Window.GL.GenVertexArray(); Window.GL.BindVertexArray(Vao); diff --git a/SharpEngine.Core/Shaders/ShaderBase.cs b/SharpEngine.Core/Shaders/ShaderBase.cs index 2eac3ae..6359998 100644 --- a/SharpEngine.Core/Shaders/ShaderBase.cs +++ b/SharpEngine.Core/Shaders/ShaderBase.cs @@ -1,4 +1,5 @@ -using System; +using SharpEngine.Core.Components.Properties; +using System; namespace SharpEngine.Core.Shaders; diff --git a/SharpEngine.Core/Shaders/Shader.cs b/SharpEngine.Core/Shaders/ShaderExtensions.cs similarity index 63% rename from SharpEngine.Core/Shaders/Shader.cs rename to SharpEngine.Core/Shaders/ShaderExtensions.cs index 9b117c0..1bcc890 100644 --- a/SharpEngine.Core/Shaders/Shader.cs +++ b/SharpEngine.Core/Shaders/ShaderExtensions.cs @@ -1,93 +1,59 @@ -using SharpEngine.Core.Windowing; +using SharpEngine.Core.Windowing; using Silk.NET.OpenGL; using System; using System.Collections.Generic; using System.IO; using System.Numerics; using System.Text.RegularExpressions; -using static System.Runtime.InteropServices.JavaScript.JSType; namespace SharpEngine.Core.Shaders; -/// -/// Represents a shader program. -/// -public class Shader +public static class ShaderExtensions { - /// Gets the handle to the shader program. - public readonly uint Handle; - - /// Gets or sets the identifying name of the shader. - public string Name { get; set; } - - private Dictionary _uniformLocations = []; - - /// - /// Initializes a new instance of . - /// - /// - /// 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 vertex shader full path. - /// The fragment shader full path. - /// The identifier name of the shader. - public Shader(string vertPath, string fragPath, string name) + public static Shader Initialize(this Shader shader) { - Name = name; - - // 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. - // The vertex shader won't be too important here, but they'll be more important later. - // The fragment shader is responsible for then converting the vertices to "fragments", which represent all the data OpenGL needs to draw a pixel. - // The fragment shader is what we'll be using the most here. - - if (!vertPath.EndsWith(".vert")) - Console.WriteLine("Vertex shaders should have the file extension '.vert' for easier manageability."); - - if (!fragPath.EndsWith(".frag")) - Console.WriteLine("Fragment shaders should have the file extension '.frag' for easier manageability."); - // Load and compile shader - if (!LoadShader(ShaderType.VertexShader, vertPath, out uint vertexShader)) + if (!LoadShader(ShaderType.VertexShader, shader.VertPath, out uint vertexShader)) { Console.WriteLine("Unable to load vertex shader."); - return; + return shader; } - if (!LoadShader(ShaderType.FragmentShader, fragPath, out uint fragmentShader)) + if (!LoadShader(ShaderType.FragmentShader, shader.FragPath, out uint fragmentShader)) { Console.WriteLine("Unable to load fragment shader."); - return; + return shader; } // These two shaders must then be merged into a shader program, which can then be used by OpenGL. // To do this, create a program... - Handle = Window.GL.CreateProgram(); + shader.Handle = Window.GL.CreateProgram(); // Attach both shaders... - Window.GL.AttachShader(Handle, vertexShader); - Window.GL.AttachShader(Handle, fragmentShader); + Window.GL.AttachShader(shader.Handle, vertexShader); + Window.GL.AttachShader(shader.Handle, fragmentShader); // And then link them together. - if (!LinkProgram(Handle)) + if (!LinkProgram(shader.Handle)) { Console.WriteLine("Unable to link shader program."); - return; + return shader; } // When the shader program is linked, it no longer needs the individual shaders attached to it; the compiled code is copied into the shader program. // Detach them, and then delete them. - Window.GL.DetachShader(Handle, vertexShader); - Window.GL.DetachShader(Handle, fragmentShader); + Window.GL.DetachShader(shader.Handle, vertexShader); + Window.GL.DetachShader(shader.Handle, fragmentShader); Window.GL.DeleteShader(fragmentShader); Window.GL.DeleteShader(vertexShader); // The shader is now ready to go, but first, we're going to cache all the shader uniform locations. // Querying this from the shader is very slow, so we do it once on initialization and reuse those values // later. - GetUniformLocations(); + SetUniformLocations(shader); + + return shader; } private static bool LoadShader(ShaderType shaderType, string shaderPath, out uint shader) @@ -116,26 +82,29 @@ private static bool LoadShader(ShaderType shaderType, string shaderPath, out uin return true; } - private void GetUniformLocations() + public static Shader SetUniformLocations(this Shader shader) { // First, we have to get the number of active uniforms in the shader. - Window.GL.GetProgram(Handle, GLEnum.ActiveUniforms, out var numberOfUniforms); + Window.GL.GetProgram(shader.Handle, GLEnum.ActiveUniforms, out var numberOfUniforms); // Next, allocate the dictionary to hold the locations. - _uniformLocations = []; + Dictionary uniformLocations = []; // Loop over all the uniforms, for (uint i = 0; i < numberOfUniforms; i++) { // get the name of this uniform, - var key = Window.GL.GetActiveUniform(Handle, i, out _, out _); + var key = Window.GL.GetActiveUniform(shader.Handle, i, out _, out _); // get the location, - var location = Window.GL.GetUniformLocation(Handle, key); + var location = Window.GL.GetUniformLocation(shader.Handle, key); // and then add it to the dictionary. - _uniformLocations.Add(key, location); + uniformLocations.Add(key, location); } + + shader.InitializeUniforms(uniformLocations); + return shader; } private static string ProcessIncludes(string shaderCode, string directory) @@ -187,8 +156,8 @@ private static bool LinkProgram(uint program) /// /// Enables the shader program. /// - public void Use() - => Window.GL.UseProgram(Handle); + public static void Use(this Shader shader) + => Window.GL.UseProgram(shader.Handle); /// /// Checks if the shader attribute exists within the current shader. @@ -196,9 +165,9 @@ public void Use() /// The name of the attribute that's being looked for. /// Outputs the location of the attribute in the shader if found; otherwise -1. /// If the attribute exists, ; otherwise, . - public bool TryGetAttribLocation(string attribName, out int location) + public static bool TryGetAttribLocation(this Shader shader, string attribName, out int location) { - location = Window.GL.GetAttribLocation(Handle, attribName); + location = Window.GL.GetAttribLocation(shader.Handle, attribName); if (location == ShaderAttributes.AttributeLocationNotFound) { Console.WriteLine($"Attribute '{attribName}' not found in shader program."); @@ -217,9 +186,10 @@ public bool TryGetAttribLocation(string attribName, out int location) // 2. Get a handle to the location of the uniform with GL.GetUniformLocation. // 3. Use the appropriate GL.Uniform* function to set the uniform. - private bool TrySetUniform(string name, T data, Action setter) + private static bool TrySetUniform(this Shader shader, string name, T data, Action setter) { - if (!_uniformLocations.TryGetValue(name, out int uniform)) + var uniforms = shader.GetUniformLocations(); + if (!uniforms.TryGetValue(name, out int uniform)) { Console.WriteLine($"Uniform '{name}' not found in shader program."); return false; @@ -234,10 +204,10 @@ private bool TrySetUniform(string name, T data, Action setter) /// /// The name of the uniform. /// The data to set. - public void SetInt(string name, int data) + public static void SetInt(this Shader shader, string name, int data) { - Window.GL.UseProgram(Handle); - TrySetUniform(name, data, Window.GL.Uniform1); + Window.GL.UseProgram(shader.Handle); + shader.TrySetUniform(name, data, Window.GL.Uniform1); } /// @@ -245,10 +215,10 @@ public void SetInt(string name, int data) /// /// The name of the uniform. /// The data to set. - public void SetFloat(string name, float data) + public static void SetFloat(this Shader shader, string name, float data) { - Window.GL.UseProgram(Handle); - TrySetUniform(name, data, Window.GL.Uniform1); + Window.GL.UseProgram(shader.Handle); + shader.TrySetUniform(name, data, Window.GL.Uniform1); } /// @@ -262,10 +232,10 @@ public void SetFloat(string name, float data) /// The matrix is transposed before being sent to the shader unless is set to . /// /// - public void SetMatrix4(string name, Matrix4x4 data, bool transpose = true) + public static void SetMatrix4(this Shader shader, string name, Matrix4x4 data, bool transpose = true) { - Window.GL.UseProgram(Handle); - TrySetUniform(name, data, (uniform, d) => Window.GL.UniformMatrix4(uniform, transpose, d.ToSpan())); + Window.GL.UseProgram(shader.Handle); + shader.TrySetUniform(name, data, (uniform, d) => Window.GL.UniformMatrix4(uniform, transpose, d.ToSpan())); } /// @@ -273,10 +243,10 @@ public void SetMatrix4(string name, Matrix4x4 data, bool transpose = true) /// /// The name of the uniform. /// The data to set. - public void SetVector2(string name, Vector2 data) + public static void SetVector2(this Shader shader, string name, Vector2 data) { - Window.GL.UseProgram(Handle); - TrySetUniform(name, data, Window.GL.Uniform2); + Window.GL.UseProgram(shader.Handle); + shader.TrySetUniform(name, data, Window.GL.Uniform2); } /// @@ -284,10 +254,10 @@ public void SetVector2(string name, Vector2 data) /// /// The name of the uniform. /// The data to set. - public void SetVector3(string name, Vector3 data) + public static void SetVector3(this Shader shader, string name, Vector3 data) { - Window.GL.UseProgram(Handle); - TrySetUniform(name, data, Window.GL.Uniform3); + Window.GL.UseProgram(shader.Handle); + shader.TrySetUniform(name, data, Window.GL.Uniform3); } /// @@ -295,9 +265,9 @@ public void SetVector3(string name, Vector3 data) /// /// The name of the uniform. /// The data to set. - public void SetVector4(string name, Vector4 data) + public static void SetVector4(this Shader shader, string name, Vector4 data) { - Window.GL.UseProgram(Handle); - TrySetUniform(name, data, Window.GL.Uniform4); + Window.GL.UseProgram(shader.Handle); + shader.TrySetUniform(name, data, Window.GL.Uniform4); } } diff --git a/SharpEngine.Core/Shaders/ShaderService.cs b/SharpEngine.Core/Shaders/ShaderService.cs index 6a27cb8..f1b0bfe 100644 --- a/SharpEngine.Core/Shaders/ShaderService.cs +++ b/SharpEngine.Core/Shaders/ShaderService.cs @@ -82,7 +82,7 @@ public Shader LoadShader(string vertPath, string fragPath, string name) } // Create a new shader instance and add it to the cache - var shader = new Shader(vertPath, fragPath, name); + var shader = new Shader(vertPath, fragPath, name).Initialize(); _shaderCache[name] = shader; HasShadersToLoad = true; diff --git a/SharpEngine.Core/Shaders/UIShader.cs b/SharpEngine.Core/Shaders/UIShader.cs index 4c5e675..d7e192d 100644 --- a/SharpEngine.Core/Shaders/UIShader.cs +++ b/SharpEngine.Core/Shaders/UIShader.cs @@ -1,6 +1,7 @@ using SharpEngine.Core.Entities.Properties.Meshes; -using SharpEngine.Core.Extensions; using SharpEngine.Core.Windowing; +using SharpEngine.Core._Resources; + using Silk.NET.OpenGL; namespace SharpEngine.Core.Shaders; @@ -12,7 +13,7 @@ internal class UIShader : ShaderBase /// public UIShader() { - Shader = new Shader(PathExtensions.GetAssemblyPath("Shaders\\uiShader.vert"), PathExtensions.GetAssemblyPath("Shaders\\uiShader.frag"), "ui"); + Shader = new Shader(Default.VertexShader, Default.FragmentShader, nameof(UIShader)).Initialize(); } /// diff --git a/SharpEngine.Core/SharpEngine.Core.csproj b/SharpEngine.Core/SharpEngine.Core.csproj index a0cb0a8..867a952 100644 --- a/SharpEngine.Core/SharpEngine.Core.csproj +++ b/SharpEngine.Core/SharpEngine.Core.csproj @@ -1,4 +1,4 @@ - + Everything needed to build games using a purely C# game engine. @@ -35,21 +35,17 @@ - - - - - - - - - - - Always - - - PreserveNewest - + + + + + + + + + + + \ No newline at end of file diff --git a/SharpEngine.Core/Textures/Texture.cs b/SharpEngine.Core/Textures/TextureExtensions.cs similarity index 52% rename from SharpEngine.Core/Textures/Texture.cs rename to SharpEngine.Core/Textures/TextureExtensions.cs index a947e3e..800443e 100644 --- a/SharpEngine.Core/Textures/Texture.cs +++ b/SharpEngine.Core/Textures/TextureExtensions.cs @@ -3,22 +3,8 @@ namespace SharpEngine.Core.Textures; -/// -/// Represents a texture program. -/// -public class Texture +public static class TextureExtensions { - /// The OpenGL handle for the texture. - public readonly uint Handle; - - /// - /// Initializes a new instance of . - /// - /// The handle to the texture. - public Texture(uint glHandle) - { - Handle = glHandle; - } // Multiple textures can be bound, if your shader needs more than just one. // If you want to do that, use GL.ActiveTexture to set which slot GL.BindTexture binds to. @@ -28,9 +14,9 @@ public Texture(uint glHandle) /// Activate the texture. /// /// The bound texture location. - public void Use(TextureUnit unit) + public static void Use(this Texture texture, TextureUnit unit) { Window.GL.ActiveTexture(unit); - Window.GL.BindTexture(TextureTarget.Texture2D, Handle); + Window.GL.BindTexture(TextureTarget.Texture2D, texture.Handle); } } diff --git a/SharpEngine.Core/Windowing/Window.cs b/SharpEngine.Core/Windowing/Window.cs index 3d4f44f..efc052d 100644 --- a/SharpEngine.Core/Windowing/Window.cs +++ b/SharpEngine.Core/Windowing/Window.cs @@ -6,7 +6,6 @@ using SharpEngine.Core.Renderers; using SharpEngine.Core.Scenes; using SharpEngine.Core.Shaders; -using Shader = SharpEngine.Core.Shaders.Shader; using Silk.NET.Input; using Silk.NET.Maths; @@ -20,6 +19,7 @@ using System.Linq; using System.Numerics; using System.Threading.Tasks; +using Shader = SharpEngine.Core.Shaders.Shader; namespace SharpEngine.Core.Windowing; diff --git a/SharpEngine.Core/_Resources/Default.cs b/SharpEngine.Core/_Resources/Default.cs index fb078fb..24c29a9 100644 --- a/SharpEngine.Core/_Resources/Default.cs +++ b/SharpEngine.Core/_Resources/Default.cs @@ -8,11 +8,16 @@ namespace SharpEngine.Core._Resources; public struct Default { /// Gets the path to the debug texture. - public static string DebugTexture => PathExtensions.GetAssemblyPath("Textures\\DefaultTextures\\debug.JPG"); + public static string DebugTexture => PathExtensions.GetAssemblyPath("_Resources\\Textures\\debug.JPG"); /// Gets the path to the default vertex shader. - public static string VertexShader => PathExtensions.GetAssemblyPath("Shaders\\shader.vert"); + public static string VertexShader => PathExtensions.GetAssemblyPath("_Resources\\Shaders\\shader.vert"); /// Gets the path to the lighting fragment shader. - public static string FragmentShader => PathExtensions.GetAssemblyPath("Shaders\\lighting.frag"); + public static string FragmentShader => PathExtensions.GetAssemblyPath("_Resources\\Shaders\\lighting.frag"); + + public static string LightShader => PathExtensions.GetAssemblyPath("_Resources\\Shaders\\shader.frag"); + + public static string UIVertexShader => PathExtensions.GetAssemblyPath("_Resources\\Shaders\\uiShader.vert"); + public static string UIFragmentShader => PathExtensions.GetAssemblyPath("_Resources\\Shaders\\uiShader.frag"); } diff --git a/SharpEngine.Core/Shaders/Light/DirectionalLight.glsl b/SharpEngine.Core/_Resources/Shaders/Light/DirectionalLight.glsl similarity index 100% rename from SharpEngine.Core/Shaders/Light/DirectionalLight.glsl rename to SharpEngine.Core/_Resources/Shaders/Light/DirectionalLight.glsl diff --git a/SharpEngine.Core/Shaders/Light/PointLight.glsl b/SharpEngine.Core/_Resources/Shaders/Light/PointLight.glsl similarity index 100% rename from SharpEngine.Core/Shaders/Light/PointLight.glsl rename to SharpEngine.Core/_Resources/Shaders/Light/PointLight.glsl diff --git a/SharpEngine.Core/Shaders/Light/SpotLight.glsl b/SharpEngine.Core/_Resources/Shaders/Light/SpotLight.glsl similarity index 100% rename from SharpEngine.Core/Shaders/Light/SpotLight.glsl rename to SharpEngine.Core/_Resources/Shaders/Light/SpotLight.glsl diff --git a/SharpEngine.Core/Shaders/Material.glsl b/SharpEngine.Core/_Resources/Shaders/Material.glsl similarity index 100% rename from SharpEngine.Core/Shaders/Material.glsl rename to SharpEngine.Core/_Resources/Shaders/Material.glsl diff --git a/SharpEngine.Core/Shaders/lighting.frag b/SharpEngine.Core/_Resources/Shaders/lighting.frag similarity index 100% rename from SharpEngine.Core/Shaders/lighting.frag rename to SharpEngine.Core/_Resources/Shaders/lighting.frag diff --git a/SharpEngine.Core/Shaders/shader.frag b/SharpEngine.Core/_Resources/Shaders/shader.frag similarity index 100% rename from SharpEngine.Core/Shaders/shader.frag rename to SharpEngine.Core/_Resources/Shaders/shader.frag diff --git a/SharpEngine.Core/Shaders/shader.vert b/SharpEngine.Core/_Resources/Shaders/shader.vert similarity index 100% rename from SharpEngine.Core/Shaders/shader.vert rename to SharpEngine.Core/_Resources/Shaders/shader.vert diff --git a/SharpEngine.Core/Shaders/uiShader.frag b/SharpEngine.Core/_Resources/Shaders/uiShader.frag similarity index 100% rename from SharpEngine.Core/Shaders/uiShader.frag rename to SharpEngine.Core/_Resources/Shaders/uiShader.frag diff --git a/SharpEngine.Core/Shaders/uiShader.vert b/SharpEngine.Core/_Resources/Shaders/uiShader.vert similarity index 100% rename from SharpEngine.Core/Shaders/uiShader.vert rename to SharpEngine.Core/_Resources/Shaders/uiShader.vert diff --git a/SharpEngine.Core/Textures/DefaultTextures/debug.jpg b/SharpEngine.Core/_Resources/Textures/debug.jpg similarity index 100% rename from SharpEngine.Core/Textures/DefaultTextures/debug.jpg rename to SharpEngine.Core/_Resources/Textures/debug.jpg diff --git a/Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs b/Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs index f51b6e1..0f64bc5 100644 --- a/Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs +++ b/Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs @@ -7,6 +7,8 @@ using FluentAssertions; using ObjLoader.Loader.Loaders; using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; +using SharpEngine.Core.Entities.Properties; +using SharpEngine.Core.Components.Properties; namespace ObjLoader.Test.Loaders { diff --git a/Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs index 4349771..4a14990 100644 --- a/Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs +++ b/Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs @@ -51,14 +51,14 @@ public void Parses_normal_line_correctly() class TextureDataStoreMock : ITextureDataStore { - public Texture ParsedTexture { get; private set; } + public TextureCoordinate ParsedTexture { get; private set; } - public Texture GetTexture(int i) + public TextureCoordinate GetTexture(int i) { throw new System.NotImplementedException(); } - public void AddTexture(Texture texture) + public void AddTexture(TextureCoordinate texture) { ParsedTexture = texture; } From a81706ab9a70d387dafa3ea54d1d2fa3244ada59 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Thu, 10 Apr 2025 23:50:35 +0300 Subject: [PATCH 44/92] #2 Use correct ui shaders --- SharpEngine.Core/Shaders/UIShader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharpEngine.Core/Shaders/UIShader.cs b/SharpEngine.Core/Shaders/UIShader.cs index d7e192d..6cd2e0e 100644 --- a/SharpEngine.Core/Shaders/UIShader.cs +++ b/SharpEngine.Core/Shaders/UIShader.cs @@ -13,7 +13,7 @@ internal class UIShader : ShaderBase /// public UIShader() { - Shader = new Shader(Default.VertexShader, Default.FragmentShader, nameof(UIShader)).Initialize(); + Shader = new Shader(Default.UIVertexShader, Default.UIFragmentShader, nameof(UIShader)).Initialize(); } /// From 4ba921be73a51ae2f3519762bf72d9ecd8ba6785 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Fri, 11 Apr 2025 00:18:02 +0300 Subject: [PATCH 45/92] #2 Fix absolute path bug --- Examples/MinecraftClone/Minecraft.cs | 10 +++------- ObjLoader/Loaders/IObjLoader.cs | 2 +- ObjLoader/Loaders/MaterialStreamProvider.cs | 12 +++++++++++- ObjLoader/Loaders/ObjLoader.cs | 10 +++++++--- ObjLoader/Loaders/ObjLoaderFactory.cs | 11 +++++++++-- ObjLoader/ObjLoader.csproj | 5 +++++ ObjLoader/TypeParsers/MaterialLibraryParser.cs | 4 ++-- 7 files changed, 38 insertions(+), 16 deletions(-) diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index 7b970ce..502cfac 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -148,16 +148,12 @@ private void InitializeWorld() // TODO: Does not work yet. // var torus = MeshService.Instance.LoadMesh("torus", @"C:\Users\antti\Documents\Untitled2.obj"); - // This should be simplified to something like this: + // TODO: This should be simplified to something like this: // new ObjLoaderFactory().Load(); - var objLoaderFactory = new ObjLoaderFactory(); + var objLoaderFactory = new ObjLoaderFactory(@"C:\Users\antti\Documents\Untitled2.obj"); var objLoader = objLoaderFactory.Create(); - - // TODO: There is a bug that an exception is thrown if no mtl file is not found. This should be just a warning. - // TODO: This should be able to load from an absolute and a relative path. - var fileStream = new FileStream("Untitled2.obj", FileMode.Open); - var result = objLoader.Load(fileStream); + var result = objLoader.Load(); // var mesh = new Mesh() // { // Vertices = result.Vertices.ToArray(), diff --git a/ObjLoader/Loaders/IObjLoader.cs b/ObjLoader/Loaders/IObjLoader.cs index 298e1dc..ef9a584 100644 --- a/ObjLoader/Loaders/IObjLoader.cs +++ b/ObjLoader/Loaders/IObjLoader.cs @@ -4,6 +4,6 @@ namespace ObjLoader.Loader.Loaders { public interface IObjLoader { - LoadResult Load(Stream lineStream); + LoadResult Load(); } } \ No newline at end of file diff --git a/ObjLoader/Loaders/MaterialStreamProvider.cs b/ObjLoader/Loaders/MaterialStreamProvider.cs index 7c74e54..b8f96bf 100644 --- a/ObjLoader/Loaders/MaterialStreamProvider.cs +++ b/ObjLoader/Loaders/MaterialStreamProvider.cs @@ -4,9 +4,19 @@ namespace ObjLoader.Loader.Loaders { public class MaterialStreamProvider : IMaterialStreamProvider { + private string _objPath; + + public MaterialStreamProvider(string objPath) + { + _objPath = objPath; + } + + /// public Stream Open(string materialFilePath) { - return File.Open(materialFilePath, FileMode.Open, FileAccess.Read); + var dir = Path.GetDirectoryName(_objPath); + var path = Path.Combine(dir, materialFilePath); + return File.Open(path, FileMode.Open, FileAccess.Read); } } diff --git a/ObjLoader/Loaders/ObjLoader.cs b/ObjLoader/Loaders/ObjLoader.cs index f37115b..bcfbe7b 100644 --- a/ObjLoader/Loaders/ObjLoader.cs +++ b/ObjLoader/Loaders/ObjLoader.cs @@ -7,12 +7,13 @@ namespace ObjLoader.Loader.Loaders { public class ObjLoader : LoaderBase, IObjLoader { + private string _path; private readonly IDataStore _dataStore; private readonly List _typeParsers = []; - private readonly List _unrecognizedLines = []; public ObjLoader( + string path, IDataStore dataStore, IFaceParser faceParser, IGroupParser groupParser, @@ -22,6 +23,8 @@ public ObjLoader( IMaterialLibraryParser materialLibraryParser, IUseMaterialParser useMaterialParser) { + _path = path; + _dataStore = dataStore; SetupTypeParsers( vertexParser, @@ -55,9 +58,10 @@ protected override void ParseLine(string keyword, string data) _unrecognizedLines.Add(keyword + " " + data); } - public LoadResult Load(Stream lineStream) + public LoadResult Load() { - StartLoad(lineStream); + var fileStream = new FileStream(_path, FileMode.Open, FileAccess.Read); + StartLoad(fileStream); return new() { diff --git a/ObjLoader/Loaders/ObjLoaderFactory.cs b/ObjLoader/Loaders/ObjLoaderFactory.cs index d99d1ca..f29172b 100644 --- a/ObjLoader/Loaders/ObjLoaderFactory.cs +++ b/ObjLoader/Loaders/ObjLoaderFactory.cs @@ -11,8 +11,15 @@ public interface IMaterialStreamProvider public class ObjLoaderFactory : IObjLoaderFactory { + private string _path; + + public ObjLoaderFactory(string path) + { + _path = path; + } + public IObjLoader Create() - => Create(new MaterialStreamProvider()); + => Create(new MaterialStreamProvider(_path)); public IObjLoader Create(IMaterialStreamProvider materialStreamProvider) { @@ -29,7 +36,7 @@ public IObjLoader Create(IMaterialStreamProvider materialStreamProvider) var materialLibraryParser = new MaterialLibraryParser(materialLibraryLoaderFacade); var useMaterialParser = new UseMaterialParser(dataStore); - return new ObjLoader(dataStore, faceParser, groupParser, normalParser, textureParser, vertexParser, materialLibraryParser, useMaterialParser); + return new ObjLoader(_path, dataStore, faceParser, groupParser, normalParser, textureParser, vertexParser, materialLibraryParser, useMaterialParser); } } } \ No newline at end of file diff --git a/ObjLoader/ObjLoader.csproj b/ObjLoader/ObjLoader.csproj index fecacdb..44cd0f4 100644 --- a/ObjLoader/ObjLoader.csproj +++ b/ObjLoader/ObjLoader.csproj @@ -4,6 +4,11 @@ net8.0 + + + + + diff --git a/ObjLoader/TypeParsers/MaterialLibraryParser.cs b/ObjLoader/TypeParsers/MaterialLibraryParser.cs index 10a27cf..e90d362 100644 --- a/ObjLoader/TypeParsers/MaterialLibraryParser.cs +++ b/ObjLoader/TypeParsers/MaterialLibraryParser.cs @@ -5,9 +5,9 @@ namespace ObjLoader.Loader.TypeParsers { public class MaterialLibraryParser : TypeParserBase, IMaterialLibraryParser { - private readonly IMaterialLibraryLoaderFacade _libraryLoaderFacade; + private readonly MaterialLibraryLoaderFacade _libraryLoaderFacade; - public MaterialLibraryParser(IMaterialLibraryLoaderFacade libraryLoaderFacade) + public MaterialLibraryParser(MaterialLibraryLoaderFacade libraryLoaderFacade) { _libraryLoaderFacade = libraryLoaderFacade; } From d411a39e7fd214c4710f6866041d9e07e32a6fa3 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Fri, 11 Apr 2025 19:43:01 +0300 Subject: [PATCH 46/92] #2 Fix build (WIP) --- .../TypeParsers/MaterialLibraryParser.cs | 4 ++-- .../Properties/Meshes/MeshData/Face.cs | 21 +++++-------------- .../ObjLoader.Test/Loaders/ObjLoaderTests.cs | 6 +++--- 3 files changed, 10 insertions(+), 21 deletions(-) diff --git a/ObjLoader/TypeParsers/MaterialLibraryParser.cs b/ObjLoader/TypeParsers/MaterialLibraryParser.cs index e90d362..10a27cf 100644 --- a/ObjLoader/TypeParsers/MaterialLibraryParser.cs +++ b/ObjLoader/TypeParsers/MaterialLibraryParser.cs @@ -5,9 +5,9 @@ namespace ObjLoader.Loader.TypeParsers { public class MaterialLibraryParser : TypeParserBase, IMaterialLibraryParser { - private readonly MaterialLibraryLoaderFacade _libraryLoaderFacade; + private readonly IMaterialLibraryLoaderFacade _libraryLoaderFacade; - public MaterialLibraryParser(MaterialLibraryLoaderFacade libraryLoaderFacade) + public MaterialLibraryParser(IMaterialLibraryLoaderFacade libraryLoaderFacade) { _libraryLoaderFacade = libraryLoaderFacade; } diff --git a/SharpEngine.Core.Components/Properties/Meshes/MeshData/Face.cs b/SharpEngine.Core.Components/Properties/Meshes/MeshData/Face.cs index 9524a15..8c582e7 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/MeshData/Face.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/MeshData/Face.cs @@ -1,25 +1,14 @@ -using System.Collections.Generic; - -namespace ObjLoader.Loader.Data.Elements +namespace ObjLoader.Loader.Data.Elements { public class Face { - private readonly List _vertices = new List(); + private readonly List _vertices = []; - public void AddVertex(FaceVertex vertex) - { - _vertices.Add(vertex); - } + public void AddVertex(FaceVertex vertex) => _vertices.Add(vertex); - public FaceVertex this[int i] - { - get { return _vertices[i]; } - } + public FaceVertex this[int i] => _vertices[i]; - public int Count - { - get { return _vertices.Count; } - } + public int Count => _vertices.Count; } public struct FaceVertex diff --git a/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs b/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs index eb3e441..d5f4df0 100644 --- a/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs +++ b/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs @@ -57,7 +57,7 @@ public void SetUp() _materialLibraryParser = new MaterialLibraryParser(_materialLibraryLoaderFacade); _useMaterialParser = new UseMaterialParser(_textureDataStore); - _loader = new Loader.Loaders.ObjLoader(_textureDataStore, _faceParser, _groupParser, _normalParser, _textureParser, _vertexParser, _materialLibraryParser, _useMaterialParser); + // _loader = new Loader.Loaders.ObjLoader(_textureDataStore, _faceParser, _groupParser, _normalParser, _textureParser, _vertexParser, _materialLibraryParser, _useMaterialParser); } [Test] @@ -86,7 +86,7 @@ public void Loads_object_correctly_when_material_is_not_found() var materialLibraryLoaderFacade = new MaterialLibraryLoaderFacade(_materialLibraryLoader, _materialStreamProviderSpy); var materialLibraryParser = new MaterialLibraryParser(materialLibraryLoaderFacade); - _loader = new Loader.Loaders.ObjLoader(_textureDataStore, _faceParser, _groupParser, _normalParser, _textureParser, _vertexParser, materialLibraryParser, _useMaterialParser); + // _loader = new Loader.Loaders.ObjLoader(_textureDataStore, _faceParser, _groupParser, _normalParser, _textureParser, _vertexParser, materialLibraryParser, _useMaterialParser); Load(); @@ -106,7 +106,7 @@ private void Load() { var objectStream = CreateMemoryStreamFromString(ObjectFileString); - _loadResult = _loader.Load(objectStream); + // _loadResult = _loader.Load(objectStream); } private Stream CreateMemoryStreamFromString(string str) From dc883d2ab749172a404af048263508f5ba9f1837 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Fri, 11 Apr 2025 20:00:29 +0300 Subject: [PATCH 47/92] #2 Cleanup --- ObjLoader/Data/DataStore/DataStore.cs | 37 +++++-------------- ObjLoader/Data/DataStore/IDataStore.cs | 10 ++--- ObjLoader/Loaders/MaterialLibraryLoader.cs | 12 +++--- ObjLoader/TypeParsers/FaceParser.cs | 8 ++-- ObjLoader/TypeParsers/GroupParser.cs | 15 +++++--- .../TypeParsers/MaterialLibraryParser.cs | 2 + ObjLoader/TypeParsers/NormalParser.cs | 12 +++--- ObjLoader/TypeParsers/TextureParser.cs | 12 +++--- ObjLoader/TypeParsers/UseMaterialParser.cs | 6 ++- ObjLoader/TypeParsers/VertexParser.cs | 12 +++--- .../Loaders/MaterialLibraryLoaderTests.cs | 2 +- .../TypeParsers/GroupParserTests.cs | 2 +- .../TypeParsers/NormalParserTests.cs | 4 +- .../TypeParsers/TextureParserTests.cs | 2 +- .../TypeParsers/VertexParserTests.cs | 2 +- 15 files changed, 68 insertions(+), 70 deletions(-) diff --git a/ObjLoader/Data/DataStore/DataStore.cs b/ObjLoader/Data/DataStore/DataStore.cs index 9a491eb..ebeede1 100644 --- a/ObjLoader/Data/DataStore/DataStore.cs +++ b/ObjLoader/Data/DataStore/DataStore.cs @@ -9,32 +9,30 @@ namespace ObjLoader.Loader.Data.DataStore { - public class DataStore : IDataStore, IGroupDataStore, IVertexDataStore, ITextureDataStore, INormalDataStore, - IFaceGroup, IMaterialLibrary, IElementGroup + public class DataStore : IDataStore, IGroupDataStore, IFaceGroup, IElementGroup { private Group _currentGroup; private readonly List _groups = []; private readonly List _materials = []; - private readonly List _vertices = []; - private readonly List _textures = []; - private readonly List _normals = []; + public List Vertices { get; } = []; - public IList Vertices => _vertices; + public List Textures { get; } = []; - public IList Textures => _textures; + public List Normals { get; } = []; - public IList Normals => _normals; + public List Materials { get; } = []; - public IList Materials => _materials; + public List Groups { get; } = []; - public IList Groups => _groups; + public DataStore() + { + PushGroup("default"); + } public void AddFace(Face face) { - PushGroupIfNeeded(); - _currentGroup.AddFace(face); } @@ -44,24 +42,9 @@ public void PushGroup(string groupName) _groups.Add(_currentGroup); } - private void PushGroupIfNeeded() - { - if (_currentGroup == null) - PushGroup("default"); - } - - public void AddVertex(Vertex vertex) => _vertices.Add(vertex); - - public void AddTexture(TextureCoordinate texture) => _textures.Add(texture); - - public void AddNormal(Normal normal) => _normals.Add(normal); - - public void Push(Material material) => _materials.Add(material); - public void SetMaterial(string materialName) { var material = _materials.SingleOrDefault(x => x.Name.EqualsOrdinalIgnoreCase(materialName)); - PushGroupIfNeeded(); _currentGroup.Material = material; } } diff --git a/ObjLoader/Data/DataStore/IDataStore.cs b/ObjLoader/Data/DataStore/IDataStore.cs index 447ded5..af321c1 100644 --- a/ObjLoader/Data/DataStore/IDataStore.cs +++ b/ObjLoader/Data/DataStore/IDataStore.cs @@ -7,10 +7,10 @@ namespace ObjLoader.Loader.Data.DataStore { public interface IDataStore { - IList Vertices { get; } - IList Textures { get; } - IList Normals { get; } - IList Materials { get; } - IList Groups { get; } + List Vertices { get; } + List Textures { get; } + List Normals { get; } + List Materials { get; } + List Groups { get; } } } \ No newline at end of file diff --git a/ObjLoader/Loaders/MaterialLibraryLoader.cs b/ObjLoader/Loaders/MaterialLibraryLoader.cs index 8277f1c..0087adb 100644 --- a/ObjLoader/Loaders/MaterialLibraryLoader.cs +++ b/ObjLoader/Loaders/MaterialLibraryLoader.cs @@ -1,8 +1,8 @@ using ObjLoader.Loader.Common; -using ObjLoader.Loader.Data; +using ObjLoader.Loader.Data.DataStore; using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; using SharpEngine.Core.Components.Properties; -using SharpEngine.Core.Entities.Properties; + using System; using System.Collections.Generic; using System.IO; @@ -12,13 +12,13 @@ namespace ObjLoader.Loader.Loaders { public class MaterialLibraryLoader : LoaderBase, IMaterialLibraryLoader { - private readonly IMaterialLibrary _materialLibrary; + private readonly DataStore _dataStore; private readonly Dictionary> _parseActionDictionary = []; private readonly List _unrecognizedLines = []; - public MaterialLibraryLoader(IMaterialLibrary materialLibrary) + public MaterialLibraryLoader(DataStore dataStore) { - _materialLibrary = materialLibrary; + _dataStore = dataStore; AddParseAction("newmtl", PushMaterial); AddParseAction("Ka", d => CurrentMaterial.AmbientColor = ParseVec3(d)); @@ -75,7 +75,7 @@ private Action GetKeywordAction(string keyword) private void PushMaterial(string materialName) { CurrentMaterial = new Material(materialName); - _materialLibrary.Push(CurrentMaterial); + _dataStore.Materials.Add(CurrentMaterial); } private static Vector3 ParseVec3(string data) diff --git a/ObjLoader/TypeParsers/FaceParser.cs b/ObjLoader/TypeParsers/FaceParser.cs index 04ef3d2..7f16827 100644 --- a/ObjLoader/TypeParsers/FaceParser.cs +++ b/ObjLoader/TypeParsers/FaceParser.cs @@ -15,11 +15,13 @@ public FaceParser(IFaceGroup faceGroup) _faceGroup = faceGroup; } + /// protected override string Keyword => "f"; + /// public override void Parse(string line) { - string[] vertices = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + string[] vertices = line.Split(' ', StringSplitOptions.RemoveEmptyEntries); var face = new Face(); @@ -32,9 +34,9 @@ public override void Parse(string line) _faceGroup.AddFace(face); } - private FaceVertex ParseFaceVertex(string vertexString) + private static FaceVertex ParseFaceVertex(string vertexString) { - string[] fields = vertexString.Split(new[] { '/' }, StringSplitOptions.None); + string[] fields = vertexString.Split('/', StringSplitOptions.None); int vertexIndex = fields[0].ParseInvariantInt(); var faceVertex = new FaceVertex(vertexIndex, 0, 0); diff --git a/ObjLoader/TypeParsers/GroupParser.cs b/ObjLoader/TypeParsers/GroupParser.cs index babb7b4..38d4cdd 100644 --- a/ObjLoader/TypeParsers/GroupParser.cs +++ b/ObjLoader/TypeParsers/GroupParser.cs @@ -1,19 +1,22 @@ -using ObjLoader.Loader.TypeParsers.Interfaces; -using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; +using ObjLoader.Loader.Data.DataStore; +using ObjLoader.Loader.TypeParsers.Interfaces; namespace ObjLoader.Loader.TypeParsers { public class GroupParser : TypeParserBase, IGroupParser { - private readonly IGroupDataStore _groupDataStore; + private readonly DataStore _dataStore; - public GroupParser(IGroupDataStore groupDataStore) + public GroupParser(DataStore dataStore) { - _groupDataStore = groupDataStore; + _dataStore = dataStore; } + /// protected override string Keyword => "g"; - public override void Parse(string line) => _groupDataStore.PushGroup(line); + /// + public override void Parse(string line) + => _dataStore.PushGroup(line); } } \ No newline at end of file diff --git a/ObjLoader/TypeParsers/MaterialLibraryParser.cs b/ObjLoader/TypeParsers/MaterialLibraryParser.cs index 10a27cf..fd78743 100644 --- a/ObjLoader/TypeParsers/MaterialLibraryParser.cs +++ b/ObjLoader/TypeParsers/MaterialLibraryParser.cs @@ -12,8 +12,10 @@ public MaterialLibraryParser(IMaterialLibraryLoaderFacade libraryLoaderFacade) _libraryLoaderFacade = libraryLoaderFacade; } + /// 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 index 4180846..2271a2d 100644 --- a/ObjLoader/TypeParsers/NormalParser.cs +++ b/ObjLoader/TypeParsers/NormalParser.cs @@ -1,21 +1,23 @@ using ObjLoader.Loader.Common; +using ObjLoader.Loader.Data.DataStore; using ObjLoader.Loader.TypeParsers.Interfaces; -using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; namespace ObjLoader.Loader.TypeParsers { public class NormalParser : TypeParserBase, INormalParser { - private readonly INormalDataStore _normalDataStore; + private readonly DataStore _dataStore; - public NormalParser(INormalDataStore normalDataStore) + public NormalParser(DataStore dataStore) { - _normalDataStore = normalDataStore; + _dataStore = dataStore; } + /// protected override string Keyword => "vn"; + /// public override void Parse(string line) { string[] parts = line.Split(' '); @@ -25,7 +27,7 @@ public override void Parse(string line) float z = parts[2].ParseInvariantFloat(); var normal = new Normal(x, y, z); - _normalDataStore.AddNormal(normal); + _dataStore.Normals.Add(normal); } } } \ No newline at end of file diff --git a/ObjLoader/TypeParsers/TextureParser.cs b/ObjLoader/TypeParsers/TextureParser.cs index deab7e7..e0f4fdf 100644 --- a/ObjLoader/TypeParsers/TextureParser.cs +++ b/ObjLoader/TypeParsers/TextureParser.cs @@ -1,21 +1,23 @@ using ObjLoader.Loader.Common; +using ObjLoader.Loader.Data.DataStore; using ObjLoader.Loader.TypeParsers.Interfaces; -using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; namespace ObjLoader.Loader.TypeParsers { public class TextureParser : TypeParserBase, ITextureParser { - private readonly ITextureDataStore _textureDataStore; + private readonly DataStore _dataStore; - public TextureParser(ITextureDataStore textureDataStore) + public TextureParser(DataStore dataStore) { - _textureDataStore = textureDataStore; + _dataStore = dataStore; } + /// protected override string Keyword => "vt"; + /// public override void Parse(string line) { string[] parts = line.Split(' '); @@ -24,7 +26,7 @@ public override void Parse(string line) float y = parts[1].ParseInvariantFloat(); var texture = new TextureCoordinate(x, y); - _textureDataStore.AddTexture(texture); + _dataStore.Textures.Add(texture); } } } \ No newline at end of file diff --git a/ObjLoader/TypeParsers/UseMaterialParser.cs b/ObjLoader/TypeParsers/UseMaterialParser.cs index 2df7f4b..39e7cd6 100644 --- a/ObjLoader/TypeParsers/UseMaterialParser.cs +++ b/ObjLoader/TypeParsers/UseMaterialParser.cs @@ -11,9 +11,11 @@ public UseMaterialParser(IElementGroup elementGroup) { _elementGroup = elementGroup; } - + + /// protected override string Keyword => "usemtl"; - + + /// public override void Parse(string line) => _elementGroup.SetMaterial(line); } } \ No newline at end of file diff --git a/ObjLoader/TypeParsers/VertexParser.cs b/ObjLoader/TypeParsers/VertexParser.cs index d3195e0..7e2e609 100644 --- a/ObjLoader/TypeParsers/VertexParser.cs +++ b/ObjLoader/TypeParsers/VertexParser.cs @@ -1,6 +1,6 @@ using ObjLoader.Loader.Common; +using ObjLoader.Loader.Data.DataStore; using ObjLoader.Loader.TypeParsers.Interfaces; -using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; using System; @@ -8,15 +8,17 @@ namespace ObjLoader.Loader.TypeParsers { public class VertexParser : TypeParserBase, IVertexParser { - private readonly IVertexDataStore _vertexDataStore; + private readonly DataStore _dataStore; - public VertexParser(IVertexDataStore vertexDataStore) + public VertexParser(DataStore dataStore) { - _vertexDataStore = vertexDataStore; + _dataStore = dataStore; } + /// protected override string Keyword => "v"; + /// public override void Parse(string line) { string[] parts = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); @@ -26,7 +28,7 @@ public override void Parse(string line) float z = parts[2].ParseInvariantFloat(); var vertex = new Vertex(x, y, z); - _vertexDataStore.AddVertex(vertex); + _dataStore.Vertices.Add(vertex); } } } \ No newline at end of file diff --git a/Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs b/Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs index 0f64bc5..1075303 100644 --- a/Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs +++ b/Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs @@ -26,7 +26,7 @@ public class MaterialLibraryLoaderTests public void SetUp() { _materialLibrarySpy = new MaterialLibrarySpy(); - _materialLibraryLoader = new MaterialLibraryLoader(_materialLibrarySpy); + // _materialLibraryLoader = new MaterialLibraryLoader(_materialLibrarySpy); } [Test] diff --git a/Tests/ObjLoader.Test/TypeParsers/GroupParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/GroupParserTests.cs index 6b94478..97ea846 100644 --- a/Tests/ObjLoader.Test/TypeParsers/GroupParserTests.cs +++ b/Tests/ObjLoader.Test/TypeParsers/GroupParserTests.cs @@ -17,7 +17,7 @@ public void SetUp() { _groupDataStoreMock = new GroupDataStoreMock(); - _groupParser = new GroupParser(_groupDataStoreMock); + // _groupParser = new GroupParser(_groupDataStoreMock); } [Test] diff --git a/Tests/ObjLoader.Test/TypeParsers/NormalParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/NormalParserTests.cs index 90b12ae..302a7c9 100644 --- a/Tests/ObjLoader.Test/TypeParsers/NormalParserTests.cs +++ b/Tests/ObjLoader.Test/TypeParsers/NormalParserTests.cs @@ -13,11 +13,11 @@ public class NormalParserTests private NormalDataStoreMock _normalDataStoreMock; [SetUp] - public void SetUp() + public void SetUp() { _normalDataStoreMock = new NormalDataStoreMock(); - _normalParser = new NormalParser(_normalDataStoreMock); + // _normalParser = new NormalParser(_normalDataStoreMock); } [Test] diff --git a/Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs index 4a14990..f84d450 100644 --- a/Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs +++ b/Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs @@ -17,7 +17,7 @@ public void SetUp() { _textureDataStoreMock = new TextureDataStoreMock(); - _textureParser = new TextureParser(_textureDataStoreMock); + // _textureParser = new TextureParser(_textureDataStoreMock); } [Test] diff --git a/Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs index 5a4f180..b69a0c4 100644 --- a/Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs +++ b/Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs @@ -17,7 +17,7 @@ public void SetUp() { _vertexDataStoreMock = new VertexDataStoreMock(); - _vertexParser = new VertexParser(_vertexDataStoreMock); + // _vertexParser = new VertexParser(_vertexDataStoreMock); } [Test] From 375dcd7a0d1a2b16c13d3eb645db71e312b5a6b7 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Fri, 11 Apr 2025 20:07:17 +0300 Subject: [PATCH 48/92] #2 Remove redundant interfaces --- ObjLoader/Data/{DataStore => }/DataStore.cs | 4 ++-- ObjLoader/Data/DataStore/IDataStore.cs | 16 ------------- .../Data/{DataStore => }/IElementGroup.cs | 2 +- ObjLoader/Loaders/MaterialLibraryLoader.cs | 4 ++-- ObjLoader/Loaders/ObjLoader.cs | 23 ++++++++++--------- ObjLoader/Loaders/ObjLoaderFactory.cs | 2 +- ObjLoader/TypeParsers/FaceParser.cs | 4 ++-- ObjLoader/TypeParsers/GroupParser.cs | 6 ++--- .../{Interfaces => }/ITypeParser.cs | 2 +- .../TypeParsers/Interfaces/IFaceParser.cs | 6 ----- .../TypeParsers/Interfaces/IGroupParser.cs | 6 ----- .../Interfaces/IMaterialLibraryParser.cs | 6 ----- .../TypeParsers/Interfaces/INormalParser.cs | 6 ----- .../TypeParsers/Interfaces/ITextureParser.cs | 6 ----- .../Interfaces/IUseMaterialParser.cs | 6 ----- .../TypeParsers/Interfaces/IVertexParser.cs | 6 ----- .../TypeParsers/MaterialLibraryParser.cs | 4 ++-- ObjLoader/TypeParsers/NormalParser.cs | 6 ++--- ObjLoader/TypeParsers/TextureParser.cs | 8 +++---- ObjLoader/TypeParsers/TypeParserBase.cs | 2 +- ObjLoader/TypeParsers/UseMaterialParser.cs | 6 ++--- ObjLoader/TypeParsers/VertexParser.cs | 6 ++--- .../ObjLoader.Test/Loaders/ObjLoaderTests.cs | 4 ++-- .../TypeParsers/UseMaterialParserTests.cs | 3 +-- 24 files changed, 43 insertions(+), 101 deletions(-) rename ObjLoader/Data/{DataStore => }/DataStore.cs (91%) delete mode 100644 ObjLoader/Data/DataStore/IDataStore.cs rename ObjLoader/Data/{DataStore => }/IElementGroup.cs (69%) rename ObjLoader/TypeParsers/{Interfaces => }/ITypeParser.cs (69%) delete mode 100644 ObjLoader/TypeParsers/Interfaces/IFaceParser.cs delete mode 100644 ObjLoader/TypeParsers/Interfaces/IGroupParser.cs delete mode 100644 ObjLoader/TypeParsers/Interfaces/IMaterialLibraryParser.cs delete mode 100644 ObjLoader/TypeParsers/Interfaces/INormalParser.cs delete mode 100644 ObjLoader/TypeParsers/Interfaces/ITextureParser.cs delete mode 100644 ObjLoader/TypeParsers/Interfaces/IUseMaterialParser.cs delete mode 100644 ObjLoader/TypeParsers/Interfaces/IVertexParser.cs diff --git a/ObjLoader/Data/DataStore/DataStore.cs b/ObjLoader/Data/DataStore.cs similarity index 91% rename from ObjLoader/Data/DataStore/DataStore.cs rename to ObjLoader/Data/DataStore.cs index ebeede1..8f6e58f 100644 --- a/ObjLoader/Data/DataStore/DataStore.cs +++ b/ObjLoader/Data/DataStore.cs @@ -7,9 +7,9 @@ using System.Collections.Generic; using System.Linq; -namespace ObjLoader.Loader.Data.DataStore +namespace ObjLoader.Data { - public class DataStore : IDataStore, IGroupDataStore, IFaceGroup, IElementGroup + public class DataStore : IGroupDataStore, IFaceGroup, IElementGroup { private Group _currentGroup; diff --git a/ObjLoader/Data/DataStore/IDataStore.cs b/ObjLoader/Data/DataStore/IDataStore.cs deleted file mode 100644 index af321c1..0000000 --- a/ObjLoader/Data/DataStore/IDataStore.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Collections.Generic; -using ObjLoader.Loader.Data.Elements; -using SharpEngine.Core.Components.Properties; -using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; - -namespace ObjLoader.Loader.Data.DataStore -{ - public interface IDataStore - { - List Vertices { get; } - List Textures { get; } - List Normals { get; } - List Materials { get; } - List Groups { get; } - } -} \ No newline at end of file diff --git a/ObjLoader/Data/DataStore/IElementGroup.cs b/ObjLoader/Data/IElementGroup.cs similarity index 69% rename from ObjLoader/Data/DataStore/IElementGroup.cs rename to ObjLoader/Data/IElementGroup.cs index f828800..7c78289 100644 --- a/ObjLoader/Data/DataStore/IElementGroup.cs +++ b/ObjLoader/Data/IElementGroup.cs @@ -1,4 +1,4 @@ -namespace ObjLoader.Loader.Data.DataStore +namespace ObjLoader.Data { public interface IElementGroup { diff --git a/ObjLoader/Loaders/MaterialLibraryLoader.cs b/ObjLoader/Loaders/MaterialLibraryLoader.cs index 0087adb..98ee700 100644 --- a/ObjLoader/Loaders/MaterialLibraryLoader.cs +++ b/ObjLoader/Loaders/MaterialLibraryLoader.cs @@ -1,5 +1,5 @@ -using ObjLoader.Loader.Common; -using ObjLoader.Loader.Data.DataStore; +using ObjLoader.Data; +using ObjLoader.Loader.Common; using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; using SharpEngine.Core.Components.Properties; diff --git a/ObjLoader/Loaders/ObjLoader.cs b/ObjLoader/Loaders/ObjLoader.cs index bcfbe7b..4cdfe64 100644 --- a/ObjLoader/Loaders/ObjLoader.cs +++ b/ObjLoader/Loaders/ObjLoader.cs @@ -1,5 +1,6 @@ -using ObjLoader.Loader.Data.DataStore; -using ObjLoader.Loader.TypeParsers.Interfaces; +using ObjLoader.Data; +using ObjLoader.TypeParsers; + using System.Collections.Generic; using System.IO; @@ -8,20 +9,20 @@ namespace ObjLoader.Loader.Loaders public class ObjLoader : LoaderBase, IObjLoader { private string _path; - private readonly IDataStore _dataStore; + private readonly DataStore _dataStore; private readonly List _typeParsers = []; private readonly List _unrecognizedLines = []; public ObjLoader( string path, - IDataStore dataStore, - IFaceParser faceParser, - IGroupParser groupParser, - INormalParser normalParser, - ITextureParser textureParser, - IVertexParser vertexParser, - IMaterialLibraryParser materialLibraryParser, - IUseMaterialParser useMaterialParser) + DataStore dataStore, + ITypeParser faceParser, + ITypeParser groupParser, + ITypeParser normalParser, + ITypeParser textureParser, + ITypeParser vertexParser, + ITypeParser materialLibraryParser, + ITypeParser useMaterialParser) { _path = path; diff --git a/ObjLoader/Loaders/ObjLoaderFactory.cs b/ObjLoader/Loaders/ObjLoaderFactory.cs index f29172b..0814477 100644 --- a/ObjLoader/Loaders/ObjLoaderFactory.cs +++ b/ObjLoader/Loaders/ObjLoaderFactory.cs @@ -1,5 +1,5 @@ using System.IO; -using ObjLoader.Loader.Data.DataStore; +using ObjLoader.Data; using ObjLoader.Loader.TypeParsers; namespace ObjLoader.Loader.Loaders diff --git a/ObjLoader/TypeParsers/FaceParser.cs b/ObjLoader/TypeParsers/FaceParser.cs index 7f16827..c7328f7 100644 --- a/ObjLoader/TypeParsers/FaceParser.cs +++ b/ObjLoader/TypeParsers/FaceParser.cs @@ -1,12 +1,12 @@ using ObjLoader.Loader.Common; using ObjLoader.Loader.Data.Elements; -using ObjLoader.Loader.TypeParsers.Interfaces; +using ObjLoader.TypeParsers; using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; using System; namespace ObjLoader.Loader.TypeParsers { - public class FaceParser : TypeParserBase, IFaceParser + public class FaceParser : TypeParserBase, ITypeParser { private readonly IFaceGroup _faceGroup; diff --git a/ObjLoader/TypeParsers/GroupParser.cs b/ObjLoader/TypeParsers/GroupParser.cs index 38d4cdd..88a259d 100644 --- a/ObjLoader/TypeParsers/GroupParser.cs +++ b/ObjLoader/TypeParsers/GroupParser.cs @@ -1,9 +1,9 @@ -using ObjLoader.Loader.Data.DataStore; -using ObjLoader.Loader.TypeParsers.Interfaces; +using ObjLoader.Data; +using ObjLoader.TypeParsers; namespace ObjLoader.Loader.TypeParsers { - public class GroupParser : TypeParserBase, IGroupParser + public class GroupParser : TypeParserBase, ITypeParser { private readonly DataStore _dataStore; diff --git a/ObjLoader/TypeParsers/Interfaces/ITypeParser.cs b/ObjLoader/TypeParsers/ITypeParser.cs similarity index 69% rename from ObjLoader/TypeParsers/Interfaces/ITypeParser.cs rename to ObjLoader/TypeParsers/ITypeParser.cs index 07dbb74..9cb2d7e 100644 --- a/ObjLoader/TypeParsers/Interfaces/ITypeParser.cs +++ b/ObjLoader/TypeParsers/ITypeParser.cs @@ -1,4 +1,4 @@ -namespace ObjLoader.Loader.TypeParsers.Interfaces +namespace ObjLoader.TypeParsers { public interface ITypeParser { diff --git a/ObjLoader/TypeParsers/Interfaces/IFaceParser.cs b/ObjLoader/TypeParsers/Interfaces/IFaceParser.cs deleted file mode 100644 index a78fa13..0000000 --- a/ObjLoader/TypeParsers/Interfaces/IFaceParser.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ObjLoader.Loader.TypeParsers.Interfaces -{ - public interface IFaceParser : ITypeParser - { - } -} \ No newline at end of file diff --git a/ObjLoader/TypeParsers/Interfaces/IGroupParser.cs b/ObjLoader/TypeParsers/Interfaces/IGroupParser.cs deleted file mode 100644 index 0755d05..0000000 --- a/ObjLoader/TypeParsers/Interfaces/IGroupParser.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ObjLoader.Loader.TypeParsers.Interfaces -{ - public interface IGroupParser : ITypeParser - { - } -} \ No newline at end of file diff --git a/ObjLoader/TypeParsers/Interfaces/IMaterialLibraryParser.cs b/ObjLoader/TypeParsers/Interfaces/IMaterialLibraryParser.cs deleted file mode 100644 index f2df760..0000000 --- a/ObjLoader/TypeParsers/Interfaces/IMaterialLibraryParser.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ObjLoader.Loader.TypeParsers.Interfaces -{ - public interface IMaterialLibraryParser : ITypeParser - { - } -} \ No newline at end of file diff --git a/ObjLoader/TypeParsers/Interfaces/INormalParser.cs b/ObjLoader/TypeParsers/Interfaces/INormalParser.cs deleted file mode 100644 index 0a9f993..0000000 --- a/ObjLoader/TypeParsers/Interfaces/INormalParser.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ObjLoader.Loader.TypeParsers.Interfaces -{ - public interface INormalParser : ITypeParser - { - } -} \ No newline at end of file diff --git a/ObjLoader/TypeParsers/Interfaces/ITextureParser.cs b/ObjLoader/TypeParsers/Interfaces/ITextureParser.cs deleted file mode 100644 index 68aed32..0000000 --- a/ObjLoader/TypeParsers/Interfaces/ITextureParser.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ObjLoader.Loader.TypeParsers.Interfaces -{ - public interface ITextureParser : ITypeParser - { - } -} \ No newline at end of file diff --git a/ObjLoader/TypeParsers/Interfaces/IUseMaterialParser.cs b/ObjLoader/TypeParsers/Interfaces/IUseMaterialParser.cs deleted file mode 100644 index 84b2116..0000000 --- a/ObjLoader/TypeParsers/Interfaces/IUseMaterialParser.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ObjLoader.Loader.TypeParsers.Interfaces -{ - public interface IUseMaterialParser : ITypeParser - { - } -} \ No newline at end of file diff --git a/ObjLoader/TypeParsers/Interfaces/IVertexParser.cs b/ObjLoader/TypeParsers/Interfaces/IVertexParser.cs deleted file mode 100644 index 2ea2059..0000000 --- a/ObjLoader/TypeParsers/Interfaces/IVertexParser.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ObjLoader.Loader.TypeParsers.Interfaces -{ - public interface IVertexParser : ITypeParser - { - } -} \ No newline at end of file diff --git a/ObjLoader/TypeParsers/MaterialLibraryParser.cs b/ObjLoader/TypeParsers/MaterialLibraryParser.cs index fd78743..ab11553 100644 --- a/ObjLoader/TypeParsers/MaterialLibraryParser.cs +++ b/ObjLoader/TypeParsers/MaterialLibraryParser.cs @@ -1,9 +1,9 @@ using ObjLoader.Loader.Loaders; -using ObjLoader.Loader.TypeParsers.Interfaces; +using ObjLoader.TypeParsers; namespace ObjLoader.Loader.TypeParsers { - public class MaterialLibraryParser : TypeParserBase, IMaterialLibraryParser + public class MaterialLibraryParser : TypeParserBase, ITypeParser { private readonly IMaterialLibraryLoaderFacade _libraryLoaderFacade; diff --git a/ObjLoader/TypeParsers/NormalParser.cs b/ObjLoader/TypeParsers/NormalParser.cs index 2271a2d..57f0d7a 100644 --- a/ObjLoader/TypeParsers/NormalParser.cs +++ b/ObjLoader/TypeParsers/NormalParser.cs @@ -1,11 +1,11 @@ +using ObjLoader.Data; using ObjLoader.Loader.Common; -using ObjLoader.Loader.Data.DataStore; -using ObjLoader.Loader.TypeParsers.Interfaces; +using ObjLoader.TypeParsers; using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; namespace ObjLoader.Loader.TypeParsers { - public class NormalParser : TypeParserBase, INormalParser + public class NormalParser : TypeParserBase, ITypeParser { private readonly DataStore _dataStore; diff --git a/ObjLoader/TypeParsers/TextureParser.cs b/ObjLoader/TypeParsers/TextureParser.cs index e0f4fdf..6d25f30 100644 --- a/ObjLoader/TypeParsers/TextureParser.cs +++ b/ObjLoader/TypeParsers/TextureParser.cs @@ -1,11 +1,11 @@ -using ObjLoader.Loader.Common; -using ObjLoader.Loader.Data.DataStore; -using ObjLoader.Loader.TypeParsers.Interfaces; +using ObjLoader.Data; +using ObjLoader.Loader.Common; +using ObjLoader.TypeParsers; using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; namespace ObjLoader.Loader.TypeParsers { - public class TextureParser : TypeParserBase, ITextureParser + public class TextureParser : TypeParserBase, ITypeParser { private readonly DataStore _dataStore; diff --git a/ObjLoader/TypeParsers/TypeParserBase.cs b/ObjLoader/TypeParsers/TypeParserBase.cs index 5441855..7880db8 100644 --- a/ObjLoader/TypeParsers/TypeParserBase.cs +++ b/ObjLoader/TypeParsers/TypeParserBase.cs @@ -1,5 +1,5 @@ using ObjLoader.Loader.Common; -using ObjLoader.Loader.TypeParsers.Interfaces; +using ObjLoader.TypeParsers; namespace ObjLoader.Loader.TypeParsers { diff --git a/ObjLoader/TypeParsers/UseMaterialParser.cs b/ObjLoader/TypeParsers/UseMaterialParser.cs index 39e7cd6..efdff4c 100644 --- a/ObjLoader/TypeParsers/UseMaterialParser.cs +++ b/ObjLoader/TypeParsers/UseMaterialParser.cs @@ -1,9 +1,9 @@ -using ObjLoader.Loader.Data.DataStore; -using ObjLoader.Loader.TypeParsers.Interfaces; +using ObjLoader.Data; +using ObjLoader.TypeParsers; namespace ObjLoader.Loader.TypeParsers { - public class UseMaterialParser : TypeParserBase, IUseMaterialParser + public class UseMaterialParser : TypeParserBase, ITypeParser { private readonly IElementGroup _elementGroup; diff --git a/ObjLoader/TypeParsers/VertexParser.cs b/ObjLoader/TypeParsers/VertexParser.cs index 7e2e609..545555b 100644 --- a/ObjLoader/TypeParsers/VertexParser.cs +++ b/ObjLoader/TypeParsers/VertexParser.cs @@ -1,12 +1,12 @@ +using ObjLoader.Data; using ObjLoader.Loader.Common; -using ObjLoader.Loader.Data.DataStore; -using ObjLoader.Loader.TypeParsers.Interfaces; +using ObjLoader.TypeParsers; using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; using System; namespace ObjLoader.Loader.TypeParsers { - public class VertexParser : TypeParserBase, IVertexParser + public class VertexParser : TypeParserBase, ITypeParser { private readonly DataStore _dataStore; diff --git a/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs b/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs index d5f4df0..5aeb48f 100644 --- a/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs +++ b/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs @@ -1,10 +1,10 @@ using System.IO; using System.Text; +using System.Linq; using NUnit.Framework; -using ObjLoader.Loader.Data.DataStore; using ObjLoader.Loader.Loaders; using ObjLoader.Loader.TypeParsers; -using System.Linq; +using ObjLoader.Data; using FluentAssertions; namespace ObjLoader.Test.Loaders diff --git a/Tests/ObjLoader.Test/TypeParsers/UseMaterialParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/UseMaterialParserTests.cs index b22345e..9cf8cca 100644 --- a/Tests/ObjLoader.Test/TypeParsers/UseMaterialParserTests.cs +++ b/Tests/ObjLoader.Test/TypeParsers/UseMaterialParserTests.cs @@ -1,7 +1,6 @@ using FluentAssertions; using NUnit.Framework; -using ObjLoader.Loader.Data; -using ObjLoader.Loader.Data.DataStore; +using ObjLoader.Data; using ObjLoader.Loader.TypeParsers; namespace ObjLoader.Test.TypeParsers From 52cc102688b4d61754dd0ff5c150ba490270f8d8 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Fri, 11 Apr 2025 20:25:30 +0300 Subject: [PATCH 49/92] #2 More redundant interfaces --- ObjLoader/Loaders/IMaterialLibraryLoader.cs | 9 ------ ObjLoader/Loaders/IObjLoaderFactory.cs | 1 - ObjLoader/Loaders/MaterialLibraryLoader.cs | 17 ++++++++--- .../Loaders/MaterialLibraryLoaderFacade.cs | 8 ++--- ObjLoader/Loaders/MaterialStreamProvider.cs | 30 ------------------- ObjLoader/Loaders/ObjLoaderFactory.cs | 15 +++------- .../ObjLoader.Test/Loaders/ObjLoaderTests.cs | 10 +++++-- 7 files changed, 27 insertions(+), 63 deletions(-) delete mode 100644 ObjLoader/Loaders/IMaterialLibraryLoader.cs delete mode 100644 ObjLoader/Loaders/MaterialStreamProvider.cs diff --git a/ObjLoader/Loaders/IMaterialLibraryLoader.cs b/ObjLoader/Loaders/IMaterialLibraryLoader.cs deleted file mode 100644 index 52d4cc3..0000000 --- a/ObjLoader/Loaders/IMaterialLibraryLoader.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.IO; - -namespace ObjLoader.Loader.Loaders -{ - public interface IMaterialLibraryLoader - { - void Load(Stream lineStream); - } -} \ No newline at end of file diff --git a/ObjLoader/Loaders/IObjLoaderFactory.cs b/ObjLoader/Loaders/IObjLoaderFactory.cs index 2123ff9..b4bfc95 100644 --- a/ObjLoader/Loaders/IObjLoaderFactory.cs +++ b/ObjLoader/Loaders/IObjLoaderFactory.cs @@ -2,7 +2,6 @@ namespace ObjLoader.Loader.Loaders { public interface IObjLoaderFactory { - IObjLoader Create(IMaterialStreamProvider materialStreamProvider); IObjLoader Create(); } } \ No newline at end of file diff --git a/ObjLoader/Loaders/MaterialLibraryLoader.cs b/ObjLoader/Loaders/MaterialLibraryLoader.cs index 98ee700..e31acd6 100644 --- a/ObjLoader/Loaders/MaterialLibraryLoader.cs +++ b/ObjLoader/Loaders/MaterialLibraryLoader.cs @@ -1,6 +1,5 @@ using ObjLoader.Data; using ObjLoader.Loader.Common; -using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; using SharpEngine.Core.Components.Properties; using System; @@ -10,14 +9,16 @@ namespace ObjLoader.Loader.Loaders { - public class MaterialLibraryLoader : LoaderBase, IMaterialLibraryLoader + public class MaterialLibraryLoader : LoaderBase { + private string _objPath; private readonly DataStore _dataStore; private readonly Dictionary> _parseActionDictionary = []; private readonly List _unrecognizedLines = []; - public MaterialLibraryLoader(DataStore dataStore) - { + public MaterialLibraryLoader(string objPath, DataStore dataStore) + { + _objPath = objPath; _dataStore = dataStore; AddParseAction("newmtl", PushMaterial); @@ -90,5 +91,13 @@ private static Vector3 ParseVec3(string data) } 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/ObjLoader/Loaders/MaterialLibraryLoaderFacade.cs b/ObjLoader/Loaders/MaterialLibraryLoaderFacade.cs index c1c23a3..ee4bc9d 100644 --- a/ObjLoader/Loaders/MaterialLibraryLoaderFacade.cs +++ b/ObjLoader/Loaders/MaterialLibraryLoaderFacade.cs @@ -2,18 +2,16 @@ namespace ObjLoader.Loader.Loaders { public class MaterialLibraryLoaderFacade : IMaterialLibraryLoaderFacade { - private readonly IMaterialLibraryLoader _loader; - private readonly IMaterialStreamProvider _materialStreamProvider; + private readonly MaterialLibraryLoader _loader; - public MaterialLibraryLoaderFacade(IMaterialLibraryLoader loader, IMaterialStreamProvider materialStreamProvider) + public MaterialLibraryLoaderFacade(MaterialLibraryLoader loader) { _loader = loader; - _materialStreamProvider = materialStreamProvider; } public void Load(string materialFileName) { - using var stream = _materialStreamProvider.Open(materialFileName); + using var stream = _loader.Open(materialFileName); if (stream != null) _loader.Load(stream); diff --git a/ObjLoader/Loaders/MaterialStreamProvider.cs b/ObjLoader/Loaders/MaterialStreamProvider.cs deleted file mode 100644 index b8f96bf..0000000 --- a/ObjLoader/Loaders/MaterialStreamProvider.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.IO; - -namespace ObjLoader.Loader.Loaders -{ - public class MaterialStreamProvider : IMaterialStreamProvider - { - private string _objPath; - - public MaterialStreamProvider(string objPath) - { - _objPath = objPath; - } - - /// - public Stream Open(string materialFilePath) - { - var dir = Path.GetDirectoryName(_objPath); - var path = Path.Combine(dir, materialFilePath); - return File.Open(path, FileMode.Open, FileAccess.Read); - } - } - - public class MaterialNullStreamProvider : IMaterialStreamProvider - { - public Stream Open(string materialFilePath) - { - return null; - } - } -} \ No newline at end of file diff --git a/ObjLoader/Loaders/ObjLoaderFactory.cs b/ObjLoader/Loaders/ObjLoaderFactory.cs index 0814477..7f0e6f0 100644 --- a/ObjLoader/Loaders/ObjLoaderFactory.cs +++ b/ObjLoader/Loaders/ObjLoaderFactory.cs @@ -4,24 +4,17 @@ namespace ObjLoader.Loader.Loaders { - public interface IMaterialStreamProvider - { - Stream Open(string materialFilePath); - } - public class ObjLoaderFactory : IObjLoaderFactory { - private string _path; + private readonly string _path; public ObjLoaderFactory(string path) { _path = path; } + /// public IObjLoader Create() - => Create(new MaterialStreamProvider(_path)); - - public IObjLoader Create(IMaterialStreamProvider materialStreamProvider) { var dataStore = new DataStore(); @@ -31,8 +24,8 @@ public IObjLoader Create(IMaterialStreamProvider materialStreamProvider) var textureParser = new TextureParser(dataStore); var vertexParser = new VertexParser(dataStore); - var materialLibraryLoader = new MaterialLibraryLoader(dataStore); - var materialLibraryLoaderFacade = new MaterialLibraryLoaderFacade(materialLibraryLoader, materialStreamProvider); + var materialLibraryLoader = new MaterialLibraryLoader(_path, dataStore); + var materialLibraryLoaderFacade = new MaterialLibraryLoaderFacade(materialLibraryLoader); var materialLibraryParser = new MaterialLibraryParser(materialLibraryLoaderFacade); var useMaterialParser = new UseMaterialParser(dataStore); diff --git a/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs b/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs index 5aeb48f..e7a849d 100644 --- a/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs +++ b/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs @@ -52,8 +52,8 @@ public void SetUp() _materialStreamProviderSpy = new MaterialStreamProviderSpy(); _materialStreamProviderSpy.StreamToReturn = CreateMemoryStreamFromString(MaterialLibraryString); - _materialLibraryLoader = new MaterialLibraryLoader(_textureDataStore); - _materialLibraryLoaderFacade = new MaterialLibraryLoaderFacade(_materialLibraryLoader, _materialStreamProviderSpy); + _materialLibraryLoader = new MaterialLibraryLoader("", _textureDataStore); + _materialLibraryLoaderFacade = new MaterialLibraryLoaderFacade(_materialLibraryLoader); _materialLibraryParser = new MaterialLibraryParser(_materialLibraryLoaderFacade); _useMaterialParser = new UseMaterialParser(_textureDataStore); @@ -83,7 +83,7 @@ public void Loads_object_and_material_correctly() public void Loads_object_correctly_when_material_is_not_found() { _materialStreamProviderSpy.StreamToReturn = null; - var materialLibraryLoaderFacade = new MaterialLibraryLoaderFacade(_materialLibraryLoader, _materialStreamProviderSpy); + var materialLibraryLoaderFacade = new MaterialLibraryLoaderFacade(_materialLibraryLoader); var materialLibraryParser = new MaterialLibraryParser(materialLibraryLoaderFacade); // _loader = new Loader.Loaders.ObjLoader(_textureDataStore, _faceParser, _groupParser, _normalParser, _textureParser, _vertexParser, materialLibraryParser, _useMaterialParser); @@ -182,4 +182,8 @@ map_bump lenna_bump.tga disp lenna_disp.tga decal lenna_stencil.tga"; } + + internal interface IMaterialStreamProvider + { + } } \ No newline at end of file From 2cb8b12dac0f66e24e7b60defd9c4e03733cfe33 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Fri, 11 Apr 2025 20:33:04 +0300 Subject: [PATCH 50/92] #2 More redundancies --- ObjLoader/Loaders/IObjLoader.cs | 9 --------- ObjLoader/Loaders/IObjLoaderFactory.cs | 7 ------- ObjLoader/Loaders/ObjLoader.cs | 5 +++-- ObjLoader/Loaders/ObjLoaderFactory.cs | 8 +++----- ObjLoader/TypeParsers/MaterialLibraryParser.cs | 4 ++-- .../Properties/Meshes/MeshData}/LoadResult.cs | 0 Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs | 4 ++-- .../TypeParsers/MaterialLibraryParserTests.cs | 2 +- 8 files changed, 11 insertions(+), 28 deletions(-) delete mode 100644 ObjLoader/Loaders/IObjLoader.cs delete mode 100644 ObjLoader/Loaders/IObjLoaderFactory.cs rename {ObjLoader/Loaders => SharpEngine.Core.Components/Properties/Meshes/MeshData}/LoadResult.cs (100%) diff --git a/ObjLoader/Loaders/IObjLoader.cs b/ObjLoader/Loaders/IObjLoader.cs deleted file mode 100644 index ef9a584..0000000 --- a/ObjLoader/Loaders/IObjLoader.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.IO; - -namespace ObjLoader.Loader.Loaders -{ - public interface IObjLoader - { - LoadResult Load(); - } -} \ No newline at end of file diff --git a/ObjLoader/Loaders/IObjLoaderFactory.cs b/ObjLoader/Loaders/IObjLoaderFactory.cs deleted file mode 100644 index b4bfc95..0000000 --- a/ObjLoader/Loaders/IObjLoaderFactory.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ObjLoader.Loader.Loaders -{ - public interface IObjLoaderFactory - { - IObjLoader Create(); - } -} \ No newline at end of file diff --git a/ObjLoader/Loaders/ObjLoader.cs b/ObjLoader/Loaders/ObjLoader.cs index 4cdfe64..6a3eb08 100644 --- a/ObjLoader/Loaders/ObjLoader.cs +++ b/ObjLoader/Loaders/ObjLoader.cs @@ -6,9 +6,9 @@ namespace ObjLoader.Loader.Loaders { - public class ObjLoader : LoaderBase, IObjLoader + public class ObjLoader : LoaderBase { - private string _path; + private readonly string _path; private readonly DataStore _dataStore; private readonly List _typeParsers = []; private readonly List _unrecognizedLines = []; @@ -45,6 +45,7 @@ private void SetupTypeParsers(params ITypeParser[] parsers) } } + /// protected override void ParseLine(string keyword, string data) { foreach (var typeParser in _typeParsers) diff --git a/ObjLoader/Loaders/ObjLoaderFactory.cs b/ObjLoader/Loaders/ObjLoaderFactory.cs index 7f0e6f0..0df403d 100644 --- a/ObjLoader/Loaders/ObjLoaderFactory.cs +++ b/ObjLoader/Loaders/ObjLoaderFactory.cs @@ -1,10 +1,9 @@ -using System.IO; using ObjLoader.Data; using ObjLoader.Loader.TypeParsers; namespace ObjLoader.Loader.Loaders { - public class ObjLoaderFactory : IObjLoaderFactory + public class ObjLoaderFactory { private readonly string _path; @@ -14,7 +13,7 @@ public ObjLoaderFactory(string path) } /// - public IObjLoader Create() + public ObjLoader Create() { var dataStore = new DataStore(); @@ -25,8 +24,7 @@ public IObjLoader Create() var vertexParser = new VertexParser(dataStore); var materialLibraryLoader = new MaterialLibraryLoader(_path, dataStore); - var materialLibraryLoaderFacade = new MaterialLibraryLoaderFacade(materialLibraryLoader); - var materialLibraryParser = new MaterialLibraryParser(materialLibraryLoaderFacade); + var materialLibraryParser = new MaterialLibraryParser(materialLibraryLoader); var useMaterialParser = new UseMaterialParser(dataStore); return new ObjLoader(_path, dataStore, faceParser, groupParser, normalParser, textureParser, vertexParser, materialLibraryParser, useMaterialParser); diff --git a/ObjLoader/TypeParsers/MaterialLibraryParser.cs b/ObjLoader/TypeParsers/MaterialLibraryParser.cs index ab11553..b43e42f 100644 --- a/ObjLoader/TypeParsers/MaterialLibraryParser.cs +++ b/ObjLoader/TypeParsers/MaterialLibraryParser.cs @@ -7,9 +7,9 @@ public class MaterialLibraryParser : TypeParserBase, ITypeParser { private readonly IMaterialLibraryLoaderFacade _libraryLoaderFacade; - public MaterialLibraryParser(IMaterialLibraryLoaderFacade libraryLoaderFacade) + public MaterialLibraryParser(MaterialLibraryLoader loader) { - _libraryLoaderFacade = libraryLoaderFacade; + _libraryLoaderFacade = new MaterialLibraryLoaderFacade(loader); } /// diff --git a/ObjLoader/Loaders/LoadResult.cs b/SharpEngine.Core.Components/Properties/Meshes/MeshData/LoadResult.cs similarity index 100% rename from ObjLoader/Loaders/LoadResult.cs rename to SharpEngine.Core.Components/Properties/Meshes/MeshData/LoadResult.cs diff --git a/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs b/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs index e7a849d..8c426f8 100644 --- a/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs +++ b/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs @@ -54,7 +54,7 @@ public void SetUp() _materialLibraryLoader = new MaterialLibraryLoader("", _textureDataStore); _materialLibraryLoaderFacade = new MaterialLibraryLoaderFacade(_materialLibraryLoader); - _materialLibraryParser = new MaterialLibraryParser(_materialLibraryLoaderFacade); + // _materialLibraryParser = new MaterialLibraryParser(_materialLibraryLoaderFacade); _useMaterialParser = new UseMaterialParser(_textureDataStore); // _loader = new Loader.Loaders.ObjLoader(_textureDataStore, _faceParser, _groupParser, _normalParser, _textureParser, _vertexParser, _materialLibraryParser, _useMaterialParser); @@ -84,7 +84,7 @@ public void Loads_object_correctly_when_material_is_not_found() { _materialStreamProviderSpy.StreamToReturn = null; var materialLibraryLoaderFacade = new MaterialLibraryLoaderFacade(_materialLibraryLoader); - var materialLibraryParser = new MaterialLibraryParser(materialLibraryLoaderFacade); + // var materialLibraryParser = new MaterialLibraryParser(materialLibraryLoaderFacade); // _loader = new Loader.Loaders.ObjLoader(_textureDataStore, _faceParser, _groupParser, _normalParser, _textureParser, _vertexParser, materialLibraryParser, _useMaterialParser); diff --git a/Tests/ObjLoader.Test/TypeParsers/MaterialLibraryParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/MaterialLibraryParserTests.cs index 387e0db..072c408 100644 --- a/Tests/ObjLoader.Test/TypeParsers/MaterialLibraryParserTests.cs +++ b/Tests/ObjLoader.Test/TypeParsers/MaterialLibraryParserTests.cs @@ -15,7 +15,7 @@ public class MaterialLibraryParserTests public void SetUp() { _materialLibraryLoaderFacadeSpy = new MaterialLibraryLoaderFacadeSpy(); - _parser = new MaterialLibraryParser(_materialLibraryLoaderFacadeSpy); + // _parser = new MaterialLibraryParser(_materialLibraryLoaderFacadeSpy); } [Test] From 8026f6beb2bca65f539294858f639423118600f7 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Fri, 11 Apr 2025 20:37:28 +0300 Subject: [PATCH 51/92] #2 simplify data store --- Examples/MinecraftClone/Minecraft.cs | 14 ++++++-------- ObjLoader/Data/IElementGroup.cs | 7 ------- ObjLoader/{Data => }/DataStore.cs | 4 ++-- .../IMaterialLibraryLoaderFacade.cs | 2 +- .../{ => MaterialLoader}/MaterialLibraryLoader.cs | 6 +++--- .../MaterialLibraryLoaderFacade.cs | 2 +- ObjLoader/Loaders/{ => ObjLoader}/ObjLoader.cs | 8 ++------ .../Loaders/{ => ObjLoader}/ObjLoaderFactory.cs | 4 ++-- ObjLoader/TypeParsers/GroupParser.cs | 3 +-- ObjLoader/TypeParsers/MaterialLibraryParser.cs | 1 + ObjLoader/TypeParsers/NormalParser.cs | 1 - ObjLoader/TypeParsers/TextureParser.cs | 3 +-- ObjLoader/TypeParsers/UseMaterialParser.cs | 11 +++++------ ObjLoader/TypeParsers/VertexParser.cs | 1 - .../Loaders/MaterialLibraryLoaderTests.cs | 2 +- Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs | 4 ++-- .../TypeParsers/MaterialLibraryParserTests.cs | 2 +- .../TypeParsers/UseMaterialParserTests.cs | 5 ++--- 18 files changed, 31 insertions(+), 49 deletions(-) delete mode 100644 ObjLoader/Data/IElementGroup.cs rename ObjLoader/{Data => }/DataStore.cs (93%) rename ObjLoader/Loaders/{ => MaterialLoader}/IMaterialLibraryLoaderFacade.cs (71%) rename ObjLoader/Loaders/{ => MaterialLoader}/MaterialLibraryLoader.cs (97%) rename ObjLoader/Loaders/{ => MaterialLoader}/MaterialLibraryLoaderFacade.cs (91%) rename ObjLoader/Loaders/{ => ObjLoader}/ObjLoader.cs (94%) rename ObjLoader/Loaders/{ => ObjLoader}/ObjLoaderFactory.cs (93%) diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index 502cfac..08c79fb 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -1,22 +1,20 @@ using ImGuiNET; using Minecraft.Block; -using ObjLoader.Loader.Loaders; +using ObjLoader.Loaders.ObjLoader; +using Silk.NET.Input; + +using System; +using System.Numerics; + 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 Silk.NET.Input; -using System; -using System.IO; -using System.Linq; -using System.Numerics; namespace Minecraft; diff --git a/ObjLoader/Data/IElementGroup.cs b/ObjLoader/Data/IElementGroup.cs deleted file mode 100644 index 7c78289..0000000 --- a/ObjLoader/Data/IElementGroup.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ObjLoader.Data -{ - public interface IElementGroup - { - void SetMaterial(string materialName); - } -} \ No newline at end of file diff --git a/ObjLoader/Data/DataStore.cs b/ObjLoader/DataStore.cs similarity index 93% rename from ObjLoader/Data/DataStore.cs rename to ObjLoader/DataStore.cs index 8f6e58f..b877aac 100644 --- a/ObjLoader/Data/DataStore.cs +++ b/ObjLoader/DataStore.cs @@ -7,9 +7,9 @@ using System.Collections.Generic; using System.Linq; -namespace ObjLoader.Data +namespace ObjLoader { - public class DataStore : IGroupDataStore, IFaceGroup, IElementGroup + public class DataStore : IGroupDataStore, IFaceGroup { private Group _currentGroup; diff --git a/ObjLoader/Loaders/IMaterialLibraryLoaderFacade.cs b/ObjLoader/Loaders/MaterialLoader/IMaterialLibraryLoaderFacade.cs similarity index 71% rename from ObjLoader/Loaders/IMaterialLibraryLoaderFacade.cs rename to ObjLoader/Loaders/MaterialLoader/IMaterialLibraryLoaderFacade.cs index c1c8781..4417065 100644 --- a/ObjLoader/Loaders/IMaterialLibraryLoaderFacade.cs +++ b/ObjLoader/Loaders/MaterialLoader/IMaterialLibraryLoaderFacade.cs @@ -1,4 +1,4 @@ -namespace ObjLoader.Loader.Loaders +namespace ObjLoader.Loaders.MaterialLoader { public interface IMaterialLibraryLoaderFacade { diff --git a/ObjLoader/Loaders/MaterialLibraryLoader.cs b/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoader.cs similarity index 97% rename from ObjLoader/Loaders/MaterialLibraryLoader.cs rename to ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoader.cs index e31acd6..7a66889 100644 --- a/ObjLoader/Loaders/MaterialLibraryLoader.cs +++ b/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoader.cs @@ -1,5 +1,5 @@ -using ObjLoader.Data; -using ObjLoader.Loader.Common; +using ObjLoader.Loader.Common; +using ObjLoader.Loader.Loaders; using SharpEngine.Core.Components.Properties; using System; @@ -7,7 +7,7 @@ using System.IO; using System.Numerics; -namespace ObjLoader.Loader.Loaders +namespace ObjLoader.Loaders.MaterialLoader { public class MaterialLibraryLoader : LoaderBase { diff --git a/ObjLoader/Loaders/MaterialLibraryLoaderFacade.cs b/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoaderFacade.cs similarity index 91% rename from ObjLoader/Loaders/MaterialLibraryLoaderFacade.cs rename to ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoaderFacade.cs index ee4bc9d..edb433e 100644 --- a/ObjLoader/Loaders/MaterialLibraryLoaderFacade.cs +++ b/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoaderFacade.cs @@ -1,4 +1,4 @@ -namespace ObjLoader.Loader.Loaders +namespace ObjLoader.Loaders.MaterialLoader { public class MaterialLibraryLoaderFacade : IMaterialLibraryLoaderFacade { diff --git a/ObjLoader/Loaders/ObjLoader.cs b/ObjLoader/Loaders/ObjLoader/ObjLoader.cs similarity index 94% rename from ObjLoader/Loaders/ObjLoader.cs rename to ObjLoader/Loaders/ObjLoader/ObjLoader.cs index 6a3eb08..ce6f59a 100644 --- a/ObjLoader/Loaders/ObjLoader.cs +++ b/ObjLoader/Loaders/ObjLoader/ObjLoader.cs @@ -1,10 +1,10 @@ -using ObjLoader.Data; +using ObjLoader.Loader.Loaders; using ObjLoader.TypeParsers; using System.Collections.Generic; using System.IO; -namespace ObjLoader.Loader.Loaders +namespace ObjLoader.Loaders.ObjLoader { public class ObjLoader : LoaderBase { @@ -40,22 +40,18 @@ public ObjLoader( private void SetupTypeParsers(params ITypeParser[] parsers) { foreach (var parser in parsers) - { _typeParsers.Add(parser); - } } /// protected override void ParseLine(string keyword, string data) { foreach (var typeParser in _typeParsers) - { if (typeParser.CanParse(keyword)) { typeParser.Parse(data); return; } - } _unrecognizedLines.Add(keyword + " " + data); } diff --git a/ObjLoader/Loaders/ObjLoaderFactory.cs b/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs similarity index 93% rename from ObjLoader/Loaders/ObjLoaderFactory.cs rename to ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs index 0df403d..3c4006d 100644 --- a/ObjLoader/Loaders/ObjLoaderFactory.cs +++ b/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs @@ -1,7 +1,7 @@ -using ObjLoader.Data; using ObjLoader.Loader.TypeParsers; +using ObjLoader.Loaders.MaterialLoader; -namespace ObjLoader.Loader.Loaders +namespace ObjLoader.Loaders.ObjLoader { public class ObjLoaderFactory { diff --git a/ObjLoader/TypeParsers/GroupParser.cs b/ObjLoader/TypeParsers/GroupParser.cs index 88a259d..b8d1512 100644 --- a/ObjLoader/TypeParsers/GroupParser.cs +++ b/ObjLoader/TypeParsers/GroupParser.cs @@ -1,5 +1,4 @@ -using ObjLoader.Data; -using ObjLoader.TypeParsers; +using ObjLoader.TypeParsers; namespace ObjLoader.Loader.TypeParsers { diff --git a/ObjLoader/TypeParsers/MaterialLibraryParser.cs b/ObjLoader/TypeParsers/MaterialLibraryParser.cs index b43e42f..7b7c2b4 100644 --- a/ObjLoader/TypeParsers/MaterialLibraryParser.cs +++ b/ObjLoader/TypeParsers/MaterialLibraryParser.cs @@ -1,4 +1,5 @@ using ObjLoader.Loader.Loaders; +using ObjLoader.Loaders.MaterialLoader; using ObjLoader.TypeParsers; namespace ObjLoader.Loader.TypeParsers diff --git a/ObjLoader/TypeParsers/NormalParser.cs b/ObjLoader/TypeParsers/NormalParser.cs index 57f0d7a..5e88183 100644 --- a/ObjLoader/TypeParsers/NormalParser.cs +++ b/ObjLoader/TypeParsers/NormalParser.cs @@ -1,4 +1,3 @@ -using ObjLoader.Data; using ObjLoader.Loader.Common; using ObjLoader.TypeParsers; using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; diff --git a/ObjLoader/TypeParsers/TextureParser.cs b/ObjLoader/TypeParsers/TextureParser.cs index 6d25f30..a251c24 100644 --- a/ObjLoader/TypeParsers/TextureParser.cs +++ b/ObjLoader/TypeParsers/TextureParser.cs @@ -1,5 +1,4 @@ -using ObjLoader.Data; -using ObjLoader.Loader.Common; +using ObjLoader.Loader.Common; using ObjLoader.TypeParsers; using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; diff --git a/ObjLoader/TypeParsers/UseMaterialParser.cs b/ObjLoader/TypeParsers/UseMaterialParser.cs index efdff4c..72f33d8 100644 --- a/ObjLoader/TypeParsers/UseMaterialParser.cs +++ b/ObjLoader/TypeParsers/UseMaterialParser.cs @@ -1,21 +1,20 @@ -using ObjLoader.Data; -using ObjLoader.TypeParsers; +using ObjLoader.TypeParsers; namespace ObjLoader.Loader.TypeParsers { public class UseMaterialParser : TypeParserBase, ITypeParser { - private readonly IElementGroup _elementGroup; + private readonly DataStore _dataStore; - public UseMaterialParser(IElementGroup elementGroup) + public UseMaterialParser(DataStore dataStore) { - _elementGroup = elementGroup; + _dataStore = dataStore; } /// protected override string Keyword => "usemtl"; /// - public override void Parse(string line) => _elementGroup.SetMaterial(line); + public override void Parse(string line) => _dataStore.SetMaterial(line); } } \ No newline at end of file diff --git a/ObjLoader/TypeParsers/VertexParser.cs b/ObjLoader/TypeParsers/VertexParser.cs index 545555b..dcd5cbe 100644 --- a/ObjLoader/TypeParsers/VertexParser.cs +++ b/ObjLoader/TypeParsers/VertexParser.cs @@ -1,4 +1,3 @@ -using ObjLoader.Data; using ObjLoader.Loader.Common; using ObjLoader.TypeParsers; using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; diff --git a/Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs b/Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs index 1075303..39c13c4 100644 --- a/Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs +++ b/Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs @@ -5,10 +5,10 @@ using ObjLoader.Loader.Data; using System.Linq; using FluentAssertions; -using ObjLoader.Loader.Loaders; using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; using SharpEngine.Core.Entities.Properties; using SharpEngine.Core.Components.Properties; +using ObjLoader.Loaders.MaterialLoader; namespace ObjLoader.Test.Loaders { diff --git a/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs b/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs index 8c426f8..e27daf1 100644 --- a/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs +++ b/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs @@ -4,8 +4,8 @@ using NUnit.Framework; using ObjLoader.Loader.Loaders; using ObjLoader.Loader.TypeParsers; -using ObjLoader.Data; using FluentAssertions; +using ObjLoader.Loaders.MaterialLoader; namespace ObjLoader.Test.Loaders { @@ -24,7 +24,7 @@ public Stream Open(string materialFilePath) } } - private Loader.Loaders.ObjLoader _loader; + private ObjLoader.Loaders.ObjLoader.ObjLoader _loader; private LoadResult _loadResult; private DataStore _textureDataStore; diff --git a/Tests/ObjLoader.Test/TypeParsers/MaterialLibraryParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/MaterialLibraryParserTests.cs index 072c408..91089f1 100644 --- a/Tests/ObjLoader.Test/TypeParsers/MaterialLibraryParserTests.cs +++ b/Tests/ObjLoader.Test/TypeParsers/MaterialLibraryParserTests.cs @@ -1,7 +1,7 @@ using FluentAssertions; using NUnit.Framework; -using ObjLoader.Loader.Loaders; using ObjLoader.Loader.TypeParsers; +using ObjLoader.Loaders.MaterialLoader; namespace ObjLoader.Test.TypeParsers { diff --git a/Tests/ObjLoader.Test/TypeParsers/UseMaterialParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/UseMaterialParserTests.cs index 9cf8cca..863fac8 100644 --- a/Tests/ObjLoader.Test/TypeParsers/UseMaterialParserTests.cs +++ b/Tests/ObjLoader.Test/TypeParsers/UseMaterialParserTests.cs @@ -1,6 +1,5 @@ using FluentAssertions; using NUnit.Framework; -using ObjLoader.Data; using ObjLoader.Loader.TypeParsers; namespace ObjLoader.Test.TypeParsers @@ -15,7 +14,7 @@ public class UseMaterialParserTests public void SetUp() { _elementGroupSpy = new ElementGroupSpy(); - _parser = new UseMaterialParser(_elementGroupSpy); + // _parser = new UseMaterialParser(_elementGroupSpy); } [Test] @@ -45,7 +44,7 @@ public void Parses_usemtl_line_correctly_1() _elementGroupSpy.MaterialName.Should().BeEquivalentTo("materialName"); } - private class ElementGroupSpy : IElementGroup + private class ElementGroupSpy // : IElementGroup { public string MaterialName { get; private set; } From 5eb86612be726d7719f48d23d43a7d2b612b2ee2 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Fri, 11 Apr 2025 20:41:48 +0300 Subject: [PATCH 52/92] #2 Fixing readme details --- Directory.Build.props | 17 ++++++++--------- SharpEngine.Core/SharpEngine.Core.csproj | 9 +++++++++ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index b453701..c13bb19 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,13 +1,20 @@ + net8.0 + + + enable latest True + + + + Antti Veikkolainen - README.md https://github.com/Av3boy/SharpEngine @@ -26,13 +33,5 @@ 2.22.0 - - - - - True - \ - - \ No newline at end of file diff --git a/SharpEngine.Core/SharpEngine.Core.csproj b/SharpEngine.Core/SharpEngine.Core.csproj index 867a952..d25c4fa 100644 --- a/SharpEngine.Core/SharpEngine.Core.csproj +++ b/SharpEngine.Core/SharpEngine.Core.csproj @@ -12,6 +12,8 @@ $(AssemblyName).NET true + + README.md @@ -48,4 +50,11 @@ + + + True + \ + + + \ No newline at end of file From 9035fb95128567f1fbc59b93679c780da6eced68 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Fri, 11 Apr 2025 20:45:17 +0300 Subject: [PATCH 53/92] #2 Simplify call --- Examples/MinecraftClone/Minecraft.cs | 4 +--- ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs | 17 ++++++----------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index 08c79fb..4556068 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -149,9 +149,7 @@ private void InitializeWorld() // TODO: This should be simplified to something like this: // new ObjLoaderFactory().Load(); - var objLoaderFactory = new ObjLoaderFactory(@"C:\Users\antti\Documents\Untitled2.obj"); - var objLoader = objLoaderFactory.Create(); - var result = objLoader.Load(); + var result = ObjLoaderFactory.Load(@"C:\Users\antti\Documents\Untitled2.obj"); // var mesh = new Mesh() // { // Vertices = result.Vertices.ToArray(), diff --git a/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs b/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs index 3c4006d..c048dec 100644 --- a/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs +++ b/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs @@ -1,19 +1,13 @@ +using ObjLoader.Loader.Loaders; using ObjLoader.Loader.TypeParsers; using ObjLoader.Loaders.MaterialLoader; namespace ObjLoader.Loaders.ObjLoader { - public class ObjLoaderFactory + public static class ObjLoaderFactory { - private readonly string _path; - - public ObjLoaderFactory(string path) - { - _path = path; - } - /// - public ObjLoader Create() + public static LoadResult Load(string path) { var dataStore = new DataStore(); @@ -23,11 +17,12 @@ public ObjLoader Create() var textureParser = new TextureParser(dataStore); var vertexParser = new VertexParser(dataStore); - var materialLibraryLoader = new MaterialLibraryLoader(_path, dataStore); + var materialLibraryLoader = new MaterialLibraryLoader(path, dataStore); var materialLibraryParser = new MaterialLibraryParser(materialLibraryLoader); var useMaterialParser = new UseMaterialParser(dataStore); - return new ObjLoader(_path, dataStore, faceParser, groupParser, normalParser, textureParser, vertexParser, materialLibraryParser, useMaterialParser); + var loader = new ObjLoader(path, dataStore, faceParser, groupParser, normalParser, textureParser, vertexParser, materialLibraryParser, useMaterialParser); + return loader.Load(); } } } \ No newline at end of file From 58253031e719d7a2b90c5fe9101640f7a4e578cb Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Fri, 11 Apr 2025 20:48:45 +0300 Subject: [PATCH 54/92] #2 Quality of life improvements --- ObjLoader/Loaders/ObjLoader/ObjLoader.cs | 24 ++++--------------- .../Loaders/ObjLoader/ObjLoaderFactory.cs | 2 +- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/ObjLoader/Loaders/ObjLoader/ObjLoader.cs b/ObjLoader/Loaders/ObjLoader/ObjLoader.cs index ce6f59a..9eaa1ff 100644 --- a/ObjLoader/Loaders/ObjLoader/ObjLoader.cs +++ b/ObjLoader/Loaders/ObjLoader/ObjLoader.cs @@ -13,34 +13,18 @@ public class ObjLoader : LoaderBase private readonly List _typeParsers = []; private readonly List _unrecognizedLines = []; - public ObjLoader( - string path, - DataStore dataStore, - ITypeParser faceParser, - ITypeParser groupParser, - ITypeParser normalParser, - ITypeParser textureParser, - ITypeParser vertexParser, - ITypeParser materialLibraryParser, - ITypeParser useMaterialParser) + public ObjLoader(string path, DataStore dataStore) { _path = path; - _dataStore = dataStore; - SetupTypeParsers( - vertexParser, - faceParser, - normalParser, - textureParser, - groupParser, - materialLibraryParser, - useMaterialParser); } - private void SetupTypeParsers(params ITypeParser[] parsers) + public ObjLoader SetupTypeParsers(params ITypeParser[] parsers) { foreach (var parser in parsers) _typeParsers.Add(parser); + + return this; } /// diff --git a/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs b/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs index c048dec..7b3141a 100644 --- a/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs +++ b/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs @@ -21,7 +21,7 @@ public static LoadResult Load(string path) var materialLibraryParser = new MaterialLibraryParser(materialLibraryLoader); var useMaterialParser = new UseMaterialParser(dataStore); - var loader = new ObjLoader(path, dataStore, faceParser, groupParser, normalParser, textureParser, vertexParser, materialLibraryParser, useMaterialParser); + var loader = new ObjLoader(path, dataStore).SetupTypeParsers(faceParser, groupParser, normalParser, textureParser, vertexParser, materialLibraryParser, useMaterialParser); return loader.Load(); } } From 7e93b2757f0e3c878da201dc264f749bbadf4d72 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Fri, 11 Apr 2025 22:31:10 +0300 Subject: [PATCH 55/92] #2 Use mesh in obj loader --- ObjLoader/DataStore.cs | 2 +- ObjLoader/Loaders/ObjLoader/ObjLoader.cs | 8 ++++---- ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs | 4 ++-- ObjLoader/TypeParsers/NormalParser.cs | 2 +- ObjLoader/TypeParsers/TextureParser.cs | 2 +- ObjLoader/TypeParsers/VertexParser.cs | 2 +- .../ObjLoader/DataStore/INormalDataStore.cs | 2 +- .../ObjLoader/DataStore/ITextureDataStore.cs | 2 +- .../ObjLoader/DataStore/IVertexDataStore.cs | 2 +- .../Properties/Meshes/Mesh.cs | 12 +++++++++++- .../Properties/Meshes/MeshData/LoadResult.cs | 16 ---------------- .../Meshes/MeshData/{VertexData => }/Normal.cs | 2 +- .../{VertexData => }/TextureCoordinate.cs | 2 +- .../Meshes/MeshData/{VertexData => }/Vertex.cs | 2 +- .../Properties/Meshes/VertexData.cs | 7 +------ Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs | 3 ++- .../TypeParsers/NormalParserTests.cs | 2 +- .../TypeParsers/TextureParserTests.cs | 2 +- .../TypeParsers/VertexParserTests.cs | 2 +- 19 files changed, 33 insertions(+), 43 deletions(-) delete mode 100644 SharpEngine.Core.Components/Properties/Meshes/MeshData/LoadResult.cs rename SharpEngine.Core.Components/Properties/Meshes/MeshData/{VertexData => }/Normal.cs (96%) rename SharpEngine.Core.Components/Properties/Meshes/MeshData/{VertexData => }/TextureCoordinate.cs (96%) rename SharpEngine.Core.Components/Properties/Meshes/MeshData/{VertexData => }/Vertex.cs (96%) diff --git a/ObjLoader/DataStore.cs b/ObjLoader/DataStore.cs index b877aac..1bc43c4 100644 --- a/ObjLoader/DataStore.cs +++ b/ObjLoader/DataStore.cs @@ -3,7 +3,7 @@ using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; using SharpEngine.Core.Components.Properties; -using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; +using SharpEngine.Core.Components.Properties.Meshes.MeshData; using System.Collections.Generic; using System.Linq; diff --git a/ObjLoader/Loaders/ObjLoader/ObjLoader.cs b/ObjLoader/Loaders/ObjLoader/ObjLoader.cs index 9eaa1ff..104759b 100644 --- a/ObjLoader/Loaders/ObjLoader/ObjLoader.cs +++ b/ObjLoader/Loaders/ObjLoader/ObjLoader.cs @@ -1,6 +1,6 @@ using ObjLoader.Loader.Loaders; using ObjLoader.TypeParsers; - +using SharpEngine.Core.Entities.Properties.Meshes; using System.Collections.Generic; using System.IO; @@ -40,16 +40,16 @@ protected override void ParseLine(string keyword, string data) _unrecognizedLines.Add(keyword + " " + data); } - public LoadResult Load() + public Mesh Load() { var fileStream = new FileStream(_path, FileMode.Open, FileAccess.Read); StartLoad(fileStream); return new() { - Vertices = _dataStore.Vertices, + Vertices2 = _dataStore.Vertices, Textures = _dataStore.Textures, - Normals = _dataStore.Normals, + Normals2 = _dataStore.Normals, Groups = _dataStore.Groups, Materials = _dataStore.Materials }; diff --git a/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs b/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs index 7b3141a..6ea2a4b 100644 --- a/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs +++ b/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs @@ -1,13 +1,13 @@ -using ObjLoader.Loader.Loaders; using ObjLoader.Loader.TypeParsers; using ObjLoader.Loaders.MaterialLoader; +using SharpEngine.Core.Entities.Properties.Meshes; namespace ObjLoader.Loaders.ObjLoader { public static class ObjLoaderFactory { /// - public static LoadResult Load(string path) + public static Mesh Load(string path) { var dataStore = new DataStore(); diff --git a/ObjLoader/TypeParsers/NormalParser.cs b/ObjLoader/TypeParsers/NormalParser.cs index 5e88183..49af71a 100644 --- a/ObjLoader/TypeParsers/NormalParser.cs +++ b/ObjLoader/TypeParsers/NormalParser.cs @@ -1,6 +1,6 @@ using ObjLoader.Loader.Common; using ObjLoader.TypeParsers; -using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; +using SharpEngine.Core.Components.Properties.Meshes.MeshData; namespace ObjLoader.Loader.TypeParsers { diff --git a/ObjLoader/TypeParsers/TextureParser.cs b/ObjLoader/TypeParsers/TextureParser.cs index a251c24..0c596ba 100644 --- a/ObjLoader/TypeParsers/TextureParser.cs +++ b/ObjLoader/TypeParsers/TextureParser.cs @@ -1,6 +1,6 @@ using ObjLoader.Loader.Common; using ObjLoader.TypeParsers; -using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; +using SharpEngine.Core.Components.Properties.Meshes.MeshData; namespace ObjLoader.Loader.TypeParsers { diff --git a/ObjLoader/TypeParsers/VertexParser.cs b/ObjLoader/TypeParsers/VertexParser.cs index dcd5cbe..ce7d0d4 100644 --- a/ObjLoader/TypeParsers/VertexParser.cs +++ b/ObjLoader/TypeParsers/VertexParser.cs @@ -1,6 +1,6 @@ using ObjLoader.Loader.Common; using ObjLoader.TypeParsers; -using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; +using SharpEngine.Core.Components.Properties.Meshes.MeshData; using System; namespace ObjLoader.Loader.TypeParsers diff --git a/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/INormalDataStore.cs b/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/INormalDataStore.cs index cc990e2..10ae87d 100644 --- a/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/INormalDataStore.cs +++ b/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/INormalDataStore.cs @@ -1,4 +1,4 @@ -using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; +using SharpEngine.Core.Components.Properties.Meshes.MeshData; namespace SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore { diff --git a/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/ITextureDataStore.cs b/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/ITextureDataStore.cs index 7ddfe47..a1591ff 100644 --- a/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/ITextureDataStore.cs +++ b/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/ITextureDataStore.cs @@ -1,4 +1,4 @@ -using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; +using SharpEngine.Core.Components.Properties.Meshes.MeshData; namespace SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore { diff --git a/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IVertexDataStore.cs b/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IVertexDataStore.cs index b6f88b1..6667f06 100644 --- a/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IVertexDataStore.cs +++ b/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IVertexDataStore.cs @@ -1,4 +1,4 @@ -using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; +using SharpEngine.Core.Components.Properties.Meshes.MeshData; namespace SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore { diff --git a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs index dcd8d94..b09ece1 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs @@ -1,4 +1,7 @@ -using SharpEngine.Core.Attributes; +using ObjLoader.Loader.Data.Elements; +using SharpEngine.Core.Attributes; +using SharpEngine.Core.Components.Properties; +using SharpEngine.Core.Components.Properties.Meshes.MeshData; namespace SharpEngine.Core.Entities.Properties.Meshes; @@ -15,12 +18,14 @@ public class Mesh /// [Inspector(DisplayInInspector = false)] public float[] Vertices { get; set; } = []; + public List Vertices2 { get; set; } = []; /// /// Gets or sets the mesh normals. /// [Inspector(DisplayInInspector = false)] public float[] Normals { get; set; } = []; + public List Normals2 { get; set; } = []; /// /// Gets or sets the mesh texture UV coordinates. @@ -28,9 +33,14 @@ public class Mesh [Inspector(DisplayInInspector = false)] public float[] TextureCoordinates { get; set; } = []; + public List Textures { get; set; } = []; + /// /// Gets or sets the indicies of the mesh. /// [Inspector(DisplayInInspector = false)] public uint[] Indices { get; set; } = []; + + public List Groups { get; set; } = []; + public List Materials { get; set; } = []; } \ No newline at end of file diff --git a/SharpEngine.Core.Components/Properties/Meshes/MeshData/LoadResult.cs b/SharpEngine.Core.Components/Properties/Meshes/MeshData/LoadResult.cs deleted file mode 100644 index 1983535..0000000 --- a/SharpEngine.Core.Components/Properties/Meshes/MeshData/LoadResult.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Collections.Generic; -using ObjLoader.Loader.Data.Elements; -using SharpEngine.Core.Components.Properties; -using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; - -namespace ObjLoader.Loader.Loaders -{ - public class LoadResult - { - public IList Vertices { get; set; } - public IList Textures { get; set; } - public IList Normals { get; set; } - public IList Groups { get; set; } - public IList Materials { get; set; } - } -} \ No newline at end of file diff --git a/SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/Normal.cs b/SharpEngine.Core.Components/Properties/Meshes/MeshData/Normal.cs similarity index 96% rename from SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/Normal.cs rename to SharpEngine.Core.Components/Properties/Meshes/MeshData/Normal.cs index 6d325c3..5e40c14 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/Normal.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/MeshData/Normal.cs @@ -1,4 +1,4 @@ -namespace SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData +namespace SharpEngine.Core.Components.Properties.Meshes.MeshData { public struct Normal { diff --git a/SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/TextureCoordinate.cs b/SharpEngine.Core.Components/Properties/Meshes/MeshData/TextureCoordinate.cs similarity index 96% rename from SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/TextureCoordinate.cs rename to SharpEngine.Core.Components/Properties/Meshes/MeshData/TextureCoordinate.cs index 605aa5c..5bd29ce 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/TextureCoordinate.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/MeshData/TextureCoordinate.cs @@ -1,4 +1,4 @@ -namespace SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData +namespace SharpEngine.Core.Components.Properties.Meshes.MeshData { public struct TextureCoordinate { diff --git a/SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/Vertex.cs b/SharpEngine.Core.Components/Properties/Meshes/MeshData/Vertex.cs similarity index 96% rename from SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/Vertex.cs rename to SharpEngine.Core.Components/Properties/Meshes/MeshData/Vertex.cs index 87a7a03..a7c98a3 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/MeshData/VertexData/Vertex.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/MeshData/Vertex.cs @@ -1,4 +1,4 @@ -namespace SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData +namespace SharpEngine.Core.Components.Properties.Meshes.MeshData { public struct Vertex { diff --git a/SharpEngine.Core.Components/Properties/Meshes/VertexData.cs b/SharpEngine.Core.Components/Properties/Meshes/VertexData.cs index f9172c2..328d38d 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/VertexData.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/VertexData.cs @@ -3,7 +3,7 @@ /// /// Represents the data of a vertex. /// -public struct VertexData +public class VertexData { /// The stride or length of the vertex data object. public const int Stride = 8 * sizeof(float); @@ -25,9 +25,4 @@ public struct VertexData /// The byte offset to the texture coordinates in the vertex data object. public const int TexCoordsOffset = (VerticesSize + NormalsSize) * sizeof(float); - - /// - /// Initializes a new instance of . - /// - public VertexData() { } } diff --git a/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs b/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs index e27daf1..3457033 100644 --- a/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs +++ b/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs @@ -6,6 +6,7 @@ using ObjLoader.Loader.TypeParsers; using FluentAssertions; using ObjLoader.Loaders.MaterialLoader; +using SharpEngine.Core.Entities.Properties.Meshes; namespace ObjLoader.Test.Loaders { @@ -26,7 +27,7 @@ public Stream Open(string materialFilePath) private ObjLoader.Loaders.ObjLoader.ObjLoader _loader; - private LoadResult _loadResult; + private Mesh _loadResult; private DataStore _textureDataStore; private FaceParser _faceParser; private GroupParser _groupParser; diff --git a/Tests/ObjLoader.Test/TypeParsers/NormalParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/NormalParserTests.cs index 302a7c9..f9e03c7 100644 --- a/Tests/ObjLoader.Test/TypeParsers/NormalParserTests.cs +++ b/Tests/ObjLoader.Test/TypeParsers/NormalParserTests.cs @@ -2,7 +2,7 @@ using NUnit.Framework; using ObjLoader.Loader.TypeParsers; using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; -using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; +using SharpEngine.Core.Components.Properties.Meshes.MeshData; namespace ObjLoader.Test.TypeParsers { diff --git a/Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs index f84d450..539308b 100644 --- a/Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs +++ b/Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs @@ -2,7 +2,7 @@ using NUnit.Framework; using ObjLoader.Loader.TypeParsers; using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; -using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; +using SharpEngine.Core.Components.Properties.Meshes.MeshData; namespace ObjLoader.Test.TypeParsers { diff --git a/Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs index b69a0c4..432af88 100644 --- a/Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs +++ b/Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs @@ -2,7 +2,7 @@ using NUnit.Framework; using ObjLoader.Loader.TypeParsers; using SharpEngine.Core.Components.Obsolete.ObjLoader.DataStore; -using SharpEngine.Core.Components.Properties.Meshes.MeshData.VertexData; +using SharpEngine.Core.Components.Properties.Meshes.MeshData; namespace ObjLoader.Test.TypeParsers { From 249737b5ed9be0dd578735bdb2b43a100f91f8c6 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Fri, 11 Apr 2025 23:03:30 +0300 Subject: [PATCH 56/92] #2 Try map to old format --- Examples/MinecraftClone/Minecraft.cs | 13 +++++-------- ObjLoader/Loaders/ObjLoader/ObjLoader.cs | 2 +- ObjLoader/TypeParsers/VertexParser.cs | 2 +- .../Properties/Meshes/Mesh.cs | 4 ++-- Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs | 4 ++-- 5 files changed, 11 insertions(+), 14 deletions(-) diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index 4556068..2082a61 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -15,6 +15,7 @@ using SharpEngine.Core.Interfaces; using SharpEngine.Core.Scenes; using SharpEngine.Core.Windowing; +using System.Linq; namespace Minecraft; @@ -146,17 +147,13 @@ private void InitializeWorld() // TODO: Does not work yet. // var torus = MeshService.Instance.LoadMesh("torus", @"C:\Users\antti\Documents\Untitled2.obj"); - // TODO: This should be simplified to something like this: - // new ObjLoaderFactory().Load(); - var result = ObjLoaderFactory.Load(@"C:\Users\antti\Documents\Untitled2.obj"); - // var mesh = new Mesh() - // { - // Vertices = result.Vertices.ToArray(), - // }; + result.Vertices = [.. result.Vertices2.SelectMany(i => new[] { i.X, i.Y, i.Z })]; + result.Normals = [.. result.Normals2.SelectMany(i => new[] { i.X, i.Y, i.Z })]; + result.TextureCoordinates = [.. result.TextureCoordinates2.SelectMany(i => new [] { i.X, i.Y }) ]; var go = new GameObject(); - // go.Meshes.Add(torus.First()); + go.Meshes.Add(result); go.Initialize(); _scene.Root.AddChild(go); diff --git a/ObjLoader/Loaders/ObjLoader/ObjLoader.cs b/ObjLoader/Loaders/ObjLoader/ObjLoader.cs index 104759b..ef83d2e 100644 --- a/ObjLoader/Loaders/ObjLoader/ObjLoader.cs +++ b/ObjLoader/Loaders/ObjLoader/ObjLoader.cs @@ -48,7 +48,7 @@ public Mesh Load() return new() { Vertices2 = _dataStore.Vertices, - Textures = _dataStore.Textures, + TextureCoordinates2 = _dataStore.Textures, Normals2 = _dataStore.Normals, Groups = _dataStore.Groups, Materials = _dataStore.Materials diff --git a/ObjLoader/TypeParsers/VertexParser.cs b/ObjLoader/TypeParsers/VertexParser.cs index ce7d0d4..81285f2 100644 --- a/ObjLoader/TypeParsers/VertexParser.cs +++ b/ObjLoader/TypeParsers/VertexParser.cs @@ -20,7 +20,7 @@ public VertexParser(DataStore dataStore) /// public override void Parse(string line) { - string[] parts = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + string[] parts = line.Split(' ', StringSplitOptions.RemoveEmptyEntries); float x = parts[0].ParseInvariantFloat(); float y = parts[1].ParseInvariantFloat(); diff --git a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs index b09ece1..3b15398 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs @@ -33,7 +33,7 @@ public class Mesh [Inspector(DisplayInInspector = false)] public float[] TextureCoordinates { get; set; } = []; - public List Textures { get; set; } = []; + public List TextureCoordinates2 { get; set; } = []; /// /// Gets or sets the indicies of the mesh. @@ -42,5 +42,5 @@ public class Mesh public uint[] Indices { get; set; } = []; public List Groups { get; set; } = []; - public List Materials { get; set; } = []; + public List Materials { get; set; }= []; } \ No newline at end of file diff --git a/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs b/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs index 3457033..8e4190a 100644 --- a/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs +++ b/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs @@ -67,7 +67,7 @@ public void Loads_object_and_material_correctly() Load(); _loadResult.Vertices.Should().HaveCount(8); - _loadResult.Textures.Should().HaveCount(14); + _loadResult.TextureCoordinates2.Should().HaveCount(14); _loadResult.Normals.Should().HaveCount(8); _loadResult.Materials.Should().HaveCount(1); @@ -92,7 +92,7 @@ public void Loads_object_correctly_when_material_is_not_found() Load(); _loadResult.Vertices.Should().HaveCount(8); - _loadResult.Textures.Should().HaveCount(14); + _loadResult.TextureCoordinates2.Should().HaveCount(14); _loadResult.Normals.Should().HaveCount(8); _loadResult.Materials.Should().HaveCount(0); From 84434374446fe9f2848d856cbe00da5c28ba7a7b Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sat, 12 Apr 2025 23:38:57 +0300 Subject: [PATCH 57/92] #2 Use Silk.NET example for debugging purposes --- Examples/MinecraftClone/Minecraft.cs | 11 +- Examples/Tutorial 4.1 - Model Loading/Mesh.cs | 51 +++++ .../Tutorial 4.1 - Model Loading/Model.cs | 198 ++++++++++++++++++ .../Tutorial 4.1 - Model Loading/Program.cs | 184 ++++++++++++++++ .../Tutorial 4.1 - Model Loading/Shader.cs | 90 ++++++++ .../Tutorial 4.1 - Model Loading/Texture.cs | 80 +++++++ .../Tutorial 4.1 - Model Loading/Transform.cs | 24 +++ .../Tutorial 4.1 - Model Loading.csproj | 50 +++++ .../Tutorial 4.1 - Model Loading/Vertex.cs | 20 ++ .../Tutorial 4.1 - Model Loading/cube.model | 52 +++++ .../Tutorial 4.1 - Model Loading/shader.frag | 11 + .../Tutorial 4.1 - Model Loading/shader.vert | 16 ++ .../Tutorial 4.1 - Model Loading/silk.png | Bin 0 -> 11484 bytes .../Properties/Meshes/BufferObject.cs | 36 ++++ .../Properties/Meshes/Mesh.cs | 46 ++++ .../Properties/Meshes/VertexArrayObject.cs | 39 ++++ .../SharpEngine.Core.Components.csproj | 1 + SharpEngine.sln | 9 + 18 files changed, 913 insertions(+), 5 deletions(-) create mode 100644 Examples/Tutorial 4.1 - Model Loading/Mesh.cs create mode 100644 Examples/Tutorial 4.1 - Model Loading/Model.cs create mode 100644 Examples/Tutorial 4.1 - Model Loading/Program.cs create mode 100644 Examples/Tutorial 4.1 - Model Loading/Shader.cs create mode 100644 Examples/Tutorial 4.1 - Model Loading/Texture.cs create mode 100644 Examples/Tutorial 4.1 - Model Loading/Transform.cs create mode 100644 Examples/Tutorial 4.1 - Model Loading/Tutorial 4.1 - Model Loading.csproj create mode 100644 Examples/Tutorial 4.1 - Model Loading/Vertex.cs create mode 100644 Examples/Tutorial 4.1 - Model Loading/cube.model create mode 100644 Examples/Tutorial 4.1 - Model Loading/shader.frag create mode 100644 Examples/Tutorial 4.1 - Model Loading/shader.vert create mode 100644 Examples/Tutorial 4.1 - Model Loading/silk.png create mode 100644 SharpEngine.Core.Components/Properties/Meshes/BufferObject.cs create mode 100644 SharpEngine.Core.Components/Properties/Meshes/VertexArrayObject.cs diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index 2082a61..5ea18f7 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -148,15 +148,16 @@ private void InitializeWorld() // var torus = MeshService.Instance.LoadMesh("torus", @"C:\Users\antti\Documents\Untitled2.obj"); var result = ObjLoaderFactory.Load(@"C:\Users\antti\Documents\Untitled2.obj"); + result.Vertices = [.. result.Vertices2.SelectMany(i => new[] { i.X, i.Y, i.Z })]; result.Normals = [.. result.Normals2.SelectMany(i => new[] { i.X, i.Y, i.Z })]; result.TextureCoordinates = [.. result.TextureCoordinates2.SelectMany(i => new [] { i.X, i.Y }) ]; - var go = new GameObject(); - go.Meshes.Add(result); - - go.Initialize(); - _scene.Root.AddChild(go); + // var go = new GameObject(); + // go.Meshes.Add(result); + // + // go.Initialize(); + // _scene.Root.AddChild(go); } diff --git a/Examples/Tutorial 4.1 - Model Loading/Mesh.cs b/Examples/Tutorial 4.1 - Model Loading/Mesh.cs new file mode 100644 index 0000000..089ffcd --- /dev/null +++ b/Examples/Tutorial 4.1 - Model Loading/Mesh.cs @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using Silk.NET.OpenGL; + +namespace Tutorial +{ + public class Mesh : IDisposable + { + public Mesh(GL gl, float[] vertices, uint[] indices, List textures) + { + GL = gl; + Vertices = vertices; + Indices = indices; + Textures = textures; + SetupMesh(); + } + + public float[] Vertices { get; private set; } + public uint[] Indices { get; private set; } + public IReadOnlyList Textures { get; private set; } + public VertexArrayObject VAO { get; set; } + public BufferObject VBO { get; set; } + public BufferObject EBO { get; set; } + public GL GL { get; } + + public unsafe void SetupMesh() + { + EBO = new BufferObject(GL, Indices, BufferTargetARB.ElementArrayBuffer); + VBO = new BufferObject(GL, Vertices, BufferTargetARB.ArrayBuffer); + VAO = new VertexArrayObject(GL, VBO, EBO); + VAO.VertexAttributePointer(0, 3, VertexAttribPointerType.Float, 5, 0); + VAO.VertexAttributePointer(1, 2, VertexAttribPointerType.Float, 5, 3); + } + + public void Bind() + { + VAO.Bind(); + } + + public void Dispose() + { + Textures = null; + VAO.Dispose(); + VBO.Dispose(); + EBO.Dispose(); + } + } +} diff --git a/Examples/Tutorial 4.1 - Model Loading/Model.cs b/Examples/Tutorial 4.1 - Model Loading/Model.cs new file mode 100644 index 0000000..4d665f7 --- /dev/null +++ b/Examples/Tutorial 4.1 - Model Loading/Model.cs @@ -0,0 +1,198 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Silk.NET.Assimp; +using Silk.NET.OpenGL; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using AssimpMesh = Silk.NET.Assimp.Mesh; + +namespace Tutorial +{ + public class Model : IDisposable + { + public Model(GL gl, string path, bool gamma = false) + { + var assimp = Silk.NET.Assimp.Assimp.GetApi(); + _assimp = assimp; + _gl = gl; + LoadModel(path); + } + + private readonly GL _gl; + private Assimp _assimp; + private List _texturesLoaded = new List(); + public string Directory { get; protected set; } = string.Empty; + public List Meshes { get; protected set; } = new List(); + + private unsafe void LoadModel(string path) + { + var scene = _assimp.ImportFile(path, (uint)PostProcessSteps.Triangulate); + + if (scene == null || scene->MFlags == Silk.NET.Assimp.Assimp.SceneFlagsIncomplete || scene->MRootNode == null) + { + var error = _assimp.GetErrorStringS(); + throw new Exception(error); + } + + Directory = path; + + ProcessNode(scene->MRootNode, scene); + } + + private unsafe void ProcessNode(Node* node, Scene* scene) + { + for (var i = 0; i < node->MNumMeshes; i++) + { + var mesh = scene->MMeshes[node->MMeshes[i]]; + Meshes.Add(ProcessMesh(mesh, scene)); + + } + + for (var i = 0; i < node->MNumChildren; i++) + { + ProcessNode(node->MChildren[i], scene); + } + } + + private unsafe Mesh ProcessMesh(AssimpMesh* mesh, Scene* scene) + { + // data to fill + List vertices = new List(); + List indices = new List(); + List textures = new List(); + + // walk through each of the mesh's vertices + for (uint i = 0; i < mesh->MNumVertices; i++) + { + Vertex vertex = new Vertex(); + vertex.BoneIds = new int[Vertex.MAX_BONE_INFLUENCE]; + vertex.Weights = new float[Vertex.MAX_BONE_INFLUENCE]; + + vertex.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). + Vector3 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++) + { + Face 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 + Material* 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, "texture_diffuse"); + if (diffuseMaps.Any()) + textures.AddRange(diffuseMaps); + // 2. specular maps + var specularMaps = LoadMaterialTextures(material, TextureType.Specular, "texture_specular"); + if (specularMaps.Any()) + textures.AddRange(specularMaps); + // 3. normal maps + var normalMaps = LoadMaterialTextures(material, TextureType.Height, "texture_normal"); + if (normalMaps.Any()) + textures.AddRange(normalMaps); + // 4. height maps + var heightMaps = LoadMaterialTextures(material, TextureType.Ambient, "texture_height"); + 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, string typeName) + { + var textureCount = _assimp.GetMaterialTextureCount(mat, type); + List textures = new List(); + 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); + texture.Path = path; + textures.Add(texture); + _texturesLoaded.Add(texture); + } + } + return textures; + } + + 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.TexCoords.X); + vertices.Add(vertex.TexCoords.Y); + } + + return vertices.ToArray(); + } + + private uint[] BuildIndices(List indices) + { + return indices.ToArray(); + } + + public void Dispose() + { + foreach (var mesh in Meshes) + { + mesh.Dispose(); + } + + _texturesLoaded = null; + } + } +} diff --git a/Examples/Tutorial 4.1 - Model Loading/Program.cs b/Examples/Tutorial 4.1 - Model Loading/Program.cs new file mode 100644 index 0000000..e6fc2a7 --- /dev/null +++ b/Examples/Tutorial 4.1 - Model Loading/Program.cs @@ -0,0 +1,184 @@ +using Silk.NET.Input; +using Silk.NET.OpenGL; +using Silk.NET.Windowing; +using System; +using System.Linq; +using System.Numerics; +using Silk.NET.Maths; + +namespace Tutorial +{ + class Program + { + private static IWindow window; + private static GL Gl; + private static IKeyboard primaryKeyboard; + + private static Texture Texture; + private static Shader Shader; + private static Model Model; + + //Setup the camera's location, directions, and movement speed + private static Vector3 CameraPosition = new Vector3(0.0f, 0.0f, 3.0f); + private static Vector3 CameraFront = new Vector3(0.0f, 0.0f, -1.0f); + private static Vector3 CameraUp = Vector3.UnitY; + private static Vector3 CameraDirection = Vector3.Zero; + private static float CameraYaw = -90f; + private static float CameraPitch = 0f; + private static float CameraZoom = 45f; + + //Used to track change in mouse movement to allow for moving of the Camera + private static Vector2 LastMousePosition; + + private static void Main(string[] args) + { + var options = WindowOptions.Default; + options.Size = new Vector2D(800, 600); + options.Title = "LearnOpenGL with Silk.NET"; + window = Window.Create(options); + + window.Load += OnLoad; + window.Update += OnUpdate; + window.Render += OnRender; + window.FramebufferResize += OnFramebufferResize; + window.Closing += OnClose; + + window.Run(); + + window.Dispose(); + } + + private static void OnLoad() + { + IInputContext input = window.CreateInput(); + primaryKeyboard = input.Keyboards.FirstOrDefault(); + if (primaryKeyboard != null) + { + primaryKeyboard.KeyDown += KeyDown; + } + for (int i = 0; i < input.Mice.Count; i++) + { + input.Mice[i].Cursor.CursorMode = CursorMode.Raw; + input.Mice[i].MouseMove += OnMouseMove; + input.Mice[i].Scroll += OnMouseWheel; + } + + Gl = GL.GetApi(window); + + Shader = new Shader(Gl, "shader.vert", "shader.frag"); + Texture = new Texture(Gl, "silk.png"); + Model = new Model(Gl, "cube.model"); + } + + private static unsafe void OnUpdate(double deltaTime) + { + var moveSpeed = 2.5f * (float) deltaTime; + + if (primaryKeyboard.IsKeyPressed(Key.W)) + { + //Move forwards + CameraPosition += moveSpeed * CameraFront; + } + if (primaryKeyboard.IsKeyPressed(Key.S)) + { + //Move backwards + CameraPosition -= moveSpeed * CameraFront; + } + if (primaryKeyboard.IsKeyPressed(Key.A)) + { + //Move left + CameraPosition -= Vector3.Normalize(Vector3.Cross(CameraFront, CameraUp)) * moveSpeed; + } + if (primaryKeyboard.IsKeyPressed(Key.D)) + { + //Move right + CameraPosition += Vector3.Normalize(Vector3.Cross(CameraFront, CameraUp)) * moveSpeed; + } + } + + private static unsafe void OnRender(double deltaTime) + { + Gl.Enable(EnableCap.DepthTest); + Gl.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); + + Texture.Bind(); + Shader.Use(); + Shader.SetUniform("uTexture0", 0); + + //Use elapsed time to convert to radians to allow our cube to rotate over time + var difference = (float) (window.Time * 100); + + var size = window.FramebufferSize; + + var model = Matrix4x4.CreateRotationY(SharpEngine.Core.Math.DegreesToRadians(difference)) * Matrix4x4.CreateRotationX(SharpEngine.Core.Math.DegreesToRadians(difference)); + var view = Matrix4x4.CreateLookAt(CameraPosition, CameraPosition + CameraFront, CameraUp); + //Note that the apsect 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); + + foreach (var mesh in Model.Meshes) + { + mesh.Bind(); + Shader.Use(); + Texture.Bind(); + Shader.SetUniform("uTexture0", 0); + Shader.SetUniform("uModel", model); + Shader.SetUniform("uView", view); + Shader.SetUniform("uProjection", projection); + + Gl.DrawArrays(PrimitiveType.Triangles, 0, (uint)mesh.Vertices.Length); + } + } + + private static void OnFramebufferResize(Vector2D newSize) + { + Gl.Viewport(newSize); + } + + private static unsafe void OnMouseMove(IMouse mouse, Vector2 position) + { + var lookSensitivity = 0.1f; + if (LastMousePosition == default) + { + LastMousePosition = position; + } + else + { + var xOffset = (position.X - LastMousePosition.X) * lookSensitivity; + var yOffset = (position.Y - LastMousePosition.Y) * lookSensitivity; + LastMousePosition = position; + + CameraYaw += xOffset; + CameraPitch -= yOffset; + + //We don't want to be able to look behind us by going over our head or under our feet so make sure it stays within these bounds + CameraPitch = Math.Clamp(CameraPitch, -89.0f, 89.0f); + + CameraDirection.X = MathF.Cos(SharpEngine.Core.Math.DegreesToRadians(CameraYaw)) * MathF.Cos(SharpEngine.Core.Math.DegreesToRadians(CameraPitch)); + CameraDirection.Y = MathF.Sin(SharpEngine.Core.Math.DegreesToRadians(CameraPitch)); + CameraDirection.Z = MathF.Sin(SharpEngine.Core.Math.DegreesToRadians(CameraYaw)) * MathF.Cos(SharpEngine.Core.Math.DegreesToRadians(CameraPitch)); + CameraFront = Vector3.Normalize(CameraDirection); + } + } + + private static unsafe void OnMouseWheel(IMouse mouse, ScrollWheel scrollWheel) + { + //We don't want to be able to zoom in too close or too far away so clamp to these values + CameraZoom = Math.Clamp(CameraZoom - scrollWheel.Y, 1.0f, 45f); + } + + private static void OnClose() + { + Model.Dispose(); + Shader.Dispose(); + Texture.Dispose(); + } + + private static void KeyDown(IKeyboard keyboard, Key key, int arg3) + { + if (key == Key.Escape) + { + window.Close(); + } + } + } +} diff --git a/Examples/Tutorial 4.1 - Model Loading/Shader.cs b/Examples/Tutorial 4.1 - Model Loading/Shader.cs new file mode 100644 index 0000000..99a6959 --- /dev/null +++ b/Examples/Tutorial 4.1 - Model Loading/Shader.cs @@ -0,0 +1,90 @@ +using System; +using System.IO; +using System.Numerics; +using Silk.NET.OpenGL; + +namespace Tutorial +{ + public class Shader : IDisposable + { + private uint _handle; + private GL _gl; + + public Shader(GL gl, string vertexPath, string fragmentPath) + { + _gl = gl; + + uint vertex = LoadShader(ShaderType.VertexShader, vertexPath); + uint fragment = LoadShader(ShaderType.FragmentShader, fragmentPath); + _handle = _gl.CreateProgram(); + _gl.AttachShader(_handle, vertex); + _gl.AttachShader(_handle, fragment); + _gl.LinkProgram(_handle); + _gl.GetProgram(_handle, GLEnum.LinkStatus, out var status); + if (status == 0) + { + throw new Exception($"Program failed to link with error: {_gl.GetProgramInfoLog(_handle)}"); + } + _gl.DetachShader(_handle, vertex); + _gl.DetachShader(_handle, fragment); + _gl.DeleteShader(vertex); + _gl.DeleteShader(fragment); + } + + public void Use() + { + _gl.UseProgram(_handle); + } + + public void SetUniform(string name, int value) + { + int location = _gl.GetUniformLocation(_handle, name); + if (location == -1) + { + throw new Exception($"{name} uniform not found on shader."); + } + _gl.Uniform1(location, value); + } + + public unsafe void SetUniform(string name, Matrix4x4 value) + { + //A new overload has been created for setting a uniform so we can use the transform in our shader. + int location = _gl.GetUniformLocation(_handle, name); + if (location == -1) + { + throw new Exception($"{name} uniform not found on shader."); + } + _gl.UniformMatrix4(location, 1, false, (float*) &value); + } + + public void SetUniform(string name, float value) + { + int location = _gl.GetUniformLocation(_handle, name); + if (location == -1) + { + throw new Exception($"{name} uniform not found on shader."); + } + _gl.Uniform1(location, value); + } + + public void Dispose() + { + _gl.DeleteProgram(_handle); + } + + private uint LoadShader(ShaderType type, string path) + { + string src = File.ReadAllText(path); + uint handle = _gl.CreateShader(type); + _gl.ShaderSource(handle, src); + _gl.CompileShader(handle); + string infoLog = _gl.GetShaderInfoLog(handle); + if (!string.IsNullOrWhiteSpace(infoLog)) + { + throw new Exception($"Error compiling shader of type {type}, failed with error {infoLog}"); + } + + return handle; + } + } +} diff --git a/Examples/Tutorial 4.1 - Model Loading/Texture.cs b/Examples/Tutorial 4.1 - Model Loading/Texture.cs new file mode 100644 index 0000000..d4321ca --- /dev/null +++ b/Examples/Tutorial 4.1 - Model Loading/Texture.cs @@ -0,0 +1,80 @@ +using Silk.NET.Assimp; +using Silk.NET.OpenGL; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; +using System; + +namespace Tutorial +{ + public class Texture : IDisposable + { + private uint _handle; + private GL _gl; + + public string Path { get; set; } + public TextureType Type { get; } + + public unsafe Texture(GL gl, string path, TextureType type = TextureType.None) + { + _gl = gl; + Path = path; + Type = type; + _handle = _gl.GenTexture(); + Bind(); + + using (var img = Image.Load(path)) + { + gl.TexImage2D(TextureTarget.Texture2D, 0, InternalFormat.Rgba8, (uint) img.Width, (uint) img.Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, null); + + img.ProcessPixelRows(accessor => + { + for (int y = 0; y < accessor.Height; y++) + { + fixed (void* data = accessor.GetRowSpan(y)) + { + gl.TexSubImage2D(TextureTarget.Texture2D, 0, 0, y, (uint) accessor.Width, 1, PixelFormat.Rgba, PixelType.UnsignedByte, data); + } + } + }); + } + + SetParameters(); + } + + public unsafe Texture(GL gl, Span data, uint width, uint height) + { + _gl = gl; + + _handle = _gl.GenTexture(); + Bind(); + + fixed (void* d = &data[0]) + { + _gl.TexImage2D(TextureTarget.Texture2D, 0, (int) InternalFormat.Rgba, width, height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, d); + SetParameters(); + } + } + + private 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.GenerateMipmap(TextureTarget.Texture2D); + } + + public void Bind(TextureUnit textureSlot = TextureUnit.Texture0) + { + _gl.ActiveTexture(textureSlot); + _gl.BindTexture(TextureTarget.Texture2D, _handle); + } + + public void Dispose() + { + _gl.DeleteTexture(_handle); + } + } +} diff --git a/Examples/Tutorial 4.1 - Model Loading/Transform.cs b/Examples/Tutorial 4.1 - Model Loading/Transform.cs new file mode 100644 index 0000000..959ea9f --- /dev/null +++ b/Examples/Tutorial 4.1 - Model Loading/Transform.cs @@ -0,0 +1,24 @@ +using System.Numerics; + +namespace Tutorial +{ + public class Transform + { + //A transform abstraction. + //For a transform we need to have a position, a scale, and a rotation, + //depending on what application you are creating, the type for these may vary. + + //Here we have chosen a vec3 for position, float for scale and quaternion for rotation, + //as that is the most normal to go with. + //Another example could have been vec3, vec3, vec4, so the rotation is an axis angle instead of a quaternion + + public Vector3 Position { get; set; } = new Vector3(0, 0, 0); + + public float Scale { get; set; } = 1f; + + public Quaternion Rotation { get; set; } = Quaternion.Identity; + + //Note: The order here does matter. + public Matrix4x4 ViewMatrix => Matrix4x4.Identity * Matrix4x4.CreateFromQuaternion(Rotation) * Matrix4x4.CreateScale(Scale) * Matrix4x4.CreateTranslation(Position); + } +} diff --git a/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 new file mode 100644 index 0000000..18cc1d8 --- /dev/null +++ b/Examples/Tutorial 4.1 - Model Loading/Tutorial 4.1 - Model Loading.csproj @@ -0,0 +1,50 @@ + + + + Exe + net8.0 + Tutorial + true + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + Always + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + \ No newline at end of file diff --git a/Examples/Tutorial 4.1 - Model Loading/Vertex.cs b/Examples/Tutorial 4.1 - Model Loading/Vertex.cs new file mode 100644 index 0000000..5177c8a --- /dev/null +++ b/Examples/Tutorial 4.1 - Model Loading/Vertex.cs @@ -0,0 +1,20 @@ +// 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 Tutorial +{ + public struct Vertex + { + public Vector3 Position; + public Vector3 Normal; + public Vector3 Tangent; + public Vector2 TexCoords; + public Vector3 Bitangent; + + public const int MAX_BONE_INFLUENCE = 4; + public int[] BoneIds; + public float[] Weights; + } +} diff --git a/Examples/Tutorial 4.1 - Model Loading/cube.model b/Examples/Tutorial 4.1 - Model Loading/cube.model new file mode 100644 index 0000000..0150592 --- /dev/null +++ b/Examples/Tutorial 4.1 - Model Loading/cube.model @@ -0,0 +1,52 @@ +# Blender v3.0.0 OBJ File: '' +# www.blender.org +mtllib Cube.mtl +o Cube_Scene +v -0.500000 -0.500000 0.500000 +v -0.500000 0.500000 0.500000 +v 0.500000 0.500000 0.500000 +v 0.500000 -0.500000 0.500000 +v -0.500000 0.500000 -0.500000 +v 0.500000 0.500000 -0.500000 +v -0.500000 -0.500000 -0.500000 +v 0.500000 -0.500000 -0.500000 +vt 0.000000 0.000000 +vt 1.000000 1.000000 +vt 0.000000 1.000000 +vt 1.000000 0.000000 +vt 0.000000 0.000000 +vt 1.000000 1.000000 +vt 0.000000 1.000000 +vt 1.000000 0.000000 +vt 0.000000 0.000000 +vt 1.000000 1.000000 +vt 0.000000 1.000000 +vt 1.000000 0.000000 +vt 0.000000 0.000000 +vt 1.000000 1.000000 +vt 0.000000 1.000000 +vt 1.000000 0.000000 +vt 0.000000 0.000000 +vt 0.000000 1.000000 +vt 1.000000 1.000000 +vt 1.000000 0.000000 +vn 0.0000 -0.0000 1.0000 +vn 0.0000 1.0000 0.0000 +vn 0.0000 0.0000 -1.0000 +vn 0.0000 -1.0000 -0.0000 +vn 1.0000 0.0000 0.0000 +vn -1.0000 0.0000 0.0000 +usemtl Gray +s 1 +f 1/1/1 3/2/1 2/3/1 +f 1/1/1 4/4/1 3/2/1 +f 2/5/2 6/6/2 5/7/2 +f 2/5/2 3/8/2 6/6/2 +f 5/9/3 8/10/3 7/11/3 +f 5/9/3 6/12/3 8/10/3 +f 7/13/4 4/14/4 1/15/4 +f 7/13/4 8/16/4 4/14/4 +f 4/17/5 6/6/5 3/18/5 +f 4/17/5 8/16/5 6/6/5 +f 7/13/6 2/19/6 5/7/6 +f 7/13/6 1/20/6 2/19/6 diff --git a/Examples/Tutorial 4.1 - Model Loading/shader.frag b/Examples/Tutorial 4.1 - Model Loading/shader.frag new file mode 100644 index 0000000..799e260 --- /dev/null +++ b/Examples/Tutorial 4.1 - Model Loading/shader.frag @@ -0,0 +1,11 @@ +#version 330 core +in vec2 fUv; + +uniform sampler2D uTexture0; + +out vec4 FragColor; + +void main() +{ + FragColor = texture(uTexture0, fUv); +} \ No newline at end of file diff --git a/Examples/Tutorial 4.1 - Model Loading/shader.vert b/Examples/Tutorial 4.1 - Model Loading/shader.vert new file mode 100644 index 0000000..fc46c04 --- /dev/null +++ b/Examples/Tutorial 4.1 - Model Loading/shader.vert @@ -0,0 +1,16 @@ +#version 330 core +layout (location = 0) in vec3 vPos; +layout (location = 1) in vec2 vUv; + +uniform mat4 uModel; +uniform mat4 uView; +uniform mat4 uProjection; + +out vec2 fUv; + +void main() +{ + //Multiplying our uniform with the vertex position, the multiplication order here does matter. + gl_Position = uProjection * uView * uModel * vec4(vPos, 1.0); + fUv = vUv; +} \ No newline at end of file diff --git a/Examples/Tutorial 4.1 - Model Loading/silk.png b/Examples/Tutorial 4.1 - Model Loading/silk.png new file mode 100644 index 0000000000000000000000000000000000000000..a82d3ab7cc6597ced652121b863a3044d03e3e2d GIT binary patch literal 11484 zcmXYX2Q-|`_wd7NVMFxZLxf<3=w$^_qL+9Ry-T96wpLjYy_2FWHY944sL_IKv=E)> z1VO~=Rt?|d_y3%;$9ZPv_B(g(y)&_f`kL1%*(d=3xUQ|GZVUiKE>}MaGH@j5b4()m zj|6dF+mr(Q3#M?40l%+#X+1^&0QI-4AJJDHhLoNuZ0c zj&t;kJYZ547Ye#P^pK&IXPs1)A&vq&$CfLa(#QK9-c#dljtVkMqXw0ZifA0&P`?`n6Gpue4Rjoao=9S9~ZxObQ~F}jHED{ zff(-0h5abZ-3`>Yxu1z9UC1Z1B%(AU7B~?=OqBJ-^*G?EWs0<@5kbs? zGjfAy0rE{--ipXq>6rCQtA@0U!juFJfh?Boa_ugCt#$|Mi6@CWn2J5ZAJp^2iH1q$ zUF7T*>e^#^?;$kZ73FUahuXhaF+HPtpGUm#(SVQn0g;xP94|_3(@qXZayxecvMzud zx;ceBM)v_!8A^i<~Ut2=BsIo%YX~T5bGVVlZT{FNpEv zs$t}^!3#!}n+ikM3oVNeqFuvC#iHf49)$NsI_1gpv3Cyt;A`sD-iVicV`WIH)gH#V zBHfiaebAm^zW;pqM8S|1%jaVI{16^V$h97YpPo|x~H=3h22=Q) z968y<63g1~uB~w*4F<$}P#DM~nVK-{WW;%kP@Y9)@wcyHB7ae7I0CJ!Ff#Xx`!QIi`>& z5_%!40qSeqP?4|eoKSI#%(Fp>?L)FRp`@_DQFSiaEY%amwU@BWn^CcG-txI>Gx@sa zXhiPv2jm4#_N-_2n&+Cp-z9SjuZa6?odu51G`O;o3ZpAOl0534waT{i-IiqjImMMQ z9qmmB?+V!bH&znAaHsvP+n}0qfhDxZWv!G3i%y(#^OSg?f1jxROc>| z(=gyQWz%GCbnrF>e9O=;E}p87>7n{|OWDB-8Fv~DQ3s5Y>sE28Ne+dF>Rkya`jZk3 zsXiB4MC$fiM&^n@I>EaRr)eFPlU#9xZdp`Mzr^@Is8=(jmEk-6_gCJuaIx@ZOJmE= z_KfJIKL*xS9R$NMv^N2rSs-Env)=*^jCcNxIYvUsc67XdeJ}d87*=?>+w#-hfWbeZ zM&l?6`S&wPS_7pQE0%U<-*EjJRt4SB3F`7gQhLk3Efwp7H~4p79 z*JR?U%oAce?KdAV?Yza<)o8Zu&dE8H{)AMsv`f^l@ou0C03>#6u&7N6sXoP8AALxS?`k(~wv~glf zqNvOl+5m$$6j%P8o@m=s^X0jp zdTe`}*FcJNxf5O;5C`iYQ~W0~r4e}rzsf(U^YRyIt6Ph6SxX}V+?S~5|5YppuFR?; z9+>BSAwLO=vX^IZrflF467=hh_Yf1aL{{MK&XY6;o;G<}I{geZb}rr+U*z^t{}IAD zv<7a^ErT)FUGYA#Np}>FioNLw46&Jg>lR%#QJnYUc1p1TS$kb-@RTC*xOCKwW?2*Z zkdi?dBxdC@hO`d%1bwgPFUfkrhA9JcMa*to(im(2FXf{9TcW1hw9=@<4QK?FxtA)$ z6A*lFK4fk%>f^ctilxmKGh;U~`TZf|UK6l3nH$;DwoyNG11%KKZ3S0@MKy*C{QOZqGx%Z_nIcD~7)YS!f z_~w^La)VNgxx|2IhEmfhd1)YPdu+W6FXf#M?+1sSy*TrvDy2APiGd$Nrq0RbStP?B zfFMu~A(Ez&jpa^UU*Z0vVbq-D z>Jnk$1rU`L=l*;Zl@wlI@Q-7@>X=gH3s*8F|95CLQxmAVzO3ltJMPt;dI$vm6G#oQ zc`#CvVfxwUJzmv~$`7-aP|>7Mnhfb_P@y#=b!}`dro|CKXu%|j$dJC}2h*dP`9`moX@$Vb@ z@a}9U&ae|Xkx|Nz*h5SRJH}jL$x#=RD%@|fcyLE$njkdAkR?0FVTF7Fh~JlJC)`ng zRh^zdZ^d00z!1eZP}5}^(jD^(BHMK}Q(viW`ZM~sadUe&lCUoGMWkH^XmuaFug+P} z{%b?lDLtxOc8+i-lWARckkcxJ`kNy8qSs8#jZ_7abzVNFPTZsG^-2!~Nu>usqgidn zC_{LBEBELk;mk4nWAA^7L{D+uG$CePn<@~AF15dg9so_2pU_J`-kBa<{&|eRlX>H_ z>>!uLi9^gCq7)Yt6W{mGmW)WZk*e2kr?|ekhsW(>hRtyA_F%w#P>PUZK3@}$>(MfW zE@myMMA?QknfJY?_AScB7&x;&+o!#=dUEfFJWGntO@G75n-~;dt1>t@F1c!haSY*3 zvqZMgjl2q+ojt}^G3LJdgdf>Ki8jtW_bDnRX%DnrQpobnZd*BY1;{7g;5uKa!JPck z)b=FTd;VbdwW|o}HTIEsXcW}lirgG$x1!`p8e=yoq}7*%{f`o6nrx}R7cHtwjPAY* zJc|rUPngMlsklO+_gzwkx%?y_uR8LpSylzMIv!jQNY@fed(S7W{cm5ua;whkIC4(d z&{+Sc)WGwS>;aqMP6AKKo*9Oj`RV%y``l(7MIsfQFyr?_N=e7jSoG_lKTenz3|acQ>RB@DEtMkqZ!<;Lp(5}ft7{<+iz7} z!!ojAL%sl{W7|XY&RM`rL~Z9NYO}vgn8v(7V6j}~T1j-{HHaR0PXPMXC8~$bz$WhR zRO>w^69+zLTC_4~iL;UG2zs(C>YdlKTIWXMHXXmFlyw=Fw zeyx6ur}-}DsvuPA-l%w%=jt?9zTDvE>zb}d*23+KSF_cOSF`wnOEX2c&albc{McKB zp2h-cE>U5cNszDa{#U9QQ`ZPpdfKC7FuOZ)I?obc;;rjTgvNopkTCf_+5jBQMK>O4 z{rO_*Gr}wzg^l*aXVz6Q ztG&b4ABDIxU%h`WlT8J5ltnnnRL@RMS(o{LE0N+eZ0*y$U&SjXCp8kqh;bZGtmW*L zZzN-{!IQ!tGl)EKz~c(a@gZ_2asiOz!t%p(E9?Im0|+j!S62Qp@x6Q#iO@95q3j%& zp3oy8m9A9%VsW~c|NB7Ir;U%>eu!HwIcqG6t`2jKc{X2XUxrgF6=z!1|p#|y^-9GK^l)wmQ~VXX0J!dnZEG<7R8L4$Rn#yPQE`8wLg z1E-nEd;pWN!>axLZb6y%&$`e&ZMan!^k!B;At}p+`fgv3v^SbMU<~PGirDtcJ z)+H|zF0ZN0->AO=#cAnhOSz3F-))Ra!0TN(q;USk{9FAg#)XIL&QCUL zXJ+AhwByT#qOFU09^$h6Vc%{g?zh=yKn5S$5$HgNkX0!J_gPO!20nxc=UsB89jru*2QJ0ADFT-eTL2t z9%AV&k#_pmA)IU~O-{$(m**_8WvB%Cj3vU|UImub1K7~J8?nV*vzFNBsJ<)r1)zxM z$Q4m2q8m2UQ3M|@k94}+n%J|PF{%A!S##Kz(Gvo#QD9kbrzhXyRBEn%+s|p{Cyb7t z{f`Mrh1(P(lV5jS7gg)i_jk~)*yK%8olvofzng3~040+jx@kX){An9~lqBa+_J!KE zn5rfv8rGlL2`7I`{C3vzc-CB@36r$V8pm$=m>Nlj!*D`KJM~ZCA$gj^sQ_Xw(!nnS9C~XE*CiD(U-Hnf{y| ze=haPKRw?;k)4}a))#3zzD*kZd>;b&Tzf=PB<(GL7B4&t-lLA1Vh1HVxsPw#5Px{o z`xH+~$rxjux21Ch=xK+AJop{uo0m1g<+Z&oGf1{m?rW|y-ws33LpX(Q>2n$RKae-j z-R_yP^_3sw-?q(YO$?`|_8a-@^xYzK!oX(xT`6w#F)I>++oS;nOSp4!VWMObV*K60 z$_G(Nl9IQv-^0%090n44Cz&s&qI0Ny+tWMpq|!7`4J300k^#tW+w5aTCUO-@H%!BG zUv230C`U~#u(;-#{K?yx+c2IU3FaNjV_CJe#s2%jqFs`QpZ^X9fjPbKORbQb)vI;-1?o7l}*#b6s5;*5A|FYC+h*V* z!wETx^gsPWd`z3`i&=6zIwv|DhX=GaZ=F~)cpVuD@aDu~Na*4@8u zTr}|VUUm?%YEb)!D2!HFh|9AJ>9FH;|JY)c{;q4Q~9o*92v;`)bZyTT+}Y-?{u53d5MM^qqR zabc4dD%ltwPT(qfJy8Go^{RegGdp_pt~6~Oh{eMm+p2-C@nCH_sCpARvBWeoeay3C z6+R)+|LPjFwrC~JSH9r`ckO3C4xCKxWEadtP-2M7-pjvl!6RH~pl4HRj4dj&8blwZ zc1XaM?_Kpuh<51fMeQ+8n)3t7g&y0>B*Z$St$NiJ?(wPwC zi^^1t46oN1jOnyL`!{lQX1_H)ehYBjUpDFCgi0c5A?_N3S&1&eH77Cz6`x03_gttz zJY8@Xn{OQ@KicM129kE@n(o+U^wO}bZ~A=uvvB_RU)bOLvwtbG-LUjL*w7Szidy$$ zG<}VN{%5ep)P(v@)N-t$y4)}BqOBiu-@3`-yeCN}FA}r>=7{{+UnbA8rDG`!o;p(C zbXD8oF1gDYp?a5J#0OGBMO85JFYF3=?68s#eHV~xt!;LZIN4^WaR&NeAkAmSH3#H9vnJ*-00dFFluH9F7 zbH)A-jo&r^+wz^m)&I(tNl3uqZ}4W3EG+^N+p-(qNcWcPMK{bOLt<#l$S;XB%ld}z z%73VWV{V)-xK4xdED6IaJFyB2?Sj#RF}ztdnUnyY5?(BNC1CYI-31Rw(AwvB*}))6 zS)B9L9Iy)alSqNs&Ixst+rO_|fKm4H@ipA0o>kMzUsQG?nAs3YN-m)m0jBqVO>%V_ zEQR$=4Nv)AbuZC&9x_px#s30Ha^7GnZ#8q;<+E+Oqv*h+C)T(dUZncrtr5lYEHzZp z=#*uBO!iq2yKGBGs0Bzj$pLFJ(kIK8fB<(8-w_NvkPhyWEj~?D17T;o;SG9bLF}4= zPYMJ;;8oa=`;CLU`3d{sAZWh>mPQY4P1f?nK?R&7z=oo+>+S&F8AV+Q0#_%8dl=C` zu<7{QEoeKz>gaG~G|x{ow?QY29tl9^5?pgrQ@S(l1ox=Pno{{2yNLGO2JJv^T2X>Z zVPEWU$w~IB&odI>@jNo8bwqR2CYtVpX;#8oV=MRRf6eZwhoE4fyE)f66>iBr>Gv27j$*O5}xmE8RBIBBLUbwhf2IZ5hztzh{ zG*&E((^bzs?68OfD}|eC2W{oVe1~plAl%%v2Y!|DyZfs6Z9AtJH zj(hzxlU+~Z1eAWg*a@CDlgjkHzfWrxqR-UQCJ}cuZ<`mfzHkbJEmR#n^jHDpPH&Ri zs3`FEI?7t}nhGUo1rF3^3wf=YX>)|wyI!Qn25+yYb69#g5U1X-`cHsQIC*ZrYb|T6 zqCUD;m~pHv44T$VU88iZ5kv}aXzAx)tXNTYCbU}lY z#8F5UKQegvm4U-S1KTNU2l*XCs;f`Cj2Y~tM}loOUaloBT+jyul@524q&9e7d-X|!o7IoQ3oh;S zG>Sr{jJhTI@kK-Kg1pz5ia0^=1Bw3IakkC9i3*B79=FJ{g#4h0jkH*dfu7TRQZn#z zwV+fUMDt7~N>239&t~)F)9u@=nIt>8_^0PD!EtsRratV|s{~y(z;My34|hxr(erhM zBBEO$*grVB-<;X$$Bf_*EUM9g;Z&?jW?*1JbYST@RBBim%%-%LJABkI;~;Yo7FWKg zDWyHJAr=>hz=6gB7FSA1aDcBjM00>v6S=ZUOqTUE#?Iej#R~hU_Q7SH1<^}Fg!SAv zxJd@AzhXwREqGQF?tpRllmY3n@OPo42G^tQ24bGU875J6WWe~3iLPrrWLYl~>;^LQ z^e(H#2gnj?`an8-QE~`|Gx-*o0cuB+KAIx%sJgAivI?bNTjY01y}69xg-VeU;V{TX zT5x3TsX)Yh^j_Cl=2v)no<#rS-CobU=8J+t@%~U1x|Y;K@B5%;RO~ZqG^C|3pS8(S z4Jx>BK=eYt!d%j87BpDTIv<;{uHCW4f?zqnY>Qen(hYcA{lBB8Z-}ME{%2h-Q=_Cg9y@A9~Eih3{EXxFDEV z{oPP+_K@AlChtT(>ivVl9wYpn^C1#Luk@fb>=IZy6zY_T3x%83}adHWE>^IP;E zwo`WDU$>-6^ipI(k~$vLUN(z!Wolg7-fr`g(_UWv=Kw5F&|%+Dhs704JvNmnl^k7Y zSY5O?YBE`)M>^mpVCFH;;Ehr9C!~1i?x}YO0^2T*d^%JRy+5`YN`LccDzpFdE9T}p zttC@utmdPq2Sc{24k>QaitoSq=|PKFNr1?}J@5uZ58nYpS^X_avPeYe-!~`L`Ycb= z_#(V;0@j~v?zwa_SVurVTIN7i+miE?&E>?-g5~%_7H4iltCOL9^N{&zwI?d&!&NDr z71z}(9Iz#FQB&f&*;ek71F`zU0xb`78YG5DVExL*Z{M<8O;1EjC+r_+4xU2Wh0P!2 zCxFFNq8)+8NKwIad@`)=@N>PvbHH$CEQ%X8^y?e!Oz$jcxvj&X<=o4=M?o%BO}3M@`RU8%(tF}F&2yP&v0NSQn7MbhB*q?V4F zYPd>JyX7>i7~t^@_57ap*oas=LU|6d88Pjr1JU9g_>}g-s`NM{NHSFv>RSaeUAVX2 za^2zi^x2MoH!E<%J2ZU{?#Kz@ghFfDSjS(TW*TFPUPFUe7jGfXXd!q{aQJrB?k~Te zU*3F27%TXY@w7*jC`Y$|+1IV8smp}*N|R9iQiEcd*hqBkS<5vf6$CF1MeuAA(cNyd ze(QsAd4)L=Z@;Z~h+N@>)~dkz!*`=ke#>lXftfzYfjZQNydD&RbqoD$e@^vBQKDQHl24qIIgjXl$l~g0ml2`Cc=Y~kR%#i# zSzKa8vKZl;XD|;YwGbSKti_Sr0^z?V1AT>oBV~j)C;Dt8L>Xkyof*fWSejvB%=+*w zLT4mN61cgSe-v>vLjfh5rjC+JQI-+BfNL@hy^}QvJNP)rkg<^Jl+pm^XPq$e*B8<` zeQQ~N4KYOUgv@JRgOqe+@?d4wuJa%*)yB`4mosU9EDbSFyV#o~7TppVK5!>WuE%#* z?QggHpLJt-4i^CZ9cunYE%z(jg$&2xT3XuX<)B*e4f#C{VM8>um93Q?1{>P4&xp`_ zXK<%D)J^+|Zk9A59fDMT{WT-g>7|%A}FKA5ohMZ1Q4U66o zm;B_m$3zws21WEx6p9Py9a{@B<)q3&+PAcdnt>C|!Z%m;ld;WETgyY{tvPP0Y2Ia8 zdn{12O}p-%`9vA{a1!zZ7M-$Gh-B}YaD2AQ8ZQax-c|~rMXyOVQtu^Ik!9IYbCX&J zzPAt77W|ny40??Hf&3Q<0mZLOu2FKYI2c>0Z~R!%xy#{VtJB+leer|eJGwV;$^LhT zLtpofUm*DLE~}ker=lSwpye(b(F5*6)V%C z`+ePE8HtQe0t3JeyiF+g@sjO2iRcg%QEaAI?SJlBU040FQ;sQKPTQ6N-Q-rD-oh&s z?wp}kK48=+KPpZv{k9HNfYk?5&-*Z??7ufXcTiZ?)fAJQC4$u&@#APK0D$UUy#<&~ z8<&N^O_dwz;ZF5G9}-UPfkf8b2WE0m0rlothqB!|4<@J%gwd!VmXj+6*5xP@avJR1 z6lX*Rf-pq3I)B>VG90V0{}nttr*n;!>vFphk*B6brU_~fMaEN#P*TC263wMVQH)UhDo$LI4{(9>;<={X3i@D>`R_by-( z6TZ3k1k3773>42ww*{Z)xhL7)8vs&9J@Iol9=n6x({2$^_LA_A8z#HGcmA48ashyc zNYK{9C3R_{pwIZnJzU`(|4Y=0%%2QyhkV>nsMLCLCWX^YRF)LJrDQ2_kylUtDRc!Y zHIGum3}5v<-8fYx`^VI=4y`ww+xbCmN|I?T^V@@G5Ghtu)F7xH!)f-(^IMJwWTz!N zx)>sC*GeK}rwME;SGbX8*%b;>x^32q90koFq}EDg2ZiNA490A4qB+4{FxYYh6_s^z zCrgUo&06{=odLM3>;*`}A{Qw`YZ;w{hoF-8mW2-Xq9>AP>`^HYq}TueJKTLygv|i+ z{pvwH=vreKxINW`eqa}YLv+^>L&P)P#z)rU1M(N*aYY}Z=(jm-poqG$9{U$V^WnJK zPpQB!)*J{PC){zgvG}Rl;GZLj(ib7@AKT*{A-b`8~ zsM(|mGQ(;6R(_REJeqYU@P8JUt5n!XAlbgu)l#~e_>=9!jmqYdA*ysZX>k{C90D zv(5i&Ykjw?_`)|=<$c8=?!bq0s{OYhedUjOHiqn zPKBp@YDDKh2zOSl3sPcsZL~QMX$8!)8StAw3F<4n+binyD*yfGzwa><@&0=NC|$G8 zzy(PXEAb*d*jtxT_d$E+R8r$~e+0kRwmhC$tGMhT@ch|v0yVWkzhU)PRk`1>;PF@2l-)C}8pi8ayw1mjj*yUZC}41sPd3dHwiY2i_m4 z@hm}s%d>BdB1Gpm;9sw9$^5j#F9Jh5>%tq;oovBblZRBf4C8rVDM6Y3k|K2T!{8-C z4SO{KVm0OE2gaszBV+DXa6JflrD^REyx+Nb;O`MXM>?O#@ zu1xPefck9z_1R2>qcIkgX;g>GnsHqYP_6>O{U$YOml^uS^H`3v^GKD!J@CQT)`^a# zxV;&)Z+@-&@Xdix*B{>!LF`e6pto!Ziv~*GVqPHKX#rItbT2>f_N^@0xxu6FT4t`G zY@fO*>osU_ws58yP`GJ)?ChKz`z7-+L?3>E4QFx>Zd5TLz`vR4U@oAD!8 zhXQD@nf!Y4DmCAY<(Rq9-i>m~Mw)m3lx`p&8EaJ77%E?wg8@XqS99Qp-fd1<8tN!? z1Bbv~+8i+}*D4Icn=CnW?98Y+NUTDL>!G?RO_B?_nBMJkqp`PGzp`X5%V&w{r-K3Q z1_Z(C2jRbW-=ECC@LQIi%I&0LS$ptFgLxbCBxs9*B97>{rVPDPa-8jhg}Rw2#ir0% zm-^^k$}czSxra-V9l8d^9=Ec#ZvzLlO0-7pc!uFTP=D=hbzEpo@Y?x_yccq85ry8V zG*{2uU(*^1&bISlT@I!IbGo(%e^pfUcxk3`BZXYS;FfiII?DY-#Umd7xFxRW-V<62 z>Gx#qW-86Thogp>}il)$}9+97rC%YT7$<@~v*Z!zag?G5gO>MOL_oDsuRKP}JF@T%ttngg7^ zYiX*LA+vw0OxWfh$H>p@gOAjhI}) z*7pSuN@P;jGQ(XO_y|E=ofS)Yhaq*D$y7H3Cn7Q1J<7)FvzAt)0>B7_{PBIM+cmth zqXb=bG34WKja#XEvEtKQH+xvtpxMTEy&zz#v-y261r|XnI{_|w8bl-9pkyrJ!OQau zm4RJ;ns_G@7p#ZU*qxukk%w z0gQ#SKD&o@`gzW934Ua8iMKakYN4{-9E_^Wxt@-J_Bh$T@8u#-8Hq`q;eH~yB|3w9 z$+^5qWRfRa#Mb`0!KONhj3+?I>o)L7i8(U%qp{xn*E8Ed^5sol6CLtL#4JeE@CK2W zV;V7kJO9(~7!q{1Sxz&n)3zN(sd#s%NtQSH|1b5ACQ=N(VlT;| zi{iisu)34{VBUnP=kDv37SiAJxy$UD=itk!lCJ#`2Zy)fZE}xi{zOwsG7W7{=Ei?4 zGwytW3H;|t$Z5)O4FD_BV;*#!s);(T&FM%z^c%NU86+IY4M79~JYfWE)Qu zix2rS2T!8rD7#0KeP=oH9#V}|o~}I-kblgTIBQ-u^xN>xR;@z7)KxX+Mx(xEkAbYe zr4paKz9<1CcShamOJ3t7gc!BbrR)>^s8izpP)^;hQ~c`YMw)?G&{IB@A>MYDHT3gy zo@qKjp!03{U)FL1CSrNII90&sPO_$ZnYk?^LwsVac#cgdj(P@S)Q~txEtl3eLyXxWh;mMzrxbcUn#7<;QcVuogxXqV-x~x{Z;l#bnVVqc`{OH~V z!fG?kEF>Kk!FZRX9SQ7xq-GJjCS+}Fo2lMksySh~&n6zi-<1gfpGGwSr!u(cri3SWch)7!T`hP?eh`_ytoDZ*9FnJsJWyL^d>yr`#l6_g%J?m=Q zvn3r!0~wHFU9q68lycOD;}7|8D3GKHtE`!aV4sj=kEep~Gq3Swuf0va+*yoH z8a(w{2}_V{TpbW_2?G`(fYXmQo8YOYT)Evq8%;f%aDv(EFT_fe?Wt%E8rLtc!!4M} zcMOD-(LIl7=knu3g$Lfa@-_X=IOJ|)SL^?zbd!{MS(o)^;5D1kr>XzIHx)_2N++HC z*k0?@VuG=TxY2<>No!)3H6@-D%gi>PH1A6?ug1$aWJ#aO#kZc{v~a82^`^Z)WReKW zg_gchz!pa?O47PT+c!hpm~FF*-5x%0R4}c7KH_#c-9)2oAKY7bNzQe0gMRj*t~dA+ P8PL|ySFgBl`{Mrr-UrR^ literal 0 HcmV?d00001 diff --git a/SharpEngine.Core.Components/Properties/Meshes/BufferObject.cs b/SharpEngine.Core.Components/Properties/Meshes/BufferObject.cs new file mode 100644 index 0000000..efb6340 --- /dev/null +++ b/SharpEngine.Core.Components/Properties/Meshes/BufferObject.cs @@ -0,0 +1,36 @@ +using Silk.NET.OpenGL; +using System; + +namespace Tutorial +{ + public class BufferObject : IDisposable + where TDataType : unmanaged + { + private uint _handle; + private BufferTargetARB _bufferType; + private GL _gl; + + public unsafe BufferObject(GL gl, Span data, BufferTargetARB bufferType) + { + _gl = gl; + _bufferType = bufferType; + + _handle = _gl.GenBuffer(); + Bind(); + fixed (void* d = data) + { + _gl.BufferData(bufferType, (nuint) (data.Length * sizeof(TDataType)), d, BufferUsageARB.StaticDraw); + } + } + + public void Bind() + { + _gl.BindBuffer(_bufferType, _handle); + } + + public void Dispose() + { + _gl.DeleteBuffer(_handle); + } + } +} diff --git a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs index 3b15398..6ab754c 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs @@ -2,6 +2,8 @@ using SharpEngine.Core.Attributes; using SharpEngine.Core.Components.Properties; using SharpEngine.Core.Components.Properties.Meshes.MeshData; +using Silk.NET.OpenGL; +using Tutorial; namespace SharpEngine.Core.Entities.Properties.Meshes; @@ -43,4 +45,48 @@ public class Mesh public List Groups { get; set; } = []; public List Materials { get; set; }= []; + + // -------------------------------------------------- + + public Mesh(GL gl, float[] vertices, uint[] indices) //, List textures) + { + GL = gl; + Vertices = vertices; + Indices = indices; + //Textures = textures; + SetupMesh(); + } + + public Mesh() + { + + } + + public VertexArrayObject VAO { get; set; } + public BufferObject VBO { get; set; } + public BufferObject EBO { get; set; } + public GL GL { get; } + + + public unsafe void SetupMesh() + { + // EBO = new BufferObject(GL, Indices, BufferTargetARB.ElementArrayBuffer); + // VBO = new BufferObject(GL, Vertices, BufferTargetARB.ArrayBuffer); + // VAO = new VertexArrayObject(GL, VBO, EBO); + VAO.VertexAttributePointer(0, 3, VertexAttribPointerType.Float, 5, 0); + VAO.VertexAttributePointer(1, 2, VertexAttribPointerType.Float, 5, 3); + } + + public void Bind() + { + VAO.Bind(); + } + + public void Dispose() + { + // Textures = null; + VAO.Dispose(); + VBO.Dispose(); + EBO.Dispose(); + } } \ No newline at end of file diff --git a/SharpEngine.Core.Components/Properties/Meshes/VertexArrayObject.cs b/SharpEngine.Core.Components/Properties/Meshes/VertexArrayObject.cs new file mode 100644 index 0000000..11291ab --- /dev/null +++ b/SharpEngine.Core.Components/Properties/Meshes/VertexArrayObject.cs @@ -0,0 +1,39 @@ +using Silk.NET.OpenGL; +using System; + +namespace Tutorial +{ + public class VertexArrayObject : IDisposable + where TVertexType : unmanaged + where TIndexType : unmanaged + { + private uint _handle; + private GL _gl; + + public VertexArrayObject(GL gl, BufferObject vbo, BufferObject ebo) + { + _gl = gl; + + _handle = _gl.GenVertexArray(); + Bind(); + vbo.Bind(); + ebo.Bind(); + } + + public unsafe void VertexAttributePointer(uint index, int count, VertexAttribPointerType type, uint vertexSize, int offSet) + { + _gl.VertexAttribPointer(index, count, type, false, vertexSize * (uint) sizeof(TVertexType), (void*) (offSet * sizeof(TVertexType))); + _gl.EnableVertexAttribArray(index); + } + + public void Bind() + { + _gl.BindVertexArray(_handle); + } + + public void Dispose() + { + _gl.DeleteVertexArray(_handle); + } + } +} diff --git a/SharpEngine.Core.Components/SharpEngine.Core.Components.csproj b/SharpEngine.Core.Components/SharpEngine.Core.Components.csproj index 73e5562..22dfc87 100644 --- a/SharpEngine.Core.Components/SharpEngine.Core.Components.csproj +++ b/SharpEngine.Core.Components/SharpEngine.Core.Components.csproj @@ -8,6 +8,7 @@ $(GenerateNuGetPackages) + true diff --git a/SharpEngine.sln b/SharpEngine.sln index 92cd999..a8dff04 100644 --- a/SharpEngine.sln +++ b/SharpEngine.sln @@ -45,6 +45,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ObjLoader", "ObjLoader\ObjL EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ObjLoader.Tests", "Tests\ObjLoader.Test\ObjLoader.Tests.csproj", "{1807AD4A-C310-4BD8-9542-07D3D3EAE617}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tutorial 4.1 - Model Loading", "Examples\Tutorial 4.1 - Model Loading\Tutorial 4.1 - Model Loading.csproj", "{17243B7C-E72B-6C26-FCFC-3D194F29B0AF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -139,6 +141,12 @@ Global {1807AD4A-C310-4BD8-9542-07D3D3EAE617}.LauncherNonWindows|Any CPU.Build.0 = Release|Any CPU {1807AD4A-C310-4BD8-9542-07D3D3EAE617}.Release|Any CPU.ActiveCfg = Release|Any CPU {1807AD4A-C310-4BD8-9542-07D3D3EAE617}.Release|Any CPU.Build.0 = Release|Any CPU + {17243B7C-E72B-6C26-FCFC-3D194F29B0AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {17243B7C-E72B-6C26-FCFC-3D194F29B0AF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {17243B7C-E72B-6C26-FCFC-3D194F29B0AF}.LauncherNonWindows|Any CPU.ActiveCfg = Release|Any CPU + {17243B7C-E72B-6C26-FCFC-3D194F29B0AF}.LauncherNonWindows|Any CPU.Build.0 = Release|Any CPU + {17243B7C-E72B-6C26-FCFC-3D194F29B0AF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {17243B7C-E72B-6C26-FCFC-3D194F29B0AF}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -151,6 +159,7 @@ Global {385CCB8D-CA17-4B58-8DA6-D3E9210CE49B} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {D374B8A7-51F6-4688-BD99-74EB0E159079} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {1807AD4A-C310-4BD8-9542-07D3D3EAE617} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {17243B7C-E72B-6C26-FCFC-3D194F29B0AF} = {B36A84DF-456D-A817-6EDD-3EC3E7F6E11F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AA03EC4B-4E7B-4B73-BEA4-60C539332773} From ce2cc39e219c642b654c3546f9775498318a7752 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sun, 13 Apr 2025 00:20:24 +0300 Subject: [PATCH 58/92] #2 Consolidate new changes --- Examples/Tutorial 4.1 - Model Loading/Mesh.cs | 51 ------------------- .../Tutorial 4.1 - Model Loading/Model.cs | 3 +- .../Tutorial 4.1 - Model Loading/Transform.cs | 24 --------- .../Properties/Meshes/Mesh.cs | 8 +-- .../Properties/Shader.cs | 14 ++++- 5 files changed, 18 insertions(+), 82 deletions(-) delete mode 100644 Examples/Tutorial 4.1 - Model Loading/Mesh.cs delete mode 100644 Examples/Tutorial 4.1 - Model Loading/Transform.cs diff --git a/Examples/Tutorial 4.1 - Model Loading/Mesh.cs b/Examples/Tutorial 4.1 - Model Loading/Mesh.cs deleted file mode 100644 index 089ffcd..0000000 --- a/Examples/Tutorial 4.1 - Model Loading/Mesh.cs +++ /dev/null @@ -1,51 +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; -using System.Collections.Generic; -using Silk.NET.OpenGL; - -namespace Tutorial -{ - public class Mesh : IDisposable - { - public Mesh(GL gl, float[] vertices, uint[] indices, List textures) - { - GL = gl; - Vertices = vertices; - Indices = indices; - Textures = textures; - SetupMesh(); - } - - public float[] Vertices { get; private set; } - public uint[] Indices { get; private set; } - public IReadOnlyList Textures { get; private set; } - public VertexArrayObject VAO { get; set; } - public BufferObject VBO { get; set; } - public BufferObject EBO { get; set; } - public GL GL { get; } - - public unsafe void SetupMesh() - { - EBO = new BufferObject(GL, Indices, BufferTargetARB.ElementArrayBuffer); - VBO = new BufferObject(GL, Vertices, BufferTargetARB.ArrayBuffer); - VAO = new VertexArrayObject(GL, VBO, EBO); - VAO.VertexAttributePointer(0, 3, VertexAttribPointerType.Float, 5, 0); - VAO.VertexAttributePointer(1, 2, VertexAttribPointerType.Float, 5, 3); - } - - public void Bind() - { - VAO.Bind(); - } - - public void Dispose() - { - Textures = null; - VAO.Dispose(); - VBO.Dispose(); - EBO.Dispose(); - } - } -} diff --git a/Examples/Tutorial 4.1 - Model Loading/Model.cs b/Examples/Tutorial 4.1 - Model Loading/Model.cs index 4d665f7..da6c577 100644 --- a/Examples/Tutorial 4.1 - Model Loading/Model.cs +++ b/Examples/Tutorial 4.1 - Model Loading/Model.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Numerics; using AssimpMesh = Silk.NET.Assimp.Mesh; +using Mesh = SharpEngine.Core.Entities.Properties.Meshes.Mesh; namespace Tutorial { @@ -131,7 +132,7 @@ private unsafe Mesh ProcessMesh(AssimpMesh* mesh, Scene* scene) textures.AddRange(heightMaps); // return a mesh object created from the extracted mesh data - var result = new Mesh(_gl, BuildVertices(vertices), BuildIndices(indices), textures); + var result = new Mesh(_gl, BuildVertices(vertices), BuildIndices(indices)); //, textures); return result; } diff --git a/Examples/Tutorial 4.1 - Model Loading/Transform.cs b/Examples/Tutorial 4.1 - Model Loading/Transform.cs deleted file mode 100644 index 959ea9f..0000000 --- a/Examples/Tutorial 4.1 - Model Loading/Transform.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Numerics; - -namespace Tutorial -{ - public class Transform - { - //A transform abstraction. - //For a transform we need to have a position, a scale, and a rotation, - //depending on what application you are creating, the type for these may vary. - - //Here we have chosen a vec3 for position, float for scale and quaternion for rotation, - //as that is the most normal to go with. - //Another example could have been vec3, vec3, vec4, so the rotation is an axis angle instead of a quaternion - - public Vector3 Position { get; set; } = new Vector3(0, 0, 0); - - public float Scale { get; set; } = 1f; - - public Quaternion Rotation { get; set; } = Quaternion.Identity; - - //Note: The order here does matter. - public Matrix4x4 ViewMatrix => Matrix4x4.Identity * Matrix4x4.CreateFromQuaternion(Rotation) * Matrix4x4.CreateScale(Scale) * Matrix4x4.CreateTranslation(Position); - } -} diff --git a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs index 6ab754c..b9c13b6 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs @@ -10,7 +10,7 @@ namespace SharpEngine.Core.Entities.Properties.Meshes; /// /// Represents a game object mesh. /// -public class Mesh +public class Mesh : IDisposable { /// Gets or sets a identifying name for the mesh. public string Name { get; set; } = "New Mesh"; @@ -70,9 +70,9 @@ public Mesh() public unsafe void SetupMesh() { - // EBO = new BufferObject(GL, Indices, BufferTargetARB.ElementArrayBuffer); - // VBO = new BufferObject(GL, Vertices, BufferTargetARB.ArrayBuffer); - // VAO = new VertexArrayObject(GL, VBO, EBO); + EBO = new BufferObject(GL, Indices, BufferTargetARB.ElementArrayBuffer); + VBO = new BufferObject(GL, Vertices, BufferTargetARB.ArrayBuffer); + VAO = new VertexArrayObject(GL, VBO, EBO); VAO.VertexAttributePointer(0, 3, VertexAttribPointerType.Float, 5, 0); VAO.VertexAttributePointer(1, 2, VertexAttribPointerType.Float, 5, 3); } diff --git a/SharpEngine.Core.Components/Properties/Shader.cs b/SharpEngine.Core.Components/Properties/Shader.cs index d8fe831..2d43246 100644 --- a/SharpEngine.Core.Components/Properties/Shader.cs +++ b/SharpEngine.Core.Components/Properties/Shader.cs @@ -1,9 +1,11 @@ +using Silk.NET.OpenGL; + namespace SharpEngine.Core.Shaders; /// /// Represents a shader program. /// -public class Shader +public class Shader : IDisposable { /// Gets the handle to the shader program. public uint Handle; @@ -15,6 +17,8 @@ public class Shader private Dictionary _uniformLocations = []; + private readonly GL _gl; + /// /// Initializes a new instance of . /// @@ -25,9 +29,10 @@ public class Shader /// The vertex shader full path. /// The fragment shader full path. /// The identifier name of the shader. - public Shader(string vertPath, string fragPath, string name) + public Shader(GL gl, string vertPath, string fragPath, string name) { Name = name; + _gl = gl; // 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. @@ -49,4 +54,9 @@ public void InitializeUniforms(Dictionary uniforms) => _uniformLocations = uniforms; public Dictionary GetUniformLocations() => _uniformLocations; + + public void Dispose() + { + _gl.DeleteProgram(Handle); + } } From 31e400494cd816ed31f8e5ceffde32da35d13667 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sun, 13 Apr 2025 00:28:04 +0300 Subject: [PATCH 59/92] #67 Partial class definition --- .../Properties/{ => Shaders}/Shader.cs | 2 +- .../Properties}/Shaders/ShaderAttributes.cs | 0 .../Properties}/Shaders/ShaderExtensions.cs | 122 +++++++++--------- SharpEngine.Core/Shaders/ShaderService.cs | 3 +- SharpEngine.Core/Shaders/UIShader.cs | 2 +- 5 files changed, 63 insertions(+), 66 deletions(-) rename SharpEngine.Core.Components/Properties/{ => Shaders}/Shader.cs (98%) rename {SharpEngine.Core => SharpEngine.Core.Components/Properties}/Shaders/ShaderAttributes.cs (100%) rename {SharpEngine.Core => SharpEngine.Core.Components/Properties}/Shaders/ShaderExtensions.cs (63%) diff --git a/SharpEngine.Core.Components/Properties/Shader.cs b/SharpEngine.Core.Components/Properties/Shaders/Shader.cs similarity index 98% rename from SharpEngine.Core.Components/Properties/Shader.cs rename to SharpEngine.Core.Components/Properties/Shaders/Shader.cs index 2d43246..a61eda5 100644 --- a/SharpEngine.Core.Components/Properties/Shader.cs +++ b/SharpEngine.Core.Components/Properties/Shaders/Shader.cs @@ -5,7 +5,7 @@ namespace SharpEngine.Core.Shaders; /// /// Represents a shader program. /// -public class Shader : IDisposable +public partial class Shader : IDisposable { /// Gets the handle to the shader program. public uint Handle; diff --git a/SharpEngine.Core/Shaders/ShaderAttributes.cs b/SharpEngine.Core.Components/Properties/Shaders/ShaderAttributes.cs similarity index 100% rename from SharpEngine.Core/Shaders/ShaderAttributes.cs rename to SharpEngine.Core.Components/Properties/Shaders/ShaderAttributes.cs diff --git a/SharpEngine.Core/Shaders/ShaderExtensions.cs b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs similarity index 63% rename from SharpEngine.Core/Shaders/ShaderExtensions.cs rename to SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs index 1bcc890..fab755d 100644 --- a/SharpEngine.Core/Shaders/ShaderExtensions.cs +++ b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs @@ -1,62 +1,58 @@ -using SharpEngine.Core.Windowing; -using Silk.NET.OpenGL; -using System; -using System.Collections.Generic; -using System.IO; +using Silk.NET.OpenGL; using System.Numerics; using System.Text.RegularExpressions; namespace SharpEngine.Core.Shaders; -public static class ShaderExtensions +public partial class Shader { - public static Shader Initialize(this Shader shader) + public Shader Initialize() { // Load and compile shader - if (!LoadShader(ShaderType.VertexShader, shader.VertPath, out uint vertexShader)) + if (!LoadShader(ShaderType.VertexShader, VertPath, out uint vertexShader)) { Console.WriteLine("Unable to load vertex shader."); - return shader; + return this; } - if (!LoadShader(ShaderType.FragmentShader, shader.FragPath, out uint fragmentShader)) + if (!LoadShader(ShaderType.FragmentShader, FragPath, out uint fragmentShader)) { Console.WriteLine("Unable to load fragment shader."); - return shader; + return this; } // These two shaders must then be merged into a shader program, which can then be used by OpenGL. // To do this, create a program... - shader.Handle = Window.GL.CreateProgram(); + Handle = _gl.CreateProgram(); // Attach both shaders... - Window.GL.AttachShader(shader.Handle, vertexShader); - Window.GL.AttachShader(shader.Handle, fragmentShader); + _gl.AttachShader(Handle, vertexShader); + _gl.AttachShader(Handle, fragmentShader); // And then link them together. - if (!LinkProgram(shader.Handle)) + if (!LinkProgram(Handle)) { Console.WriteLine("Unable to link shader program."); - return shader; + return this; } // When the shader program is linked, it no longer needs the individual shaders attached to it; the compiled code is copied into the shader program. // Detach them, and then delete them. - Window.GL.DetachShader(shader.Handle, vertexShader); - Window.GL.DetachShader(shader.Handle, fragmentShader); - Window.GL.DeleteShader(fragmentShader); - Window.GL.DeleteShader(vertexShader); + _gl.DetachShader(Handle, vertexShader); + _gl.DetachShader(Handle, fragmentShader); + _gl.DeleteShader(fragmentShader); + _gl.DeleteShader(vertexShader); // The shader is now ready to go, but first, we're going to cache all the shader uniform locations. // Querying this from the shader is very slow, so we do it once on initialization and reuse those values // later. - SetUniformLocations(shader); + SetUniformLocations(); - return shader; + return this; } - private static bool LoadShader(ShaderType shaderType, string shaderPath, out uint shader) + private bool LoadShader(ShaderType shaderType, string shaderPath, out uint shader) { if (!File.Exists(shaderPath)) { @@ -70,8 +66,8 @@ private static bool LoadShader(ShaderType shaderType, string shaderPath, out uin shaderSource = ProcessIncludes(shaderSource, Path.GetDirectoryName(shaderPath)!); // GL.CreateShader will create an empty shader (obviously). The ShaderType enum denotes which type of shader will be created. - shader = Window.GL.CreateShader(shaderType); - Window.GL.ShaderSource(shader, shaderSource); + shader = _gl.CreateShader(shaderType); + _gl.ShaderSource(shader, shaderSource); if (!CompileShader(shader)) { @@ -82,10 +78,10 @@ private static bool LoadShader(ShaderType shaderType, string shaderPath, out uin return true; } - public static Shader SetUniformLocations(this Shader shader) + public Shader SetUniformLocations() { // First, we have to get the number of active uniforms in the shader. - Window.GL.GetProgram(shader.Handle, GLEnum.ActiveUniforms, out var numberOfUniforms); + _gl.GetProgram(Handle, GLEnum.ActiveUniforms, out var numberOfUniforms); // Next, allocate the dictionary to hold the locations. Dictionary uniformLocations = []; @@ -94,17 +90,17 @@ public static Shader SetUniformLocations(this Shader shader) for (uint i = 0; i < numberOfUniforms; i++) { // get the name of this uniform, - var key = Window.GL.GetActiveUniform(shader.Handle, i, out _, out _); + var key = _gl.GetActiveUniform(Handle, i, out _, out _); // get the location, - var location = Window.GL.GetUniformLocation(shader.Handle, key); + var location = _gl.GetUniformLocation(Handle, key); // and then add it to the dictionary. uniformLocations.Add(key, location); } - shader.InitializeUniforms(uniformLocations); - return shader; + InitializeUniforms(uniformLocations); + return this; } private static string ProcessIncludes(string shaderCode, string directory) @@ -118,17 +114,17 @@ private static string ProcessIncludes(string shaderCode, string directory) }); } - private static bool CompileShader(uint shader) + private bool CompileShader(uint shader) { // Try to compile the shader - Window.GL.CompileShader(shader); + _gl.CompileShader(shader); // Check for compilation errors - Window.GL.GetShader(shader, GLEnum.CompileStatus, out var statusCode); + _gl.GetShader(shader, GLEnum.CompileStatus, out var statusCode); if (statusCode != (int)GLEnum.True) { // We can use `GL.GetShaderInfoLog(shader)` to get information about the error. - var infoLog = Window.GL.GetShaderInfoLog(shader); + var infoLog = _gl.GetShaderInfoLog(shader); Console.WriteLine($"Error occurred whilst compiling Shader({shader}).\n\n{infoLog}"); return false; @@ -137,14 +133,14 @@ private static bool CompileShader(uint shader) return true; } - private static bool LinkProgram(uint program) + private bool LinkProgram(uint program) { - Window.GL.LinkProgram(program); - Window.GL.GetProgram(program, GLEnum.LinkStatus, out var statusCode); + _gl.LinkProgram(program); + _gl.GetProgram(program, GLEnum.LinkStatus, out var statusCode); if (statusCode != (int)GLEnum.True) { - string infoLog = Window.GL.GetProgramInfoLog(program); + string infoLog = _gl.GetProgramInfoLog(program); Console.WriteLine($"Error occurred whilst linking Program({program}): {infoLog}"); return false; @@ -156,8 +152,8 @@ private static bool LinkProgram(uint program) /// /// Enables the shader program. /// - public static void Use(this Shader shader) - => Window.GL.UseProgram(shader.Handle); + public void Use() + => _gl.UseProgram(Handle); /// /// Checks if the shader attribute exists within the current shader. @@ -165,9 +161,9 @@ public static void Use(this Shader shader) /// The name of the attribute that's being looked for. /// Outputs the location of the attribute in the shader if found; otherwise -1. /// If the attribute exists, ; otherwise, . - public static bool TryGetAttribLocation(this Shader shader, string attribName, out int location) + public bool TryGetAttribLocation(string attribName, out int location) { - location = Window.GL.GetAttribLocation(shader.Handle, attribName); + location = _gl.GetAttribLocation(Handle, attribName); if (location == ShaderAttributes.AttributeLocationNotFound) { Console.WriteLine($"Attribute '{attribName}' not found in shader program."); @@ -186,9 +182,9 @@ public static bool TryGetAttribLocation(this Shader shader, string attribName, o // 2. Get a handle to the location of the uniform with GL.GetUniformLocation. // 3. Use the appropriate GL.Uniform* function to set the uniform. - private static bool TrySetUniform(this Shader shader, string name, T data, Action setter) + private bool TrySetUniform(string name, T data, Action setter) { - var uniforms = shader.GetUniformLocations(); + var uniforms = GetUniformLocations(); if (!uniforms.TryGetValue(name, out int uniform)) { Console.WriteLine($"Uniform '{name}' not found in shader program."); @@ -204,10 +200,10 @@ private static bool TrySetUniform(this Shader shader, string name, T data, Ac /// /// The name of the uniform. /// The data to set. - public static void SetInt(this Shader shader, string name, int data) + public void SetInt(string name, int data) { - Window.GL.UseProgram(shader.Handle); - shader.TrySetUniform(name, data, Window.GL.Uniform1); + _gl.UseProgram(Handle); + TrySetUniform(name, data, _gl.Uniform1); } /// @@ -215,10 +211,10 @@ public static void SetInt(this Shader shader, string name, int data) /// /// The name of the uniform. /// The data to set. - public static void SetFloat(this Shader shader, string name, float data) + public void SetFloat(string name, float data) { - Window.GL.UseProgram(shader.Handle); - shader.TrySetUniform(name, data, Window.GL.Uniform1); + _gl.UseProgram(Handle); + TrySetUniform(name, data, _gl.Uniform1); } /// @@ -232,10 +228,10 @@ public static void SetFloat(this Shader shader, string name, float data) /// The matrix is transposed before being sent to the shader unless is set to . /// /// - public static void SetMatrix4(this Shader shader, string name, Matrix4x4 data, bool transpose = true) + public void SetMatrix4(string name, Matrix4x4 data, bool transpose = true) { - Window.GL.UseProgram(shader.Handle); - shader.TrySetUniform(name, data, (uniform, d) => Window.GL.UniformMatrix4(uniform, transpose, d.ToSpan())); + _gl.UseProgram(Handle); + TrySetUniform(name, data, (uniform, d) => _gl.UniformMatrix4(uniform, transpose, d.ToSpan())); } /// @@ -243,10 +239,10 @@ public static void SetMatrix4(this Shader shader, string name, Matrix4x4 data, b /// /// The name of the uniform. /// The data to set. - public static void SetVector2(this Shader shader, string name, Vector2 data) + public void SetVector2(string name, Vector2 data) { - Window.GL.UseProgram(shader.Handle); - shader.TrySetUniform(name, data, Window.GL.Uniform2); + _gl.UseProgram(Handle); + TrySetUniform(name, data, _gl.Uniform2); } /// @@ -254,10 +250,10 @@ public static void SetVector2(this Shader shader, string name, Vector2 data) /// /// The name of the uniform. /// The data to set. - public static void SetVector3(this Shader shader, string name, Vector3 data) + public void SetVector3(string name, Vector3 data) { - Window.GL.UseProgram(shader.Handle); - shader.TrySetUniform(name, data, Window.GL.Uniform3); + _gl.UseProgram(Handle); + TrySetUniform(name, data, _gl.Uniform3); } /// @@ -265,9 +261,9 @@ public static void SetVector3(this Shader shader, string name, Vector3 data) /// /// The name of the uniform. /// The data to set. - public static void SetVector4(this Shader shader, string name, Vector4 data) + public void SetVector4(string name, Vector4 data) { - Window.GL.UseProgram(shader.Handle); - shader.TrySetUniform(name, data, Window.GL.Uniform4); + _gl.UseProgram(Handle); + TrySetUniform(name, data, _gl.Uniform4); } } diff --git a/SharpEngine.Core/Shaders/ShaderService.cs b/SharpEngine.Core/Shaders/ShaderService.cs index f1b0bfe..ad25acb 100644 --- a/SharpEngine.Core/Shaders/ShaderService.cs +++ b/SharpEngine.Core/Shaders/ShaderService.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Collections.Generic; +using SharpEngine.Core.Windowing; namespace SharpEngine.Core.Shaders; @@ -82,7 +83,7 @@ public Shader LoadShader(string vertPath, string fragPath, string name) } // Create a new shader instance and add it to the cache - var shader = new Shader(vertPath, fragPath, name).Initialize(); + var shader = new Shader(Window.GL, vertPath, fragPath, name).Initialize(); _shaderCache[name] = shader; HasShadersToLoad = true; diff --git a/SharpEngine.Core/Shaders/UIShader.cs b/SharpEngine.Core/Shaders/UIShader.cs index 6cd2e0e..37caf51 100644 --- a/SharpEngine.Core/Shaders/UIShader.cs +++ b/SharpEngine.Core/Shaders/UIShader.cs @@ -13,7 +13,7 @@ internal class UIShader : ShaderBase /// public UIShader() { - Shader = new Shader(Default.UIVertexShader, Default.UIFragmentShader, nameof(UIShader)).Initialize(); + Shader = new Shader(Window.GL, Default.UIVertexShader, Default.UIFragmentShader, nameof(UIShader)).Initialize(); } /// From 03c6393ab280606dc8c5e964709881bed783ff38 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sun, 13 Apr 2025 02:28:57 +0300 Subject: [PATCH 60/92] #2 Use Core Shader in tutorial --- .../Tutorial 4.1 - Model Loading/Program.cs | 25 +++++++++++----- .../Tutorial 4.1 - Model Loading/Shader.cs | 5 ++-- .../Properties/Shaders/Shader.cs | 5 ---- .../Properties/Shaders/ShaderExtensions.cs | 29 +++++++++++-------- 4 files changed, 37 insertions(+), 27 deletions(-) diff --git a/Examples/Tutorial 4.1 - Model Loading/Program.cs b/Examples/Tutorial 4.1 - Model Loading/Program.cs index e6fc2a7..e7f347c 100644 --- a/Examples/Tutorial 4.1 - Model Loading/Program.cs +++ b/Examples/Tutorial 4.1 - Model Loading/Program.cs @@ -1,21 +1,24 @@ +using SharpEngine.Core.Extensions; using Silk.NET.Input; +using Silk.NET.Maths; using Silk.NET.OpenGL; using Silk.NET.Windowing; using System; using System.Linq; using System.Numerics; -using Silk.NET.Maths; +using Shader = SharpEngine.Core.Shaders.Shader; namespace Tutorial { 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 SharpEngine.Core.Shaders.Shader Shader; private static Model Model; //Setup the camera's location, directions, and movement speed @@ -29,6 +32,7 @@ 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[] args) { @@ -65,7 +69,10 @@ private static void OnLoad() Gl = GL.GetApi(window); - Shader = new Shader(Gl, "shader.vert", "shader.frag"); + Gl.GetInteger(GLEnum.ContextFlags, out int contextFlags); + Console.WriteLine($"OpenGL Context Flags: {contextFlags}"); + + Shader = new Shader(Gl, PathExtensions.GetAssemblyPath("shader.vert"), PathExtensions.GetAssemblyPath("shader.frag"), "test").Initialize(); Texture = new Texture(Gl, "silk.png"); Model = new Model(Gl, "cube.model"); } @@ -103,7 +110,8 @@ private static unsafe void OnRender(double deltaTime) Texture.Bind(); Shader.Use(); - Shader.SetUniform("uTexture0", 0); + //Shader.SetUniform("uTexture0", 0); + Shader.SetInt("uTexture0", 0); //Use elapsed time to convert to radians to allow our cube to rotate over time var difference = (float) (window.Time * 100); @@ -120,10 +128,11 @@ private static unsafe void OnRender(double deltaTime) mesh.Bind(); Shader.Use(); Texture.Bind(); - Shader.SetUniform("uTexture0", 0); - Shader.SetUniform("uModel", model); - Shader.SetUniform("uView", view); - Shader.SetUniform("uProjection", projection); + + Shader.SetInt("uTexture0", 0); + Shader.SetMatrix4("uModel", model, false); + Shader.SetMatrix4("uView", view, false); + Shader.SetMatrix4("uProjection", projection, false); Gl.DrawArrays(PrimitiveType.Triangles, 0, (uint)mesh.Vertices.Length); } diff --git a/Examples/Tutorial 4.1 - Model Loading/Shader.cs b/Examples/Tutorial 4.1 - Model Loading/Shader.cs index 99a6959..5eaa02b 100644 --- a/Examples/Tutorial 4.1 - Model Loading/Shader.cs +++ b/Examples/Tutorial 4.1 - Model Loading/Shader.cs @@ -1,4 +1,4 @@ -using System; +/*using System; using System.IO; using System.Numerics; using Silk.NET.OpenGL; @@ -7,7 +7,7 @@ namespace Tutorial { public class Shader : IDisposable { - private uint _handle; + public uint _handle; private GL _gl; public Shader(GL gl, string vertexPath, string fragmentPath) @@ -88,3 +88,4 @@ private uint LoadShader(ShaderType type, string path) } } } +*/ \ No newline at end of file diff --git a/SharpEngine.Core.Components/Properties/Shaders/Shader.cs b/SharpEngine.Core.Components/Properties/Shaders/Shader.cs index a61eda5..4eae830 100644 --- a/SharpEngine.Core.Components/Properties/Shaders/Shader.cs +++ b/SharpEngine.Core.Components/Properties/Shaders/Shader.cs @@ -50,11 +50,6 @@ public Shader(GL gl, string vertPath, string fragPath, string name) FragPath = fragPath; } - public void InitializeUniforms(Dictionary uniforms) - => _uniformLocations = uniforms; - - public Dictionary GetUniformLocations() => _uniformLocations; - public void Dispose() { _gl.DeleteProgram(Handle); diff --git a/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs index fab755d..c60fd06 100644 --- a/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs +++ b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs @@ -31,11 +31,7 @@ public Shader Initialize() _gl.AttachShader(Handle, fragmentShader); // And then link them together. - if (!LinkProgram(Handle)) - { - Console.WriteLine("Unable to link shader program."); - return this; - } + bool shaderLinked = LinkProgram(Handle); // When the shader program is linked, it no longer needs the individual shaders attached to it; the compiled code is copied into the shader program. // Detach them, and then delete them. @@ -44,6 +40,12 @@ public Shader Initialize() _gl.DeleteShader(fragmentShader); _gl.DeleteShader(vertexShader); + if (!shaderLinked) + { + Console.WriteLine("Unable to link shader program."); + return this; + } + // The shader is now ready to go, but first, we're going to cache all the shader uniform locations. // Querying this from the shader is very slow, so we do it once on initialization and reuse those values // later. @@ -83,7 +85,6 @@ public Shader SetUniformLocations() // First, we have to get the number of active uniforms in the shader. _gl.GetProgram(Handle, GLEnum.ActiveUniforms, out var numberOfUniforms); - // Next, allocate the dictionary to hold the locations. Dictionary uniformLocations = []; // Loop over all the uniforms, @@ -99,7 +100,7 @@ public Shader SetUniformLocations() uniformLocations.Add(key, location); } - InitializeUniforms(uniformLocations); + _uniformLocations = uniformLocations; return this; } @@ -184,17 +185,20 @@ public bool TryGetAttribLocation(string attribName, out int location) private bool TrySetUniform(string name, T data, Action setter) { - var uniforms = GetUniformLocations(); - if (!uniforms.TryGetValue(name, out int uniform)) + //int location = _gl.GetUniformLocation(Handle, name); + if (!_uniformLocations.TryGetValue(name, out int location)) + //if (location == -1) { Console.WriteLine($"Uniform '{name}' not found in shader program."); return false; } - setter(uniform, data); + setter(location, data); return true; } + // TODO: The _gl.UseProgram should be not be called here. Rather the renderer should call it once before rendering. + /// /// Set a uniform int on this shader. /// @@ -228,10 +232,11 @@ public void SetFloat(string name, float data) /// The matrix is transposed before being sent to the shader unless is set to . /// /// - public void SetMatrix4(string name, Matrix4x4 data, bool transpose = true) + public unsafe void SetMatrix4(string name, Matrix4x4 data, bool transpose = true) { _gl.UseProgram(Handle); - TrySetUniform(name, data, (uniform, d) => _gl.UniformMatrix4(uniform, transpose, d.ToSpan())); + // TrySetUniform(name, data, (uniform, d) => _gl.UniformMatrix4(uniform, transpose, d.ToSpan())); + TrySetUniform(name, data, (uniform, d) => _gl.UniformMatrix4(uniform, 1, transpose, (float*) &d)); } /// From 3c5b4b5cb85ad6e750ca4fcb16c5787bdb06c3dd Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sun, 13 Apr 2025 16:59:25 +0300 Subject: [PATCH 61/92] #2 Remove redundancies and plan merging --- Examples/MinecraftClone/Minecraft.cs | 64 ++++++++++--- .../Tutorial 4.1 - Model Loading/Program.cs | 11 +-- .../Tutorial 4.1 - Model Loading/Shader.cs | 91 ------------------- .../Tutorial 4.1 - Model Loading.csproj | 14 +-- .../Tutorial 4.1 - Model Loading/cube.model | 52 ----------- .../Tutorial 4.1 - Model Loading/shader.frag | 11 --- .../MaterialLoader/MaterialLibraryLoader.cs | 8 +- .../Properties/Material.cs | 2 +- .../Properties/Meshes/MeshData/Face.cs | 2 +- .../Properties/Meshes/MeshData/Vertex.cs | 2 + .../Properties/Meshes/MeshData/Vertex2.cs | 2 +- .../Properties/Meshes}/Model.cs | 20 ++-- .../Properties/{ => Textures}/Texture.cs | 10 +- .../Properties/Textures/Texture2.cs | 6 +- .../SharpEngine.Core.Components.csproj | 7 ++ .../_Resources/Shaders/shader.frag | 7 ++ 16 files changed, 104 insertions(+), 205 deletions(-) delete mode 100644 Examples/Tutorial 4.1 - Model Loading/Shader.cs delete mode 100644 Examples/Tutorial 4.1 - Model Loading/cube.model delete mode 100644 Examples/Tutorial 4.1 - Model Loading/shader.frag rename Examples/Tutorial 4.1 - Model Loading/Vertex.cs => SharpEngine.Core.Components/Properties/Meshes/MeshData/Vertex2.cs (94%) rename {Examples/Tutorial 4.1 - Model Loading => SharpEngine.Core.Components/Properties/Meshes}/Model.cs (90%) rename SharpEngine.Core.Components/Properties/{ => Textures}/Texture.cs (67%) rename Examples/Tutorial 4.1 - Model Loading/Texture.cs => SharpEngine.Core.Components/Properties/Textures/Texture2.cs (92%) diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index 5ea18f7..08c89e3 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -1,21 +1,21 @@ using ImGuiNET; using Minecraft.Block; using ObjLoader.Loaders.ObjLoader; -using Silk.NET.Input; - -using System; -using System.Numerics; - using SharpEngine.Core; using SharpEngine.Core.Entities; using SharpEngine.Core.Entities.Lights; +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 Silk.NET.Input; +using System; +using System.Collections.Generic; using System.Linq; +using System.Numerics; namespace Minecraft; @@ -142,23 +142,59 @@ public void OnAfterRender(Frame frame) private void InitializeWorld() { InitializeLights(); - InitializeChunks(); + // InitializeChunks(); // TODO: Does not work yet. // var torus = MeshService.Instance.LoadMesh("torus", @"C:\Users\antti\Documents\Untitled2.obj"); var result = ObjLoaderFactory.Load(@"C:\Users\antti\Documents\Untitled2.obj"); - result.Vertices = [.. result.Vertices2.SelectMany(i => new[] { i.X, i.Y, i.Z })]; - result.Normals = [.. result.Normals2.SelectMany(i => new[] { i.X, i.Y, i.Z })]; - result.TextureCoordinates = [.. result.TextureCoordinates2.SelectMany(i => new [] { i.X, i.Y }) ]; + ResolveMeshData(result); - // var go = new GameObject(); - // go.Meshes.Add(result); - // - // go.Initialize(); - // _scene.Root.AddChild(go); + var go = new GameObject(); + go.Meshes.Add(result); + + go.Initialize(); + _scene.Root.AddChild(go); + + } + + private void ResolveMeshData(Mesh mesh) + { + var resolvedVertices = new List(); + var resolvedNormals = new List(); + var resolvedTextureCoordinates = new List(); + + foreach (var group in mesh.Groups) + { + foreach (var face in group.Faces) + { + foreach (var vertex in face._vertices) + { + // Resolve vertex positions + var position = mesh.Vertices2[vertex.VertexIndex]; + resolvedVertices.Add(position.X); + resolvedVertices.Add(position.Y); + resolvedVertices.Add(position.Z); + + // Resolve normals + var normal = mesh.Normals2[vertex.NormalIndex]; + resolvedNormals.Add(normal.X); + resolvedNormals.Add(normal.Y); + resolvedNormals.Add(normal.Z); + + // Resolve texture coordinates + var texCoord = mesh.TextureCoordinates2[vertex.TextureIndex]; + resolvedTextureCoordinates.Add(texCoord.X); + resolvedTextureCoordinates.Add(texCoord.Y); + } + } + } + // Update the mesh with resolved data + mesh.Vertices = resolvedVertices.ToArray(); + mesh.Normals = resolvedNormals.ToArray(); + mesh.TextureCoordinates = resolvedTextureCoordinates.ToArray(); } private void InitializeLights() diff --git a/Examples/Tutorial 4.1 - Model Loading/Program.cs b/Examples/Tutorial 4.1 - Model Loading/Program.cs index e7f347c..475458c 100644 --- a/Examples/Tutorial 4.1 - Model Loading/Program.cs +++ b/Examples/Tutorial 4.1 - Model Loading/Program.cs @@ -17,8 +17,8 @@ class Program private static GL Gl; private static IKeyboard primaryKeyboard; - private static Texture Texture; - private static SharpEngine.Core.Shaders.Shader Shader; + private static Texture2 Texture; + private static Shader Shader; private static Model Model; //Setup the camera's location, directions, and movement speed @@ -72,9 +72,9 @@ private static void OnLoad() Gl.GetInteger(GLEnum.ContextFlags, out int contextFlags); Console.WriteLine($"OpenGL Context Flags: {contextFlags}"); - Shader = new Shader(Gl, PathExtensions.GetAssemblyPath("shader.vert"), PathExtensions.GetAssemblyPath("shader.frag"), "test").Initialize(); - Texture = new Texture(Gl, "silk.png"); - Model = new Model(Gl, "cube.model"); + Shader = new Shader(Gl, PathExtensions.GetAssemblyPath("shader.vert"), SharpEngine.Core._Resources.Default.LightShader, "test").Initialize(); + Texture = new Texture2(Gl, "silk.png"); + Model = new Model(Gl, "Untitled2.obj"); } private static unsafe void OnUpdate(double deltaTime) @@ -110,7 +110,6 @@ private static unsafe void OnRender(double deltaTime) Texture.Bind(); Shader.Use(); - //Shader.SetUniform("uTexture0", 0); Shader.SetInt("uTexture0", 0); //Use elapsed time to convert to radians to allow our cube to rotate over time diff --git a/Examples/Tutorial 4.1 - Model Loading/Shader.cs b/Examples/Tutorial 4.1 - Model Loading/Shader.cs deleted file mode 100644 index 5eaa02b..0000000 --- a/Examples/Tutorial 4.1 - Model Loading/Shader.cs +++ /dev/null @@ -1,91 +0,0 @@ -/*using System; -using System.IO; -using System.Numerics; -using Silk.NET.OpenGL; - -namespace Tutorial -{ - public class Shader : IDisposable - { - public uint _handle; - private GL _gl; - - public Shader(GL gl, string vertexPath, string fragmentPath) - { - _gl = gl; - - uint vertex = LoadShader(ShaderType.VertexShader, vertexPath); - uint fragment = LoadShader(ShaderType.FragmentShader, fragmentPath); - _handle = _gl.CreateProgram(); - _gl.AttachShader(_handle, vertex); - _gl.AttachShader(_handle, fragment); - _gl.LinkProgram(_handle); - _gl.GetProgram(_handle, GLEnum.LinkStatus, out var status); - if (status == 0) - { - throw new Exception($"Program failed to link with error: {_gl.GetProgramInfoLog(_handle)}"); - } - _gl.DetachShader(_handle, vertex); - _gl.DetachShader(_handle, fragment); - _gl.DeleteShader(vertex); - _gl.DeleteShader(fragment); - } - - public void Use() - { - _gl.UseProgram(_handle); - } - - public void SetUniform(string name, int value) - { - int location = _gl.GetUniformLocation(_handle, name); - if (location == -1) - { - throw new Exception($"{name} uniform not found on shader."); - } - _gl.Uniform1(location, value); - } - - public unsafe void SetUniform(string name, Matrix4x4 value) - { - //A new overload has been created for setting a uniform so we can use the transform in our shader. - int location = _gl.GetUniformLocation(_handle, name); - if (location == -1) - { - throw new Exception($"{name} uniform not found on shader."); - } - _gl.UniformMatrix4(location, 1, false, (float*) &value); - } - - public void SetUniform(string name, float value) - { - int location = _gl.GetUniformLocation(_handle, name); - if (location == -1) - { - throw new Exception($"{name} uniform not found on shader."); - } - _gl.Uniform1(location, value); - } - - public void Dispose() - { - _gl.DeleteProgram(_handle); - } - - private uint LoadShader(ShaderType type, string path) - { - string src = File.ReadAllText(path); - uint handle = _gl.CreateShader(type); - _gl.ShaderSource(handle, src); - _gl.CompileShader(handle); - string infoLog = _gl.GetShaderInfoLog(handle); - if (!string.IsNullOrWhiteSpace(infoLog)) - { - throw new Exception($"Error compiling shader of type {type}, failed with error {infoLog}"); - } - - return handle; - } - } -} -*/ \ No newline at end of file diff --git a/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 index 18cc1d8..7066116 100644 --- a/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 @@ -7,10 +7,6 @@ true - - - - + + + + + + diff --git a/SharpEngine.Core/_Resources/Shaders/shader.frag b/SharpEngine.Core/_Resources/Shaders/shader.frag index 1c649f4..8170aee 100644 --- a/SharpEngine.Core/_Resources/Shaders/shader.frag +++ b/SharpEngine.Core/_Resources/Shaders/shader.frag @@ -1,7 +1,14 @@ #version 330 core +in vec2 fUv; + + +uniform sampler2D uTexture0; + out vec4 FragColor; void main() { FragColor = vec4(1.0); // set all 4 vector values to 1.0 + // FragColor = texture(uTexture0, fUv); + } \ No newline at end of file From 0beff6f8c1e663cdf8e062e2c762dcfae71bbf39 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sun, 13 Apr 2025 17:03:05 +0300 Subject: [PATCH 62/92] #2 Texture partial class --- Examples/MinecraftClone/Minecraft.cs | 2 +- Examples/Tutorial 4.1 - Model Loading/Program.cs | 1 + .../Properties/Meshes/Model.cs | 1 + .../Properties/Textures/Texture.cs | 6 +++++- .../Properties/Textures/Texture2.cs | 4 +--- .../Properties}/Textures/TextureExtensions.cs | 13 ++++++------- SharpEngine.Core/Renderers/Renderer.cs | 9 +++++++++ SharpEngine.Core/Textures/TextureService.cs | 4 +++- 8 files changed, 27 insertions(+), 13 deletions(-) rename {SharpEngine.Core => SharpEngine.Core.Components/Properties}/Textures/TextureExtensions.cs (58%) diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index 08c89e3..7224b75 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -142,7 +142,7 @@ public void OnAfterRender(Frame frame) private void InitializeWorld() { InitializeLights(); - // InitializeChunks(); + InitializeChunks(); // TODO: Does not work yet. // var torus = MeshService.Instance.LoadMesh("torus", @"C:\Users\antti\Documents\Untitled2.obj"); diff --git a/Examples/Tutorial 4.1 - Model Loading/Program.cs b/Examples/Tutorial 4.1 - Model Loading/Program.cs index 475458c..08998b9 100644 --- a/Examples/Tutorial 4.1 - Model Loading/Program.cs +++ b/Examples/Tutorial 4.1 - Model Loading/Program.cs @@ -1,3 +1,4 @@ +using SharpEngine.Core.Components.Properties.Textures; using SharpEngine.Core.Extensions; using Silk.NET.Input; using Silk.NET.Maths; diff --git a/SharpEngine.Core.Components/Properties/Meshes/Model.cs b/SharpEngine.Core.Components/Properties/Meshes/Model.cs index 90f25cd..026e1ea 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/Model.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/Model.cs @@ -1,6 +1,7 @@ // 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.Textures; using Silk.NET.Assimp; using Silk.NET.OpenGL; using System; diff --git a/SharpEngine.Core.Components/Properties/Textures/Texture.cs b/SharpEngine.Core.Components/Properties/Textures/Texture.cs index 813ff71..46e718f 100644 --- a/SharpEngine.Core.Components/Properties/Textures/Texture.cs +++ b/SharpEngine.Core.Components/Properties/Textures/Texture.cs @@ -1,4 +1,5 @@ using Silk.NET.Assimp; +using Silk.NET.OpenGL; namespace SharpEngine.Core.Components.Properties.Textures; @@ -14,12 +15,15 @@ public partial class Texture public TextureType Type { get; } + private readonly GL _gl; + /// /// Initializes a new instance of . /// /// The handle to the texture. - public Texture(uint glHandle) + public Texture(uint glHandle, GL gl) { Handle = glHandle; + _gl = gl; } } diff --git a/SharpEngine.Core.Components/Properties/Textures/Texture2.cs b/SharpEngine.Core.Components/Properties/Textures/Texture2.cs index 26159d1..cb3ed72 100644 --- a/SharpEngine.Core.Components/Properties/Textures/Texture2.cs +++ b/SharpEngine.Core.Components/Properties/Textures/Texture2.cs @@ -4,7 +4,7 @@ using SixLabors.ImageSharp.PixelFormats; using System; -namespace Tutorial +namespace SharpEngine.Core.Components.Properties.Textures { public class Texture2 : IDisposable { @@ -29,12 +29,10 @@ public unsafe Texture2(GL gl, string path, TextureType type = TextureType.None) img.ProcessPixelRows(accessor => { for (int y = 0; y < accessor.Height; y++) - { fixed (void* data = accessor.GetRowSpan(y)) { gl.TexSubImage2D(TextureTarget.Texture2D, 0, 0, y, (uint) accessor.Width, 1, PixelFormat.Rgba, PixelType.UnsignedByte, data); } - } }); } diff --git a/SharpEngine.Core/Textures/TextureExtensions.cs b/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs similarity index 58% rename from SharpEngine.Core/Textures/TextureExtensions.cs rename to SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs index 800443e..35019e2 100644 --- a/SharpEngine.Core/Textures/TextureExtensions.cs +++ b/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs @@ -1,9 +1,8 @@ -using SharpEngine.Core.Windowing; -using Silk.NET.OpenGL; +using Silk.NET.OpenGL; -namespace SharpEngine.Core.Textures; +namespace SharpEngine.Core.Components.Properties.Textures; -public static class TextureExtensions +public partial class Texture { // Multiple textures can be bound, if your shader needs more than just one. @@ -14,9 +13,9 @@ public static class TextureExtensions /// Activate the texture. /// /// The bound texture location. - public static void Use(this Texture texture, TextureUnit unit) + public void Use(TextureUnit unit) { - Window.GL.ActiveTexture(unit); - Window.GL.BindTexture(TextureTarget.Texture2D, texture.Handle); + _gl.ActiveTexture(unit); + _gl.BindTexture(TextureTarget.Texture2D, Handle); } } diff --git a/SharpEngine.Core/Renderers/Renderer.cs b/SharpEngine.Core/Renderers/Renderer.cs index 3768c84..92efdc2 100644 --- a/SharpEngine.Core/Renderers/Renderer.cs +++ b/SharpEngine.Core/Renderers/Renderer.cs @@ -25,6 +25,10 @@ public class Renderer : RendererBase private readonly Scene _scene; private readonly Window _window; + // TODO: Property for specific type of objects + // No heavy iteration reads for filtering, + // instead use a notification system from the scene that an item has been removed / added? + // Read only once, load into OpenGL buffer once. // TODO: Multiple meshes @@ -57,6 +61,11 @@ public override Task Render() { Window.GL.Enable(EnableCap.DepthTest); + // Enable image transparency. + // TODO: Needs testing. + Window.GL.Enable(EnableCap.Blend); + Window.GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); + _camera.SetShaderUniforms(_lightingShader.Shader!); Window.GL.BindVertexArray(_lightingShader.Vao); diff --git a/SharpEngine.Core/Textures/TextureService.cs b/SharpEngine.Core/Textures/TextureService.cs index 05b1775..fe3388d 100644 --- a/SharpEngine.Core/Textures/TextureService.cs +++ b/SharpEngine.Core/Textures/TextureService.cs @@ -6,6 +6,8 @@ using Silk.NET.OpenGL; using SharpEngine.Core.Windowing; +using SharpEngine.Core.Components.Properties.Textures; +using Texture = SharpEngine.Core.Components.Properties.Textures.Texture; namespace SharpEngine.Core.Textures; @@ -67,7 +69,7 @@ public Texture LoadTexture(string path) Window.GL.GenerateMipmap(GLEnum.Texture2D); // Create a new texture instance and add it to the cache - var texture = new Texture(handle); + var texture = new Texture(handle, Window.GL); _textureCache[path] = texture; return texture; From c53b1e29c6e207204b24ddcffe0599be0018262f Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sun, 13 Apr 2025 17:12:07 +0300 Subject: [PATCH 63/92] #2 Improve texture class --- .../Properties/Textures/Texture.cs | 32 ++++++++++++++++++- .../Properties/Textures/TextureExtensions.cs | 12 ------- SharpEngine.Core/Textures/TextureService.cs | 15 ++++----- 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/SharpEngine.Core.Components/Properties/Textures/Texture.cs b/SharpEngine.Core.Components/Properties/Textures/Texture.cs index 46e718f..ec4d829 100644 --- a/SharpEngine.Core.Components/Properties/Textures/Texture.cs +++ b/SharpEngine.Core.Components/Properties/Textures/Texture.cs @@ -6,7 +6,7 @@ namespace SharpEngine.Core.Components.Properties.Textures; /// /// Represents a texture program. /// -public partial class Texture +public partial class Texture : IDisposable { /// The OpenGL handle for the texture. public readonly uint Handle; @@ -26,4 +26,34 @@ public Texture(uint glHandle, GL gl) Handle = glHandle; _gl = gl; } + + 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.GenerateMipmap(TextureTarget.Texture2D); + } + + // Multiple textures can be bound, if your shader needs more than just one. + // If you want to do that, use GL.ActiveTexture to set which slot GL.BindTexture binds to. + // The OpenGL standard requires that there be at least 16, but there can be more depending on your graphics card. + + /// + /// Activate the texture. + /// + /// The bound texture location. + public void Use(TextureUnit unit = TextureUnit.Texture0) + { + _gl.ActiveTexture(unit); + _gl.BindTexture(TextureTarget.Texture2D, Handle); + } + + public void Dispose() + { + _gl.DeleteTexture(Handle); + } } diff --git a/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs b/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs index 35019e2..35cc367 100644 --- a/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs +++ b/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs @@ -5,17 +5,5 @@ namespace SharpEngine.Core.Components.Properties.Textures; public partial class Texture { - // Multiple textures can be bound, if your shader needs more than just one. - // If you want to do that, use GL.ActiveTexture to set which slot GL.BindTexture binds to. - // The OpenGL standard requires that there be at least 16, but there can be more depending on your graphics card. - /// - /// Activate the texture. - /// - /// The bound texture location. - public void Use(TextureUnit unit) - { - _gl.ActiveTexture(unit); - _gl.BindTexture(TextureTarget.Texture2D, Handle); - } } diff --git a/SharpEngine.Core/Textures/TextureService.cs b/SharpEngine.Core/Textures/TextureService.cs index fe3388d..3bacd96 100644 --- a/SharpEngine.Core/Textures/TextureService.cs +++ b/SharpEngine.Core/Textures/TextureService.cs @@ -35,16 +35,19 @@ public Texture LoadTexture(string path) if (string.IsNullOrWhiteSpace(path)) throw new FileNotFoundException("No texture file provided."); + if (!File.Exists(path)) + throw new FileNotFoundException($"Texture file not found from path '{path}'."); + // Check if the texture is already in the cache if (_textureCache.TryGetValue(path, out var cachedTexture)) return cachedTexture; // Generate handle uint handle = Window.GL.GenTexture(); + var texture = new Texture(handle, Window.GL); // Bind the handle - Window.GL.ActiveTexture(TextureUnit.Texture0); - Window.GL.BindTexture(TextureTarget.Texture2D, handle); + texture.Use(); // OpenGL has its texture origin in the lower left corner instead of the top left corner, // so we tell StbImageSharp to flip the image when loading. @@ -60,16 +63,12 @@ public Texture LoadTexture(string path) } // Set texture parameters - Window.GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); - Window.GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); - Window.GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat); - Window.GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat); + texture.SetParameters(); // Generate mipmaps Window.GL.GenerateMipmap(GLEnum.Texture2D); - // Create a new texture instance and add it to the cache - var texture = new Texture(handle, Window.GL); + // Add it to the cache _textureCache[path] = texture; return texture; From 803eb9ab1bbb3b4d5b49426e3cb9f093554be1bb Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sun, 13 Apr 2025 17:21:06 +0300 Subject: [PATCH 64/92] #2 Cleanup --- .../Tutorial 4.1 - Model Loading/Program.cs | 9 ++-- .../Properties/Textures/Texture.cs | 14 ++--- .../Properties/Textures/TextureExtensions.cs | 51 ++++++++++++++++++- .../SharpEngine.Core.Components.csproj | 3 ++ SharpEngine.Core/Textures/TextureService.cs | 4 +- 5 files changed, 67 insertions(+), 14 deletions(-) diff --git a/Examples/Tutorial 4.1 - Model Loading/Program.cs b/Examples/Tutorial 4.1 - Model Loading/Program.cs index 08998b9..d7d4766 100644 --- a/Examples/Tutorial 4.1 - Model Loading/Program.cs +++ b/Examples/Tutorial 4.1 - Model Loading/Program.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Numerics; using Shader = SharpEngine.Core.Shaders.Shader; +using Texture = SharpEngine.Core.Components.Properties.Textures.Texture; namespace Tutorial { @@ -18,7 +19,7 @@ class Program private static GL Gl; private static IKeyboard primaryKeyboard; - private static Texture2 Texture; + private static Texture Texture; private static Shader Shader; private static Model Model; @@ -74,7 +75,7 @@ private static void OnLoad() Console.WriteLine($"OpenGL Context Flags: {contextFlags}"); Shader = new Shader(Gl, PathExtensions.GetAssemblyPath("shader.vert"), SharpEngine.Core._Resources.Default.LightShader, "test").Initialize(); - Texture = new Texture2(Gl, "silk.png"); + Texture = new Texture(Gl, "silk.png", Silk.NET.Assimp.TextureType.Diffuse); Model = new Model(Gl, "Untitled2.obj"); } @@ -109,7 +110,7 @@ private static unsafe void OnRender(double deltaTime) Gl.Enable(EnableCap.DepthTest); Gl.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); - Texture.Bind(); + Texture.Use(); Shader.Use(); Shader.SetInt("uTexture0", 0); @@ -127,7 +128,7 @@ private static unsafe void OnRender(double deltaTime) { mesh.Bind(); Shader.Use(); - Texture.Bind(); + Texture.Use(); Shader.SetInt("uTexture0", 0); Shader.SetMatrix4("uModel", model, false); diff --git a/SharpEngine.Core.Components/Properties/Textures/Texture.cs b/SharpEngine.Core.Components/Properties/Textures/Texture.cs index ec4d829..19f28cc 100644 --- a/SharpEngine.Core.Components/Properties/Textures/Texture.cs +++ b/SharpEngine.Core.Components/Properties/Textures/Texture.cs @@ -10,21 +10,21 @@ public partial class Texture : IDisposable { /// The OpenGL handle for the texture. public readonly uint Handle; + public readonly TextureType Type; - public string Path { get; set; } - - public TextureType Type { get; } - + private readonly string Path; private readonly GL _gl; /// /// Initializes a new instance of . /// - /// The handle to the texture. - public Texture(uint glHandle, GL gl) + public Texture(GL gl, string path, TextureType type) { - Handle = glHandle; _gl = gl; + Handle = _gl.GenTexture(); + + Path = path; + Type = type; } public void SetParameters() diff --git a/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs b/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs index 35cc367..e5908b2 100644 --- a/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs +++ b/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs @@ -1,9 +1,58 @@ -using Silk.NET.OpenGL; +using StbImageSharp; +using Silk.NET.OpenGL; namespace SharpEngine.Core.Components.Properties.Textures; public partial class Texture { + private readonly Dictionary _textureCache = []; + /// + /// Loads a texture from the specified path. + /// + /// the full path to the texture. + /// The loaded texture program. + public Texture LoadTexture(string path) + { + if (string.IsNullOrWhiteSpace(path)) + throw new FileNotFoundException("No texture file provided."); + + if (!File.Exists(path)) + throw new FileNotFoundException($"Texture file not found from path '{path}'."); + + // Check if the texture is already in the cache + if (_textureCache.TryGetValue(path, out var cachedTexture)) + return cachedTexture; + + // Generate texture + var texture = new Texture(_gl, path, Silk.NET.Assimp.TextureType.Diffuse); + + // Bind the handle + texture.Use(); + + // OpenGL has its texture origin in the lower left corner instead of the top left corner, + // so we tell StbImageSharp to flip the image when loading. + StbImage.stbi_set_flip_vertically_on_load(1); + + // Here we open a stream to the file and pass it to StbImageSharp to load. + using (Stream stream = File.OpenRead(path)) + { + var image = ImageResult.FromStream(stream, ColorComponents.RedGreenBlueAlpha); + + // Generate a texture + _gl.TexImage2D(TextureTarget.Texture2D, 0, InternalFormat.Rgba, (uint)image.Width, (uint)image.Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, image.Data.AsSpan()); + } + + // Set texture parameters + texture.SetParameters(); + + // Generate mipmaps + _gl.GenerateMipmap(GLEnum.Texture2D); + + // Add it to the cache + _textureCache[path] = texture; + + return texture; + } } diff --git a/SharpEngine.Core.Components/SharpEngine.Core.Components.csproj b/SharpEngine.Core.Components/SharpEngine.Core.Components.csproj index 5943c68..bec75b6 100644 --- a/SharpEngine.Core.Components/SharpEngine.Core.Components.csproj +++ b/SharpEngine.Core.Components/SharpEngine.Core.Components.csproj @@ -15,7 +15,10 @@ + + + diff --git a/SharpEngine.Core/Textures/TextureService.cs b/SharpEngine.Core/Textures/TextureService.cs index 3bacd96..7f07afc 100644 --- a/SharpEngine.Core/Textures/TextureService.cs +++ b/SharpEngine.Core/Textures/TextureService.cs @@ -43,8 +43,8 @@ public Texture LoadTexture(string path) return cachedTexture; // Generate handle - uint handle = Window.GL.GenTexture(); - var texture = new Texture(handle, Window.GL); + // TODO: Determine the type of texture. + var texture = new Texture(Window.GL, path, Silk.NET.Assimp.TextureType.Diffuse); // Bind the handle texture.Use(); From 34a19cfe1962984424e6f2a8ad63fce52ce7a219 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sun, 13 Apr 2025 17:25:05 +0300 Subject: [PATCH 65/92] #2 More cleanup --- .../Properties/Textures/Texture.cs | 29 +++++++++++++++++++ SharpEngine.Core/Textures/TextureService.cs | 23 +-------------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/SharpEngine.Core.Components/Properties/Textures/Texture.cs b/SharpEngine.Core.Components/Properties/Textures/Texture.cs index 19f28cc..2f1404d 100644 --- a/SharpEngine.Core.Components/Properties/Textures/Texture.cs +++ b/SharpEngine.Core.Components/Properties/Textures/Texture.cs @@ -1,5 +1,7 @@ using Silk.NET.Assimp; using Silk.NET.OpenGL; +using StbImageSharp; +using System.IO; namespace SharpEngine.Core.Components.Properties.Textures; @@ -25,6 +27,33 @@ public Texture(GL gl, string path, TextureType type) Path = path; Type = type; + + Initialize(); + } + + public void Initialize() + { + // Bind the handle + Use(); + + // OpenGL has its texture origin in the lower left corner instead of the top left corner, + // so we tell StbImageSharp to flip the image when loading. + StbImage.stbi_set_flip_vertically_on_load(1); + + // Here we open a stream to the file and pass it to StbImageSharp to load. + using (Stream stream = System.IO.File.OpenRead(Path)) + { + var image = ImageResult.FromStream(stream, ColorComponents.RedGreenBlueAlpha); + + // Generate a texture + _gl.TexImage2D(TextureTarget.Texture2D, 0, InternalFormat.Rgba, (uint)image.Width, (uint)image.Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, image.Data.AsSpan()); + } + + // Set texture parameters + SetParameters(); + + // Generate mipmaps + _gl.GenerateMipmap(GLEnum.Texture2D); } public void SetParameters() diff --git a/SharpEngine.Core/Textures/TextureService.cs b/SharpEngine.Core/Textures/TextureService.cs index 7f07afc..6dea240 100644 --- a/SharpEngine.Core/Textures/TextureService.cs +++ b/SharpEngine.Core/Textures/TextureService.cs @@ -45,28 +45,7 @@ public Texture LoadTexture(string path) // Generate handle // TODO: Determine the type of texture. var texture = new Texture(Window.GL, path, Silk.NET.Assimp.TextureType.Diffuse); - - // Bind the handle - texture.Use(); - - // OpenGL has its texture origin in the lower left corner instead of the top left corner, - // so we tell StbImageSharp to flip the image when loading. - StbImage.stbi_set_flip_vertically_on_load(1); - - // Here we open a stream to the file and pass it to StbImageSharp to load. - using (Stream stream = File.OpenRead(path)) - { - var image = ImageResult.FromStream(stream, ColorComponents.RedGreenBlueAlpha); - - // Generate a texture - Window.GL.TexImage2D(TextureTarget.Texture2D, 0, InternalFormat.Rgba, (uint)image.Width, (uint)image.Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, image.Data.AsSpan()); - } - - // Set texture parameters - texture.SetParameters(); - - // Generate mipmaps - Window.GL.GenerateMipmap(GLEnum.Texture2D); + texture.Initialize(); // Add it to the cache _textureCache[path] = texture; From 55a638c6d447239541e9a98c9ba920955c5b1659 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sun, 13 Apr 2025 17:47:48 +0300 Subject: [PATCH 66/92] #2 Get rid of duplicates --- .../Properties/Meshes/Mesh.cs | 8 +- .../Properties/Meshes/Model.cs | 23 +++--- .../Properties/Textures/Texture.cs | 61 +-------------- .../Properties/Textures/Texture2.cs | 78 ------------------- .../Properties/Textures/TextureExtensions.cs | 59 +++++++------- SharpEngine.Core/Textures/TextureService.cs | 5 -- 6 files changed, 49 insertions(+), 185 deletions(-) delete mode 100644 SharpEngine.Core.Components/Properties/Textures/Texture2.cs diff --git a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs index b9c13b6..5d78f82 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs @@ -5,6 +5,8 @@ using Silk.NET.OpenGL; using Tutorial; +using Texture = SharpEngine.Core.Components.Properties.Textures.Texture; + namespace SharpEngine.Core.Entities.Properties.Meshes; /// @@ -46,14 +48,16 @@ public class Mesh : IDisposable public List Groups { get; set; } = []; public List Materials { get; set; }= []; + public IReadOnlyList Textures { get; private set; } + // -------------------------------------------------- - public Mesh(GL gl, float[] vertices, uint[] indices) //, List textures) + public Mesh(GL gl, float[] vertices, uint[] indices, List textures) { GL = gl; Vertices = vertices; Indices = indices; - //Textures = textures; + Textures = textures; SetupMesh(); } diff --git a/SharpEngine.Core.Components/Properties/Meshes/Model.cs b/SharpEngine.Core.Components/Properties/Meshes/Model.cs index 026e1ea..2bf88d3 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/Model.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/Model.cs @@ -1,15 +1,12 @@ // 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.Textures; using Silk.NET.Assimp; using Silk.NET.OpenGL; -using System; -using System.Collections.Generic; -using System.Linq; 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 { @@ -25,7 +22,7 @@ public Model(GL gl, string path, bool gamma = false) private readonly GL _gl; private Assimp _assimp; - private List _texturesLoaded = new List(); + private List _texturesLoaded = new List(); public string Directory { get; protected set; } = string.Empty; public List Meshes { get; protected set; } = new List(); @@ -64,7 +61,7 @@ private unsafe Mesh ProcessMesh(AssimpMesh* mesh, Scene* scene) // data to fill List vertices = new List(); List indices = new List(); - List textures = new List(); + List textures = new List(); // walk through each of the mesh's vertices for (uint i = 0; i < mesh->MNumVertices; i++) @@ -133,14 +130,14 @@ private unsafe Mesh ProcessMesh(AssimpMesh* mesh, Scene* scene) textures.AddRange(heightMaps); // return a mesh object created from the extracted mesh data - var result = new Mesh(_gl, BuildVertices(vertices), BuildIndices(indices)); //, textures); + var result = new Mesh(_gl, BuildVertices(vertices), BuildIndices(indices), textures); return result; } - private unsafe List LoadMaterialTextures(Material* mat, TextureType type, string typeName) + private unsafe List LoadMaterialTextures(Material* mat, TextureType type, string typeName) { var textureCount = _assimp.GetMaterialTextureCount(mat, type); - List textures = new List(); + List textures = new List(); for (uint i = 0; i < textureCount; i++) { AssimpString path; @@ -155,10 +152,10 @@ private unsafe List LoadMaterialTextures(Material* mat, TextureType ty break; } } + if (!skip) { - var texture = new Texture2(_gl, Directory, type); - texture.Path = path; + var texture = new Texture(_gl, path, type); textures.Add(texture); _texturesLoaded.Add(texture); } @@ -183,9 +180,7 @@ private float[] BuildVertices(List vertexCollection) } private uint[] BuildIndices(List indices) - { - return indices.ToArray(); - } + => indices.ToArray(); public void Dispose() { diff --git a/SharpEngine.Core.Components/Properties/Textures/Texture.cs b/SharpEngine.Core.Components/Properties/Textures/Texture.cs index 2f1404d..345e134 100644 --- a/SharpEngine.Core.Components/Properties/Textures/Texture.cs +++ b/SharpEngine.Core.Components/Properties/Textures/Texture.cs @@ -1,7 +1,5 @@ using Silk.NET.Assimp; using Silk.NET.OpenGL; -using StbImageSharp; -using System.IO; namespace SharpEngine.Core.Components.Properties.Textures; @@ -13,8 +11,8 @@ public partial class Texture : IDisposable /// The OpenGL handle for the texture. public readonly uint Handle; public readonly TextureType Type; - - private readonly string Path; + public readonly string Path; + private readonly GL _gl; /// @@ -30,59 +28,4 @@ public Texture(GL gl, string path, TextureType type) Initialize(); } - - public void Initialize() - { - // Bind the handle - Use(); - - // OpenGL has its texture origin in the lower left corner instead of the top left corner, - // so we tell StbImageSharp to flip the image when loading. - StbImage.stbi_set_flip_vertically_on_load(1); - - // Here we open a stream to the file and pass it to StbImageSharp to load. - using (Stream stream = System.IO.File.OpenRead(Path)) - { - var image = ImageResult.FromStream(stream, ColorComponents.RedGreenBlueAlpha); - - // Generate a texture - _gl.TexImage2D(TextureTarget.Texture2D, 0, InternalFormat.Rgba, (uint)image.Width, (uint)image.Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, image.Data.AsSpan()); - } - - // Set texture parameters - SetParameters(); - - // Generate mipmaps - _gl.GenerateMipmap(GLEnum.Texture2D); - } - - 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.GenerateMipmap(TextureTarget.Texture2D); - } - - // Multiple textures can be bound, if your shader needs more than just one. - // If you want to do that, use GL.ActiveTexture to set which slot GL.BindTexture binds to. - // The OpenGL standard requires that there be at least 16, but there can be more depending on your graphics card. - - /// - /// Activate the texture. - /// - /// The bound texture location. - public void Use(TextureUnit unit = TextureUnit.Texture0) - { - _gl.ActiveTexture(unit); - _gl.BindTexture(TextureTarget.Texture2D, Handle); - } - - public void Dispose() - { - _gl.DeleteTexture(Handle); - } } diff --git a/SharpEngine.Core.Components/Properties/Textures/Texture2.cs b/SharpEngine.Core.Components/Properties/Textures/Texture2.cs deleted file mode 100644 index cb3ed72..0000000 --- a/SharpEngine.Core.Components/Properties/Textures/Texture2.cs +++ /dev/null @@ -1,78 +0,0 @@ -using Silk.NET.Assimp; -using Silk.NET.OpenGL; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.PixelFormats; -using System; - -namespace SharpEngine.Core.Components.Properties.Textures -{ - public class Texture2 : IDisposable - { - private uint _handle; - private GL _gl; - - public string Path { get; set; } - public TextureType Type { get; } - - public unsafe Texture2(GL gl, string path, TextureType type = TextureType.None) - { - _gl = gl; - Path = path; - Type = type; - _handle = _gl.GenTexture(); - Bind(); - - using (var img = Image.Load(path)) - { - gl.TexImage2D(TextureTarget.Texture2D, 0, InternalFormat.Rgba8, (uint) img.Width, (uint) img.Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, null); - - img.ProcessPixelRows(accessor => - { - for (int y = 0; y < accessor.Height; y++) - fixed (void* data = accessor.GetRowSpan(y)) - { - gl.TexSubImage2D(TextureTarget.Texture2D, 0, 0, y, (uint) accessor.Width, 1, PixelFormat.Rgba, PixelType.UnsignedByte, data); - } - }); - } - - SetParameters(); - } - - public unsafe Texture2(GL gl, Span data, uint width, uint height) - { - _gl = gl; - - _handle = _gl.GenTexture(); - Bind(); - - fixed (void* d = &data[0]) - { - _gl.TexImage2D(TextureTarget.Texture2D, 0, (int) InternalFormat.Rgba, width, height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, d); - SetParameters(); - } - } - - private 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.GenerateMipmap(TextureTarget.Texture2D); - } - - public void Bind(TextureUnit textureSlot = TextureUnit.Texture0) - { - _gl.ActiveTexture(textureSlot); - _gl.BindTexture(TextureTarget.Texture2D, _handle); - } - - public void Dispose() - { - _gl.DeleteTexture(_handle); - } - } -} diff --git a/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs b/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs index e5908b2..4ab86e3 100644 --- a/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs +++ b/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs @@ -5,37 +5,17 @@ namespace SharpEngine.Core.Components.Properties.Textures; public partial class Texture { - private readonly Dictionary _textureCache = []; - - /// - /// Loads a texture from the specified path. - /// - /// the full path to the texture. - /// The loaded texture program. - public Texture LoadTexture(string path) + public void Initialize() { - if (string.IsNullOrWhiteSpace(path)) - throw new FileNotFoundException("No texture file provided."); - - if (!File.Exists(path)) - throw new FileNotFoundException($"Texture file not found from path '{path}'."); - - // Check if the texture is already in the cache - if (_textureCache.TryGetValue(path, out var cachedTexture)) - return cachedTexture; - - // Generate texture - var texture = new Texture(_gl, path, Silk.NET.Assimp.TextureType.Diffuse); - // Bind the handle - texture.Use(); + Use(); // OpenGL has its texture origin in the lower left corner instead of the top left corner, // so we tell StbImageSharp to flip the image when loading. StbImage.stbi_set_flip_vertically_on_load(1); // Here we open a stream to the file and pass it to StbImageSharp to load. - using (Stream stream = File.OpenRead(path)) + using (Stream stream = File.OpenRead(Path)) { var image = ImageResult.FromStream(stream, ColorComponents.RedGreenBlueAlpha); @@ -44,15 +24,40 @@ public Texture LoadTexture(string path) } // Set texture parameters - texture.SetParameters(); + SetParameters(); // Generate mipmaps _gl.GenerateMipmap(GLEnum.Texture2D); + } - // Add it to the cache - _textureCache[path] = 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.GenerateMipmap(TextureTarget.Texture2D); + } + + // Multiple textures can be bound, if your shader needs more than just one. + // If you want to do that, use GL.ActiveTexture to set which slot GL.BindTexture binds to. + // The OpenGL standard requires that there be at least 16, but there can be more depending on your graphics card. + + /// + /// Activate the texture. + /// + /// The bound texture location. + public void Use(TextureUnit unit = TextureUnit.Texture0) + { + _gl.ActiveTexture(unit); + _gl.BindTexture(TextureTarget.Texture2D, Handle); + } - return texture; + public void Dispose() + { + _gl.DeleteTexture(Handle); } } diff --git a/SharpEngine.Core/Textures/TextureService.cs b/SharpEngine.Core/Textures/TextureService.cs index 6dea240..9da5b3b 100644 --- a/SharpEngine.Core/Textures/TextureService.cs +++ b/SharpEngine.Core/Textures/TextureService.cs @@ -1,12 +1,7 @@ -using StbImageSharp; - using System.IO; using System.Collections.Generic; -using System; -using Silk.NET.OpenGL; using SharpEngine.Core.Windowing; -using SharpEngine.Core.Components.Properties.Textures; using Texture = SharpEngine.Core.Components.Properties.Textures.Texture; namespace SharpEngine.Core.Textures; From 8bd8a3ef1006ab22c37987f5957af645c1671df3 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sun, 13 Apr 2025 21:42:29 +0300 Subject: [PATCH 67/92] #2 Reorganize content --- Examples/MinecraftClone/Minecraft.cs | 6 ++--- Examples/MinecraftClone/Minecraft.csproj | 2 +- ...proj => SharpEngine.Core.ObjLoader.csproj} | 0 ObjLoader/TypeParsers/VertexParser.cs | 6 ++++- .../Properties/Meshes/MeshData/Vertex.cs | 27 ++++++++++--------- .../Properties/Meshes/MeshData/Vertex2.cs | 20 -------------- .../Properties/Meshes/Model.cs | 11 ++++---- SharpEngine.sln | 2 +- Tests/ObjLoader.Test/ObjLoader.Tests.csproj | 2 +- .../TypeParsers/VertexParserTests.cs | 2 +- .../SharpEngine.Shared.Net8}/Class1.cs | 0 .../SharpEngine.Shared.Net8.csproj | 0 12 files changed, 33 insertions(+), 45 deletions(-) rename ObjLoader/{ObjLoader.csproj => SharpEngine.Core.ObjLoader.csproj} (100%) delete mode 100644 SharpEngine.Core.Components/Properties/Meshes/MeshData/Vertex2.cs rename {SharpEngine.Shared.Net8 => Tests/SharpEngine.Shared.Net8}/Class1.cs (100%) rename {SharpEngine.Shared.Net8 => Tests/SharpEngine.Shared.Net8}/SharpEngine.Shared.Net8.csproj (100%) diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index 7224b75..dc63219 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -173,9 +173,9 @@ private void ResolveMeshData(Mesh mesh) { // Resolve vertex positions var position = mesh.Vertices2[vertex.VertexIndex]; - resolvedVertices.Add(position.X); - resolvedVertices.Add(position.Y); - resolvedVertices.Add(position.Z); + resolvedVertices.Add(position.Position.X); + resolvedVertices.Add(position.Position.Y); + resolvedVertices.Add(position.Position.Z); // Resolve normals var normal = mesh.Normals2[vertex.NormalIndex]; diff --git a/Examples/MinecraftClone/Minecraft.csproj b/Examples/MinecraftClone/Minecraft.csproj index 95af1dc..d3d98c6 100644 --- a/Examples/MinecraftClone/Minecraft.csproj +++ b/Examples/MinecraftClone/Minecraft.csproj @@ -6,7 +6,7 @@ - + diff --git a/ObjLoader/ObjLoader.csproj b/ObjLoader/SharpEngine.Core.ObjLoader.csproj similarity index 100% rename from ObjLoader/ObjLoader.csproj rename to ObjLoader/SharpEngine.Core.ObjLoader.csproj diff --git a/ObjLoader/TypeParsers/VertexParser.cs b/ObjLoader/TypeParsers/VertexParser.cs index 81285f2..d6b4fcf 100644 --- a/ObjLoader/TypeParsers/VertexParser.cs +++ b/ObjLoader/TypeParsers/VertexParser.cs @@ -2,6 +2,7 @@ using ObjLoader.TypeParsers; using SharpEngine.Core.Components.Properties.Meshes.MeshData; using System; +using Tutorial; namespace ObjLoader.Loader.TypeParsers { @@ -26,7 +27,10 @@ public override void Parse(string line) float y = parts[1].ParseInvariantFloat(); float z = parts[2].ParseInvariantFloat(); - var vertex = new Vertex(x, y, z); + var vertex = new Vertex() + { + Position = new System.Numerics.Vector3(x, y, z), + }; _dataStore.Vertices.Add(vertex); } } diff --git a/SharpEngine.Core.Components/Properties/Meshes/MeshData/Vertex.cs b/SharpEngine.Core.Components/Properties/Meshes/MeshData/Vertex.cs index 8dd7214..5eb1fda 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/MeshData/Vertex.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/MeshData/Vertex.cs @@ -1,18 +1,21 @@ +// 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 { - // TODO: Use vertex2 instead of this one - public struct Vertex { - public Vertex(float x, float y, float z) : this() - { - X = x; - Y = y; - Z = z; - } + public Vector3 Position; + public Vector3 Normal; + public Vector3 Tangent; + public Vector2 TexCoords; + public Vector3 Bitangent; - public float X { get; private set; } - public float Y { get; private set; } - public float Z { get; private set; } + // TODO: #65 Skeletal mesh + public const int MAX_BONE_INFLUENCE = 4; + public int[] BoneIds; + public float[] Weights; } -} \ No newline at end of file +} diff --git a/SharpEngine.Core.Components/Properties/Meshes/MeshData/Vertex2.cs b/SharpEngine.Core.Components/Properties/Meshes/MeshData/Vertex2.cs deleted file mode 100644 index e69994f..0000000 --- a/SharpEngine.Core.Components/Properties/Meshes/MeshData/Vertex2.cs +++ /dev/null @@ -1,20 +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 Tutorial -{ - public struct Vertex2 - { - public Vector3 Position; - public Vector3 Normal; - public Vector3 Tangent; - public Vector2 TexCoords; - public Vector3 Bitangent; - - public const int MAX_BONE_INFLUENCE = 4; - public int[] BoneIds; - public float[] Weights; - } -} diff --git a/SharpEngine.Core.Components/Properties/Meshes/Model.cs b/SharpEngine.Core.Components/Properties/Meshes/Model.cs index 2bf88d3..32c5a32 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/Model.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/Model.cs @@ -1,6 +1,7 @@ // 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 Silk.NET.Assimp; using Silk.NET.OpenGL; using System.Numerics; @@ -59,16 +60,16 @@ private unsafe void ProcessNode(Node* node, Scene* scene) private unsafe Mesh ProcessMesh(AssimpMesh* mesh, Scene* scene) { // data to fill - List vertices = new List(); + List vertices = new List(); List indices = new List(); List textures = new List(); // walk through each of the mesh's vertices for (uint i = 0; i < mesh->MNumVertices; i++) { - Vertex2 vertex = new Vertex2(); - vertex.BoneIds = new int[Vertex2.MAX_BONE_INFLUENCE]; - vertex.Weights = new float[Vertex2.MAX_BONE_INFLUENCE]; + Vertex vertex = new Vertex(); + vertex.BoneIds = new int[Vertex.MAX_BONE_INFLUENCE]; + vertex.Weights = new float[Vertex.MAX_BONE_INFLUENCE]; vertex.Position = mesh->MVertices[i]; @@ -163,7 +164,7 @@ private unsafe List LoadMaterialTextures(Material* mat, TextureType typ return textures; } - private float[] BuildVertices(List vertexCollection) + private float[] BuildVertices(List vertexCollection) { var vertices = new List(); diff --git a/SharpEngine.sln b/SharpEngine.sln index a8dff04..1d5f3a5 100644 --- a/SharpEngine.sln +++ b/SharpEngine.sln @@ -41,7 +41,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpEngine.Core.Components EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpEngine.Core", "SharpEngine.Core\SharpEngine.Core.csproj", "{52043A27-E9FF-3216-A026-E241F706D49B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ObjLoader", "ObjLoader\ObjLoader.csproj", "{9D23A8B2-C143-B170-10B8-069D9FA119FD}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpEngine.Core.ObjLoader", "ObjLoader\SharpEngine.Core.ObjLoader.csproj", "{9D23A8B2-C143-B170-10B8-069D9FA119FD}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ObjLoader.Tests", "Tests\ObjLoader.Test\ObjLoader.Tests.csproj", "{1807AD4A-C310-4BD8-9542-07D3D3EAE617}" EndProject diff --git a/Tests/ObjLoader.Test/ObjLoader.Tests.csproj b/Tests/ObjLoader.Test/ObjLoader.Tests.csproj index a766284..7725988 100644 --- a/Tests/ObjLoader.Test/ObjLoader.Tests.csproj +++ b/Tests/ObjLoader.Test/ObjLoader.Tests.csproj @@ -13,6 +13,6 @@ - + \ No newline at end of file diff --git a/Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs b/Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs index 432af88..ba27316 100644 --- a/Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs +++ b/Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs @@ -44,7 +44,7 @@ public void Parses_vertex_line_correctly() const string vertexLine = "0.123 0.234 0.345"; _vertexParser.Parse(vertexLine); - var parsedNormal = _vertexDataStoreMock.ParsedVertex; + var parsedNormal = _vertexDataStoreMock.ParsedVertex.Position; parsedNormal.X.Should().BeApproximately(0.123f, 0.000001f); parsedNormal.Y.Should().BeApproximately(0.234f, 0.000001f); parsedNormal.Z.Should().BeApproximately(0.345f, 0.000001f); diff --git a/SharpEngine.Shared.Net8/Class1.cs b/Tests/SharpEngine.Shared.Net8/Class1.cs similarity index 100% rename from SharpEngine.Shared.Net8/Class1.cs rename to Tests/SharpEngine.Shared.Net8/Class1.cs diff --git a/SharpEngine.Shared.Net8/SharpEngine.Shared.Net8.csproj b/Tests/SharpEngine.Shared.Net8/SharpEngine.Shared.Net8.csproj similarity index 100% rename from SharpEngine.Shared.Net8/SharpEngine.Shared.Net8.csproj rename to Tests/SharpEngine.Shared.Net8/SharpEngine.Shared.Net8.csproj From 033421ca74a82c62f9e3a6dba052e368d2199c34 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sun, 13 Apr 2025 23:32:28 +0300 Subject: [PATCH 68/92] #2 Using Core data types (Silk example no longer works) --- Examples/MinecraftClone/Minecraft.cs | 13 +- .../Tutorial 4.1 - Model Loading/Program.cs | 9 +- .../Tutorial 4.1 - Model Loading.csproj | 1 + .../MaterialLibraryLoaderFacade.cs | 9 + ObjLoader/Loaders/ObjLoader/ObjLoader.cs | 20 +- .../Loaders/ObjLoader/ObjLoaderFactory.cs | 7 +- .../Properties/Material.cs | 6 +- .../Properties/Meshes/Mesh.cs | 10 +- .../Properties/Meshes/Model.cs | 178 +++++------------- SharpEngine.Core/Entities/MeshService.cs | 6 +- SharpEngine.Core/Primitives/Cube.cs | 3 +- SharpEngine.Core/Primitives/Plane.cs | 3 +- 12 files changed, 101 insertions(+), 164 deletions(-) diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index dc63219..59abf2c 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -11,6 +11,7 @@ using SharpEngine.Core.Interfaces; using SharpEngine.Core.Scenes; using SharpEngine.Core.Windowing; +using Silk.NET.Core.Native; using Silk.NET.Input; using System; using System.Collections.Generic; @@ -147,12 +148,14 @@ private void InitializeWorld() // TODO: Does not work yet. // var torus = MeshService.Instance.LoadMesh("torus", @"C:\Users\antti\Documents\Untitled2.obj"); - var result = ObjLoaderFactory.Load(@"C:\Users\antti\Documents\Untitled2.obj"); - - ResolveMeshData(result); - var go = new GameObject(); - go.Meshes.Add(result); + var meshes = ObjLoaderFactory.Load(Window.GL, @"C:\Users\antti\Documents\Untitled2.obj"); + + foreach (var mesh in meshes) + { + ResolveMeshData(mesh); + go.Meshes.Add(mesh); + } go.Initialize(); _scene.Root.AddChild(go); diff --git a/Examples/Tutorial 4.1 - Model Loading/Program.cs b/Examples/Tutorial 4.1 - Model Loading/Program.cs index d7d4766..f252394 100644 --- a/Examples/Tutorial 4.1 - Model Loading/Program.cs +++ b/Examples/Tutorial 4.1 - Model Loading/Program.cs @@ -1,3 +1,4 @@ +using ObjLoader.Loaders.ObjLoader; using SharpEngine.Core.Components.Properties.Textures; using SharpEngine.Core.Extensions; using Silk.NET.Input; @@ -5,6 +6,7 @@ using Silk.NET.OpenGL; using Silk.NET.Windowing; using System; +using System.IO; using System.Linq; using System.Numerics; using Shader = SharpEngine.Core.Shaders.Shader; @@ -76,7 +78,9 @@ private static void OnLoad() Shader = new Shader(Gl, PathExtensions.GetAssemblyPath("shader.vert"), SharpEngine.Core._Resources.Default.LightShader, "test").Initialize(); Texture = new Texture(Gl, "silk.png", Silk.NET.Assimp.TextureType.Diffuse); - Model = new Model(Gl, "Untitled2.obj"); + + var meshes = ObjLoaderFactory.Load(Gl, "Untitled2.obj"); + Model = new Model(Gl, "Untitled2.obj", meshes); } private static unsafe void OnUpdate(double deltaTime) @@ -135,7 +139,8 @@ private static unsafe void OnRender(double deltaTime) Shader.SetMatrix4("uView", view, false); Shader.SetMatrix4("uProjection", projection, false); - Gl.DrawArrays(PrimitiveType.Triangles, 0, (uint)mesh.Vertices.Length); + // Gl.DrawArrays(PrimitiveType.Triangles, 0, (uint)mesh.Vertices.Length); + Gl.DrawElements(PrimitiveType.Triangles, (uint)mesh.Indices.Length, DrawElementsType.UnsignedInt, null); } } diff --git a/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 index 7066116..36bab99 100644 --- a/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 @@ -20,6 +20,7 @@ + diff --git a/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoaderFacade.cs b/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoaderFacade.cs index edb433e..f9045de 100644 --- a/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoaderFacade.cs +++ b/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoaderFacade.cs @@ -1,3 +1,6 @@ +using System; +using System.IO; + namespace ObjLoader.Loaders.MaterialLoader { public class MaterialLibraryLoaderFacade : IMaterialLibraryLoaderFacade @@ -11,6 +14,12 @@ public MaterialLibraryLoaderFacade(MaterialLibraryLoader loader) public void Load(string materialFileName) { + if (!File.Exists(materialFileName)) + { + Console.WriteLine($"Material file '{materialFileName}' doesn't exist."); + return; + } + using var stream = _loader.Open(materialFileName); if (stream != null) diff --git a/ObjLoader/Loaders/ObjLoader/ObjLoader.cs b/ObjLoader/Loaders/ObjLoader/ObjLoader.cs index ef83d2e..118edba 100644 --- a/ObjLoader/Loaders/ObjLoader/ObjLoader.cs +++ b/ObjLoader/Loaders/ObjLoader/ObjLoader.cs @@ -1,8 +1,11 @@ using ObjLoader.Loader.Loaders; using ObjLoader.TypeParsers; using SharpEngine.Core.Entities.Properties.Meshes; +using Silk.NET.Core.Contexts; +using Silk.NET.OpenGL; using System.Collections.Generic; using System.IO; +using Tutorial; namespace ObjLoader.Loaders.ObjLoader { @@ -40,18 +43,21 @@ protected override void ParseLine(string keyword, string data) _unrecognizedLines.Add(keyword + " " + data); } - public Mesh Load() + public List Load(GL gl) { var fileStream = new FileStream(_path, FileMode.Open, FileAccess.Read); StartLoad(fileStream); - return new() + return new List() { - Vertices2 = _dataStore.Vertices, - TextureCoordinates2 = _dataStore.Textures, - Normals2 = _dataStore.Normals, - Groups = _dataStore.Groups, - Materials = _dataStore.Materials + new(gl) + { + Vertices2 = _dataStore.Vertices, + TextureCoordinates2 = _dataStore.Textures, + Normals2 = _dataStore.Normals, + Groups = _dataStore.Groups, + Materials = _dataStore.Materials + } }; } } diff --git a/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs b/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs index 6ea2a4b..26682b7 100644 --- a/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs +++ b/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs @@ -1,13 +1,16 @@ using ObjLoader.Loader.TypeParsers; using ObjLoader.Loaders.MaterialLoader; using SharpEngine.Core.Entities.Properties.Meshes; +using Silk.NET.OpenGL; +using System.Collections.Generic; +using Tutorial; namespace ObjLoader.Loaders.ObjLoader { public static class ObjLoaderFactory { /// - public static Mesh Load(string path) + public static List Load(GL gl, string path) { var dataStore = new DataStore(); @@ -22,7 +25,7 @@ public static Mesh Load(string path) var useMaterialParser = new UseMaterialParser(dataStore); var loader = new ObjLoader(path, dataStore).SetupTypeParsers(faceParser, groupParser, normalParser, textureParser, vertexParser, materialLibraryParser, useMaterialParser); - return loader.Load(); + return loader.Load(gl); } } } \ No newline at end of file diff --git a/SharpEngine.Core.Components/Properties/Material.cs b/SharpEngine.Core.Components/Properties/Material.cs index 3b0e8be..b40c9e0 100644 --- a/SharpEngine.Core.Components/Properties/Material.cs +++ b/SharpEngine.Core.Components/Properties/Material.cs @@ -39,11 +39,15 @@ public Material(string materialName) /// public Texture DiffuseMap { get; set; } + public string DiffuseTextureMap { get; set; } + /// /// Gets or sets the specular map texture. /// public Texture SpecularMap { get; set; } + public string SpecularTextureMap { get; set; } + /// Gets whether the material uses a specular map. public bool UseSpecularMap => SpecularMap.Handle != DiffuseMap.Handle; @@ -75,9 +79,7 @@ public Material(string materialName) public int IlluminationModel { get; set; } public string AmbientTextureMap { get; set; } - public string DiffuseTextureMap { get; set; } - public string SpecularTextureMap { get; set; } public string SpecularHighlightTextureMap { get; set; } public string BumpMap { get; set; } diff --git a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs index 5d78f82..7cc25b4 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs @@ -46,9 +46,9 @@ public class Mesh : IDisposable public uint[] Indices { get; set; } = []; public List Groups { get; set; } = []; - public List Materials { get; set; }= []; + public List Materials { get; set; } = []; - public IReadOnlyList Textures { get; private set; } + public IReadOnlyList Textures { get; set; } // -------------------------------------------------- @@ -61,9 +61,10 @@ public Mesh(GL gl, float[] vertices, uint[] indices, List textures) SetupMesh(); } - public Mesh() + public Mesh(GL gl) { - + GL = gl; + SetupMesh(); } public VertexArrayObject VAO { get; set; } @@ -71,7 +72,6 @@ public Mesh() public BufferObject EBO { get; set; } public GL GL { get; } - public unsafe void SetupMesh() { EBO = new BufferObject(GL, Indices, BufferTargetARB.ElementArrayBuffer); diff --git a/SharpEngine.Core.Components/Properties/Meshes/Model.cs b/SharpEngine.Core.Components/Properties/Meshes/Model.cs index 32c5a32..1a79842 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/Model.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/Model.cs @@ -1,11 +1,8 @@ -// 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 Silk.NET.Assimp; using Silk.NET.OpenGL; using System.Numerics; -using AssimpMesh = Silk.NET.Assimp.Mesh; +using System.Linq; using Mesh = SharpEngine.Core.Entities.Properties.Meshes.Mesh; using Texture = SharpEngine.Core.Components.Properties.Textures.Texture; @@ -13,155 +10,70 @@ namespace Tutorial { public class Model : IDisposable { - public Model(GL gl, string path, bool gamma = false) + public readonly string Path; + public List Meshes { get; set; } = new List(); + + private readonly GL _gl; + + public Model(GL gl, string path) { - var assimp = Silk.NET.Assimp.Assimp.GetApi(); - _assimp = assimp; _gl = gl; - LoadModel(path); + Path = path; } - private readonly GL _gl; - private Assimp _assimp; - private List _texturesLoaded = new List(); - public string Directory { get; protected set; } = string.Empty; - public List Meshes { get; protected set; } = new List(); - - private unsafe void LoadModel(string path) + public Model(GL gl, string path, List meshes) { - var scene = _assimp.ImportFile(path, (uint)PostProcessSteps.Triangulate); - - if (scene == null || scene->MFlags == Silk.NET.Assimp.Assimp.SceneFlagsIncomplete || scene->MRootNode == null) - { - var error = _assimp.GetErrorStringS(); - throw new Exception(error); - } - - Directory = path; + _gl = gl; + Path = path; + Meshes = meshes; - ProcessNode(scene->MRootNode, scene); + foreach (var mesh in Meshes) + ProcessMesh(mesh); } - private unsafe void ProcessNode(Node* node, Scene* scene) + public void Dispose() { - for (var i = 0; i < node->MNumMeshes; i++) - { - var mesh = scene->MMeshes[node->MMeshes[i]]; - Meshes.Add(ProcessMesh(mesh, scene)); - - } - - for (var i = 0; i < node->MNumChildren; i++) + foreach (var mesh in Meshes) { - ProcessNode(node->MChildren[i], scene); + mesh.Dispose(); } } - private unsafe Mesh ProcessMesh(AssimpMesh* mesh, Scene* scene) + public Mesh ProcessMesh(Mesh mesh) { // data to fill - List vertices = new List(); - List indices = new List(); - List textures = new List(); - - // walk through each of the mesh's vertices - for (uint i = 0; i < mesh->MNumVertices; i++) + for (int i = 0; i < mesh.Vertices2.Count; i++) { - Vertex vertex = new Vertex(); + var vertex = mesh.Vertices2[i]; vertex.BoneIds = new int[Vertex.MAX_BONE_INFLUENCE]; vertex.Weights = new float[Vertex.MAX_BONE_INFLUENCE]; - - vertex.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). - Vector3 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++) + List indices = new List(); + foreach (var group in mesh.Groups) { - Face 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]); + foreach (var face in group.Faces) + { + indices.AddRange(face._vertices.Select(v => (uint)v.VertexIndex)); + } } - // process materials - Material* 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, "texture_diffuse"); - if (diffuseMaps.Any()) - textures.AddRange(diffuseMaps); - // 2. specular maps - var specularMaps = LoadMaterialTextures(material, TextureType.Specular, "texture_specular"); - if (specularMaps.Any()) - textures.AddRange(specularMaps); - // 3. normal maps - var normalMaps = LoadMaterialTextures(material, TextureType.Height, "texture_normal"); - if (normalMaps.Any()) - textures.AddRange(normalMaps); - // 4. height maps - var heightMaps = LoadMaterialTextures(material, TextureType.Ambient, "texture_height"); - 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, string typeName) - { - var textureCount = _assimp.GetMaterialTextureCount(mat, type); List textures = new List(); - for (uint i = 0; i < textureCount; i++) + foreach (var material in mesh.Materials) { - 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 (material.DiffuseMap != null) + textures.Add(material.DiffuseMap); - if (!skip) - { - var texture = new Texture(_gl, path, type); - textures.Add(texture); - _texturesLoaded.Add(texture); - } + if (material.UseSpecularMap && material.SpecularMap != null) + textures.Add(material.SpecularMap); } - return textures; + + // 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) @@ -173,6 +85,10 @@ private float[] BuildVertices(List 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); } @@ -182,15 +98,5 @@ private float[] BuildVertices(List vertexCollection) private uint[] BuildIndices(List indices) => indices.ToArray(); - - public void Dispose() - { - foreach (var mesh in Meshes) - { - mesh.Dispose(); - } - - _texturesLoaded = null; - } } } diff --git a/SharpEngine.Core/Entities/MeshService.cs b/SharpEngine.Core/Entities/MeshService.cs index 1ef1c98..99a405f 100644 --- a/SharpEngine.Core/Entities/MeshService.cs +++ b/SharpEngine.Core/Entities/MeshService.cs @@ -43,7 +43,7 @@ public Mesh LoadMesh(string identifier, Mesh mesh) const string FbxExtension = ".fbx"; const string ObjExtension = ".obj"; - /// + /*/// /// Loads a mesh based on the file extension of the provided path. /// /// Used to specify the unique identifier for the mesh being loaded. @@ -68,7 +68,7 @@ private IEnumerable LoadObj(string identifier, string meshFilePath) Mesh LoadMeshIntoBuffer() { - var mesh = LoadMesh(identifier, new Mesh + var mesh = LoadMesh(identifier, new Mesh() { Vertices = [.. vertices], Normals = [.. normals], @@ -127,7 +127,7 @@ Mesh LoadMeshIntoBuffer() if (vertices.Count > 0) yield return LoadMeshIntoBuffer(); - } + }*/ // TODO: #3 Load fbx mesh from file private IEnumerable LoadFbx(string identifier, string meshFilePath) diff --git a/SharpEngine.Core/Primitives/Cube.cs b/SharpEngine.Core/Primitives/Cube.cs index 7a82896..9362991 100644 --- a/SharpEngine.Core/Primitives/Cube.cs +++ b/SharpEngine.Core/Primitives/Cube.cs @@ -1,4 +1,5 @@ using SharpEngine.Core.Entities.Properties.Meshes; +using SharpEngine.Core.Windowing; namespace SharpEngine.Core.Primitives; @@ -8,7 +9,7 @@ namespace SharpEngine.Core.Primitives; public static class Cube { /// The cube mesh. - public static readonly Mesh Mesh = new() + public static readonly Mesh Mesh = new(Window.GL) { Vertices = [ diff --git a/SharpEngine.Core/Primitives/Plane.cs b/SharpEngine.Core/Primitives/Plane.cs index b7c6911..ba046a5 100644 --- a/SharpEngine.Core/Primitives/Plane.cs +++ b/SharpEngine.Core/Primitives/Plane.cs @@ -1,4 +1,5 @@ using SharpEngine.Core.Entities.Properties.Meshes; +using SharpEngine.Core.Windowing; namespace SharpEngine.Core.Primitives; @@ -8,7 +9,7 @@ namespace SharpEngine.Core.Primitives; public static class Plane { /// The plane mesh. - public static Mesh Mesh { get; } = new() + public static Mesh Mesh { get; } = new(Window.GL) { Vertices = [ From 4b4e50630b867a355b067faa1a645ef1d32b0254 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Mon, 14 Apr 2025 00:00:13 +0300 Subject: [PATCH 69/92] #2 Intermediate state Both test projects work but the Model_Old is still required. --- .../Tutorial 4.1 - Model Loading/Program.cs | 13 +- .../Properties/Meshes/Mesh.cs | 16 +- .../Properties/Meshes/Model_Old.cs | 200 ++++++++++++++++++ 3 files changed, 221 insertions(+), 8 deletions(-) create mode 100644 SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs diff --git a/Examples/Tutorial 4.1 - Model Loading/Program.cs b/Examples/Tutorial 4.1 - Model Loading/Program.cs index f252394..d9fa05e 100644 --- a/Examples/Tutorial 4.1 - Model Loading/Program.cs +++ b/Examples/Tutorial 4.1 - Model Loading/Program.cs @@ -23,7 +23,8 @@ class Program private static Texture Texture; private static Shader Shader; - private static Model Model; + private static Model_Old Model; + // private static Model Model; //Setup the camera's location, directions, and movement speed private static Vector3 CameraPosition = new Vector3(0.0f, 0.0f, 3.0f); @@ -79,8 +80,10 @@ private static void OnLoad() Shader = new Shader(Gl, PathExtensions.GetAssemblyPath("shader.vert"), SharpEngine.Core._Resources.Default.LightShader, "test").Initialize(); Texture = new Texture(Gl, "silk.png", Silk.NET.Assimp.TextureType.Diffuse); - var meshes = ObjLoaderFactory.Load(Gl, "Untitled2.obj"); - Model = new Model(Gl, "Untitled2.obj", meshes); + // var meshes = ObjLoaderFactory.Load(Gl, "Untitled2.obj"); + // Model = new Model(Gl, "Untitled2.obj", meshes); + + Model = new Model_Old(Gl, "Untitled2.obj"); } private static unsafe void OnUpdate(double deltaTime) @@ -139,8 +142,8 @@ private static unsafe void OnRender(double deltaTime) Shader.SetMatrix4("uView", view, false); Shader.SetMatrix4("uProjection", projection, false); - // Gl.DrawArrays(PrimitiveType.Triangles, 0, (uint)mesh.Vertices.Length); - Gl.DrawElements(PrimitiveType.Triangles, (uint)mesh.Indices.Length, DrawElementsType.UnsignedInt, null); + Gl.DrawArrays(PrimitiveType.Triangles, 0, (uint)mesh.Vertices.Length); + // Gl.DrawElements(PrimitiveType.Triangles, (uint)mesh.Indices.Length, DrawElementsType.UnsignedInt, null); } } diff --git a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs index 7cc25b4..cc0918b 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs @@ -5,7 +5,7 @@ using Silk.NET.OpenGL; using Tutorial; -using Texture = SharpEngine.Core.Components.Properties.Textures.Texture; +using Texture2 = SharpEngine.Core.Components.Properties.Textures.Texture; namespace SharpEngine.Core.Entities.Properties.Meshes; @@ -48,11 +48,12 @@ public class Mesh : IDisposable public List Groups { get; set; } = []; public List Materials { get; set; } = []; - public IReadOnlyList Textures { get; set; } + public IReadOnlyList Textures { get; set; } + public IReadOnlyList Textures_Old { get; set; } // -------------------------------------------------- - public Mesh(GL gl, float[] vertices, uint[] indices, List textures) + public Mesh(GL gl, float[] vertices, uint[] indices, List textures) { GL = gl; Vertices = vertices; @@ -61,6 +62,15 @@ public Mesh(GL gl, float[] vertices, uint[] indices, List textures) SetupMesh(); } + public Mesh(GL gl, float[] vertices, uint[] indices, List textures) + { + GL = gl; + Vertices = vertices; + Indices = indices; + Textures_Old = textures; + SetupMesh(); + } + public Mesh(GL gl) { GL = gl; diff --git a/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs b/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs new file mode 100644 index 0000000..9639539 --- /dev/null +++ b/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs @@ -0,0 +1,200 @@ +// 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 Silk.NET.Assimp; +using Silk.NET.OpenGL; +using System; +using System.Collections.Generic; +using System.Linq; +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 +{ + public class Model_Old : IDisposable + { + public Model_Old(GL gl, string path, bool gamma = false) + { + var assimp = Silk.NET.Assimp.Assimp.GetApi(); + _assimp = assimp; + _gl = gl; + LoadModel(path); + } + + private readonly GL _gl; + private Assimp _assimp; + private List _texturesLoaded = new List(); + public string Directory { get; protected set; } = string.Empty; + public List Meshes { get; protected set; } = new List(); + + private unsafe void LoadModel(string path) + { + var scene = _assimp.ImportFile(path, (uint)PostProcessSteps.Triangulate); + + if (scene == null || scene->MFlags == Silk.NET.Assimp.Assimp.SceneFlagsIncomplete || scene->MRootNode == null) + { + var error = _assimp.GetErrorStringS(); + throw new Exception(error); + } + + Directory = path; + + ProcessNode(scene->MRootNode, scene); + } + + private unsafe void ProcessNode(Node* node, Scene* scene) + { + for (var i = 0; i < node->MNumMeshes; i++) + { + var mesh = scene->MMeshes[node->MMeshes[i]]; + Meshes.Add(ProcessMesh(mesh, scene)); + + } + + for (var i = 0; i < node->MNumChildren; i++) + { + ProcessNode(node->MChildren[i], scene); + } + } + + private unsafe Mesh ProcessMesh(AssimpMesh* mesh, Scene* scene) + { + // data to fill + List vertices = new List(); + List indices = new List(); + List textures = new List(); + + // walk through each of the mesh's vertices + for (uint i = 0; i < mesh->MNumVertices; i++) + { + Vertex vertex = new Vertex(); + vertex.BoneIds = new int[Vertex.MAX_BONE_INFLUENCE]; + vertex.Weights = new float[Vertex.MAX_BONE_INFLUENCE]; + + vertex.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). + Vector3 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++) + { + Face 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 + Material* 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, "texture_diffuse"); + if (diffuseMaps.Any()) + textures.AddRange(diffuseMaps); + // 2. specular maps + var specularMaps = LoadMaterialTextures(material, TextureType.Specular, "texture_specular"); + if (specularMaps.Any()) + textures.AddRange(specularMaps); + // 3. normal maps + var normalMaps = LoadMaterialTextures(material, TextureType.Height, "texture_normal"); + if (normalMaps.Any()) + textures.AddRange(normalMaps); + // 4. height maps + var heightMaps = LoadMaterialTextures(material, TextureType.Ambient, "texture_height"); + 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, string typeName) + { + var textureCount = _assimp.GetMaterialTextureCount(mat, type); + List textures = new List(); + 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 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.TexCoords.X); + vertices.Add(vertex.TexCoords.Y); + } + + return vertices.ToArray(); + } + + private uint[] BuildIndices(List indices) + { + return indices.ToArray(); + } + + public void Dispose() + { + foreach (var mesh in Meshes) + { + mesh.Dispose(); + } + + _texturesLoaded = null; + } + } +} \ No newline at end of file From d541d659fdbdfda93d86cda12b03c4f538c21ec8 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Thu, 17 Apr 2025 21:23:44 +0300 Subject: [PATCH 70/92] #73 Document issues --- Editor/EditorWindow.cs | 16 +++++++------- Editor/Program.cs | 1 - Editor/Windows/ActionsMenuWindow.cs | 4 ++-- Editor/Windows/AssetsWindow.cs | 2 +- Editor/Windows/ImGuiWindowBase.cs | 3 +-- Examples/MinecraftClone/Block/Stone.cs | 4 ++-- Examples/MinecraftClone/Inventory.cs | 4 ++-- Examples/MinecraftClone/Minecraft.cs | 14 ++++++------ Examples/MinecraftClone/Program.cs | 2 +- .../MaterialLoader/MaterialLibraryLoader.cs | 2 +- SharpEngine.Core/Abstractions/IRenderable.cs | 2 +- SharpEngine.Core/Entities/GameObject.cs | 4 ++-- .../Entities/UI/Layouts/GridLayout.cs | 2 +- SharpEngine.Core/Entities/UI/UIElement.cs | 4 ++-- SharpEngine.Core/Entities/Views/CameraView.cs | 2 +- SharpEngine.Core/Renderers/Renderer.cs | 12 +++++----- SharpEngine.Core/Scenes/Scene.cs | 2 +- SharpEngine.Core/Shaders/ShaderService.cs | 1 - SharpEngine.Core/Windowing/SilkWindow.cs | 2 ++ SharpEngine.Core/Windowing/Window.cs | 22 +++++++------------ 20 files changed, 49 insertions(+), 56 deletions(-) diff --git a/Editor/EditorWindow.cs b/Editor/EditorWindow.cs index 4746b74..bcc7b9c 100644 --- a/Editor/EditorWindow.cs +++ b/Editor/EditorWindow.cs @@ -129,7 +129,7 @@ protected override void AfterRender(Frame frame) private void Save() { - // TODO: Save all changes. + // TODO: #84 Save all changes. } private static void EnableDocking() @@ -173,7 +173,7 @@ private void RenderMenuBar() { // Handle New action - // TODO: Select preferred editor + // TODO: #76 Select preferred editor // Required fields: // radio button, each defined editor (store as json) // textbox,Path to executable @@ -204,12 +204,12 @@ private void RenderFileMenu() { if (ImGui.MenuItem("New")) { - // TODO: Handle New action + // TODO: #83 Handle New action } if (ImGui.MenuItem("Open")) { - // TODO: Handle Open action + // TODO: #82 Handle Open action } if (ImGui.MenuItem("Save")) @@ -217,12 +217,12 @@ private void RenderFileMenu() if (ImGui.MenuItem("Exit")) { - // TODO: Handle Exit action + // TODO: #81 Handle Exit action } if (ImGui.MenuItem("Publish")) { - // TODO: Handle Publish action + // TODO: #80 Handle Publish action } ImGui.EndMenu(); @@ -236,7 +236,7 @@ public override void OnMouseClick(IMouse mouse, MouseButton button, Vector2 vect if (button == Settings.PrimaryButton) { - // TODO: This probably isn't doable using ImGui. Figure out a new way or wait until UI is written using the Core 2D renderer. + // TODO: #79 This probably isn't doable using ImGui. Figure out a new way or wait until UI is written using the Core 2D renderer. if (ImGui.IsItemClicked((ImGuiMouseButton)button)) { // Clicked on an ImGui component @@ -252,7 +252,7 @@ public override void OnMouseClick(IMouse mouse, MouseButton button, Vector2 vect if (button == Settings.SecondaryButton) { - // TODO: Make this work. + // TODO: #79 Make this work. if (ImGui.IsItemClicked((ImGuiMouseButton)button)) { // Clicked on an ImGui component diff --git a/Editor/Program.cs b/Editor/Program.cs index e899d16..b1f251f 100644 --- a/Editor/Program.cs +++ b/Editor/Program.cs @@ -41,7 +41,6 @@ public static void Main(string[] args) var scene = !string.IsNullOrEmpty(sceneFile) ? Scene.LoadScene(sceneFile) : new Scene(); var project = !string.IsNullOrEmpty(projectFile) ? Project.LoadProject(projectFile) #if DEBUG - // TODO: We should create an additional getter for the .sharpproject file. : new Project() { Path = Path.Combine(Directory.GetCurrentDirectory(), @"..\..\..\..\Examples\Minimal"), Name = "Minimal" }; #else : new Project(); diff --git a/Editor/Windows/ActionsMenuWindow.cs b/Editor/Windows/ActionsMenuWindow.cs index a0e356e..9401c6a 100644 --- a/Editor/Windows/ActionsMenuWindow.cs +++ b/Editor/Windows/ActionsMenuWindow.cs @@ -65,10 +65,10 @@ private void StartGame() { if (Project is null) { - // TODO: This should never be possible. If the Project is null when it's loaded we should make sure it's initialized. + // TODO: #78 This should never be possible. If the Project is null when it's loaded we should make sure it's initialized. // Editor service probably needs to be made shared so that we can initialize the project / solution when the editor is opened. - // TODO: Do we want to save here automatically or prompt the user to save? + // TODO: #77 Save automatically Debug.LogInformation("The project was null"); return; } diff --git a/Editor/Windows/AssetsWindow.cs b/Editor/Windows/AssetsWindow.cs index 9f6f531..f3c79ba 100644 --- a/Editor/Windows/AssetsWindow.cs +++ b/Editor/Windows/AssetsWindow.cs @@ -32,7 +32,7 @@ private static void RenderDirectory(string path) foreach (var file in files) if (ImGui.Selectable(Path.GetFileName(file))) { - // TODO: Open the file in the IDE + // TODO: #76 Open the file in the IDE // Process.Start(Settings.PreferredIDE.Name + Settings.PreferredIDE.CLIArguments + file); // Scene.ActiveElement = file; // Set the file as the active element diff --git a/Editor/Windows/ImGuiWindowBase.cs b/Editor/Windows/ImGuiWindowBase.cs index 5fabc93..2bc647e 100644 --- a/Editor/Windows/ImGuiWindowBase.cs +++ b/Editor/Windows/ImGuiWindowBase.cs @@ -89,8 +89,7 @@ protected virtual void OnWindowUndocked() { Console.WriteLine($"Window {Name} was undocked."); - // TODO: This method of doing this does not work (at least in .Net 8). - // See issue #44 for more information. + // TODO: #75 This method of doing this does not work (at least in .Net 8). //CreateSilkWindow(); } diff --git a/Examples/MinecraftClone/Block/Stone.cs b/Examples/MinecraftClone/Block/Stone.cs index d54faf9..13352d3 100644 --- a/Examples/MinecraftClone/Block/Stone.cs +++ b/Examples/MinecraftClone/Block/Stone.cs @@ -6,8 +6,8 @@ namespace Minecraft.Block; internal class Stone : BlockBase { - // TODO: Create record for textures files for less parameters - // TODO: Create const files for these file strings + // TODO: #91 Create record for textures files for less parameters + // TODO: #91 Create const files for these file strings /// /// Initializes a new block. diff --git a/Examples/MinecraftClone/Inventory.cs b/Examples/MinecraftClone/Inventory.cs index 7379b8f..ed8b7eb 100644 --- a/Examples/MinecraftClone/Inventory.cs +++ b/Examples/MinecraftClone/Inventory.cs @@ -14,13 +14,13 @@ public class Inventory /// Gets or sets the selected slot. public ToolbarSlot SelectedSlot { get; set; } = new(1); - // TODO: After first version + // TODO: #90 After first version // public List Items { get; set; } = new(); /// Gets or sets the toolbar slots. public ToolbarSlot[] Toolbar { get; set; } = new ToolbarSlot[10]; - // TODO: Use later to optimize inventory logic + // TODO: #90 Use later to optimize inventory logic // private bool _toolbarSlotsAvailable; /// diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index 59abf2c..c118839 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -69,7 +69,7 @@ public override void Initialize() var gridLayout = new GridLayout(); - // TODO: Fix UI renderer + // TODO: #89 Fix UI renderer _uiElem = new UIElement("uiElement"); _scene.UIElements.Add(_uiElem); @@ -145,7 +145,7 @@ private void InitializeWorld() InitializeLights(); InitializeChunks(); - // TODO: Does not work yet. + // TODO: #2 Does not work yet. // var torus = MeshService.Instance.LoadMesh("torus", @"C:\Users\antti\Documents\Untitled2.obj"); var go = new GameObject(); @@ -221,9 +221,9 @@ private void InitializeLights() private void InitializeChunks() { - // TODO: Generate chunks when player moves + // TODO: #88 Generate chunks when player moves - // TODO: Generate chunks using 3d Perlin noise + // TODO: #87 Generate chunks using 3d Perlin noise const int chunkSize = 16; const int numChunks = 3; @@ -266,7 +266,7 @@ public override void Update(double deltaTime, IInputContext input) private void UpdateUI() => _uiElem.Transform.Rotation.Angle += 0.01f; - // TODO: Input system to let users change change key bindings? + // TODO: #21 Input system to let users change change key bindings? /// public override void HandleKeyboard(IKeyboard input, double deltaTime) { @@ -322,8 +322,8 @@ public override void HandleMouseDown(IMouse mouse, MouseButton button) var destroyedBlockType = DestroyBlock(); if (destroyedBlockType != BlockType.None) { - // TODO: The block should be added to the slot so that 0 is the last slot instead of 9. - // TODO: The first block destroyed doesn't seem to be added to the inventory. + // 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. Console.WriteLine($"Block destroyed: {destroyedBlockType}."); _inventory.AddToolbarItem(destroyedBlockType); } diff --git a/Examples/MinecraftClone/Program.cs b/Examples/MinecraftClone/Program.cs index bf3e6a3..727a8f4 100644 --- a/Examples/MinecraftClone/Program.cs +++ b/Examples/MinecraftClone/Program.cs @@ -28,7 +28,7 @@ private static void Main() window.HandleMouseWheel += game.HandleMouseWheel; window.OnAfterRender += frame => game.OnAfterRender(frame); - // TODO: This needs to be streamlined. + // TODO: #85 This needs to be streamlined. game.Window = window; window.Run(); diff --git a/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoader.cs b/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoader.cs index e6cd967..90ebb1b 100644 --- a/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoader.cs +++ b/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoader.cs @@ -20,7 +20,7 @@ public class MaterialLibraryLoader : LoaderBase private Material CurrentMaterial { get; set; } - // TODO: See Model class. This support both materials and textures + // TODO: #2 See Model class. This support both materials and textures public MaterialLibraryLoader(string objPath, DataStore dataStore) { diff --git a/SharpEngine.Core/Abstractions/IRenderable.cs b/SharpEngine.Core/Abstractions/IRenderable.cs index 6b00f6f..f3f4216 100644 --- a/SharpEngine.Core/Abstractions/IRenderable.cs +++ b/SharpEngine.Core/Abstractions/IRenderable.cs @@ -2,7 +2,7 @@ namespace SharpEngine.Core.Interfaces; -// TODO: Make an abstract class and move Render method here? +// TODO: #55 Make an abstract class and move Render method here? /// /// Contains definitions for rendering objects. diff --git a/SharpEngine.Core/Entities/GameObject.cs b/SharpEngine.Core/Entities/GameObject.cs index 3866a36..36b359f 100644 --- a/SharpEngine.Core/Entities/GameObject.cs +++ b/SharpEngine.Core/Entities/GameObject.cs @@ -27,7 +27,7 @@ public class GameObject : EmptyNode, IRenderable /// public GameObject() : base(string.Empty) { - // TODO: Using lightning shader here will most likely break stuff, it needs to be refactored out. + // TODO: #5 Using lightning shader here will most likely break stuff, it needs to be refactored out. var shader = ShaderService.Instance.LoadShader(_Resources.Default.VertexShader, _Resources.Default.FragmentShader, "lighting"); var diffuse = TextureService.Instance.LoadTexture(_Resources.Default.DebugTexture); Material = new(shader, diffuse); @@ -57,7 +57,7 @@ public GameObject(string? diffuseMapFile = null, string? specularMapFile = null, /// public List Meshes { get; set; } = []; - // TODO: Each mesh should have its own material. + // TODO: #5 Each mesh should have its own material. /// /// Gets or sets the material of the game object. /// diff --git a/SharpEngine.Core/Entities/UI/Layouts/GridLayout.cs b/SharpEngine.Core/Entities/UI/Layouts/GridLayout.cs index 993a73c..452cc3e 100644 --- a/SharpEngine.Core/Entities/UI/Layouts/GridLayout.cs +++ b/SharpEngine.Core/Entities/UI/Layouts/GridLayout.cs @@ -42,7 +42,7 @@ public override void AddItem(TItem item) { base.AddItem(item); - var offset = -100; // TODO: Fix this, this is just a temporary solution. + var offset = -100; // TODO: #26 Fix this, this is just a temporary solution. if (Items.Count % Columns != 0) offset = offset + (Items.Count * 30); diff --git a/SharpEngine.Core/Entities/UI/UIElement.cs b/SharpEngine.Core/Entities/UI/UIElement.cs index 068a40f..024d888 100644 --- a/SharpEngine.Core/Entities/UI/UIElement.cs +++ b/SharpEngine.Core/Entities/UI/UIElement.cs @@ -29,7 +29,7 @@ public UIElement() : this("UIElement") { } /// The name of the UI element. public UIElement(string name) : base(name) { - // TODO: Support custom meshes? + // TODO: #5 Support custom meshes? Mesh = MeshService.Instance.LoadMesh(nameof(Primitives.Plane), Primitives.Plane.Mesh); Initialize(); @@ -91,7 +91,7 @@ public override Task Render(CameraView camera, Window window) Bind(); - // TODO: These should come from somewhere else. + // TODO: #75 These should come from somewhere else. const float screenWidth = 1280; const float screenHeight = 720; diff --git a/SharpEngine.Core/Entities/Views/CameraView.cs b/SharpEngine.Core/Entities/Views/CameraView.cs index 9a88a2d..c144c85 100644 --- a/SharpEngine.Core/Entities/Views/CameraView.cs +++ b/SharpEngine.Core/Entities/Views/CameraView.cs @@ -134,7 +134,7 @@ public override void UpdateMousePosition(Vector2 mousePosition) lastPos = new Vector2(mousePosition.X, mousePosition.Y); firstMove = false; } - else // TODO: Split so that only the camera view will rotate + else // TODO: #48 Split so that only the camera view will rotate { var deltaX = mousePosition.X - lastPos.X; var deltaY = mousePosition.Y - lastPos.Y; diff --git a/SharpEngine.Core/Renderers/Renderer.cs b/SharpEngine.Core/Renderers/Renderer.cs index 92efdc2..58846dc 100644 --- a/SharpEngine.Core/Renderers/Renderer.cs +++ b/SharpEngine.Core/Renderers/Renderer.cs @@ -25,12 +25,12 @@ public class Renderer : RendererBase private readonly Scene _scene; private readonly Window _window; - // TODO: Property for specific type of objects + // TODO: #7 Property for specific type of objects // No heavy iteration reads for filtering, // instead use a notification system from the scene that an item has been removed / added? // Read only once, load into OpenGL buffer once. - // TODO: Multiple meshes + // TODO: #5 Multiple meshes /// public override RenderFlags RenderFlag => RenderFlags.Renderer3D; @@ -48,7 +48,7 @@ public Renderer(CameraView camera, Window window, ISettings settings, Scene scen _scene = scene; _window = window; - // TODO: These should be refactored out. The minimum build shouldn't need to use these. + // TODO: #5 These should be refactored out. The minimum build shouldn't need to use these. _lightingShader = new LightingShader(); _lampShader = new LampShader(); } @@ -62,7 +62,7 @@ public override Task Render() Window.GL.Enable(EnableCap.DepthTest); // Enable image transparency. - // TODO: Needs testing. + // TODO: #62 Needs testing. Window.GL.Enable(EnableCap.Blend); Window.GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); @@ -88,12 +88,12 @@ private Task RenderGameObject(SceneNode node) if (node is not GameObject gameObject) return Task.CompletedTask; - // TODO: Fix culling for blocks that are partially in view + // TODO: #7 Fix culling for blocks that are partially in view // Perform frustum culling if (!IsInViewFrustum(gameObject.BoundingBox, _camera)) return Task.CompletedTask; - // TODO: Skip blocks that are behind others relative to the camera + // TODO: #7 Skip blocks that are behind others relative to the camera return gameObject.Render(_camera, _window); } diff --git a/SharpEngine.Core/Scenes/Scene.cs b/SharpEngine.Core/Scenes/Scene.cs index 6e4706f..6d84857 100644 --- a/SharpEngine.Core/Scenes/Scene.cs +++ b/SharpEngine.Core/Scenes/Scene.cs @@ -111,7 +111,7 @@ public virtual void RemoveNode(SceneNode node) /// All the game objects in the current scene. public List GetObjectsOfType(SceneNode? root = null) { - // TODO: Can we make this async? + // TODO: #94 Can we make this async? var result = new List(); static void FindsObjects(SceneNode node, List result) { diff --git a/SharpEngine.Core/Shaders/ShaderService.cs b/SharpEngine.Core/Shaders/ShaderService.cs index ad25acb..bc9f802 100644 --- a/SharpEngine.Core/Shaders/ShaderService.cs +++ b/SharpEngine.Core/Shaders/ShaderService.cs @@ -15,7 +15,6 @@ public class ShaderService /// public static ShaderService Instance { get; } = new ShaderService(); - // TODO: Cache data is never set private readonly Dictionary _shaderCache = []; /// diff --git a/SharpEngine.Core/Windowing/SilkWindow.cs b/SharpEngine.Core/Windowing/SilkWindow.cs index 3cae2f5..4301fa0 100644 --- a/SharpEngine.Core/Windowing/SilkWindow.cs +++ b/SharpEngine.Core/Windowing/SilkWindow.cs @@ -159,6 +159,8 @@ public bool VSync set => CurrentWindow.ShouldSwapAutomatically = value; } + public bool IsFocused { get; } + /// public VideoMode VideoMode => CurrentWindow.VideoMode; diff --git a/SharpEngine.Core/Windowing/Window.cs b/SharpEngine.Core/Windowing/Window.cs index efc052d..7a508da 100644 --- a/SharpEngine.Core/Windowing/Window.cs +++ b/SharpEngine.Core/Windowing/Window.cs @@ -20,6 +20,7 @@ using System.Numerics; using System.Threading.Tasks; using Shader = SharpEngine.Core.Shaders.Shader; +using Silk.NET.GLFW; namespace SharpEngine.Core.Windowing; @@ -65,7 +66,7 @@ public class Window : SilkWindow /// The OpenGL context. public static GL GL; - // TODO: Use this method. + // TODO: #93 Use this method. /// /// Gets the current OpenGL context. /// @@ -147,9 +148,6 @@ public override void OnLoad() GL.ClearColor(0.2f, 0.3f, 0.3f, 1.0f); - // TODO: Set cursor shape - // CursorShape = CursorShape.Hand; - // Load all meshes from the mesh cache MeshService.Instance.LoadMesh("cube", Primitives.Cube.Mesh); @@ -161,7 +159,7 @@ public override void OnLoad() foreach (var type in rendererTypes) { // Make sure the renderer has the correct constructor parameters! - // TODO: The static reference to the context will not work when multiple windows are implemented, since the context will be different. + // 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)!; @@ -212,9 +210,6 @@ protected void RenderFrame(Frame frame) Task.WaitAll([.. renderTasks]); - // TODO: This call causes flickering in the new framework. Investigate why. - // _window.SwapBuffers(); - AfterRender(frame); _imGuiController?.Render(); @@ -250,14 +245,10 @@ protected void OnUpdateFrame(Frame frame) // Wait for the window to be initialized. } - // TODO: GLFW_ISFOCUSED - // if (!_window.IsFocused) - // return; - if (Settings.PrintFrameRate) Console.WriteLine($"FPS: {frame.FrameRate}"); - // TODO: Handle multiple mice? + // TODO: #21 Handle multiple mice? var mouse = Input?.Mice[0]; if (mouse is not null) { @@ -295,6 +286,9 @@ private void AssignInputEvents() mouse.Scroll += OnMouseWheel; mouse.Click += OnMouseClick; mouse.MouseDown += OnMouseDown; + + if (IsFocused) + mouse.Cursor.CursorMode = CursorMode.Raw; } } @@ -338,7 +332,7 @@ protected override void OnMouseDown(IMouse mouse, MouseButton button) /// The contents of the new scene. protected void SetScene(Scene scene) { - // TODO: Do we need to clear anything from e.g. the GPU when we change change the scene? + // TODO: #92 Do we need to clear anything from e.g. the GPU when we change change the scene? Scene = scene; } } From 1e078ad521211b36a82e3a86e406719229988793 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Thu, 17 Apr 2025 22:13:58 +0300 Subject: [PATCH 71/92] #73 Add missing issue links --- Launcher/Services/EditorService.cs | 6 +++--- Launcher/UI/Home.razor.cs | 6 +++--- SharpEngine.Core.Components/Properties/BoundingBox.cs | 4 ++-- .../Properties/Shaders/ShaderExtensions.cs | 2 +- SharpEngine.Core/Textures/TextureService.cs | 6 +++--- SharpEngine.Shared/Dto/UserProfile.cs | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Launcher/Services/EditorService.cs b/Launcher/Services/EditorService.cs index 0f8f10a..b6d6b85 100644 --- a/Launcher/Services/EditorService.cs +++ b/Launcher/Services/EditorService.cs @@ -86,7 +86,7 @@ private void CreateSolution(Project project) string createProject = $"dotnet new console -n {projectName} -o {project.Path} -f {FRAMEWORK}"; string addProjectToSolution = $"dotnet sln {project.Path}/{projectName}.sln add {project.Path}/{projectName}.csproj"; - // TODO: Add the NuGet package after it's been published + // TODO: #34 Add the NuGet package after it's been published //string installNuGetPackage = $"dotnet add {project.Path}/{projectName}.csproj package {SHARP_ENGINE_CORE_NUGET_PACKAGE}"; string installNuGetPackage = "echo done"; @@ -109,9 +109,9 @@ private void CreateSolution(Project project) else _notificationService.Show("Solution and project created successfully!"); - // TODO: Set example program.cs content with the minimal projects content. + // TODO: #34 Set example program.cs content with the minimal projects content. // string programFilePath = Path.Combine(project.Path!, "Program.cs"); - // string programContent = ""; // TODO: Replace with program content + // string programContent = ""; // // File.WriteAllText(programFilePath, programContent); } diff --git a/Launcher/UI/Home.razor.cs b/Launcher/UI/Home.razor.cs index 73ff595..1a0cfa5 100644 --- a/Launcher/UI/Home.razor.cs +++ b/Launcher/UI/Home.razor.cs @@ -50,8 +50,8 @@ protected override async Task OnInitializedAsync() { await base.OnInitializedAsync(); - // TODO: Get current launcher version - // TODO: Check if GitHub has a new version released. + // TODO: #96 Get current launcher version + // TODO: #96 Check if GitHub has a new version released. #if DEBUG if (TestData.TestData.SimulateLoading) @@ -94,7 +94,7 @@ private void OnDeleteProjectConfirm() if (project is not null) { Projects.Remove(project); - // TODO: Delete project files + // TODO: #26 Delete project files } else _notificationService.Show($"Unable to delete project '{project?.Name}'.", false, _selectedProject, Projects); diff --git a/SharpEngine.Core.Components/Properties/BoundingBox.cs b/SharpEngine.Core.Components/Properties/BoundingBox.cs index e0a4e67..e774eaa 100644 --- a/SharpEngine.Core.Components/Properties/BoundingBox.cs +++ b/SharpEngine.Core.Components/Properties/BoundingBox.cs @@ -28,12 +28,12 @@ public BoundingBox(Vector3 min, Vector3 max) Max = max; } - // TODO: This should be calculated by the mesh. + // TODO: #5 This should be calculated by the mesh. /// /// Calculates the bounding box of the game object. /// /// The bounding box of the game object. - public static BoundingBox CalculateBoundingBox(ITransform transform) + public static BoundingBox CalculateBoundingBox(ITransform transform) { var min = transform.Position - (transform.Scale / 2); var max = transform.Position + (transform.Scale / 2); diff --git a/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs index c60fd06..17a4666 100644 --- a/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs +++ b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs @@ -197,7 +197,7 @@ private bool TrySetUniform(string name, T data, Action setter) return true; } - // TODO: The _gl.UseProgram should be not be called here. Rather the renderer should call it once before rendering. + // TODO: #95 The _gl.UseProgram should be not be called here. Rather the renderer should call it once before rendering. /// /// Set a uniform int on this shader. diff --git a/SharpEngine.Core/Textures/TextureService.cs b/SharpEngine.Core/Textures/TextureService.cs index 9da5b3b..3a71c87 100644 --- a/SharpEngine.Core/Textures/TextureService.cs +++ b/SharpEngine.Core/Textures/TextureService.cs @@ -3,6 +3,7 @@ using SharpEngine.Core.Windowing; using Texture = SharpEngine.Core.Components.Properties.Textures.Texture; +using TextureType = Silk.NET.Assimp.TextureType; namespace SharpEngine.Core.Textures; @@ -25,7 +26,7 @@ private TextureService() { } /// /// the full path to the texture. /// The loaded texture program. - public Texture LoadTexture(string path) + public Texture LoadTexture(string path, TextureType textureType = TextureType.Diffuse) { if (string.IsNullOrWhiteSpace(path)) throw new FileNotFoundException("No texture file provided."); @@ -38,8 +39,7 @@ public Texture LoadTexture(string path) return cachedTexture; // Generate handle - // TODO: Determine the type of texture. - var texture = new Texture(Window.GL, path, Silk.NET.Assimp.TextureType.Diffuse); + var texture = new Texture(Window.GL, path, textureType); texture.Initialize(); // Add it to the cache diff --git a/SharpEngine.Shared/Dto/UserProfile.cs b/SharpEngine.Shared/Dto/UserProfile.cs index 6235570..b7a2f8b 100644 --- a/SharpEngine.Shared/Dto/UserProfile.cs +++ b/SharpEngine.Shared/Dto/UserProfile.cs @@ -26,7 +26,7 @@ public string Password private void SetPassword(string pwd) { - // TODO: Figure out a good way to handle encryption + // TODO: #60 Figure out a good way to handle encryption _password = pwd; } } From 2bbb3bae6e76f82292406f72063fbca7e9b7d51e Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Thu, 17 Apr 2025 22:46:30 +0300 Subject: [PATCH 72/92] #2 Use obsolete loader Let's use Model_Old for now to resolve the meshes. Later on once we are implementing the fbx stuff we can try to figure out again how to make the loader properly work. --- Examples/MinecraftClone/Minecraft.cs | 4 +- .../Tutorial 4.1 - Model Loading/Program.cs | 18 ++-- .../Loaders/ObjLoader/ObjLoaderFactory.cs | 42 +++++++- .../Properties/Meshes/Mesh.cs | 3 + .../Properties/Meshes/Model_Old.cs | 7 +- .../Properties/Textures/Texture.cs | 2 +- SharpEngine.Core/Entities/MeshService.cs | 96 ------------------- 7 files changed, 54 insertions(+), 118 deletions(-) diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index c118839..36f73db 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -149,9 +149,9 @@ private void InitializeWorld() // var torus = MeshService.Instance.LoadMesh("torus", @"C:\Users\antti\Documents\Untitled2.obj"); var go = new GameObject(); - var meshes = ObjLoaderFactory.Load(Window.GL, @"C:\Users\antti\Documents\Untitled2.obj"); + var model = ObjLoaderFactory.Load(Window.GL, @"C:\Users\antti\Documents\Untitled2.obj"); - foreach (var mesh in meshes) + foreach (var mesh in model.Meshes) { ResolveMeshData(mesh); go.Meshes.Add(mesh); diff --git a/Examples/Tutorial 4.1 - Model Loading/Program.cs b/Examples/Tutorial 4.1 - Model Loading/Program.cs index d9fa05e..19cad1e 100644 --- a/Examples/Tutorial 4.1 - Model Loading/Program.cs +++ b/Examples/Tutorial 4.1 - Model Loading/Program.cs @@ -9,6 +9,7 @@ using System.IO; using System.Linq; using System.Numerics; +using SharpEngine.Core._Resources; using Shader = SharpEngine.Core.Shaders.Shader; using Texture = SharpEngine.Core.Components.Properties.Textures.Texture; @@ -23,8 +24,7 @@ class Program private static Texture Texture; private static Shader Shader; - private static Model_Old Model; - // private static Model Model; + private static Model_Old Model_Old; //Setup the camera's location, directions, and movement speed private static Vector3 CameraPosition = new Vector3(0.0f, 0.0f, 3.0f); @@ -77,13 +77,10 @@ private static void OnLoad() Gl.GetInteger(GLEnum.ContextFlags, out int contextFlags); Console.WriteLine($"OpenGL Context Flags: {contextFlags}"); - Shader = new Shader(Gl, PathExtensions.GetAssemblyPath("shader.vert"), SharpEngine.Core._Resources.Default.LightShader, "test").Initialize(); - Texture = new Texture(Gl, "silk.png", Silk.NET.Assimp.TextureType.Diffuse); + Shader = new Shader(Gl, PathExtensions.GetAssemblyPath("shader.vert"), Default.LightShader, "test").Initialize(); + Texture = new Texture(Gl, "silk.png"); - // var meshes = ObjLoaderFactory.Load(Gl, "Untitled2.obj"); - // Model = new Model(Gl, "Untitled2.obj", meshes); - - Model = new Model_Old(Gl, "Untitled2.obj"); + Model_Old = ObjLoaderFactory.Load(Gl, "Untitled2.obj"); } private static unsafe void OnUpdate(double deltaTime) @@ -131,7 +128,7 @@ private static unsafe void OnRender(double deltaTime) //Note that the apsect 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); - foreach (var mesh in Model.Meshes) + foreach (var mesh in Model_Old.Meshes) { mesh.Bind(); Shader.Use(); @@ -143,7 +140,6 @@ private static unsafe void OnRender(double deltaTime) Shader.SetMatrix4("uProjection", projection, false); Gl.DrawArrays(PrimitiveType.Triangles, 0, (uint)mesh.Vertices.Length); - // Gl.DrawElements(PrimitiveType.Triangles, (uint)mesh.Indices.Length, DrawElementsType.UnsignedInt, null); } } @@ -186,7 +182,7 @@ private static unsafe void OnMouseWheel(IMouse mouse, ScrollWheel scrollWheel) private static void OnClose() { - Model.Dispose(); + Model_Old.Dispose(); Shader.Dispose(); Texture.Dispose(); } diff --git a/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs b/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs index 26682b7..408855c 100644 --- a/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs +++ b/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs @@ -1,19 +1,52 @@ 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 { + /// + /// Handles loading 3D models. + /// public static class ObjLoaderFactory { - /// - public static List Load(GL gl, string path) + const string FbxExtension = ".fbx"; + const string ObjExtension = ".obj"; + + /// + /// 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. + /// 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) + => Path.GetExtension(path) switch + { + FbxExtension => LoadFbx("", path), + ObjExtension => LoadObj(gl, path), + _ => throw new NotSupportedException($"The file extension {Path.GetExtension(path)} is not a supported mesh file.") + }; + + // TODO: #3 Load fbx mesh from file + private static Model_Old LoadFbx(string identifier, string meshFilePath) { - var dataStore = new DataStore(); - + throw new NotImplementedException(); + } + + private static Model_Old 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 dataStore = new DataStore(); + var faceParser = new FaceParser(dataStore); var groupParser = new GroupParser(dataStore); var normalParser = new NormalParser(dataStore); @@ -26,6 +59,7 @@ public static List Load(GL gl, string path) 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/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs index cc0918b..c0989d8 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs @@ -87,6 +87,9 @@ public unsafe void SetupMesh() EBO = new BufferObject(GL, Indices, BufferTargetARB.ElementArrayBuffer); VBO = new BufferObject(GL, Vertices, BufferTargetARB.ArrayBuffer); VAO = new VertexArrayObject(GL, VBO, EBO); + + // TODO: This should use VertexData properties. + // TODO: This assumes we only use the vertex position and texture coordinates, it should also support normals. VAO.VertexAttributePointer(0, 3, VertexAttribPointerType.Float, 5, 0); VAO.VertexAttributePointer(1, 2, VertexAttribPointerType.Float, 5, 3); } diff --git a/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs b/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs index 9639539..e05c810 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs @@ -4,9 +4,6 @@ using SharpEngine.Core.Components.Properties.Meshes.MeshData; using Silk.NET.Assimp; using Silk.NET.OpenGL; -using System; -using System.Collections.Generic; -using System.Linq; using System.Numerics; using AssimpMesh = Silk.NET.Assimp.Mesh; using Mesh = SharpEngine.Core.Entities.Properties.Meshes.Mesh; @@ -14,11 +11,12 @@ 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, bool gamma = false) { - var assimp = Silk.NET.Assimp.Assimp.GetApi(); + var assimp = Assimp.GetApi(); _assimp = assimp; _gl = gl; LoadModel(path); @@ -175,6 +173,7 @@ private float[] BuildVertices(List vertexCollection) vertices.Add(vertex.Position.X); vertices.Add(vertex.Position.Y); vertices.Add(vertex.Position.Z); + vertices.Add(vertex.TexCoords.X); vertices.Add(vertex.TexCoords.Y); } diff --git a/SharpEngine.Core.Components/Properties/Textures/Texture.cs b/SharpEngine.Core.Components/Properties/Textures/Texture.cs index 345e134..d271f1e 100644 --- a/SharpEngine.Core.Components/Properties/Textures/Texture.cs +++ b/SharpEngine.Core.Components/Properties/Textures/Texture.cs @@ -18,7 +18,7 @@ public partial class Texture : IDisposable /// /// Initializes a new instance of . /// - public Texture(GL gl, string path, TextureType type) + public Texture(GL gl, string path, TextureType type = TextureType.Diffuse) { _gl = gl; Handle = _gl.GenTexture(); diff --git a/SharpEngine.Core/Entities/MeshService.cs b/SharpEngine.Core/Entities/MeshService.cs index 99a405f..7e42482 100644 --- a/SharpEngine.Core/Entities/MeshService.cs +++ b/SharpEngine.Core/Entities/MeshService.cs @@ -39,100 +39,4 @@ public Mesh LoadMesh(string identifier, Mesh mesh) Meshes.Add(identifier, mesh); return mesh; } - - const string FbxExtension = ".fbx"; - const string ObjExtension = ".obj"; - - /*/// - /// Loads a mesh based on the file extension of the provided path. - /// - /// Used to specify the unique identifier for the mesh being loaded. - /// Specifies the file path of the mesh to be loaded, which determines the loading method based on its extension. - /// A collection of objects loaded from the specified file. - /// Thrown when the file extension of the provided path is not recognized as a supported mesh format. - public IEnumerable LoadMesh(string identifier, string meshFilePath) - => Path.GetExtension(meshFilePath) switch - { - FbxExtension => LoadFbx(identifier, meshFilePath), - ObjExtension => LoadObj(identifier, meshFilePath), - _ => throw new NotSupportedException($"The file extension {Path.GetExtension(meshFilePath)} is not a supported mesh file.") - }; - - // TODO: #2 Load obj mesh from file - private IEnumerable LoadObj(string identifier, string meshFilePath) - { - var vertices = new List(); - var normals = new List(); - var textureCoordinates = new List(); - var indices = new List(); - - Mesh LoadMeshIntoBuffer() - { - var mesh = LoadMesh(identifier, new Mesh() - { - Vertices = [.. vertices], - Normals = [.. normals], - TextureCoordinates = [.. textureCoordinates], - Indices = [.. indices] - }); - - vertices.Clear(); - normals.Clear(); - textureCoordinates.Clear(); - indices.Clear(); - - return mesh; - } - - static IEnumerable GetData(string[] parts) => parts.Skip(1).Select(float.Parse); - - var contents = File.ReadAllLines(meshFilePath); - foreach (var line in contents) - { - var parts = line.Split(' ', StringSplitOptions.RemoveEmptyEntries); - if (parts.Length == 0) continue; - - switch (parts[0]) - { - case ObjMeshData.VERTEX: - vertices.AddRange(GetData(parts)); - break; - case ObjMeshData.VERTEX_NORMAL: - normals.AddRange(GetData(parts)); - break; - case ObjMeshData.VERTEX_TEXTURE: - textureCoordinates.AddRange(GetData(parts)); - break; - case ObjMeshData.FACE: // OBJ faces are defined as a list of vertex indices - var faceVertices = parts.Skip(1).ToArray(); - for (int i = 1; i < faceVertices.Length - 1; i++) - { - // Triangle 1: Vertex 1, Vertex i, Vertex i+1 - var indicesParts1 = faceVertices[0].Split('/'); - var indicesParts2 = faceVertices[i].Split('/'); - var indicesParts3 = faceVertices[i + 1].Split('/'); - - // OBJ indices are 1-based so we need to subtract 1 to convert to 0-based - indices.Add(uint.Parse(indicesParts1[0]) - 1); - indices.Add(uint.Parse(indicesParts2[0]) - 1); - indices.Add(uint.Parse(indicesParts3[0]) - 1); - } - break; - case ObjMeshData.OBJECT: - if (vertices.Count > 0) - yield return LoadMeshIntoBuffer(); - break; - } - } - - if (vertices.Count > 0) - yield return LoadMeshIntoBuffer(); - }*/ - - // TODO: #3 Load fbx mesh from file - private IEnumerable LoadFbx(string identifier, string meshFilePath) - { - throw new NotImplementedException(); - } - } \ No newline at end of file From 944353ab5c49b51d9ea2d3cd5b79dd4bcf3845e4 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Thu, 17 Apr 2025 23:38:52 +0300 Subject: [PATCH 73/92] #2 Using custom meshes in engine works --- Examples/MinecraftClone/Minecraft.cs | 15 +++++------- .../Tutorial 4.1 - Model Loading/Program.cs | 2 +- .../Tutorial 4.1 - Model Loading.csproj | 2 +- .../{shader.vert => shader2.vert} | 0 SharpEngine.Core/Abstractions/IRenderable.cs | 2 +- SharpEngine.Core/Entities/GameObject.cs | 24 ++++++++++++------- SharpEngine.Core/Entities/UI/UIElement.cs | 2 +- SharpEngine.Core/SharpEngine.Core.csproj | 3 +++ .../_Resources/Shaders/shader2.vert | 16 +++++++++++++ 9 files changed, 44 insertions(+), 22 deletions(-) rename Examples/Tutorial 4.1 - Model Loading/{shader.vert => shader2.vert} (100%) create mode 100644 SharpEngine.Core/_Resources/Shaders/shader2.vert diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index 36f73db..c81ec22 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -143,21 +143,18 @@ public void OnAfterRender(Frame frame) private void InitializeWorld() { InitializeLights(); - InitializeChunks(); + // InitializeChunks(); // TODO: #2 Does not work yet. // var torus = MeshService.Instance.LoadMesh("torus", @"C:\Users\antti\Documents\Untitled2.obj"); - var go = new GameObject(); var model = ObjLoaderFactory.Load(Window.GL, @"C:\Users\antti\Documents\Untitled2.obj"); - - foreach (var mesh in model.Meshes) + var go = new GameObject() { - ResolveMeshData(mesh); - go.Meshes.Add(mesh); - } - - go.Initialize(); + Meshes = model.Meshes + }; + + go.Initialize(true); _scene.Root.AddChild(go); } diff --git a/Examples/Tutorial 4.1 - Model Loading/Program.cs b/Examples/Tutorial 4.1 - Model Loading/Program.cs index 19cad1e..33d23f5 100644 --- a/Examples/Tutorial 4.1 - Model Loading/Program.cs +++ b/Examples/Tutorial 4.1 - Model Loading/Program.cs @@ -77,7 +77,7 @@ private static void OnLoad() Gl.GetInteger(GLEnum.ContextFlags, out int contextFlags); Console.WriteLine($"OpenGL Context Flags: {contextFlags}"); - Shader = new Shader(Gl, PathExtensions.GetAssemblyPath("shader.vert"), Default.LightShader, "test").Initialize(); + Shader = new Shader(Gl, PathExtensions.GetAssemblyPath("shader2.vert"), Default.LightShader, "test").Initialize(); Texture = new Texture(Gl, "silk.png"); Model_Old = ObjLoaderFactory.Load(Gl, "Untitled2.obj"); diff --git a/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 index 36bab99..3649e84 100644 --- a/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 @@ -29,7 +29,7 @@ Always - + PreserveNewest diff --git a/Examples/Tutorial 4.1 - Model Loading/shader.vert b/Examples/Tutorial 4.1 - Model Loading/shader2.vert similarity index 100% rename from Examples/Tutorial 4.1 - Model Loading/shader.vert rename to Examples/Tutorial 4.1 - Model Loading/shader2.vert diff --git a/SharpEngine.Core/Abstractions/IRenderable.cs b/SharpEngine.Core/Abstractions/IRenderable.cs index f3f4216..19f3a77 100644 --- a/SharpEngine.Core/Abstractions/IRenderable.cs +++ b/SharpEngine.Core/Abstractions/IRenderable.cs @@ -18,7 +18,7 @@ public interface IRenderable /// Initializes the necessary buffers for the object. /// /// The mesh that should the buffers should be initialized with. - public void InitializeBuffers(Mesh mesh); + public void InitializeBuffers(Mesh mesh, bool useMeshVertices); /// /// Binds the VAO to the current context. diff --git a/SharpEngine.Core/Entities/GameObject.cs b/SharpEngine.Core/Entities/GameObject.cs index 36b359f..ea995a1 100644 --- a/SharpEngine.Core/Entities/GameObject.cs +++ b/SharpEngine.Core/Entities/GameObject.cs @@ -89,13 +89,13 @@ public override Transform Transform public uint VAO { get; set; } /// - public void Initialize() + public void Initialize(bool useMeshVertices = false) { VAO = Window.GL.GenVertexArray(); Bind(); foreach (var mesh in Meshes) - InitializeBuffers(mesh); + InitializeBuffers(mesh, useMeshVertices); Material.Shader.Use(); } @@ -107,15 +107,18 @@ public void Bind() } /// - public void InitializeBuffers(Mesh mesh) + 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); + if (useMeshVertices) + { + var vertexBufferObject = Window.GL.GenBuffer(); + Window.GL.BindBuffer(GLEnum.ArrayBuffer, vertexBufferObject); + Window.GL.BufferData(GLEnum.ArrayBuffer, useMeshVertices ? mesh.Vertices : mesh.GetVertices(), GLEnum.StaticDraw); - var elementBufferObject = Window.GL.GenBuffer(); - Window.GL.BindBuffer(GLEnum.ElementArrayBuffer, elementBufferObject); - Window.GL.BufferData(GLEnum.ElementArrayBuffer, mesh.Indices, GLEnum.StaticDraw); + var elementBufferObject = Window.GL.GenBuffer(); + Window.GL.BindBuffer(GLEnum.ElementArrayBuffer, elementBufferObject); + Window.GL.BufferData(GLEnum.ElementArrayBuffer, mesh.Indices, GLEnum.StaticDraw); + } } /// @@ -143,8 +146,11 @@ public override Task Render(CameraView camera, Window window) Material.Shader.SetMatrix4(ShaderAttributes.Model, Transform.ModelMatrix); foreach (var mesh in Meshes) + { + mesh.Bind(); Window.GL.DrawArrays(PrimitiveType.Triangles, 0, (uint)mesh.Vertices.Length); // Window.GL.DrawElements(PrimitiveType.Triangles, (uint)mesh.Indices.Length, DrawElementsType.UnsignedInt, []); + } return Task.CompletedTask; } diff --git a/SharpEngine.Core/Entities/UI/UIElement.cs b/SharpEngine.Core/Entities/UI/UIElement.cs index 024d888..80abdd8 100644 --- a/SharpEngine.Core/Entities/UI/UIElement.cs +++ b/SharpEngine.Core/Entities/UI/UIElement.cs @@ -68,7 +68,7 @@ public void Bind() } /// - public void InitializeBuffers(Mesh mesh) + public void InitializeBuffers(Mesh mesh, bool useMeshVertices = false) { var vertexBufferObject = Window.GL.GenBuffer(); Window.GL.BindBuffer(GLEnum.ArrayBuffer, vertexBufferObject); diff --git a/SharpEngine.Core/SharpEngine.Core.csproj b/SharpEngine.Core/SharpEngine.Core.csproj index d25c4fa..005cf46 100644 --- a/SharpEngine.Core/SharpEngine.Core.csproj +++ b/SharpEngine.Core/SharpEngine.Core.csproj @@ -44,6 +44,9 @@ + + PreserveNewest + diff --git a/SharpEngine.Core/_Resources/Shaders/shader2.vert b/SharpEngine.Core/_Resources/Shaders/shader2.vert new file mode 100644 index 0000000..fc46c04 --- /dev/null +++ b/SharpEngine.Core/_Resources/Shaders/shader2.vert @@ -0,0 +1,16 @@ +#version 330 core +layout (location = 0) in vec3 vPos; +layout (location = 1) in vec2 vUv; + +uniform mat4 uModel; +uniform mat4 uView; +uniform mat4 uProjection; + +out vec2 fUv; + +void main() +{ + //Multiplying our uniform with the vertex position, the multiplication order here does matter. + gl_Position = uProjection * uView * uModel * vec4(vPos, 1.0); + fUv = vUv; +} \ No newline at end of file From c10a96cd2ed910abd11724031b5e3040e644ca11 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sun, 20 Apr 2025 23:37:20 +0300 Subject: [PATCH 74/92] #2 A very bandaid solution for the obj renderer The implementation works but it's very hacky. This needs to fixed --- Editor/EditorWindow.cs | 17 +-- Editor/Program.cs | 6 +- Editor/Windows/ActionsMenuWindow.cs | 27 +++-- Editor/Windows/ImGuiWindowBase.cs | 5 +- Editor/Windows/PropertiesWindow.cs | 5 +- Examples/MinecraftClone/Block/BlockBase.cs | 4 +- Examples/MinecraftClone/Minecraft.cs | 60 ++-------- Examples/MultipleWindows/Program.cs | 3 +- .../Tutorial 4.1 - Model Loading/Program.cs | 54 ++++++--- .../MaterialLibraryLoaderFacade.cs | 9 +- .../Properties/Material.cs | 80 ++++++++++--- .../Properties/Shaders/Shader.cs | 7 +- .../Properties/Shaders/ShaderExtensions.cs | 21 ++-- .../Properties/Transform.cs | 6 +- SharpEngine.Core/Abstractions/IRenderable.cs | 14 --- SharpEngine.Core/Audio/WavPlayer.cs | 7 +- SharpEngine.Core/Debug.cs | 30 ----- SharpEngine.Core/Entities/GameObject.cs | 111 +++++------------- .../Entities/Lights/DirectionalLight.cs | 12 +- .../Entities/Lights/PointLight.cs | 28 +++-- SharpEngine.Core/Entities/Lights/SpotLight.cs | 33 ++++-- SharpEngine.Core/Primitives/Cube.cs | 10 ++ .../Primitives/PrimitiveFactory.cs | 27 +++-- SharpEngine.Core/Renderers/Renderer.cs | 20 ++-- SharpEngine.Core/Renderers/UIRenderer.cs | 4 +- SharpEngine.Core/Scenes/Scene.cs | 3 +- SharpEngine.Core/Shaders/ShaderBase.cs | 3 +- SharpEngine.Core/Shaders/ShaderService.cs | 9 +- SharpEngine.Core/SharpEngine.Core.csproj | 5 +- SharpEngine.Core/Windowing/Window.cs | 15 +-- .../_Resources/Shaders/lighting.frag | 25 ++-- .../_Resources/Shaders/shader.frag | 4 +- SharpEngine.Shared/Debug.cs | 32 +++++ SharpEngine.Shared/SharpEngine.Shared.csproj | 5 + 34 files changed, 363 insertions(+), 338 deletions(-) delete mode 100644 SharpEngine.Core/Debug.cs create mode 100644 SharpEngine.Shared/Debug.cs diff --git a/Editor/EditorWindow.cs b/Editor/EditorWindow.cs index bcc7b9c..7eae472 100644 --- a/Editor/EditorWindow.cs +++ b/Editor/EditorWindow.cs @@ -14,6 +14,7 @@ using System.Reflection; using SharpEngine.Core.Windowing; using SharpEngine.Shared.Dto; +using SharpEngine.Shared; namespace SharpEngine.Editor; @@ -73,25 +74,25 @@ public override void OnLoad() _windows.Add(windowBase); } - catch (Exception e) + catch (Exception ex) { - Debug.LogInformation(e.Message, e); + Debug.Log.Error(ex.Message); } } _contextMenuWindow = (ContextMenuWindow?)_windows.FirstOrDefault(w => w.GetType() == typeof(ContextMenuWindow)); if (_contextMenuWindow is null) - Debug.LogInformation("ContextMenuWindow not found."); + Debug.Log.Error("ContextMenuWindow not found."); _actionsMenuWindow = (ActionsMenuWindow?)_windows.FirstOrDefault(w => w.GetType() == typeof(ActionsMenuWindow)); if (_actionsMenuWindow is null) - Debug.LogInformation("ActionsMenuWindow not found."); + Debug.Log.Error("ActionsMenuWindow not found."); else _actionsMenuWindow.OnSceneLoaded += SetScene; } - catch (Exception e) + catch (Exception ex) { - Debug.LogInformation(e.Message, e); + Debug.Log.Error(ex, ex.Message); } } @@ -241,7 +242,7 @@ public override void OnMouseClick(IMouse mouse, MouseButton button, Vector2 vect { // Clicked on an ImGui component uint hoveredItemId = ImGui.GetID(""); - Debug.LogInformation($"Clicked on ImGui component with ID: {hoveredItemId}"); + Debug.Log.Information("Clicked on ImGui component with ID: {HoveredItemId}", hoveredItemId); } else { @@ -257,7 +258,7 @@ public override void OnMouseClick(IMouse mouse, MouseButton button, Vector2 vect { // Clicked on an ImGui component uint hoveredItemId = ImGui.GetID(""); - Debug.LogInformation($"Clicked on ImGui component with ID: {hoveredItemId}"); + Debug.Log.Information("Clicked on ImGui component with ID: {HoveredItemId}", hoveredItemId); } else { diff --git a/Editor/Program.cs b/Editor/Program.cs index b1f251f..08cfcbb 100644 --- a/Editor/Program.cs +++ b/Editor/Program.cs @@ -46,13 +46,13 @@ public static void Main(string[] args) : new Project(); #endif using var window = new EditorWindow(scene, project!, new DefaultViewSettings()); - window.OnLoaded += () => Console.WriteLine("test"); + window.OnLoaded += () => Debug.Log.Information("test"); window.Run(); } - catch (Exception e) + catch (Exception ex) { - Debug.LogInformation($"Failed to start the editor: {e.Message}", e, true); + Debug.Log.Information(ex, "Failed to start the editor: {Message}", ex.Message); } } } \ No newline at end of file diff --git a/Editor/Windows/ActionsMenuWindow.cs b/Editor/Windows/ActionsMenuWindow.cs index 9401c6a..4cbbf1c 100644 --- a/Editor/Windows/ActionsMenuWindow.cs +++ b/Editor/Windows/ActionsMenuWindow.cs @@ -2,6 +2,7 @@ using SharpEngine.Core; using SharpEngine.Core.Audio; using SharpEngine.Core.Scenes; +using SharpEngine.Shared; using SharpEngine.Shared.Extensions; using System.Text; @@ -44,7 +45,7 @@ private void PlayTestAudio(string filePath) { if (!File.Exists(filePath)) { - Debug.LogInformation($"Audio file '{filePath}' does not exist."); + Debug.Log.Warning("Audio file '{FilePath}' does not exist.", filePath); return; } @@ -57,7 +58,7 @@ private void PlayTestAudio(string filePath) } catch (Exception ex) { - Debug.LogInformation($"Error during audio playback: {ex.Message}"); + Debug.Log.Error(ex, "Error during audio playback: {Message}", ex.Message); } } @@ -69,21 +70,21 @@ private void StartGame() // Editor service probably needs to be made shared so that we can initialize the project / solution when the editor is opened. // TODO: #77 Save automatically - Debug.LogInformation("The project was null"); + Debug.Log.Information("The project was null"); return; } - Debug.LogInformation($"Starting {Project.Name}."); - ProcessExtensions.RunProcess($"dotnet run --project {Project.Path}/{Project.Name}.csproj", true, msg => Debug.LogInformation(msg)); + Debug.Log.Information("Starting {ProjectName}.", Project.Name); + ProcessExtensions.RunProcess($"dotnet run --project {Project.Path}/{Project.Name}.csproj", true, Debug.Log.Information); } private void SaveScene(Scene scene) { - Console.WriteLine("Saving.."); + Debug.Log.Information("Saving.."); if (!scene.HasUnsavedChanges && scene.HasSaveFile()) { - Console.WriteLine("No changes to save."); + Debug.Log.Information("No changes to save."); return; } @@ -91,7 +92,7 @@ private void SaveScene(Scene scene) { scene.SaveScene().Wait(); OnSceneLoaded?.Invoke(scene); - Console.WriteLine("File saved successfully!"); + Debug.Log.Information("File saved successfully!"); return; } @@ -110,15 +111,15 @@ private void SaveScene(Scene scene) scene.SaveScene(dialog.FileName).Wait(); Scene.SetFileFullPath(dialog.FileName); - Console.WriteLine("File saved successfully!"); + Debug.Log.Information("File saved successfully!"); } else - Console.WriteLine("File save cancelled."); + Debug.Log.Information("File save cancelled."); } private static bool SelectFile(out string selectedFile) { - Console.WriteLine("Selecting file.."); + Debug.Log.Information("Selecting file.."); using var dialog = new OpenFileDialog() { @@ -140,12 +141,12 @@ private static bool SelectFile(out string selectedFile) private void LoadScene(string sceneFile) { - Console.WriteLine($"Loading scene from file: {sceneFile}."); + Debug.Log.Information($"Loading scene from file: {sceneFile}."); var newScene = Scene.LoadScene(sceneFile); SetScene(newScene); - Console.WriteLine("Scene loaded successfully!"); + Debug.Log.Information("Scene loaded successfully!"); } } } diff --git a/Editor/Windows/ImGuiWindowBase.cs b/Editor/Windows/ImGuiWindowBase.cs index 2bc647e..4210f05 100644 --- a/Editor/Windows/ImGuiWindowBase.cs +++ b/Editor/Windows/ImGuiWindowBase.cs @@ -2,6 +2,7 @@ using SharpEngine.Core.Entities.Views.Settings; using SharpEngine.Core.Scenes; +using SharpEngine.Shared; using SharpEngine.Shared.Dto; namespace SharpEngine.Editor.Windows @@ -87,7 +88,7 @@ public void RenderWindow() /// protected virtual void OnWindowUndocked() { - Console.WriteLine($"Window {Name} was undocked."); + Debug.Log.Information($"Window {Name} was undocked."); // TODO: #75 This method of doing this does not work (at least in .Net 8). //CreateSilkWindow(); @@ -117,7 +118,7 @@ private void CreateSilkWindow() } catch (Exception ex) { - Console.WriteLine($"Failed to create window: {ex.Message}"); + Debug.Log.Information($"Failed to create window: {ex.Message}"); } } diff --git a/Editor/Windows/PropertiesWindow.cs b/Editor/Windows/PropertiesWindow.cs index 6f998ff..038a01f 100644 --- a/Editor/Windows/PropertiesWindow.cs +++ b/Editor/Windows/PropertiesWindow.cs @@ -1,5 +1,6 @@ using ImGuiNET; using SharpEngine.Core.Attributes; +using SharpEngine.Shared; using System.Numerics; using System.Reflection; @@ -80,9 +81,9 @@ public void RenderActiveElementProperties(object obj, int maxRecursionDepth = 5, } } } - catch (Exception e) + catch (Exception ex) { - Console.WriteLine(e); + Debug.Log.Error(ex, "{Message}", ex.Message); } } } diff --git a/Examples/MinecraftClone/Block/BlockBase.cs b/Examples/MinecraftClone/Block/BlockBase.cs index 7f06016..eb1ce12 100644 --- a/Examples/MinecraftClone/Block/BlockBase.cs +++ b/Examples/MinecraftClone/Block/BlockBase.cs @@ -56,7 +56,7 @@ private void AssignProperties(GameObject cube, string name) }; Name = name; - Material = cube.Material; - Meshes = cube.Meshes; + // Material = cube.Material; + Model = cube.Model; } } diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index c81ec22..29b216d 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -4,6 +4,7 @@ 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; @@ -11,12 +12,14 @@ using SharpEngine.Core.Interfaces; using SharpEngine.Core.Scenes; using SharpEngine.Core.Windowing; +using SharpEngine.Shared; using Silk.NET.Core.Native; using Silk.NET.Input; using System; using System.Collections.Generic; using System.Linq; using System.Numerics; +using Tutorial; namespace Minecraft; @@ -87,7 +90,7 @@ public override void Initialize() } catch (Exception ex) { - Console.WriteLine(ex); + Debug.Log.Information(ex.Message, "{Message}", ex.Message); } } @@ -149,54 +152,17 @@ private void InitializeWorld() // 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 go = new GameObject() + var go = new GameObject(model); + var go2 = new GameObject(model) { - Meshes = model.Meshes + Transform = new Transform(new SharpEngine.Core.Numerics.Vector3(0, 0, 30)) }; - go.Initialize(true); _scene.Root.AddChild(go); + _scene.Root.AddChild(go2); } - private void ResolveMeshData(Mesh mesh) - { - var resolvedVertices = new List(); - var resolvedNormals = new List(); - var resolvedTextureCoordinates = new List(); - - foreach (var group in mesh.Groups) - { - foreach (var face in group.Faces) - { - foreach (var vertex in face._vertices) - { - // Resolve vertex positions - var position = mesh.Vertices2[vertex.VertexIndex]; - resolvedVertices.Add(position.Position.X); - resolvedVertices.Add(position.Position.Y); - resolvedVertices.Add(position.Position.Z); - - // Resolve normals - var normal = mesh.Normals2[vertex.NormalIndex]; - resolvedNormals.Add(normal.X); - resolvedNormals.Add(normal.Y); - resolvedNormals.Add(normal.Z); - - // Resolve texture coordinates - var texCoord = mesh.TextureCoordinates2[vertex.TextureIndex]; - resolvedTextureCoordinates.Add(texCoord.X); - resolvedTextureCoordinates.Add(texCoord.Y); - } - } - } - - // Update the mesh with resolved data - mesh.Vertices = resolvedVertices.ToArray(); - mesh.Normals = resolvedNormals.ToArray(); - mesh.TextureCoordinates = resolvedTextureCoordinates.ToArray(); - } - private void InitializeLights() { _lightsNode.AddChild(new DirectionalLight()); @@ -272,7 +238,7 @@ public override void HandleKeyboard(IKeyboard input, double deltaTime) if (input.IsKeyPressed(Key.Number0 + i)) { _inventory.SetSelectedSlot(i); - Console.WriteLine($"Selected slot: {i} ({_inventory.SelectedSlot.Items.Type})"); + Debug.Log.Information($"Selected slot: {i} ({_inventory.SelectedSlot.Items.Type})"); } } @@ -310,7 +276,7 @@ public override void HandleMouseDown(IMouse mouse, MouseButton button) } else { - Console.WriteLine($"No more {_inventory.SelectedSlot.Items.Type}s."); + Debug.Log.Information($"No more {_inventory.SelectedSlot.Items.Type}s."); } } @@ -321,7 +287,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. - Console.WriteLine($"Block destroyed: {destroyedBlockType}."); + Debug.Log.Information($"Block destroyed: {destroyedBlockType}."); _inventory.AddToolbarItem(destroyedBlockType); } } @@ -350,7 +316,7 @@ private void PlaceBlock() var newBlock = BlockFactory.CreateBlock(_inventory.SelectedSlot.Items.Type, newBlockPosition, $"Dirt ({_blocksNode.Children.Count})"); _blocksNode.AddChild(newBlock); - Console.WriteLine($"New block created: {newBlock.Transform.Position}, block in view location: {intersectingObject!.Transform.Position}"); + Debug.Log.Information($"New block created: {newBlock.Transform.Position}, block in view location: {intersectingObject!.Transform.Position}"); } @@ -376,7 +342,7 @@ public override void HandleMouseWheel(MouseWheelScrollDirection direction, Scrol slotIndex = 0; _inventory.SetSelectedSlot(slotIndex); - Console.WriteLine($"Selected slot: {slotIndex}"); + Debug.Log.Information($"Selected slot: {slotIndex}"); } } diff --git a/Examples/MultipleWindows/Program.cs b/Examples/MultipleWindows/Program.cs index 83caac5..f32735e 100644 --- a/Examples/MultipleWindows/Program.cs +++ b/Examples/MultipleWindows/Program.cs @@ -4,6 +4,7 @@ using System.Collections.Concurrent; using SharpEngine.Core.Entities.Views.Settings; +using SharpEngine.Shared; // An example provided a lovely person in this thread: // https://github.com/dotnet/Silk.NET/issues/2436#issuecomment-2752966073 @@ -70,7 +71,7 @@ private static void StartWindowQueueTask() while (!_cancellationTokenSource.IsCancellationRequested) { await Task.Delay(1000); - Console.WriteLine("Running loop on background thread..."); + Debug.Log.Information("Running loop on background thread..."); } }); diff --git a/Examples/Tutorial 4.1 - Model Loading/Program.cs b/Examples/Tutorial 4.1 - Model Loading/Program.cs index 33d23f5..3fbfad3 100644 --- a/Examples/Tutorial 4.1 - Model Loading/Program.cs +++ b/Examples/Tutorial 4.1 - Model Loading/Program.cs @@ -1,4 +1,5 @@ using ObjLoader.Loaders.ObjLoader; +using SharpEngine.Core._Resources; using SharpEngine.Core.Components.Properties.Textures; using SharpEngine.Core.Extensions; using Silk.NET.Input; @@ -6,10 +7,11 @@ using Silk.NET.OpenGL; using Silk.NET.Windowing; using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Numerics; -using SharpEngine.Core._Resources; +using System.Reflection; using Shader = SharpEngine.Core.Shaders.Shader; using Texture = SharpEngine.Core.Components.Properties.Textures.Texture; @@ -20,11 +22,11 @@ class Program #region fields private static IWindow window; private static GL Gl; - private static IKeyboard primaryKeyboard; + private static IKeyboard? primaryKeyboard; private static Texture Texture; private static Shader Shader; - private static Model_Old Model_Old; + private static List Models = []; //Setup the camera's location, directions, and movement speed private static Vector3 CameraPosition = new Vector3(0.0f, 0.0f, 3.0f); @@ -60,11 +62,11 @@ private static void Main(string[] args) private static void OnLoad() { IInputContext input = window.CreateInput(); - primaryKeyboard = input.Keyboards.FirstOrDefault(); + primaryKeyboard = input.Keyboards.Count > 0 ? input.Keyboards[0] : null; + if (primaryKeyboard != null) - { primaryKeyboard.KeyDown += KeyDown; - } + for (int i = 0; i < input.Mice.Count; i++) { input.Mice[i].Cursor.CursorMode = CursorMode.Raw; @@ -74,13 +76,13 @@ private static void OnLoad() Gl = GL.GetApi(window); - Gl.GetInteger(GLEnum.ContextFlags, out int contextFlags); - Console.WriteLine($"OpenGL Context Flags: {contextFlags}"); - Shader = new Shader(Gl, PathExtensions.GetAssemblyPath("shader2.vert"), Default.LightShader, "test").Initialize(); Texture = new Texture(Gl, "silk.png"); - Model_Old = ObjLoaderFactory.Load(Gl, "Untitled2.obj"); + var model = ObjLoaderFactory.Load(Gl, "Untitled2.obj"); + + Models.Add(model); + Models.Add(model); } private static unsafe void OnUpdate(double deltaTime) @@ -114,28 +116,42 @@ private static unsafe void OnRender(double deltaTime) Gl.Enable(EnableCap.DepthTest); Gl.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); - Texture.Use(); - Shader.Use(); - Shader.SetInt("uTexture0", 0); + // Texture.Use(); + // Shader.Use(); + //Shader.SetInt("uTexture0", 0); //Use elapsed time to convert to radians to allow our cube to rotate over time var difference = (float) (window.Time * 100); var size = window.FramebufferSize; - var model = Matrix4x4.CreateRotationY(SharpEngine.Core.Math.DegreesToRadians(difference)) * Matrix4x4.CreateRotationX(SharpEngine.Core.Math.DegreesToRadians(difference)); + var modelMatrix = Matrix4x4.CreateRotationY(SharpEngine.Core.Math.DegreesToRadians(difference)) * + Matrix4x4.CreateRotationX(SharpEngine.Core.Math.DegreesToRadians(difference)); + var view = Matrix4x4.CreateLookAt(CameraPosition, CameraPosition + CameraFront, CameraUp); //Note that the apsect 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); - foreach (var mesh in Model_Old.Meshes) + 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); + } + } + + private static unsafe void RenderModel(Model_Old model, Matrix4x4 modelMatrix, Matrix4x4 view, Matrix4x4 projection) + { + foreach (var mesh in model.Meshes) { mesh.Bind(); - Shader.Use(); + Texture.Use(); + Shader.Use(); Shader.SetInt("uTexture0", 0); - Shader.SetMatrix4("uModel", model, false); + Shader.SetMatrix4("uModel", modelMatrix, false); Shader.SetMatrix4("uView", view, false); Shader.SetMatrix4("uProjection", projection, false); @@ -182,7 +198,9 @@ private static unsafe void OnMouseWheel(IMouse mouse, ScrollWheel scrollWheel) private static void OnClose() { - Model_Old.Dispose(); + foreach (var model in Models) + model.Dispose(); + Shader.Dispose(); Texture.Dispose(); } diff --git a/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoaderFacade.cs b/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoaderFacade.cs index f9045de..c6f62af 100644 --- a/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoaderFacade.cs +++ b/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoaderFacade.cs @@ -1,4 +1,4 @@ -using System; +using SharpEngine.Shared; using System.IO; namespace ObjLoader.Loaders.MaterialLoader @@ -7,16 +7,21 @@ 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)) { - Console.WriteLine($"Material file '{materialFileName}' doesn't exist."); + Debug.Log.Warning("Material file '{MaterialFileName}' doesn't exist.", materialFileName); return; } diff --git a/SharpEngine.Core.Components/Properties/Material.cs b/SharpEngine.Core.Components/Properties/Material.cs index b40c9e0..8d35758 100644 --- a/SharpEngine.Core.Components/Properties/Material.cs +++ b/SharpEngine.Core.Components/Properties/Material.cs @@ -1,7 +1,7 @@ -using SharpEngine.Core.Components.Properties; -using SharpEngine.Core.Components.Properties.Textures; -using SharpEngine.Core.Shaders; +using Silk.NET.OpenGL; using System.Numerics; +using Shader = SharpEngine.Core.Shaders.Shader; +using Texture = SharpEngine.Core.Components.Properties.Textures.Texture; namespace SharpEngine.Core.Components.Properties; @@ -13,6 +13,9 @@ public class Material /// /// Initializes a new instance of . /// + /// The shader used to render the 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(Shader shader, Texture diffuseMap, Texture? specularMap = null) { Shader = shader; @@ -32,59 +35,98 @@ public Material(string materialName) Name = materialName; } + /// Gets or sets the name of the material. public string Name { get; set; } - /// - /// Gets or sets the diffuse map texture. - /// + /// Gets or sets the diffuse map texture. public Texture DiffuseMap { get; set; } + /// Gets or sets the path to the diffuse texture map. public string DiffuseTextureMap { get; set; } - /// - /// Gets or sets the specular map texture. - /// + /// Gets or sets the specular map texture. public Texture SpecularMap { get; set; } + /// Gets or sets the path to the specular texture map. public string SpecularTextureMap { get; set; } - /// Gets whether the material uses a specular map. + /// Gets a value indicating whether the material uses a specular map. public bool UseSpecularMap => SpecularMap.Handle != DiffuseMap.Handle; - /// - /// Gets or sets the shader used to render the material. - /// + /// Gets or sets the shader used to render the material. public Shader Shader { get; set; } + /// The texture unit for the diffuse map. public const int DIFFUSE_UNIT = 0; + + /// The texture unit for the specular map. public const int SPECULAR_UNIT = 1; - /// - /// Gets or sets the ambient color of the material. - /// + /// Gets or sets the specular color of the material. public Vector3 Specular { get; set; } - /// - /// Gets or sets the shininess of the material. - /// + /// Gets or sets the shininess of the material. public float Shininess { get; set; } + /// Gets or sets the ambient color of the material. public Vector3 AmbientColor { get; set; } + + /// Gets or sets the diffuse color of the material. public Vector3 DiffuseColor { get; set; } + + /// Gets or sets the specular color of the material. public Vector3 SpecularColor { get; set; } + + /// Gets or sets the specular coefficient of the material. public float SpecularCoefficient { get; set; } + /// Gets or sets the transparency of the material. public float Transparency { get; set; } + /// Gets or sets the illumination model of the material. public int IlluminationModel { get; set; } + /// Gets or sets the path to the ambient texture map. public string AmbientTextureMap { get; set; } + /// Gets or sets the path to the specular highlight texture map. public string SpecularHighlightTextureMap { get; set; } + /// Gets or sets the path to the bump map. public string BumpMap { get; set; } + + /// Gets or sets the path to the displacement map. public string DisplacementMap { get; set; } + + /// Gets or sets the path to the stencil decal map. public string StencilDecalMap { get; set; } + /// Gets or sets the path to the alpha texture map. public string AlphaTextureMap { get; set; } + + /// + /// Sets the uniform values for the material in the specified shader. + /// + /// The shader to set the uniform values in. + 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 (UseSpecularMap) + { + 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.SetFloat("material.shininess", 0); + } + } } diff --git a/SharpEngine.Core.Components/Properties/Shaders/Shader.cs b/SharpEngine.Core.Components/Properties/Shaders/Shader.cs index 4eae830..a86d829 100644 --- a/SharpEngine.Core.Components/Properties/Shaders/Shader.cs +++ b/SharpEngine.Core.Components/Properties/Shaders/Shader.cs @@ -1,3 +1,4 @@ +using SharpEngine.Shared; using Silk.NET.OpenGL; namespace SharpEngine.Core.Shaders; @@ -41,17 +42,19 @@ 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")) - Console.WriteLine("Vertex shaders should have the file extension '.vert' for easier manageability."); + Debug.Log.Warning("Vertex shaders should have the file extension '.vert' for easier manageability."); if (!fragPath.EndsWith(".frag")) - Console.WriteLine("Fragment shaders should have the file extension '.frag' for easier manageability."); + Debug.Log.Warning("Fragment shaders should have the file extension '.frag' for easier manageability."); VertPath = vertPath; FragPath = fragPath; } + /// public void Dispose() { _gl.DeleteProgram(Handle); + GC.SuppressFinalize(this); } } diff --git a/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs index 17a4666..f7c960e 100644 --- a/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs +++ b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs @@ -1,4 +1,5 @@ -using Silk.NET.OpenGL; +using SharpEngine.Shared; +using Silk.NET.OpenGL; using System.Numerics; using System.Text.RegularExpressions; @@ -11,13 +12,13 @@ public Shader Initialize() // Load and compile shader if (!LoadShader(ShaderType.VertexShader, VertPath, out uint vertexShader)) { - Console.WriteLine("Unable to load vertex shader."); + Debug.Log.Error("Unable to load vertex shader."); return this; } if (!LoadShader(ShaderType.FragmentShader, FragPath, out uint fragmentShader)) { - Console.WriteLine("Unable to load fragment shader."); + Debug.Log.Error("Unable to load fragment shader."); return this; } @@ -42,7 +43,7 @@ public Shader Initialize() if (!shaderLinked) { - Console.WriteLine("Unable to link shader program."); + Debug.Log.Information("Unable to link shader program."); return this; } @@ -58,7 +59,7 @@ private bool LoadShader(ShaderType shaderType, string shaderPath, out uint shade { if (!File.Exists(shaderPath)) { - Console.WriteLine($"Shader file not found: {shaderPath}"); + Debug.Log.Information($"Shader file not found: {shaderPath}"); shader = 0; return false; @@ -73,7 +74,7 @@ private bool LoadShader(ShaderType shaderType, string shaderPath, out uint shade if (!CompileShader(shader)) { - Console.WriteLine($"Unable to load {shaderType} shader from '{shaderPath}'."); + Debug.Log.Information($"Unable to load {shaderType} shader from '{shaderPath}'."); return false; } @@ -126,7 +127,7 @@ private bool CompileShader(uint shader) { // We can use `GL.GetShaderInfoLog(shader)` to get information about the error. var infoLog = _gl.GetShaderInfoLog(shader); - Console.WriteLine($"Error occurred whilst compiling Shader({shader}).\n\n{infoLog}"); + Debug.Log.Information($"Error occurred whilst compiling Shader({shader}).\n\n{infoLog}"); return false; } @@ -142,7 +143,7 @@ private bool LinkProgram(uint program) if (statusCode != (int)GLEnum.True) { string infoLog = _gl.GetProgramInfoLog(program); - Console.WriteLine($"Error occurred whilst linking Program({program}): {infoLog}"); + Debug.Log.Information($"Error occurred whilst linking Program({program}): {infoLog}"); return false; } @@ -167,7 +168,7 @@ public bool TryGetAttribLocation(string attribName, out int location) location = _gl.GetAttribLocation(Handle, attribName); if (location == ShaderAttributes.AttributeLocationNotFound) { - Console.WriteLine($"Attribute '{attribName}' not found in shader program."); + Debug.Log.Information($"Attribute '{attribName}' not found in shader program."); return false; } @@ -189,7 +190,7 @@ private bool TrySetUniform(string name, T data, Action setter) if (!_uniformLocations.TryGetValue(name, out int location)) //if (location == -1) { - Console.WriteLine($"Uniform '{name}' not found in shader program."); + Debug.Log.Information($"Uniform '{name}' not found in shader program."); return false; } diff --git a/SharpEngine.Core.Components/Properties/Transform.cs b/SharpEngine.Core.Components/Properties/Transform.cs index 81f0467..3f2f075 100644 --- a/SharpEngine.Core.Components/Properties/Transform.cs +++ b/SharpEngine.Core.Components/Properties/Transform.cs @@ -9,9 +9,13 @@ namespace SharpEngine.Core.Entities.Properties; public class Transform : ITransform { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of . /// public Transform() { } + public Transform(Vector3 position) + { + Position = position; + } /// /// Gets or sets the position of the game object. diff --git a/SharpEngine.Core/Abstractions/IRenderable.cs b/SharpEngine.Core/Abstractions/IRenderable.cs index 19f3a77..e248e60 100644 --- a/SharpEngine.Core/Abstractions/IRenderable.cs +++ b/SharpEngine.Core/Abstractions/IRenderable.cs @@ -9,20 +9,6 @@ namespace SharpEngine.Core.Interfaces; /// public interface IRenderable { - /// - /// Gets or sets the vertex array object of the object. - /// - public uint VAO { get; set; } - /// - /// Initializes the necessary buffers for the object. - /// - /// The mesh that should the buffers should be initialized with. - public void InitializeBuffers(Mesh mesh, bool useMeshVertices); - - /// - /// Binds the VAO to the current context. - /// - public void Bind(); } diff --git a/SharpEngine.Core/Audio/WavPlayer.cs b/SharpEngine.Core/Audio/WavPlayer.cs index 02f9ed7..a686bea 100644 --- a/SharpEngine.Core/Audio/WavPlayer.cs +++ b/SharpEngine.Core/Audio/WavPlayer.cs @@ -1,4 +1,5 @@ -using Silk.NET.OpenAL; +using SharpEngine.Shared; +using Silk.NET.OpenAL; using System; using System.Buffers.Binary; @@ -40,7 +41,7 @@ public override void Play(string filePath) if (!CheckHeader(file, ref index, WavConstants.RiffHeader)) { - Console.WriteLine("Given file is not in RIFF format"); + Debug.Log.Warning("Given file is not in RIFF format"); return; } @@ -48,7 +49,7 @@ public override void Play(string filePath) if (!CheckHeader(file, ref index, WavConstants.WaveHeader)) { - Console.WriteLine("Given file is not in WAVE format"); + Debug.Log.Warning("Given file is not in WAVE format"); return; } diff --git a/SharpEngine.Core/Debug.cs b/SharpEngine.Core/Debug.cs deleted file mode 100644 index e3fa033..0000000 --- a/SharpEngine.Core/Debug.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Serilog; -using System; - -namespace SharpEngine.Core; - -/// -/// Contains methods for debugging the application. -/// -public static class Debug -{ - /// - /// Logs an information message. - /// - /// The message to be logged. - /// The possible exception. - /// Determines whether the log should be written to a file. - public static void LogInformation(string message, Exception? ex = null, bool writeToFile = false) - { - Console.WriteLine(message); - - if (!writeToFile) - return; - - var log = new LoggerConfiguration() - .WriteTo.Console() - .CreateLogger(); - - log.Information(ex, message); - } -} \ No newline at end of file diff --git a/SharpEngine.Core/Entities/GameObject.cs b/SharpEngine.Core/Entities/GameObject.cs index ea995a1..e1abd89 100644 --- a/SharpEngine.Core/Entities/GameObject.cs +++ b/SharpEngine.Core/Entities/GameObject.cs @@ -1,19 +1,15 @@ using SharpEngine.Core.Attributes; -using SharpEngine.Core.Components.Properties; using SharpEngine.Core.Entities.Properties; -using SharpEngine.Core.Entities.Properties.Meshes; using SharpEngine.Core.Entities.Views; using SharpEngine.Core.Interfaces; using SharpEngine.Core.Numerics; using SharpEngine.Core.Scenes; using SharpEngine.Core.Shaders; -using SharpEngine.Core.Textures; using SharpEngine.Core.Windowing; +using Shader = SharpEngine.Core.Shaders.Shader; using Silk.NET.OpenGL; - -using System.Collections.Generic; -using System.Threading.Tasks; +using Tutorial; namespace SharpEngine.Core.Entities; @@ -27,12 +23,15 @@ public class GameObject : EmptyNode, IRenderable /// public GameObject() : base(string.Empty) { - // TODO: #5 Using lightning shader here will most likely break stuff, it needs to be refactored out. - var shader = ShaderService.Instance.LoadShader(_Resources.Default.VertexShader, _Resources.Default.FragmentShader, "lighting"); - var diffuse = TextureService.Instance.LoadTexture(_Resources.Default.DebugTexture); - Material = new(shader, diffuse); - 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"); } /// @@ -42,27 +41,18 @@ public GameObject() : base(string.Empty) /// The file path of the specular map texture. /// The file path of the vertex shader. /// The file path of the fragment shader. - public GameObject(string? diffuseMapFile = null, string? specularMapFile = null, string? vertShaderFile = null, string? fragShaderFile = null) : base(string.Empty) + public GameObject(Shader shader) : base(string.Empty) { - var shader = ShaderService.Instance.LoadShader(vertShaderFile ?? _Resources.Default.VertexShader, fragShaderFile ?? _Resources.Default.FragmentShader, "lighting"); - var diffuse = TextureService.Instance.LoadTexture(diffuseMapFile ?? _Resources.Default.DebugTexture); - var specular = string.IsNullOrEmpty(specularMapFile) ? null : TextureService.Instance.LoadTexture(specularMapFile!); - Material = new Material(shader, diffuse, specular); - BoundingBox = BoundingBox.CalculateBoundingBox(Transform); + Shader = shader; } - /// - /// Gets or sets the mesh of the game object. - /// - public List Meshes { get; set; } = []; + public Shader Shader { get; set; } - // TODO: #5 Each mesh should have its own material. /// - /// Gets or sets the material of the game object. + /// Gets or sets the mesh of the game object. /// - [Inspector(DisplayInInspector = false)] - public Material Material { get; set; } + public Model_Old Model { get; set; } /// /// Gets or sets the transform of the game object. @@ -85,73 +75,36 @@ public override Transform Transform [Inspector(DisplayInInspector = false)] public BoundingBox BoundingBox { get; set; } - /// - public uint VAO { get; set; } - - /// - public void Initialize(bool useMeshVertices = false) + protected virtual void SetShaderUniforms(CameraView camera) { - VAO = Window.GL.GenVertexArray(); - Bind(); - - foreach (var mesh in Meshes) - InitializeBuffers(mesh, useMeshVertices); - - Material.Shader.Use(); + Shader.SetMatrix4(ShaderAttributes.Model, Transform.ModelMatrix); + Shader.SetMatrix4("uView", camera.GetViewMatrix(), false); + Shader.SetMatrix4("uProjection", camera.GetProjectionMatrix(), false); } /// - public void Bind() + public void Render(CameraView camera, Window window) { - Window.GL.BindVertexArray(VAO); - } + // TODO: This needs to removed later once fixed. + if (Model is null || Model.Meshes is null) + return; - /// - public void InitializeBuffers(Mesh mesh, bool useMeshVertices = false) - { - if (useMeshVertices) + foreach (var mesh in Model.Meshes) { - var vertexBufferObject = Window.GL.GenBuffer(); - Window.GL.BindBuffer(GLEnum.ArrayBuffer, vertexBufferObject); - Window.GL.BufferData(GLEnum.ArrayBuffer, useMeshVertices ? mesh.Vertices : mesh.GetVertices(), GLEnum.StaticDraw); - - var elementBufferObject = Window.GL.GenBuffer(); - Window.GL.BindBuffer(GLEnum.ElementArrayBuffer, elementBufferObject); - Window.GL.BufferData(GLEnum.ElementArrayBuffer, mesh.Indices, GLEnum.StaticDraw); - } - } - - /// - public override Task Render(CameraView camera, Window window) - { - // Bind(); + mesh.Bind(); - Material.DiffuseMap.Use(TextureUnit.Texture0); - Material.Shader.SetInt("material.diffuse", Material.DIFFUSE_UNIT); + foreach (var texture in mesh.Textures) + texture.Use(); - if (Material.UseSpecularMap) - { - Material.SpecularMap.Use(TextureUnit.Texture1); - Material.Shader.SetInt("material.specular", Material.SPECULAR_UNIT); - Material.Shader.SetVector3("material.specular", Material.Specular); - Material.Shader.SetFloat("material.shininess", Material.Shininess); - } - else - { - Material.Shader.SetInt("material.specular", 0); - Material.Shader.SetVector3("material.specular", new System.Numerics.Vector3(0)); - Material.Shader.SetFloat("material.shininess", 0); - } + Shader.Use(); + SetShaderUniforms(camera); - Material.Shader.SetMatrix4(ShaderAttributes.Model, Transform.ModelMatrix); + foreach (var material in mesh.Materials) + material.SetUniformValues(Shader); - foreach (var mesh in Meshes) - { - mesh.Bind(); Window.GL.DrawArrays(PrimitiveType.Triangles, 0, (uint)mesh.Vertices.Length); - // Window.GL.DrawElements(PrimitiveType.Triangles, (uint)mesh.Indices.Length, DrawElementsType.UnsignedInt, []); } - return Task.CompletedTask; + // return Task.CompletedTask; } } diff --git a/SharpEngine.Core/Entities/Lights/DirectionalLight.cs b/SharpEngine.Core/Entities/Lights/DirectionalLight.cs index 5653492..c7c0701 100644 --- a/SharpEngine.Core/Entities/Lights/DirectionalLight.cs +++ b/SharpEngine.Core/Entities/Lights/DirectionalLight.cs @@ -27,16 +27,16 @@ public DirectionalLight() Diffuse = new Vector3(0.4f, 0.4f, 0.4f); Specular = new Vector3(0.5f, 0.5f, 0.5f); - Material.Shader = ShaderService.Instance.LoadShader(Default.VertexShader, Default.FragmentShader, "lighting"); + Shader = ShaderService.Instance.LoadShader(Default.VertexShader, Default.FragmentShader, "lighting"); } /// - public override Task Render(CameraView camera, Window window) + public Task Render(CameraView camera, Window window) { - Material.Shader.SetVector3("dirLight.direction", Direction); - Material.Shader.SetVector3("dirLight.ambient", Ambient); - Material.Shader.SetVector3("dirLight.diffuse", Diffuse); - Material.Shader.SetVector3("dirLight.specular", Specular); + Shader.SetVector3("dirLight.direction", Direction); + Shader.SetVector3("dirLight.ambient", Ambient); + Shader.SetVector3("dirLight.diffuse", Diffuse); + Shader.SetVector3("dirLight.specular", Specular); return Task.CompletedTask; } diff --git a/SharpEngine.Core/Entities/Lights/PointLight.cs b/SharpEngine.Core/Entities/Lights/PointLight.cs index 710f52f..33fbb14 100644 --- a/SharpEngine.Core/Entities/Lights/PointLight.cs +++ b/SharpEngine.Core/Entities/Lights/PointLight.cs @@ -28,7 +28,7 @@ public PointLight(Vector3 position, int index) _index = index; - Material.Shader = ShaderService.Instance.LoadShader(Default.VertexShader, Default.FragmentShader, "lighting"); + // Material.Shader = ShaderService.Instance.LoadShader(Default.VertexShader, Default.FragmentShader, "lighting"); LampShader = new LampShader(); } @@ -52,21 +52,23 @@ public PointLight(Vector3 position, int index) /// public float Quadratic { get; set; } - /// - public override Task Render(CameraView camera, Window window) + protected override void SetShaderUniforms(CameraView camera) { - Material.Shader.SetVector3($"pointLights[{_index}].position", (Vector3)Transform.Position); - Material.Shader.SetVector3($"pointLights[{_index}].ambient", Ambient); - Material.Shader.SetVector3($"pointLights[{_index}].diffuse", Diffuse); - Material.Shader.SetVector3($"pointLights[{_index}].specular", Specular); - Material.Shader.SetFloat($"pointLights[{_index}].constant", Constant); - Material.Shader.SetFloat($"pointLights[{_index}].linear", Linear); - Material.Shader.SetFloat($"pointLights[{_index}].quadratic", Quadratic); + Shader.SetVector3($"pointLights[{_index}].position", (Vector3)Transform.Position); + Shader.SetVector3($"pointLights[{_index}].ambient", Ambient); + Shader.SetVector3($"pointLights[{_index}].diffuse", Diffuse); + Shader.SetVector3($"pointLights[{_index}].specular", Specular); + Shader.SetFloat($"pointLights[{_index}].constant", Constant); + Shader.SetFloat($"pointLights[{_index}].linear", Linear); + Shader.SetFloat($"pointLights[{_index}].quadratic", Quadratic); - var lampMatrix = Matrix4x4.CreateScale((Vector3)Transform.Scale); - lampMatrix *= Matrix4x4.CreateTranslation((Vector3)Transform.Position); + base.SetShaderUniforms(camera); + } - LampShader.Shader?.SetMatrix4(ShaderAttributes.Model, lampMatrix); + /// + public Task Render(CameraView camera, Window window) + { + SetShaderUniforms(camera); return Task.CompletedTask; } diff --git a/SharpEngine.Core/Entities/Lights/SpotLight.cs b/SharpEngine.Core/Entities/Lights/SpotLight.cs index 9b244ed..d26ee73 100644 --- a/SharpEngine.Core/Entities/Lights/SpotLight.cs +++ b/SharpEngine.Core/Entities/Lights/SpotLight.cs @@ -14,7 +14,7 @@ namespace SharpEngine.Core.Entities.Lights; public class SpotLight : Light { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of . /// public SpotLight() { @@ -25,7 +25,7 @@ public SpotLight() Linear = 0.09f; Quadratic = 0.032f; - Material.Shader = ShaderService.Instance.LoadShader(Default.VertexShader, Default.FragmentShader, "lighting"); + Shader = ShaderService.Instance.LoadShader(Default.VertexShader, Default.FragmentShader, "lighting"); } /// @@ -58,19 +58,26 @@ public SpotLight() /// public float Quadratic { get; set; } + protected override void SetShaderUniforms(CameraView camera) + { + Shader.SetVector3("spotLight.position", (Vector3)Transform.Position); + Shader.SetVector3("spotLight.direction", Direction); + Shader.SetVector3("spotLight.ambient", Ambient); + Shader.SetVector3("spotLight.diffuse", Diffuse); + Shader.SetVector3("spotLight.specular", Specular); + Shader.SetFloat("spotLight.constant", Constant); + Shader.SetFloat("spotLight.linear", Linear); + Shader.SetFloat("spotLight.quadratic", Quadratic); + Shader.SetFloat("spotLight.cutOff", CutOff); + Shader.SetFloat("spotLight.outerCutOff", OuterCutOff); + + base.SetShaderUniforms(camera); + } + /// - public override Task Render(CameraView camera, Window window) + public Task Render(CameraView camera, Window window) { - Material.Shader.SetVector3("spotLight.position", (Vector3)Transform.Position); - Material.Shader.SetVector3("spotLight.direction", Direction); - Material.Shader.SetVector3("spotLight.ambient", Ambient); - Material.Shader.SetVector3("spotLight.diffuse", Diffuse); - Material.Shader.SetVector3("spotLight.specular", Specular); - Material.Shader.SetFloat("spotLight.constant", Constant); - Material.Shader.SetFloat("spotLight.linear", Linear); - Material.Shader.SetFloat("spotLight.quadratic", Quadratic); - Material.Shader.SetFloat("spotLight.cutOff", CutOff); - Material.Shader.SetFloat("spotLight.outerCutOff", OuterCutOff); + SetShaderUniforms(camera); return Task.CompletedTask; } diff --git a/SharpEngine.Core/Primitives/Cube.cs b/SharpEngine.Core/Primitives/Cube.cs index 9362991..5a3bbe4 100644 --- a/SharpEngine.Core/Primitives/Cube.cs +++ b/SharpEngine.Core/Primitives/Cube.cs @@ -1,5 +1,6 @@ using SharpEngine.Core.Entities.Properties.Meshes; using SharpEngine.Core.Windowing; +using Tutorial; namespace SharpEngine.Core.Primitives; @@ -8,6 +9,15 @@ namespace SharpEngine.Core.Primitives; /// public static class Cube { + public static Model_Old Model = new Model_Old(Window.GL, string.Empty); + // { + // Vertices = Mesh.Vertices, + // Normals = Mesh.Normals, + // TextureCoordinates = Mesh.TextureCoordinates, + // Indices = Mesh.Indices, + // Textures = new List { _Resources.Default.DebugTexture } + // }; + /// The cube mesh. public static readonly Mesh Mesh = new(Window.GL) { diff --git a/SharpEngine.Core/Primitives/PrimitiveFactory.cs b/SharpEngine.Core/Primitives/PrimitiveFactory.cs index cbcd671..5650cda 100644 --- a/SharpEngine.Core/Primitives/PrimitiveFactory.cs +++ b/SharpEngine.Core/Primitives/PrimitiveFactory.cs @@ -1,8 +1,11 @@ using SharpEngine.Core.Entities; using SharpEngine.Core.Entities.Properties; - +using SharpEngine.Core.Entities.Properties.Meshes; +using SharpEngine.Core.Shaders; using System; +using System.Collections.Generic; using System.Numerics; +using Tutorial; namespace SharpEngine.Core.Primitives; @@ -30,19 +33,21 @@ public static GameObject Create(PrimitiveType primitiveType, Vector3 position) /// Thrown when the specified primitive type does not exist. public static GameObject Create(PrimitiveType primitiveType, Vector3 position, string diffuseMapFile, string? specularMapFile = null, string? vertShaderFile = null, string? fragShaderFile = null) { - var primitive = new GameObject(diffuseMapFile, specularMapFile, vertShaderFile ?? _Resources.Default.VertexShader, fragShaderFile ?? _Resources.Default.FragmentShader) + // var material = diffuseMapFile, specularMapFile, + + // Model_Old model = primitiveType switch + // { + // PrimitiveType.Cube => [Cube.Mesh], + // PrimitiveType.Plane => [Plane.Mesh], + // _ => throw new InvalidOperationException($"A primitive of type {primitiveType} does not exist.") + // }; + + var shader = ShaderService.Instance.LoadShader(vertShaderFile ?? _Resources.Default.VertexShader, fragShaderFile ?? _Resources.Default.FragmentShader, "lighting"); + return new GameObject(shader) { Transform = new Transform { Position = (Numerics.Vector3)position }, - Meshes = primitiveType switch - { - PrimitiveType.Cube => [Cube.Mesh], - PrimitiveType.Plane => [Plane.Mesh], - _ => throw new InvalidOperationException($"A primitive of type {primitiveType} does not exist.") - } - }; - primitive.Initialize(); - return primitive; + }; } } diff --git a/SharpEngine.Core/Renderers/Renderer.cs b/SharpEngine.Core/Renderers/Renderer.cs index 58846dc..d874cdd 100644 --- a/SharpEngine.Core/Renderers/Renderer.cs +++ b/SharpEngine.Core/Renderers/Renderer.cs @@ -5,6 +5,7 @@ using SharpEngine.Core.Scenes; using SharpEngine.Core.Shaders; using SharpEngine.Core.Windowing; +using SharpEngine.Shared; using Silk.NET.OpenGL; using System; @@ -69,32 +70,35 @@ public override Task Render() _camera.SetShaderUniforms(_lightingShader.Shader!); Window.GL.BindVertexArray(_lightingShader.Vao); - var gameObjectRenderTasks = _scene.IterateAsync(_scene.Root.Children, RenderGameObject); - var renderTask = Task.WhenAll(gameObjectRenderTasks); + _scene.Iterate(_scene.Root.Children, RenderGameObject); + //var gameObjectRenderTasks = _scene.Iterate(_scene.Root.Children, RenderGameObject); + //var renderTask = Task.WhenAll(gameObjectRenderTasks); Window.GL.BindVertexArray(_lampShader.Vao); - return renderTask; + return Task.CompletedTask; + //return renderTask; } catch (Exception ex) { - Console.WriteLine(ex); + Debug.Log.Error(ex, "{Message}", ex.Message); return Task.FromException(ex); } } - private Task RenderGameObject(SceneNode node) + private void RenderGameObject(SceneNode node) { if (node is not GameObject gameObject) - return Task.CompletedTask; + return; // Task.CompletedTask; // TODO: #7 Fix culling for blocks that are partially in view // Perform frustum culling if (!IsInViewFrustum(gameObject.BoundingBox, _camera)) - return Task.CompletedTask; + return; // Task.CompletedTask; // TODO: #7 Skip blocks that are behind others relative to the camera - return gameObject.Render(_camera, _window); + //return gameObject.Render(_camera, _window); + gameObject.Render(_camera, _window); } private static bool IsInViewFrustum(BoundingBox boundingBox, CameraView camera) diff --git a/SharpEngine.Core/Renderers/UIRenderer.cs b/SharpEngine.Core/Renderers/UIRenderer.cs index 6c0e29e..0453b51 100644 --- a/SharpEngine.Core/Renderers/UIRenderer.cs +++ b/SharpEngine.Core/Renderers/UIRenderer.cs @@ -4,7 +4,7 @@ using SharpEngine.Core.Scenes; using SharpEngine.Core.Shaders; using SharpEngine.Core.Windowing; - +using SharpEngine.Shared; using Silk.NET.OpenGL; using System; @@ -59,7 +59,7 @@ public override Task Render() } catch (Exception ex) { - Console.WriteLine(ex); + Debug.Log.Error(ex, "{Message}", ex.Message); return Task.FromException(ex); } } diff --git a/SharpEngine.Core/Scenes/Scene.cs b/SharpEngine.Core/Scenes/Scene.cs index 6d84857..e53d524 100644 --- a/SharpEngine.Core/Scenes/Scene.cs +++ b/SharpEngine.Core/Scenes/Scene.cs @@ -1,6 +1,7 @@ using SharpEngine.Core.Entities; using SharpEngine.Core.Entities.Properties; using SharpEngine.Core.Entities.UI; +using SharpEngine.Shared; using System; using System.Collections.Generic; using System.Linq; @@ -182,7 +183,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) { - Console.WriteLine(sceneFile); + Debug.Log.Debug(sceneFile); var loadedScene = JsonSerializer.Deserialize(sceneFile); diff --git a/SharpEngine.Core/Shaders/ShaderBase.cs b/SharpEngine.Core/Shaders/ShaderBase.cs index 6359998..e7fd389 100644 --- a/SharpEngine.Core/Shaders/ShaderBase.cs +++ b/SharpEngine.Core/Shaders/ShaderBase.cs @@ -1,4 +1,5 @@ using SharpEngine.Core.Components.Properties; +using SharpEngine.Shared; using System; namespace SharpEngine.Core.Shaders; @@ -24,7 +25,7 @@ public virtual bool SetAttributes() { if (Shader is null) { - Console.WriteLine("Unable to set shader attributes, shader not found."); + Debug.Log.Error("Unable to set shader attributes, shader not found."); return false; } diff --git a/SharpEngine.Core/Shaders/ShaderService.cs b/SharpEngine.Core/Shaders/ShaderService.cs index bc9f802..ee8f516 100644 --- a/SharpEngine.Core/Shaders/ShaderService.cs +++ b/SharpEngine.Core/Shaders/ShaderService.cs @@ -1,7 +1,8 @@ -using System; -using System.IO; +using System.IO; using System.Collections.Generic; + using SharpEngine.Core.Windowing; +using SharpEngine.Shared; namespace SharpEngine.Core.Shaders; @@ -71,13 +72,13 @@ public Shader LoadShader(string vertPath, string fragPath, string name) if (!File.Exists(vertPath)) { - Console.WriteLine($"Vertex shader file not found: {vertPath}"); + Debug.Log.Information("Vertex shader file not found: {VertPath}", vertPath); throw new FileNotFoundException($"Vertex shader file not found: {vertPath}"); } if (!File.Exists(fragPath)) { - Console.WriteLine($"Fragment shader file not found: {fragPath}"); + Debug.Log.Information("Fragment shader file not found: {FragPath}", fragPath); throw new FileNotFoundException($"Fragment shader file not found: {fragPath}"); } diff --git a/SharpEngine.Core/SharpEngine.Core.csproj b/SharpEngine.Core/SharpEngine.Core.csproj index 005cf46..4d681dc 100644 --- a/SharpEngine.Core/SharpEngine.Core.csproj +++ b/SharpEngine.Core/SharpEngine.Core.csproj @@ -16,10 +16,7 @@ README.md - - - - + diff --git a/SharpEngine.Core/Windowing/Window.cs b/SharpEngine.Core/Windowing/Window.cs index 7a508da..0d2cf12 100644 --- a/SharpEngine.Core/Windowing/Window.cs +++ b/SharpEngine.Core/Windowing/Window.cs @@ -21,6 +21,7 @@ using System.Threading.Tasks; using Shader = SharpEngine.Core.Shaders.Shader; using Silk.NET.GLFW; +using SharpEngine.Shared; namespace SharpEngine.Core.Windowing; @@ -118,7 +119,7 @@ private void InitializeWindow() public override void Run(Action onFrame) { if (!_windowInitialized) - throw new Exception("Window not been initialized for this instance. Try calling 'window.Initialize()' first."); + throw new InvalidOperationException("Window not been initialized for this instance. Try calling 'window.Initialize()' first."); try { @@ -127,7 +128,7 @@ public override void Run(Action onFrame) } catch (Exception ex) { - Debug.LogInformation("Error running window: " + ex.Message, ex); + Debug.Log.Error(ex, "Error running window: {Message}", ex.Message); } } @@ -149,7 +150,7 @@ public override void OnLoad() GL.ClearColor(0.2f, 0.3f, 0.3f, 1.0f); // Load all meshes from the mesh cache - MeshService.Instance.LoadMesh("cube", Primitives.Cube.Mesh); + // MeshService.Instance.LoadMesh("cube", Primitives.Cube.Mesh); // Using reflection, find all renderers that implement the RendererBase. var rendererTypes = AppDomain.CurrentDomain.GetAssemblies() @@ -175,7 +176,7 @@ public override void OnLoad() } catch (Exception ex) { - Debug.LogInformation("Error loading window: " + ex.Message, ex); + Debug.Log.Information(ex, "Error loading window: {Message}", ex.Message); } base.OnLoad(); @@ -216,7 +217,7 @@ protected void RenderFrame(Frame frame) } catch (Exception ex) { - Debug.LogInformation(ex.Message); + Debug.Log.Information(ex.Message); } } @@ -246,7 +247,7 @@ protected void OnUpdateFrame(Frame frame) } if (Settings.PrintFrameRate) - Console.WriteLine($"FPS: {frame.FrameRate}"); + Debug.Log.Information($"FPS: {frame.FrameRate}"); // TODO: #21 Handle multiple mice? var mouse = Input?.Mice[0]; @@ -274,7 +275,7 @@ private void AssignInputEvents() { if (Input is null) { - Debug.LogInformation("Input is null. No input events will be assigned."); + Debug.Log.Information("Input is null. No input events will be assigned."); return; } diff --git a/SharpEngine.Core/_Resources/Shaders/lighting.frag b/SharpEngine.Core/_Resources/Shaders/lighting.frag index 8e2354d..ebd80d6 100644 --- a/SharpEngine.Core/_Resources/Shaders/lighting.frag +++ b/SharpEngine.Core/_Resources/Shaders/lighting.frag @@ -1,3 +1,5 @@ +// Represents a basic forward rendered lighting shader. + #version 330 core #include "Material.glsl" @@ -23,15 +25,18 @@ uniform SpotLight spotLight; void main() { - vec3 norm = normalize(Normal); - vec3 viewDir = normalize(viewPos - FragPos); - - vec3 result = CalcDirLight(dirLight, norm, viewDir); - - for(int i = 0; i < NR_POINT_LIGHTS; i++) - result += CalcPointLight(pointLights[i], norm, FragPos, viewDir); - - result += CalcSpotLight(spotLight, norm, FragPos, viewDir); - FragColor = vec4(result, 1.0); + // vec3 norm = normalize(Normal); + // vec3 viewDir = normalize(viewPos - FragPos); + // + // vec3 result = CalcDirLight(dirLight, norm, viewDir); + // + // for(int i = 0; i < NR_POINT_LIGHTS; i++) + // result += CalcPointLight(pointLights[i], norm, FragPos, viewDir); + // + // result += CalcSpotLight(spotLight, norm, FragPos, viewDir); + // + // FragColor = vec4(result, 1.0); + + FragColor = vec4(1.0); // set all 4 vector values to 1.0 } \ No newline at end of file diff --git a/SharpEngine.Core/_Resources/Shaders/shader.frag b/SharpEngine.Core/_Resources/Shaders/shader.frag index 8170aee..c35339c 100644 --- a/SharpEngine.Core/_Resources/Shaders/shader.frag +++ b/SharpEngine.Core/_Resources/Shaders/shader.frag @@ -8,7 +8,7 @@ out vec4 FragColor; void main() { - FragColor = vec4(1.0); // set all 4 vector values to 1.0 - // FragColor = texture(uTexture0, fUv); + // FragColor = vec4(1.0); // set all 4 vector values to 1.0 + FragColor = texture(uTexture0, fUv); } \ No newline at end of file diff --git a/SharpEngine.Shared/Debug.cs b/SharpEngine.Shared/Debug.cs new file mode 100644 index 0000000..07fa37d --- /dev/null +++ b/SharpEngine.Shared/Debug.cs @@ -0,0 +1,32 @@ +using Serilog; +using Serilog.Events; +using System; + +namespace SharpEngine.Shared; + +/// +/// Contains methods for debugging the application. +/// +public static class Debug +{ + public static ILogger Log; + + private static LogEventLevel _logLevel = LogEventLevel.Information; + + static Debug() + { + SetLogger(); + } + + public static void SetLogger() + => Log = new LoggerConfiguration() + .MinimumLevel.Is(_logLevel) + .WriteTo.Console() + .CreateLogger(); + + public static void SetLogLevel(LogEventLevel logLevel) + { + _logLevel = logLevel; + SetLogger(); + } +} \ No newline at end of file diff --git a/SharpEngine.Shared/SharpEngine.Shared.csproj b/SharpEngine.Shared/SharpEngine.Shared.csproj index fa71b7a..e0034eb 100644 --- a/SharpEngine.Shared/SharpEngine.Shared.csproj +++ b/SharpEngine.Shared/SharpEngine.Shared.csproj @@ -6,4 +6,9 @@ enable + + + + + From 06a7c00c3407642fafa02804c1e489610a91bc3e Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Mon, 21 Apr 2025 17:26:49 +0300 Subject: [PATCH 75/92] #2 Cherrypick --- .../Properties/Meshes/Model_Old.cs | 9 +- SharpEngine.Core/Entities/MeshService.cs | 10 +- SharpEngine.Core/Primitives/Cube.cs | 137 ++++++++++-------- SharpEngine.Core/SharpEngine.Core.csproj | 2 + 4 files changed, 87 insertions(+), 71 deletions(-) diff --git a/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs b/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs index e05c810..5640831 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs @@ -14,12 +14,13 @@ 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, bool gamma = false) + public Model_Old(GL gl, string path) { - var assimp = Assimp.GetApi(); - _assimp = assimp; + _assimp = Assimp.GetApi(); _gl = gl; - LoadModel(path); + + if (!string.IsNullOrWhiteSpace(path)) + LoadModel(path); } private readonly GL _gl; diff --git a/SharpEngine.Core/Entities/MeshService.cs b/SharpEngine.Core/Entities/MeshService.cs index 7e42482..920513a 100644 --- a/SharpEngine.Core/Entities/MeshService.cs +++ b/SharpEngine.Core/Entities/MeshService.cs @@ -30,11 +30,11 @@ public Mesh LoadMesh(string identifier, Mesh mesh) if (Meshes.TryGetValue(identifier, out var cachedMesh)) return cachedMesh; - var meshData = mesh.GetVertices(); - - var vertexBufferObject = Window.GL.GenBuffer(); - Window.GL.BindBuffer(GLEnum.ArrayBuffer, vertexBufferObject); - Window.GL.BufferData(GLEnum.ArrayBuffer, (uint)meshData.Length * sizeof(float), meshData, GLEnum.StaticDraw); + // var meshData = mesh.GetVertices(); + // + // var vertexBufferObject = Window.GL.GenBuffer(); + // Window.GL.BindBuffer(GLEnum.ArrayBuffer, vertexBufferObject); + // Window.GL.BufferData(GLEnum.ArrayBuffer, (uint)meshData.Length * sizeof(float), meshData, GLEnum.StaticDraw); Meshes.Add(identifier, mesh); return mesh; diff --git a/SharpEngine.Core/Primitives/Cube.cs b/SharpEngine.Core/Primitives/Cube.cs index 5a3bbe4..4b86483 100644 --- a/SharpEngine.Core/Primitives/Cube.cs +++ b/SharpEngine.Core/Primitives/Cube.cs @@ -1,4 +1,4 @@ -using SharpEngine.Core.Entities.Properties.Meshes; +using SharpEngine.Core.Entities.Properties.Meshes; using SharpEngine.Core.Windowing; using Tutorial; @@ -9,19 +9,33 @@ namespace SharpEngine.Core.Primitives; /// public static class Cube { - public static Model_Old Model = new Model_Old(Window.GL, string.Empty); - // { - // Vertices = Mesh.Vertices, - // Normals = Mesh.Normals, - // TextureCoordinates = Mesh.TextureCoordinates, - // Indices = Mesh.Indices, - // Textures = new List { _Resources.Default.DebugTexture } - // }; + static Cube() + { + if (_loaded) + return; + + var mesh = new Mesh(Window.GL) + { + Vertices = [.. Vertices], + Normals = [.. Normals], + TextureCoordinates = [.. TextureCoordinates], + Indices = [.. Indices], + }; + + 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 = new(Window.GL) - { - Vertices = + public static readonly Mesh Mesh; + + public static float[] Vertices = [ -0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, @@ -64,52 +78,52 @@ public static class Cube 0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, -0.5f, - ], - 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, - ], - TextureCoordinates = + ]; + 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, @@ -152,8 +166,8 @@ public static class Cube 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f - ], - Indices = + ]; + public static uint[] Indices = [ // Front face 0, 1, 2, @@ -178,6 +192,5 @@ public static class Cube // Bottom face 4, 5, 1, 1, 0, 4 - ] - }; + ]; } diff --git a/SharpEngine.Core/SharpEngine.Core.csproj b/SharpEngine.Core/SharpEngine.Core.csproj index 4d681dc..4a179d4 100644 --- a/SharpEngine.Core/SharpEngine.Core.csproj +++ b/SharpEngine.Core/SharpEngine.Core.csproj @@ -11,6 +11,8 @@ $(AssemblyName).NET + + true README.md From 19c4212b7d25334874db1518b35ec13d2477b162 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Mon, 21 Apr 2025 17:11:56 +0300 Subject: [PATCH 76/92] #2 Tiny cleanup --- .../Properties/Shaders/ShaderExtensions.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs index f7c960e..c2c4e2f 100644 --- a/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs +++ b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs @@ -186,15 +186,15 @@ public bool TryGetAttribLocation(string attribName, out int location) private bool TrySetUniform(string name, T data, Action setter) { - //int location = _gl.GetUniformLocation(Handle, name); if (!_uniformLocations.TryGetValue(name, out int location)) - //if (location == -1) { - Debug.Log.Information($"Uniform '{name}' not found in shader program."); + Debug.Log.Information("Uniform '{Name}' not found in shader program.", name); return false; } + _gl.UseProgram(Handle); setter(location, data); + return true; } @@ -207,7 +207,6 @@ private bool TrySetUniform(string name, T data, Action setter) /// The data to set. public void SetInt(string name, int data) { - _gl.UseProgram(Handle); TrySetUniform(name, data, _gl.Uniform1); } @@ -218,7 +217,6 @@ public void SetInt(string name, int data) /// The data to set. public void SetFloat(string name, float data) { - _gl.UseProgram(Handle); TrySetUniform(name, data, _gl.Uniform1); } @@ -235,7 +233,6 @@ public void SetFloat(string name, float data) /// public unsafe void SetMatrix4(string name, Matrix4x4 data, bool transpose = true) { - _gl.UseProgram(Handle); // TrySetUniform(name, data, (uniform, d) => _gl.UniformMatrix4(uniform, transpose, d.ToSpan())); TrySetUniform(name, data, (uniform, d) => _gl.UniformMatrix4(uniform, 1, transpose, (float*) &d)); } @@ -247,7 +244,6 @@ public unsafe void SetMatrix4(string name, Matrix4x4 data, bool transpose = true /// The data to set. public void SetVector2(string name, Vector2 data) { - _gl.UseProgram(Handle); TrySetUniform(name, data, _gl.Uniform2); } @@ -258,7 +254,6 @@ public void SetVector2(string name, Vector2 data) /// The data to set. public void SetVector3(string name, Vector3 data) { - _gl.UseProgram(Handle); TrySetUniform(name, data, _gl.Uniform3); } @@ -269,7 +264,6 @@ public void SetVector3(string name, Vector3 data) /// The data to set. public void SetVector4(string name, Vector4 data) { - _gl.UseProgram(Handle); TrySetUniform(name, data, _gl.Uniform4); } } From 3b7e4e6fe0b6fdc0e7541d279d9fe4e07cf9a7a4 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Mon, 21 Apr 2025 17:50:50 +0300 Subject: [PATCH 77/92] #2 Shader issue? --- Examples/MinecraftClone/Minecraft.cs | 2 +- .../Properties/Meshes/Model_Old.cs | 73 +++++++++++-------- .../Properties/Shaders/ShaderAttributes.cs | 4 + .../Properties/Shaders/ShaderExtensions.cs | 3 +- SharpEngine.Core/Entities/GameObject.cs | 10 ++- .../Primitives/PrimitiveFactory.cs | 17 ++--- SharpEngine.Core/Renderers/Renderer.cs | 20 ++--- 7 files changed, 73 insertions(+), 56 deletions(-) diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index 29b216d..111f536 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -146,7 +146,7 @@ public void OnAfterRender(Frame frame) private void InitializeWorld() { InitializeLights(); - // InitializeChunks(); + InitializeChunks(); // TODO: #2 Does not work yet. // var torus = MeshService.Instance.LoadMesh("torus", @"C:\Users\antti\Documents\Untitled2.obj"); diff --git a/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs b/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs index 5640831..fa44bd2 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs @@ -1,10 +1,11 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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 Silk.NET.Assimp; using Silk.NET.OpenGL; using System.Numerics; +using static System.Formats.Asn1.AsnWriter; using AssimpMesh = Silk.NET.Assimp.Mesh; using Mesh = SharpEngine.Core.Entities.Properties.Meshes.Mesh; using Texture = SharpEngine.Core.Components.Properties.Textures.Texture; @@ -23,19 +24,28 @@ public Model_Old(GL gl, string path) LoadModel(path); } + public Model_Old(GL gl, Mesh mesh) + { + _assimp = Assimp.GetApi(); + _gl = gl; + + var result = new Mesh(_gl, BuildVertices(mesh.Vertices2), BuildIndices(mesh.Indices.ToList()), new List()); + Meshes.Add(result); + } + private readonly GL _gl; private Assimp _assimp; - private List _texturesLoaded = new List(); + private List _texturesLoaded = []; public string Directory { get; protected set; } = string.Empty; - public List Meshes { get; protected set; } = new List(); + 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 == Silk.NET.Assimp.Assimp.SceneFlagsIncomplete || scene->MRootNode == null) + if (scene == null || scene->MFlags == Assimp.SceneFlagsIncomplete || scene->MRootNode == null) { - var error = _assimp.GetErrorStringS(); + string error = _assimp.GetErrorStringS(); throw new Exception(error); } @@ -46,14 +56,14 @@ private unsafe void LoadModel(string path) private unsafe void ProcessNode(Node* node, Scene* scene) { - for (var i = 0; i < node->MNumMeshes; i++) + for (int i = 0; i < node->MNumMeshes; i++) { var mesh = scene->MMeshes[node->MMeshes[i]]; Meshes.Add(ProcessMesh(mesh, scene)); } - for (var i = 0; i < node->MNumChildren; i++) + for (int i = 0; i < node->MNumChildren; i++) { ProcessNode(node->MChildren[i], scene); } @@ -62,18 +72,20 @@ private unsafe void ProcessNode(Node* node, Scene* scene) private unsafe Mesh ProcessMesh(AssimpMesh* mesh, Scene* scene) { // data to fill - List vertices = new List(); - List indices = new List(); - List textures = new List(); + List vertices = []; + List indices = []; + List textures = []; // walk through each of the mesh's vertices for (uint i = 0; i < mesh->MNumVertices; i++) { - Vertex vertex = new Vertex(); - vertex.BoneIds = new int[Vertex.MAX_BONE_INFLUENCE]; - vertex.Weights = new float[Vertex.MAX_BONE_INFLUENCE]; + var vertex = new Vertex + { + BoneIds = new int[Vertex.MAX_BONE_INFLUENCE], + Weights = new float[Vertex.MAX_BONE_INFLUENCE], - vertex.Position = mesh->MVertices[i]; + Position = mesh->MVertices[i] + }; // normals if (mesh->MNormals != null) @@ -90,7 +102,7 @@ private unsafe Mesh ProcessMesh(AssimpMesh* mesh, Scene* scene) { // 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). - Vector3 texcoord3 = mesh->MTextureCoords[0][i]; + var texcoord3 = mesh->MTextureCoords[0][i]; vertex.TexCoords = new Vector2(texcoord3.X, texcoord3.Y); } @@ -100,14 +112,14 @@ private unsafe Mesh ProcessMesh(AssimpMesh* mesh, Scene* scene) // 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++) { - Face face = mesh->MFaces[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 - Material* material = scene->MMaterials[mesh->MMaterialIndex]; + 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: @@ -116,19 +128,22 @@ private unsafe Mesh ProcessMesh(AssimpMesh* mesh, Scene* scene) // normal: texture_normalN // 1. diffuse maps - var diffuseMaps = LoadMaterialTextures(material, TextureType.Diffuse, "texture_diffuse"); + var diffuseMaps = LoadMaterialTextures(material, TextureType.Diffuse); if (diffuseMaps.Any()) textures.AddRange(diffuseMaps); + // 2. specular maps - var specularMaps = LoadMaterialTextures(material, TextureType.Specular, "texture_specular"); + var specularMaps = LoadMaterialTextures(material, TextureType.Specular); if (specularMaps.Any()) textures.AddRange(specularMaps); + // 3. normal maps - var normalMaps = LoadMaterialTextures(material, TextureType.Height, "texture_normal"); + var normalMaps = LoadMaterialTextures(material, TextureType.Height); if (normalMaps.Any()) textures.AddRange(normalMaps); + // 4. height maps - var heightMaps = LoadMaterialTextures(material, TextureType.Ambient, "texture_height"); + var heightMaps = LoadMaterialTextures(material, TextureType.Ambient); if (heightMaps.Any()) textures.AddRange(heightMaps); @@ -137,10 +152,10 @@ private unsafe Mesh ProcessMesh(AssimpMesh* mesh, Scene* scene) return result; } - private unsafe List LoadMaterialTextures(Material* mat, TextureType type, string typeName) + private unsafe List LoadMaterialTextures(Material* mat, TextureType type) { - var textureCount = _assimp.GetMaterialTextureCount(mat, type); - List textures = new List(); + uint textureCount = _assimp.GetMaterialTextureCount(mat, type); + List textures = []; for (uint i = 0; i < textureCount; i++) { AssimpString path; @@ -165,7 +180,7 @@ private unsafe List LoadMaterialTextures(Material* mat, TextureType typ return textures; } - private float[] BuildVertices(List vertexCollection) + private static float[] BuildVertices(List vertexCollection) { var vertices = new List(); @@ -182,10 +197,7 @@ private float[] BuildVertices(List vertexCollection) return vertices.ToArray(); } - private uint[] BuildIndices(List indices) - { - return indices.ToArray(); - } + private static uint[] BuildIndices(List indices) => indices.ToArray(); public void Dispose() { @@ -194,7 +206,8 @@ public void Dispose() mesh.Dispose(); } - _texturesLoaded = null; + _texturesLoaded = []; + GC.SuppressFinalize(this); } } } \ No newline at end of file diff --git a/SharpEngine.Core.Components/Properties/Shaders/ShaderAttributes.cs b/SharpEngine.Core.Components/Properties/Shaders/ShaderAttributes.cs index f099087..393d9d4 100644 --- a/SharpEngine.Core.Components/Properties/Shaders/ShaderAttributes.cs +++ b/SharpEngine.Core.Components/Properties/Shaders/ShaderAttributes.cs @@ -17,4 +17,8 @@ public static class ShaderAttributes /// Represents the model matrix attribute. public const string Model = "model"; + + public const string View = "uView"; + + public const string Projection = "uProjection"; } diff --git a/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs index c2c4e2f..61564c3 100644 --- a/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs +++ b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs @@ -192,14 +192,13 @@ private bool TrySetUniform(string name, T data, Action setter) return false; } + // TODO: #95 The _gl.UseProgram should be not be called here. Rather the renderer should call it once before rendering. _gl.UseProgram(Handle); setter(location, data); return true; } - // TODO: #95 The _gl.UseProgram should be not be called here. Rather the renderer should call it once before rendering. - /// /// Set a uniform int on this shader. /// diff --git a/SharpEngine.Core/Entities/GameObject.cs b/SharpEngine.Core/Entities/GameObject.cs index e1abd89..4301a92 100644 --- a/SharpEngine.Core/Entities/GameObject.cs +++ b/SharpEngine.Core/Entities/GameObject.cs @@ -10,6 +10,7 @@ using Silk.NET.OpenGL; using Tutorial; +using System.Threading.Tasks; namespace SharpEngine.Core.Entities; @@ -41,8 +42,9 @@ public GameObject(Model_Old model) : base(string.Empty) /// 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) : base(string.Empty) + public GameObject(Shader shader, Model_Old model) : base(string.Empty) { + Model = model; BoundingBox = BoundingBox.CalculateBoundingBox(Transform); Shader = shader; } @@ -83,11 +85,11 @@ protected virtual void SetShaderUniforms(CameraView camera) } /// - public void Render(CameraView camera, Window window) + public Task Render(CameraView camera, Window window) { // TODO: This needs to removed later once fixed. if (Model is null || Model.Meshes is null) - return; + return Task.CompletedTask; foreach (var mesh in Model.Meshes) { @@ -105,6 +107,6 @@ public void Render(CameraView camera, Window window) Window.GL.DrawArrays(PrimitiveType.Triangles, 0, (uint)mesh.Vertices.Length); } - // return Task.CompletedTask; + return Task.CompletedTask; } } diff --git a/SharpEngine.Core/Primitives/PrimitiveFactory.cs b/SharpEngine.Core/Primitives/PrimitiveFactory.cs index 5650cda..633580d 100644 --- a/SharpEngine.Core/Primitives/PrimitiveFactory.cs +++ b/SharpEngine.Core/Primitives/PrimitiveFactory.cs @@ -35,18 +35,17 @@ public static GameObject Create(PrimitiveType primitiveType, Vector3 position, s { // var material = diffuseMapFile, specularMapFile, - // Model_Old model = primitiveType switch - // { - // PrimitiveType.Cube => [Cube.Mesh], - // PrimitiveType.Plane => [Plane.Mesh], - // _ => throw new InvalidOperationException($"A primitive of type {primitiveType} does not exist.") - // }; + Model_Old model = primitiveType switch + { + PrimitiveType.Cube => Cube.Model, + // PrimitiveType.Plane => [Plane.Mesh], + _ => throw new InvalidOperationException($"A primitive of type {primitiveType} does not exist.") + }; var shader = ShaderService.Instance.LoadShader(vertShaderFile ?? _Resources.Default.VertexShader, fragShaderFile ?? _Resources.Default.FragmentShader, "lighting"); - return new GameObject(shader) + return new GameObject(shader, model) { - Transform = new Transform { Position = (Numerics.Vector3)position }, - + Transform = new Transform((Numerics.Vector3)position), }; } diff --git a/SharpEngine.Core/Renderers/Renderer.cs b/SharpEngine.Core/Renderers/Renderer.cs index d874cdd..f80f62d 100644 --- a/SharpEngine.Core/Renderers/Renderer.cs +++ b/SharpEngine.Core/Renderers/Renderer.cs @@ -70,14 +70,14 @@ public override Task Render() _camera.SetShaderUniforms(_lightingShader.Shader!); Window.GL.BindVertexArray(_lightingShader.Vao); - _scene.Iterate(_scene.Root.Children, RenderGameObject); - //var gameObjectRenderTasks = _scene.Iterate(_scene.Root.Children, RenderGameObject); - //var renderTask = Task.WhenAll(gameObjectRenderTasks); + // _scene.Iterate(_scene.Root.Children, RenderGameObject); + var gameObjectRenderTasks = _scene.IterateAsync(_scene.Root.Children, RenderGameObject); + var renderTask = Task.WhenAll(gameObjectRenderTasks); Window.GL.BindVertexArray(_lampShader.Vao); - return Task.CompletedTask; - //return renderTask; + // return Task.CompletedTask; + return renderTask; } catch (Exception ex) { @@ -86,19 +86,19 @@ public override Task Render() } } - private void RenderGameObject(SceneNode node) + private Task RenderGameObject(SceneNode node) { if (node is not GameObject gameObject) - return; // Task.CompletedTask; + return Task.CompletedTask; // TODO: #7 Fix culling for blocks that are partially in view // Perform frustum culling if (!IsInViewFrustum(gameObject.BoundingBox, _camera)) - return; // Task.CompletedTask; + 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 static bool IsInViewFrustum(BoundingBox boundingBox, CameraView camera) From f191534cb5a294db0cd5cc110348ca5cc6e04e2a Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Mon, 21 Apr 2025 18:06:29 +0300 Subject: [PATCH 78/92] #2 A very slow though "working" solution Textures still missing and the framerate is very bad --- Examples/MinecraftClone/Block/BlockBase.cs | 1 - Examples/MinecraftClone/Minecraft.cs | 1 - .../Properties/Meshes/Mesh.cs | 11 ++++---- .../Properties/Meshes/Model_Old.cs | 12 ++++++--- SharpEngine.Core/Primitives/Cube.cs | 2 +- .../_Resources/Shaders/lighting.frag | 26 +++++++++---------- 6 files changed, 27 insertions(+), 26 deletions(-) diff --git a/Examples/MinecraftClone/Block/BlockBase.cs b/Examples/MinecraftClone/Block/BlockBase.cs index eb1ce12..1c62d38 100644 --- a/Examples/MinecraftClone/Block/BlockBase.cs +++ b/Examples/MinecraftClone/Block/BlockBase.cs @@ -56,7 +56,6 @@ private void AssignProperties(GameObject cube, string name) }; Name = name; - // Material = cube.Material; Model = cube.Model; } } diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index 111f536..0443c66 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -160,7 +160,6 @@ private void InitializeWorld() _scene.Root.AddChild(go); _scene.Root.AddChild(go2); - } private void InitializeLights() diff --git a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs index c0989d8..ebcc169 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs @@ -90,18 +90,17 @@ public unsafe void SetupMesh() // TODO: This should use VertexData properties. // TODO: This assumes we only use the vertex position and texture coordinates, it should also support normals. - VAO.VertexAttributePointer(0, 3, VertexAttribPointerType.Float, 5, 0); - VAO.VertexAttributePointer(1, 2, VertexAttribPointerType.Float, 5, 3); + VAO.VertexAttributePointer(0, 3, VertexAttribPointerType.Float, 8, 0); + VAO.VertexAttributePointer(1, 3, VertexAttribPointerType.Float, 8, 3); + VAO.VertexAttributePointer(2, 2, VertexAttribPointerType.Float, 8, 6); } public void Bind() - { - VAO.Bind(); - } + => VAO.Bind(); public void Dispose() { - // Textures = null; + Textures = null; VAO.Dispose(); VBO.Dispose(); EBO.Dispose(); diff --git a/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs b/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs index fa44bd2..d8c2058 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs @@ -2,10 +2,10 @@ // 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 static System.Formats.Asn1.AsnWriter; using AssimpMesh = Silk.NET.Assimp.Mesh; using Mesh = SharpEngine.Core.Entities.Properties.Meshes.Mesh; using Texture = SharpEngine.Core.Components.Properties.Textures.Texture; @@ -26,10 +26,10 @@ public Model_Old(GL gl, string path) public Model_Old(GL gl, Mesh mesh) { - _assimp = Assimp.GetApi(); - _gl = gl; + // _assimp = Assimp.GetApi(); + // _gl = gl; - var result = new Mesh(_gl, BuildVertices(mesh.Vertices2), BuildIndices(mesh.Indices.ToList()), new List()); + var result = new Mesh(gl, mesh.GetVertices(), mesh.Indices, new List()); Meshes.Add(result); } @@ -190,6 +190,10 @@ private static float[] BuildVertices(List vertexCollection) 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); } diff --git a/SharpEngine.Core/Primitives/Cube.cs b/SharpEngine.Core/Primitives/Cube.cs index 4b86483..66599b7 100644 --- a/SharpEngine.Core/Primitives/Cube.cs +++ b/SharpEngine.Core/Primitives/Cube.cs @@ -23,7 +23,7 @@ static Cube() }; Mesh = MeshService.Instance.LoadMesh(nameof(Cube), mesh); - // Model = new(Window.GL, Mesh); + Model = new(Window.GL, Mesh); _loaded = true; } diff --git a/SharpEngine.Core/_Resources/Shaders/lighting.frag b/SharpEngine.Core/_Resources/Shaders/lighting.frag index ebd80d6..b725244 100644 --- a/SharpEngine.Core/_Resources/Shaders/lighting.frag +++ b/SharpEngine.Core/_Resources/Shaders/lighting.frag @@ -26,17 +26,17 @@ uniform SpotLight spotLight; void main() { - // vec3 norm = normalize(Normal); - // vec3 viewDir = normalize(viewPos - FragPos); - // - // vec3 result = CalcDirLight(dirLight, norm, viewDir); - // - // for(int i = 0; i < NR_POINT_LIGHTS; i++) - // result += CalcPointLight(pointLights[i], norm, FragPos, viewDir); - // - // result += CalcSpotLight(spotLight, norm, FragPos, viewDir); - // - // FragColor = vec4(result, 1.0); - - FragColor = vec4(1.0); // set all 4 vector values to 1.0 + vec3 norm = normalize(Normal); + vec3 viewDir = normalize(viewPos - FragPos); + + vec3 result = CalcDirLight(dirLight, norm, viewDir); + + for(int i = 0; i < NR_POINT_LIGHTS; i++) + result += CalcPointLight(pointLights[i], norm, FragPos, viewDir); + + result += CalcSpotLight(spotLight, norm, FragPos, viewDir); + + FragColor = vec4(result, 1.0); + + // FragColor = vec4(1.0); // set all 4 vector values to 1.0 } \ No newline at end of file From 5ba79047d2dd6809f9b477de4ecb09457d1ecae6 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Mon, 21 Apr 2025 21:42:29 +0300 Subject: [PATCH 79/92] #2 Progress! --- Examples/MinecraftClone/Minecraft.cs | 3 ++- .../Properties/Shaders/ShaderAttributes.cs | 2 +- .../Properties/Shaders/ShaderExtensions.cs | 6 +++--- SharpEngine.Core/Entities/GameObject.cs | 8 +++++--- SharpEngine.Core/Entities/Lights/PointLight.cs | 1 - SharpEngine.Core/Entities/Lights/SpotLight.cs | 4 ++-- SharpEngine.Core/Shaders/LightingShader.cs | 4 ++-- SharpEngine.Core/_Resources/Default.cs | 2 +- SharpEngine.Core/_Resources/Shaders/shader.vert | 12 ++++++------ SharpEngine.Core/_Resources/Shaders/uiShader.vert | 8 ++++---- 10 files changed, 26 insertions(+), 24 deletions(-) diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index 0443c66..6c9465c 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -188,7 +188,8 @@ private void InitializeChunks() // TODO: #87 Generate chunks using 3d Perlin noise const int chunkSize = 16; - const int numChunks = 3; + const int numChunks = 1; + // const int numChunks = 3; for (int i = 0; i < numChunks; i++) { diff --git a/SharpEngine.Core.Components/Properties/Shaders/ShaderAttributes.cs b/SharpEngine.Core.Components/Properties/Shaders/ShaderAttributes.cs index 393d9d4..29c14ac 100644 --- a/SharpEngine.Core.Components/Properties/Shaders/ShaderAttributes.cs +++ b/SharpEngine.Core.Components/Properties/Shaders/ShaderAttributes.cs @@ -16,7 +16,7 @@ public static class ShaderAttributes public const int AttributeLocationNotFound = -1; /// Represents the model matrix attribute. - public const string Model = "model"; + public const string Model = "uModel"; public const string View = "uView"; diff --git a/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs index 61564c3..5b265ef 100644 --- a/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs +++ b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs @@ -184,11 +184,11 @@ public bool TryGetAttribLocation(string attribName, out int location) // 2. Get a handle to the location of the uniform with GL.GetUniformLocation. // 3. Use the appropriate GL.Uniform* function to set the uniform. - private bool TrySetUniform(string name, T data, Action setter) + private bool TrySetUniform(string uniformName, T data, Action setter) { - if (!_uniformLocations.TryGetValue(name, out int location)) + if (!_uniformLocations.TryGetValue(uniformName, out int location)) { - Debug.Log.Information("Uniform '{Name}' not found in shader program.", name); + Debug.Log.Information("Uniform '{UniformName}' not found in shader '{ShaderName}'.", uniformName, Name); return false; } diff --git a/SharpEngine.Core/Entities/GameObject.cs b/SharpEngine.Core/Entities/GameObject.cs index 4301a92..160896a 100644 --- a/SharpEngine.Core/Entities/GameObject.cs +++ b/SharpEngine.Core/Entities/GameObject.cs @@ -80,12 +80,14 @@ public override Transform Transform protected virtual void SetShaderUniforms(CameraView camera) { Shader.SetMatrix4(ShaderAttributes.Model, Transform.ModelMatrix); - Shader.SetMatrix4("uView", camera.GetViewMatrix(), false); - Shader.SetMatrix4("uProjection", camera.GetProjectionMatrix(), false); + + // 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 Task Render(CameraView camera, Window window) + public override Task Render(CameraView camera, Window window) { // TODO: This needs to removed later once fixed. if (Model is null || Model.Meshes is null) diff --git a/SharpEngine.Core/Entities/Lights/PointLight.cs b/SharpEngine.Core/Entities/Lights/PointLight.cs index 33fbb14..0522f97 100644 --- a/SharpEngine.Core/Entities/Lights/PointLight.cs +++ b/SharpEngine.Core/Entities/Lights/PointLight.cs @@ -28,7 +28,6 @@ public PointLight(Vector3 position, int index) _index = index; - // Material.Shader = ShaderService.Instance.LoadShader(Default.VertexShader, Default.FragmentShader, "lighting"); LampShader = new LampShader(); } diff --git a/SharpEngine.Core/Entities/Lights/SpotLight.cs b/SharpEngine.Core/Entities/Lights/SpotLight.cs index d26ee73..59ad0fe 100644 --- a/SharpEngine.Core/Entities/Lights/SpotLight.cs +++ b/SharpEngine.Core/Entities/Lights/SpotLight.cs @@ -75,10 +75,10 @@ protected override void SetShaderUniforms(CameraView camera) } /// - public Task Render(CameraView camera, Window window) + public override Task Render(CameraView camera, Window window) { SetShaderUniforms(camera); - + return Task.CompletedTask; } } diff --git a/SharpEngine.Core/Shaders/LightingShader.cs b/SharpEngine.Core/Shaders/LightingShader.cs index 6947bf8..0893499 100644 --- a/SharpEngine.Core/Shaders/LightingShader.cs +++ b/SharpEngine.Core/Shaders/LightingShader.cs @@ -27,7 +27,7 @@ public override bool SetAttributes() if (!base.SetAttributes()) return false; - if (!Shader!.TryGetAttribLocation(ShaderAttributes.Pos, out int positionLocation)) + /*if (!Shader!.TryGetAttribLocation(ShaderAttributes.Pos, out int positionLocation)) return false; var positionLocationUint = (uint)positionLocation; @@ -47,7 +47,7 @@ public override bool SetAttributes() 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/SharpEngine.Core/_Resources/Default.cs b/SharpEngine.Core/_Resources/Default.cs index 24c29a9..ef3e138 100644 --- a/SharpEngine.Core/_Resources/Default.cs +++ b/SharpEngine.Core/_Resources/Default.cs @@ -5,7 +5,7 @@ namespace SharpEngine.Core._Resources; /// /// Contains default resources used by the engine. /// -public struct Default +public static class Default { /// Gets the path to the debug texture. public static string DebugTexture => PathExtensions.GetAssemblyPath("_Resources\\Textures\\debug.JPG"); diff --git a/SharpEngine.Core/_Resources/Shaders/shader.vert b/SharpEngine.Core/_Resources/Shaders/shader.vert index af12da3..b2f7b4a 100644 --- a/SharpEngine.Core/_Resources/Shaders/shader.vert +++ b/SharpEngine.Core/_Resources/Shaders/shader.vert @@ -3,9 +3,9 @@ layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aNormal; layout (location = 2) in vec2 aTexCoords; -uniform mat4 model; -uniform mat4 view; -uniform mat4 projection; +uniform mat4 uModel; +uniform mat4 uView; +uniform mat4 uProjection; out vec3 Normal; out vec3 FragPos; @@ -13,8 +13,8 @@ out vec2 TexCoords; void main() { - gl_Position = vec4(aPos, 1.0) * model * view * projection; - FragPos = vec3(vec4(aPos, 1.0) * model); - Normal = aNormal * mat3(transpose(inverse(model))); + gl_Position = vec4(aPos, 1.0) * uModel * uView * uProjection; + FragPos = vec3(vec4(aPos, 1.0) * uModel); + Normal = aNormal * mat3(transpose(inverse(uModel))); TexCoords = aTexCoords; } \ No newline at end of file diff --git a/SharpEngine.Core/_Resources/Shaders/uiShader.vert b/SharpEngine.Core/_Resources/Shaders/uiShader.vert index 2967764..7787de5 100644 --- a/SharpEngine.Core/_Resources/Shaders/uiShader.vert +++ b/SharpEngine.Core/_Resources/Shaders/uiShader.vert @@ -12,7 +12,7 @@ uniform float rotation; uniform vec2 screenSize; uniform mat4 orthoMatrix; -uniform mat4 model; +uniform mat4 uModel; out vec3 Normal; out vec3 FragPos; @@ -41,7 +41,7 @@ void main() ); // Calculate the model-view-projection matrix using the orthographic projection matrix - mat4 mvp = orthoMatrix * rotationMatrix * model; + mat4 mvp = orthoMatrix * rotationMatrix * uModel; // Apply the MVP matrix to the scaled vertex position with aspect ratio gl_Position = mvp * vec4( @@ -52,7 +52,7 @@ void main() ); // Pass through other attributes - Normal = mat3(model) * aNormal; // Transform the normal - FragPos = vec3(model * vec4(aPos, 1.0)); // Transform the fragment position + Normal = mat3(uModel) * aNormal; // Transform the normal + FragPos = vec3(uModel * vec4(aPos, 1.0)); // Transform the fragment position TexCoords = aTexCoords; } \ No newline at end of file From 06de8eef262d58c877f9fc642c2569d328150572 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Tue, 22 Apr 2025 23:05:07 +0300 Subject: [PATCH 80/92] #2 Pop stash --- SharpEngine.Core/Entities/UI/UIElement.cs | 4 +--- SharpEngine.Core/Primitives/Cube.cs | 3 +++ SharpEngine.Core/Renderers/Renderer.cs | 2 ++ SharpEngine.Core/Renderers/UIRenderer.cs | 8 +++----- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/SharpEngine.Core/Entities/UI/UIElement.cs b/SharpEngine.Core/Entities/UI/UIElement.cs index 80abdd8..4230410 100644 --- a/SharpEngine.Core/Entities/UI/UIElement.cs +++ b/SharpEngine.Core/Entities/UI/UIElement.cs @@ -86,9 +86,7 @@ public void InitializeBuffers(Mesh mesh, bool useMeshVertices = false) /// public override Task Render(CameraView camera, Window window) { - if (_uiShader.Shader is null) - return Task.CompletedTask; - + _uiShader.Shader.Use(); Bind(); // TODO: #75 These should come from somewhere else. diff --git a/SharpEngine.Core/Primitives/Cube.cs b/SharpEngine.Core/Primitives/Cube.cs index 66599b7..0349952 100644 --- a/SharpEngine.Core/Primitives/Cube.cs +++ b/SharpEngine.Core/Primitives/Cube.cs @@ -20,6 +20,9 @@ static Cube() Normals = [.. Normals], TextureCoordinates = [.. TextureCoordinates], Indices = [.. Indices], + Textures = [] //[defaultTexture], + //Materials = [MaterialService.Instance.LoadMaterial(Default.DebugMaterial)], + //Materials = [new(defaultTexture)] }; Mesh = MeshService.Instance.LoadMesh(nameof(Cube), mesh); diff --git a/SharpEngine.Core/Renderers/Renderer.cs b/SharpEngine.Core/Renderers/Renderer.cs index f80f62d..1ceca89 100644 --- a/SharpEngine.Core/Renderers/Renderer.cs +++ b/SharpEngine.Core/Renderers/Renderer.cs @@ -57,7 +57,9 @@ public Renderer(CameraView camera, Window window, ISettings settings, Scene scen /// public override Task Render() { + // TODO: Make toggling these shaders into a hotkey. // return Task.CompletedTask; + try { Window.GL.Enable(EnableCap.DepthTest); diff --git a/SharpEngine.Core/Renderers/UIRenderer.cs b/SharpEngine.Core/Renderers/UIRenderer.cs index 0453b51..2823a24 100644 --- a/SharpEngine.Core/Renderers/UIRenderer.cs +++ b/SharpEngine.Core/Renderers/UIRenderer.cs @@ -18,7 +18,6 @@ namespace SharpEngine.Core.Renderers; public class UIRenderer : RendererBase { private readonly Scene _scene; - private readonly UIShader _uiShader; private readonly CameraView _camera; private readonly Window _window; @@ -31,7 +30,6 @@ public class UIRenderer : RendererBase public UIRenderer(CameraView camera, Window window, ISettings settings, Scene scene) : base(settings) { _scene = scene; - _uiShader = new UIShader(); _camera = camera; _window = window; } @@ -39,8 +37,8 @@ public UIRenderer(CameraView camera, Window window, ISettings settings, Scene sc /// public override Task Render() { - if (_uiShader.Shader is null) - return Task.CompletedTask; + // TODO: Make toggling these shaders into a hotkey. + // return Task.CompletedTask; try { @@ -51,7 +49,7 @@ public override Task Render() Window.GL.Disable(EnableCap.CullFace); // _camera.SetShaderUniforms(_uiShader.Shader!); - _uiShader.Shader?.Use(); + // _uiShader.Shader?.Use(); var uiElementRenderTasks = _scene.IterateAsync(_scene.UIElements, elem => elem.Render(_camera, _window)); From 7f728665aab50fb8a06e6e90c834a15fc093d819 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Tue, 22 Apr 2025 23:06:14 +0300 Subject: [PATCH 81/92] #2 pop stash --- SharpEngine.Core/Primitives/Cube.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/SharpEngine.Core/Primitives/Cube.cs b/SharpEngine.Core/Primitives/Cube.cs index 0349952..2db7033 100644 --- a/SharpEngine.Core/Primitives/Cube.cs +++ b/SharpEngine.Core/Primitives/Cube.cs @@ -1,4 +1,6 @@ +using SharpEngine.Core._Resources; using SharpEngine.Core.Entities.Properties.Meshes; +using SharpEngine.Core.Textures; using SharpEngine.Core.Windowing; using Tutorial; @@ -14,15 +16,17 @@ 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)] + Textures = [defaultTexture], + // Materials = [MaterialService.Instance.LoadMaterial(Default.DebugMaterial)], + // Materials = [new(defaultTexture)] }; Mesh = MeshService.Instance.LoadMesh(nameof(Cube), mesh); From b002bd118478cd015d2f457309d52229eb4d60c3 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Tue, 22 Apr 2025 23:06:50 +0300 Subject: [PATCH 82/92] #2 Cleanup IDisposables --- SharpEngine.Core.Components/Properties/Meshes/Mesh.cs | 2 ++ SharpEngine.Core.Components/Properties/Meshes/Model.cs | 2 ++ .../Properties/Meshes/VertexArrayObject.cs | 1 + .../Properties/Textures/TextureExtensions.cs | 2 +- 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs index ebcc169..0867e7f 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs @@ -104,5 +104,7 @@ public void Dispose() VAO.Dispose(); VBO.Dispose(); EBO.Dispose(); + + GC.SuppressFinalize(this); } } \ No newline at end of file diff --git a/SharpEngine.Core.Components/Properties/Meshes/Model.cs b/SharpEngine.Core.Components/Properties/Meshes/Model.cs index 1a79842..513cf4e 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/Model.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/Model.cs @@ -37,6 +37,8 @@ public void Dispose() { mesh.Dispose(); } + + GC.SuppressFinalize(this); } public Mesh ProcessMesh(Mesh mesh) diff --git a/SharpEngine.Core.Components/Properties/Meshes/VertexArrayObject.cs b/SharpEngine.Core.Components/Properties/Meshes/VertexArrayObject.cs index 11291ab..904fc6a 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/VertexArrayObject.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/VertexArrayObject.cs @@ -34,6 +34,7 @@ public void Bind() public void Dispose() { _gl.DeleteVertexArray(_handle); + GC.SuppressFinalize(this); } } } diff --git a/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs b/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs index 4ab86e3..a060f8c 100644 --- a/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs +++ b/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs @@ -58,6 +58,6 @@ public void Use(TextureUnit unit = TextureUnit.Texture0) public void Dispose() { _gl.DeleteTexture(Handle); + GC.SuppressFinalize(this); } - } From 289dfe5cf289139b88dadb9a18ff878d9fee1bb9 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Tue, 22 Apr 2025 23:11:16 +0300 Subject: [PATCH 83/92] #2 Cleanup --- ObjLoader/Loaders/ObjLoader/ObjLoader.cs | 6 +++--- SharpEngine.Core.Components/Properties/Material.cs | 7 +------ .../Properties/Meshes/BufferObject.cs | 1 + SharpEngine.Core/Entities/MeshService.cs | 13 +------------ SharpEngine.Core/Entities/Views/CameraView.cs | 4 ++-- SharpEngine.Core/Primitives/Cube.cs | 2 +- SharpEngine.Core/Renderers/Renderer.cs | 2 -- SharpEngine.Core/Renderers/UIRenderer.cs | 3 --- 8 files changed, 9 insertions(+), 29 deletions(-) diff --git a/ObjLoader/Loaders/ObjLoader/ObjLoader.cs b/ObjLoader/Loaders/ObjLoader/ObjLoader.cs index 118edba..798bc3c 100644 --- a/ObjLoader/Loaders/ObjLoader/ObjLoader.cs +++ b/ObjLoader/Loaders/ObjLoader/ObjLoader.cs @@ -48,8 +48,8 @@ public List Load(GL gl) var fileStream = new FileStream(_path, FileMode.Open, FileAccess.Read); StartLoad(fileStream); - return new List() - { + return + [ new(gl) { Vertices2 = _dataStore.Vertices, @@ -58,7 +58,7 @@ public List Load(GL gl) Groups = _dataStore.Groups, Materials = _dataStore.Materials } - }; + ]; } } } \ No newline at end of file diff --git a/SharpEngine.Core.Components/Properties/Material.cs b/SharpEngine.Core.Components/Properties/Material.cs index 8d35758..07c21be 100644 --- a/SharpEngine.Core.Components/Properties/Material.cs +++ b/SharpEngine.Core.Components/Properties/Material.cs @@ -13,12 +13,10 @@ public class Material /// /// Initializes a new instance of . /// - /// The shader used to render the 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(Shader shader, Texture diffuseMap, Texture? specularMap = null) + public Material(Texture diffuseMap, Texture? specularMap = null) { - Shader = shader; DiffuseMap = diffuseMap; SpecularMap = specularMap ?? diffuseMap; @@ -53,9 +51,6 @@ public Material(string materialName) /// Gets a value indicating whether the material uses a specular map. public bool UseSpecularMap => SpecularMap.Handle != DiffuseMap.Handle; - /// Gets or sets the shader used to render the material. - public Shader Shader { get; set; } - /// The texture unit for the diffuse map. public const int DIFFUSE_UNIT = 0; diff --git a/SharpEngine.Core.Components/Properties/Meshes/BufferObject.cs b/SharpEngine.Core.Components/Properties/Meshes/BufferObject.cs index efb6340..79fd0be 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/BufferObject.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/BufferObject.cs @@ -31,6 +31,7 @@ public void Bind() public void Dispose() { _gl.DeleteBuffer(_handle); + GC.SuppressFinalize(this); } } } diff --git a/SharpEngine.Core/Entities/MeshService.cs b/SharpEngine.Core/Entities/MeshService.cs index 920513a..99a60a2 100644 --- a/SharpEngine.Core/Entities/MeshService.cs +++ b/SharpEngine.Core/Entities/MeshService.cs @@ -1,9 +1,4 @@ -using SharpEngine.Core.Windowing; -using Silk.NET.OpenGL; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; +using System.Collections.Generic; namespace SharpEngine.Core.Entities.Properties.Meshes; @@ -30,12 +25,6 @@ public Mesh LoadMesh(string identifier, Mesh mesh) if (Meshes.TryGetValue(identifier, out var cachedMesh)) return cachedMesh; - // var meshData = mesh.GetVertices(); - // - // var vertexBufferObject = Window.GL.GenBuffer(); - // Window.GL.BindBuffer(GLEnum.ArrayBuffer, vertexBufferObject); - // Window.GL.BufferData(GLEnum.ArrayBuffer, (uint)meshData.Length * sizeof(float), meshData, GLEnum.StaticDraw); - Meshes.Add(identifier, mesh); return mesh; } diff --git a/SharpEngine.Core/Entities/Views/CameraView.cs b/SharpEngine.Core/Entities/Views/CameraView.cs index c144c85..d98a3ff 100644 --- a/SharpEngine.Core/Entities/Views/CameraView.cs +++ b/SharpEngine.Core/Entities/Views/CameraView.cs @@ -209,8 +209,8 @@ public Plane[] GetFrustumPlanes() /// The shader to set the uniforms on. public override void SetShaderUniforms(Shader shader) { - shader.SetMatrix4("view", GetViewMatrix()); - shader.SetMatrix4("projection", GetProjectionMatrix()); + shader.SetMatrix4(ShaderAttributes.View, GetViewMatrix()); + shader.SetMatrix4(ShaderAttributes.Projection, GetProjectionMatrix()); shader.SetVector3("viewPos", Position); } } \ No newline at end of file diff --git a/SharpEngine.Core/Primitives/Cube.cs b/SharpEngine.Core/Primitives/Cube.cs index 2db7033..16be872 100644 --- a/SharpEngine.Core/Primitives/Cube.cs +++ b/SharpEngine.Core/Primitives/Cube.cs @@ -26,7 +26,7 @@ static Cube() Indices = [.. Indices], Textures = [defaultTexture], // Materials = [MaterialService.Instance.LoadMaterial(Default.DebugMaterial)], - // Materials = [new(defaultTexture)] + Materials = [new(defaultTexture)] }; Mesh = MeshService.Instance.LoadMesh(nameof(Cube), mesh); diff --git a/SharpEngine.Core/Renderers/Renderer.cs b/SharpEngine.Core/Renderers/Renderer.cs index 1ceca89..91f4417 100644 --- a/SharpEngine.Core/Renderers/Renderer.cs +++ b/SharpEngine.Core/Renderers/Renderer.cs @@ -72,13 +72,11 @@ public override Task Render() _camera.SetShaderUniforms(_lightingShader.Shader!); Window.GL.BindVertexArray(_lightingShader.Vao); - // _scene.Iterate(_scene.Root.Children, RenderGameObject); var gameObjectRenderTasks = _scene.IterateAsync(_scene.Root.Children, RenderGameObject); var renderTask = Task.WhenAll(gameObjectRenderTasks); Window.GL.BindVertexArray(_lampShader.Vao); - // return Task.CompletedTask; return renderTask; } catch (Exception ex) diff --git a/SharpEngine.Core/Renderers/UIRenderer.cs b/SharpEngine.Core/Renderers/UIRenderer.cs index 2823a24..54ee5da 100644 --- a/SharpEngine.Core/Renderers/UIRenderer.cs +++ b/SharpEngine.Core/Renderers/UIRenderer.cs @@ -48,9 +48,6 @@ public override Task Render() // Disable face culling to render both sides of the quad Window.GL.Disable(EnableCap.CullFace); - // _camera.SetShaderUniforms(_uiShader.Shader!); - // _uiShader.Shader?.Use(); - var uiElementRenderTasks = _scene.IterateAsync(_scene.UIElements, elem => elem.Render(_camera, _window)); return Task.WhenAll(uiElementRenderTasks); From 57983205e0cce0890a85ed53da23e240a92c59a2 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Tue, 22 Apr 2025 23:16:48 +0300 Subject: [PATCH 84/92] #2 Cleanup --- .../Properties/Shaders/ShaderExtensions.cs | 36 +++++++------------ SharpEngine.Core/Textures/TextureService.cs | 1 - 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs index 5b265ef..0571b71 100644 --- a/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs +++ b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs @@ -204,20 +204,16 @@ private bool TrySetUniform(string uniformName, T data, Action setter) /// /// The name of the uniform. /// The data to set. - public void SetInt(string name, int data) - { - TrySetUniform(name, data, _gl.Uniform1); - } + public bool SetInt(string name, int data) + => TrySetUniform(name, data, _gl.Uniform1); /// /// Set a uniform float on this shader. /// /// The name of the uniform. /// The data to set. - public void SetFloat(string name, float data) - { - TrySetUniform(name, data, _gl.Uniform1); - } + public bool SetFloat(string name, float data) + => TrySetUniform(name, data, _gl.Uniform1); /// /// Set a uniform Matrix4 on this shader @@ -230,39 +226,31 @@ public void SetFloat(string name, float data) /// The matrix is transposed before being sent to the shader unless is set to . /// /// - public unsafe void SetMatrix4(string name, Matrix4x4 data, bool transpose = true) - { + public unsafe bool SetMatrix4(string name, Matrix4x4 data, bool transpose = true) + => TrySetUniform(name, data, (uniform, d) => _gl.UniformMatrix4(uniform, 1, transpose, (float*) &d)); // TrySetUniform(name, data, (uniform, d) => _gl.UniformMatrix4(uniform, transpose, d.ToSpan())); - TrySetUniform(name, data, (uniform, d) => _gl.UniformMatrix4(uniform, 1, transpose, (float*) &d)); - } /// /// Set a uniform Vector2 on this shader. /// /// The name of the uniform. /// The data to set. - public void SetVector2(string name, Vector2 data) - { - TrySetUniform(name, data, _gl.Uniform2); - } + public bool SetVector2(string name, Vector2 data) + => TrySetUniform(name, data, _gl.Uniform2); /// /// Set a uniform Vector3 on this shader. /// /// The name of the uniform. /// The data to set. - public void SetVector3(string name, Vector3 data) - { - TrySetUniform(name, data, _gl.Uniform3); - } + public bool SetVector3(string name, Vector3 data) + => TrySetUniform(name, data, _gl.Uniform3); /// /// Set a uniform Vector3 on this shader. /// /// The name of the uniform. /// The data to set. - public void SetVector4(string name, Vector4 data) - { - TrySetUniform(name, data, _gl.Uniform4); - } + public bool SetVector4(string name, Vector4 data) + => TrySetUniform(name, data, _gl.Uniform4); } diff --git a/SharpEngine.Core/Textures/TextureService.cs b/SharpEngine.Core/Textures/TextureService.cs index 3a71c87..4c40568 100644 --- a/SharpEngine.Core/Textures/TextureService.cs +++ b/SharpEngine.Core/Textures/TextureService.cs @@ -40,7 +40,6 @@ public Texture LoadTexture(string path, TextureType textureType = TextureType.Di // Generate handle var texture = new Texture(Window.GL, path, textureType); - texture.Initialize(); // Add it to the cache _textureCache[path] = texture; From d005e5b18607cb7b8b5e63b69d10540646f1ef93 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Tue, 22 Apr 2025 23:18:06 +0300 Subject: [PATCH 85/92] #2 Pop stash --- SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs b/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs index d8c2058..0f477aa 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs @@ -26,10 +26,7 @@ public Model_Old(GL gl, string path) public Model_Old(GL gl, Mesh mesh) { - // _assimp = Assimp.GetApi(); - // _gl = gl; - - var result = new Mesh(gl, mesh.GetVertices(), mesh.Indices, new List()); + var result = new Mesh(gl, mesh.GetVertices(), mesh.Indices, mesh.Textures.ToList()); Meshes.Add(result); } From ada10e5454af79d93097b3b94d3d41c192a3555b Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Tue, 22 Apr 2025 23:38:36 +0300 Subject: [PATCH 86/92] #2 A few warnings cleanup --- Examples/MinecraftClone/Minecraft.cs | 14 ++--- .../Tutorial 4.1 - Model Loading/Program.cs | 59 +++++++------------ ObjLoader/DataStore.cs | 1 + 3 files changed, 28 insertions(+), 46 deletions(-) diff --git a/Examples/MinecraftClone/Minecraft.cs b/Examples/MinecraftClone/Minecraft.cs index 6c9465c..92494da 100644 --- a/Examples/MinecraftClone/Minecraft.cs +++ b/Examples/MinecraftClone/Minecraft.cs @@ -238,7 +238,7 @@ public override void HandleKeyboard(IKeyboard input, double deltaTime) if (input.IsKeyPressed(Key.Number0 + i)) { _inventory.SetSelectedSlot(i); - Debug.Log.Information($"Selected slot: {i} ({_inventory.SelectedSlot.Items.Type})"); + Debug.Log.Information("Selected slot: {I} ({Type})", i, _inventory.SelectedSlot.Items.Type); } } @@ -258,9 +258,6 @@ private void Input_KeyUp(IKeyboard arg1, Key arg2, int arg3) } } - /// - public override void HandleMouse(IMouse mouse) { } - /// public override void HandleMouseDown(IMouse mouse, MouseButton button) { @@ -276,7 +273,7 @@ public override void HandleMouseDown(IMouse mouse, MouseButton button) } else { - Debug.Log.Information($"No more {_inventory.SelectedSlot.Items.Type}s."); + Debug.Log.Information("No more {Type}s.", _inventory.SelectedSlot.Items.Type); } } @@ -287,7 +284,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}."); + Debug.Log.Information("Block destroyed: {DestroyedBlockType}.", destroyedBlockType); _inventory.AddToolbarItem(destroyedBlockType); } } @@ -316,8 +313,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: {newBlock.Transform.Position}, block in view location: {intersectingObject!.Transform.Position}"); - + Debug.Log.Information("New block created: {Pos}, block in view location: {IntersectingPos}", newBlock.Transform.Position, intersectingObject!.Transform.Position); } private static Vector3 GetNewBlockPosition(Vector3 hitPosition, GameObject intersectingObject) @@ -342,7 +338,7 @@ public override void HandleMouseWheel(MouseWheelScrollDirection direction, Scrol slotIndex = 0; _inventory.SetSelectedSlot(slotIndex); - Debug.Log.Information($"Selected slot: {slotIndex}"); + Debug.Log.Information("Selected slot: {Index}", slotIndex); } } diff --git a/Examples/Tutorial 4.1 - Model Loading/Program.cs b/Examples/Tutorial 4.1 - Model Loading/Program.cs index 3fbfad3..6bede10 100644 --- a/Examples/Tutorial 4.1 - Model Loading/Program.cs +++ b/Examples/Tutorial 4.1 - Model Loading/Program.cs @@ -1,36 +1,34 @@ using ObjLoader.Loaders.ObjLoader; using SharpEngine.Core._Resources; -using SharpEngine.Core.Components.Properties.Textures; using SharpEngine.Core.Extensions; +using Shader = SharpEngine.Core.Shaders.Shader; +using Texture = SharpEngine.Core.Components.Properties.Textures.Texture; + using Silk.NET.Input; using Silk.NET.Maths; using Silk.NET.OpenGL; using Silk.NET.Windowing; + using System; using System.Collections.Generic; -using System.IO; -using System.Linq; using System.Numerics; -using System.Reflection; -using Shader = SharpEngine.Core.Shaders.Shader; -using Texture = SharpEngine.Core.Components.Properties.Textures.Texture; namespace Tutorial { - class Program + public static class Program { #region fields private static IWindow window; private static GL Gl; - private static IKeyboard? primaryKeyboard; + private static IKeyboard primaryKeyboard; private static Texture Texture; private static Shader Shader; private static List Models = []; //Setup the camera's location, directions, and movement speed - private static Vector3 CameraPosition = new Vector3(0.0f, 0.0f, 3.0f); - private static Vector3 CameraFront = new Vector3(0.0f, 0.0f, -1.0f); + private static Vector3 CameraPosition = new(0.0f, 0.0f, 3.0f); + private static Vector3 CameraFront = new(0.0f, 0.0f, -1.0f); private static Vector3 CameraUp = Vector3.UnitY; private static Vector3 CameraDirection = Vector3.Zero; private static float CameraYaw = -90f; @@ -41,7 +39,7 @@ class Program private static Vector2 LastMousePosition; #endregion - private static void Main(string[] args) + private static void Main(string[] _) { var options = WindowOptions.Default; options.Size = new Vector2D(800, 600); @@ -62,7 +60,7 @@ private static void Main(string[] args) private static void OnLoad() { IInputContext input = window.CreateInput(); - primaryKeyboard = input.Keyboards.Count > 0 ? input.Keyboards[0] : null; + primaryKeyboard = input.Keyboards[0]; if (primaryKeyboard != null) primaryKeyboard.KeyDown += KeyDown; @@ -89,26 +87,21 @@ private static unsafe void OnUpdate(double deltaTime) { var moveSpeed = 2.5f * (float) deltaTime; + //Move forwards if (primaryKeyboard.IsKeyPressed(Key.W)) - { - //Move forwards CameraPosition += moveSpeed * CameraFront; - } + + //Move backwards if (primaryKeyboard.IsKeyPressed(Key.S)) - { - //Move backwards CameraPosition -= moveSpeed * CameraFront; - } + + //Move left if (primaryKeyboard.IsKeyPressed(Key.A)) - { - //Move left CameraPosition -= Vector3.Normalize(Vector3.Cross(CameraFront, CameraUp)) * moveSpeed; - } + + //Move right if (primaryKeyboard.IsKeyPressed(Key.D)) - { - //Move right CameraPosition += Vector3.Normalize(Vector3.Cross(CameraFront, CameraUp)) * moveSpeed; - } } private static unsafe void OnRender(double deltaTime) @@ -116,10 +109,6 @@ private static unsafe void OnRender(double deltaTime) Gl.Enable(EnableCap.DepthTest); Gl.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); - // Texture.Use(); - // Shader.Use(); - //Shader.SetInt("uTexture0", 0); - //Use elapsed time to convert to radians to allow our cube to rotate over time var difference = (float) (window.Time * 100); @@ -129,7 +118,7 @@ private static unsafe void OnRender(double deltaTime) Matrix4x4.CreateRotationX(SharpEngine.Core.Math.DegreesToRadians(difference)); var view = Matrix4x4.CreateLookAt(CameraPosition, CameraPosition + CameraFront, CameraUp); - //Note that the apsect ratio calculation must be performed as a float, otherwise integer division will be performed (truncating the result). + //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++) @@ -159,10 +148,7 @@ private static unsafe void RenderModel(Model_Old model, Matrix4x4 modelMatrix, M } } - private static void OnFramebufferResize(Vector2D newSize) - { - Gl.Viewport(newSize); - } + private static void OnFramebufferResize(Vector2D newSize) => Gl.Viewport(newSize); private static unsafe void OnMouseMove(IMouse mouse, Vector2 position) { @@ -190,11 +176,10 @@ private static unsafe void OnMouseMove(IMouse mouse, Vector2 position) } } + //We don't want to be able to zoom in too close or too far away so clamp to these values + private static unsafe void OnMouseWheel(IMouse mouse, ScrollWheel scrollWheel) - { - //We don't want to be able to zoom in too close or too far away so clamp to these values - CameraZoom = Math.Clamp(CameraZoom - scrollWheel.Y, 1.0f, 45f); - } + => CameraZoom = Math.Clamp(CameraZoom - scrollWheel.Y, 1.0f, 45f); private static void OnClose() { diff --git a/ObjLoader/DataStore.cs b/ObjLoader/DataStore.cs index 1bc43c4..5ee2b5c 100644 --- a/ObjLoader/DataStore.cs +++ b/ObjLoader/DataStore.cs @@ -42,6 +42,7 @@ public void PushGroup(string groupName) _groups.Add(_currentGroup); } + /// public void SetMaterial(string materialName) { var material = _materials.SingleOrDefault(x => x.Name.EqualsOrdinalIgnoreCase(materialName)); From db35c6c53917d2f62032b57a9c318aa321ea830b Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sat, 3 May 2025 21:03:27 +0300 Subject: [PATCH 87/92] #2 Try clean reliability ratings --- Examples/MultipleWindows/Program.cs | 32 +++++++++++++----- SharpEngine.Core.Numerics/Float.cs | 9 +++++ SharpEngine.Core.Numerics/IVector.cs | 2 ++ .../Vector2_Intrinsics.cs | 18 +++++----- .../Vector3_Intrinsics.cs | 33 ++++++++----------- SharpEngine.Core/Windowing/Window.cs | 2 +- 6 files changed, 59 insertions(+), 37 deletions(-) create mode 100644 SharpEngine.Core.Numerics/Float.cs diff --git a/Examples/MultipleWindows/Program.cs b/Examples/MultipleWindows/Program.cs index f32735e..788b808 100644 --- a/Examples/MultipleWindows/Program.cs +++ b/Examples/MultipleWindows/Program.cs @@ -6,8 +6,14 @@ using SharpEngine.Core.Entities.Views.Settings; using SharpEngine.Shared; +namespace SharpEngine.Examples.MultipleWindows; + // An example provided a lovely person in this thread: // https://github.com/dotnet/Silk.NET/issues/2436#issuecomment-2752966073 + +/// +/// Represents the main entry point of the application. +/// public static partial class Program { private static readonly List _windows = []; @@ -23,12 +29,23 @@ public static void Main(string[] _) { StartWindowQueueTask(); - while (!_cancellationTokenSource.IsCancellationRequested) + try { - for (int i = 0; i < _windows.Count; i++) - UpdateWindow(ref i); + while (!_cancellationTokenSource.IsCancellationRequested) + { + for (int i = 0; i < _windows.Count; i++) + UpdateWindow(ref i); - DequeueWindows(); + DequeueWindows(); + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + finally + { + _cancellationTokenSource.Dispose(); } } @@ -60,8 +77,8 @@ private static void DequeueWindows() if (_cancellationTokenSource.IsCancellationRequested) return; - while (_windowQueue.TryDequeue(out var options)) - EnqueueWindow(options); + while (_windowQueue.TryDequeue(out var _)) + EnqueueWindow(); } private static void StartWindowQueueTask() @@ -90,14 +107,13 @@ private static SharpEngine.Core.Windowing.Window CreateWindow() } }; - //var window = Window.Create(options); var window = new SharpEngine.Core.Windowing.Window(new(), options); window.Initialize(); return window; } - private static void EnqueueWindow(WindowOptions options) + private static void EnqueueWindow() { var window = CreateWindow(); foreach (var mouse in window!.Input!.Mice) diff --git a/SharpEngine.Core.Numerics/Float.cs b/SharpEngine.Core.Numerics/Float.cs new file mode 100644 index 0000000..333f856 --- /dev/null +++ b/SharpEngine.Core.Numerics/Float.cs @@ -0,0 +1,9 @@ +namespace SharpEngine.Core.Numerics; + +public static class Float +{ + /// + /// Represents a constant value for tolerance set to 1e-6. Used for precision in calculations. + /// + public const float Tolerance = 1e-6f; +} diff --git a/SharpEngine.Core.Numerics/IVector.cs b/SharpEngine.Core.Numerics/IVector.cs index 939cf80..a620e8d 100644 --- a/SharpEngine.Core.Numerics/IVector.cs +++ b/SharpEngine.Core.Numerics/IVector.cs @@ -10,4 +10,6 @@ public interface IVector /// float Y { get; set; } + + public const float Epsilon = 1e-5f; } \ No newline at end of file diff --git a/SharpEngine.Core.Numerics/Vector2_Intrinsics.cs b/SharpEngine.Core.Numerics/Vector2_Intrinsics.cs index 3e56847..093518f 100644 --- a/SharpEngine.Core.Numerics/Vector2_Intrinsics.cs +++ b/SharpEngine.Core.Numerics/Vector2_Intrinsics.cs @@ -47,7 +47,7 @@ public Vector2(float x, float y) /// /// The destination array. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyTo(float[] array) => CopyTo(array, 0); + public readonly void CopyTo(float[] array) => CopyTo(array, 0); /// /// Copies the contents of the vector into the given array, starting from the given index. @@ -60,14 +60,13 @@ public Vector2(float x, float y) public readonly void CopyTo(float[] array, int index) { // Match the JIT's exception type here. For perf, a NullReference is thrown instead of an ArgumentNull. - if (array == null) - throw new NullReferenceException(); + ArgumentNullException.ThrowIfNull(array); if (index < 0 || index >= array.Length) throw new ArgumentOutOfRangeException(nameof(index)); if ((array.Length - index) < 2) - throw new ArgumentException(nameof(index)); + throw new ArgumentException("The given index is outside the supported range.", nameof(index)); array[index] = X; array[index + 1] = Y; @@ -77,9 +76,10 @@ public readonly void CopyTo(float[] array, int index) /// Returns a boolean indicating whether the given Vector2 is equal to this Vector2 instance. /// /// The Vector2 to compare this instance to. - /// True if the other Vector2 is equal to this instance; False otherwise. + /// True if the other Vector2 is approximately equal to this instance; False otherwise. [JitIntrinsic] - public bool Equals(Vector2 other) => X == other.X && Y == other.Y; + public readonly bool Equals(Vector2 other) + => MathF.Abs(X - other.X) < Float.Tolerance && MathF.Abs(Y - other.Y) < Float.Tolerance; #endregion Public Instance Methods @@ -135,7 +135,8 @@ public static Vector2 Max(Vector2 value1, Vector2 value2) /// The absolute value vector. [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 Abs(Vector2 value) => new(MathF.Abs(value.X), MathF.Abs(value.Y)); + public static Vector2 Abs(Vector2 value) + => new(MathF.Abs(value.X), MathF.Abs(value.Y)); /// /// Returns a vector whose elements are the square root of each of the source vector's elements. @@ -144,7 +145,8 @@ public static Vector2 Max(Vector2 value1, Vector2 value2) /// The square root vector. [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 SquareRoot(Vector2 value) => new((float)MathF.Sqrt(value.X), (float)MathF.Sqrt(value.Y)); + public static Vector2 SquareRoot(Vector2 value) + => new(MathF.Sqrt(value.X), MathF.Sqrt(value.Y)); #endregion Public Static Methods diff --git a/SharpEngine.Core.Numerics/Vector3_Intrinsics.cs b/SharpEngine.Core.Numerics/Vector3_Intrinsics.cs index 70f5f06..e747bab 100644 --- a/SharpEngine.Core.Numerics/Vector3_Intrinsics.cs +++ b/SharpEngine.Core.Numerics/Vector3_Intrinsics.cs @@ -74,9 +74,8 @@ public Vector3(float x, float y, float z) public readonly void CopyTo(float[] array, int index) { // Match the JIT's exception type here. For perf, a NullReference is thrown instead of an ArgumentNull. - if (array == null) - throw new NullReferenceException(); - + ArgumentNullException.ThrowIfNull(array); + if (index < 0 || index >= array.Length) throw new ArgumentOutOfRangeException(nameof(index)); @@ -92,14 +91,12 @@ public readonly void CopyTo(float[] array, int index) /// Returns a boolean indicating whether the given Vector3 is equal to this Vector3 instance. /// /// The Vector3 to compare this instance to. - /// True if the other Vector3 is equal to this instance; False otherwise. + /// True if the other Vector3 is approximately equal to this instance; False otherwise. [JitIntrinsic] public readonly bool Equals(Vector3 other) - { - return X == other.X && - Y == other.Y && - Z == other.Z; - } + => MathF.Abs(X - other.X) < Float.Tolerance && + MathF.Abs(Y - other.Y) < Float.Tolerance && + MathF.Abs(Z - other.Z) < Float.Tolerance; #endregion Public Instance Methods @@ -114,11 +111,9 @@ public readonly bool Equals(Vector3 other) [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Dot(Vector3 vector1, Vector3 vector2) - { - return (vector1.X * vector2.X) + - (vector1.Y * vector2.Y) + - (vector1.Z * vector2.Z); - } + => (vector1.X * vector2.X) + + (vector1.Y * vector2.Y) + + (vector1.Z * vector2.Z); /// /// Returns a vector whose elements are the minimum of each of the pairs of elements in the two source vectors. @@ -280,9 +275,9 @@ public static Vector3 SquareRoot(Vector3 value) [JitIntrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Vector3 left, Vector3 right) - => left.X == right.X && - left.Y == right.Y && - left.Z == right.Z; + => Math.Abs(left.X - right.X) < Float.Tolerance && + Math.Abs(left.Y - right.Y) < Float.Tolerance && + Math.Abs(left.Z - right.Z) < Float.Tolerance; /// /// Returns a boolean indicating whether the two given vectors are not equal. @@ -292,9 +287,7 @@ public static Vector3 SquareRoot(Vector3 value) /// True if the vectors are not equal; False if they are equal. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Vector3 left, Vector3 right) - => left.X != right.X || - left.Y != right.Y || - left.Z != right.Z; + => !(left == right); /// /// Converts the SharpEngine representation to a System.Numerics representation. diff --git a/SharpEngine.Core/Windowing/Window.cs b/SharpEngine.Core/Windowing/Window.cs index 0d2cf12..787d9e3 100644 --- a/SharpEngine.Core/Windowing/Window.cs +++ b/SharpEngine.Core/Windowing/Window.cs @@ -320,7 +320,7 @@ protected void OnResize(Vector2D size) GL.Viewport(size); if (size != Vector2D.Zero) - Camera.AspectRatio = size.X / size.Y; + Camera.AspectRatio = (float)size.X / size.Y; } /// From a9d5a2054b0d495f7d242fc7da525ee3e0feef2c Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sat, 3 May 2025 21:23:34 +0300 Subject: [PATCH 88/92] #2 Light cleaning up --- Launcher/UI/Home.razor.cs | 6 +++- .../Properties/Shaders/Shader.cs | 29 +++++++++++++++++-- .../Properties/Shaders/ShaderExtensions.cs | 24 +++++++++------ 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/Launcher/UI/Home.razor.cs b/Launcher/UI/Home.razor.cs index 1a0cfa5..5fe6573 100644 --- a/Launcher/UI/Home.razor.cs +++ b/Launcher/UI/Home.razor.cs @@ -1,6 +1,7 @@ using Launcher.Services; using Launcher.UI.Components; using Microsoft.AspNetCore.Components; + using SharpEngine.Shared.Dto; using System.Diagnostics; using System.Text.Json; @@ -10,6 +11,7 @@ namespace Launcher.UI { /// Represents the home page of the launcher. + [System.Diagnostics.CodeAnalysis.SuppressMessage("Major Code Smell", "S6966:Awaitable method should be used", Justification = "")] public partial class Home : ComponentBase { [Inject] @@ -123,7 +125,7 @@ private async Task OpenExistingFileAsync() if (pickedFile == null) return; - if (pickedFile.FileName.EndsWith(".sharpproject") == false) + if (!pickedFile.FileName.EndsWith(".sharpproject")) { _notificationService.Show("Invalid file type selected. Please select a .sharpproject file."); return; @@ -150,6 +152,8 @@ private void SetProjects(Project project) File.WriteAllText(_projectsFilePath, json); } + // If the user sets the project path as an executable command, this will execute that command. + // In most cases that should be fine as the developer has the launcher installed on their machine, however this still should be resolved soon. private static void OpenInExplorer(string projectPath) => Process.Start("explorer.exe", projectPath); diff --git a/SharpEngine.Core.Components/Properties/Shaders/Shader.cs b/SharpEngine.Core.Components/Properties/Shaders/Shader.cs index a86d829..13aea94 100644 --- a/SharpEngine.Core.Components/Properties/Shaders/Shader.cs +++ b/SharpEngine.Core.Components/Properties/Shaders/Shader.cs @@ -1,5 +1,6 @@ using SharpEngine.Shared; using Silk.NET.OpenGL; +using System.Diagnostics.CodeAnalysis; namespace SharpEngine.Core.Shaders; @@ -9,15 +10,19 @@ namespace SharpEngine.Core.Shaders; public partial class Shader : IDisposable { /// Gets the handle to the shader program. - public uint Handle; + public uint Handle { get; private set; } /// Gets or sets the identifying name of the shader. public string Name { get; set; } + + /// Gets or sets the path to the vertex shader file. public string VertPath { get; set; } + + /// Gets or sets the path to the fragment shader file. public string FragPath { get; set; } private Dictionary _uniformLocations = []; - + private bool disposedValue; private readonly GL _gl; /// @@ -27,6 +32,7 @@ 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 vertex shader full path. /// The fragment shader full path. /// The identifier name of the shader. @@ -51,10 +57,27 @@ public Shader(GL gl, string vertPath, string fragPath, string name) FragPath = fragPath; } + /// + protected virtual void Dispose(bool disposing) + { + if (disposedValue) + return; + + if (disposing) + { + _gl.DeleteProgram(Handle); + Handle = 0; + _uniformLocations.Clear(); + } + + disposedValue = true; + } + /// public void Dispose() { - _gl.DeleteProgram(Handle); + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); GC.SuppressFinalize(this); } } diff --git a/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs index 0571b71..abba04d 100644 --- a/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs +++ b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs @@ -5,8 +5,15 @@ namespace SharpEngine.Core.Shaders; +/// +/// Represents a shader program in the engine. +/// public partial class Shader { + /// + /// Initializes and compiles vertex and fragment shaders into a shader program. + /// + /// The current instance after initialization. public Shader Initialize() { // Load and compile shader @@ -59,7 +66,7 @@ private bool LoadShader(ShaderType shaderType, string shaderPath, out uint shade { if (!File.Exists(shaderPath)) { - Debug.Log.Information($"Shader file not found: {shaderPath}"); + Debug.Log.Information("Shader file not found: {Path}", shaderPath); shader = 0; return false; @@ -74,14 +81,14 @@ private bool LoadShader(ShaderType shaderType, string shaderPath, out uint shade if (!CompileShader(shader)) { - Debug.Log.Information($"Unable to load {shaderType} shader from '{shaderPath}'."); + Debug.Log.Information("Unable to load {Type} shader from '{Path}'.", shaderType, shaderPath); return false; } return true; } - public Shader SetUniformLocations() + private void SetUniformLocations() { // First, we have to get the number of active uniforms in the shader. _gl.GetProgram(Handle, GLEnum.ActiveUniforms, out var numberOfUniforms); @@ -102,18 +109,17 @@ public Shader SetUniformLocations() } _uniformLocations = uniformLocations; - return this; } private static string ProcessIncludes(string shaderCode, string directory) { - string includePattern = @"#include\s+""(.+?)"""; + const string includePattern = @"#include\s+""(.+?)"""; return Regex.Replace(shaderCode, includePattern, match => { string includePath = Path.Combine(directory, match.Groups[1].Value); string includeCode = File.ReadAllText(includePath); return ProcessIncludes(includeCode, Path.GetDirectoryName(includePath)!); - }); + }, RegexOptions.NonBacktracking); } private bool CompileShader(uint shader) @@ -127,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.Information($"Error occurred whilst compiling Shader({shader}).\n\n{infoLog}"); + Debug.Log.Error("Error occurred whilst compiling Shader({Shader}).\n\n{Log}", shader, infoLog); return false; } @@ -143,7 +149,7 @@ private bool LinkProgram(uint program) if (statusCode != (int)GLEnum.True) { string infoLog = _gl.GetProgramInfoLog(program); - Debug.Log.Information($"Error occurred whilst linking Program({program}): {infoLog}"); + Debug.Log.Error("Error occurred whilst linking Program({Program}): {Info}", program, infoLog); return false; } @@ -168,7 +174,7 @@ public bool TryGetAttribLocation(string attribName, out int location) location = _gl.GetAttribLocation(Handle, attribName); if (location == ShaderAttributes.AttributeLocationNotFound) { - Debug.Log.Information($"Attribute '{attribName}' not found in shader program."); + Debug.Log.Warning("Attribute '{Attribute}' not found in shader program.", attribName); return false; } From a516bfd2bb168c2c91d4f5b926461b26b80a97db Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sat, 3 May 2025 21:54:31 +0300 Subject: [PATCH 89/92] #2 Cleanup --- .../Tutorial 4.1 - Model Loading/Program.cs | 10 +- .../Tutorial 4.1 - Model Loading.csproj | 1 - .../Properties/Meshes/BufferObject.cs | 53 +++++--- .../Properties/Meshes/Mesh.cs | 126 ++++++++++++++---- .../Properties/Meshes/VertexArrayObject.cs | 57 ++++++-- .../Properties/Shaders/ShaderExtensions.cs | 6 +- 6 files changed, 196 insertions(+), 57 deletions(-) diff --git a/Examples/Tutorial 4.1 - Model Loading/Program.cs b/Examples/Tutorial 4.1 - Model Loading/Program.cs index 6bede10..1bffe63 100644 --- a/Examples/Tutorial 4.1 - Model Loading/Program.cs +++ b/Examples/Tutorial 4.1 - Model Loading/Program.cs @@ -83,7 +83,7 @@ private static void OnLoad() Models.Add(model); } - private static unsafe void OnUpdate(double deltaTime) + private static void OnUpdate(double deltaTime) { var moveSpeed = 2.5f * (float) deltaTime; @@ -104,7 +104,7 @@ private static unsafe void OnUpdate(double deltaTime) CameraPosition += Vector3.Normalize(Vector3.Cross(CameraFront, CameraUp)) * moveSpeed; } - private static unsafe void OnRender(double deltaTime) + private static void OnRender(double deltaTime) { Gl.Enable(EnableCap.DepthTest); Gl.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); @@ -130,7 +130,7 @@ private static unsafe void OnRender(double deltaTime) } } - private static unsafe void RenderModel(Model_Old model, Matrix4x4 modelMatrix, Matrix4x4 view, Matrix4x4 projection) + private static void RenderModel(Model_Old model, Matrix4x4 modelMatrix, Matrix4x4 view, Matrix4x4 projection) { foreach (var mesh in model.Meshes) { @@ -150,7 +150,7 @@ private static unsafe void RenderModel(Model_Old model, Matrix4x4 modelMatrix, M private static void OnFramebufferResize(Vector2D newSize) => Gl.Viewport(newSize); - private static unsafe void OnMouseMove(IMouse mouse, Vector2 position) + private static void OnMouseMove(IMouse mouse, Vector2 position) { var lookSensitivity = 0.1f; if (LastMousePosition == default) @@ -178,7 +178,7 @@ private static unsafe void OnMouseMove(IMouse mouse, Vector2 position) //We don't want to be able to zoom in too close or too far away so clamp to these values - private static unsafe void OnMouseWheel(IMouse mouse, ScrollWheel scrollWheel) + private static void OnMouseWheel(IMouse mouse, ScrollWheel scrollWheel) => CameraZoom = Math.Clamp(CameraZoom - scrollWheel.Y, 1.0f, 45f); private static void OnClose() diff --git a/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 index 3649e84..079bf1a 100644 --- a/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 @@ -4,7 +4,6 @@ Exe net8.0 Tutorial - true diff --git a/SharpEngine.Core.Components/Properties/Meshes/BufferObject.cs b/SharpEngine.Core.Components/Properties/Meshes/BufferObject.cs index 79fd0be..1279b1d 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/BufferObject.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/BufferObject.cs @@ -1,36 +1,59 @@ using Silk.NET.OpenGL; -using System; +using System.Runtime.InteropServices; -namespace Tutorial +namespace SharpEngine.Core.Components.Properties.Meshes.MeshData { - public class BufferObject : IDisposable - where TDataType : unmanaged + /// + /// Represents a buffer object in OpenGL that manages memory allocation and data transfer for a specific data type. + /// + /// Specifies the type of data stored in the buffer, which must be an unmanaged type for proper memory handling. + public class BufferObject : IDisposable where TDataType : unmanaged { - private uint _handle; - private BufferTargetARB _bufferType; - private GL _gl; + private readonly uint _handle; + private readonly BufferTargetARB _bufferType; + private readonly GL _gl; + private bool disposedValue; - public unsafe BufferObject(GL gl, Span data, BufferTargetARB bufferType) + /// + /// Initializes a new instance of . + /// + /// The OpenGL context where the memory should be allocated. + /// The data buffer. + /// The type of buffer target. + public BufferObject(GL gl, Span data, BufferTargetARB bufferType) { _gl = gl; _bufferType = bufferType; _handle = _gl.GenBuffer(); Bind(); - fixed (void* d = data) - { - _gl.BufferData(bufferType, (nuint) (data.Length * sizeof(TDataType)), d, BufferUsageARB.StaticDraw); - } + + var size = (nuint)(data.Length * Marshal.SizeOf()); + _gl.BufferData(bufferType, size, data, BufferUsageARB.StaticDraw); } - public void Bind() + /// + /// Binds the buffer object. + /// + public void Bind() => _gl.BindBuffer(_bufferType, _handle); + + /// + protected virtual void Dispose(bool disposing) { - _gl.BindBuffer(_bufferType, _handle); + if (disposedValue) + return; + + if (disposing) + _gl.DeleteBuffer(_handle); + + disposedValue = true; } + /// public void Dispose() { - _gl.DeleteBuffer(_handle); + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); GC.SuppressFinalize(this); } } diff --git a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs index 0867e7f..ce22efa 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs @@ -10,49 +10,104 @@ namespace SharpEngine.Core.Entities.Properties.Meshes; /// -/// Represents a game object mesh. +/// 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. /// public class Mesh : IDisposable { - /// Gets or sets a identifying name for the mesh. + private bool disposedValue; + + /// + /// Gets or sets an identifying name for the mesh. + /// public string Name { get; set; } = "New Mesh"; /// - /// Gets or sets the mesh vertices. + /// Gets or sets the mesh vertices as an array of floats. /// [Inspector(DisplayInInspector = false)] public float[] Vertices { get; set; } = []; + + /// + /// Gets or sets the mesh vertices as a list of objects. + /// public List Vertices2 { get; set; } = []; /// - /// Gets or sets the mesh normals. + /// Gets or sets the mesh normals as an array of floats. /// [Inspector(DisplayInInspector = false)] public float[] Normals { get; set; } = []; + + /// + /// Gets or sets the mesh normals as a list of objects. + /// public List Normals2 { get; set; } = []; /// - /// Gets or sets the mesh texture UV coordinates. + /// Gets or sets the mesh texture UV coordinates as an array of floats. /// [Inspector(DisplayInInspector = false)] public float[] TextureCoordinates { get; set; } = []; + /// + /// Gets or sets the mesh texture UV coordinates as a list of objects. + /// public List TextureCoordinates2 { get; set; } = []; /// - /// Gets or sets the indicies of the mesh. + /// Gets or sets the indices of the mesh as an array of unsigned integers. /// [Inspector(DisplayInInspector = false)] public uint[] Indices { get; set; } = []; + /// + /// Gets or sets the groups of faces in the mesh. + /// public List Groups { get; set; } = []; + + /// + /// Gets or sets the materials used by the mesh. + /// public List Materials { get; set; } = []; + /// + /// Gets or sets the textures used by the mesh. + /// public IReadOnlyList Textures { get; set; } + + /// + /// Gets or sets the legacy textures used by the mesh. + /// public IReadOnlyList Textures_Old { get; set; } - // -------------------------------------------------- + /// + /// Gets or sets the Vertex Array Object (VAO) for the mesh. + /// + public VertexArrayObject VAO { get; set; } + + /// + /// Gets or sets the Vertex Buffer Object (VBO) for the mesh. + /// + public BufferObject VBO { get; set; } + /// + /// Gets or sets the Element Buffer Object (EBO) for the mesh. + /// + public BufferObject EBO { get; set; } + + /// + /// Gets the OpenGL context associated with the mesh. + /// + public GL GL { get; } + + /// + /// Initializes a new instance of the class with the specified OpenGL context, vertices, indices, and textures. + /// + /// The OpenGL context. + /// The vertices of the mesh. + /// The indices of the mesh. + /// The textures of the mesh. public Mesh(GL gl, float[] vertices, uint[] indices, List textures) { GL = gl; @@ -62,6 +117,13 @@ public Mesh(GL gl, float[] vertices, uint[] indices, List textures) SetupMesh(); } + /// + /// Initializes a new instance of the class with the specified OpenGL context, vertices, indices, and legacy textures. + /// + /// The OpenGL context. + /// The vertices of the mesh. + /// The indices of the mesh. + /// The legacy textures of the mesh. public Mesh(GL gl, float[] vertices, uint[] indices, List textures) { GL = gl; @@ -71,40 +133,56 @@ public Mesh(GL gl, float[] vertices, uint[] indices, List textures) SetupMesh(); } + /// + /// Initializes a new instance of the class with the specified OpenGL context. + /// + /// The OpenGL context. public Mesh(GL gl) { GL = gl; SetupMesh(); } - public VertexArrayObject VAO { get; set; } - public BufferObject VBO { get; set; } - public BufferObject EBO { get; set; } - public GL GL { get; } - - public unsafe void SetupMesh() + /// + /// Allocates the required memory for the mesh and sets up the Vertex Array Object (VAO), Vertex Buffer Object (VBO), and Element Buffer Object (EBO). + /// + public void SetupMesh() { EBO = new BufferObject(GL, Indices, BufferTargetARB.ElementArrayBuffer); VBO = new BufferObject(GL, Vertices, BufferTargetARB.ArrayBuffer); VAO = new VertexArrayObject(GL, VBO, EBO); - // TODO: This should use VertexData properties. - // TODO: This assumes we only use the vertex position and texture coordinates, it should also support normals. - VAO.VertexAttributePointer(0, 3, VertexAttribPointerType.Float, 8, 0); - VAO.VertexAttributePointer(1, 3, VertexAttribPointerType.Float, 8, 3); - VAO.VertexAttributePointer(2, 2, VertexAttribPointerType.Float, 8, 6); + VAO.VertexAttributePointer(0, VertexData.VerticesSize, VertexAttribPointerType.Float, VertexData.Stride, VertexData.VerticesOffset); + VAO.VertexAttributePointer(1, VertexData.NormalsSize, VertexAttribPointerType.Float, VertexData.Stride, VertexData.NormalsOffset); + VAO.VertexAttributePointer(2, VertexData.TexCoordsSize, VertexAttribPointerType.Float, VertexData.Stride, VertexData.TexCoordsOffset); } + /// + /// Binds the mesh Vertex Array Object (VAO) to the current OpenGL context. + /// public void Bind() => VAO.Bind(); - public void Dispose() + /// + protected virtual void Dispose(bool disposing) { - Textures = null; - VAO.Dispose(); - VBO.Dispose(); - EBO.Dispose(); + if (disposedValue) + return; + if (disposing) + { + VAO.Dispose(); + VBO.Dispose(); + EBO.Dispose(); + } + + disposedValue = true; + } + + /// + public void Dispose() + { + Dispose(disposing: true); GC.SuppressFinalize(this); } -} \ No newline at end of file +} diff --git a/SharpEngine.Core.Components/Properties/Meshes/VertexArrayObject.cs b/SharpEngine.Core.Components/Properties/Meshes/VertexArrayObject.cs index 904fc6a..4ba4ad0 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/VertexArrayObject.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/VertexArrayObject.cs @@ -1,15 +1,27 @@ using Silk.NET.OpenGL; -using System; +using System.Runtime.InteropServices; -namespace Tutorial +namespace SharpEngine.Core.Components.Properties.Meshes.MeshData { + /// + /// Represents a vertex array object for managing vertex and index data in OpenGL. + /// + /// Specifies the type of vertex data used in the vertex array. + /// Specifies the type of index data used for indexing vertices in the vertex array. public class VertexArrayObject : IDisposable where TVertexType : unmanaged where TIndexType : unmanaged { - private uint _handle; - private GL _gl; + private readonly uint _handle; + private readonly GL _gl; + private bool disposedValue; + /// + /// Initializes an instance of . + /// + /// Represents the OpenGL context used for generating and managing the vertex array. + /// Represents the buffer object containing vertex data that will be bound to the vertex array. + /// Represents the buffer object containing index data that will be bound to the vertex array. public VertexArrayObject(GL gl, BufferObject vbo, BufferObject ebo) { _gl = gl; @@ -20,20 +32,47 @@ public VertexArrayObject(GL gl, BufferObject vbo, BufferObject + /// Configures the vertex attribute pointer for rendering. + /// + /// Specifies the index of the vertex attribute to be configured. + /// Indicates the number of components per vertex attribute. + /// Defines the data type of each component in the vertex attribute. + /// Determines the size of each vertex in bytes. + /// Sets the offset in bytes from the start of the vertex data. + public void VertexAttributePointer(uint index, int count, VertexAttribPointerType type, uint vertexSize, int offSet) { - _gl.VertexAttribPointer(index, count, type, false, vertexSize * (uint) sizeof(TVertexType), (void*) (offSet * sizeof(TVertexType))); + var size = Marshal.SizeOf(); + var stride = (uint)(vertexSize * size); + var pointer = (nint)offSet * size; + + _gl.VertexAttribPointer(index, count, type, false, stride, pointer); _gl.EnableVertexAttribArray(index); } - public void Bind() + /// + /// Binds the vertex array object (VAO) to the current OpenGL context. + /// + public void Bind() + => _gl.BindVertexArray(_handle); + + /// + protected virtual void Dispose(bool disposing) { - _gl.BindVertexArray(_handle); + if (disposedValue) + return; + + if (disposing) + _gl.DeleteVertexArray(_handle); + + disposedValue = true; } + /// public void Dispose() { - _gl.DeleteVertexArray(_handle); + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); GC.SuppressFinalize(this); } } diff --git a/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs index abba04d..ff72cef 100644 --- a/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs +++ b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs @@ -232,9 +232,9 @@ public bool SetFloat(string name, float data) /// The matrix is transposed before being sent to the shader unless is set to . /// /// - public unsafe bool SetMatrix4(string name, Matrix4x4 data, bool transpose = true) - => TrySetUniform(name, data, (uniform, d) => _gl.UniformMatrix4(uniform, 1, transpose, (float*) &d)); - // TrySetUniform(name, data, (uniform, d) => _gl.UniformMatrix4(uniform, transpose, d.ToSpan())); + public bool SetMatrix4(string name, Matrix4x4 data, bool transpose = true) + //=> TrySetUniform(name, data, (uniform, d) => _gl.UniformMatrix4(uniform, 1, transpose, (float*) &d)); + => TrySetUniform(name, data, (uniform, d) => _gl.UniformMatrix4(uniform, transpose, d.ToSpan())); /// /// Set a uniform Vector2 on this shader. From f504a85171788d37ccd3725efbb30a6c6c70bb11 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sat, 3 May 2025 21:57:52 +0300 Subject: [PATCH 90/92] #2 Fix --- SharpEngine.Core.Components/Properties/Meshes/Mesh.cs | 10 +++++++--- .../Properties/Shaders/ShaderExtensions.cs | 1 - 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs index ce22efa..e6f66fc 100644 --- a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs +++ b/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs @@ -152,9 +152,13 @@ public void SetupMesh() VBO = new BufferObject(GL, Vertices, BufferTargetARB.ArrayBuffer); VAO = new VertexArrayObject(GL, VBO, EBO); - VAO.VertexAttributePointer(0, VertexData.VerticesSize, VertexAttribPointerType.Float, VertexData.Stride, VertexData.VerticesOffset); - VAO.VertexAttributePointer(1, VertexData.NormalsSize, VertexAttribPointerType.Float, VertexData.Stride, VertexData.NormalsOffset); - VAO.VertexAttributePointer(2, VertexData.TexCoordsSize, VertexAttribPointerType.Float, VertexData.Stride, VertexData.TexCoordsOffset); + VAO.VertexAttributePointer(0, 3, VertexAttribPointerType.Float, 8, 0); + VAO.VertexAttributePointer(1, 3, VertexAttribPointerType.Float, 8, 3); + VAO.VertexAttributePointer(2, 2, VertexAttribPointerType.Float, 8, 6); + + // VAO.VertexAttributePointer(0, VertexData.VerticesSize, VertexAttribPointerType.Float, VertexData.Stride, VertexData.VerticesOffset); + // VAO.VertexAttributePointer(1, VertexData.NormalsSize, VertexAttribPointerType.Float, VertexData.Stride, VertexData.NormalsOffset); + // VAO.VertexAttributePointer(2, VertexData.TexCoordsSize, VertexAttribPointerType.Float, VertexData.Stride, VertexData.TexCoordsOffset); } /// diff --git a/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs index ff72cef..830a2aa 100644 --- a/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs +++ b/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs @@ -233,7 +233,6 @@ public bool SetFloat(string name, float data) /// /// public bool SetMatrix4(string name, Matrix4x4 data, bool transpose = true) - //=> TrySetUniform(name, data, (uniform, d) => _gl.UniformMatrix4(uniform, 1, transpose, (float*) &d)); => TrySetUniform(name, data, (uniform, d) => _gl.UniformMatrix4(uniform, transpose, d.ToSpan())); /// From f0e1deaab4ffb2d2f4275c6a2166483aa175bdc0 Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sat, 6 Dec 2025 15:25:32 +0200 Subject: [PATCH 91/92] #52 gamification (#112) * #52 Modify folder structure * #52 Initial backend project * #52 Initial databases * #52 Temp arch in place --------- Co-authored-by: Antti Veikkolainen --- .../AssetStore.Database.csproj | 26 ++++ .../AssetStore.Database/DatabaseContext.cs | 44 +++++++ .../AssetStore.Database/Models/Asset.cs | 36 ++++++ .../AssetStore.Database/Models/Comment.cs | 14 +++ Asset Store/AssetStore.slnx | 16 +++ Asset Store/AssetStore/AssetStore.Api.csproj | 21 ++++ Asset Store/AssetStore/AssetStore.http | 6 + .../AssetStore/Controllers/AssetController.cs | 112 ++++++++++++++++++ .../Controllers/CommentController.cs | 30 +++++ Asset Store/AssetStore/Program.cs | 23 ++++ .../AssetStore/Properties/launchSettings.json | 23 ++++ .../AssetStore/Services/Asset/AssetService.cs | 88 ++++++++++++++ .../Services/Asset/IAssetService.cs | 17 +++ .../AssetStore/appsettings.Development.json | 8 ++ Asset Store/AssetStore/appsettings.json | 9 ++ Asset Store/Directory.Build.props | 0 Asset Store/Readme.md | 0 .../AssetStore.Api.Tests.csproj | 9 ++ .../Controllers/AssetControllerTests.cs | 9 ++ .../Controllers/CommentControllerTests.cs | 9 ++ .../Services/AssetServiceTests.cs | 9 ++ .../Services/CommentServiceTests.cs | 9 ++ Asset Store/Tests/Directory.Build.props | 0 .editorconfig => Engine/.editorconfig | 0 .../Directory.Build.props | 0 {Editor => Engine/Editor}/EditorSettings.cs | 0 {Editor => Engine/Editor}/EditorWindow.cs | 0 {Editor => Engine/Editor}/Program.cs | 0 .../Editor}/SharpEngine.Editor.csproj | 0 .../Editor}/SharpEngine.Editor.sln | 0 .../Editor}/Windows/ActionsMenuWindow.cs | 0 .../Editor}/Windows/AssetsWindow.cs | 0 .../Editor}/Windows/ContextMenuWindow.cs | 0 .../Editor}/Windows/ImGuiWindowBase.cs | 0 .../Editor}/Windows/PropertiesWindow.cs | 0 .../Editor}/Windows/SceneWindow.cs | 0 .../MinecraftClone/Block/BlockBase.cs | 0 .../Examples}/MinecraftClone/Block/Dirt.cs | 0 .../Examples}/MinecraftClone/Block/Stone.cs | 0 .../Examples}/MinecraftClone/BlockFactory.cs | 0 .../Examples}/MinecraftClone/Input.cs | 0 .../Examples}/MinecraftClone/Inventory.cs | 0 .../Examples}/MinecraftClone/Minecraft.cs | 0 .../Examples}/MinecraftClone/Minecraft.csproj | 0 .../Examples}/MinecraftClone/Minecraft.sln | 0 .../Examples}/MinecraftClone/Program.cs | 0 .../MinecraftClone/Resources/container2.png | Bin .../Resources/container2_specular.png | Bin .../MinecraftClone/Resources/grass.jpg | Bin .../Examples}/Minimal/Minimal.csproj | 0 .../Examples}/Minimal/Minimal.sln | 0 .../Examples}/Minimal/Program.cs | 0 .../MultipleWindows/MultipleWindows.csproj | 0 .../Examples}/MultipleWindows/Program.cs | 0 .../Tutorial 4.1 - Model Loading/Program.cs | 0 .../Tutorial 4.1 - Model Loading.csproj | 0 .../Tutorial 4.1 - Model Loading/shader2.vert | 0 .../Tutorial 4.1 - Model Loading/silk.png | Bin {Launcher => Engine/Launcher}/App.xaml | 0 {Launcher => Engine/Launcher}/App.xaml.cs | 0 .../Launcher}/Attributes/FileAttribute.cs | 0 .../Launcher}/Enums/SvgIcon.cs | 0 {Launcher => Engine/Launcher}/Launcher.csproj | 0 {Launcher => Engine/Launcher}/Launcher.sln | 0 {Launcher => Engine/Launcher}/MainPage.xaml | 0 .../Launcher}/MainPage.xaml.cs | 0 {Launcher => Engine/Launcher}/MauiProgram.cs | 0 .../Platforms/Android/AndroidManifest.xml | 0 .../Platforms/Android/MainActivity.cs | 0 .../Platforms/Android/MainApplication.cs | 0 .../Android/Resources/values/colors.xml | 0 .../Platforms/MacCatalyst/AppDelegate.cs | 0 .../Platforms/MacCatalyst/Entitlements.plist | 0 .../Platforms/MacCatalyst/Info.plist | 0 .../Platforms/MacCatalyst/Program.cs | 0 .../Launcher}/Platforms/Tizen/Main.cs | 0 .../Platforms/Tizen/tizen-manifest.xml | 0 .../Launcher}/Platforms/Windows/App.xaml | 0 .../Launcher}/Platforms/Windows/App.xaml.cs | 0 .../Platforms/Windows/Package.appxmanifest | 0 .../Launcher}/Platforms/Windows/app.manifest | 0 .../Launcher}/Platforms/iOS/AppDelegate.cs | 0 .../Launcher}/Platforms/iOS/Info.plist | 0 .../Launcher}/Platforms/iOS/Program.cs | 0 .../iOS/Resources/PrivacyInfo.xcprivacy | 0 .../Launcher}/Properties/launchSettings.json | 0 .../Launcher}/Resources/AppIcon/appicon.svg | 0 .../Launcher}/Resources/AppIcon/appiconfg.svg | 0 .../Launcher}/Resources/AppIcon/icon.ico | Bin .../Launcher}/Resources/AppIcon/icon.png | Bin .../Launcher}/Resources/AppIcon/icon.svg | 0 .../Resources/Fonts/OpenSans-Regular.ttf | Bin .../Launcher}/Resources/Images/dotnet_bot.svg | 0 .../Launcher}/Resources/Raw/AboutAssets.txt | 0 .../Launcher}/Resources/Splash/splash.svg | 0 .../Launcher}/Services/EditorService.cs | 0 .../Launcher}/Services/NotificationService.cs | 0 .../Launcher}/TestData/TestData.cs | 0 .../Launcher}/UI/Components/ContextMenu.razor | 0 .../UI/Components/ContextMenu.razor.css | 0 .../UI/Components/ContextMenu.razor.min.css | 0 .../UI/Components/ContextMenu.razor.scss | 0 .../Dialogs/ConfirmDeleteDialog.razor | 0 .../Dialogs/ConfirmDeleteDialog.razor.css | 0 .../Dialogs/ConfirmDeleteDialog.razor.min.css | 0 .../Dialogs/ConfirmDeleteDialog.razor.scss | 0 .../Dialogs/CreateProjectDialog.razor | 0 .../Dialogs/CreateProjectDialog.razor.cs | 0 .../Dialogs/CreateProjectDialog.razor.css | 0 .../Dialogs/CreateProjectDialog.razor.min.css | 0 .../Dialogs/CreateProjectDialog.razor.scss | 0 .../UI/Components/Dialogs/DialogBase.cs | 0 .../UI/Components/Flyouts/Flyout.razor | 0 .../UI/Components/Flyouts/Flyout.razor.css | 0 .../Components/Flyouts/Flyout.razor.min.css | 0 .../UI/Components/Flyouts/Flyout.razor.scss | 0 .../UI/Components/Flyouts/FlyoutBase.cs | 0 .../Components/Flyouts/SettingsFlyout.razor | 0 .../Launcher}/UI/Components/Grid/Grid.razor | 0 .../UI/Components/Grid/Grid.razor.css | 0 .../UI/Components/Grid/Grid.razor.min.css | 0 .../UI/Components/Grid/Grid.razor.scss | 0 .../UI/Components/Grid/GridHeader.cs | 0 .../UI/Components/Grid/GridHeader.razor | 0 .../UI/Components/Grid/GridHeader.razor.css | 0 .../Components/Grid/GridHeader.razor.min.css | 0 .../UI/Components/Grid/GridHeader.razor.scss | 0 .../UI/Components/Grid/GridRow.razor | 0 .../UI/Components/Icons/DiscardIcon.razor | 0 .../Launcher}/UI/Components/Icons/Icon.razor | 0 .../Launcher}/UI/Components/Layout.razor | 0 .../Launcher}/UI/Components/Layout.razor.css | 0 .../UI/Components/Layout.razor.min.css | 0 .../Launcher}/UI/Components/Layout.razor.scss | 0 .../Components/Navigation/SideBarItem.razor | 0 .../Navigation/SideBarItem.razor.css | 0 .../Navigation/SideBarItem.razor.min.css | 0 .../Navigation/SideBarItem.razor.scss | 0 .../UI/Components/Navigation/Sidebar.razor | 0 .../Components/Navigation/Sidebar.razor.css | 0 .../Navigation/Sidebar.razor.min.css | 0 .../Components/Navigation/Sidebar.razor.scss | 0 .../Notification/Notification.razor | 0 .../Notification/Notification.razor.css | 0 .../Notification/Notification.razor.min.css | 0 .../Notification/Notification.razor.scss | 0 .../Notification/NotificationType.cs | 0 .../NotificationTypeExtensions.cs | 0 .../Launcher}/UI/Components/Searchbox.razor | 0 .../UI/Components/Searchbox.razor.css | 0 .../UI/Components/Searchbox.razor.min.css | 0 .../UI/Components/Searchbox.razor.scss | 0 {Launcher => Engine/Launcher}/UI/Home.razor | 0 .../Launcher}/UI/Home.razor.cs | 0 .../Launcher}/UI/Home.razor.css | 0 .../Launcher}/UI/Home.razor.min.css | 0 .../Launcher}/UI/Home.razor.scss | 0 {Launcher => Engine/Launcher}/UI/Routes.razor | 0 .../Launcher}/UI/_Imports.razor | 0 .../Launcher}/compilerconfig.json | 0 .../Launcher}/compilerconfig.json.defaults | 0 .../Launcher}/wwwroot/css/additional.css | 0 .../Launcher}/wwwroot/css/additional.min.css | 0 .../Launcher}/wwwroot/css/additional.scss | 0 .../Launcher}/wwwroot/css/app.css | 0 .../wwwroot/css/bootstrap/bootstrap.min.css | 0 .../css/bootstrap/bootstrap.min.css.map | 0 .../Launcher}/wwwroot/favicon.png | Bin .../Launcher}/wwwroot/index.html | 0 {ObjLoader => Engine/ObjLoader}/DataStore.cs | 0 .../ObjLoader}/Loaders/LoaderBase.cs | 0 .../IMaterialLibraryLoaderFacade.cs | 0 .../MaterialLoader/MaterialLibraryLoader.cs | 0 .../MaterialLibraryLoaderFacade.cs | 0 .../ObjLoader}/Loaders/ObjLoader/ObjLoader.cs | 0 .../Loaders/ObjLoader/ObjLoaderFactory.cs | 0 .../SharpEngine.Core.ObjLoader.csproj | 0 .../ObjLoader}/TypeParsers/FaceParser.cs | 0 .../ObjLoader}/TypeParsers/GroupParser.cs | 0 .../ObjLoader}/TypeParsers/ITypeParser.cs | 0 .../TypeParsers/MaterialLibraryParser.cs | 0 .../ObjLoader}/TypeParsers/NormalParser.cs | 0 .../ObjLoader}/TypeParsers/TextureParser.cs | 0 .../ObjLoader}/TypeParsers/TypeParserBase.cs | 0 .../TypeParsers/UseMaterialParser.cs | 0 .../ObjLoader}/TypeParsers/VertexParser.cs | 0 .../Resources}/Screenshots/editor.png | Bin .../Resources}/Screenshots/launcher.png | Bin {Resources => Engine/Resources}/icon.ico | Bin {Resources => Engine/Resources}/icon.png | Bin {Resources => Engine/Resources}/icon.svg | 0 {Resources => Engine/Resources}/icon.xcf | Bin .../IComponent.cs | 0 .../ObjLoader/DataStore/IFaceGroup.cs | 0 .../ObjLoader/DataStore/IGroupDataStore.cs | 0 .../ObjLoader/DataStore/IMaterialLibrary.cs | 0 .../ObjLoader/DataStore/INormalDataStore.cs | 0 .../ObjLoader/DataStore/ITextureDataStore.cs | 0 .../ObjLoader/DataStore/IVertexDataStore.cs | 0 .../Properties/BoundingBox.cs | 0 .../Properties/ITransform.cs | 0 .../Properties/Material.cs | 0 .../Properties/Meshes/BufferObject.cs | 0 .../Properties/Meshes/Mesh.cs | 0 .../Properties/Meshes/MeshData/Face.cs | 0 .../Properties/Meshes/MeshData/Group.cs | 0 .../Properties/Meshes/MeshData/Normal.cs | 0 .../Meshes/MeshData/TextureCoordinate.cs | 0 .../Properties/Meshes/MeshData/Vertex.cs | 0 .../Properties/Meshes/MeshExtensions.cs | 0 .../Properties/Meshes/Model.cs | 0 .../Properties/Meshes/Model_Old.cs | 0 .../Properties/Meshes/ObjMeshData.cs | 0 .../Properties/Meshes/VertexArrayObject.cs | 0 .../Properties/Meshes/VertexData.cs | 0 .../Properties/Quaternion.cs | 0 .../Properties/Shaders/Shader.cs | 0 .../Properties/Shaders/ShaderAttributes.cs | 0 .../Properties/Shaders/ShaderExtensions.cs | 0 .../Properties/Textures/Texture.cs | 0 .../Properties/Textures/TextureExtensions.cs | 0 .../Properties/Transform.cs | 0 .../Properties/Transform2D.cs | 0 .../SharpEngine.Core.Components.csproj | 0 .../SharpEngine.Core.Numerics}/Float.cs | 0 .../HashCodeHelper.cs | 0 .../SharpEngine.Core.Numerics}/IVector.cs | 0 .../JitIntrinsicAttribute.cs | 0 .../SharpEngine.Core.Numerics.csproj | 0 .../SharpEngine.Core.Numerics}/Vector2.cs | 0 .../Vector2_Intrinsics.cs | 0 .../SharpEngine.Core.Numerics}/Vector3.cs | 0 .../Vector3_Intrinsics.cs | 0 .../SharpEngine.Core}/Abstractions/IGame.cs | 0 .../Abstractions/IRenderable.cs | 0 .../Abstractions/ISettings.cs | 0 .../SharpEngine.Core}/Audio/Audio.cs | 0 .../SharpEngine.Core}/Audio/AudioBuffer.cs | 0 .../SharpEngine.Core}/Audio/AudioDevice.cs | 0 .../Audio/AudioFileExtensions.cs | 0 .../Audio/AudioPlayerBase.cs | 0 .../Audio/AudioProperties.cs | 0 .../SharpEngine.Core}/Audio/AudioSource.cs | 0 .../SharpEngine.Core}/Audio/WavData.cs | 0 .../SharpEngine.Core}/Audio/WavPlayer.cs | 0 .../SharpEngine.Core}/Entities/BezierCurve.cs | 0 .../SharpEngine.Core}/Entities/GameObject.cs | 0 .../Entities/Lights/DirectionalLight.cs | 0 .../Entities/Lights/Light.cs | 0 .../Entities/Lights/PointLight.cs | 0 .../Entities/Lights/SpotLight.cs | 0 .../SharpEngine.Core}/Entities/MeshService.cs | 0 .../Entities/UI/Layouts/FlexLayout.cs | 0 .../Entities/UI/Layouts/GridLayout.cs | 0 .../Entities/UI/Layouts/LayoutBase.cs | 0 .../Entities/UI/UIElement.cs | 0 .../Entities/Views/CameraView.cs | 0 .../Views/Settings/DefaultViewSettings.cs | 0 .../Entities/Views/Settings/IViewSettings.cs | 0 .../Entities/Views/Settings/ViewSettings.cs | 0 .../SharpEngine.Core}/Entities/Views/View.cs | 0 .../Enums/MouseWheelScrollDirection.cs | 0 .../Extensions/CollectionExtensions.cs | 0 .../Extensions/PathExtensions.cs | 0 .../SharpEngine.Core}/Primitives/Cube.cs | 0 .../SharpEngine.Core}/Primitives/Plane.cs | 0 .../Primitives/PrimitiveFactory.cs | 0 .../Primitives/PrimitiveType.cs | 0 .../SharpEngine.Core}/Ray.cs | 0 .../Renderers/RenderFlags.cs | 0 .../SharpEngine.Core}/Renderers/Renderer.cs | 0 .../Renderers/RendererBase.cs | 0 .../Renderers/TextRenderer.cs | 0 .../SharpEngine.Core}/Renderers/UIRenderer.cs | 0 .../SharpEngine.Core}/Scenes/Scene.cs | 0 .../SharpEngine.Core}/Scenes/SceneNode.cs | 0 .../SharpEngine.Core}/Shaders/LampShader.cs | 0 .../Shaders/LightingShader.cs | 0 .../SharpEngine.Core}/Shaders/ShaderBase.cs | 0 .../Shaders/ShaderService.cs | 0 .../SharpEngine.Core}/Shaders/UIShader.cs | 0 .../SharpEngine.Core}/SharpEngine.Core.csproj | 0 .../Textures/TextureService.cs | 0 .../SharpEngine.Core}/Windowing/Frame.cs | 0 .../SharpEngine.Core}/Windowing/SilkWindow.cs | 0 .../SharpEngine.Core}/Windowing/Window.cs | 0 .../SharpEngine.Core}/_Resources/Default.cs | 0 .../Shaders/Light/DirectionalLight.glsl | 0 .../_Resources/Shaders/Light/PointLight.glsl | 0 .../_Resources/Shaders/Light/SpotLight.glsl | 0 .../_Resources/Shaders/Material.glsl | 0 .../_Resources/Shaders/lighting.frag | 0 .../_Resources/Shaders/shader.frag | 0 .../_Resources/Shaders/shader.vert | 0 .../_Resources/Shaders/shader2.vert | 0 .../_Resources/Shaders/uiShader.frag | 0 .../_Resources/Shaders/uiShader.vert | 0 .../_Resources/Textures/debug.jpg | Bin .../SharpEngine.Core}/_Resources/icon.png | Bin .../Clients/AssetStoreClient.cs | 12 ++ .../Clients/IAssetStoreClient.cs | 8 ++ .../SharpEngine.Rest/Clients/IPortalClient.cs | 5 + .../SharpEngine.Rest/Clients/PortalClient.cs | 12 ++ Engine/SharpEngine.Rest/Clients/RestClient.cs | 28 +++++ .../SharpEngine.Rest/SharpEngine.Rest.csproj | 13 ++ Engine/SharpEngine.Rest/Urls/AssetStore.cs | 7 ++ Engine/SharpEngine.Rest/Urls/Portal.cs | 6 + Engine/SharpEngine.Shared/AssetType.cs | 8 ++ .../Attributes/FilterAttribute.cs | 0 .../Attributes/InspectorAttribute.cs | 0 .../SharpEngine.Shared}/Debug.cs | 0 .../Dto/AssetStore/AssetDto.cs | 33 ++++++ .../Dto/AssetStore/CommentDto.cs | 11 ++ .../Dto/Primitives/AssetId.cs | 8 ++ .../Dto/Primitives/CommentId.cs | 8 ++ .../Dto/Primitives/UserId.cs | 8 ++ .../SharpEngine.Shared}/Dto/Project.cs | 0 .../SharpEngine.Shared}/Dto/UserProfile.cs | 0 .../SharpEngine.Shared}/Enums/FilterMode.cs | 0 .../EnvironmentVariables.cs | 0 .../Extensions/OrderedEnumerableExtensions.cs | 0 .../Extensions/ProcessExtensions.cs | 0 .../Extensions/ReflectionExtensions.cs | 0 .../Extensions/StringExtensions.cs | 0 .../SharpEngine.Shared}/Math.cs | 0 .../NaturalStringComparer.cs | 0 .../SharpEngine.Shared.csproj | 0 SharpEngine.sln => Engine/SharpEngine.sln | 8 ++ SharpEngine.slnx => Engine/SharpEngine.slnx | 0 .../Loaders/MaterialLibraryLoaderTests.cs | 0 .../ObjLoader.Test/Loaders/ObjLoaderTests.cs | 0 .../ObjLoader.Test/ObjLoader.Tests.csproj | 0 .../TypeParsers/FaceParserTests.cs | 0 .../TypeParsers/GroupParserTests.cs | 0 .../TypeParsers/MaterialLibraryParserTests.cs | 0 .../TypeParsers/NormalParserTests.cs | 0 .../TypeParsers/TextureParserTests.cs | 0 .../TypeParsers/UseMaterialParserTests.cs | 0 .../TypeParsers/VertexParserTests.cs | 0 .../Tests}/SharpEngine.Core.Tests/Class1.cs | 0 .../SharpEngine.Core.Tests.csproj | 0 .../Tests}/SharpEngine.Editor.Tests/Class1.cs | 0 .../SharpEngine.Editor.Tests.csproj | 0 .../Tests}/SharpEngine.Shared.Net8/Class1.cs | 0 .../SharpEngine.Shared.Net8.csproj | 0 .../Tests}/SharpEngine.Shared.Tests/Class1.cs | 0 .../SharpEngine.Shared.Tests.csproj | 0 .../Tests}/Test.Directory.Build.props | 0 {docs => Engine/docs}/CODE_OF_CONDUCT.md | 0 {docs => Engine/docs}/CONTRIBUTING.md | 0 {docs => Engine/docs}/SECURITY.md | 0 .../docs}/materials_and_inspiration.md | 0 .../docs}/pull_request_template.md | 0 .../Controllers/AchievementController.cs | 23 ++++ .../Controllers/UserController.cs | 23 ++++ Portal/Portal.Backend/Database.http | 6 + Portal/Portal.Backend/Portal.Backend.csproj | 17 +++ Portal/Portal.Backend/Program.cs | 23 ++++ .../Properties/launchSettings.json | 23 ++++ .../Services/AchievementService.cs | 5 + .../appsettings.Development.json | 8 ++ Portal/Portal.Backend/appsettings.json | 9 ++ Portal/Portal.Database/DatabaseContext.cs | 18 +++ Portal/Portal.Database/Models/Achievement.cs | 9 ++ Portal/Portal.Database/Models/User.cs | 10 ++ .../Models/UserAchievements.cs | 9 ++ Portal/Portal.Database/Portal.Database.csproj | 17 +++ Portal/Portal.Dto/Class1.cs | 6 + Portal/Portal.Dto/Portal.Dto.csproj | 9 ++ Portal/Portal.slnx | 7 ++ 370 files changed, 915 insertions(+) create mode 100644 Asset Store/AssetStore.Database/AssetStore.Database.csproj create mode 100644 Asset Store/AssetStore.Database/DatabaseContext.cs create mode 100644 Asset Store/AssetStore.Database/Models/Asset.cs create mode 100644 Asset Store/AssetStore.Database/Models/Comment.cs create mode 100644 Asset Store/AssetStore.slnx create mode 100644 Asset Store/AssetStore/AssetStore.Api.csproj create mode 100644 Asset Store/AssetStore/AssetStore.http create mode 100644 Asset Store/AssetStore/Controllers/AssetController.cs create mode 100644 Asset Store/AssetStore/Controllers/CommentController.cs create mode 100644 Asset Store/AssetStore/Program.cs create mode 100644 Asset Store/AssetStore/Properties/launchSettings.json create mode 100644 Asset Store/AssetStore/Services/Asset/AssetService.cs create mode 100644 Asset Store/AssetStore/Services/Asset/IAssetService.cs create mode 100644 Asset Store/AssetStore/appsettings.Development.json create mode 100644 Asset Store/AssetStore/appsettings.json create mode 100644 Asset Store/Directory.Build.props create mode 100644 Asset Store/Readme.md create mode 100644 Asset Store/Tests/AssetStore.API.Tests/AssetStore.Api.Tests.csproj create mode 100644 Asset Store/Tests/AssetStore.API.Tests/Controllers/AssetControllerTests.cs create mode 100644 Asset Store/Tests/AssetStore.API.Tests/Controllers/CommentControllerTests.cs create mode 100644 Asset Store/Tests/AssetStore.API.Tests/Services/AssetServiceTests.cs create mode 100644 Asset Store/Tests/AssetStore.API.Tests/Services/CommentServiceTests.cs create mode 100644 Asset Store/Tests/Directory.Build.props rename .editorconfig => Engine/.editorconfig (100%) rename Directory.Build.props => Engine/Directory.Build.props (100%) rename {Editor => Engine/Editor}/EditorSettings.cs (100%) rename {Editor => Engine/Editor}/EditorWindow.cs (100%) rename {Editor => Engine/Editor}/Program.cs (100%) rename {Editor => Engine/Editor}/SharpEngine.Editor.csproj (100%) rename {Editor => Engine/Editor}/SharpEngine.Editor.sln (100%) rename {Editor => Engine/Editor}/Windows/ActionsMenuWindow.cs (100%) rename {Editor => Engine/Editor}/Windows/AssetsWindow.cs (100%) rename {Editor => Engine/Editor}/Windows/ContextMenuWindow.cs (100%) rename {Editor => Engine/Editor}/Windows/ImGuiWindowBase.cs (100%) rename {Editor => Engine/Editor}/Windows/PropertiesWindow.cs (100%) rename {Editor => Engine/Editor}/Windows/SceneWindow.cs (100%) rename {Examples => Engine/Examples}/MinecraftClone/Block/BlockBase.cs (100%) rename {Examples => Engine/Examples}/MinecraftClone/Block/Dirt.cs (100%) rename {Examples => Engine/Examples}/MinecraftClone/Block/Stone.cs (100%) rename {Examples => Engine/Examples}/MinecraftClone/BlockFactory.cs (100%) rename {Examples => Engine/Examples}/MinecraftClone/Input.cs (100%) rename {Examples => Engine/Examples}/MinecraftClone/Inventory.cs (100%) rename {Examples => Engine/Examples}/MinecraftClone/Minecraft.cs (100%) rename {Examples => Engine/Examples}/MinecraftClone/Minecraft.csproj (100%) rename {Examples => Engine/Examples}/MinecraftClone/Minecraft.sln (100%) rename {Examples => Engine/Examples}/MinecraftClone/Program.cs (100%) rename {Examples => Engine/Examples}/MinecraftClone/Resources/container2.png (100%) rename {Examples => Engine/Examples}/MinecraftClone/Resources/container2_specular.png (100%) rename {Examples => Engine/Examples}/MinecraftClone/Resources/grass.jpg (100%) rename {Examples => Engine/Examples}/Minimal/Minimal.csproj (100%) rename {Examples => Engine/Examples}/Minimal/Minimal.sln (100%) rename {Examples => Engine/Examples}/Minimal/Program.cs (100%) rename {Examples => Engine/Examples}/MultipleWindows/MultipleWindows.csproj (100%) rename {Examples => Engine/Examples}/MultipleWindows/Program.cs (100%) rename {Examples => Engine/Examples}/Tutorial 4.1 - Model Loading/Program.cs (100%) rename {Examples => Engine/Examples}/Tutorial 4.1 - Model Loading/Tutorial 4.1 - Model Loading.csproj (100%) rename {Examples => Engine/Examples}/Tutorial 4.1 - Model Loading/shader2.vert (100%) rename {Examples => Engine/Examples}/Tutorial 4.1 - Model Loading/silk.png (100%) rename {Launcher => Engine/Launcher}/App.xaml (100%) rename {Launcher => Engine/Launcher}/App.xaml.cs (100%) rename {Launcher => Engine/Launcher}/Attributes/FileAttribute.cs (100%) rename {Launcher => Engine/Launcher}/Enums/SvgIcon.cs (100%) rename {Launcher => Engine/Launcher}/Launcher.csproj (100%) rename {Launcher => Engine/Launcher}/Launcher.sln (100%) rename {Launcher => Engine/Launcher}/MainPage.xaml (100%) rename {Launcher => Engine/Launcher}/MainPage.xaml.cs (100%) rename {Launcher => Engine/Launcher}/MauiProgram.cs (100%) rename {Launcher => Engine/Launcher}/Platforms/Android/AndroidManifest.xml (100%) rename {Launcher => Engine/Launcher}/Platforms/Android/MainActivity.cs (100%) rename {Launcher => Engine/Launcher}/Platforms/Android/MainApplication.cs (100%) rename {Launcher => Engine/Launcher}/Platforms/Android/Resources/values/colors.xml (100%) rename {Launcher => Engine/Launcher}/Platforms/MacCatalyst/AppDelegate.cs (100%) rename {Launcher => Engine/Launcher}/Platforms/MacCatalyst/Entitlements.plist (100%) rename {Launcher => Engine/Launcher}/Platforms/MacCatalyst/Info.plist (100%) rename {Launcher => Engine/Launcher}/Platforms/MacCatalyst/Program.cs (100%) rename {Launcher => Engine/Launcher}/Platforms/Tizen/Main.cs (100%) rename {Launcher => Engine/Launcher}/Platforms/Tizen/tizen-manifest.xml (100%) rename {Launcher => Engine/Launcher}/Platforms/Windows/App.xaml (100%) rename {Launcher => Engine/Launcher}/Platforms/Windows/App.xaml.cs (100%) rename {Launcher => Engine/Launcher}/Platforms/Windows/Package.appxmanifest (100%) rename {Launcher => Engine/Launcher}/Platforms/Windows/app.manifest (100%) rename {Launcher => Engine/Launcher}/Platforms/iOS/AppDelegate.cs (100%) rename {Launcher => Engine/Launcher}/Platforms/iOS/Info.plist (100%) rename {Launcher => Engine/Launcher}/Platforms/iOS/Program.cs (100%) rename {Launcher => Engine/Launcher}/Platforms/iOS/Resources/PrivacyInfo.xcprivacy (100%) rename {Launcher => Engine/Launcher}/Properties/launchSettings.json (100%) rename {Launcher => Engine/Launcher}/Resources/AppIcon/appicon.svg (100%) rename {Launcher => Engine/Launcher}/Resources/AppIcon/appiconfg.svg (100%) rename {Launcher => Engine/Launcher}/Resources/AppIcon/icon.ico (100%) rename {Launcher => Engine/Launcher}/Resources/AppIcon/icon.png (100%) rename {Launcher => Engine/Launcher}/Resources/AppIcon/icon.svg (100%) rename {Launcher => Engine/Launcher}/Resources/Fonts/OpenSans-Regular.ttf (100%) rename {Launcher => Engine/Launcher}/Resources/Images/dotnet_bot.svg (100%) rename {Launcher => Engine/Launcher}/Resources/Raw/AboutAssets.txt (100%) rename {Launcher => Engine/Launcher}/Resources/Splash/splash.svg (100%) rename {Launcher => Engine/Launcher}/Services/EditorService.cs (100%) rename {Launcher => Engine/Launcher}/Services/NotificationService.cs (100%) rename {Launcher => Engine/Launcher}/TestData/TestData.cs (100%) rename {Launcher => Engine/Launcher}/UI/Components/ContextMenu.razor (100%) rename {Launcher => Engine/Launcher}/UI/Components/ContextMenu.razor.css (100%) rename {Launcher => Engine/Launcher}/UI/Components/ContextMenu.razor.min.css (100%) rename {Launcher => Engine/Launcher}/UI/Components/ContextMenu.razor.scss (100%) rename {Launcher => Engine/Launcher}/UI/Components/Dialogs/ConfirmDeleteDialog.razor (100%) rename {Launcher => Engine/Launcher}/UI/Components/Dialogs/ConfirmDeleteDialog.razor.css (100%) rename {Launcher => Engine/Launcher}/UI/Components/Dialogs/ConfirmDeleteDialog.razor.min.css (100%) rename {Launcher => Engine/Launcher}/UI/Components/Dialogs/ConfirmDeleteDialog.razor.scss (100%) rename {Launcher => Engine/Launcher}/UI/Components/Dialogs/CreateProjectDialog.razor (100%) rename {Launcher => Engine/Launcher}/UI/Components/Dialogs/CreateProjectDialog.razor.cs (100%) rename {Launcher => Engine/Launcher}/UI/Components/Dialogs/CreateProjectDialog.razor.css (100%) rename {Launcher => Engine/Launcher}/UI/Components/Dialogs/CreateProjectDialog.razor.min.css (100%) rename {Launcher => Engine/Launcher}/UI/Components/Dialogs/CreateProjectDialog.razor.scss (100%) rename {Launcher => Engine/Launcher}/UI/Components/Dialogs/DialogBase.cs (100%) rename {Launcher => Engine/Launcher}/UI/Components/Flyouts/Flyout.razor (100%) rename {Launcher => Engine/Launcher}/UI/Components/Flyouts/Flyout.razor.css (100%) rename {Launcher => Engine/Launcher}/UI/Components/Flyouts/Flyout.razor.min.css (100%) rename {Launcher => Engine/Launcher}/UI/Components/Flyouts/Flyout.razor.scss (100%) rename {Launcher => Engine/Launcher}/UI/Components/Flyouts/FlyoutBase.cs (100%) rename {Launcher => Engine/Launcher}/UI/Components/Flyouts/SettingsFlyout.razor (100%) rename {Launcher => Engine/Launcher}/UI/Components/Grid/Grid.razor (100%) rename {Launcher => Engine/Launcher}/UI/Components/Grid/Grid.razor.css (100%) rename {Launcher => Engine/Launcher}/UI/Components/Grid/Grid.razor.min.css (100%) rename {Launcher => Engine/Launcher}/UI/Components/Grid/Grid.razor.scss (100%) rename {Launcher => Engine/Launcher}/UI/Components/Grid/GridHeader.cs (100%) rename {Launcher => Engine/Launcher}/UI/Components/Grid/GridHeader.razor (100%) rename {Launcher => Engine/Launcher}/UI/Components/Grid/GridHeader.razor.css (100%) rename {Launcher => Engine/Launcher}/UI/Components/Grid/GridHeader.razor.min.css (100%) rename {Launcher => Engine/Launcher}/UI/Components/Grid/GridHeader.razor.scss (100%) rename {Launcher => Engine/Launcher}/UI/Components/Grid/GridRow.razor (100%) rename {Launcher => Engine/Launcher}/UI/Components/Icons/DiscardIcon.razor (100%) rename {Launcher => Engine/Launcher}/UI/Components/Icons/Icon.razor (100%) rename {Launcher => Engine/Launcher}/UI/Components/Layout.razor (100%) rename {Launcher => Engine/Launcher}/UI/Components/Layout.razor.css (100%) rename {Launcher => Engine/Launcher}/UI/Components/Layout.razor.min.css (100%) rename {Launcher => Engine/Launcher}/UI/Components/Layout.razor.scss (100%) rename {Launcher => Engine/Launcher}/UI/Components/Navigation/SideBarItem.razor (100%) rename {Launcher => Engine/Launcher}/UI/Components/Navigation/SideBarItem.razor.css (100%) rename {Launcher => Engine/Launcher}/UI/Components/Navigation/SideBarItem.razor.min.css (100%) rename {Launcher => Engine/Launcher}/UI/Components/Navigation/SideBarItem.razor.scss (100%) rename {Launcher => Engine/Launcher}/UI/Components/Navigation/Sidebar.razor (100%) rename {Launcher => Engine/Launcher}/UI/Components/Navigation/Sidebar.razor.css (100%) rename {Launcher => Engine/Launcher}/UI/Components/Navigation/Sidebar.razor.min.css (100%) rename {Launcher => Engine/Launcher}/UI/Components/Navigation/Sidebar.razor.scss (100%) rename {Launcher => Engine/Launcher}/UI/Components/Notification/Notification.razor (100%) rename {Launcher => Engine/Launcher}/UI/Components/Notification/Notification.razor.css (100%) rename {Launcher => Engine/Launcher}/UI/Components/Notification/Notification.razor.min.css (100%) rename {Launcher => Engine/Launcher}/UI/Components/Notification/Notification.razor.scss (100%) rename {Launcher => Engine/Launcher}/UI/Components/Notification/NotificationType.cs (100%) rename {Launcher => Engine/Launcher}/UI/Components/Notification/NotificationTypeExtensions.cs (100%) rename {Launcher => Engine/Launcher}/UI/Components/Searchbox.razor (100%) rename {Launcher => Engine/Launcher}/UI/Components/Searchbox.razor.css (100%) rename {Launcher => Engine/Launcher}/UI/Components/Searchbox.razor.min.css (100%) rename {Launcher => Engine/Launcher}/UI/Components/Searchbox.razor.scss (100%) rename {Launcher => Engine/Launcher}/UI/Home.razor (100%) rename {Launcher => Engine/Launcher}/UI/Home.razor.cs (100%) rename {Launcher => Engine/Launcher}/UI/Home.razor.css (100%) rename {Launcher => Engine/Launcher}/UI/Home.razor.min.css (100%) rename {Launcher => Engine/Launcher}/UI/Home.razor.scss (100%) rename {Launcher => Engine/Launcher}/UI/Routes.razor (100%) rename {Launcher => Engine/Launcher}/UI/_Imports.razor (100%) rename {Launcher => Engine/Launcher}/compilerconfig.json (100%) rename {Launcher => Engine/Launcher}/compilerconfig.json.defaults (100%) rename {Launcher => Engine/Launcher}/wwwroot/css/additional.css (100%) rename {Launcher => Engine/Launcher}/wwwroot/css/additional.min.css (100%) rename {Launcher => Engine/Launcher}/wwwroot/css/additional.scss (100%) rename {Launcher => Engine/Launcher}/wwwroot/css/app.css (100%) rename {Launcher => Engine/Launcher}/wwwroot/css/bootstrap/bootstrap.min.css (100%) rename {Launcher => Engine/Launcher}/wwwroot/css/bootstrap/bootstrap.min.css.map (100%) rename {Launcher => Engine/Launcher}/wwwroot/favicon.png (100%) rename {Launcher => Engine/Launcher}/wwwroot/index.html (100%) rename {ObjLoader => Engine/ObjLoader}/DataStore.cs (100%) rename {ObjLoader => Engine/ObjLoader}/Loaders/LoaderBase.cs (100%) rename {ObjLoader => Engine/ObjLoader}/Loaders/MaterialLoader/IMaterialLibraryLoaderFacade.cs (100%) rename {ObjLoader => Engine/ObjLoader}/Loaders/MaterialLoader/MaterialLibraryLoader.cs (100%) rename {ObjLoader => Engine/ObjLoader}/Loaders/MaterialLoader/MaterialLibraryLoaderFacade.cs (100%) rename {ObjLoader => Engine/ObjLoader}/Loaders/ObjLoader/ObjLoader.cs (100%) rename {ObjLoader => Engine/ObjLoader}/Loaders/ObjLoader/ObjLoaderFactory.cs (100%) rename {ObjLoader => Engine/ObjLoader}/SharpEngine.Core.ObjLoader.csproj (100%) rename {ObjLoader => Engine/ObjLoader}/TypeParsers/FaceParser.cs (100%) rename {ObjLoader => Engine/ObjLoader}/TypeParsers/GroupParser.cs (100%) rename {ObjLoader => Engine/ObjLoader}/TypeParsers/ITypeParser.cs (100%) rename {ObjLoader => Engine/ObjLoader}/TypeParsers/MaterialLibraryParser.cs (100%) rename {ObjLoader => Engine/ObjLoader}/TypeParsers/NormalParser.cs (100%) rename {ObjLoader => Engine/ObjLoader}/TypeParsers/TextureParser.cs (100%) rename {ObjLoader => Engine/ObjLoader}/TypeParsers/TypeParserBase.cs (100%) rename {ObjLoader => Engine/ObjLoader}/TypeParsers/UseMaterialParser.cs (100%) rename {ObjLoader => Engine/ObjLoader}/TypeParsers/VertexParser.cs (100%) rename {Resources => Engine/Resources}/Screenshots/editor.png (100%) rename {Resources => Engine/Resources}/Screenshots/launcher.png (100%) rename {Resources => Engine/Resources}/icon.ico (100%) rename {Resources => Engine/Resources}/icon.png (100%) rename {Resources => Engine/Resources}/icon.svg (100%) rename {Resources => Engine/Resources}/icon.xcf (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/IComponent.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Obsolete/ObjLoader/DataStore/IFaceGroup.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Obsolete/ObjLoader/DataStore/IGroupDataStore.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Obsolete/ObjLoader/DataStore/IMaterialLibrary.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Obsolete/ObjLoader/DataStore/INormalDataStore.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Obsolete/ObjLoader/DataStore/ITextureDataStore.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Obsolete/ObjLoader/DataStore/IVertexDataStore.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/BoundingBox.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/ITransform.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/Material.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/Meshes/BufferObject.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/Meshes/Mesh.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/Meshes/MeshData/Face.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/Meshes/MeshData/Group.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/Meshes/MeshData/Normal.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/Meshes/MeshData/TextureCoordinate.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/Meshes/MeshData/Vertex.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/Meshes/MeshExtensions.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/Meshes/Model.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/Meshes/Model_Old.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/Meshes/ObjMeshData.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/Meshes/VertexArrayObject.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/Meshes/VertexData.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/Quaternion.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/Shaders/Shader.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/Shaders/ShaderAttributes.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/Shaders/ShaderExtensions.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/Textures/Texture.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/Textures/TextureExtensions.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/Transform.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/Properties/Transform2D.cs (100%) rename {SharpEngine.Core.Components => Engine/SharpEngine.Core.Components}/SharpEngine.Core.Components.csproj (100%) rename {SharpEngine.Core.Numerics => Engine/SharpEngine.Core.Numerics}/Float.cs (100%) rename {SharpEngine.Core.Numerics => Engine/SharpEngine.Core.Numerics}/HashCodeHelper.cs (100%) rename {SharpEngine.Core.Numerics => Engine/SharpEngine.Core.Numerics}/IVector.cs (100%) rename {SharpEngine.Core.Numerics => Engine/SharpEngine.Core.Numerics}/JitIntrinsicAttribute.cs (100%) rename {SharpEngine.Core.Numerics => Engine/SharpEngine.Core.Numerics}/SharpEngine.Core.Numerics.csproj (100%) rename {SharpEngine.Core.Numerics => Engine/SharpEngine.Core.Numerics}/Vector2.cs (100%) rename {SharpEngine.Core.Numerics => Engine/SharpEngine.Core.Numerics}/Vector2_Intrinsics.cs (100%) rename {SharpEngine.Core.Numerics => Engine/SharpEngine.Core.Numerics}/Vector3.cs (100%) rename {SharpEngine.Core.Numerics => Engine/SharpEngine.Core.Numerics}/Vector3_Intrinsics.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Abstractions/IGame.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Abstractions/IRenderable.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Abstractions/ISettings.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Audio/Audio.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Audio/AudioBuffer.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Audio/AudioDevice.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Audio/AudioFileExtensions.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Audio/AudioPlayerBase.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Audio/AudioProperties.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Audio/AudioSource.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Audio/WavData.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Audio/WavPlayer.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Entities/BezierCurve.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Entities/GameObject.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Entities/Lights/DirectionalLight.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Entities/Lights/Light.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Entities/Lights/PointLight.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Entities/Lights/SpotLight.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Entities/MeshService.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Entities/UI/Layouts/FlexLayout.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Entities/UI/Layouts/GridLayout.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Entities/UI/Layouts/LayoutBase.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Entities/UI/UIElement.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Entities/Views/CameraView.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Entities/Views/Settings/DefaultViewSettings.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Entities/Views/Settings/IViewSettings.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Entities/Views/Settings/ViewSettings.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Entities/Views/View.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Enums/MouseWheelScrollDirection.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Extensions/CollectionExtensions.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Extensions/PathExtensions.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Primitives/Cube.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Primitives/Plane.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Primitives/PrimitiveFactory.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Primitives/PrimitiveType.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Ray.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Renderers/RenderFlags.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Renderers/Renderer.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Renderers/RendererBase.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Renderers/TextRenderer.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Renderers/UIRenderer.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Scenes/Scene.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Scenes/SceneNode.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Shaders/LampShader.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Shaders/LightingShader.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Shaders/ShaderBase.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Shaders/ShaderService.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Shaders/UIShader.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/SharpEngine.Core.csproj (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Textures/TextureService.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Windowing/Frame.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Windowing/SilkWindow.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/Windowing/Window.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/_Resources/Default.cs (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/_Resources/Shaders/Light/DirectionalLight.glsl (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/_Resources/Shaders/Light/PointLight.glsl (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/_Resources/Shaders/Light/SpotLight.glsl (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/_Resources/Shaders/Material.glsl (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/_Resources/Shaders/lighting.frag (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/_Resources/Shaders/shader.frag (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/_Resources/Shaders/shader.vert (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/_Resources/Shaders/shader2.vert (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/_Resources/Shaders/uiShader.frag (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/_Resources/Shaders/uiShader.vert (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/_Resources/Textures/debug.jpg (100%) rename {SharpEngine.Core => Engine/SharpEngine.Core}/_Resources/icon.png (100%) create mode 100644 Engine/SharpEngine.Rest/Clients/AssetStoreClient.cs create mode 100644 Engine/SharpEngine.Rest/Clients/IAssetStoreClient.cs create mode 100644 Engine/SharpEngine.Rest/Clients/IPortalClient.cs create mode 100644 Engine/SharpEngine.Rest/Clients/PortalClient.cs create mode 100644 Engine/SharpEngine.Rest/Clients/RestClient.cs create mode 100644 Engine/SharpEngine.Rest/SharpEngine.Rest.csproj create mode 100644 Engine/SharpEngine.Rest/Urls/AssetStore.cs create mode 100644 Engine/SharpEngine.Rest/Urls/Portal.cs create mode 100644 Engine/SharpEngine.Shared/AssetType.cs rename {SharpEngine.Shared => Engine/SharpEngine.Shared}/Attributes/FilterAttribute.cs (100%) rename {SharpEngine.Shared => Engine/SharpEngine.Shared}/Attributes/InspectorAttribute.cs (100%) rename {SharpEngine.Shared => Engine/SharpEngine.Shared}/Debug.cs (100%) create mode 100644 Engine/SharpEngine.Shared/Dto/AssetStore/AssetDto.cs create mode 100644 Engine/SharpEngine.Shared/Dto/AssetStore/CommentDto.cs create mode 100644 Engine/SharpEngine.Shared/Dto/Primitives/AssetId.cs create mode 100644 Engine/SharpEngine.Shared/Dto/Primitives/CommentId.cs create mode 100644 Engine/SharpEngine.Shared/Dto/Primitives/UserId.cs rename {SharpEngine.Shared => Engine/SharpEngine.Shared}/Dto/Project.cs (100%) rename {SharpEngine.Shared => Engine/SharpEngine.Shared}/Dto/UserProfile.cs (100%) rename {SharpEngine.Shared => Engine/SharpEngine.Shared}/Enums/FilterMode.cs (100%) rename {SharpEngine.Shared => Engine/SharpEngine.Shared}/EnvironmentVariables.cs (100%) rename {SharpEngine.Shared => Engine/SharpEngine.Shared}/Extensions/OrderedEnumerableExtensions.cs (100%) rename {SharpEngine.Shared => Engine/SharpEngine.Shared}/Extensions/ProcessExtensions.cs (100%) rename {SharpEngine.Shared => Engine/SharpEngine.Shared}/Extensions/ReflectionExtensions.cs (100%) rename {SharpEngine.Shared => Engine/SharpEngine.Shared}/Extensions/StringExtensions.cs (100%) rename {SharpEngine.Shared => Engine/SharpEngine.Shared}/Math.cs (100%) rename {SharpEngine.Shared => Engine/SharpEngine.Shared}/NaturalStringComparer.cs (100%) rename {SharpEngine.Shared => Engine/SharpEngine.Shared}/SharpEngine.Shared.csproj (100%) rename SharpEngine.sln => Engine/SharpEngine.sln (94%) rename SharpEngine.slnx => Engine/SharpEngine.slnx (100%) rename {Tests => Engine/Tests}/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs (100%) rename {Tests => Engine/Tests}/ObjLoader.Test/Loaders/ObjLoaderTests.cs (100%) rename {Tests => Engine/Tests}/ObjLoader.Test/ObjLoader.Tests.csproj (100%) rename {Tests => Engine/Tests}/ObjLoader.Test/TypeParsers/FaceParserTests.cs (100%) rename {Tests => Engine/Tests}/ObjLoader.Test/TypeParsers/GroupParserTests.cs (100%) rename {Tests => Engine/Tests}/ObjLoader.Test/TypeParsers/MaterialLibraryParserTests.cs (100%) rename {Tests => Engine/Tests}/ObjLoader.Test/TypeParsers/NormalParserTests.cs (100%) rename {Tests => Engine/Tests}/ObjLoader.Test/TypeParsers/TextureParserTests.cs (100%) rename {Tests => Engine/Tests}/ObjLoader.Test/TypeParsers/UseMaterialParserTests.cs (100%) rename {Tests => Engine/Tests}/ObjLoader.Test/TypeParsers/VertexParserTests.cs (100%) rename {Tests => Engine/Tests}/SharpEngine.Core.Tests/Class1.cs (100%) rename {Tests => Engine/Tests}/SharpEngine.Core.Tests/SharpEngine.Core.Tests.csproj (100%) rename {Tests => Engine/Tests}/SharpEngine.Editor.Tests/Class1.cs (100%) rename {Tests => Engine/Tests}/SharpEngine.Editor.Tests/SharpEngine.Editor.Tests.csproj (100%) rename {Tests => Engine/Tests}/SharpEngine.Shared.Net8/Class1.cs (100%) rename {Tests => Engine/Tests}/SharpEngine.Shared.Net8/SharpEngine.Shared.Net8.csproj (100%) rename {Tests => Engine/Tests}/SharpEngine.Shared.Tests/Class1.cs (100%) rename {Tests => Engine/Tests}/SharpEngine.Shared.Tests/SharpEngine.Shared.Tests.csproj (100%) rename {Tests => Engine/Tests}/Test.Directory.Build.props (100%) rename {docs => Engine/docs}/CODE_OF_CONDUCT.md (100%) rename {docs => Engine/docs}/CONTRIBUTING.md (100%) rename {docs => Engine/docs}/SECURITY.md (100%) rename {docs => Engine/docs}/materials_and_inspiration.md (100%) rename {docs => Engine/docs}/pull_request_template.md (100%) create mode 100644 Portal/Portal.Backend/Controllers/AchievementController.cs create mode 100644 Portal/Portal.Backend/Controllers/UserController.cs create mode 100644 Portal/Portal.Backend/Database.http create mode 100644 Portal/Portal.Backend/Portal.Backend.csproj create mode 100644 Portal/Portal.Backend/Program.cs create mode 100644 Portal/Portal.Backend/Properties/launchSettings.json create mode 100644 Portal/Portal.Backend/Services/AchievementService.cs create mode 100644 Portal/Portal.Backend/appsettings.Development.json create mode 100644 Portal/Portal.Backend/appsettings.json create mode 100644 Portal/Portal.Database/DatabaseContext.cs create mode 100644 Portal/Portal.Database/Models/Achievement.cs create mode 100644 Portal/Portal.Database/Models/User.cs create mode 100644 Portal/Portal.Database/Models/UserAchievements.cs create mode 100644 Portal/Portal.Database/Portal.Database.csproj create mode 100644 Portal/Portal.Dto/Class1.cs create mode 100644 Portal/Portal.Dto/Portal.Dto.csproj create mode 100644 Portal/Portal.slnx diff --git a/Asset Store/AssetStore.Database/AssetStore.Database.csproj b/Asset Store/AssetStore.Database/AssetStore.Database.csproj new file mode 100644 index 0000000..247bc9d --- /dev/null +++ b/Asset Store/AssetStore.Database/AssetStore.Database.csproj @@ -0,0 +1,26 @@ + + + + net10.0 + enable + enable + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/Asset Store/AssetStore.Database/DatabaseContext.cs b/Asset Store/AssetStore.Database/DatabaseContext.cs new file mode 100644 index 0000000..344ae80 --- /dev/null +++ b/Asset Store/AssetStore.Database/DatabaseContext.cs @@ -0,0 +1,44 @@ +using AssetStore.Database.Models; +using Microsoft.EntityFrameworkCore; +using SharpEngine.Shared.Dto.Primitives; + +namespace AssetStore.Database; + +public class DatabaseContext : DbContext +{ + public DbSet Assets { get; set; } + public DbSet Comments { get; set; } + + public DatabaseContext() + { + } + + protected override void OnConfiguring(DbContextOptionsBuilder options) + { + options.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCoreExampleDB;Trusted_Connection=True;"); + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity(entity => + { + entity.HasMany(asset => asset.Comments); + + entity.Property(u => u.Id) + .HasConversion( + id => id.Value, + value => new AssetId(value)); + }); + + modelBuilder.Entity(entity => + { + entity.Property(u => u.Id) + .HasConversion( + id => id.Value, + value => new CommentId(value)); + + }); + } +} \ No newline at end of file diff --git a/Asset Store/AssetStore.Database/Models/Asset.cs b/Asset Store/AssetStore.Database/Models/Asset.cs new file mode 100644 index 0000000..0ae9119 --- /dev/null +++ b/Asset Store/AssetStore.Database/Models/Asset.cs @@ -0,0 +1,36 @@ +using SharpEngine.Shared.Dto.AssetStore; +using SharpEngine.Shared.Dto.Primitives; + +namespace AssetStore.Database.Models; + +public class Asset +{ + public AssetId Id { get; set; } + public required string Name { get; set; } + public string Description { get; set; } = string.Empty; + public decimal Price { get; set; } + public DateTime CreatedAt { get; set; } = DateTime.UtcNow; + public DateTime LastUpdatedAt { get; set; } = DateTime.UtcNow; + public IReadOnlyList KeyWords { get; set; } = []; + public IReadOnlyList Comments { get; set; } = []; + public UserId AuthorId { get; set; } + public bool Tombstoned { get; set; } = false; + public Version Version { get; set; } + // (e.g., model, texture, sound, etc.) + // public AssetType + + public required string BlobUri { get; set; } + public required string FileSize { get; set; } + + public required string Checksum { get; set; } + + public static explicit operator Asset(AssetDto dto) + { + throw new NotImplementedException(); + } + + public static explicit operator AssetDto(Asset? model) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/Asset Store/AssetStore.Database/Models/Comment.cs b/Asset Store/AssetStore.Database/Models/Comment.cs new file mode 100644 index 0000000..ef189ca --- /dev/null +++ b/Asset Store/AssetStore.Database/Models/Comment.cs @@ -0,0 +1,14 @@ +using SharpEngine.Shared.Dto.Primitives; + +namespace AssetStore.Database.Models; + +public class Comment +{ + public CommentId Id { get; set; } + public AssetId AssetId { get; set; } + public UserId UserId { get; set; } + public required string Content { get; set; } + public DateTime CreatedAt { get; set; } = DateTime.UtcNow; + public Comment? ParentComment { get; set; } + public IReadOnlyList Replies { get; set; } = []; +} diff --git a/Asset Store/AssetStore.slnx b/Asset Store/AssetStore.slnx new file mode 100644 index 0000000..268f27a --- /dev/null +++ b/Asset Store/AssetStore.slnx @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/Asset Store/AssetStore/AssetStore.Api.csproj b/Asset Store/AssetStore/AssetStore.Api.csproj new file mode 100644 index 0000000..5fa94a2 --- /dev/null +++ b/Asset Store/AssetStore/AssetStore.Api.csproj @@ -0,0 +1,21 @@ + + + + net10.0 + enable + enable + + + + + + + + + + + + + + + diff --git a/Asset Store/AssetStore/AssetStore.http b/Asset Store/AssetStore/AssetStore.http new file mode 100644 index 0000000..2e4293e --- /dev/null +++ b/Asset Store/AssetStore/AssetStore.http @@ -0,0 +1,6 @@ +@AssetStore_HostAddress = http://localhost:5274 + +GET {{AssetStore_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/Asset Store/AssetStore/Controllers/AssetController.cs b/Asset Store/AssetStore/Controllers/AssetController.cs new file mode 100644 index 0000000..4ea29c8 --- /dev/null +++ b/Asset Store/AssetStore/Controllers/AssetController.cs @@ -0,0 +1,112 @@ +using AssetStore.Database.Models; +using AssetStore.Services.Asset; +using Microsoft.AspNetCore.Mvc; +using SharpEngine.Shared.Dto.AssetStore; + +namespace AssetStore.Controllers +{ + [ApiController] + [Route("[controller]")] + public class AssetController : ControllerBase + { + private readonly ILogger _logger; + private readonly IAssetService _service; + + public AssetController(ILogger logger, IAssetService service) + { + _logger = logger; + _service = service; + } + + [HttpGet] + public ActionResult> GetAllAssets() + { + _logger.LogDebug("Retrieving assets."); + + var assets = _service.GetAssets(); + _logger.LogDebug("Found {Count} assets.", assets.Count()); + + return StatusCode(StatusCodes.Status200OK, assets); + } + + [HttpGet("{assetId}")] + public ActionResult GetById(Guid assetId) + { + _logger.LogDebug("Retrieving asset with id '{assetId}'.", assetId); + var asset = _service.GetAsset(assetId); + + if (asset is null) + return StatusCode(StatusCodes.Status204NoContent, "Unable to find asset."); + + return StatusCode(StatusCodes.Status200OK, asset); + } + + [HttpGet("/keyword")] + public ActionResult> GetAllAssetsByKeyWord([FromBody] IReadOnlyList keywords) + { + var joinedKeyWords = string.Join(", ", keywords); + _logger.LogDebug("Retrieving assets for the given keywords: {KeyWords}.", joinedKeyWords); + + var assets = _service.GetAssets(keywords); + _logger.LogDebug("Found {Count} assets for the given keywords: {KeyWords}.", assets.Count(), joinedKeyWords); + + if (!assets.Any()) + return StatusCode(StatusCodes.Status204NoContent, $"Unable to find assets with keywords '{joinedKeyWords}'."); + + return StatusCode(StatusCodes.Status200OK, assets); + } + + [HttpGet("/author/{author}")] + public ActionResult> GetAllAssetsByAuthor(Guid authorId) + { + _logger.LogDebug("Retrieving assets for author with id: '{Author}'.", authorId); + + var assets = _service.GetAssets(authorId); + _logger.LogDebug("Found {Count} assets for the given author: '{AuthorId}'.", assets.Count(), authorId); + + if (!assets.Any()) + return StatusCode(StatusCodes.Status204NoContent, $"Unable to find assets by author with id '{authorId}'."); + + return StatusCode(StatusCodes.Status200OK, assets); + } + + [HttpPost] + public async Task> CreateAsset([FromBody] AssetDto asset) + { + _logger.LogDebug("Checking if asset already exists."); + if (asset.Id.Value != Guid.Empty) + { + _logger.LogDebug("Asset already exists."); + return ReviseAsset(asset); + } + + _logger.LogDebug("Creating asset '{Asset}'. Published by '{Author}'.", asset.Name, asset.AuthorId); + var result = await _service.CreateAsset(asset); + + _logger.LogDebug("Successfully created asset '{Asset}'. Published by '{Author}'.", asset.Name, asset.AuthorId); + return result; + } + + [HttpPut] + public AssetDto ReviseAsset([FromBody] AssetDto asset) + { + // TODO: versioning logic + + // TODO: Replace existing with revised asset + var result = _service.ReviseAsset(asset); + + _logger.LogDebug("Successfully revised asset '{Asset}'. Published by '{Author}'.", asset.Name, asset.AuthorId); + return asset; + } + + [HttpDelete] + public async Task DeleteAsset(Guid assetId) + { + bool removed = await _service.DeleteAsset(assetId); + if (!removed) + return StatusCode(StatusCodes.Status404NotFound); + + return StatusCode(StatusCodes.Status200OK, "Asset successfully deleted."); + } + } +} diff --git a/Asset Store/AssetStore/Controllers/CommentController.cs b/Asset Store/AssetStore/Controllers/CommentController.cs new file mode 100644 index 0000000..ca4235c --- /dev/null +++ b/Asset Store/AssetStore/Controllers/CommentController.cs @@ -0,0 +1,30 @@ +using AssetStore.Database.Models; +using Microsoft.AspNetCore.Mvc; +using SharpEngine.Shared.Dto.AssetStore; + +namespace AssetStore.Controllers +{ + [ApiController] + [Route("[controller]")] + public class CommentController : ControllerBase + { + private readonly ILogger _logger; + + public CommentController(ILogger logger) + { + _logger = logger; + } + + [HttpGet] + public IEnumerable GetAssetComments(Guid assetId) + { + return new List(); + } + + [HttpPost] + public CommentDto PostComment(Guid assetId, CommentDto comment) + { + return new CommentDto(); + } + } +} diff --git a/Asset Store/AssetStore/Program.cs b/Asset Store/AssetStore/Program.cs new file mode 100644 index 0000000..666a9c5 --- /dev/null +++ b/Asset Store/AssetStore/Program.cs @@ -0,0 +1,23 @@ +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. + +builder.Services.AddControllers(); +// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi +builder.Services.AddOpenApi(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.MapOpenApi(); +} + +app.UseHttpsRedirection(); + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); diff --git a/Asset Store/AssetStore/Properties/launchSettings.json b/Asset Store/AssetStore/Properties/launchSettings.json new file mode 100644 index 0000000..4c87c24 --- /dev/null +++ b/Asset Store/AssetStore/Properties/launchSettings.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "http://localhost:5274", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "https://localhost:7215;http://localhost:5274", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/Asset Store/AssetStore/Services/Asset/AssetService.cs b/Asset Store/AssetStore/Services/Asset/AssetService.cs new file mode 100644 index 0000000..a11c7e6 --- /dev/null +++ b/Asset Store/AssetStore/Services/Asset/AssetService.cs @@ -0,0 +1,88 @@ +using AssetStore.Database.Models; +using Microsoft.EntityFrameworkCore; +using SharpEngine.Shared.Dto.AssetStore; +using SharpEngine.Shared.Dto.Primitives; + +namespace AssetStore.Services.Asset; + +public class AssetService : IAssetService +{ + private readonly ILogger _logger; + private readonly Database.DatabaseContext _db; + + public AssetService(ILogger _logger, Database.DatabaseContext db) + { + _db = db; + } + + /// + /// + public async Task CreateAsset(AssetDto asset) + { + _logger.LogDebug("Creating asset."); + + var model = (Asset)asset; + await _db.Assets.AddAsync(model); + await _db.SaveChangesAsync(); + + return asset; + } + + /// + public async Task DeleteAsset(AssetId assetId) + { + var asset = await _db.Assets.FirstOrDefaultAsync(asset => asset.Id.Value == assetId.Value); + if (asset is null) + return false; + + _db.Assets.Remove(asset); + await _db.SaveChangesAsync(); + + return true; + } + + /// + public async Task GetAsset(AssetId assetId) + { + var asset = await _db.Assets.FirstOrDefaultAsync(asset => asset.Id.Value == assetId.Value); + return (AssetDto?)asset; + } + + /// + public IEnumerable GetAssets() + { + var assets = _db.Assets.AsNoTracking().Select(asset => (AssetDto)asset); + return assets; + } + + /// + public IEnumerable GetAssets(IReadOnlyList keywords) + { + var assets = _db.Assets.AsNoTracking() + .Where(asset => asset.KeyWords.Any(keyword => keywords.Contains(keyword))) + .Select(asset => (AssetDto)asset); + + return assets; + } + + /// + public IEnumerable GetAssets(UserId authorId) + { + var assets = _db.Assets.AsNoTracking() + .Where(asset => asset.AuthorId.Value == authorId.Value) + .Select(asset => (AssetDto)asset); + + return assets; + } + + /// + public AssetDto GetByChecksum(string checksum) => throw new NotImplementedException(); + + /// + public AssetDto ReviseAsset(AssetDto asset) + { + asset.Version = new Version(asset.Version.Major, asset.Version.Minor + 1); + + throw new NotImplementedException(); + } +} diff --git a/Asset Store/AssetStore/Services/Asset/IAssetService.cs b/Asset Store/AssetStore/Services/Asset/IAssetService.cs new file mode 100644 index 0000000..ad4df4c --- /dev/null +++ b/Asset Store/AssetStore/Services/Asset/IAssetService.cs @@ -0,0 +1,17 @@ +using AssetStore.Database.Models; +using SharpEngine.Shared.Dto.AssetStore; +using SharpEngine.Shared.Dto.Primitives; + +namespace AssetStore.Services.Asset; + +public interface IAssetService +{ + Task CreateAsset(AssetDto asset); + Task DeleteAsset(AssetId assetId); + Task GetAsset(AssetId assetId); + IEnumerable GetAssets(); + IEnumerable GetAssets(IReadOnlyList keywords); + IEnumerable GetAssets(UserId authorId); + AssetDto GetByChecksum(string checksum); + AssetDto ReviseAsset(AssetDto asset); +} \ No newline at end of file diff --git a/Asset Store/AssetStore/appsettings.Development.json b/Asset Store/AssetStore/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/Asset Store/AssetStore/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/Asset Store/AssetStore/appsettings.json b/Asset Store/AssetStore/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/Asset Store/AssetStore/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/Asset Store/Directory.Build.props b/Asset Store/Directory.Build.props new file mode 100644 index 0000000..e69de29 diff --git a/Asset Store/Readme.md b/Asset Store/Readme.md new file mode 100644 index 0000000..e69de29 diff --git a/Asset Store/Tests/AssetStore.API.Tests/AssetStore.Api.Tests.csproj b/Asset Store/Tests/AssetStore.API.Tests/AssetStore.Api.Tests.csproj new file mode 100644 index 0000000..b760144 --- /dev/null +++ b/Asset Store/Tests/AssetStore.API.Tests/AssetStore.Api.Tests.csproj @@ -0,0 +1,9 @@ + + + + net10.0 + enable + enable + + + diff --git a/Asset Store/Tests/AssetStore.API.Tests/Controllers/AssetControllerTests.cs b/Asset Store/Tests/AssetStore.API.Tests/Controllers/AssetControllerTests.cs new file mode 100644 index 0000000..48fe198 --- /dev/null +++ b/Asset Store/Tests/AssetStore.API.Tests/Controllers/AssetControllerTests.cs @@ -0,0 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace AssetStore.Api.Tests.Controllers; + +internal class AssetControllerTests +{ +} diff --git a/Asset Store/Tests/AssetStore.API.Tests/Controllers/CommentControllerTests.cs b/Asset Store/Tests/AssetStore.API.Tests/Controllers/CommentControllerTests.cs new file mode 100644 index 0000000..1180378 --- /dev/null +++ b/Asset Store/Tests/AssetStore.API.Tests/Controllers/CommentControllerTests.cs @@ -0,0 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace AssetStore.Api.Tests.Controllers; + +internal class CommentControllerTests +{ +} diff --git a/Asset Store/Tests/AssetStore.API.Tests/Services/AssetServiceTests.cs b/Asset Store/Tests/AssetStore.API.Tests/Services/AssetServiceTests.cs new file mode 100644 index 0000000..44d8123 --- /dev/null +++ b/Asset Store/Tests/AssetStore.API.Tests/Services/AssetServiceTests.cs @@ -0,0 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace AssetStore.Api.Tests.Services; + +internal class AssetServiceTests +{ +} diff --git a/Asset Store/Tests/AssetStore.API.Tests/Services/CommentServiceTests.cs b/Asset Store/Tests/AssetStore.API.Tests/Services/CommentServiceTests.cs new file mode 100644 index 0000000..93698f0 --- /dev/null +++ b/Asset Store/Tests/AssetStore.API.Tests/Services/CommentServiceTests.cs @@ -0,0 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace AssetStore.Api.Tests.Services; + +internal class CommentServiceTests +{ +} diff --git a/Asset Store/Tests/Directory.Build.props b/Asset Store/Tests/Directory.Build.props new file mode 100644 index 0000000..e69de29 diff --git a/.editorconfig b/Engine/.editorconfig similarity index 100% rename from .editorconfig rename to Engine/.editorconfig diff --git a/Directory.Build.props b/Engine/Directory.Build.props similarity index 100% rename from Directory.Build.props rename to Engine/Directory.Build.props diff --git a/Editor/EditorSettings.cs b/Engine/Editor/EditorSettings.cs similarity index 100% rename from Editor/EditorSettings.cs rename to Engine/Editor/EditorSettings.cs diff --git a/Editor/EditorWindow.cs b/Engine/Editor/EditorWindow.cs similarity index 100% rename from Editor/EditorWindow.cs rename to Engine/Editor/EditorWindow.cs diff --git a/Editor/Program.cs b/Engine/Editor/Program.cs similarity index 100% rename from Editor/Program.cs rename to Engine/Editor/Program.cs diff --git a/Editor/SharpEngine.Editor.csproj b/Engine/Editor/SharpEngine.Editor.csproj similarity index 100% rename from Editor/SharpEngine.Editor.csproj rename to Engine/Editor/SharpEngine.Editor.csproj diff --git a/Editor/SharpEngine.Editor.sln b/Engine/Editor/SharpEngine.Editor.sln similarity index 100% rename from Editor/SharpEngine.Editor.sln rename to Engine/Editor/SharpEngine.Editor.sln diff --git a/Editor/Windows/ActionsMenuWindow.cs b/Engine/Editor/Windows/ActionsMenuWindow.cs similarity index 100% rename from Editor/Windows/ActionsMenuWindow.cs rename to Engine/Editor/Windows/ActionsMenuWindow.cs diff --git a/Editor/Windows/AssetsWindow.cs b/Engine/Editor/Windows/AssetsWindow.cs similarity index 100% rename from Editor/Windows/AssetsWindow.cs rename to Engine/Editor/Windows/AssetsWindow.cs diff --git a/Editor/Windows/ContextMenuWindow.cs b/Engine/Editor/Windows/ContextMenuWindow.cs similarity index 100% rename from Editor/Windows/ContextMenuWindow.cs rename to Engine/Editor/Windows/ContextMenuWindow.cs diff --git a/Editor/Windows/ImGuiWindowBase.cs b/Engine/Editor/Windows/ImGuiWindowBase.cs similarity index 100% rename from Editor/Windows/ImGuiWindowBase.cs rename to Engine/Editor/Windows/ImGuiWindowBase.cs diff --git a/Editor/Windows/PropertiesWindow.cs b/Engine/Editor/Windows/PropertiesWindow.cs similarity index 100% rename from Editor/Windows/PropertiesWindow.cs rename to Engine/Editor/Windows/PropertiesWindow.cs diff --git a/Editor/Windows/SceneWindow.cs b/Engine/Editor/Windows/SceneWindow.cs similarity index 100% rename from Editor/Windows/SceneWindow.cs rename to Engine/Editor/Windows/SceneWindow.cs diff --git a/Examples/MinecraftClone/Block/BlockBase.cs b/Engine/Examples/MinecraftClone/Block/BlockBase.cs similarity index 100% rename from Examples/MinecraftClone/Block/BlockBase.cs rename to Engine/Examples/MinecraftClone/Block/BlockBase.cs diff --git a/Examples/MinecraftClone/Block/Dirt.cs b/Engine/Examples/MinecraftClone/Block/Dirt.cs similarity index 100% rename from Examples/MinecraftClone/Block/Dirt.cs rename to Engine/Examples/MinecraftClone/Block/Dirt.cs diff --git a/Examples/MinecraftClone/Block/Stone.cs b/Engine/Examples/MinecraftClone/Block/Stone.cs similarity index 100% rename from Examples/MinecraftClone/Block/Stone.cs rename to Engine/Examples/MinecraftClone/Block/Stone.cs diff --git a/Examples/MinecraftClone/BlockFactory.cs b/Engine/Examples/MinecraftClone/BlockFactory.cs similarity index 100% rename from Examples/MinecraftClone/BlockFactory.cs rename to Engine/Examples/MinecraftClone/BlockFactory.cs diff --git a/Examples/MinecraftClone/Input.cs b/Engine/Examples/MinecraftClone/Input.cs similarity index 100% rename from Examples/MinecraftClone/Input.cs rename to Engine/Examples/MinecraftClone/Input.cs diff --git a/Examples/MinecraftClone/Inventory.cs b/Engine/Examples/MinecraftClone/Inventory.cs similarity index 100% rename from Examples/MinecraftClone/Inventory.cs rename to Engine/Examples/MinecraftClone/Inventory.cs diff --git a/Examples/MinecraftClone/Minecraft.cs b/Engine/Examples/MinecraftClone/Minecraft.cs similarity index 100% rename from Examples/MinecraftClone/Minecraft.cs rename to Engine/Examples/MinecraftClone/Minecraft.cs diff --git a/Examples/MinecraftClone/Minecraft.csproj b/Engine/Examples/MinecraftClone/Minecraft.csproj similarity index 100% rename from Examples/MinecraftClone/Minecraft.csproj rename to Engine/Examples/MinecraftClone/Minecraft.csproj diff --git a/Examples/MinecraftClone/Minecraft.sln b/Engine/Examples/MinecraftClone/Minecraft.sln similarity index 100% rename from Examples/MinecraftClone/Minecraft.sln rename to Engine/Examples/MinecraftClone/Minecraft.sln diff --git a/Examples/MinecraftClone/Program.cs b/Engine/Examples/MinecraftClone/Program.cs similarity index 100% rename from Examples/MinecraftClone/Program.cs rename to Engine/Examples/MinecraftClone/Program.cs diff --git a/Examples/MinecraftClone/Resources/container2.png b/Engine/Examples/MinecraftClone/Resources/container2.png similarity index 100% rename from Examples/MinecraftClone/Resources/container2.png rename to Engine/Examples/MinecraftClone/Resources/container2.png diff --git a/Examples/MinecraftClone/Resources/container2_specular.png b/Engine/Examples/MinecraftClone/Resources/container2_specular.png similarity index 100% rename from Examples/MinecraftClone/Resources/container2_specular.png rename to Engine/Examples/MinecraftClone/Resources/container2_specular.png diff --git a/Examples/MinecraftClone/Resources/grass.jpg b/Engine/Examples/MinecraftClone/Resources/grass.jpg similarity index 100% rename from Examples/MinecraftClone/Resources/grass.jpg rename to Engine/Examples/MinecraftClone/Resources/grass.jpg diff --git a/Examples/Minimal/Minimal.csproj b/Engine/Examples/Minimal/Minimal.csproj similarity index 100% rename from Examples/Minimal/Minimal.csproj rename to Engine/Examples/Minimal/Minimal.csproj diff --git a/Examples/Minimal/Minimal.sln b/Engine/Examples/Minimal/Minimal.sln similarity index 100% rename from Examples/Minimal/Minimal.sln rename to Engine/Examples/Minimal/Minimal.sln diff --git a/Examples/Minimal/Program.cs b/Engine/Examples/Minimal/Program.cs similarity index 100% rename from Examples/Minimal/Program.cs rename to Engine/Examples/Minimal/Program.cs diff --git a/Examples/MultipleWindows/MultipleWindows.csproj b/Engine/Examples/MultipleWindows/MultipleWindows.csproj similarity index 100% rename from Examples/MultipleWindows/MultipleWindows.csproj rename to Engine/Examples/MultipleWindows/MultipleWindows.csproj diff --git a/Examples/MultipleWindows/Program.cs b/Engine/Examples/MultipleWindows/Program.cs similarity index 100% rename from Examples/MultipleWindows/Program.cs rename to Engine/Examples/MultipleWindows/Program.cs diff --git a/Examples/Tutorial 4.1 - Model Loading/Program.cs b/Engine/Examples/Tutorial 4.1 - Model Loading/Program.cs similarity index 100% rename from Examples/Tutorial 4.1 - Model Loading/Program.cs rename to Engine/Examples/Tutorial 4.1 - Model Loading/Program.cs diff --git a/Examples/Tutorial 4.1 - Model Loading/Tutorial 4.1 - Model Loading.csproj b/Engine/Examples/Tutorial 4.1 - Model Loading/Tutorial 4.1 - Model Loading.csproj similarity index 100% rename from Examples/Tutorial 4.1 - Model Loading/Tutorial 4.1 - Model Loading.csproj rename to Engine/Examples/Tutorial 4.1 - Model Loading/Tutorial 4.1 - Model Loading.csproj diff --git a/Examples/Tutorial 4.1 - Model Loading/shader2.vert b/Engine/Examples/Tutorial 4.1 - Model Loading/shader2.vert similarity index 100% rename from Examples/Tutorial 4.1 - Model Loading/shader2.vert rename to Engine/Examples/Tutorial 4.1 - Model Loading/shader2.vert diff --git a/Examples/Tutorial 4.1 - Model Loading/silk.png b/Engine/Examples/Tutorial 4.1 - Model Loading/silk.png similarity index 100% rename from Examples/Tutorial 4.1 - Model Loading/silk.png rename to Engine/Examples/Tutorial 4.1 - Model Loading/silk.png diff --git a/Launcher/App.xaml b/Engine/Launcher/App.xaml similarity index 100% rename from Launcher/App.xaml rename to Engine/Launcher/App.xaml diff --git a/Launcher/App.xaml.cs b/Engine/Launcher/App.xaml.cs similarity index 100% rename from Launcher/App.xaml.cs rename to Engine/Launcher/App.xaml.cs diff --git a/Launcher/Attributes/FileAttribute.cs b/Engine/Launcher/Attributes/FileAttribute.cs similarity index 100% rename from Launcher/Attributes/FileAttribute.cs rename to Engine/Launcher/Attributes/FileAttribute.cs diff --git a/Launcher/Enums/SvgIcon.cs b/Engine/Launcher/Enums/SvgIcon.cs similarity index 100% rename from Launcher/Enums/SvgIcon.cs rename to Engine/Launcher/Enums/SvgIcon.cs diff --git a/Launcher/Launcher.csproj b/Engine/Launcher/Launcher.csproj similarity index 100% rename from Launcher/Launcher.csproj rename to Engine/Launcher/Launcher.csproj diff --git a/Launcher/Launcher.sln b/Engine/Launcher/Launcher.sln similarity index 100% rename from Launcher/Launcher.sln rename to Engine/Launcher/Launcher.sln diff --git a/Launcher/MainPage.xaml b/Engine/Launcher/MainPage.xaml similarity index 100% rename from Launcher/MainPage.xaml rename to Engine/Launcher/MainPage.xaml diff --git a/Launcher/MainPage.xaml.cs b/Engine/Launcher/MainPage.xaml.cs similarity index 100% rename from Launcher/MainPage.xaml.cs rename to Engine/Launcher/MainPage.xaml.cs diff --git a/Launcher/MauiProgram.cs b/Engine/Launcher/MauiProgram.cs similarity index 100% rename from Launcher/MauiProgram.cs rename to Engine/Launcher/MauiProgram.cs diff --git a/Launcher/Platforms/Android/AndroidManifest.xml b/Engine/Launcher/Platforms/Android/AndroidManifest.xml similarity index 100% rename from Launcher/Platforms/Android/AndroidManifest.xml rename to Engine/Launcher/Platforms/Android/AndroidManifest.xml diff --git a/Launcher/Platforms/Android/MainActivity.cs b/Engine/Launcher/Platforms/Android/MainActivity.cs similarity index 100% rename from Launcher/Platforms/Android/MainActivity.cs rename to Engine/Launcher/Platforms/Android/MainActivity.cs diff --git a/Launcher/Platforms/Android/MainApplication.cs b/Engine/Launcher/Platforms/Android/MainApplication.cs similarity index 100% rename from Launcher/Platforms/Android/MainApplication.cs rename to Engine/Launcher/Platforms/Android/MainApplication.cs diff --git a/Launcher/Platforms/Android/Resources/values/colors.xml b/Engine/Launcher/Platforms/Android/Resources/values/colors.xml similarity index 100% rename from Launcher/Platforms/Android/Resources/values/colors.xml rename to Engine/Launcher/Platforms/Android/Resources/values/colors.xml diff --git a/Launcher/Platforms/MacCatalyst/AppDelegate.cs b/Engine/Launcher/Platforms/MacCatalyst/AppDelegate.cs similarity index 100% rename from Launcher/Platforms/MacCatalyst/AppDelegate.cs rename to Engine/Launcher/Platforms/MacCatalyst/AppDelegate.cs diff --git a/Launcher/Platforms/MacCatalyst/Entitlements.plist b/Engine/Launcher/Platforms/MacCatalyst/Entitlements.plist similarity index 100% rename from Launcher/Platforms/MacCatalyst/Entitlements.plist rename to Engine/Launcher/Platforms/MacCatalyst/Entitlements.plist diff --git a/Launcher/Platforms/MacCatalyst/Info.plist b/Engine/Launcher/Platforms/MacCatalyst/Info.plist similarity index 100% rename from Launcher/Platforms/MacCatalyst/Info.plist rename to Engine/Launcher/Platforms/MacCatalyst/Info.plist diff --git a/Launcher/Platforms/MacCatalyst/Program.cs b/Engine/Launcher/Platforms/MacCatalyst/Program.cs similarity index 100% rename from Launcher/Platforms/MacCatalyst/Program.cs rename to Engine/Launcher/Platforms/MacCatalyst/Program.cs diff --git a/Launcher/Platforms/Tizen/Main.cs b/Engine/Launcher/Platforms/Tizen/Main.cs similarity index 100% rename from Launcher/Platforms/Tizen/Main.cs rename to Engine/Launcher/Platforms/Tizen/Main.cs diff --git a/Launcher/Platforms/Tizen/tizen-manifest.xml b/Engine/Launcher/Platforms/Tizen/tizen-manifest.xml similarity index 100% rename from Launcher/Platforms/Tizen/tizen-manifest.xml rename to Engine/Launcher/Platforms/Tizen/tizen-manifest.xml diff --git a/Launcher/Platforms/Windows/App.xaml b/Engine/Launcher/Platforms/Windows/App.xaml similarity index 100% rename from Launcher/Platforms/Windows/App.xaml rename to Engine/Launcher/Platforms/Windows/App.xaml diff --git a/Launcher/Platforms/Windows/App.xaml.cs b/Engine/Launcher/Platforms/Windows/App.xaml.cs similarity index 100% rename from Launcher/Platforms/Windows/App.xaml.cs rename to Engine/Launcher/Platforms/Windows/App.xaml.cs diff --git a/Launcher/Platforms/Windows/Package.appxmanifest b/Engine/Launcher/Platforms/Windows/Package.appxmanifest similarity index 100% rename from Launcher/Platforms/Windows/Package.appxmanifest rename to Engine/Launcher/Platforms/Windows/Package.appxmanifest diff --git a/Launcher/Platforms/Windows/app.manifest b/Engine/Launcher/Platforms/Windows/app.manifest similarity index 100% rename from Launcher/Platforms/Windows/app.manifest rename to Engine/Launcher/Platforms/Windows/app.manifest diff --git a/Launcher/Platforms/iOS/AppDelegate.cs b/Engine/Launcher/Platforms/iOS/AppDelegate.cs similarity index 100% rename from Launcher/Platforms/iOS/AppDelegate.cs rename to Engine/Launcher/Platforms/iOS/AppDelegate.cs diff --git a/Launcher/Platforms/iOS/Info.plist b/Engine/Launcher/Platforms/iOS/Info.plist similarity index 100% rename from Launcher/Platforms/iOS/Info.plist rename to Engine/Launcher/Platforms/iOS/Info.plist diff --git a/Launcher/Platforms/iOS/Program.cs b/Engine/Launcher/Platforms/iOS/Program.cs similarity index 100% rename from Launcher/Platforms/iOS/Program.cs rename to Engine/Launcher/Platforms/iOS/Program.cs diff --git a/Launcher/Platforms/iOS/Resources/PrivacyInfo.xcprivacy b/Engine/Launcher/Platforms/iOS/Resources/PrivacyInfo.xcprivacy similarity index 100% rename from Launcher/Platforms/iOS/Resources/PrivacyInfo.xcprivacy rename to Engine/Launcher/Platforms/iOS/Resources/PrivacyInfo.xcprivacy diff --git a/Launcher/Properties/launchSettings.json b/Engine/Launcher/Properties/launchSettings.json similarity index 100% rename from Launcher/Properties/launchSettings.json rename to Engine/Launcher/Properties/launchSettings.json diff --git a/Launcher/Resources/AppIcon/appicon.svg b/Engine/Launcher/Resources/AppIcon/appicon.svg similarity index 100% rename from Launcher/Resources/AppIcon/appicon.svg rename to Engine/Launcher/Resources/AppIcon/appicon.svg diff --git a/Launcher/Resources/AppIcon/appiconfg.svg b/Engine/Launcher/Resources/AppIcon/appiconfg.svg similarity index 100% rename from Launcher/Resources/AppIcon/appiconfg.svg rename to Engine/Launcher/Resources/AppIcon/appiconfg.svg diff --git a/Launcher/Resources/AppIcon/icon.ico b/Engine/Launcher/Resources/AppIcon/icon.ico similarity index 100% rename from Launcher/Resources/AppIcon/icon.ico rename to Engine/Launcher/Resources/AppIcon/icon.ico diff --git a/Launcher/Resources/AppIcon/icon.png b/Engine/Launcher/Resources/AppIcon/icon.png similarity index 100% rename from Launcher/Resources/AppIcon/icon.png rename to Engine/Launcher/Resources/AppIcon/icon.png diff --git a/Launcher/Resources/AppIcon/icon.svg b/Engine/Launcher/Resources/AppIcon/icon.svg similarity index 100% rename from Launcher/Resources/AppIcon/icon.svg rename to Engine/Launcher/Resources/AppIcon/icon.svg diff --git a/Launcher/Resources/Fonts/OpenSans-Regular.ttf b/Engine/Launcher/Resources/Fonts/OpenSans-Regular.ttf similarity index 100% rename from Launcher/Resources/Fonts/OpenSans-Regular.ttf rename to Engine/Launcher/Resources/Fonts/OpenSans-Regular.ttf diff --git a/Launcher/Resources/Images/dotnet_bot.svg b/Engine/Launcher/Resources/Images/dotnet_bot.svg similarity index 100% rename from Launcher/Resources/Images/dotnet_bot.svg rename to Engine/Launcher/Resources/Images/dotnet_bot.svg diff --git a/Launcher/Resources/Raw/AboutAssets.txt b/Engine/Launcher/Resources/Raw/AboutAssets.txt similarity index 100% rename from Launcher/Resources/Raw/AboutAssets.txt rename to Engine/Launcher/Resources/Raw/AboutAssets.txt diff --git a/Launcher/Resources/Splash/splash.svg b/Engine/Launcher/Resources/Splash/splash.svg similarity index 100% rename from Launcher/Resources/Splash/splash.svg rename to Engine/Launcher/Resources/Splash/splash.svg diff --git a/Launcher/Services/EditorService.cs b/Engine/Launcher/Services/EditorService.cs similarity index 100% rename from Launcher/Services/EditorService.cs rename to Engine/Launcher/Services/EditorService.cs diff --git a/Launcher/Services/NotificationService.cs b/Engine/Launcher/Services/NotificationService.cs similarity index 100% rename from Launcher/Services/NotificationService.cs rename to Engine/Launcher/Services/NotificationService.cs diff --git a/Launcher/TestData/TestData.cs b/Engine/Launcher/TestData/TestData.cs similarity index 100% rename from Launcher/TestData/TestData.cs rename to Engine/Launcher/TestData/TestData.cs diff --git a/Launcher/UI/Components/ContextMenu.razor b/Engine/Launcher/UI/Components/ContextMenu.razor similarity index 100% rename from Launcher/UI/Components/ContextMenu.razor rename to Engine/Launcher/UI/Components/ContextMenu.razor diff --git a/Launcher/UI/Components/ContextMenu.razor.css b/Engine/Launcher/UI/Components/ContextMenu.razor.css similarity index 100% rename from Launcher/UI/Components/ContextMenu.razor.css rename to Engine/Launcher/UI/Components/ContextMenu.razor.css diff --git a/Launcher/UI/Components/ContextMenu.razor.min.css b/Engine/Launcher/UI/Components/ContextMenu.razor.min.css similarity index 100% rename from Launcher/UI/Components/ContextMenu.razor.min.css rename to Engine/Launcher/UI/Components/ContextMenu.razor.min.css diff --git a/Launcher/UI/Components/ContextMenu.razor.scss b/Engine/Launcher/UI/Components/ContextMenu.razor.scss similarity index 100% rename from Launcher/UI/Components/ContextMenu.razor.scss rename to Engine/Launcher/UI/Components/ContextMenu.razor.scss diff --git a/Launcher/UI/Components/Dialogs/ConfirmDeleteDialog.razor b/Engine/Launcher/UI/Components/Dialogs/ConfirmDeleteDialog.razor similarity index 100% rename from Launcher/UI/Components/Dialogs/ConfirmDeleteDialog.razor rename to Engine/Launcher/UI/Components/Dialogs/ConfirmDeleteDialog.razor diff --git a/Launcher/UI/Components/Dialogs/ConfirmDeleteDialog.razor.css b/Engine/Launcher/UI/Components/Dialogs/ConfirmDeleteDialog.razor.css similarity index 100% rename from Launcher/UI/Components/Dialogs/ConfirmDeleteDialog.razor.css rename to Engine/Launcher/UI/Components/Dialogs/ConfirmDeleteDialog.razor.css diff --git a/Launcher/UI/Components/Dialogs/ConfirmDeleteDialog.razor.min.css b/Engine/Launcher/UI/Components/Dialogs/ConfirmDeleteDialog.razor.min.css similarity index 100% rename from Launcher/UI/Components/Dialogs/ConfirmDeleteDialog.razor.min.css rename to Engine/Launcher/UI/Components/Dialogs/ConfirmDeleteDialog.razor.min.css diff --git a/Launcher/UI/Components/Dialogs/ConfirmDeleteDialog.razor.scss b/Engine/Launcher/UI/Components/Dialogs/ConfirmDeleteDialog.razor.scss similarity index 100% rename from Launcher/UI/Components/Dialogs/ConfirmDeleteDialog.razor.scss rename to Engine/Launcher/UI/Components/Dialogs/ConfirmDeleteDialog.razor.scss diff --git a/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor b/Engine/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor similarity index 100% rename from Launcher/UI/Components/Dialogs/CreateProjectDialog.razor rename to Engine/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor diff --git a/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.cs b/Engine/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.cs similarity index 100% rename from Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.cs rename to Engine/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.cs diff --git a/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.css b/Engine/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.css similarity index 100% rename from Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.css rename to Engine/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.css diff --git a/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.min.css b/Engine/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.min.css similarity index 100% rename from Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.min.css rename to Engine/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.min.css diff --git a/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.scss b/Engine/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.scss similarity index 100% rename from Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.scss rename to Engine/Launcher/UI/Components/Dialogs/CreateProjectDialog.razor.scss diff --git a/Launcher/UI/Components/Dialogs/DialogBase.cs b/Engine/Launcher/UI/Components/Dialogs/DialogBase.cs similarity index 100% rename from Launcher/UI/Components/Dialogs/DialogBase.cs rename to Engine/Launcher/UI/Components/Dialogs/DialogBase.cs diff --git a/Launcher/UI/Components/Flyouts/Flyout.razor b/Engine/Launcher/UI/Components/Flyouts/Flyout.razor similarity index 100% rename from Launcher/UI/Components/Flyouts/Flyout.razor rename to Engine/Launcher/UI/Components/Flyouts/Flyout.razor diff --git a/Launcher/UI/Components/Flyouts/Flyout.razor.css b/Engine/Launcher/UI/Components/Flyouts/Flyout.razor.css similarity index 100% rename from Launcher/UI/Components/Flyouts/Flyout.razor.css rename to Engine/Launcher/UI/Components/Flyouts/Flyout.razor.css diff --git a/Launcher/UI/Components/Flyouts/Flyout.razor.min.css b/Engine/Launcher/UI/Components/Flyouts/Flyout.razor.min.css similarity index 100% rename from Launcher/UI/Components/Flyouts/Flyout.razor.min.css rename to Engine/Launcher/UI/Components/Flyouts/Flyout.razor.min.css diff --git a/Launcher/UI/Components/Flyouts/Flyout.razor.scss b/Engine/Launcher/UI/Components/Flyouts/Flyout.razor.scss similarity index 100% rename from Launcher/UI/Components/Flyouts/Flyout.razor.scss rename to Engine/Launcher/UI/Components/Flyouts/Flyout.razor.scss diff --git a/Launcher/UI/Components/Flyouts/FlyoutBase.cs b/Engine/Launcher/UI/Components/Flyouts/FlyoutBase.cs similarity index 100% rename from Launcher/UI/Components/Flyouts/FlyoutBase.cs rename to Engine/Launcher/UI/Components/Flyouts/FlyoutBase.cs diff --git a/Launcher/UI/Components/Flyouts/SettingsFlyout.razor b/Engine/Launcher/UI/Components/Flyouts/SettingsFlyout.razor similarity index 100% rename from Launcher/UI/Components/Flyouts/SettingsFlyout.razor rename to Engine/Launcher/UI/Components/Flyouts/SettingsFlyout.razor diff --git a/Launcher/UI/Components/Grid/Grid.razor b/Engine/Launcher/UI/Components/Grid/Grid.razor similarity index 100% rename from Launcher/UI/Components/Grid/Grid.razor rename to Engine/Launcher/UI/Components/Grid/Grid.razor diff --git a/Launcher/UI/Components/Grid/Grid.razor.css b/Engine/Launcher/UI/Components/Grid/Grid.razor.css similarity index 100% rename from Launcher/UI/Components/Grid/Grid.razor.css rename to Engine/Launcher/UI/Components/Grid/Grid.razor.css diff --git a/Launcher/UI/Components/Grid/Grid.razor.min.css b/Engine/Launcher/UI/Components/Grid/Grid.razor.min.css similarity index 100% rename from Launcher/UI/Components/Grid/Grid.razor.min.css rename to Engine/Launcher/UI/Components/Grid/Grid.razor.min.css diff --git a/Launcher/UI/Components/Grid/Grid.razor.scss b/Engine/Launcher/UI/Components/Grid/Grid.razor.scss similarity index 100% rename from Launcher/UI/Components/Grid/Grid.razor.scss rename to Engine/Launcher/UI/Components/Grid/Grid.razor.scss diff --git a/Launcher/UI/Components/Grid/GridHeader.cs b/Engine/Launcher/UI/Components/Grid/GridHeader.cs similarity index 100% rename from Launcher/UI/Components/Grid/GridHeader.cs rename to Engine/Launcher/UI/Components/Grid/GridHeader.cs diff --git a/Launcher/UI/Components/Grid/GridHeader.razor b/Engine/Launcher/UI/Components/Grid/GridHeader.razor similarity index 100% rename from Launcher/UI/Components/Grid/GridHeader.razor rename to Engine/Launcher/UI/Components/Grid/GridHeader.razor diff --git a/Launcher/UI/Components/Grid/GridHeader.razor.css b/Engine/Launcher/UI/Components/Grid/GridHeader.razor.css similarity index 100% rename from Launcher/UI/Components/Grid/GridHeader.razor.css rename to Engine/Launcher/UI/Components/Grid/GridHeader.razor.css diff --git a/Launcher/UI/Components/Grid/GridHeader.razor.min.css b/Engine/Launcher/UI/Components/Grid/GridHeader.razor.min.css similarity index 100% rename from Launcher/UI/Components/Grid/GridHeader.razor.min.css rename to Engine/Launcher/UI/Components/Grid/GridHeader.razor.min.css diff --git a/Launcher/UI/Components/Grid/GridHeader.razor.scss b/Engine/Launcher/UI/Components/Grid/GridHeader.razor.scss similarity index 100% rename from Launcher/UI/Components/Grid/GridHeader.razor.scss rename to Engine/Launcher/UI/Components/Grid/GridHeader.razor.scss diff --git a/Launcher/UI/Components/Grid/GridRow.razor b/Engine/Launcher/UI/Components/Grid/GridRow.razor similarity index 100% rename from Launcher/UI/Components/Grid/GridRow.razor rename to Engine/Launcher/UI/Components/Grid/GridRow.razor diff --git a/Launcher/UI/Components/Icons/DiscardIcon.razor b/Engine/Launcher/UI/Components/Icons/DiscardIcon.razor similarity index 100% rename from Launcher/UI/Components/Icons/DiscardIcon.razor rename to Engine/Launcher/UI/Components/Icons/DiscardIcon.razor diff --git a/Launcher/UI/Components/Icons/Icon.razor b/Engine/Launcher/UI/Components/Icons/Icon.razor similarity index 100% rename from Launcher/UI/Components/Icons/Icon.razor rename to Engine/Launcher/UI/Components/Icons/Icon.razor diff --git a/Launcher/UI/Components/Layout.razor b/Engine/Launcher/UI/Components/Layout.razor similarity index 100% rename from Launcher/UI/Components/Layout.razor rename to Engine/Launcher/UI/Components/Layout.razor diff --git a/Launcher/UI/Components/Layout.razor.css b/Engine/Launcher/UI/Components/Layout.razor.css similarity index 100% rename from Launcher/UI/Components/Layout.razor.css rename to Engine/Launcher/UI/Components/Layout.razor.css diff --git a/Launcher/UI/Components/Layout.razor.min.css b/Engine/Launcher/UI/Components/Layout.razor.min.css similarity index 100% rename from Launcher/UI/Components/Layout.razor.min.css rename to Engine/Launcher/UI/Components/Layout.razor.min.css diff --git a/Launcher/UI/Components/Layout.razor.scss b/Engine/Launcher/UI/Components/Layout.razor.scss similarity index 100% rename from Launcher/UI/Components/Layout.razor.scss rename to Engine/Launcher/UI/Components/Layout.razor.scss diff --git a/Launcher/UI/Components/Navigation/SideBarItem.razor b/Engine/Launcher/UI/Components/Navigation/SideBarItem.razor similarity index 100% rename from Launcher/UI/Components/Navigation/SideBarItem.razor rename to Engine/Launcher/UI/Components/Navigation/SideBarItem.razor diff --git a/Launcher/UI/Components/Navigation/SideBarItem.razor.css b/Engine/Launcher/UI/Components/Navigation/SideBarItem.razor.css similarity index 100% rename from Launcher/UI/Components/Navigation/SideBarItem.razor.css rename to Engine/Launcher/UI/Components/Navigation/SideBarItem.razor.css diff --git a/Launcher/UI/Components/Navigation/SideBarItem.razor.min.css b/Engine/Launcher/UI/Components/Navigation/SideBarItem.razor.min.css similarity index 100% rename from Launcher/UI/Components/Navigation/SideBarItem.razor.min.css rename to Engine/Launcher/UI/Components/Navigation/SideBarItem.razor.min.css diff --git a/Launcher/UI/Components/Navigation/SideBarItem.razor.scss b/Engine/Launcher/UI/Components/Navigation/SideBarItem.razor.scss similarity index 100% rename from Launcher/UI/Components/Navigation/SideBarItem.razor.scss rename to Engine/Launcher/UI/Components/Navigation/SideBarItem.razor.scss diff --git a/Launcher/UI/Components/Navigation/Sidebar.razor b/Engine/Launcher/UI/Components/Navigation/Sidebar.razor similarity index 100% rename from Launcher/UI/Components/Navigation/Sidebar.razor rename to Engine/Launcher/UI/Components/Navigation/Sidebar.razor diff --git a/Launcher/UI/Components/Navigation/Sidebar.razor.css b/Engine/Launcher/UI/Components/Navigation/Sidebar.razor.css similarity index 100% rename from Launcher/UI/Components/Navigation/Sidebar.razor.css rename to Engine/Launcher/UI/Components/Navigation/Sidebar.razor.css diff --git a/Launcher/UI/Components/Navigation/Sidebar.razor.min.css b/Engine/Launcher/UI/Components/Navigation/Sidebar.razor.min.css similarity index 100% rename from Launcher/UI/Components/Navigation/Sidebar.razor.min.css rename to Engine/Launcher/UI/Components/Navigation/Sidebar.razor.min.css diff --git a/Launcher/UI/Components/Navigation/Sidebar.razor.scss b/Engine/Launcher/UI/Components/Navigation/Sidebar.razor.scss similarity index 100% rename from Launcher/UI/Components/Navigation/Sidebar.razor.scss rename to Engine/Launcher/UI/Components/Navigation/Sidebar.razor.scss diff --git a/Launcher/UI/Components/Notification/Notification.razor b/Engine/Launcher/UI/Components/Notification/Notification.razor similarity index 100% rename from Launcher/UI/Components/Notification/Notification.razor rename to Engine/Launcher/UI/Components/Notification/Notification.razor diff --git a/Launcher/UI/Components/Notification/Notification.razor.css b/Engine/Launcher/UI/Components/Notification/Notification.razor.css similarity index 100% rename from Launcher/UI/Components/Notification/Notification.razor.css rename to Engine/Launcher/UI/Components/Notification/Notification.razor.css diff --git a/Launcher/UI/Components/Notification/Notification.razor.min.css b/Engine/Launcher/UI/Components/Notification/Notification.razor.min.css similarity index 100% rename from Launcher/UI/Components/Notification/Notification.razor.min.css rename to Engine/Launcher/UI/Components/Notification/Notification.razor.min.css diff --git a/Launcher/UI/Components/Notification/Notification.razor.scss b/Engine/Launcher/UI/Components/Notification/Notification.razor.scss similarity index 100% rename from Launcher/UI/Components/Notification/Notification.razor.scss rename to Engine/Launcher/UI/Components/Notification/Notification.razor.scss diff --git a/Launcher/UI/Components/Notification/NotificationType.cs b/Engine/Launcher/UI/Components/Notification/NotificationType.cs similarity index 100% rename from Launcher/UI/Components/Notification/NotificationType.cs rename to Engine/Launcher/UI/Components/Notification/NotificationType.cs diff --git a/Launcher/UI/Components/Notification/NotificationTypeExtensions.cs b/Engine/Launcher/UI/Components/Notification/NotificationTypeExtensions.cs similarity index 100% rename from Launcher/UI/Components/Notification/NotificationTypeExtensions.cs rename to Engine/Launcher/UI/Components/Notification/NotificationTypeExtensions.cs diff --git a/Launcher/UI/Components/Searchbox.razor b/Engine/Launcher/UI/Components/Searchbox.razor similarity index 100% rename from Launcher/UI/Components/Searchbox.razor rename to Engine/Launcher/UI/Components/Searchbox.razor diff --git a/Launcher/UI/Components/Searchbox.razor.css b/Engine/Launcher/UI/Components/Searchbox.razor.css similarity index 100% rename from Launcher/UI/Components/Searchbox.razor.css rename to Engine/Launcher/UI/Components/Searchbox.razor.css diff --git a/Launcher/UI/Components/Searchbox.razor.min.css b/Engine/Launcher/UI/Components/Searchbox.razor.min.css similarity index 100% rename from Launcher/UI/Components/Searchbox.razor.min.css rename to Engine/Launcher/UI/Components/Searchbox.razor.min.css diff --git a/Launcher/UI/Components/Searchbox.razor.scss b/Engine/Launcher/UI/Components/Searchbox.razor.scss similarity index 100% rename from Launcher/UI/Components/Searchbox.razor.scss rename to Engine/Launcher/UI/Components/Searchbox.razor.scss diff --git a/Launcher/UI/Home.razor b/Engine/Launcher/UI/Home.razor similarity index 100% rename from Launcher/UI/Home.razor rename to Engine/Launcher/UI/Home.razor diff --git a/Launcher/UI/Home.razor.cs b/Engine/Launcher/UI/Home.razor.cs similarity index 100% rename from Launcher/UI/Home.razor.cs rename to Engine/Launcher/UI/Home.razor.cs diff --git a/Launcher/UI/Home.razor.css b/Engine/Launcher/UI/Home.razor.css similarity index 100% rename from Launcher/UI/Home.razor.css rename to Engine/Launcher/UI/Home.razor.css diff --git a/Launcher/UI/Home.razor.min.css b/Engine/Launcher/UI/Home.razor.min.css similarity index 100% rename from Launcher/UI/Home.razor.min.css rename to Engine/Launcher/UI/Home.razor.min.css diff --git a/Launcher/UI/Home.razor.scss b/Engine/Launcher/UI/Home.razor.scss similarity index 100% rename from Launcher/UI/Home.razor.scss rename to Engine/Launcher/UI/Home.razor.scss diff --git a/Launcher/UI/Routes.razor b/Engine/Launcher/UI/Routes.razor similarity index 100% rename from Launcher/UI/Routes.razor rename to Engine/Launcher/UI/Routes.razor diff --git a/Launcher/UI/_Imports.razor b/Engine/Launcher/UI/_Imports.razor similarity index 100% rename from Launcher/UI/_Imports.razor rename to Engine/Launcher/UI/_Imports.razor diff --git a/Launcher/compilerconfig.json b/Engine/Launcher/compilerconfig.json similarity index 100% rename from Launcher/compilerconfig.json rename to Engine/Launcher/compilerconfig.json diff --git a/Launcher/compilerconfig.json.defaults b/Engine/Launcher/compilerconfig.json.defaults similarity index 100% rename from Launcher/compilerconfig.json.defaults rename to Engine/Launcher/compilerconfig.json.defaults diff --git a/Launcher/wwwroot/css/additional.css b/Engine/Launcher/wwwroot/css/additional.css similarity index 100% rename from Launcher/wwwroot/css/additional.css rename to Engine/Launcher/wwwroot/css/additional.css diff --git a/Launcher/wwwroot/css/additional.min.css b/Engine/Launcher/wwwroot/css/additional.min.css similarity index 100% rename from Launcher/wwwroot/css/additional.min.css rename to Engine/Launcher/wwwroot/css/additional.min.css diff --git a/Launcher/wwwroot/css/additional.scss b/Engine/Launcher/wwwroot/css/additional.scss similarity index 100% rename from Launcher/wwwroot/css/additional.scss rename to Engine/Launcher/wwwroot/css/additional.scss diff --git a/Launcher/wwwroot/css/app.css b/Engine/Launcher/wwwroot/css/app.css similarity index 100% rename from Launcher/wwwroot/css/app.css rename to Engine/Launcher/wwwroot/css/app.css diff --git a/Launcher/wwwroot/css/bootstrap/bootstrap.min.css b/Engine/Launcher/wwwroot/css/bootstrap/bootstrap.min.css similarity index 100% rename from Launcher/wwwroot/css/bootstrap/bootstrap.min.css rename to Engine/Launcher/wwwroot/css/bootstrap/bootstrap.min.css diff --git a/Launcher/wwwroot/css/bootstrap/bootstrap.min.css.map b/Engine/Launcher/wwwroot/css/bootstrap/bootstrap.min.css.map similarity index 100% rename from Launcher/wwwroot/css/bootstrap/bootstrap.min.css.map rename to Engine/Launcher/wwwroot/css/bootstrap/bootstrap.min.css.map diff --git a/Launcher/wwwroot/favicon.png b/Engine/Launcher/wwwroot/favicon.png similarity index 100% rename from Launcher/wwwroot/favicon.png rename to Engine/Launcher/wwwroot/favicon.png diff --git a/Launcher/wwwroot/index.html b/Engine/Launcher/wwwroot/index.html similarity index 100% rename from Launcher/wwwroot/index.html rename to Engine/Launcher/wwwroot/index.html diff --git a/ObjLoader/DataStore.cs b/Engine/ObjLoader/DataStore.cs similarity index 100% rename from ObjLoader/DataStore.cs rename to Engine/ObjLoader/DataStore.cs diff --git a/ObjLoader/Loaders/LoaderBase.cs b/Engine/ObjLoader/Loaders/LoaderBase.cs similarity index 100% rename from ObjLoader/Loaders/LoaderBase.cs rename to Engine/ObjLoader/Loaders/LoaderBase.cs diff --git a/ObjLoader/Loaders/MaterialLoader/IMaterialLibraryLoaderFacade.cs b/Engine/ObjLoader/Loaders/MaterialLoader/IMaterialLibraryLoaderFacade.cs similarity index 100% rename from ObjLoader/Loaders/MaterialLoader/IMaterialLibraryLoaderFacade.cs rename to Engine/ObjLoader/Loaders/MaterialLoader/IMaterialLibraryLoaderFacade.cs diff --git a/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoader.cs b/Engine/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoader.cs similarity index 100% rename from ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoader.cs rename to Engine/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoader.cs diff --git a/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoaderFacade.cs b/Engine/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoaderFacade.cs similarity index 100% rename from ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoaderFacade.cs rename to Engine/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoaderFacade.cs diff --git a/ObjLoader/Loaders/ObjLoader/ObjLoader.cs b/Engine/ObjLoader/Loaders/ObjLoader/ObjLoader.cs similarity index 100% rename from ObjLoader/Loaders/ObjLoader/ObjLoader.cs rename to Engine/ObjLoader/Loaders/ObjLoader/ObjLoader.cs diff --git a/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs b/Engine/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs similarity index 100% rename from ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs rename to Engine/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs diff --git a/ObjLoader/SharpEngine.Core.ObjLoader.csproj b/Engine/ObjLoader/SharpEngine.Core.ObjLoader.csproj similarity index 100% rename from ObjLoader/SharpEngine.Core.ObjLoader.csproj rename to Engine/ObjLoader/SharpEngine.Core.ObjLoader.csproj diff --git a/ObjLoader/TypeParsers/FaceParser.cs b/Engine/ObjLoader/TypeParsers/FaceParser.cs similarity index 100% rename from ObjLoader/TypeParsers/FaceParser.cs rename to Engine/ObjLoader/TypeParsers/FaceParser.cs diff --git a/ObjLoader/TypeParsers/GroupParser.cs b/Engine/ObjLoader/TypeParsers/GroupParser.cs similarity index 100% rename from ObjLoader/TypeParsers/GroupParser.cs rename to Engine/ObjLoader/TypeParsers/GroupParser.cs diff --git a/ObjLoader/TypeParsers/ITypeParser.cs b/Engine/ObjLoader/TypeParsers/ITypeParser.cs similarity index 100% rename from ObjLoader/TypeParsers/ITypeParser.cs rename to Engine/ObjLoader/TypeParsers/ITypeParser.cs diff --git a/ObjLoader/TypeParsers/MaterialLibraryParser.cs b/Engine/ObjLoader/TypeParsers/MaterialLibraryParser.cs similarity index 100% rename from ObjLoader/TypeParsers/MaterialLibraryParser.cs rename to Engine/ObjLoader/TypeParsers/MaterialLibraryParser.cs diff --git a/ObjLoader/TypeParsers/NormalParser.cs b/Engine/ObjLoader/TypeParsers/NormalParser.cs similarity index 100% rename from ObjLoader/TypeParsers/NormalParser.cs rename to Engine/ObjLoader/TypeParsers/NormalParser.cs diff --git a/ObjLoader/TypeParsers/TextureParser.cs b/Engine/ObjLoader/TypeParsers/TextureParser.cs similarity index 100% rename from ObjLoader/TypeParsers/TextureParser.cs rename to Engine/ObjLoader/TypeParsers/TextureParser.cs diff --git a/ObjLoader/TypeParsers/TypeParserBase.cs b/Engine/ObjLoader/TypeParsers/TypeParserBase.cs similarity index 100% rename from ObjLoader/TypeParsers/TypeParserBase.cs rename to Engine/ObjLoader/TypeParsers/TypeParserBase.cs diff --git a/ObjLoader/TypeParsers/UseMaterialParser.cs b/Engine/ObjLoader/TypeParsers/UseMaterialParser.cs similarity index 100% rename from ObjLoader/TypeParsers/UseMaterialParser.cs rename to Engine/ObjLoader/TypeParsers/UseMaterialParser.cs diff --git a/ObjLoader/TypeParsers/VertexParser.cs b/Engine/ObjLoader/TypeParsers/VertexParser.cs similarity index 100% rename from ObjLoader/TypeParsers/VertexParser.cs rename to Engine/ObjLoader/TypeParsers/VertexParser.cs diff --git a/Resources/Screenshots/editor.png b/Engine/Resources/Screenshots/editor.png similarity index 100% rename from Resources/Screenshots/editor.png rename to Engine/Resources/Screenshots/editor.png diff --git a/Resources/Screenshots/launcher.png b/Engine/Resources/Screenshots/launcher.png similarity index 100% rename from Resources/Screenshots/launcher.png rename to Engine/Resources/Screenshots/launcher.png diff --git a/Resources/icon.ico b/Engine/Resources/icon.ico similarity index 100% rename from Resources/icon.ico rename to Engine/Resources/icon.ico diff --git a/Resources/icon.png b/Engine/Resources/icon.png similarity index 100% rename from Resources/icon.png rename to Engine/Resources/icon.png diff --git a/Resources/icon.svg b/Engine/Resources/icon.svg similarity index 100% rename from Resources/icon.svg rename to Engine/Resources/icon.svg diff --git a/Resources/icon.xcf b/Engine/Resources/icon.xcf similarity index 100% rename from Resources/icon.xcf rename to Engine/Resources/icon.xcf diff --git a/SharpEngine.Core.Components/IComponent.cs b/Engine/SharpEngine.Core.Components/IComponent.cs similarity index 100% rename from SharpEngine.Core.Components/IComponent.cs rename to Engine/SharpEngine.Core.Components/IComponent.cs diff --git a/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IFaceGroup.cs b/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IFaceGroup.cs similarity index 100% rename from SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IFaceGroup.cs rename to Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IFaceGroup.cs diff --git a/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IGroupDataStore.cs b/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IGroupDataStore.cs similarity index 100% rename from SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IGroupDataStore.cs rename to Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IGroupDataStore.cs diff --git a/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IMaterialLibrary.cs b/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IMaterialLibrary.cs similarity index 100% rename from SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IMaterialLibrary.cs rename to Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IMaterialLibrary.cs diff --git a/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/INormalDataStore.cs b/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/INormalDataStore.cs similarity index 100% rename from SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/INormalDataStore.cs rename to Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/INormalDataStore.cs diff --git a/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/ITextureDataStore.cs b/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/ITextureDataStore.cs similarity index 100% rename from SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/ITextureDataStore.cs rename to Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/ITextureDataStore.cs diff --git a/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IVertexDataStore.cs b/Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IVertexDataStore.cs similarity index 100% rename from SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IVertexDataStore.cs rename to Engine/SharpEngine.Core.Components/Obsolete/ObjLoader/DataStore/IVertexDataStore.cs diff --git a/SharpEngine.Core.Components/Properties/BoundingBox.cs b/Engine/SharpEngine.Core.Components/Properties/BoundingBox.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/BoundingBox.cs rename to Engine/SharpEngine.Core.Components/Properties/BoundingBox.cs diff --git a/SharpEngine.Core.Components/Properties/ITransform.cs b/Engine/SharpEngine.Core.Components/Properties/ITransform.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/ITransform.cs rename to Engine/SharpEngine.Core.Components/Properties/ITransform.cs diff --git a/SharpEngine.Core.Components/Properties/Material.cs b/Engine/SharpEngine.Core.Components/Properties/Material.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/Material.cs rename to Engine/SharpEngine.Core.Components/Properties/Material.cs diff --git a/SharpEngine.Core.Components/Properties/Meshes/BufferObject.cs b/Engine/SharpEngine.Core.Components/Properties/Meshes/BufferObject.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/Meshes/BufferObject.cs rename to Engine/SharpEngine.Core.Components/Properties/Meshes/BufferObject.cs diff --git a/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs b/Engine/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/Meshes/Mesh.cs rename to Engine/SharpEngine.Core.Components/Properties/Meshes/Mesh.cs diff --git a/SharpEngine.Core.Components/Properties/Meshes/MeshData/Face.cs b/Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/Face.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/Meshes/MeshData/Face.cs rename to Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/Face.cs diff --git a/SharpEngine.Core.Components/Properties/Meshes/MeshData/Group.cs b/Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/Group.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/Meshes/MeshData/Group.cs rename to Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/Group.cs diff --git a/SharpEngine.Core.Components/Properties/Meshes/MeshData/Normal.cs b/Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/Normal.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/Meshes/MeshData/Normal.cs rename to Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/Normal.cs diff --git a/SharpEngine.Core.Components/Properties/Meshes/MeshData/TextureCoordinate.cs b/Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/TextureCoordinate.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/Meshes/MeshData/TextureCoordinate.cs rename to Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/TextureCoordinate.cs diff --git a/SharpEngine.Core.Components/Properties/Meshes/MeshData/Vertex.cs b/Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/Vertex.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/Meshes/MeshData/Vertex.cs rename to Engine/SharpEngine.Core.Components/Properties/Meshes/MeshData/Vertex.cs diff --git a/SharpEngine.Core.Components/Properties/Meshes/MeshExtensions.cs b/Engine/SharpEngine.Core.Components/Properties/Meshes/MeshExtensions.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/Meshes/MeshExtensions.cs rename to Engine/SharpEngine.Core.Components/Properties/Meshes/MeshExtensions.cs diff --git a/SharpEngine.Core.Components/Properties/Meshes/Model.cs b/Engine/SharpEngine.Core.Components/Properties/Meshes/Model.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/Meshes/Model.cs rename to Engine/SharpEngine.Core.Components/Properties/Meshes/Model.cs diff --git a/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs b/Engine/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs rename to Engine/SharpEngine.Core.Components/Properties/Meshes/Model_Old.cs diff --git a/SharpEngine.Core.Components/Properties/Meshes/ObjMeshData.cs b/Engine/SharpEngine.Core.Components/Properties/Meshes/ObjMeshData.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/Meshes/ObjMeshData.cs rename to Engine/SharpEngine.Core.Components/Properties/Meshes/ObjMeshData.cs diff --git a/SharpEngine.Core.Components/Properties/Meshes/VertexArrayObject.cs b/Engine/SharpEngine.Core.Components/Properties/Meshes/VertexArrayObject.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/Meshes/VertexArrayObject.cs rename to Engine/SharpEngine.Core.Components/Properties/Meshes/VertexArrayObject.cs diff --git a/SharpEngine.Core.Components/Properties/Meshes/VertexData.cs b/Engine/SharpEngine.Core.Components/Properties/Meshes/VertexData.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/Meshes/VertexData.cs rename to Engine/SharpEngine.Core.Components/Properties/Meshes/VertexData.cs diff --git a/SharpEngine.Core.Components/Properties/Quaternion.cs b/Engine/SharpEngine.Core.Components/Properties/Quaternion.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/Quaternion.cs rename to Engine/SharpEngine.Core.Components/Properties/Quaternion.cs diff --git a/SharpEngine.Core.Components/Properties/Shaders/Shader.cs b/Engine/SharpEngine.Core.Components/Properties/Shaders/Shader.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/Shaders/Shader.cs rename to Engine/SharpEngine.Core.Components/Properties/Shaders/Shader.cs diff --git a/SharpEngine.Core.Components/Properties/Shaders/ShaderAttributes.cs b/Engine/SharpEngine.Core.Components/Properties/Shaders/ShaderAttributes.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/Shaders/ShaderAttributes.cs rename to Engine/SharpEngine.Core.Components/Properties/Shaders/ShaderAttributes.cs diff --git a/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs b/Engine/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs rename to Engine/SharpEngine.Core.Components/Properties/Shaders/ShaderExtensions.cs diff --git a/SharpEngine.Core.Components/Properties/Textures/Texture.cs b/Engine/SharpEngine.Core.Components/Properties/Textures/Texture.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/Textures/Texture.cs rename to Engine/SharpEngine.Core.Components/Properties/Textures/Texture.cs diff --git a/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs b/Engine/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs rename to Engine/SharpEngine.Core.Components/Properties/Textures/TextureExtensions.cs diff --git a/SharpEngine.Core.Components/Properties/Transform.cs b/Engine/SharpEngine.Core.Components/Properties/Transform.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/Transform.cs rename to Engine/SharpEngine.Core.Components/Properties/Transform.cs diff --git a/SharpEngine.Core.Components/Properties/Transform2D.cs b/Engine/SharpEngine.Core.Components/Properties/Transform2D.cs similarity index 100% rename from SharpEngine.Core.Components/Properties/Transform2D.cs rename to Engine/SharpEngine.Core.Components/Properties/Transform2D.cs diff --git a/SharpEngine.Core.Components/SharpEngine.Core.Components.csproj b/Engine/SharpEngine.Core.Components/SharpEngine.Core.Components.csproj similarity index 100% rename from SharpEngine.Core.Components/SharpEngine.Core.Components.csproj rename to Engine/SharpEngine.Core.Components/SharpEngine.Core.Components.csproj diff --git a/SharpEngine.Core.Numerics/Float.cs b/Engine/SharpEngine.Core.Numerics/Float.cs similarity index 100% rename from SharpEngine.Core.Numerics/Float.cs rename to Engine/SharpEngine.Core.Numerics/Float.cs diff --git a/SharpEngine.Core.Numerics/HashCodeHelper.cs b/Engine/SharpEngine.Core.Numerics/HashCodeHelper.cs similarity index 100% rename from SharpEngine.Core.Numerics/HashCodeHelper.cs rename to Engine/SharpEngine.Core.Numerics/HashCodeHelper.cs diff --git a/SharpEngine.Core.Numerics/IVector.cs b/Engine/SharpEngine.Core.Numerics/IVector.cs similarity index 100% rename from SharpEngine.Core.Numerics/IVector.cs rename to Engine/SharpEngine.Core.Numerics/IVector.cs diff --git a/SharpEngine.Core.Numerics/JitIntrinsicAttribute.cs b/Engine/SharpEngine.Core.Numerics/JitIntrinsicAttribute.cs similarity index 100% rename from SharpEngine.Core.Numerics/JitIntrinsicAttribute.cs rename to Engine/SharpEngine.Core.Numerics/JitIntrinsicAttribute.cs diff --git a/SharpEngine.Core.Numerics/SharpEngine.Core.Numerics.csproj b/Engine/SharpEngine.Core.Numerics/SharpEngine.Core.Numerics.csproj similarity index 100% rename from SharpEngine.Core.Numerics/SharpEngine.Core.Numerics.csproj rename to Engine/SharpEngine.Core.Numerics/SharpEngine.Core.Numerics.csproj diff --git a/SharpEngine.Core.Numerics/Vector2.cs b/Engine/SharpEngine.Core.Numerics/Vector2.cs similarity index 100% rename from SharpEngine.Core.Numerics/Vector2.cs rename to Engine/SharpEngine.Core.Numerics/Vector2.cs diff --git a/SharpEngine.Core.Numerics/Vector2_Intrinsics.cs b/Engine/SharpEngine.Core.Numerics/Vector2_Intrinsics.cs similarity index 100% rename from SharpEngine.Core.Numerics/Vector2_Intrinsics.cs rename to Engine/SharpEngine.Core.Numerics/Vector2_Intrinsics.cs diff --git a/SharpEngine.Core.Numerics/Vector3.cs b/Engine/SharpEngine.Core.Numerics/Vector3.cs similarity index 100% rename from SharpEngine.Core.Numerics/Vector3.cs rename to Engine/SharpEngine.Core.Numerics/Vector3.cs diff --git a/SharpEngine.Core.Numerics/Vector3_Intrinsics.cs b/Engine/SharpEngine.Core.Numerics/Vector3_Intrinsics.cs similarity index 100% rename from SharpEngine.Core.Numerics/Vector3_Intrinsics.cs rename to Engine/SharpEngine.Core.Numerics/Vector3_Intrinsics.cs diff --git a/SharpEngine.Core/Abstractions/IGame.cs b/Engine/SharpEngine.Core/Abstractions/IGame.cs similarity index 100% rename from SharpEngine.Core/Abstractions/IGame.cs rename to Engine/SharpEngine.Core/Abstractions/IGame.cs diff --git a/SharpEngine.Core/Abstractions/IRenderable.cs b/Engine/SharpEngine.Core/Abstractions/IRenderable.cs similarity index 100% rename from SharpEngine.Core/Abstractions/IRenderable.cs rename to Engine/SharpEngine.Core/Abstractions/IRenderable.cs diff --git a/SharpEngine.Core/Abstractions/ISettings.cs b/Engine/SharpEngine.Core/Abstractions/ISettings.cs similarity index 100% rename from SharpEngine.Core/Abstractions/ISettings.cs rename to Engine/SharpEngine.Core/Abstractions/ISettings.cs diff --git a/SharpEngine.Core/Audio/Audio.cs b/Engine/SharpEngine.Core/Audio/Audio.cs similarity index 100% rename from SharpEngine.Core/Audio/Audio.cs rename to Engine/SharpEngine.Core/Audio/Audio.cs diff --git a/SharpEngine.Core/Audio/AudioBuffer.cs b/Engine/SharpEngine.Core/Audio/AudioBuffer.cs similarity index 100% rename from SharpEngine.Core/Audio/AudioBuffer.cs rename to Engine/SharpEngine.Core/Audio/AudioBuffer.cs diff --git a/SharpEngine.Core/Audio/AudioDevice.cs b/Engine/SharpEngine.Core/Audio/AudioDevice.cs similarity index 100% rename from SharpEngine.Core/Audio/AudioDevice.cs rename to Engine/SharpEngine.Core/Audio/AudioDevice.cs diff --git a/SharpEngine.Core/Audio/AudioFileExtensions.cs b/Engine/SharpEngine.Core/Audio/AudioFileExtensions.cs similarity index 100% rename from SharpEngine.Core/Audio/AudioFileExtensions.cs rename to Engine/SharpEngine.Core/Audio/AudioFileExtensions.cs diff --git a/SharpEngine.Core/Audio/AudioPlayerBase.cs b/Engine/SharpEngine.Core/Audio/AudioPlayerBase.cs similarity index 100% rename from SharpEngine.Core/Audio/AudioPlayerBase.cs rename to Engine/SharpEngine.Core/Audio/AudioPlayerBase.cs diff --git a/SharpEngine.Core/Audio/AudioProperties.cs b/Engine/SharpEngine.Core/Audio/AudioProperties.cs similarity index 100% rename from SharpEngine.Core/Audio/AudioProperties.cs rename to Engine/SharpEngine.Core/Audio/AudioProperties.cs diff --git a/SharpEngine.Core/Audio/AudioSource.cs b/Engine/SharpEngine.Core/Audio/AudioSource.cs similarity index 100% rename from SharpEngine.Core/Audio/AudioSource.cs rename to Engine/SharpEngine.Core/Audio/AudioSource.cs diff --git a/SharpEngine.Core/Audio/WavData.cs b/Engine/SharpEngine.Core/Audio/WavData.cs similarity index 100% rename from SharpEngine.Core/Audio/WavData.cs rename to Engine/SharpEngine.Core/Audio/WavData.cs diff --git a/SharpEngine.Core/Audio/WavPlayer.cs b/Engine/SharpEngine.Core/Audio/WavPlayer.cs similarity index 100% rename from SharpEngine.Core/Audio/WavPlayer.cs rename to Engine/SharpEngine.Core/Audio/WavPlayer.cs diff --git a/SharpEngine.Core/Entities/BezierCurve.cs b/Engine/SharpEngine.Core/Entities/BezierCurve.cs similarity index 100% rename from SharpEngine.Core/Entities/BezierCurve.cs rename to Engine/SharpEngine.Core/Entities/BezierCurve.cs diff --git a/SharpEngine.Core/Entities/GameObject.cs b/Engine/SharpEngine.Core/Entities/GameObject.cs similarity index 100% rename from SharpEngine.Core/Entities/GameObject.cs rename to Engine/SharpEngine.Core/Entities/GameObject.cs diff --git a/SharpEngine.Core/Entities/Lights/DirectionalLight.cs b/Engine/SharpEngine.Core/Entities/Lights/DirectionalLight.cs similarity index 100% rename from SharpEngine.Core/Entities/Lights/DirectionalLight.cs rename to Engine/SharpEngine.Core/Entities/Lights/DirectionalLight.cs diff --git a/SharpEngine.Core/Entities/Lights/Light.cs b/Engine/SharpEngine.Core/Entities/Lights/Light.cs similarity index 100% rename from SharpEngine.Core/Entities/Lights/Light.cs rename to Engine/SharpEngine.Core/Entities/Lights/Light.cs diff --git a/SharpEngine.Core/Entities/Lights/PointLight.cs b/Engine/SharpEngine.Core/Entities/Lights/PointLight.cs similarity index 100% rename from SharpEngine.Core/Entities/Lights/PointLight.cs rename to Engine/SharpEngine.Core/Entities/Lights/PointLight.cs diff --git a/SharpEngine.Core/Entities/Lights/SpotLight.cs b/Engine/SharpEngine.Core/Entities/Lights/SpotLight.cs similarity index 100% rename from SharpEngine.Core/Entities/Lights/SpotLight.cs rename to Engine/SharpEngine.Core/Entities/Lights/SpotLight.cs diff --git a/SharpEngine.Core/Entities/MeshService.cs b/Engine/SharpEngine.Core/Entities/MeshService.cs similarity index 100% rename from SharpEngine.Core/Entities/MeshService.cs rename to Engine/SharpEngine.Core/Entities/MeshService.cs diff --git a/SharpEngine.Core/Entities/UI/Layouts/FlexLayout.cs b/Engine/SharpEngine.Core/Entities/UI/Layouts/FlexLayout.cs similarity index 100% rename from SharpEngine.Core/Entities/UI/Layouts/FlexLayout.cs rename to Engine/SharpEngine.Core/Entities/UI/Layouts/FlexLayout.cs diff --git a/SharpEngine.Core/Entities/UI/Layouts/GridLayout.cs b/Engine/SharpEngine.Core/Entities/UI/Layouts/GridLayout.cs similarity index 100% rename from SharpEngine.Core/Entities/UI/Layouts/GridLayout.cs rename to Engine/SharpEngine.Core/Entities/UI/Layouts/GridLayout.cs diff --git a/SharpEngine.Core/Entities/UI/Layouts/LayoutBase.cs b/Engine/SharpEngine.Core/Entities/UI/Layouts/LayoutBase.cs similarity index 100% rename from SharpEngine.Core/Entities/UI/Layouts/LayoutBase.cs rename to Engine/SharpEngine.Core/Entities/UI/Layouts/LayoutBase.cs diff --git a/SharpEngine.Core/Entities/UI/UIElement.cs b/Engine/SharpEngine.Core/Entities/UI/UIElement.cs similarity index 100% rename from SharpEngine.Core/Entities/UI/UIElement.cs rename to Engine/SharpEngine.Core/Entities/UI/UIElement.cs diff --git a/SharpEngine.Core/Entities/Views/CameraView.cs b/Engine/SharpEngine.Core/Entities/Views/CameraView.cs similarity index 100% rename from SharpEngine.Core/Entities/Views/CameraView.cs rename to Engine/SharpEngine.Core/Entities/Views/CameraView.cs diff --git a/SharpEngine.Core/Entities/Views/Settings/DefaultViewSettings.cs b/Engine/SharpEngine.Core/Entities/Views/Settings/DefaultViewSettings.cs similarity index 100% rename from SharpEngine.Core/Entities/Views/Settings/DefaultViewSettings.cs rename to Engine/SharpEngine.Core/Entities/Views/Settings/DefaultViewSettings.cs diff --git a/SharpEngine.Core/Entities/Views/Settings/IViewSettings.cs b/Engine/SharpEngine.Core/Entities/Views/Settings/IViewSettings.cs similarity index 100% rename from SharpEngine.Core/Entities/Views/Settings/IViewSettings.cs rename to Engine/SharpEngine.Core/Entities/Views/Settings/IViewSettings.cs diff --git a/SharpEngine.Core/Entities/Views/Settings/ViewSettings.cs b/Engine/SharpEngine.Core/Entities/Views/Settings/ViewSettings.cs similarity index 100% rename from SharpEngine.Core/Entities/Views/Settings/ViewSettings.cs rename to Engine/SharpEngine.Core/Entities/Views/Settings/ViewSettings.cs diff --git a/SharpEngine.Core/Entities/Views/View.cs b/Engine/SharpEngine.Core/Entities/Views/View.cs similarity index 100% rename from SharpEngine.Core/Entities/Views/View.cs rename to Engine/SharpEngine.Core/Entities/Views/View.cs diff --git a/SharpEngine.Core/Enums/MouseWheelScrollDirection.cs b/Engine/SharpEngine.Core/Enums/MouseWheelScrollDirection.cs similarity index 100% rename from SharpEngine.Core/Enums/MouseWheelScrollDirection.cs rename to Engine/SharpEngine.Core/Enums/MouseWheelScrollDirection.cs diff --git a/SharpEngine.Core/Extensions/CollectionExtensions.cs b/Engine/SharpEngine.Core/Extensions/CollectionExtensions.cs similarity index 100% rename from SharpEngine.Core/Extensions/CollectionExtensions.cs rename to Engine/SharpEngine.Core/Extensions/CollectionExtensions.cs diff --git a/SharpEngine.Core/Extensions/PathExtensions.cs b/Engine/SharpEngine.Core/Extensions/PathExtensions.cs similarity index 100% rename from SharpEngine.Core/Extensions/PathExtensions.cs rename to Engine/SharpEngine.Core/Extensions/PathExtensions.cs diff --git a/SharpEngine.Core/Primitives/Cube.cs b/Engine/SharpEngine.Core/Primitives/Cube.cs similarity index 100% rename from SharpEngine.Core/Primitives/Cube.cs rename to Engine/SharpEngine.Core/Primitives/Cube.cs diff --git a/SharpEngine.Core/Primitives/Plane.cs b/Engine/SharpEngine.Core/Primitives/Plane.cs similarity index 100% rename from SharpEngine.Core/Primitives/Plane.cs rename to Engine/SharpEngine.Core/Primitives/Plane.cs diff --git a/SharpEngine.Core/Primitives/PrimitiveFactory.cs b/Engine/SharpEngine.Core/Primitives/PrimitiveFactory.cs similarity index 100% rename from SharpEngine.Core/Primitives/PrimitiveFactory.cs rename to Engine/SharpEngine.Core/Primitives/PrimitiveFactory.cs diff --git a/SharpEngine.Core/Primitives/PrimitiveType.cs b/Engine/SharpEngine.Core/Primitives/PrimitiveType.cs similarity index 100% rename from SharpEngine.Core/Primitives/PrimitiveType.cs rename to Engine/SharpEngine.Core/Primitives/PrimitiveType.cs diff --git a/SharpEngine.Core/Ray.cs b/Engine/SharpEngine.Core/Ray.cs similarity index 100% rename from SharpEngine.Core/Ray.cs rename to Engine/SharpEngine.Core/Ray.cs diff --git a/SharpEngine.Core/Renderers/RenderFlags.cs b/Engine/SharpEngine.Core/Renderers/RenderFlags.cs similarity index 100% rename from SharpEngine.Core/Renderers/RenderFlags.cs rename to Engine/SharpEngine.Core/Renderers/RenderFlags.cs diff --git a/SharpEngine.Core/Renderers/Renderer.cs b/Engine/SharpEngine.Core/Renderers/Renderer.cs similarity index 100% rename from SharpEngine.Core/Renderers/Renderer.cs rename to Engine/SharpEngine.Core/Renderers/Renderer.cs diff --git a/SharpEngine.Core/Renderers/RendererBase.cs b/Engine/SharpEngine.Core/Renderers/RendererBase.cs similarity index 100% rename from SharpEngine.Core/Renderers/RendererBase.cs rename to Engine/SharpEngine.Core/Renderers/RendererBase.cs diff --git a/SharpEngine.Core/Renderers/TextRenderer.cs b/Engine/SharpEngine.Core/Renderers/TextRenderer.cs similarity index 100% rename from SharpEngine.Core/Renderers/TextRenderer.cs rename to Engine/SharpEngine.Core/Renderers/TextRenderer.cs diff --git a/SharpEngine.Core/Renderers/UIRenderer.cs b/Engine/SharpEngine.Core/Renderers/UIRenderer.cs similarity index 100% rename from SharpEngine.Core/Renderers/UIRenderer.cs rename to Engine/SharpEngine.Core/Renderers/UIRenderer.cs diff --git a/SharpEngine.Core/Scenes/Scene.cs b/Engine/SharpEngine.Core/Scenes/Scene.cs similarity index 100% rename from SharpEngine.Core/Scenes/Scene.cs rename to Engine/SharpEngine.Core/Scenes/Scene.cs diff --git a/SharpEngine.Core/Scenes/SceneNode.cs b/Engine/SharpEngine.Core/Scenes/SceneNode.cs similarity index 100% rename from SharpEngine.Core/Scenes/SceneNode.cs rename to Engine/SharpEngine.Core/Scenes/SceneNode.cs diff --git a/SharpEngine.Core/Shaders/LampShader.cs b/Engine/SharpEngine.Core/Shaders/LampShader.cs similarity index 100% rename from SharpEngine.Core/Shaders/LampShader.cs rename to Engine/SharpEngine.Core/Shaders/LampShader.cs diff --git a/SharpEngine.Core/Shaders/LightingShader.cs b/Engine/SharpEngine.Core/Shaders/LightingShader.cs similarity index 100% rename from SharpEngine.Core/Shaders/LightingShader.cs rename to Engine/SharpEngine.Core/Shaders/LightingShader.cs diff --git a/SharpEngine.Core/Shaders/ShaderBase.cs b/Engine/SharpEngine.Core/Shaders/ShaderBase.cs similarity index 100% rename from SharpEngine.Core/Shaders/ShaderBase.cs rename to Engine/SharpEngine.Core/Shaders/ShaderBase.cs diff --git a/SharpEngine.Core/Shaders/ShaderService.cs b/Engine/SharpEngine.Core/Shaders/ShaderService.cs similarity index 100% rename from SharpEngine.Core/Shaders/ShaderService.cs rename to Engine/SharpEngine.Core/Shaders/ShaderService.cs diff --git a/SharpEngine.Core/Shaders/UIShader.cs b/Engine/SharpEngine.Core/Shaders/UIShader.cs similarity index 100% rename from SharpEngine.Core/Shaders/UIShader.cs rename to Engine/SharpEngine.Core/Shaders/UIShader.cs diff --git a/SharpEngine.Core/SharpEngine.Core.csproj b/Engine/SharpEngine.Core/SharpEngine.Core.csproj similarity index 100% rename from SharpEngine.Core/SharpEngine.Core.csproj rename to Engine/SharpEngine.Core/SharpEngine.Core.csproj diff --git a/SharpEngine.Core/Textures/TextureService.cs b/Engine/SharpEngine.Core/Textures/TextureService.cs similarity index 100% rename from SharpEngine.Core/Textures/TextureService.cs rename to Engine/SharpEngine.Core/Textures/TextureService.cs diff --git a/SharpEngine.Core/Windowing/Frame.cs b/Engine/SharpEngine.Core/Windowing/Frame.cs similarity index 100% rename from SharpEngine.Core/Windowing/Frame.cs rename to Engine/SharpEngine.Core/Windowing/Frame.cs diff --git a/SharpEngine.Core/Windowing/SilkWindow.cs b/Engine/SharpEngine.Core/Windowing/SilkWindow.cs similarity index 100% rename from SharpEngine.Core/Windowing/SilkWindow.cs rename to Engine/SharpEngine.Core/Windowing/SilkWindow.cs diff --git a/SharpEngine.Core/Windowing/Window.cs b/Engine/SharpEngine.Core/Windowing/Window.cs similarity index 100% rename from SharpEngine.Core/Windowing/Window.cs rename to Engine/SharpEngine.Core/Windowing/Window.cs diff --git a/SharpEngine.Core/_Resources/Default.cs b/Engine/SharpEngine.Core/_Resources/Default.cs similarity index 100% rename from SharpEngine.Core/_Resources/Default.cs rename to Engine/SharpEngine.Core/_Resources/Default.cs diff --git a/SharpEngine.Core/_Resources/Shaders/Light/DirectionalLight.glsl b/Engine/SharpEngine.Core/_Resources/Shaders/Light/DirectionalLight.glsl similarity index 100% rename from SharpEngine.Core/_Resources/Shaders/Light/DirectionalLight.glsl rename to Engine/SharpEngine.Core/_Resources/Shaders/Light/DirectionalLight.glsl diff --git a/SharpEngine.Core/_Resources/Shaders/Light/PointLight.glsl b/Engine/SharpEngine.Core/_Resources/Shaders/Light/PointLight.glsl similarity index 100% rename from SharpEngine.Core/_Resources/Shaders/Light/PointLight.glsl rename to Engine/SharpEngine.Core/_Resources/Shaders/Light/PointLight.glsl diff --git a/SharpEngine.Core/_Resources/Shaders/Light/SpotLight.glsl b/Engine/SharpEngine.Core/_Resources/Shaders/Light/SpotLight.glsl similarity index 100% rename from SharpEngine.Core/_Resources/Shaders/Light/SpotLight.glsl rename to Engine/SharpEngine.Core/_Resources/Shaders/Light/SpotLight.glsl diff --git a/SharpEngine.Core/_Resources/Shaders/Material.glsl b/Engine/SharpEngine.Core/_Resources/Shaders/Material.glsl similarity index 100% rename from SharpEngine.Core/_Resources/Shaders/Material.glsl rename to Engine/SharpEngine.Core/_Resources/Shaders/Material.glsl diff --git a/SharpEngine.Core/_Resources/Shaders/lighting.frag b/Engine/SharpEngine.Core/_Resources/Shaders/lighting.frag similarity index 100% rename from SharpEngine.Core/_Resources/Shaders/lighting.frag rename to Engine/SharpEngine.Core/_Resources/Shaders/lighting.frag diff --git a/SharpEngine.Core/_Resources/Shaders/shader.frag b/Engine/SharpEngine.Core/_Resources/Shaders/shader.frag similarity index 100% rename from SharpEngine.Core/_Resources/Shaders/shader.frag rename to Engine/SharpEngine.Core/_Resources/Shaders/shader.frag diff --git a/SharpEngine.Core/_Resources/Shaders/shader.vert b/Engine/SharpEngine.Core/_Resources/Shaders/shader.vert similarity index 100% rename from SharpEngine.Core/_Resources/Shaders/shader.vert rename to Engine/SharpEngine.Core/_Resources/Shaders/shader.vert diff --git a/SharpEngine.Core/_Resources/Shaders/shader2.vert b/Engine/SharpEngine.Core/_Resources/Shaders/shader2.vert similarity index 100% rename from SharpEngine.Core/_Resources/Shaders/shader2.vert rename to Engine/SharpEngine.Core/_Resources/Shaders/shader2.vert diff --git a/SharpEngine.Core/_Resources/Shaders/uiShader.frag b/Engine/SharpEngine.Core/_Resources/Shaders/uiShader.frag similarity index 100% rename from SharpEngine.Core/_Resources/Shaders/uiShader.frag rename to Engine/SharpEngine.Core/_Resources/Shaders/uiShader.frag diff --git a/SharpEngine.Core/_Resources/Shaders/uiShader.vert b/Engine/SharpEngine.Core/_Resources/Shaders/uiShader.vert similarity index 100% rename from SharpEngine.Core/_Resources/Shaders/uiShader.vert rename to Engine/SharpEngine.Core/_Resources/Shaders/uiShader.vert diff --git a/SharpEngine.Core/_Resources/Textures/debug.jpg b/Engine/SharpEngine.Core/_Resources/Textures/debug.jpg similarity index 100% rename from SharpEngine.Core/_Resources/Textures/debug.jpg rename to Engine/SharpEngine.Core/_Resources/Textures/debug.jpg diff --git a/SharpEngine.Core/_Resources/icon.png b/Engine/SharpEngine.Core/_Resources/icon.png similarity index 100% rename from SharpEngine.Core/_Resources/icon.png rename to Engine/SharpEngine.Core/_Resources/icon.png diff --git a/Engine/SharpEngine.Rest/Clients/AssetStoreClient.cs b/Engine/SharpEngine.Rest/Clients/AssetStoreClient.cs new file mode 100644 index 0000000..e209d12 --- /dev/null +++ b/Engine/SharpEngine.Rest/Clients/AssetStoreClient.cs @@ -0,0 +1,12 @@ +using SharpEngine.Rest.Urls; +using SharpEngine.Shared.Dto.AssetStore; + +namespace SharpEngine.Rest.Clients; + +public class AssetStoreClient : RestClient, IAssetStoreClient +{ + public AssetStoreClient(HttpClient httpClient) : base(httpClient) { } + + public async Task GetAssetAsync(Guid assetId) + => await GetAsync(AssetStore.GetById(assetId)); +} diff --git a/Engine/SharpEngine.Rest/Clients/IAssetStoreClient.cs b/Engine/SharpEngine.Rest/Clients/IAssetStoreClient.cs new file mode 100644 index 0000000..b99147a --- /dev/null +++ b/Engine/SharpEngine.Rest/Clients/IAssetStoreClient.cs @@ -0,0 +1,8 @@ +using SharpEngine.Shared.Dto.AssetStore; + +namespace SharpEngine.Rest.Clients; + +public interface IAssetStoreClient +{ + Task GetAssetAsync(Guid assetId); +} diff --git a/Engine/SharpEngine.Rest/Clients/IPortalClient.cs b/Engine/SharpEngine.Rest/Clients/IPortalClient.cs new file mode 100644 index 0000000..55de6a5 --- /dev/null +++ b/Engine/SharpEngine.Rest/Clients/IPortalClient.cs @@ -0,0 +1,5 @@ +namespace SharpEngine.Rest.Clients; + +internal interface IPortalClient +{ +} \ No newline at end of file diff --git a/Engine/SharpEngine.Rest/Clients/PortalClient.cs b/Engine/SharpEngine.Rest/Clients/PortalClient.cs new file mode 100644 index 0000000..f8213f6 --- /dev/null +++ b/Engine/SharpEngine.Rest/Clients/PortalClient.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpEngine.Rest.Clients; + +internal class PortalClient : RestClient, IPortalClient +{ + public PortalClient(HttpClient httpClient) : base(httpClient) { } +} diff --git a/Engine/SharpEngine.Rest/Clients/RestClient.cs b/Engine/SharpEngine.Rest/Clients/RestClient.cs new file mode 100644 index 0000000..3e96916 --- /dev/null +++ b/Engine/SharpEngine.Rest/Clients/RestClient.cs @@ -0,0 +1,28 @@ +using SharpEngine.Rest.Urls; +using System.Diagnostics; +using System.Text.Json; + +namespace SharpEngine.Rest.Clients; + +public abstract class RestClient +{ + private readonly HttpClient _httpClient; + public RestClient(HttpClient httpClient) + { + _httpClient = httpClient; + _httpClient.BaseAddress = new Uri(AssetStore.BaseUrl); + } + + public async Task GetAsync(string url) + { + var response = await _httpClient.GetAsync(url); + response.EnsureSuccessStatusCode(); + + var json = await response.Content.ReadAsStringAsync(); + + var result = JsonSerializer.Deserialize(json); + Debug.Assert(result is not null, "Deserialized result is null."); + + return result; + } +} diff --git a/Engine/SharpEngine.Rest/SharpEngine.Rest.csproj b/Engine/SharpEngine.Rest/SharpEngine.Rest.csproj new file mode 100644 index 0000000..d6ab7f9 --- /dev/null +++ b/Engine/SharpEngine.Rest/SharpEngine.Rest.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/Engine/SharpEngine.Rest/Urls/AssetStore.cs b/Engine/SharpEngine.Rest/Urls/AssetStore.cs new file mode 100644 index 0000000..e369a96 --- /dev/null +++ b/Engine/SharpEngine.Rest/Urls/AssetStore.cs @@ -0,0 +1,7 @@ +namespace SharpEngine.Rest.Urls; + +public static class AssetStore +{ + public const string BaseUrl = "https://assetstore.sharpengine.com/"; + public static string GetById(Guid assetId) => $"assets/{assetId}"; +} diff --git a/Engine/SharpEngine.Rest/Urls/Portal.cs b/Engine/SharpEngine.Rest/Urls/Portal.cs new file mode 100644 index 0000000..749348f --- /dev/null +++ b/Engine/SharpEngine.Rest/Urls/Portal.cs @@ -0,0 +1,6 @@ +namespace SharpEngine.Rest.Urls; + +public static class Portal +{ + public const string BaseUrl = "https://portal.sharpengine.com/"; +} diff --git a/Engine/SharpEngine.Shared/AssetType.cs b/Engine/SharpEngine.Shared/AssetType.cs new file mode 100644 index 0000000..e460210 --- /dev/null +++ b/Engine/SharpEngine.Shared/AssetType.cs @@ -0,0 +1,8 @@ +namespace SharpEngine.Shared; + +public enum AssetType +{ + Shader, + Model, + Texture, +} diff --git a/SharpEngine.Shared/Attributes/FilterAttribute.cs b/Engine/SharpEngine.Shared/Attributes/FilterAttribute.cs similarity index 100% rename from SharpEngine.Shared/Attributes/FilterAttribute.cs rename to Engine/SharpEngine.Shared/Attributes/FilterAttribute.cs diff --git a/SharpEngine.Shared/Attributes/InspectorAttribute.cs b/Engine/SharpEngine.Shared/Attributes/InspectorAttribute.cs similarity index 100% rename from SharpEngine.Shared/Attributes/InspectorAttribute.cs rename to Engine/SharpEngine.Shared/Attributes/InspectorAttribute.cs diff --git a/SharpEngine.Shared/Debug.cs b/Engine/SharpEngine.Shared/Debug.cs similarity index 100% rename from SharpEngine.Shared/Debug.cs rename to Engine/SharpEngine.Shared/Debug.cs diff --git a/Engine/SharpEngine.Shared/Dto/AssetStore/AssetDto.cs b/Engine/SharpEngine.Shared/Dto/AssetStore/AssetDto.cs new file mode 100644 index 0000000..1acf076 --- /dev/null +++ b/Engine/SharpEngine.Shared/Dto/AssetStore/AssetDto.cs @@ -0,0 +1,33 @@ +using SharpEngine.Shared.Dto.Primitives; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace SharpEngine.Shared.Dto.AssetStore; + +public class AssetDto +{ + public AssetId Id { get; init; } + public string Name { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public decimal Price { get; set; } + public DateTime CreatedAt { get; init; } + public DateTime LastUpdatedAt { get; init; } + public IReadOnlyList Tags { get; set; } = []; + public IReadOnlyList Comments { get; set; } = []; + public UserId AuthorId { get; init; } + public bool Tombstoned { get; set; } + public Version Version { get; set; } + + + // (e.g., model, texture, sound, etc.) + // public AssetType + + public required string BlobUri { get; set; } + public required string FileSize { get; set; } + + public required string Checksum { get; set; } +} diff --git a/Engine/SharpEngine.Shared/Dto/AssetStore/CommentDto.cs b/Engine/SharpEngine.Shared/Dto/AssetStore/CommentDto.cs new file mode 100644 index 0000000..053abeb --- /dev/null +++ b/Engine/SharpEngine.Shared/Dto/AssetStore/CommentDto.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharpEngine.Shared.Dto.AssetStore; + +public class CommentDto +{ +} diff --git a/Engine/SharpEngine.Shared/Dto/Primitives/AssetId.cs b/Engine/SharpEngine.Shared/Dto/Primitives/AssetId.cs new file mode 100644 index 0000000..eada9db --- /dev/null +++ b/Engine/SharpEngine.Shared/Dto/Primitives/AssetId.cs @@ -0,0 +1,8 @@ +namespace SharpEngine.Shared.Dto.Primitives; + +public readonly record struct AssetId(Guid Value) +{ + public static AssetId New() => new(Guid.NewGuid()); + public static implicit operator Guid(AssetId id) => id.Value; + public static implicit operator AssetId(Guid value) => new(value); +} diff --git a/Engine/SharpEngine.Shared/Dto/Primitives/CommentId.cs b/Engine/SharpEngine.Shared/Dto/Primitives/CommentId.cs new file mode 100644 index 0000000..1ec8ef4 --- /dev/null +++ b/Engine/SharpEngine.Shared/Dto/Primitives/CommentId.cs @@ -0,0 +1,8 @@ +namespace SharpEngine.Shared.Dto.Primitives; + +public readonly record struct CommentId(Guid Value) +{ + public static CommentId New() => new(Guid.NewGuid()); + public static implicit operator Guid(CommentId id) => id.Value; + public static implicit operator CommentId(Guid value) => new(value); +} diff --git a/Engine/SharpEngine.Shared/Dto/Primitives/UserId.cs b/Engine/SharpEngine.Shared/Dto/Primitives/UserId.cs new file mode 100644 index 0000000..d0fb0c2 --- /dev/null +++ b/Engine/SharpEngine.Shared/Dto/Primitives/UserId.cs @@ -0,0 +1,8 @@ +namespace SharpEngine.Shared.Dto.Primitives; + +public readonly record struct UserId(Guid Value) +{ + public static UserId New() => new(Guid.NewGuid()); + public static implicit operator Guid(UserId id) => id.Value; + public static implicit operator UserId(Guid value) => new(value); +} diff --git a/SharpEngine.Shared/Dto/Project.cs b/Engine/SharpEngine.Shared/Dto/Project.cs similarity index 100% rename from SharpEngine.Shared/Dto/Project.cs rename to Engine/SharpEngine.Shared/Dto/Project.cs diff --git a/SharpEngine.Shared/Dto/UserProfile.cs b/Engine/SharpEngine.Shared/Dto/UserProfile.cs similarity index 100% rename from SharpEngine.Shared/Dto/UserProfile.cs rename to Engine/SharpEngine.Shared/Dto/UserProfile.cs diff --git a/SharpEngine.Shared/Enums/FilterMode.cs b/Engine/SharpEngine.Shared/Enums/FilterMode.cs similarity index 100% rename from SharpEngine.Shared/Enums/FilterMode.cs rename to Engine/SharpEngine.Shared/Enums/FilterMode.cs diff --git a/SharpEngine.Shared/EnvironmentVariables.cs b/Engine/SharpEngine.Shared/EnvironmentVariables.cs similarity index 100% rename from SharpEngine.Shared/EnvironmentVariables.cs rename to Engine/SharpEngine.Shared/EnvironmentVariables.cs diff --git a/SharpEngine.Shared/Extensions/OrderedEnumerableExtensions.cs b/Engine/SharpEngine.Shared/Extensions/OrderedEnumerableExtensions.cs similarity index 100% rename from SharpEngine.Shared/Extensions/OrderedEnumerableExtensions.cs rename to Engine/SharpEngine.Shared/Extensions/OrderedEnumerableExtensions.cs diff --git a/SharpEngine.Shared/Extensions/ProcessExtensions.cs b/Engine/SharpEngine.Shared/Extensions/ProcessExtensions.cs similarity index 100% rename from SharpEngine.Shared/Extensions/ProcessExtensions.cs rename to Engine/SharpEngine.Shared/Extensions/ProcessExtensions.cs diff --git a/SharpEngine.Shared/Extensions/ReflectionExtensions.cs b/Engine/SharpEngine.Shared/Extensions/ReflectionExtensions.cs similarity index 100% rename from SharpEngine.Shared/Extensions/ReflectionExtensions.cs rename to Engine/SharpEngine.Shared/Extensions/ReflectionExtensions.cs diff --git a/SharpEngine.Shared/Extensions/StringExtensions.cs b/Engine/SharpEngine.Shared/Extensions/StringExtensions.cs similarity index 100% rename from SharpEngine.Shared/Extensions/StringExtensions.cs rename to Engine/SharpEngine.Shared/Extensions/StringExtensions.cs diff --git a/SharpEngine.Shared/Math.cs b/Engine/SharpEngine.Shared/Math.cs similarity index 100% rename from SharpEngine.Shared/Math.cs rename to Engine/SharpEngine.Shared/Math.cs diff --git a/SharpEngine.Shared/NaturalStringComparer.cs b/Engine/SharpEngine.Shared/NaturalStringComparer.cs similarity index 100% rename from SharpEngine.Shared/NaturalStringComparer.cs rename to Engine/SharpEngine.Shared/NaturalStringComparer.cs diff --git a/SharpEngine.Shared/SharpEngine.Shared.csproj b/Engine/SharpEngine.Shared/SharpEngine.Shared.csproj similarity index 100% rename from SharpEngine.Shared/SharpEngine.Shared.csproj rename to Engine/SharpEngine.Shared/SharpEngine.Shared.csproj diff --git a/SharpEngine.sln b/Engine/SharpEngine.sln similarity index 94% rename from SharpEngine.sln rename to Engine/SharpEngine.sln index 1d5f3a5..c51bee3 100644 --- a/SharpEngine.sln +++ b/Engine/SharpEngine.sln @@ -47,6 +47,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ObjLoader.Tests", "Tests\Ob EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tutorial 4.1 - Model Loading", "Examples\Tutorial 4.1 - Model Loading\Tutorial 4.1 - Model Loading.csproj", "{17243B7C-E72B-6C26-FCFC-3D194F29B0AF}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpEngine.Rest", "SharpEngine.Rest\SharpEngine.Rest.csproj", "{FE7C7460-6599-4BF8-A756-0C04315D3144}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -147,6 +149,12 @@ Global {17243B7C-E72B-6C26-FCFC-3D194F29B0AF}.LauncherNonWindows|Any CPU.Build.0 = Release|Any CPU {17243B7C-E72B-6C26-FCFC-3D194F29B0AF}.Release|Any CPU.ActiveCfg = Release|Any CPU {17243B7C-E72B-6C26-FCFC-3D194F29B0AF}.Release|Any CPU.Build.0 = Release|Any CPU + {FE7C7460-6599-4BF8-A756-0C04315D3144}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FE7C7460-6599-4BF8-A756-0C04315D3144}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FE7C7460-6599-4BF8-A756-0C04315D3144}.LauncherNonWindows|Any CPU.ActiveCfg = Release|Any CPU + {FE7C7460-6599-4BF8-A756-0C04315D3144}.LauncherNonWindows|Any CPU.Build.0 = Release|Any CPU + {FE7C7460-6599-4BF8-A756-0C04315D3144}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FE7C7460-6599-4BF8-A756-0C04315D3144}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SharpEngine.slnx b/Engine/SharpEngine.slnx similarity index 100% rename from SharpEngine.slnx rename to Engine/SharpEngine.slnx diff --git a/Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs b/Engine/Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs similarity index 100% rename from Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs rename to Engine/Tests/ObjLoader.Test/Loaders/MaterialLibraryLoaderTests.cs diff --git a/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs b/Engine/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs similarity index 100% rename from Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs rename to Engine/Tests/ObjLoader.Test/Loaders/ObjLoaderTests.cs diff --git a/Tests/ObjLoader.Test/ObjLoader.Tests.csproj b/Engine/Tests/ObjLoader.Test/ObjLoader.Tests.csproj similarity index 100% rename from Tests/ObjLoader.Test/ObjLoader.Tests.csproj rename to Engine/Tests/ObjLoader.Test/ObjLoader.Tests.csproj diff --git a/Tests/ObjLoader.Test/TypeParsers/FaceParserTests.cs b/Engine/Tests/ObjLoader.Test/TypeParsers/FaceParserTests.cs similarity index 100% rename from Tests/ObjLoader.Test/TypeParsers/FaceParserTests.cs rename to Engine/Tests/ObjLoader.Test/TypeParsers/FaceParserTests.cs diff --git a/Tests/ObjLoader.Test/TypeParsers/GroupParserTests.cs b/Engine/Tests/ObjLoader.Test/TypeParsers/GroupParserTests.cs similarity index 100% rename from Tests/ObjLoader.Test/TypeParsers/GroupParserTests.cs rename to Engine/Tests/ObjLoader.Test/TypeParsers/GroupParserTests.cs diff --git a/Tests/ObjLoader.Test/TypeParsers/MaterialLibraryParserTests.cs b/Engine/Tests/ObjLoader.Test/TypeParsers/MaterialLibraryParserTests.cs similarity index 100% rename from Tests/ObjLoader.Test/TypeParsers/MaterialLibraryParserTests.cs rename to Engine/Tests/ObjLoader.Test/TypeParsers/MaterialLibraryParserTests.cs diff --git a/Tests/ObjLoader.Test/TypeParsers/NormalParserTests.cs b/Engine/Tests/ObjLoader.Test/TypeParsers/NormalParserTests.cs similarity index 100% rename from Tests/ObjLoader.Test/TypeParsers/NormalParserTests.cs rename to Engine/Tests/ObjLoader.Test/TypeParsers/NormalParserTests.cs diff --git a/Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs b/Engine/Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs similarity index 100% rename from Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs rename to Engine/Tests/ObjLoader.Test/TypeParsers/TextureParserTests.cs diff --git a/Tests/ObjLoader.Test/TypeParsers/UseMaterialParserTests.cs b/Engine/Tests/ObjLoader.Test/TypeParsers/UseMaterialParserTests.cs similarity index 100% rename from Tests/ObjLoader.Test/TypeParsers/UseMaterialParserTests.cs rename to Engine/Tests/ObjLoader.Test/TypeParsers/UseMaterialParserTests.cs diff --git a/Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs b/Engine/Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs similarity index 100% rename from Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs rename to Engine/Tests/ObjLoader.Test/TypeParsers/VertexParserTests.cs diff --git a/Tests/SharpEngine.Core.Tests/Class1.cs b/Engine/Tests/SharpEngine.Core.Tests/Class1.cs similarity index 100% rename from Tests/SharpEngine.Core.Tests/Class1.cs rename to Engine/Tests/SharpEngine.Core.Tests/Class1.cs diff --git a/Tests/SharpEngine.Core.Tests/SharpEngine.Core.Tests.csproj b/Engine/Tests/SharpEngine.Core.Tests/SharpEngine.Core.Tests.csproj similarity index 100% rename from Tests/SharpEngine.Core.Tests/SharpEngine.Core.Tests.csproj rename to Engine/Tests/SharpEngine.Core.Tests/SharpEngine.Core.Tests.csproj diff --git a/Tests/SharpEngine.Editor.Tests/Class1.cs b/Engine/Tests/SharpEngine.Editor.Tests/Class1.cs similarity index 100% rename from Tests/SharpEngine.Editor.Tests/Class1.cs rename to Engine/Tests/SharpEngine.Editor.Tests/Class1.cs diff --git a/Tests/SharpEngine.Editor.Tests/SharpEngine.Editor.Tests.csproj b/Engine/Tests/SharpEngine.Editor.Tests/SharpEngine.Editor.Tests.csproj similarity index 100% rename from Tests/SharpEngine.Editor.Tests/SharpEngine.Editor.Tests.csproj rename to Engine/Tests/SharpEngine.Editor.Tests/SharpEngine.Editor.Tests.csproj diff --git a/Tests/SharpEngine.Shared.Net8/Class1.cs b/Engine/Tests/SharpEngine.Shared.Net8/Class1.cs similarity index 100% rename from Tests/SharpEngine.Shared.Net8/Class1.cs rename to Engine/Tests/SharpEngine.Shared.Net8/Class1.cs diff --git a/Tests/SharpEngine.Shared.Net8/SharpEngine.Shared.Net8.csproj b/Engine/Tests/SharpEngine.Shared.Net8/SharpEngine.Shared.Net8.csproj similarity index 100% rename from Tests/SharpEngine.Shared.Net8/SharpEngine.Shared.Net8.csproj rename to Engine/Tests/SharpEngine.Shared.Net8/SharpEngine.Shared.Net8.csproj diff --git a/Tests/SharpEngine.Shared.Tests/Class1.cs b/Engine/Tests/SharpEngine.Shared.Tests/Class1.cs similarity index 100% rename from Tests/SharpEngine.Shared.Tests/Class1.cs rename to Engine/Tests/SharpEngine.Shared.Tests/Class1.cs diff --git a/Tests/SharpEngine.Shared.Tests/SharpEngine.Shared.Tests.csproj b/Engine/Tests/SharpEngine.Shared.Tests/SharpEngine.Shared.Tests.csproj similarity index 100% rename from Tests/SharpEngine.Shared.Tests/SharpEngine.Shared.Tests.csproj rename to Engine/Tests/SharpEngine.Shared.Tests/SharpEngine.Shared.Tests.csproj diff --git a/Tests/Test.Directory.Build.props b/Engine/Tests/Test.Directory.Build.props similarity index 100% rename from Tests/Test.Directory.Build.props rename to Engine/Tests/Test.Directory.Build.props diff --git a/docs/CODE_OF_CONDUCT.md b/Engine/docs/CODE_OF_CONDUCT.md similarity index 100% rename from docs/CODE_OF_CONDUCT.md rename to Engine/docs/CODE_OF_CONDUCT.md diff --git a/docs/CONTRIBUTING.md b/Engine/docs/CONTRIBUTING.md similarity index 100% rename from docs/CONTRIBUTING.md rename to Engine/docs/CONTRIBUTING.md diff --git a/docs/SECURITY.md b/Engine/docs/SECURITY.md similarity index 100% rename from docs/SECURITY.md rename to Engine/docs/SECURITY.md diff --git a/docs/materials_and_inspiration.md b/Engine/docs/materials_and_inspiration.md similarity index 100% rename from docs/materials_and_inspiration.md rename to Engine/docs/materials_and_inspiration.md diff --git a/docs/pull_request_template.md b/Engine/docs/pull_request_template.md similarity index 100% rename from docs/pull_request_template.md rename to Engine/docs/pull_request_template.md diff --git a/Portal/Portal.Backend/Controllers/AchievementController.cs b/Portal/Portal.Backend/Controllers/AchievementController.cs new file mode 100644 index 0000000..40157d1 --- /dev/null +++ b/Portal/Portal.Backend/Controllers/AchievementController.cs @@ -0,0 +1,23 @@ +using Microsoft.AspNetCore.Mvc; +using Portal.Database.Models; + +namespace Database.Controllers +{ + [ApiController] + [Route("[controller]")] + public class AchievementController : ControllerBase + { + private readonly ILogger _logger; + + public AchievementController(ILogger logger) + { + _logger = logger; + } + + [HttpGet] + public UserAchievements GetUserAchievements() + { + return new(); + } + } +} diff --git a/Portal/Portal.Backend/Controllers/UserController.cs b/Portal/Portal.Backend/Controllers/UserController.cs new file mode 100644 index 0000000..0e0be3f --- /dev/null +++ b/Portal/Portal.Backend/Controllers/UserController.cs @@ -0,0 +1,23 @@ +using Microsoft.AspNetCore.Mvc; +using Portal.Database.Models; + +namespace Database.Controllers +{ + [ApiController] + [Route("[controller]")] + public class UserController : ControllerBase + { + private readonly ILogger _logger; + + public UserController(ILogger logger) + { + _logger = logger; + } + + [HttpGet] + public User Get() + { + return new(); + } + } +} diff --git a/Portal/Portal.Backend/Database.http b/Portal/Portal.Backend/Database.http new file mode 100644 index 0000000..7a874e2 --- /dev/null +++ b/Portal/Portal.Backend/Database.http @@ -0,0 +1,6 @@ +@Database_HostAddress = http://localhost:5088 + +GET {{Database_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/Portal/Portal.Backend/Portal.Backend.csproj b/Portal/Portal.Backend/Portal.Backend.csproj new file mode 100644 index 0000000..cde64ec --- /dev/null +++ b/Portal/Portal.Backend/Portal.Backend.csproj @@ -0,0 +1,17 @@ + + + + net10.0 + enable + enable + + + + + + + + + + + diff --git a/Portal/Portal.Backend/Program.cs b/Portal/Portal.Backend/Program.cs new file mode 100644 index 0000000..666a9c5 --- /dev/null +++ b/Portal/Portal.Backend/Program.cs @@ -0,0 +1,23 @@ +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. + +builder.Services.AddControllers(); +// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi +builder.Services.AddOpenApi(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.MapOpenApi(); +} + +app.UseHttpsRedirection(); + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); diff --git a/Portal/Portal.Backend/Properties/launchSettings.json b/Portal/Portal.Backend/Properties/launchSettings.json new file mode 100644 index 0000000..20fd58f --- /dev/null +++ b/Portal/Portal.Backend/Properties/launchSettings.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "http://localhost:5088", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "https://localhost:7063;http://localhost:5088", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/Portal/Portal.Backend/Services/AchievementService.cs b/Portal/Portal.Backend/Services/AchievementService.cs new file mode 100644 index 0000000..37a7309 --- /dev/null +++ b/Portal/Portal.Backend/Services/AchievementService.cs @@ -0,0 +1,5 @@ +namespace Portal.Backend.Services; + +public class AchievementService +{ +} diff --git a/Portal/Portal.Backend/appsettings.Development.json b/Portal/Portal.Backend/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/Portal/Portal.Backend/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/Portal/Portal.Backend/appsettings.json b/Portal/Portal.Backend/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/Portal/Portal.Backend/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/Portal/Portal.Database/DatabaseContext.cs b/Portal/Portal.Database/DatabaseContext.cs new file mode 100644 index 0000000..75bbecd --- /dev/null +++ b/Portal/Portal.Database/DatabaseContext.cs @@ -0,0 +1,18 @@ +using Microsoft.EntityFrameworkCore; +using Portal.Database.Models; + +public class BloggingContext : DbContext +{ + public DbSet User { get; set; } + public DbSet Achievements { get; set; } + public DbSet UserAchievements { get; set; } + + public BloggingContext() + { + } + + protected override void OnConfiguring(DbContextOptionsBuilder options) + { + + } +} \ No newline at end of file diff --git a/Portal/Portal.Database/Models/Achievement.cs b/Portal/Portal.Database/Models/Achievement.cs new file mode 100644 index 0000000..b9aa35c --- /dev/null +++ b/Portal/Portal.Database/Models/Achievement.cs @@ -0,0 +1,9 @@ +namespace Portal.Database.Models; + +public class Achievement +{ + public Guid Id { get; set; } + public string Title { get; set; } + public string Description { get; set; } + public string IconUrl { get; set; } +} diff --git a/Portal/Portal.Database/Models/User.cs b/Portal/Portal.Database/Models/User.cs new file mode 100644 index 0000000..58e7876 --- /dev/null +++ b/Portal/Portal.Database/Models/User.cs @@ -0,0 +1,10 @@ +namespace Portal.Database.Models; + +public class User +{ + public Guid Id { get; set; } + public string Username { get; set; } + public string Email { get; set; } + public string PasswordHash { get; set; } + public IReadOnlyList Achievements { get; set; } = []; +} diff --git a/Portal/Portal.Database/Models/UserAchievements.cs b/Portal/Portal.Database/Models/UserAchievements.cs new file mode 100644 index 0000000..160f939 --- /dev/null +++ b/Portal/Portal.Database/Models/UserAchievements.cs @@ -0,0 +1,9 @@ +namespace Portal.Database.Models; + +public class UserAchievements +{ + public User User { get; set; } + public Achievement Achievement { get; set; } + public DateTime UnlockedAt { get; set; } + public int Progress { get; set; } +} diff --git a/Portal/Portal.Database/Portal.Database.csproj b/Portal/Portal.Database/Portal.Database.csproj new file mode 100644 index 0000000..1fbe411 --- /dev/null +++ b/Portal/Portal.Database/Portal.Database.csproj @@ -0,0 +1,17 @@ + + + + net10.0 + enable + enable + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/Portal/Portal.Dto/Class1.cs b/Portal/Portal.Dto/Class1.cs new file mode 100644 index 0000000..b3f360e --- /dev/null +++ b/Portal/Portal.Dto/Class1.cs @@ -0,0 +1,6 @@ +namespace Portal.Dto; + +public class Class1 +{ + +} diff --git a/Portal/Portal.Dto/Portal.Dto.csproj b/Portal/Portal.Dto/Portal.Dto.csproj new file mode 100644 index 0000000..b760144 --- /dev/null +++ b/Portal/Portal.Dto/Portal.Dto.csproj @@ -0,0 +1,9 @@ + + + + net10.0 + enable + enable + + + diff --git a/Portal/Portal.slnx b/Portal/Portal.slnx new file mode 100644 index 0000000..48b5f58 --- /dev/null +++ b/Portal/Portal.slnx @@ -0,0 +1,7 @@ + + + + + + + From 0be0b7e5b78d151a85dc5dd9747c9a901e7b93dc Mon Sep 17 00:00:00 2001 From: Antti Veikkolainen Date: Sat, 6 Dec 2025 17:25:08 +0200 Subject: [PATCH 92/92] #52 Fix files (#114) Co-authored-by: Antti Veikkolainen --- .../Resources => Resources}/Screenshots/editor.png | Bin .../Screenshots/launcher.png | Bin {Engine/Resources => Resources}/icon.ico | Bin {Engine/Resources => Resources}/icon.png | Bin {Engine/Resources => Resources}/icon.svg | 0 {Engine/Resources => Resources}/icon.xcf | Bin {Engine/docs => docs}/CODE_OF_CONDUCT.md | 0 {Engine/docs => docs}/CONTRIBUTING.md | 0 {Engine/docs => docs}/SECURITY.md | 0 {Engine/docs => docs}/materials_and_inspiration.md | 0 {Engine/docs => docs}/pull_request_template.md | 0 11 files changed, 0 insertions(+), 0 deletions(-) rename {Engine/Resources => Resources}/Screenshots/editor.png (100%) rename {Engine/Resources => Resources}/Screenshots/launcher.png (100%) rename {Engine/Resources => Resources}/icon.ico (100%) rename {Engine/Resources => Resources}/icon.png (100%) rename {Engine/Resources => Resources}/icon.svg (100%) rename {Engine/Resources => Resources}/icon.xcf (100%) rename {Engine/docs => docs}/CODE_OF_CONDUCT.md (100%) rename {Engine/docs => docs}/CONTRIBUTING.md (100%) rename {Engine/docs => docs}/SECURITY.md (100%) rename {Engine/docs => docs}/materials_and_inspiration.md (100%) rename {Engine/docs => docs}/pull_request_template.md (100%) diff --git a/Engine/Resources/Screenshots/editor.png b/Resources/Screenshots/editor.png similarity index 100% rename from Engine/Resources/Screenshots/editor.png rename to Resources/Screenshots/editor.png diff --git a/Engine/Resources/Screenshots/launcher.png b/Resources/Screenshots/launcher.png similarity index 100% rename from Engine/Resources/Screenshots/launcher.png rename to Resources/Screenshots/launcher.png diff --git a/Engine/Resources/icon.ico b/Resources/icon.ico similarity index 100% rename from Engine/Resources/icon.ico rename to Resources/icon.ico diff --git a/Engine/Resources/icon.png b/Resources/icon.png similarity index 100% rename from Engine/Resources/icon.png rename to Resources/icon.png diff --git a/Engine/Resources/icon.svg b/Resources/icon.svg similarity index 100% rename from Engine/Resources/icon.svg rename to Resources/icon.svg diff --git a/Engine/Resources/icon.xcf b/Resources/icon.xcf similarity index 100% rename from Engine/Resources/icon.xcf rename to Resources/icon.xcf diff --git a/Engine/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md similarity index 100% rename from Engine/docs/CODE_OF_CONDUCT.md rename to docs/CODE_OF_CONDUCT.md diff --git a/Engine/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md similarity index 100% rename from Engine/docs/CONTRIBUTING.md rename to docs/CONTRIBUTING.md diff --git a/Engine/docs/SECURITY.md b/docs/SECURITY.md similarity index 100% rename from Engine/docs/SECURITY.md rename to docs/SECURITY.md diff --git a/Engine/docs/materials_and_inspiration.md b/docs/materials_and_inspiration.md similarity index 100% rename from Engine/docs/materials_and_inspiration.md rename to docs/materials_and_inspiration.md diff --git a/Engine/docs/pull_request_template.md b/docs/pull_request_template.md similarity index 100% rename from Engine/docs/pull_request_template.md rename to docs/pull_request_template.md