diff --git a/FinalEngine.Editor.Common/FinalEngine.Editor.Common.csproj b/FinalEngine.Editor.Common/FinalEngine.Editor.Common.csproj index 1cbc5447..9721447b 100644 --- a/FinalEngine.Editor.Common/FinalEngine.Editor.Common.csproj +++ b/FinalEngine.Editor.Common/FinalEngine.Editor.Common.csproj @@ -30,4 +30,8 @@ + + + + diff --git a/FinalEngine.Editor.Common/GlobalSuppressions.cs b/FinalEngine.Editor.Common/GlobalSuppressions.cs new file mode 100644 index 00000000..f52f45a5 --- /dev/null +++ b/FinalEngine.Editor.Common/GlobalSuppressions.cs @@ -0,0 +1,8 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Performance", "CA1848:Use the LoggerMessage delegates", Justification = "KISS")] +[assembly: SuppressMessage("Usage", "CA2254:Template should be a static expression", Justification = "KISS")] diff --git a/FinalEngine.Editor.Common/Services/Scenes/ISceneRenderer.cs b/FinalEngine.Editor.Common/Services/Scenes/ISceneRenderer.cs new file mode 100644 index 00000000..5b7c2947 --- /dev/null +++ b/FinalEngine.Editor.Common/Services/Scenes/ISceneRenderer.cs @@ -0,0 +1,16 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Editor.Common.Services.Scenes; + +/// +/// Defines an interface that renders a scene. +/// +public interface ISceneRenderer +{ + /// + /// Renders the scene. + /// + void Render(); +} diff --git a/FinalEngine.Editor.Common/Services/Scenes/SceneRenderer.cs b/FinalEngine.Editor.Common/Services/Scenes/SceneRenderer.cs new file mode 100644 index 00000000..65563976 --- /dev/null +++ b/FinalEngine.Editor.Common/Services/Scenes/SceneRenderer.cs @@ -0,0 +1,41 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Editor.Common.Services.Scenes; + +using System; +using System.Drawing; +using FinalEngine.Rendering; + +/// +/// Provides a standard implementation of an . +/// +/// +public sealed class SceneRenderer : ISceneRenderer +{ + /// + /// The render device. + /// + private readonly IRenderDevice renderDevice; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The render device. + /// + /// + /// The specified parameter cannot be null. + /// + public SceneRenderer(IRenderDevice renderDevice) + { + this.renderDevice = renderDevice ?? throw new ArgumentNullException(nameof(renderDevice)); + } + + /// + public void Render() + { + this.renderDevice.Clear(Color.FromArgb(255, 30, 30, 30)); + } +} diff --git a/FinalEngine.Editor.Desktop/App.xaml.cs b/FinalEngine.Editor.Desktop/App.xaml.cs index d609e2ad..9a8f31ae 100644 --- a/FinalEngine.Editor.Desktop/App.xaml.cs +++ b/FinalEngine.Editor.Desktop/App.xaml.cs @@ -7,10 +7,10 @@ namespace FinalEngine.Editor.Desktop; using System.Diagnostics; using System.IO.Abstractions; using System.Windows; -using CommunityToolkit.Mvvm.Messaging; using FinalEngine.Editor.Common.Extensions; using FinalEngine.Editor.Common.Services.Application; using FinalEngine.Editor.Common.Services.Environment; +using FinalEngine.Editor.Common.Services.Scenes; using FinalEngine.Editor.Desktop.Services.Actions; using FinalEngine.Editor.Desktop.Services.Factories.Layout; using FinalEngine.Editor.Desktop.Views; @@ -25,6 +25,8 @@ namespace FinalEngine.Editor.Desktop; using FinalEngine.Editor.ViewModels.Interactions; using FinalEngine.Editor.ViewModels.Services.Actions; using FinalEngine.Editor.ViewModels.Services.Factories.Layout; +using FinalEngine.Rendering; +using FinalEngine.Rendering.OpenGL; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; @@ -102,11 +104,13 @@ private static void ConfigureServices(HostBuilderContext context, IServiceCollec builder.AddConsole().SetMinimumLevel(Debugger.IsAttached ? LogLevel.Debug : LogLevel.Information); }); + services.AddSingleton(); + services.AddSingleton(); - services.AddSingleton(WeakReferenceMessenger.Default); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddFactory(); services.AddFactory(); diff --git a/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj b/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj index ed1fdbd5..d8c412a1 100644 --- a/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj +++ b/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj @@ -28,6 +28,7 @@ + all @@ -43,6 +44,7 @@ + diff --git a/FinalEngine.Editor.Desktop/Views/Scenes/SceneView.xaml b/FinalEngine.Editor.Desktop/Views/Scenes/SceneView.xaml index 2ec8bdcd..15be9a02 100644 --- a/FinalEngine.Editor.Desktop/Views/Scenes/SceneView.xaml +++ b/FinalEngine.Editor.Desktop/Views/Scenes/SceneView.xaml @@ -3,9 +3,23 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:eb="clr-namespace:EventBinder;assembly=EventBinder" xmlns:vm="clr-namespace:FinalEngine.Editor.ViewModels.Docking.Panes.Scenes;assembly=FinalEngine.Editor.ViewModels" + xmlns:glwpf="clr-namespace:OpenTK.Wpf;assembly=GLWpfControl" mc:Ignorable="d" d:DataContext="{d:DesignInstance Type=vm:SceneViewPaneViewModel}"> + + + + + diff --git a/FinalEngine.Editor.Desktop/Views/Scenes/SceneView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Scenes/SceneView.xaml.cs index 62f25d52..2f994263 100644 --- a/FinalEngine.Editor.Desktop/Views/Scenes/SceneView.xaml.cs +++ b/FinalEngine.Editor.Desktop/Views/Scenes/SceneView.xaml.cs @@ -17,5 +17,6 @@ public partial class SceneView : UserControl public SceneView() { this.InitializeComponent(); + this.glWpfControl.Start(); } } diff --git a/FinalEngine.Editor.ViewModels/Docking/Panes/Scenes/ISceneViewPaneViewModel.cs b/FinalEngine.Editor.ViewModels/Docking/Panes/Scenes/ISceneViewPaneViewModel.cs index 47c9c38c..8d6b22d8 100644 --- a/FinalEngine.Editor.ViewModels/Docking/Panes/Scenes/ISceneViewPaneViewModel.cs +++ b/FinalEngine.Editor.ViewModels/Docking/Panes/Scenes/ISceneViewPaneViewModel.cs @@ -4,10 +4,22 @@ namespace FinalEngine.Editor.ViewModels.Docking.Panes.Scenes; +using System.Windows.Input; + /// /// Defines an interface that represents a model of the scene view pane. /// /// public interface ISceneViewPaneViewModel : IPaneViewModel { + /// + /// Gets the render command. + /// + /// + /// The render command. + /// + /// + /// The is used to render the currently active scene. + /// + ICommand RenderCommand { get; } } diff --git a/FinalEngine.Editor.ViewModels/Docking/Panes/Scenes/SceneViewPaneViewModel.cs b/FinalEngine.Editor.ViewModels/Docking/Panes/Scenes/SceneViewPaneViewModel.cs index 45a82426..bf0bf34b 100644 --- a/FinalEngine.Editor.ViewModels/Docking/Panes/Scenes/SceneViewPaneViewModel.cs +++ b/FinalEngine.Editor.ViewModels/Docking/Panes/Scenes/SceneViewPaneViewModel.cs @@ -5,6 +5,9 @@ namespace FinalEngine.Editor.ViewModels.Docking.Panes.Scenes; using System; +using System.Windows.Input; +using CommunityToolkit.Mvvm.Input; +using FinalEngine.Editor.Common.Services.Scenes; using Microsoft.Extensions.Logging; /// @@ -14,22 +17,53 @@ namespace FinalEngine.Editor.ViewModels.Docking.Panes.Scenes; /// public sealed class SceneViewPaneViewModel : PaneViewModelBase, ISceneViewPaneViewModel { + /// + /// The scene renderer, used to render the current scene. + /// + private readonly ISceneRenderer sceneRenderer; + + /// + /// The render command, used to render the current scene. + /// + private ICommand? renderCommand; + /// /// Initializes a new instance of the class. /// /// /// The logger. /// - public SceneViewPaneViewModel(ILogger logger) + /// + /// The scene renderer used to render the currently active scene. + /// + public SceneViewPaneViewModel( + ILogger logger, + ISceneRenderer sceneRenderer) { if (logger == null) { throw new ArgumentNullException(nameof(logger)); } + this.sceneRenderer = sceneRenderer ?? throw new ArgumentNullException(nameof(sceneRenderer)); + this.Title = "Scene View"; this.ContentID = "SceneView"; logger.LogInformation($"Initializing {this.Title}..."); } + + /// + public ICommand RenderCommand + { + get { return this.renderCommand ??= new RelayCommand(this.Render); } + } + + /// + /// Renders the currently active scene. + /// + private void Render() + { + this.sceneRenderer.Render(); + } } diff --git a/FinalEngine.Examples.Game/Program.cs b/FinalEngine.Examples.Game/Program.cs index 75866043..edb70ee1 100644 --- a/FinalEngine.Examples.Game/Program.cs +++ b/FinalEngine.Examples.Game/Program.cs @@ -73,7 +73,7 @@ internal static void Main() var gameTime = new GameTime(120.0d); resourceManager.RegisterLoader(new SoundResourceLoader(fileSystem)); - resourceManager.RegisterLoader(new ShaderResourceLoader(renderDevice.Factory, fileSystem)); + resourceManager.RegisterLoader(new ShaderResourceLoader(fileSystem, renderDevice.Factory)); resourceManager.RegisterLoader(new Texture2DResourceLoader(fileSystem, renderDevice.Factory)); displayManager.ChangeResolution(DisplayResolution.HighDefinition); diff --git a/FinalEngine.Extensions.Resources/Loaders/Shaders/ShaderResourceLoader.cs b/FinalEngine.Extensions.Resources/Loaders/Shaders/ShaderResourceLoader.cs index ab534973..a06059af 100644 --- a/FinalEngine.Extensions.Resources/Loaders/Shaders/ShaderResourceLoader.cs +++ b/FinalEngine.Extensions.Resources/Loaders/Shaders/ShaderResourceLoader.cs @@ -29,16 +29,16 @@ public sealed class ShaderResourceLoader : ResourceLoaderBase /// /// Initializes a new instance of the class. /// - /// - /// The GPU resource factory, used to load shaders into memory. - /// /// /// The file system, used to load shader source code into memory. /// + /// + /// The GPU resource factory, used to load shaders into memory. + /// /// /// The specified or parameter cannot be null. /// - public ShaderResourceLoader(IGPUResourceFactory factory, IFileSystem fileSystem) + public ShaderResourceLoader(IFileSystem fileSystem, IGPUResourceFactory factory) { this.factory = factory ?? throw new ArgumentNullException(nameof(factory)); this.fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); diff --git a/FinalEngine.Tests/Editor/Common/Services/Rendering/SceneRendererTests.cs b/FinalEngine.Tests/Editor/Common/Services/Rendering/SceneRendererTests.cs new file mode 100644 index 00000000..d028228b --- /dev/null +++ b/FinalEngine.Tests/Editor/Common/Services/Rendering/SceneRendererTests.cs @@ -0,0 +1,47 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Tests.Editor.Common.Services.Rendering; + +using System; +using System.Drawing; +using FinalEngine.Editor.Common.Services.Scenes; +using FinalEngine.Rendering; +using Moq; +using NUnit.Framework; + +[TestFixture] +public sealed class SceneRendererTests +{ + private Mock renderDevice; + + private SceneRenderer sceneRenderer; + + [Test] + public void ConstructorShouldThrowArgumentNullExceptionWhenRenderDeviceIsNull() + { + // Act and assert + Assert.Throws(() => + { + new SceneRenderer(null); + }); + } + + [Test] + public void RenderShouldInvokeRenderDeviceClearWhenInvoked() + { + // Act + this.sceneRenderer.Render(); + + // Assert + this.renderDevice.Verify(x => x.Clear(Color.FromArgb(255, 30, 30, 30), 1, 0), Times.Once); + } + + [SetUp] + public void Setup() + { + this.renderDevice = new Mock(); + this.sceneRenderer = new SceneRenderer(this.renderDevice.Object); + } +} diff --git a/FinalEngine.Tests/Editor/ViewModels/Docking/Panes/Scenes/SceneViewPaneViewModelTests.cs b/FinalEngine.Tests/Editor/ViewModels/Docking/Panes/Scenes/SceneViewPaneViewModelTests.cs index 00ac3bbd..43089bb0 100644 --- a/FinalEngine.Tests/Editor/ViewModels/Docking/Panes/Scenes/SceneViewPaneViewModelTests.cs +++ b/FinalEngine.Tests/Editor/ViewModels/Docking/Panes/Scenes/SceneViewPaneViewModelTests.cs @@ -5,6 +5,7 @@ namespace FinalEngine.Tests.Editor.ViewModels.Docking.Panes.Scenes; using System; +using FinalEngine.Editor.Common.Services.Scenes; using FinalEngine.Editor.ViewModels.Docking.Panes.Scenes; using Microsoft.Extensions.Logging; using Moq; @@ -15,6 +16,8 @@ public sealed class SceneViewPaneViewModelTests { private Mock> logger; + private Mock sceneRenderer; + private SceneViewPaneViewModel viewModel; [Test] @@ -48,14 +51,34 @@ public void ConstructorShouldThrowArgumentNullExceptionWhenLoggerIsNull() { Assert.Throws(() => { - new SceneViewPaneViewModel(null); + new SceneViewPaneViewModel(null, this.sceneRenderer.Object); + }); + } + + [Test] + public void ConstructorShouldThrowArgumentNullExceptionWhenSceneRendererIsNull() + { + Assert.Throws(() => + { + new SceneViewPaneViewModel(this.logger.Object, null); }); } + [Test] + public void RenderCommandExecuteShouldInvokeSceneRendererRenderWhenInvoked() + { + // Act + this.viewModel.RenderCommand.Execute(null); + + // Assert + this.sceneRenderer.Verify(x => x.Render(), Times.Once); + } + [SetUp] public void Setup() { this.logger = new Mock>(); - this.viewModel = new SceneViewPaneViewModel(this.logger.Object); + this.sceneRenderer = new Mock(); + this.viewModel = new SceneViewPaneViewModel(this.logger.Object, this.sceneRenderer.Object); } } diff --git a/FinalEngine.Tests/Extensions/Resources/Loaders/Shaders/ShaderResourceLoaderTests.cs b/FinalEngine.Tests/Extensions/Resources/Loaders/Shaders/ShaderResourceLoaderTests.cs index f6477730..220fd257 100644 --- a/FinalEngine.Tests/Extensions/Resources/Loaders/Shaders/ShaderResourceLoaderTests.cs +++ b/FinalEngine.Tests/Extensions/Resources/Loaders/Shaders/ShaderResourceLoaderTests.cs @@ -30,7 +30,7 @@ public void ConstructorShouldThrowArgumentNullExceptionWhenFactoryIsNull() // Act and assert Assert.Throws(() => { - new ShaderResourceLoader(null, this.fileSystem); + new ShaderResourceLoader(this.fileSystem, null); }); } @@ -40,7 +40,7 @@ public void ConstructorShouldThrowArgumentNullExceptionWhenFileSystemIsNull() // Act and assert Assert.Throws(() => { - new ShaderResourceLoader(this.factory.Object, null); + new ShaderResourceLoader(null, this.factory.Object); }); } @@ -149,6 +149,6 @@ public void Setup() this.factory.Setup(x => x.CreateShader(It.IsAny(), It.IsAny())).Returns(this.shader.Object); - this.loader = new ShaderResourceLoader(this.factory.Object, this.fileSystem); + this.loader = new ShaderResourceLoader(this.fileSystem, this.factory.Object); } } diff --git a/SharedAssemblyInfo.cs b/SharedAssemblyInfo.cs index 98e8aae4..c67831b0 100644 --- a/SharedAssemblyInfo.cs +++ b/SharedAssemblyInfo.cs @@ -9,8 +9,8 @@ [assembly: AssemblyCopyright("© 2023 Software Antics")] [assembly: AssemblyTrademark("Software Antics™")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("2023.3.1924.0")] -[assembly: AssemblyFileVersion("2023.3.1924.0")] +[assembly: AssemblyVersion("2023.3.2334.0")] +[assembly: AssemblyFileVersion("2023.3.2333.0")] #if DEBUG [assembly: AssemblyConfiguration("Debug")] #else