├── .gitignore ├── Examples.SampleGame ├── Assets │ └── Textures │ │ ├── background_0.png │ │ ├── background_1.png │ │ ├── background_2.png │ │ ├── background_3.png │ │ ├── border.png │ │ ├── color_palette.ai │ │ ├── color_palette.png │ │ ├── n8dev.png │ │ ├── player.png │ │ ├── spike_d.png │ │ ├── spike_u.png │ │ └── sprite_sheet.ai ├── Examples.SampleGame.csproj ├── Examples.SampleGame.csproj.DotSettings └── Source │ ├── Components │ ├── Body.cs │ ├── Parallax.cs │ ├── Player.cs │ ├── PlayerStart.cs │ ├── RestartScene.cs │ └── Scrolling.cs │ ├── Globals │ ├── Events.cs │ └── Scenes.cs │ ├── Program.cs │ ├── Scenes │ └── MainScene.cs │ └── Utilities │ └── Event.cs ├── LICENSE ├── N8Engine.Core ├── Assets │ ├── Shaders │ │ ├── colors.frag │ │ ├── colors.vert │ │ ├── sprite.frag │ │ └── sprite.vert │ └── Textures │ │ └── n8dev.png ├── N8Engine.Core.csproj ├── N8Engine.Core.csproj.DotSettings └── Source │ ├── Core │ ├── Component.cs │ ├── Debug.cs │ ├── Exceptions │ │ ├── ComponentAlreadyAttachedException.cs │ │ ├── ComponentNotAttachedException.cs │ │ ├── GameObjectIsDestroyedException.cs │ │ └── ModuleNotFoundException.cs │ ├── Frame.cs │ ├── Game.cs │ ├── GameObject.cs │ ├── GameStart.cs │ ├── Loop.cs │ ├── Module.cs │ ├── Modules.cs │ ├── Ticks.cs │ ├── Transform.cs │ └── UpdateDebugger.cs │ ├── InputSystem │ ├── Input.cs │ ├── InputDebugger.cs │ ├── InputExtensions.cs │ ├── Key.cs │ └── KeyExtensions.cs │ ├── Rendering │ ├── BufferObject.cs │ ├── Camera.cs │ ├── CameraController.cs │ ├── Exceptions │ │ ├── MissingUniformOnShaderException.cs │ │ ├── ShaderFailedCompilationException.cs │ │ └── ShaderProgramFailedLinkException.cs │ ├── Graphics.cs │ ├── Shader.cs │ ├── Sprite.cs │ ├── SpriteRenderer.cs │ ├── Texture.cs │ └── VertexArrayObject.cs │ ├── SceneManagement │ ├── Element.cs │ ├── ElementNotFoundException.cs │ ├── Elements.cs │ ├── EmptyScene.cs │ ├── Scene.cs │ └── SceneManager.cs │ ├── Utilities │ ├── Bounds.cs │ ├── MathExtensions.cs │ ├── PathExtensions.cs │ ├── ServiceLocator.cs │ └── ServiceNotFoundException.cs │ └── Windowing │ ├── Window.cs │ ├── WindowEvents.cs │ ├── WindowOptions.cs │ ├── WindowSize.cs │ └── WindowState.cs ├── N8Engine.Tests ├── Assets │ └── dummy.txt ├── N8Engine.Tests.csproj ├── N8Engine.Tests.csproj.DotSettings └── Source │ ├── BoundsTests.cs │ ├── DebugTests.cs │ ├── GameObjectTests.cs │ ├── InputSystemTests.cs │ ├── PathExtensionsTests.cs │ ├── SceneManagementTests.cs │ └── ServiceLocatorTests.cs ├── N8Engine.sln ├── N8Engine.sln.DotSettings └── N8Engine.sln.DotSettings.user /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | /packages/ 4 | riderModule.iml 5 | /_ReSharper.Caches/ 6 | .idea/ 7 | -------------------------------------------------------------------------------- /Examples.SampleGame/Assets/Textures/background_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natecurtiss/n8engine/4148c2b2328acb846f8a6c063776662bd21e0ecd/Examples.SampleGame/Assets/Textures/background_0.png -------------------------------------------------------------------------------- /Examples.SampleGame/Assets/Textures/background_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natecurtiss/n8engine/4148c2b2328acb846f8a6c063776662bd21e0ecd/Examples.SampleGame/Assets/Textures/background_1.png -------------------------------------------------------------------------------- /Examples.SampleGame/Assets/Textures/background_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natecurtiss/n8engine/4148c2b2328acb846f8a6c063776662bd21e0ecd/Examples.SampleGame/Assets/Textures/background_2.png -------------------------------------------------------------------------------- /Examples.SampleGame/Assets/Textures/background_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natecurtiss/n8engine/4148c2b2328acb846f8a6c063776662bd21e0ecd/Examples.SampleGame/Assets/Textures/background_3.png -------------------------------------------------------------------------------- /Examples.SampleGame/Assets/Textures/border.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natecurtiss/n8engine/4148c2b2328acb846f8a6c063776662bd21e0ecd/Examples.SampleGame/Assets/Textures/border.png -------------------------------------------------------------------------------- /Examples.SampleGame/Assets/Textures/color_palette.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natecurtiss/n8engine/4148c2b2328acb846f8a6c063776662bd21e0ecd/Examples.SampleGame/Assets/Textures/color_palette.ai -------------------------------------------------------------------------------- /Examples.SampleGame/Assets/Textures/color_palette.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natecurtiss/n8engine/4148c2b2328acb846f8a6c063776662bd21e0ecd/Examples.SampleGame/Assets/Textures/color_palette.png -------------------------------------------------------------------------------- /Examples.SampleGame/Assets/Textures/n8dev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natecurtiss/n8engine/4148c2b2328acb846f8a6c063776662bd21e0ecd/Examples.SampleGame/Assets/Textures/n8dev.png -------------------------------------------------------------------------------- /Examples.SampleGame/Assets/Textures/player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natecurtiss/n8engine/4148c2b2328acb846f8a6c063776662bd21e0ecd/Examples.SampleGame/Assets/Textures/player.png -------------------------------------------------------------------------------- /Examples.SampleGame/Assets/Textures/spike_d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natecurtiss/n8engine/4148c2b2328acb846f8a6c063776662bd21e0ecd/Examples.SampleGame/Assets/Textures/spike_d.png -------------------------------------------------------------------------------- /Examples.SampleGame/Assets/Textures/spike_u.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natecurtiss/n8engine/4148c2b2328acb846f8a6c063776662bd21e0ecd/Examples.SampleGame/Assets/Textures/spike_u.png -------------------------------------------------------------------------------- /Examples.SampleGame/Assets/Textures/sprite_sheet.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natecurtiss/n8engine/4148c2b2328acb846f8a6c063776662bd21e0ecd/Examples.SampleGame/Assets/Textures/sprite_sheet.ai -------------------------------------------------------------------------------- /Examples.SampleGame/Examples.SampleGame.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | latest 7 | SampleGame 8 | Release;Debug 9 | AnyCPU 10 | 11 | 12 | 13 | x64 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Examples.SampleGame/Examples.SampleGame.csproj.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True 3 | True 4 | True 5 | True 6 | True -------------------------------------------------------------------------------- /Examples.SampleGame/Source/Components/Body.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using N8Engine; 3 | 4 | namespace SampleGame; 5 | 6 | sealed class Body : Component 7 | { 8 | readonly float _gravity; 9 | 10 | public Vector2 Velocity { get; set; } 11 | public bool UseGravity { get; set; } 12 | 13 | public Body(float gravity, bool useGravity = true) 14 | { 15 | _gravity = gravity; 16 | UseGravity = useGravity; 17 | } 18 | 19 | public override void EarlyUpdate(Frame frame) 20 | { 21 | if (!UseGravity) 22 | return; 23 | var vel = Velocity; 24 | // V = 1/2g * t^2 25 | vel.Y += _gravity * frame.DeltaTime; 26 | Velocity = vel; 27 | } 28 | } -------------------------------------------------------------------------------- /Examples.SampleGame/Source/Components/Parallax.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using N8Engine; 3 | using N8Engine.SceneManagement; 4 | 5 | namespace SampleGame; 6 | 7 | sealed class Parallax : Component 8 | { 9 | // Values 0-1 work best. 10 | readonly float _speed; 11 | readonly Scrolling _scrolling; 12 | 13 | Transform _transform; 14 | float _length; 15 | float _startingPosition; 16 | 17 | public Parallax(float speed, Scrolling scrolling) 18 | { 19 | _speed = speed; 20 | _scrolling = scrolling; 21 | } 22 | 23 | public override void Create(GameObject gameObject, Scene scene) 24 | { 25 | _transform = gameObject.GetComponent(); 26 | _length = _transform.Bounds().Size.X; 27 | _startingPosition = _transform.Position.X; 28 | } 29 | 30 | public override void LateUpdate(Frame frame) 31 | { 32 | _transform.Position -= new Vector2(_scrolling.Speed * frame.DeltaTime * (1 - _speed), 0f); 33 | var distance = _startingPosition - _transform.Position.X; 34 | if (distance > _length) 35 | _transform.Position = new(_startingPosition, _transform.Position.Y); 36 | } 37 | } -------------------------------------------------------------------------------- /Examples.SampleGame/Source/Components/Player.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using N8Engine; 3 | using N8Engine.SceneManagement; 4 | 5 | namespace SampleGame; 6 | 7 | sealed class Player : Component 8 | { 9 | readonly float _jump; 10 | readonly Func _whenToJump; 11 | 12 | Transform _transform; 13 | Body _body; 14 | 15 | public bool IsEnabled { get; set; } 16 | 17 | public Player(float jump, Func whenToJump) 18 | { 19 | _jump = jump; 20 | _whenToJump = whenToJump; 21 | } 22 | 23 | public override void Create(GameObject gameObject, Scene scene) 24 | { 25 | _transform = gameObject.GetComponent(); 26 | _body = gameObject.GetComponent(); 27 | Events.OnPlayerStart.Add(Enable); 28 | } 29 | 30 | public override void Destroy() => Events.OnPlayerStart.Remove(Enable); 31 | 32 | public override void Update(Frame frame) 33 | { 34 | if (!IsEnabled) 35 | return; 36 | if (_whenToJump()) 37 | _body.Velocity = new(0, _jump); 38 | _transform.Position += _body.Velocity * frame.DeltaTime; 39 | } 40 | 41 | void Enable() 42 | { 43 | IsEnabled = true; 44 | _body.UseGravity = true; 45 | } 46 | } -------------------------------------------------------------------------------- /Examples.SampleGame/Source/Components/PlayerStart.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using N8Engine; 3 | using N8Engine.SceneManagement; 4 | 5 | namespace SampleGame; 6 | 7 | sealed class PlayerStart : Component 8 | { 9 | readonly Func _whenToStart; 10 | GameObject _gameObject; 11 | 12 | public PlayerStart(Func whenToStart) => _whenToStart = whenToStart; 13 | 14 | public override void Create(GameObject gameObject, Scene scene) => _gameObject = gameObject; 15 | 16 | public override void Update(Frame frame) 17 | { 18 | if (_whenToStart()) 19 | { 20 | Events.OnPlayerStart.Raise(); 21 | _gameObject.RemoveComponent(); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /Examples.SampleGame/Source/Components/RestartScene.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using N8Engine; 3 | using N8Engine.SceneManagement; 4 | 5 | namespace SampleGame; 6 | 7 | sealed class RestartScene : Component 8 | { 9 | readonly Func _whenToRestart; 10 | readonly SceneManager _sceneManager; 11 | 12 | public RestartScene(Func whenToRestart) 13 | { 14 | _whenToRestart = whenToRestart; 15 | _sceneManager = Modules.Get(); 16 | } 17 | 18 | public override void LateUpdate(Frame frame) 19 | { 20 | if (_whenToRestart()) 21 | _sceneManager.Load(_sceneManager.CurrentScene); 22 | } 23 | } -------------------------------------------------------------------------------- /Examples.SampleGame/Source/Components/Scrolling.cs: -------------------------------------------------------------------------------- 1 | namespace SampleGame; 2 | 3 | sealed class Scrolling 4 | { 5 | public bool IsScrolling { get; private set; } 6 | public float Speed { get; } 7 | 8 | public Scrolling(float speed) => Speed = speed; 9 | 10 | public void Start() => IsScrolling = true; 11 | public void Stop() => IsScrolling = false; 12 | } -------------------------------------------------------------------------------- /Examples.SampleGame/Source/Globals/Events.cs: -------------------------------------------------------------------------------- 1 | namespace SampleGame; 2 | 3 | static class Events 4 | { 5 | public static readonly Event OnPlayerStart = new(); 6 | } -------------------------------------------------------------------------------- /Examples.SampleGame/Source/Globals/Scenes.cs: -------------------------------------------------------------------------------- 1 | namespace SampleGame; 2 | 3 | static class Scenes 4 | { 5 | public static readonly MainScene Main = new(); 6 | } -------------------------------------------------------------------------------- /Examples.SampleGame/Source/Program.cs: -------------------------------------------------------------------------------- 1 | using N8Engine; 2 | using SampleGame; 3 | 4 | new Game() 5 | .WithFirstScene(Scenes.Main) 6 | .WithWindowTitle("Flappo") 7 | .WithWindowSize(1300, 700) 8 | .WithNotResizableWindow() 9 | .Run(); -------------------------------------------------------------------------------- /Examples.SampleGame/Source/Scenes/MainScene.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using N8Engine; 3 | using N8Engine.InputSystem; 4 | using N8Engine.Rendering; 5 | using N8Engine.SceneManagement; 6 | using N8Engine.Utilities; 7 | 8 | namespace SampleGame; 9 | 10 | sealed class MainScene : Scene 11 | { 12 | public override string Name => "Main"; 13 | 14 | protected override void Load() 15 | { 16 | var input = Modules.Get(); 17 | var camera = Get(); 18 | camera.Zoom = 0.5f; 19 | 20 | Create("background_wall") 21 | .AddComponent(new Transform().WithScale(1920 * 2, 1080 * 2)) 22 | .AddComponent(new Sprite("Assets/Textures/background_3.png".Find())); 23 | 24 | var scrolling = new Scrolling(1000f); 25 | var scrollSpeeds = new[] { 0f, 0.5f, 0.8f }; 26 | var scrollPositions = new[] {-500f, -210, 60f}; 27 | var duplicateScrollPositions = new[] {-3918f, 0, 3918f}; 28 | var backgroundScales = new Vector2[] {new(3918, 395), new(3918, 518), new(3918, 743)}; 29 | for (var s = 2; s >= 0; s--) 30 | { 31 | for (var d = 0; d < 3; d++) 32 | { 33 | Create($"background_{s}_{d}") 34 | .AddComponent(new Parallax(scrollSpeeds[s], scrolling)) 35 | .AddComponent(new Sprite($"Assets/Textures/background_{s}.png".Find())) 36 | .AddComponent(new Transform() 37 | .AtPosition(duplicateScrollPositions[d], scrollPositions[s]) 38 | .WithScale(backgroundScales[s])); 39 | } 40 | } 41 | 42 | Create("player") 43 | .AddComponent(new PlayerStart(() => input.WasJustPressed(Key.Space))) 44 | .AddComponent(new Player(1000f, () => input.WasJustPressed(Key.Space))) 45 | .AddComponent(new Body(-2300)) 46 | .AddComponent(new Sprite("Assets/Textures/player.png".Find())) 47 | .AddComponent(new Transform() 48 | .AtPosition(-100, 0) 49 | .WithScale(199, 178), out var player) 50 | .AddComponent(new RestartScene(() => !camera.Bounds().Contains(player.Position))); 51 | } 52 | } -------------------------------------------------------------------------------- /Examples.SampleGame/Source/Utilities/Event.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SampleGame; 4 | 5 | sealed class Event 6 | { 7 | event Action OnEvent; 8 | public void Add(Action action) => OnEvent += action; 9 | public void Remove(Action action) => OnEvent -= action; 10 | public void Raise() => OnEvent?.Invoke(); 11 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Nathan Curtiss 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /N8Engine.Core/Assets/Shaders/colors.frag: -------------------------------------------------------------------------------- 1 |  #version 330 core 2 | 3 | in vec4 fColor; 4 | out vec4 FragColor; 5 | 6 | void main() 7 | { 8 | FragColor = fColor; 9 | } -------------------------------------------------------------------------------- /N8Engine.Core/Assets/Shaders/colors.vert: -------------------------------------------------------------------------------- 1 |  #version 330 core 2 | 3 | layout (location = 0) in vec3 vPos; 4 | layout (location = 1) in vec4 vColor; 5 | 6 | uniform float uBlue; 7 | 8 | out vec4 fColor; 9 | 10 | void main() 11 | { 12 | gl_Position = vec4(vPos, 1.0); 13 | fColor = vColor; 14 | } -------------------------------------------------------------------------------- /N8Engine.Core/Assets/Shaders/sprite.frag: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | in vec2 fUv; 3 | 4 | uniform sampler2D uTexture0; 5 | 6 | out vec4 FragColor; 7 | 8 | void main() 9 | { 10 | if (texture(uTexture0, fUv).a != 1.0f) 11 | { 12 | discard; 13 | } 14 | FragColor = texture(uTexture0, fUv); 15 | } -------------------------------------------------------------------------------- /N8Engine.Core/Assets/Shaders/sprite.vert: -------------------------------------------------------------------------------- 1 | #version 330 core 2 | layout (location = 0) in vec3 vPos; 3 | layout (location = 1) in vec2 vUv; 4 | 5 | uniform mat4 uModel; 6 | uniform mat4 uProjection; 7 | 8 | out vec2 fUv; 9 | 10 | void main() 11 | { 12 | gl_Position = uProjection * uModel * vec4(vPos, 1.0); 13 | fUv = vUv; 14 | } -------------------------------------------------------------------------------- /N8Engine.Core/Assets/Textures/n8dev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natecurtiss/n8engine/4148c2b2328acb846f8a6c063776662bd21e0ecd/N8Engine.Core/Assets/Textures/n8dev.png -------------------------------------------------------------------------------- /N8Engine.Core/N8Engine.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | net6.0 6 | true 7 | true 8 | n8engine 9 | n8dev 10 | An open-source C# terminal game engine. 11 | https://github.com/N-8-D-e-v/n8engine 12 | n8engine 13 | https://www.mit.edu/~amini/LICENSE.md 14 | true 15 | 2.1.0 16 | true 17 | latest 18 | N8Engine 19 | Release;Debug 20 | AnyCPU 21 | 22 | 23 | 24 | 25 | true 26 | 27 | 28 | 29 | 30 | <_Parameter1>N8Engine.Tests 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /N8Engine.Core/N8Engine.Core.csproj.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True 3 | True 4 | True 5 | False 6 | True 7 | True 8 | True -------------------------------------------------------------------------------- /N8Engine.Core/Source/Core/Component.cs: -------------------------------------------------------------------------------- 1 | using N8Engine.SceneManagement; 2 | 3 | namespace N8Engine; 4 | 5 | public abstract class Component 6 | { 7 | public virtual void Destroy() { } 8 | public virtual void Create(GameObject gameObject, Scene scene) { } 9 | public virtual void Start() { } 10 | public virtual void EarlyUpdate(Frame frame) { } 11 | public virtual void Update(Frame frame) { } 12 | public virtual void LateUpdate(Frame frame) { } 13 | public virtual void Render() { } 14 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Core/Debug.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace N8Engine; 4 | 5 | public static class Debug 6 | { 7 | static Action _onOutput; 8 | public static void OnOutput(Action onOutput) => _onOutput = onOutput; 9 | public static void Log(object message) => _onOutput(message); 10 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Core/Exceptions/ComponentAlreadyAttachedException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace N8Engine; 4 | 5 | public sealed class ComponentAlreadyAttachedException : Exception 6 | { 7 | public ComponentAlreadyAttachedException() { } 8 | public ComponentAlreadyAttachedException(string message) : base(message) { } 9 | public ComponentAlreadyAttachedException(string message, Exception inner) : base(message, inner) { } 10 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Core/Exceptions/ComponentNotAttachedException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace N8Engine; 4 | 5 | public class ComponentNotAttachedException : Exception 6 | { 7 | public ComponentNotAttachedException() { } 8 | public ComponentNotAttachedException(string message) : base(message) { } 9 | public ComponentNotAttachedException(string message, Exception inner) : base(message, inner) { } 10 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Core/Exceptions/GameObjectIsDestroyedException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace N8Engine; 4 | 5 | public sealed class GameObjectIsDestroyedException : Exception 6 | { 7 | public GameObjectIsDestroyedException() { } 8 | public GameObjectIsDestroyedException(string message) : base(message) { } 9 | public GameObjectIsDestroyedException(string message, Exception inner) : base(message, inner) { } 10 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Core/Exceptions/ModuleNotFoundException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace N8Engine; 4 | 5 | public sealed class ModuleNotFoundException : Exception 6 | { 7 | public ModuleNotFoundException() { } 8 | public ModuleNotFoundException(string message) : base(message) { } 9 | public ModuleNotFoundException(string message, Exception inner) : base(message, inner) { } 10 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Core/Frame.cs: -------------------------------------------------------------------------------- 1 | namespace N8Engine; 2 | 3 | public struct Frame 4 | { 5 | public readonly float DeltaTime; 6 | 7 | public Frame(float deltaTime) 8 | { 9 | DeltaTime = deltaTime; 10 | } 11 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Core/Game.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using N8Engine.InputSystem; 3 | using N8Engine.Rendering; 4 | using N8Engine.SceneManagement; 5 | using N8Engine.Windowing; 6 | 7 | namespace N8Engine; 8 | 9 | public sealed class Game : Loop, Ticks 10 | { 11 | public event Action OnStart; 12 | public event Action OnUpdate; 13 | public event Action OnRender; 14 | 15 | WindowOptions _windowOptions; 16 | Scene _firstScene = new EmptyScene(); 17 | 18 | public Game() => _windowOptions = new("N8Engine Game", 1280, 720, 60, WindowState.Windowed, true); 19 | 20 | public Game WithWindowTitle(string title) 21 | { 22 | _windowOptions = _windowOptions.WithTitle(title); 23 | return this; 24 | } 25 | 26 | public Game WithWindowSize(uint width, uint height) 27 | { 28 | _windowOptions = _windowOptions.WithSize(width, height); 29 | return this; 30 | } 31 | 32 | public Game WithFps(int fps) 33 | { 34 | _windowOptions = _windowOptions.WithFps(fps); 35 | return this; 36 | } 37 | 38 | public Game Fullscreen() 39 | { 40 | _windowOptions = _windowOptions.Fullscreen(); 41 | return this; 42 | } 43 | 44 | public Game Maximized() 45 | { 46 | _windowOptions = _windowOptions.Maximized(); 47 | return this; 48 | } 49 | 50 | public Game Windowed() 51 | { 52 | _windowOptions = _windowOptions.Windowed(); 53 | return this; 54 | } 55 | 56 | public Game WithResizableWindow() 57 | { 58 | _windowOptions = _windowOptions.Resizable(); 59 | return this; 60 | } 61 | 62 | public Game WithNotResizableWindow() 63 | { 64 | _windowOptions = _windowOptions.NotResizable(); 65 | return this; 66 | } 67 | 68 | public Game WithFirstScene(Scene scene) 69 | { 70 | _firstScene = scene; 71 | return this; 72 | } 73 | 74 | public Game WithDebugOutput(Action onOutput) 75 | { 76 | Debug.OnOutput(onOutput); 77 | return this; 78 | } 79 | 80 | public void Run() => Run(GameStart.Default); 81 | internal void Run(GameStart starter) => starter.Start(this, this, _windowOptions, _firstScene); 82 | 83 | void Ticks.Start() => OnStart?.Invoke(); 84 | void Ticks.Update(Frame frame) => OnUpdate?.Invoke(frame); 85 | void Ticks.Render() => OnRender?.Invoke(); 86 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Core/GameObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using N8Engine.SceneManagement; 4 | 5 | namespace N8Engine; 6 | 7 | public sealed class GameObject 8 | { 9 | readonly Dictionary _components = new(); 10 | readonly Scene _scene; 11 | 12 | public bool IsDestroyed { get; private set; } 13 | public string Name { get; set; } 14 | 15 | internal GameObject(Scene scene, string name) 16 | { 17 | _scene = scene; 18 | Name = name; 19 | } 20 | 21 | public void Destroy() 22 | { 23 | IsDestroyed = true; 24 | _scene.Destroy(this); 25 | foreach (var component in _components.Values) 26 | component.Destroy(); 27 | _components.Clear(); 28 | } 29 | 30 | public T GetComponent() where T : Component 31 | { 32 | if (IsDestroyed) 33 | throw new GameObjectIsDestroyedException($"GameObject {Name} is destroyed, you cannot access its components!"); 34 | foreach (var (type, component) in _components) 35 | { 36 | if (type == typeof(T)) 37 | { 38 | var component1 = component as T; 39 | return component1; 40 | } 41 | } 42 | return null; 43 | } 44 | 45 | public GameObject AddComponent() where T : Component, new() => AddComponent(new T()); 46 | public GameObject AddComponent(out T result) where T : Component, new() => AddComponent(new(), out result); 47 | public GameObject AddComponent(T component) where T : Component => AddComponent(component, out _); 48 | public GameObject AddComponent(T component, out T result) where T : Component 49 | { 50 | if (IsDestroyed) 51 | throw new GameObjectIsDestroyedException($"GameObject {this} is destroyed, you cannot access its components!"); 52 | if (_components.ContainsKey(typeof(T))) 53 | throw new ComponentAlreadyAttachedException($"GameObject {this} already has a component of type {typeof(T)} attached!"); 54 | _components.Add(typeof(T), component); 55 | result = component; 56 | return this; 57 | } 58 | 59 | public GameObject RemoveComponent() where T : Component 60 | { 61 | if (!_components.ContainsKey(typeof(T))) 62 | throw new ComponentNotAttachedException($"Component of type {typeof(T)} is not attached to {this}!"); 63 | return RemoveComponent(_components[typeof(T)] as T); 64 | } 65 | 66 | public GameObject RemoveComponent(T component) where T : Component 67 | { 68 | if (IsDestroyed) 69 | throw new GameObjectIsDestroyedException($"GameObject {this} is destroyed, you cannot access its components!"); 70 | if (!_components.ContainsKey(typeof(T))) 71 | throw new ComponentNotAttachedException($"Component of type {typeof(T)} is not attached to {this}!"); 72 | _components.Remove(typeof(T)); 73 | component.Destroy(); 74 | return this; 75 | } 76 | 77 | internal void Create() 78 | { 79 | foreach (var component in _components.Values) 80 | { 81 | if (IsDestroyed) 82 | return; 83 | Console.WriteLine($"{this} {_scene.Name}"); 84 | component.Create(this, _scene); 85 | } 86 | } 87 | 88 | internal void Start() 89 | { 90 | foreach (var component in _components.Values) 91 | { 92 | if (IsDestroyed) 93 | return; 94 | component.Start(); 95 | } 96 | } 97 | 98 | internal void EarlyUpdate(Frame frame) 99 | { 100 | foreach (var component in _components.Values) 101 | { 102 | if (IsDestroyed) 103 | return; 104 | component.EarlyUpdate(frame); 105 | } 106 | } 107 | 108 | internal void Update(Frame frame) 109 | { 110 | foreach (var component in _components.Values) 111 | { 112 | if (IsDestroyed) 113 | return; 114 | component.Update(frame); 115 | } 116 | } 117 | 118 | internal void LateUpdate(Frame frame) 119 | { 120 | foreach (var component in _components.Values) 121 | { 122 | if (IsDestroyed) 123 | return; 124 | component.LateUpdate(frame); 125 | } 126 | } 127 | 128 | internal void Render() 129 | { 130 | foreach (var component in _components.Values) 131 | { 132 | if (IsDestroyed) 133 | return; 134 | component.Render(); 135 | } 136 | } 137 | 138 | public override string ToString() => Name; 139 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Core/GameStart.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using N8Engine.InputSystem; 3 | using N8Engine.Rendering; 4 | using N8Engine.SceneManagement; 5 | using N8Engine.Windowing; 6 | 7 | namespace N8Engine; 8 | 9 | readonly struct GameStart 10 | { 11 | public static readonly GameStart Default = new((loop, ticks, windowOptions, firstScene) => 12 | { 13 | var window = new Window(windowOptions); 14 | 15 | window.OnLoad += () => 16 | { 17 | var gl = window.CreateGL(); 18 | var input = new Input(); 19 | var sceneManager = new SceneManager(loop, window, m => 20 | { 21 | m.Add(new Camera(window)); 22 | m.Add(new SpriteRenderer(gl)); 23 | }, m => 24 | { 25 | m.Remove(); 26 | m.Remove(); 27 | }); 28 | Modules.Add(input); 29 | Modules.Add(sceneManager); 30 | Modules.Add(gl); 31 | 32 | sceneManager.Load(firstScene); 33 | ticks.Start(); 34 | window.OnUpdate += ticks.Update; 35 | window.OnRender += ticks.Render; 36 | window.OnKeyDown += key => input.UpdateKey(key, true); 37 | window.OnKeyUp += key => input.UpdateKey(key, false); 38 | }; 39 | window.Run(); 40 | }); 41 | readonly Action _onStart; 42 | 43 | public GameStart() => _onStart = (_, _, _, _) => { }; 44 | public GameStart(Action onStart) => _onStart = onStart; 45 | 46 | public void Start(Loop loop, Ticks ticks, WindowOptions windowOptions, Scene firstScene) => _onStart(loop, ticks, windowOptions, firstScene); 47 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Core/Loop.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace N8Engine; 4 | 5 | interface Loop 6 | { 7 | event Action OnStart; 8 | event Action OnUpdate; 9 | event Action OnRender; 10 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Core/Module.cs: -------------------------------------------------------------------------------- 1 | namespace N8Engine; 2 | 3 | public interface Module 4 | { 5 | 6 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Core/Modules.cs: -------------------------------------------------------------------------------- 1 | using N8Engine.Utilities; 2 | 3 | namespace N8Engine; 4 | 5 | public sealed class Modules : ServiceLocator 6 | { 7 | static readonly Modules _singleton = new(); 8 | 9 | protected override ModuleNotFoundException WhenMissing() => new($"Module of type {typeof(T)} not found!"); 10 | 11 | public static T Get() where T : Module => _singleton.Find(); 12 | internal static void Add(T module) where T : Module => _singleton.Register(module); 13 | internal static void Remove() where T : Module => _singleton.Deregister(); 14 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Core/Ticks.cs: -------------------------------------------------------------------------------- 1 | namespace N8Engine; 2 | 3 | interface Ticks 4 | { 5 | void Start(); 6 | void Update(Frame frame); 7 | void Render(); 8 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Core/Transform.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using N8Engine.Utilities; 3 | using static System.Numerics.Matrix4x4; 4 | 5 | namespace N8Engine; 6 | 7 | public sealed class Transform : Component 8 | { 9 | public Vector2 Position { get; set; } 10 | public Vector2 Scale { get; set; } = Vector2.One; 11 | public float Rotation { get; set; } 12 | 13 | public Transform AtPosition(Vector2 value) 14 | { 15 | Position = value; 16 | return this; 17 | } 18 | 19 | public Transform AtPosition(float x, float y) 20 | { 21 | Position = new(x, y); 22 | return this; 23 | } 24 | 25 | public Transform WithScale(Vector2 value) 26 | { 27 | Scale = value; 28 | return this; 29 | } 30 | 31 | public Transform WithScale(float x, float y) 32 | { 33 | Scale = new(x, y); 34 | return this; 35 | } 36 | 37 | public Transform WithRotation(float value) 38 | { 39 | Rotation = value; 40 | return this; 41 | } 42 | 43 | public Matrix4x4 ModelMatrix() => CreateScale(Scale.X, Scale.Y, 1f) * CreateRotationZ(Rotation.ToRadians()) * CreateTranslation(Position.X, Position.Y, 0f); 44 | public Bounds Bounds() => new(Position, Scale); 45 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Core/UpdateDebugger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace N8Engine; 4 | 5 | public sealed class UpdateDebugger : Component 6 | { 7 | readonly Action _onEarlyUpdate; 8 | readonly Action _onUpdate; 9 | readonly Action _onLateUpdate; 10 | 11 | public UpdateDebugger(Action onEarlyUpdate, Action onUpdate, Action onLateUpdate) 12 | { 13 | _onEarlyUpdate = onEarlyUpdate; 14 | _onUpdate = onUpdate; 15 | _onLateUpdate = onLateUpdate; 16 | } 17 | 18 | public override void EarlyUpdate(Frame frame) => _onEarlyUpdate?.Invoke(); 19 | public override void Update(Frame frame) => _onUpdate?.Invoke(); 20 | public override void LateUpdate(Frame frame) => _onLateUpdate?.Invoke(); 21 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/InputSystem/Input.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace N8Engine.InputSystem; 6 | 7 | // TODO: Fix this. 8 | public sealed class Input : Module 9 | { 10 | enum KeyState 11 | { 12 | IsPressed, 13 | IsReleased, 14 | WasJustPressed, 15 | WasJustReleased 16 | } 17 | 18 | public event Action OnKeyPress; 19 | public event Action OnKeyRelease; 20 | 21 | readonly Dictionary _keyStates = new(); 22 | readonly IEnumerable _allKeys = Enum.GetValues(); 23 | 24 | internal Input() 25 | { 26 | foreach (var key in _allKeys) 27 | { 28 | if (key != Key.Any && key != Key.Unknown) 29 | _keyStates.Add(key, KeyState.IsReleased); 30 | } 31 | } 32 | 33 | internal void UpdateKey(Key key, bool isDown) 34 | { 35 | if (key == Key.Unknown) 36 | return; 37 | 38 | var oldState = _keyStates[key]; 39 | var newState = KeyState.IsReleased; 40 | newState = oldState switch 41 | { 42 | KeyState.IsPressed => isDown ? KeyState.IsPressed : KeyState.WasJustReleased, 43 | KeyState.IsReleased => isDown ? KeyState.WasJustPressed : KeyState.IsReleased, 44 | KeyState.WasJustPressed => isDown ? KeyState.IsPressed : KeyState.WasJustReleased, 45 | KeyState.WasJustReleased => isDown ? KeyState.WasJustPressed : KeyState.IsReleased, 46 | _ => newState 47 | }; 48 | _keyStates[key] = newState; 49 | 50 | if (newState == KeyState.WasJustPressed) 51 | OnKeyPress?.Invoke(key); 52 | else if (newState == KeyState.WasJustReleased) 53 | OnKeyRelease?.Invoke(key); 54 | } 55 | 56 | public bool IsReleased(Key key) 57 | { 58 | if (key == Key.Unknown) 59 | return false; 60 | if (key == Key.Any) 61 | { 62 | var keys = _keyStates.Values; 63 | if (keys.Any(state => state is KeyState.IsReleased or KeyState.WasJustReleased)) 64 | return true; 65 | } 66 | else 67 | { 68 | return _keyStates[key] == KeyState.IsReleased || WasJustReleased(key); 69 | } 70 | return false; 71 | } 72 | 73 | public bool IsPressed(Key key) 74 | { 75 | if (key == Key.Unknown) 76 | return false; 77 | if (key == Key.Any) 78 | { 79 | var keys = _keyStates.Values; 80 | if (keys.Any(state => state is KeyState.IsPressed or KeyState.WasJustPressed)) 81 | return true; 82 | } 83 | else 84 | { 85 | return _keyStates[key] == KeyState.IsPressed || WasJustPressed(key); 86 | } 87 | return false; 88 | } 89 | 90 | public bool WasJustReleased(Key key) 91 | { 92 | if (key == Key.Unknown) 93 | return false; 94 | if (key == Key.Any) 95 | { 96 | var keys = _keyStates.Values; 97 | if (keys.Any(state => state == KeyState.WasJustReleased)) 98 | return true; 99 | } 100 | else 101 | { 102 | return _keyStates[key] == KeyState.WasJustReleased; 103 | } 104 | return false; 105 | } 106 | 107 | public bool WasJustPressed(Key key) 108 | { 109 | if (key == Key.Unknown) 110 | return false; 111 | if (key == Key.Any) 112 | { 113 | var keys = _keyStates.Values; 114 | if (keys.Any(state => state == KeyState.WasJustPressed)) 115 | return true; 116 | } 117 | else 118 | { 119 | return _keyStates[key] == KeyState.WasJustPressed; 120 | } 121 | return false; 122 | } 123 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/InputSystem/InputDebugger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace N8Engine.InputSystem; 4 | 5 | public sealed class InputDebugger : Component 6 | { 7 | readonly Action _onInput; 8 | readonly Input _input; 9 | 10 | public InputDebugger(Action onInput) 11 | { 12 | _onInput = onInput; 13 | _input = Modules.Get(); 14 | _input.OnKeyPress += KeyDown; 15 | } 16 | 17 | public override void Destroy() => _input.OnKeyPress -= KeyDown; 18 | 19 | void KeyDown(Key key) => _onInput(key); 20 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/InputSystem/InputExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using N8Engine.Utilities; 3 | using static N8Engine.InputSystem.Key; 4 | 5 | namespace N8Engine.InputSystem; 6 | 7 | public static class InputExtensions 8 | { 9 | public static Vector2 Axis(this Input input) => new Vector2(input.Horizontal(), input.Vertical()).Normalized(); 10 | 11 | public static float Horizontal(this Input input) 12 | { 13 | bool isDown(Key key) => input.IsPressed(key); 14 | return 15 | isDown(LeftArrow) || isDown(A) ? -1f : 16 | isDown(RightArrow) || isDown(D) ? 1f : 0f; 17 | } 18 | 19 | public static float Vertical(this Input input) 20 | { 21 | bool isDown(Key key) => input.IsPressed(key); 22 | return 23 | isDown(DownArrow) || isDown(S) ? -1f : 24 | isDown(UpArrow) || isDown(W) ? 1f : 0f; 25 | } 26 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/InputSystem/Key.cs: -------------------------------------------------------------------------------- 1 | namespace N8Engine.InputSystem; 2 | 3 | public enum Key 4 | { 5 | Any = -99, 6 | Unknown = -1, 7 | Space = 32, 8 | Apostrophe = 39 /* ' */, 9 | Comma = 44 /* , */, 10 | Minus = 45 /* - */, 11 | Period = 46 /* . */, 12 | Slash = 47 /* / */, 13 | Zero = 48, 14 | One = 49, 15 | Two = 50, 16 | Three = 51, 17 | Four = 52, 18 | Five = 53, 19 | Six = 54, 20 | Seven = 55, 21 | Eight = 56, 22 | Nine = 57, 23 | Semicolon = 59 /* ; */, 24 | Equals = 61 /* = */, 25 | A = 65, 26 | B = 66, 27 | C = 67, 28 | D = 68, 29 | E = 69, 30 | F = 70, 31 | G = 71, 32 | H = 72, 33 | I = 73, 34 | J = 74, 35 | K = 75, 36 | L = 76, 37 | M = 77, 38 | N = 78, 39 | O = 79, 40 | P = 80, 41 | Q = 81, 42 | R = 82, 43 | S = 83, 44 | T = 84, 45 | U = 85, 46 | V = 86, 47 | W = 87, 48 | X = 88, 49 | Y = 89, 50 | Z = 90, 51 | LeftBracket = 91 /* [ */, 52 | BackSlash = 92 /* \ */, 53 | RightBracket = 93 /* ] */, 54 | GraveAccent = 96 /* ` */, 55 | Esc = 256, 56 | Enter = 257, 57 | Tab = 258, 58 | Backspace = 259, 59 | Insert = 260, 60 | Delete = 261, 61 | RightArrow = 262, 62 | LeftArrow = 263, 63 | DownArrow = 264, 64 | UpArrow = 265, 65 | PageUp = 266, 66 | PageDown = 267, 67 | Home = 268, 68 | End = 269, 69 | CapsLock = 280, 70 | ScrollLock = 281, 71 | NumLock = 282, 72 | PrintScreen = 283, 73 | Pause = 284, 74 | F1 = 290, 75 | F2 = 291, 76 | F3 = 292, 77 | F4 = 293, 78 | F5 = 294, 79 | F6 = 295, 80 | F7 = 296, 81 | F8 = 297, 82 | F9 = 298, 83 | F10 = 299, 84 | F11 = 300, 85 | F12 = 301, 86 | F13 = 302, 87 | F14 = 303, 88 | F15 = 304, 89 | F16 = 305, 90 | F17 = 306, 91 | F18 = 307, 92 | F19 = 308, 93 | F20 = 309, 94 | F21 = 310, 95 | F22 = 311, 96 | F23 = 312, 97 | F24 = 313, 98 | F25 = 314, 99 | Numpad0 = 320, 100 | Numpad1 = 321, 101 | Numpad2 = 322, 102 | Numpad3 = 323, 103 | Numpad4 = 324, 104 | Numpad5 = 325, 105 | Numpad6 = 326, 106 | Numpad7 = 327, 107 | Numpad8 = 328, 108 | Numpad9 = 329, 109 | NumpadDecimal = 330, 110 | NumpadDivide = 331, 111 | NumpadMultiply = 332, 112 | NumpadSubtract = 333, 113 | NumpadAdd = 334, 114 | NumpadEnter = 335, 115 | NumpadEquals = 336, 116 | LeftShift = 340, 117 | LeftCtrl = 341, 118 | LeftAlt = 342, 119 | RightShift = 344, 120 | RightCtrl = 345, 121 | RightAlt = 346, 122 | Menu = 348 123 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/InputSystem/KeyExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using GLKey = Silk.NET.Input.Key; 3 | 4 | namespace N8Engine.InputSystem; 5 | 6 | static class KeyExtensions 7 | { 8 | public static Key AsKey(this GLKey glKey) 9 | { 10 | try 11 | { 12 | var key = (Key) (int) glKey; 13 | return key; 14 | } 15 | catch (Exception) 16 | { 17 | return Key.Unknown; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Rendering/BufferObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Silk.NET.OpenGL; 3 | 4 | namespace N8Engine.Rendering; 5 | 6 | sealed class BufferObject : IDisposable where T : unmanaged 7 | { 8 | readonly GL _gl; 9 | readonly uint _handle; 10 | readonly BufferTargetARB _bufferType; 11 | 12 | public unsafe BufferObject(GL gl, Span data, BufferTargetARB bufferType) 13 | { 14 | _gl = gl; 15 | _bufferType = bufferType; 16 | _handle = _gl.GenBuffer(); 17 | Bind(); 18 | fixed (void* d = data) 19 | { 20 | _gl.BufferData(bufferType, (nuint) (data.Length * sizeof(T)), d, BufferUsageARB.StaticDraw); 21 | } 22 | } 23 | 24 | public void Bind() => _gl.BindBuffer(_bufferType, _handle); 25 | public void Dispose() => _gl.DeleteBuffer(_handle); 26 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Rendering/Camera.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using N8Engine.SceneManagement; 3 | using N8Engine.Utilities; 4 | using N8Engine.Windowing; 5 | 6 | namespace N8Engine.Rendering; 7 | 8 | public sealed class Camera : Element 9 | { 10 | public Vector2 Position { get; set; } 11 | public float Zoom { get; set; } = 1f; 12 | 13 | readonly WindowSize _windowSize; 14 | 15 | internal Camera(WindowSize windowSize) => _windowSize = windowSize; 16 | 17 | public Bounds Bounds() 18 | { 19 | var size = new Vector2(_windowSize.Width, _windowSize.Height); 20 | size /= Zoom; 21 | return new(Position, size); 22 | } 23 | 24 | internal Matrix4x4 ProjectionMatrix() 25 | { 26 | var left = Position.X - _windowSize.Width / 2f; 27 | var right = Position.X + _windowSize.Width / 2f; 28 | var top = Position.Y + _windowSize.Height / 2f; 29 | var bottom = Position.Y - _windowSize.Height / 2f; 30 | 31 | var orthographicMatrix = Matrix4x4.CreateOrthographicOffCenter(left, right, bottom, top, 0.01f, 100f); 32 | var zoomMatrix = Matrix4x4.CreateScale(Zoom); 33 | return orthographicMatrix * zoomMatrix; 34 | } 35 | 36 | void Element.OnSceneLoad(Scene scene) { } 37 | void Element.OnSceneUpdate() { } 38 | void Element.OnSceneRender() { } 39 | void Element.OnSceneUnload() { } 40 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Rendering/CameraController.cs: -------------------------------------------------------------------------------- 1 | using N8Engine.InputSystem; 2 | using N8Engine.SceneManagement; 3 | 4 | namespace N8Engine.Rendering; 5 | 6 | public sealed class CameraController : Component 7 | { 8 | readonly Input _input; 9 | readonly float _speed; 10 | Camera _camera; 11 | 12 | public CameraController(float speed) 13 | { 14 | _input = Modules.Get(); 15 | _speed = speed; 16 | } 17 | 18 | public override void Create(GameObject gameObject, Scene scene) => _camera = scene.Get(); 19 | public override void Update(Frame frame) => _camera.Position += _input.Axis() * (_speed * frame.DeltaTime); 20 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Rendering/Exceptions/MissingUniformOnShaderException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace N8Engine.Rendering; 4 | 5 | public sealed class MissingUniformOnShaderException : Exception 6 | { 7 | public MissingUniformOnShaderException() { } 8 | public MissingUniformOnShaderException(string message) : base(message) { } 9 | public MissingUniformOnShaderException(string message, Exception inner) : base(message, inner) { } 10 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Rendering/Exceptions/ShaderFailedCompilationException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace N8Engine.Rendering; 4 | 5 | public sealed class ShaderFailedCompilationException : Exception 6 | { 7 | public ShaderFailedCompilationException() { } 8 | public ShaderFailedCompilationException(string message) : base(message) { } 9 | public ShaderFailedCompilationException(string message, Exception inner) : base(message, inner) { } 10 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Rendering/Exceptions/ShaderProgramFailedLinkException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace N8Engine.Rendering; 4 | 5 | public sealed class ShaderProgramFailedLinkException : Exception 6 | { 7 | public ShaderProgramFailedLinkException() { } 8 | public ShaderProgramFailedLinkException(string message) : base(message) { } 9 | public ShaderProgramFailedLinkException(string message, Exception inner) : base(message, inner) { } 10 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Rendering/Graphics.cs: -------------------------------------------------------------------------------- 1 | using Silk.NET.OpenGL; 2 | 3 | namespace N8Engine.Rendering; 4 | 5 | sealed class Graphics : Module 6 | { 7 | public static implicit operator Graphics(GL gl) => new(gl); 8 | public static implicit operator GL(Graphics g) => g.Lib; 9 | 10 | public GL Lib { get; } 11 | public Graphics(GL gl) => Lib = gl; 12 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Rendering/Shader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Numerics; 4 | using Silk.NET.OpenGL; 5 | 6 | namespace N8Engine.Rendering; 7 | 8 | sealed class Shader : IDisposable 9 | { 10 | readonly GL _gl; 11 | readonly uint _shader; 12 | 13 | public Shader(GL gl, string vertexPath, string fragmentPath) 14 | { 15 | _gl = gl; 16 | var vertex = Load(ShaderType.VertexShader, vertexPath); 17 | var fragment = Load(ShaderType.FragmentShader, fragmentPath); 18 | _shader = _gl.CreateProgram(); 19 | _gl.AttachShader(_shader, vertex); 20 | _gl.AttachShader(_shader, fragment); 21 | _gl.LinkProgram(_shader); 22 | _gl.GetProgram(_shader, GLEnum.LinkStatus, out var status); 23 | if (status == 0) 24 | throw new ShaderProgramFailedLinkException($"Program failed to link with error: {_gl.GetProgramInfoLog(_shader)}"); 25 | _gl.DetachShader(_shader, vertex); 26 | _gl.DetachShader(_shader, fragment); 27 | _gl.DeleteShader(vertex); 28 | _gl.DeleteShader(fragment); 29 | } 30 | 31 | public void Use() => _gl.UseProgram(_shader); 32 | 33 | public void Dispose() => _gl.DeleteProgram(_shader); 34 | 35 | public unsafe void SetUniform(string name, Matrix4x4 value) 36 | { 37 | var location = _gl.GetUniformLocation(_shader, name); 38 | if (location == -1) 39 | throw new MissingUniformOnShaderException($"{name} uniform not found on shader."); 40 | _gl.UniformMatrix4(location, 1, false, (float*) &value); 41 | } 42 | 43 | public void SetUniform(string name, int value) 44 | { 45 | var location = _gl.GetUniformLocation(_shader, name); 46 | if (location == -1) 47 | throw new MissingUniformOnShaderException($"{name} uniform not found on shader."); 48 | _gl.Uniform1(location, value); 49 | } 50 | 51 | public void SetUniform(string name, float value) 52 | { 53 | var location = _gl.GetUniformLocation(_shader, name); 54 | if (location == -1) 55 | throw new MissingUniformOnShaderException($"{name} uniform not found on shader."); 56 | _gl.Uniform1(location, value); 57 | } 58 | 59 | uint Load(ShaderType type, string path) 60 | { 61 | var source = File.ReadAllText(path); 62 | var loaded = _gl.CreateShader(type); 63 | _gl.ShaderSource(loaded, source); 64 | _gl.CompileShader(loaded); 65 | var infoLog = _gl.GetShaderInfoLog(loaded); 66 | if (!string.IsNullOrWhiteSpace(infoLog)) 67 | throw new ShaderFailedCompilationException($"Error compiling shader of type {type}, failed with error {infoLog}"); 68 | return loaded; 69 | } 70 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Rendering/Sprite.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Numerics; 3 | using N8Engine.SceneManagement; 4 | using N8Engine.Utilities; 5 | 6 | namespace N8Engine.Rendering; 7 | 8 | public sealed class Sprite : Component 9 | { 10 | internal readonly Shader Shader; 11 | internal readonly Texture Texture; 12 | 13 | SpriteRenderer _spriteRenderer; 14 | Transform _transform; 15 | Scene _scene; 16 | string _name; 17 | 18 | public Sprite(string path) 19 | { 20 | // TODO: Find a better way of doing this. 21 | var gl = Modules.Get().Lib; 22 | Shader = new(gl, "Assets/Shaders/sprite.vert".Find(), "Assets/Shaders/sprite.frag".Find()); 23 | Texture = new(gl, path); 24 | } 25 | 26 | public override void Create(GameObject gameObject, Scene scene) 27 | { 28 | _scene = scene; 29 | _name = gameObject.Name; 30 | _transform = gameObject.GetComponent(); 31 | _spriteRenderer = scene.Get(); 32 | } 33 | 34 | public override void Destroy() 35 | { 36 | Shader.Dispose(); 37 | Texture.Dispose(); 38 | } 39 | 40 | public override void Render() 41 | { 42 | try 43 | { 44 | _spriteRenderer.AddToRenderQueue(this); 45 | } 46 | catch (Exception) 47 | { 48 | Console.WriteLine(_name + " name " + _scene.Name); 49 | throw; 50 | } 51 | } 52 | 53 | public Matrix4x4 ModelMatrix() => _transform.ModelMatrix(); 54 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Rendering/SpriteRenderer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using N8Engine.SceneManagement; 3 | using Silk.NET.OpenGL; 4 | 5 | namespace N8Engine.Rendering; 6 | 7 | public sealed class SpriteRenderer : Element 8 | { 9 | readonly List _sprites = new(); 10 | readonly float[] _vertices = 11 | { 12 | //X Y Z U V 13 | 0.5f, 0.5f, 0.0f, 1f, 0f, 14 | 0.5f, -0.5f, 0.0f, 1f, 1f, 15 | -0.5f, -0.5f, 0.0f, 0f, 1f, 16 | -0.5f, 0.5f, 0.0f, 0f, 0f 17 | }; 18 | readonly uint[] _indices = 19 | { 20 | 0, 1, 3, 21 | 1, 2, 3 22 | }; 23 | readonly GL _gl; 24 | 25 | Camera _camera; 26 | BufferObject _vbo; 27 | BufferObject _ebo; 28 | VertexArrayObject _vao; 29 | 30 | internal SpriteRenderer(GL gl) => _gl = gl; 31 | 32 | public void AddToRenderQueue(Sprite sprite) => _sprites.Add(sprite); 33 | 34 | void Element.OnSceneLoad(Scene scene) 35 | { 36 | _camera = scene.Get(); 37 | 38 | _vbo = new(_gl, _vertices, BufferTargetARB.ArrayBuffer); 39 | _ebo = new(_gl, _indices, BufferTargetARB.ElementArrayBuffer); 40 | _vao = new(_gl, _vbo, _ebo); 41 | 42 | _vao.VertexAttributePointer(0, 3, VertexAttribPointerType.Float, 5, 0); 43 | _vao.VertexAttributePointer(1, 2, VertexAttribPointerType.Float, 5, 3); 44 | } 45 | 46 | void Element.OnSceneUpdate() { } 47 | 48 | unsafe void Element.OnSceneRender() 49 | { 50 | _gl.Clear(ClearBufferMask.ColorBufferBit); 51 | _vao.Bind(); 52 | 53 | foreach (var sprite in _sprites) 54 | { 55 | sprite.Shader.Use(); 56 | sprite.Texture.Bind(); 57 | sprite.Shader.SetUniform("uTexture0", 0); 58 | sprite.Shader.SetUniform("uModel", sprite.ModelMatrix()); 59 | sprite.Shader.SetUniform("uProjection", _camera.ProjectionMatrix()); 60 | _gl.DrawElements(PrimitiveType.Triangles, (uint) _indices.Length, DrawElementsType.UnsignedInt, null); 61 | } 62 | 63 | _sprites.Clear(); 64 | } 65 | 66 | void Element.OnSceneUnload() 67 | { 68 | _vbo.Dispose(); 69 | _ebo.Dispose(); 70 | _vao.Dispose(); 71 | _sprites.Clear(); 72 | } 73 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Rendering/Texture.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using Silk.NET.OpenGL; 4 | using SixLabors.ImageSharp; 5 | using SixLabors.ImageSharp.PixelFormats; 6 | 7 | namespace N8Engine.Rendering; 8 | 9 | [SuppressMessage("ReSharper.DPA", "DPA0003: Excessive memory allocations in LOH", MessageId = "type: SixLabors.ImageSharp.PixelFormats.Rgba32[]; size: 96MB")] 10 | public sealed class Texture : IDisposable 11 | { 12 | readonly GL _gl; 13 | readonly uint _handle; 14 | readonly Image _image; 15 | 16 | const int MAX_TEXTURE_WIDTH = 5000; 17 | const int MAX_TEXTURE_HEIGHT = 5000; 18 | 19 | static readonly Rgba32[] _pixels = new Rgba32[MAX_TEXTURE_WIDTH * MAX_TEXTURE_HEIGHT]; 20 | 21 | public unsafe Texture(GL gl, string path) 22 | { 23 | _gl = gl; 24 | _handle = _gl.GenTexture(); 25 | Bind(); 26 | 27 | _image = Image.Load(path); 28 | for (var y = 0; y < _image.Height; y++) 29 | { 30 | for (var x = 0; x < _image.Width; x++) 31 | { 32 | _pixels[y * _image.Width + x] = _image[x, y]; 33 | } 34 | } 35 | fixed (void* data = &_pixels[0]) 36 | _gl.TexImage2D(TextureTarget.Texture2D, 0, (int) InternalFormat.Rgba, (uint) _image.Width, (uint) _image.Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, data); 37 | 38 | _gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int) GLEnum.Repeat); 39 | _gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int) GLEnum.Repeat); 40 | _gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int) GLEnum.Linear); 41 | _gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int) GLEnum.Linear); 42 | _gl.GenerateMipmap(TextureTarget.Texture2D); 43 | } 44 | 45 | public void Bind(TextureUnit textureSlot = TextureUnit.Texture0) 46 | { 47 | _gl.ActiveTexture(textureSlot); 48 | _gl.BindTexture(TextureTarget.Texture2D, _handle); 49 | } 50 | 51 | public void Dispose() 52 | { 53 | _image.Dispose(); 54 | _gl.DeleteTexture(_handle); 55 | } 56 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Rendering/VertexArrayObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Silk.NET.OpenGL; 3 | 4 | namespace N8Engine.Rendering; 5 | 6 | sealed class VertexArrayObject : IDisposable 7 | where TVertex : unmanaged 8 | where TIndex : unmanaged 9 | { 10 | readonly uint _handle; 11 | readonly GL _gl; 12 | 13 | public VertexArrayObject(GL gl, BufferObject vbo, BufferObject ebo) 14 | { 15 | _gl = gl; 16 | _handle = _gl.GenVertexArray(); 17 | Bind(); 18 | vbo.Bind(); 19 | ebo.Bind(); 20 | } 21 | 22 | public unsafe void VertexAttributePointer(uint index, int count, VertexAttribPointerType type, uint vertexSize, int offset) 23 | { 24 | _gl.VertexAttribPointer(index, count, type, false, vertexSize * (uint) sizeof(TVertex), (void*) (offset * sizeof(TVertex))); 25 | _gl.EnableVertexAttribArray(index); 26 | } 27 | 28 | public void Bind() => _gl.BindVertexArray(_handle); 29 | public void Dispose() => _gl.DeleteVertexArray(_handle); 30 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/SceneManagement/Element.cs: -------------------------------------------------------------------------------- 1 | namespace N8Engine.SceneManagement; 2 | 3 | public interface Element 4 | { 5 | void OnSceneLoad(Scene scene); 6 | void OnSceneUpdate(); 7 | void OnSceneRender(); 8 | void OnSceneUnload(); 9 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/SceneManagement/ElementNotFoundException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace N8Engine.SceneManagement; 4 | 5 | public sealed class ElementNotFoundException : Exception 6 | { 7 | public ElementNotFoundException() { } 8 | public ElementNotFoundException(string message) : base(message) { } 9 | public ElementNotFoundException(string message, Exception inner) : base(message, inner) { } 10 | void Foo() 11 | { 12 | var foo = 0f; 13 | Console.WriteLine(foo); 14 | } 15 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/SceneManagement/Elements.cs: -------------------------------------------------------------------------------- 1 | namespace N8Engine.SceneManagement; 2 | 3 | interface Elements 4 | { 5 | void Add(T cog) where T : Element; 6 | void Remove() where T : Element; 7 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/SceneManagement/EmptyScene.cs: -------------------------------------------------------------------------------- 1 | namespace N8Engine.SceneManagement; 2 | 3 | public sealed class EmptyScene : Scene 4 | { 5 | public override string Name => "Empty Scene"; 6 | protected override void Load() { } 7 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/SceneManagement/Scene.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using N8Engine.Utilities; 4 | 5 | namespace N8Engine.SceneManagement; 6 | 7 | public abstract class Scene : ServiceLocator, Elements 8 | { 9 | readonly List _gameObjects = new(); 10 | bool _isLoaded; 11 | 12 | public virtual string Name { get; } = "New Scene"; 13 | IEnumerable Cogs => Services.Values; 14 | 15 | public T Get() where T : Element => Find(); 16 | void Elements.Add(T cog) => Register(cog); 17 | void Elements.Remove() => Deregister(); 18 | 19 | protected virtual void Load() { } 20 | protected virtual void Unload() { } 21 | 22 | public GameObject Create(string name) => Create(name, out _); 23 | 24 | public GameObject Create(string name, out GameObject gameObject) 25 | { 26 | if (!_isLoaded) 27 | { 28 | gameObject = null; 29 | return null; 30 | } 31 | gameObject = new(this, name); 32 | _gameObjects.Add(gameObject); 33 | return gameObject; 34 | } 35 | 36 | internal void SwitchTo(Action onAddCogs) 37 | { 38 | _isLoaded = true; 39 | onAddCogs(this); 40 | foreach (var cog in Cogs) 41 | cog.OnSceneLoad(this); 42 | Load(); 43 | } 44 | 45 | internal void SwitchFrom(Action onRemoveCogs) 46 | { 47 | _isLoaded = false; 48 | foreach (var gameObject in _gameObjects.ToArray()) 49 | gameObject.Destroy(); 50 | _gameObjects.Clear(); 51 | onRemoveCogs(this); 52 | foreach (var cog in Cogs) 53 | cog.OnSceneUnload(); 54 | Unload(); 55 | } 56 | 57 | internal void Start() 58 | { 59 | foreach (var gameObject in _gameObjects.ToArray()) 60 | gameObject.Create(); 61 | foreach (var gameObject in _gameObjects.ToArray()) 62 | gameObject.Start(); 63 | } 64 | 65 | internal void Update(Frame frame) 66 | { 67 | foreach (var gameObject in _gameObjects.ToArray()) 68 | gameObject.EarlyUpdate(frame); 69 | foreach (var gameObject in _gameObjects.ToArray()) 70 | gameObject.Update(frame); 71 | foreach (var gameObject in _gameObjects.ToArray()) 72 | gameObject.LateUpdate(frame); 73 | foreach (var cog in Cogs) 74 | cog.OnSceneUpdate(); 75 | } 76 | 77 | internal void Render() 78 | { 79 | foreach (var gameObject in _gameObjects.ToArray()) 80 | gameObject.Render(); 81 | foreach (var cog in Cogs) 82 | cog.OnSceneRender(); 83 | } 84 | 85 | internal void Destroy(GameObject gameObject) => _gameObjects.Remove(gameObject); 86 | 87 | internal new int Count() => _gameObjects.Count; 88 | internal GameObject First() => _gameObjects[0]; 89 | internal bool Any() => _gameObjects.Count > 0; 90 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/SceneManagement/SceneManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using N8Engine.Windowing; 3 | 4 | namespace N8Engine.SceneManagement; 5 | 6 | public sealed class SceneManager : Module 7 | { 8 | readonly Loop _loop; 9 | readonly WindowEvents _windowEvents; 10 | readonly Action _onAddCogs; 11 | readonly Action _onRemoveCogs; 12 | 13 | public Scene CurrentScene { get; private set; } = new EmptyScene(); 14 | 15 | internal SceneManager(Loop loop, WindowEvents windowEvents, Action onAddCogs, Action onRemoveCogs) 16 | { 17 | _loop = loop; 18 | _windowEvents = windowEvents; 19 | _onAddCogs = onAddCogs; 20 | _onRemoveCogs = onRemoveCogs; 21 | CurrentScene.SwitchTo(onAddCogs); 22 | } 23 | 24 | public void Load(Scene scene) 25 | { 26 | _loop.OnStart -= CurrentScene.Start; 27 | _loop.OnUpdate -= CurrentScene.Update; 28 | _loop.OnRender -= CurrentScene.Render; 29 | _windowEvents.OnClose -= UnloadCurrentScene; 30 | UnloadCurrentScene(); 31 | CurrentScene = scene; 32 | 33 | _loop.OnStart += CurrentScene.Start; 34 | _loop.OnUpdate += CurrentScene.Update; 35 | _loop.OnRender += CurrentScene.Render; 36 | _windowEvents.OnClose += UnloadCurrentScene; 37 | CurrentScene.SwitchTo(_onAddCogs); 38 | } 39 | 40 | void UnloadCurrentScene() => CurrentScene.SwitchFrom(_onRemoveCogs); 41 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Utilities/Bounds.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | 3 | namespace N8Engine.Utilities; 4 | 5 | public struct Bounds 6 | { 7 | public readonly Vector2 Center; 8 | public readonly Vector2 Size; 9 | 10 | public Vector2 Extents => Size / 2f; 11 | public Vector2 Left => new(Center.X - Extents.X, Center.Y); 12 | public Vector2 Right => new(Center.X + Extents.X, Center.Y); 13 | public Vector2 Bottom => new(Center.X, Center.Y - Extents.Y); 14 | public Vector2 Top => new(Center.X, Center.Y + Extents.Y); 15 | 16 | public Bounds(Vector2 center, Vector2 size) 17 | { 18 | Center = center; 19 | Size = size; 20 | } 21 | 22 | public void Move(Vector2 position) => this = new(position, Size); 23 | public void Expand(Vector2 amount) => this = new(Center, Size + amount); 24 | public void Expand(float amount) => Expand(new Vector2(amount)); 25 | public void Grow(Vector2 scale) => this = new(Center, Size * scale); 26 | public void Grow(float scale) => Grow(new Vector2(scale)); 27 | 28 | public bool Contains(Vector2 point) => 29 | point.X >= Left.X && 30 | point.X <= Right.X && 31 | point.Y >= Bottom.Y && 32 | point.Y <= Top.Y; 33 | 34 | public void Add(Vector2 point) 35 | { 36 | if (Contains(point)) return; 37 | var left = Left.X; 38 | var right = Right.X; 39 | var bottom = Bottom.Y; 40 | var top = Top.Y; 41 | if (point.X < Left.X) 42 | left = point.X; 43 | else if (point.X > Right.X) 44 | right = point.X; 45 | if (point.Y < Bottom.Y) 46 | bottom = point.Y; 47 | else if (point.Y > Top.Y) 48 | top = point.Y; 49 | var bottomLeft = new Vector2(left, bottom); 50 | var topRight = new Vector2(right, top); 51 | var size = topRight - bottomLeft; 52 | var center = bottomLeft + size / 2f; 53 | this = new(center, size); 54 | } 55 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Utilities/MathExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Numerics; 3 | 4 | namespace N8Engine.Utilities; 5 | 6 | public static class MathExtensions 7 | { 8 | public static float ToRadians(this float degrees) => MathF.PI / 180f * degrees; 9 | public static float ToDegrees(this float radians) => 180f / MathF.PI * radians; 10 | 11 | public static Vector2 Normalized(this Vector2 v) 12 | { 13 | if (v.X == 0 && v.Y == 0) 14 | return v; 15 | return Vector2.Normalize(v); 16 | } 17 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Utilities/PathExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Runtime.CompilerServices; 3 | using static System.IO.Directory; 4 | using static System.IO.Path; 5 | 6 | namespace N8Engine.Utilities; 7 | 8 | public static class PathExtensions 9 | { 10 | public static string Find(this string path, [CallerFilePath] string caller = "", int iterations = 8) 11 | { 12 | var pre = caller; 13 | var suf = path; 14 | string full() => Combine(pre, suf); 15 | if (File.Exists(full())) 16 | return full(); 17 | for (var i = 0; i < iterations; i++) 18 | { 19 | if (GetParent(pre) is null) 20 | throw new FileNotFoundException($"File {path} not found!"); 21 | pre = GetParent(pre)!.FullName; 22 | if (File.Exists(full())) 23 | return full(); 24 | } 25 | throw new FileNotFoundException($"File {path} not found!"); 26 | } 27 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Utilities/ServiceLocator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace N8Engine.Utilities; 5 | 6 | public class ServiceLocator where TE : Exception 7 | { 8 | protected readonly Dictionary Services = new(); 9 | 10 | public int Count => Services.Count; 11 | 12 | protected virtual TE WhenMissing() where T : TS => throw new ServiceNotFoundException($"Service of type {typeof(T)} not found!"); 13 | 14 | public void Register(TType service) where TType : TS 15 | { 16 | if (Services.ContainsKey(typeof(TType))) 17 | Services[typeof(TType)] = service; 18 | else 19 | Services.Add(typeof(TType), service); 20 | } 21 | 22 | public void Deregister() where T : TS 23 | { 24 | if (!Services.Remove(typeof(T))) 25 | throw WhenMissing(); 26 | } 27 | 28 | public T Find() where T : TS 29 | { 30 | if (!Services.ContainsKey(typeof(T))) 31 | throw WhenMissing(); 32 | return (T) Services[typeof(T)]; 33 | } 34 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Utilities/ServiceNotFoundException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace N8Engine; 4 | 5 | public sealed class ServiceNotFoundException : Exception 6 | { 7 | public ServiceNotFoundException() { } 8 | public ServiceNotFoundException(string message) : base(message) { } 9 | public ServiceNotFoundException(string message, Exception inner) : base(message, inner) { } 10 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Windowing/Window.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using N8Engine.InputSystem; 3 | using Silk.NET.Input; 4 | using Silk.NET.OpenGL; 5 | using Silk.NET.Windowing; 6 | using static Silk.NET.Windowing.Window; 7 | using GLWindow = Silk.NET.Windowing.IWindow; 8 | 9 | namespace N8Engine.Windowing; 10 | 11 | sealed class Window : WindowSize, WindowEvents 12 | { 13 | public event Action OnLoad; 14 | public event Action OnClose; 15 | public event Action OnUpdate; 16 | public event Action OnRender; 17 | public event Action OnKeyDown; 18 | public event Action OnKeyUp; 19 | 20 | readonly GLWindow _window; 21 | GL _gl; 22 | 23 | int WindowSize.Width => _window.Size.X; 24 | int WindowSize.Height => _window.Size.Y; 25 | 26 | public Window(WindowOptions options) 27 | { 28 | _window = Create(options); 29 | _window.WindowBorder = options.IsResizable ? WindowBorder.Resizable : WindowBorder.Fixed; 30 | _window.Load += () => 31 | { 32 | SetUpInput(); 33 | OnLoad?.Invoke(); 34 | }; 35 | _window.Closing += () => 36 | { 37 | OnClose?.Invoke(); 38 | _window.Dispose(); 39 | _gl.Dispose(); 40 | }; 41 | _window.Update += dt => OnUpdate?.Invoke(new((float) dt)); 42 | _window.Render += _ => OnRender?.Invoke(); 43 | } 44 | 45 | public void Run() => _window.Run(); 46 | 47 | public void Close() => _window.Close(); 48 | 49 | public GL CreateGL() => _gl = _window.CreateOpenGL(); 50 | 51 | void SetUpInput() 52 | { 53 | var input = _window.CreateInput(); 54 | var keyboard = input.Keyboards[0]; 55 | keyboard.KeyDown += (_, glKey, _) => OnKeyDown?.Invoke(glKey.AsKey()); 56 | keyboard.KeyUp += (_, glKey, _) => OnKeyUp?.Invoke(glKey.AsKey()); 57 | } 58 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Windowing/WindowEvents.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace N8Engine.Windowing; 4 | 5 | interface WindowEvents 6 | { 7 | event Action OnClose; 8 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Windowing/WindowOptions.cs: -------------------------------------------------------------------------------- 1 | using GLWindowOptions = Silk.NET.Windowing.WindowOptions; 2 | using GLWindowState = Silk.NET.Windowing.WindowState; 3 | 4 | namespace N8Engine.Windowing; 5 | 6 | readonly struct WindowOptions 7 | { 8 | public static implicit operator GLWindowOptions(WindowOptions options) 9 | { 10 | var result = GLWindowOptions.Default; 11 | result.Title = options._title; 12 | result.Size = new((int) options._width, (int) options._height); 13 | result.FramesPerSecond = options._fps; 14 | result.WindowState = options._state switch 15 | { 16 | WindowState.Fullscreen => GLWindowState.Fullscreen, 17 | WindowState.Maximized => GLWindowState.Maximized, 18 | WindowState.Windowed => GLWindowState.Normal, 19 | _ => result.WindowState 20 | }; 21 | return result; 22 | } 23 | 24 | public readonly bool IsResizable; 25 | readonly string _title; 26 | readonly uint _width; 27 | readonly uint _height; 28 | readonly int _fps; 29 | readonly WindowState _state; 30 | 31 | public WindowOptions(string title, uint width, uint height, int fps, WindowState state, bool isResizable) 32 | { 33 | _title = title; 34 | _width = width; 35 | _height = height; 36 | _fps = fps; 37 | _state = state; 38 | IsResizable = isResizable; 39 | } 40 | 41 | // TODO: When maximized and fullscreen set width and height to size of monitor. 42 | public WindowOptions WithTitle(string title) => new(title, _width, _height, _fps, _state, IsResizable); 43 | public WindowOptions WithSize(uint width, uint height) => new(_title, width, height, _fps, _state, IsResizable); 44 | public WindowOptions WithFps(int fps) => new(_title, _width, _height, fps, _state, IsResizable); 45 | public WindowOptions Fullscreen() => new(_title, _width, _height, _fps, WindowState.Fullscreen, IsResizable); 46 | public WindowOptions Maximized() => new(_title, _width, _height, _fps, WindowState.Maximized, IsResizable); 47 | public WindowOptions Windowed() => new(_title, _width, _height, _fps, WindowState.Windowed, IsResizable); 48 | public WindowOptions Resizable() => new(_title, _width, _height, _fps, _state, true); 49 | public WindowOptions NotResizable() => new(_title, _width, _height, _fps, _state, false); 50 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Windowing/WindowSize.cs: -------------------------------------------------------------------------------- 1 | namespace N8Engine.Windowing; 2 | 3 | interface WindowSize 4 | { 5 | int Width { get; } 6 | int Height { get; } 7 | } -------------------------------------------------------------------------------- /N8Engine.Core/Source/Windowing/WindowState.cs: -------------------------------------------------------------------------------- 1 | namespace N8Engine.Windowing; 2 | 3 | enum WindowState 4 | { 5 | Windowed, Maximized, Fullscreen 6 | } -------------------------------------------------------------------------------- /N8Engine.Tests/Assets/dummy.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natecurtiss/n8engine/4148c2b2328acb846f8a6c063776662bd21e0ecd/N8Engine.Tests/Assets/dummy.txt -------------------------------------------------------------------------------- /N8Engine.Tests/N8Engine.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | false 6 | N8Engine.Tests 7 | N8Engine.Tests 8 | Release;Debug 9 | AnyCPU 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /N8Engine.Tests/N8Engine.Tests.csproj.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True -------------------------------------------------------------------------------- /N8Engine.Tests/Source/BoundsTests.cs: -------------------------------------------------------------------------------- 1 | using System.Numerics; 2 | using N8Engine.Utilities; 3 | using NUnit.Framework; 4 | using static NUnit.Framework.Assert; 5 | 6 | namespace N8Engine.Tests; 7 | 8 | sealed class BoundsTests 9 | { 10 | Bounds _bounds; 11 | 12 | [SetUp] 13 | public void Setup() => _bounds = new(Vector2.Zero, Vector2.One * 100); 14 | 15 | [Test] 16 | [TestCase(0, 0, true)] 17 | [TestCase(-5, 3, true)] 18 | [TestCase(-50, 50, true)] 19 | [TestCase(-26, 48, true)] 20 | [TestCase(0, 100, false)] 21 | [TestCase(-51, 51, false)] 22 | [TestCase(-500000, 2, false)] 23 | [TestCase(10000, 10000, false)] 24 | public void TestBoundsContains(int x, int y, bool shouldContain) 25 | { 26 | var point = new Vector2(x, y); 27 | AreEqual(_bounds.Contains(point), shouldContain); 28 | } 29 | 30 | [Test] 31 | public void TestBoundsAdd() 32 | { 33 | var point = new Vector2(100, 100); 34 | _bounds.Add(point); 35 | IsTrue(_bounds.Contains(point)); 36 | } 37 | } -------------------------------------------------------------------------------- /N8Engine.Tests/Source/DebugTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using static NUnit.Framework.Assert; 3 | 4 | namespace N8Engine.Tests; 5 | 6 | sealed class DebugTests 7 | { 8 | [Test] 9 | public void TestRedirectOutput() 10 | { 11 | var s = "something"; 12 | Debug.OnOutput(o => s = o.ToString()); 13 | Debug.Log("something else"); 14 | AreEqual(s, "something else"); 15 | } 16 | } -------------------------------------------------------------------------------- /N8Engine.Tests/Source/GameObjectTests.cs: -------------------------------------------------------------------------------- 1 | using N8Engine.SceneManagement; 2 | using NUnit.Framework; 3 | using static NUnit.Framework.Assert; 4 | 5 | namespace N8Engine.Tests; 6 | 7 | sealed class GameObjectTests 8 | { 9 | sealed class C1 : Component { } 10 | sealed class C2 : Component { } 11 | sealed class S : Scene { protected override void Load() { } } 12 | 13 | GameObject _gameObject = null!; 14 | 15 | [SetUp] 16 | public void Setup() => _gameObject = new(new S(), "foo"); 17 | 18 | [Test] 19 | public void TestGetNonExistentComponent() => IsNull(_gameObject.GetComponent()); 20 | 21 | [Test] 22 | public void TestGetExistentComponent() 23 | { 24 | _gameObject.AddComponent(); 25 | IsNotNull(_gameObject.GetComponent()); 26 | } 27 | 28 | [Test] 29 | public void TestAddComponent() 30 | { 31 | _gameObject.AddComponent(); 32 | IsNotNull(_gameObject.GetComponent()); 33 | } 34 | 35 | [Test] 36 | public void TestAddSpecificComponent() 37 | { 38 | _gameObject.AddComponent(new C1(), out var c1); 39 | IsNotNull(c1); 40 | } 41 | 42 | [Test] 43 | public void TestAddComponentForEquality() 44 | { 45 | _gameObject.AddComponent(new C1(), out var c1); 46 | AreEqual(c1, _gameObject.GetComponent()); 47 | } 48 | 49 | [Test] 50 | public void TestAddDuplicateComponent() 51 | { 52 | _gameObject.AddComponent(); 53 | Catch(() => _gameObject.AddComponent()); 54 | } 55 | 56 | [Test] 57 | public void TestRemoveComponent() 58 | { 59 | _gameObject.AddComponent(); 60 | _gameObject.RemoveComponent(); 61 | IsNull(_gameObject.GetComponent()); 62 | } 63 | 64 | [Test] 65 | public void TestRemoveSpecificComponent() 66 | { 67 | _gameObject.AddComponent(out var c1); 68 | _gameObject.RemoveComponent(c1); 69 | IsNull(_gameObject.GetComponent()); 70 | } 71 | 72 | [Test] 73 | public void TestRemoveNonExistentComponent() => Catch(() => _gameObject.RemoveComponent(new C2())); 74 | 75 | [Test] 76 | public void TestGameObjectIsNotDestroyedInitially() => IsFalse(_gameObject.IsDestroyed); 77 | 78 | [Test] 79 | public void TestDestroyGameObject() 80 | { 81 | _gameObject.Destroy(); 82 | IsTrue(_gameObject.IsDestroyed); 83 | } 84 | 85 | [Test] 86 | public void TestGetComponentOnDestroyedGameObject() 87 | { 88 | _gameObject.AddComponent().Destroy(); 89 | Catch(() => _gameObject.GetComponent()); 90 | } 91 | 92 | [Test] 93 | public void TestAddComponentOnDestroyedGameObject() 94 | { 95 | _gameObject.Destroy(); 96 | Catch(() => _gameObject.AddComponent()); 97 | } 98 | 99 | [Test] 100 | public void TestRemoveComponentOnDestroyedGameObject() 101 | { 102 | _gameObject.AddComponent(out var c1).Destroy(); 103 | Catch(() => _gameObject.RemoveComponent(c1)); 104 | } 105 | } -------------------------------------------------------------------------------- /N8Engine.Tests/Source/InputSystemTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using N8Engine.InputSystem; 4 | using NUnit.Framework; 5 | using static N8Engine.InputSystem.Key; 6 | using static NUnit.Framework.Assert; 7 | using GLKey = Silk.NET.Input.Key; 8 | 9 | namespace N8Engine.Tests; 10 | 11 | sealed class InputSystemTests 12 | { 13 | Input _input = null!; 14 | 15 | [SetUp] 16 | public void Setup() => _input = new(); 17 | 18 | [Test] 19 | public void TestAllKeysReleasedInitially() => IsTrue(Enum.GetValues().Where(k => k != Unknown && _input.IsReleased(k)).ToList().Count == Enum.GetValues().Length - 1); 20 | [Test] 21 | public void TestNoKeysPressedInitially() => IsTrue(Enum.GetValues().Where(k => k != Unknown && !_input.IsPressed(k)).ToList().Count == Enum.GetValues().Length - 1); 22 | [Test] 23 | public void TestNoKeysJustReleasedInitially() => IsTrue(Enum.GetValues().Where(k => k != Unknown && !_input.WasJustReleased(k)).ToList().Count == Enum.GetValues().Length - 1); 24 | [Test] 25 | public void TestNoKeysJustPressedInitially() => IsTrue(Enum.GetValues().Where(k => k != Unknown && !_input.WasJustPressed(k)).ToList().Count == Enum.GetValues().Length - 1); 26 | 27 | [Test] 28 | public void TestIsSpecificKeyPressed() 29 | { 30 | _input.UpdateKey(A, true); 31 | IsTrue(_input.IsPressed(A)); 32 | } 33 | 34 | [Test] 35 | public void TestIsAnyKeyPressed() 36 | { 37 | _input.UpdateKey(A, true); 38 | IsTrue(_input.IsPressed(Any)); 39 | } 40 | 41 | [Test] 42 | public void TestWasSpecificKeyJustPressed() 43 | { 44 | _input.UpdateKey(A, true); 45 | IsTrue(_input.WasJustPressed(A)); 46 | } 47 | 48 | [Test] 49 | public void TestWasAnyKeyJustPressed() 50 | { 51 | _input.UpdateKey(A, true); 52 | IsTrue(_input.WasJustPressed(Any)); 53 | } 54 | 55 | [Test] 56 | public void TestIsSpecificKeyReleased() 57 | { 58 | _input.UpdateKey(A, true); 59 | _input.UpdateKey(A, false); 60 | IsTrue(_input.IsReleased(A)); 61 | } 62 | 63 | [Test] 64 | public void TestIsAnyKeyReleased() 65 | { 66 | _input.UpdateKey(A, true); 67 | _input.UpdateKey(A, false); 68 | IsTrue(_input.IsReleased(Any)); 69 | } 70 | 71 | [Test] 72 | public void TestWasSpecificKeyJustReleased() 73 | { 74 | _input.UpdateKey(A, true); 75 | _input.UpdateKey(A, false); 76 | IsTrue(_input.WasJustReleased(A)); 77 | } 78 | 79 | [Test] 80 | public void TestWasAnyKeyJustReleased() 81 | { 82 | _input.UpdateKey(A, true); 83 | _input.UpdateKey(A, false); 84 | IsTrue(_input.WasJustReleased(Any)); 85 | } 86 | 87 | [Test] 88 | public void TestGLKeyToKeyConversion() => IsTrue(GLKey.A.AsKey() == A); 89 | } -------------------------------------------------------------------------------- /N8Engine.Tests/Source/PathExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | using N8Engine.Utilities; 2 | using NUnit.Framework; 3 | using static NUnit.Framework.FileAssert; 4 | 5 | namespace N8Engine.Tests; 6 | 7 | sealed class PathExtensionsTests 8 | { 9 | [Test] 10 | public void TestFind() 11 | { 12 | var path = "Assets/dummy.txt"; 13 | Exists(path.Find()); 14 | } 15 | } -------------------------------------------------------------------------------- /N8Engine.Tests/Source/SceneManagementTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using N8Engine.SceneManagement; 3 | using N8Engine.Windowing; 4 | using NUnit.Framework; 5 | using static NUnit.Framework.Assert; 6 | 7 | namespace N8Engine.Tests; 8 | 9 | sealed class SceneManagementTests 10 | { 11 | sealed class W : WindowSize, WindowEvents { int WindowSize.Width => 0; int WindowSize.Height => 0; public event Action? OnClose; } 12 | sealed class L : Loop { public event Action? OnStart; public event Action? OnUpdate; public event Action? OnRender; } 13 | sealed class S1 : Scene { protected override void Load() => Create("a"); } 14 | sealed class S2 : Scene { protected override void Load() => Create("b"); } 15 | 16 | SceneManager _sceneManager = null!; 17 | 18 | [SetUp] 19 | public void Setup() => _sceneManager = new(new L(), new W(), _ => { }, _ => { }); 20 | 21 | [Test] 22 | public void TestDefaultScene() => IsNotNull(_sceneManager.CurrentScene); 23 | 24 | [Test] 25 | public void TestLoadScene() => DoesNotThrow(() => _sceneManager.Load(new S1())); 26 | 27 | [Test] 28 | public void TestLoadSceneUpdatesCurrentScene() 29 | { 30 | var s1 = new S1(); 31 | _sceneManager.Load(s1); 32 | AreEqual(s1, _sceneManager.CurrentScene); 33 | } 34 | 35 | [Test] 36 | public void TestLoadedSceneCreatesGameObjects() 37 | { 38 | var s1 = new S1(); 39 | _sceneManager.Load(s1); 40 | IsTrue(s1.Count() == 1); 41 | } 42 | 43 | [Test] 44 | public void TestLoadedSceneGameObjectsAreNotDestroyed() 45 | { 46 | var s1 = new S1(); 47 | _sceneManager.Load(s1); 48 | IsFalse(s1.First().IsDestroyed); 49 | } 50 | 51 | [Test] 52 | public void TestDestroySceneGameObjectsOnUnload() 53 | { 54 | var s1 = new S1(); 55 | _sceneManager.Load(s1); 56 | _sceneManager.Load(new S2()); 57 | IsTrue(!s1.Any()); 58 | } 59 | } -------------------------------------------------------------------------------- /N8Engine.Tests/Source/ServiceLocatorTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using N8Engine.Utilities; 3 | using NUnit.Framework; 4 | using static NUnit.Framework.Assert; 5 | 6 | namespace N8Engine.Tests; 7 | 8 | sealed class ServiceLocatorTests 9 | { 10 | sealed class S { } 11 | sealed class E : Exception { } 12 | 13 | ServiceLocator _services; 14 | 15 | [SetUp] 16 | public void Setup() => _services = new(); 17 | 18 | [Test] 19 | public void TestRegisterService() 20 | { 21 | _services.Register(new S()); 22 | IsTrue(_services.Count == 1); 23 | } 24 | 25 | [Test] 26 | public void TestDeregisterNonExistentService() => Catch(() => _services.Deregister()); 27 | 28 | [Test] 29 | public void TestDeregisterExistentService() 30 | { 31 | _services.Register(new S()); 32 | _services.Deregister(); 33 | IsTrue(_services.Count == 0); 34 | } 35 | 36 | [Test] 37 | public void TestFindNonExistentService() => Catch(() => _services.Find()); 38 | 39 | [Test] 40 | public void TestFindExistentService() 41 | { 42 | _services.Register(new S()); 43 | IsNotNull(_services.Find()); 44 | } 45 | } -------------------------------------------------------------------------------- /N8Engine.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "N8Engine.Core", "N8Engine.Core\N8Engine.Core.csproj", "{FEA166FB-16B4-474E-9982-65486655B36D}" 4 | EndProject 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Examples.SampleGame", "Examples.SampleGame\Examples.SampleGame.csproj", "{271A7D60-DDC6-4E66-9FFC-C26B32839B0B}" 6 | EndProject 7 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Engine", "Engine", "{4D9CCEBA-ED42-49B5-8851-39332E12C3B7}" 8 | EndProject 9 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{C521A1AE-3B14-4149-9728-CB3A54868FC9}" 10 | EndProject 11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "N8Engine.Tests", "N8Engine.Tests\N8Engine.Tests.csproj", "{16103C7E-8F84-4A15-B6D3-3BE594E4F51D}" 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Release|Any CPU = Release|Any CPU 16 | Debug|Any CPU = Debug|Any CPU 17 | EndGlobalSection 18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 19 | {FEA166FB-16B4-474E-9982-65486655B36D}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 | {FEA166FB-16B4-474E-9982-65486655B36D}.Release|Any CPU.Build.0 = Release|Any CPU 21 | {FEA166FB-16B4-474E-9982-65486655B36D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {FEA166FB-16B4-474E-9982-65486655B36D}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {271A7D60-DDC6-4E66-9FFC-C26B32839B0B}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {271A7D60-DDC6-4E66-9FFC-C26B32839B0B}.Release|Any CPU.Build.0 = Release|Any CPU 25 | {271A7D60-DDC6-4E66-9FFC-C26B32839B0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {271A7D60-DDC6-4E66-9FFC-C26B32839B0B}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {16103C7E-8F84-4A15-B6D3-3BE594E4F51D}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {16103C7E-8F84-4A15-B6D3-3BE594E4F51D}.Release|Any CPU.Build.0 = Release|Any CPU 29 | {16103C7E-8F84-4A15-B6D3-3BE594E4F51D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {16103C7E-8F84-4A15-B6D3-3BE594E4F51D}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | EndGlobalSection 32 | GlobalSection(NestedProjects) = preSolution 33 | {FEA166FB-16B4-474E-9982-65486655B36D} = {4D9CCEBA-ED42-49B5-8851-39332E12C3B7} 34 | {271A7D60-DDC6-4E66-9FFC-C26B32839B0B} = {C521A1AE-3B14-4149-9728-CB3A54868FC9} 35 | {16103C7E-8F84-4A15-B6D3-3BE594E4F51D} = {4D9CCEBA-ED42-49B5-8851-39332E12C3B7} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /N8Engine.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | False 3 | True 4 | True -------------------------------------------------------------------------------- /N8Engine.sln.DotSettings.user: -------------------------------------------------------------------------------- 1 |  2 | <SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from &lt;Engine&gt;\&lt;Tests&gt;" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> 3 | <Or> 4 | <Not> 5 | <TestAncestor> 6 | <TestId>NUnit3x::16103C7E-8F84-4A15-B6D3-3BE594E4F51D::net6.0::N8Engine.Tests.MathematicsTests</TestId> 7 | </TestAncestor> 8 | </Not> 9 | <TestAncestor> 10 | <TestId>NUnit3x::16103C7E-8F84-4A15-B6D3-3BE594E4F51D::net6.0::N8Engine.Tests.MathematicsTests</TestId> 11 | </TestAncestor> 12 | </Or> 13 | </SessionState> 14 | True --------------------------------------------------------------------------------