From 686e04fa3c2d0c92b2ec5322ed48132614c7cf3d Mon Sep 17 00:00:00 2001 From: Mathew O'Dwyer Date: Fri, 24 Mar 2023 00:30:48 +1100 Subject: [PATCH 01/11] Kinda working not really though --- .../FinalEngine.Editor.Desktop.csproj | 1 + .../Views/Docking/Panes/SceneView.xaml | 10 +++++ .../Views/Docking/Panes/SceneView.xaml.cs | 41 +++++++++++++++++++ .../Views/MainView.xaml | 6 +++ SharedAssemblyInfo.cs | 4 +- 5 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml create mode 100644 FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml.cs diff --git a/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj b/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj index ee52c386..31e3404d 100644 --- a/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj +++ b/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj @@ -27,6 +27,7 @@ + all diff --git a/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml b/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml new file mode 100644 index 00000000..1573681f --- /dev/null +++ b/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml @@ -0,0 +1,10 @@ + + diff --git a/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml.cs new file mode 100644 index 00000000..c84c74ce --- /dev/null +++ b/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml.cs @@ -0,0 +1,41 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Editor.Desktop.Views.Docking.Panes; + +using System.Drawing; +using OpenTK.Graphics.OpenGL4; +using OpenTK.Windowing.Common; +using OpenTK.Wpf; + +/// +/// Interaction logic for SceneView.xaml. +/// +public partial class SceneView : GLWpfControl +{ + /// + /// Initializes a new instance of the class. + /// + public SceneView() + { + this.InitializeComponent(); + + this.Start(new GLWpfControlSettings() + { + MajorVersion = 4, + MinorVersion = 6, + GraphicsContextFlags = ContextFlags.ForwardCompatible, + GraphicsProfile = ContextProfile.Core, + RenderContinuously = true, + }); + + this.Render += this.SceneView_Render; + } + + private void SceneView_Render(System.TimeSpan obj) + { + GL.ClearColor(Color.CornflowerBlue); + GL.Clear(ClearBufferMask.ColorBufferBit); + } +} diff --git a/FinalEngine.Editor.Desktop/Views/MainView.xaml b/FinalEngine.Editor.Desktop/Views/MainView.xaml index 41388116..c72c0cc1 100644 --- a/FinalEngine.Editor.Desktop/Views/MainView.xaml +++ b/FinalEngine.Editor.Desktop/Views/MainView.xaml @@ -5,6 +5,7 @@ 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:panes="clr-namespace:FinalEngine.Editor.Desktop.Views.Docking.Panes" mc:Ignorable="d" Width="800" Height="450" @@ -30,4 +31,9 @@ + + + + + diff --git a/SharedAssemblyInfo.cs b/SharedAssemblyInfo.cs index 8782cdcc..ad8784cb 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.1.834.1250")] -[assembly: AssemblyFileVersion("2023.1.834.1250")] +[assembly: AssemblyVersion("2023.1.865.1326")] +[assembly: AssemblyFileVersion("2023.1.865.1326")] #if DEBUG [assembly: AssemblyConfiguration("Debug")] #else From 0fd80454f19dd1e6066364d020844b4ff03ca49b Mon Sep 17 00:00:00 2001 From: Mathew O'Dwyer Date: Sat, 25 Mar 2023 19:05:17 +1100 Subject: [PATCH 02/11] Things are working --- .../FinalEngine.Editor.Common.csproj | 40 ++++++++++ .../Properties/AssemblyInfo.cs | 13 ++++ .../Services/Rendering/ISceneRenderer.cs | 12 +++ .../Services/Rendering/SceneRenderer.cs | 37 +++++++++ FinalEngine.Editor.Desktop/App.xaml | 2 + FinalEngine.Editor.Desktop/App.xaml.cs | 15 ++++ .../FinalEngine.Editor.Desktop.csproj | 7 +- .../Selectors/Docking/PanesStyleSelector.cs | 60 ++++++++++++++ .../Docking/PanesTemplateSelector.cs | 24 ++++++ .../Styles/Docking/PaneStyle.xaml | 14 ++++ .../Styles/Docking/ToolStyle.xaml | 18 +++++ .../Views/Docking/Panes/SceneView.xaml | 6 +- .../Views/Docking/Panes/SceneView.xaml.cs | 24 +++++- .../Views/MainView.xaml | 46 ++++++++++- .../Docking/Panes/IPaneViewModel.cs | 46 +++++++++++ .../Docking/Panes/ISceneViewModel.cs | 16 ++++ .../Docking/Panes/PaneViewModelBase.cs | 78 +++++++++++++++++++ .../Docking/Panes/SceneViewModel.cs | 66 ++++++++++++++++ .../Docking/Tools/IToolViewModel.cs | 19 +++++ .../Docking/Tools/ToolViewModelBase.cs | 35 +++++++++ .../Extensions/ServiceCollectionExtensions.cs | 32 ++++++++ .../FinalEngine.Editor.ViewModels.csproj | 2 + .../IMainViewModel.cs | 24 +++++- .../Interaction/AbstractFactory.cs | 22 ++++++ .../Interaction/IAbstractFactory.cs | 10 +++ .../MainViewModel.cs | 40 ++++++++-- FinalEngine.sln | 9 ++- SharedAssemblyInfo.cs | 4 +- 28 files changed, 697 insertions(+), 24 deletions(-) create mode 100644 FinalEngine.Editor.Common/FinalEngine.Editor.Common.csproj create mode 100644 FinalEngine.Editor.Common/Properties/AssemblyInfo.cs create mode 100644 FinalEngine.Editor.Common/Services/Rendering/ISceneRenderer.cs create mode 100644 FinalEngine.Editor.Common/Services/Rendering/SceneRenderer.cs create mode 100644 FinalEngine.Editor.Desktop/Selectors/Docking/PanesStyleSelector.cs create mode 100644 FinalEngine.Editor.Desktop/Selectors/Docking/PanesTemplateSelector.cs create mode 100644 FinalEngine.Editor.Desktop/Styles/Docking/PaneStyle.xaml create mode 100644 FinalEngine.Editor.Desktop/Styles/Docking/ToolStyle.xaml create mode 100644 FinalEngine.Editor.ViewModels/Docking/Panes/IPaneViewModel.cs create mode 100644 FinalEngine.Editor.ViewModels/Docking/Panes/ISceneViewModel.cs create mode 100644 FinalEngine.Editor.ViewModels/Docking/Panes/PaneViewModelBase.cs create mode 100644 FinalEngine.Editor.ViewModels/Docking/Panes/SceneViewModel.cs create mode 100644 FinalEngine.Editor.ViewModels/Docking/Tools/IToolViewModel.cs create mode 100644 FinalEngine.Editor.ViewModels/Docking/Tools/ToolViewModelBase.cs create mode 100644 FinalEngine.Editor.ViewModels/Extensions/ServiceCollectionExtensions.cs create mode 100644 FinalEngine.Editor.ViewModels/Interaction/AbstractFactory.cs create mode 100644 FinalEngine.Editor.ViewModels/Interaction/IAbstractFactory.cs diff --git a/FinalEngine.Editor.Common/FinalEngine.Editor.Common.csproj b/FinalEngine.Editor.Common/FinalEngine.Editor.Common.csproj new file mode 100644 index 00000000..bb7f75c5 --- /dev/null +++ b/FinalEngine.Editor.Common/FinalEngine.Editor.Common.csproj @@ -0,0 +1,40 @@ + + + + net7.0 + 11.0 + enable + All + false + true + x64 + + + + CA1848;CA2254 + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + diff --git a/FinalEngine.Editor.Common/Properties/AssemblyInfo.cs b/FinalEngine.Editor.Common/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..18db25cb --- /dev/null +++ b/FinalEngine.Editor.Common/Properties/AssemblyInfo.cs @@ -0,0 +1,13 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: CLSCompliant(true)] +[assembly: ComVisible(false)] +[assembly: AssemblyTitle("FinalEngine.Editor.Common")] +[assembly: AssemblyDescription("A common services library for the Final Engine editor.")] +[assembly: Guid("D8E94A1E-3718-429D-A3F7-40ADAADA636D")] diff --git a/FinalEngine.Editor.Common/Services/Rendering/ISceneRenderer.cs b/FinalEngine.Editor.Common/Services/Rendering/ISceneRenderer.cs new file mode 100644 index 00000000..0e2c39f5 --- /dev/null +++ b/FinalEngine.Editor.Common/Services/Rendering/ISceneRenderer.cs @@ -0,0 +1,12 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Editor.Common.Services.Rendering; + +public interface ISceneRenderer +{ + void ChangeProjection(int projectionWidth, int projectionHeight); + + void Render(); +} diff --git a/FinalEngine.Editor.Common/Services/Rendering/SceneRenderer.cs b/FinalEngine.Editor.Common/Services/Rendering/SceneRenderer.cs new file mode 100644 index 00000000..53f6c20f --- /dev/null +++ b/FinalEngine.Editor.Common/Services/Rendering/SceneRenderer.cs @@ -0,0 +1,37 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Editor.Common.Services.Rendering; + +using System; +using System.Drawing; +using System.Numerics; +using FinalEngine.Rendering; +using Microsoft.Extensions.Logging; + +public sealed class SceneRenderer : ISceneRenderer +{ + private readonly ILogger logger; + + private readonly IRenderDevice renderDevice; + + public SceneRenderer(ILogger logger, IRenderDevice renderDevice) + { + this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); + this.renderDevice = renderDevice ?? throw new ArgumentNullException(nameof(renderDevice)); + } + + public void ChangeProjection(int projectionWidth, int projectionHeight) + { + this.logger.LogInformation($"Changing projection to: ({projectionWidth}, {projectionHeight})."); + + this.renderDevice.Pipeline.SetUniform("u_projection", Matrix4x4.CreateOrthographicOffCenter(0, projectionWidth, 0, projectionHeight, -1, 1)); + this.renderDevice.Rasterizer.SetViewport(new Rectangle(0, 0, projectionWidth, projectionHeight)); + } + + public void Render() + { + this.renderDevice.Clear(Color.FromArgb(255, 30, 30, 30)); + } +} diff --git a/FinalEngine.Editor.Desktop/App.xaml b/FinalEngine.Editor.Desktop/App.xaml index 412083d9..cc63a725 100644 --- a/FinalEngine.Editor.Desktop/App.xaml +++ b/FinalEngine.Editor.Desktop/App.xaml @@ -8,6 +8,8 @@ + + diff --git a/FinalEngine.Editor.Desktop/App.xaml.cs b/FinalEngine.Editor.Desktop/App.xaml.cs index 41264071..9467b485 100644 --- a/FinalEngine.Editor.Desktop/App.xaml.cs +++ b/FinalEngine.Editor.Desktop/App.xaml.cs @@ -8,11 +8,18 @@ namespace FinalEngine.Editor.Desktop; using System.Diagnostics; using System.IO; using System.Windows; +using FinalEngine.Editor.Common.Services.Rendering; using FinalEngine.Editor.Desktop.Views; using FinalEngine.Editor.ViewModels; +using FinalEngine.Editor.ViewModels.Docking.Panes; +using FinalEngine.Editor.ViewModels.Extensions; +using FinalEngine.Rendering; +using FinalEngine.Rendering.OpenGL; +using FinalEngine.Rendering.OpenGL.Invocation; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using OpenTK.Windowing.Desktop; /// /// Interaction logic for App.xaml. @@ -71,6 +78,14 @@ private static IServiceProvider ConfigureServices() .AddFile(configuration.GetSection("LoggingOptions")); }); + services.AddSingleton(); + + services.AddSingleton(); + services.AddSingleton(); + + services.AddSingleton(); + + services.AddViewModelFactory(); services.AddSingleton(); return services.BuildServiceProvider(); diff --git a/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj b/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj index 31e3404d..6b1d7a03 100644 --- a/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj +++ b/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj @@ -1,7 +1,7 @@ - + - WinExe + Exe true net7.0-windows 11.0 @@ -40,6 +40,7 @@ + all @@ -48,7 +49,9 @@ + + diff --git a/FinalEngine.Editor.Desktop/Selectors/Docking/PanesStyleSelector.cs b/FinalEngine.Editor.Desktop/Selectors/Docking/PanesStyleSelector.cs new file mode 100644 index 00000000..b3b176e5 --- /dev/null +++ b/FinalEngine.Editor.Desktop/Selectors/Docking/PanesStyleSelector.cs @@ -0,0 +1,60 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Editor.Desktop.Selectors.Docking; + +using System.Windows; +using System.Windows.Controls; +using FinalEngine.Editor.ViewModels.Docking.Panes; +using FinalEngine.Editor.ViewModels.Docking.Tools; + +/// +/// Provides a style selector for an . +/// +/// +public class PanesStyleSelector : StyleSelector +{ + /// + /// Gets or sets the document style. + /// + /// + /// The document style. + /// + public Style? PaneStyle { get; set; } + + /// + /// Gets or sets the tool style. + /// + /// + /// The tool style. + /// + public Style? ToolStyle { get; set; } + + /// + /// When overridden in a derived class, returns a based on custom logic. + /// + /// + /// The content. + /// + /// + /// The element to which the style will be applied. + /// + /// + /// Returns an application-specific style to apply; otherwise, . + /// + public override Style? SelectStyle(object item, DependencyObject container) + { + if (item is IToolViewModel) + { + return this.ToolStyle; + } + + if (item is IPaneViewModel) + { + return this.PaneStyle; + } + + return base.SelectStyle(item, container); + } +} diff --git a/FinalEngine.Editor.Desktop/Selectors/Docking/PanesTemplateSelector.cs b/FinalEngine.Editor.Desktop/Selectors/Docking/PanesTemplateSelector.cs new file mode 100644 index 00000000..b2ce4bd7 --- /dev/null +++ b/FinalEngine.Editor.Desktop/Selectors/Docking/PanesTemplateSelector.cs @@ -0,0 +1,24 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Editor.Desktop.Selectors.Docking; + +using System.Windows; +using System.Windows.Controls; +using FinalEngine.Editor.ViewModels.Docking.Panes; + +public class PanesTemplateSelector : DataTemplateSelector +{ + public DataTemplate? SceneTemplate { get; set; } + + public override DataTemplate? SelectTemplate(object item, DependencyObject container) + { + if (item is ISceneViewModel) + { + return this.SceneTemplate; + } + + return base.SelectTemplate(item, container); + } +} diff --git a/FinalEngine.Editor.Desktop/Styles/Docking/PaneStyle.xaml b/FinalEngine.Editor.Desktop/Styles/Docking/PaneStyle.xaml new file mode 100644 index 00000000..3a064acc --- /dev/null +++ b/FinalEngine.Editor.Desktop/Styles/Docking/PaneStyle.xaml @@ -0,0 +1,14 @@ + + + diff --git a/FinalEngine.Editor.Desktop/Styles/Docking/ToolStyle.xaml b/FinalEngine.Editor.Desktop/Styles/Docking/ToolStyle.xaml new file mode 100644 index 00000000..cb3f0a7d --- /dev/null +++ b/FinalEngine.Editor.Desktop/Styles/Docking/ToolStyle.xaml @@ -0,0 +1,18 @@ + + + diff --git a/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml b/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml index 1573681f..9549f31d 100644 --- a/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml +++ b/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml @@ -3,8 +3,10 @@ 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;assembly=FinalEngine.Editor.ViewModels" xmlns:glwpf="clr-namespace:OpenTK.Wpf;assembly=GLWpfControl" + d:DataContext="{d:DesignInstance Type=vm:SceneViewModel}" mc:Ignorable="d" - Width="200" - Height="200"> + Render="{eb:EventBinding RenderCommand.Execute, `null`}"> diff --git a/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml.cs index c84c74ce..b6ff6634 100644 --- a/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml.cs +++ b/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml.cs @@ -4,7 +4,9 @@ namespace FinalEngine.Editor.Desktop.Views.Docking.Panes; -using System.Drawing; +using System; +using System.Windows; +using FinalEngine.Editor.ViewModels.Docking.Panes; using OpenTK.Graphics.OpenGL4; using OpenTK.Windowing.Common; using OpenTK.Wpf; @@ -24,7 +26,7 @@ public SceneView() this.Start(new GLWpfControlSettings() { MajorVersion = 4, - MinorVersion = 6, + MinorVersion = 5, GraphicsContextFlags = ContextFlags.ForwardCompatible, GraphicsProfile = ContextProfile.Core, RenderContinuously = true, @@ -33,9 +35,23 @@ public SceneView() this.Render += this.SceneView_Render; } + protected override void OnRenderSizeChanged(SizeChangedInfo info) + { + // I hate to do this because I'm violating MVVM but GLWpfControl doesn't use dependency properties. + if (this.DataContext is not ISceneViewModel viewModel) + { + throw new InvalidOperationException($"The current {nameof(this.DataContext)} is not of type {nameof(ISceneViewModel)}."); + } + + viewModel.ProjectionWidth = (int)info.NewSize.Width; + viewModel.ProjectionHeight = (int)info.NewSize.Height; + + base.OnRenderSizeChanged(info); + } + + //// TODO: Add issue to GLWpfControl repo to support commands. private void SceneView_Render(System.TimeSpan obj) { - GL.ClearColor(Color.CornflowerBlue); - GL.Clear(ClearBufferMask.ColorBufferBit); + GL.Finish(); } } diff --git a/FinalEngine.Editor.Desktop/Views/MainView.xaml b/FinalEngine.Editor.Desktop/Views/MainView.xaml index c72c0cc1..1e796dd9 100644 --- a/FinalEngine.Editor.Desktop/Views/MainView.xaml +++ b/FinalEngine.Editor.Desktop/Views/MainView.xaml @@ -5,7 +5,10 @@ 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:selectors="clr-namespace:FinalEngine.Editor.Desktop.Selectors.Docking" xmlns:panes="clr-namespace:FinalEngine.Editor.Desktop.Views.Docking.Panes" + xmlns:vm="clr-namespace:FinalEngine.Editor.ViewModels;assembly=FinalEngine.Editor.ViewModels" + d:DataContext="{d:DesignInstance Type=vm:MainViewModel}" mc:Ignorable="d" Width="800" Height="450" @@ -32,8 +35,43 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FinalEngine.Editor.ViewModels/Docking/Panes/IPaneViewModel.cs b/FinalEngine.Editor.ViewModels/Docking/Panes/IPaneViewModel.cs new file mode 100644 index 00000000..797d7a1e --- /dev/null +++ b/FinalEngine.Editor.ViewModels/Docking/Panes/IPaneViewModel.cs @@ -0,0 +1,46 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Editor.ViewModels.Docking.Panes; + +/// +/// Defines an interface that represents a pane view model. +/// +/// +/// A pane view is a view which is used as part of a dockable layout system. It represents any element that can be docked to a dockable layout. +/// +public interface IPaneViewModel +{ + /// + /// Gets or sets the content identifier. + /// + /// + /// The content identifier. + /// + string? ContentID { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is active. + /// + /// + /// true if this instance is active; otherwise, false. + /// + bool IsActive { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is selected. + /// + /// + /// true if this instance is selected; otherwise, false. + /// + bool IsSelected { get; set; } + + /// + /// Gets or sets the title. + /// + /// + /// The title. + /// + string Title { get; set; } +} diff --git a/FinalEngine.Editor.ViewModels/Docking/Panes/ISceneViewModel.cs b/FinalEngine.Editor.ViewModels/Docking/Panes/ISceneViewModel.cs new file mode 100644 index 00000000..b3e208c4 --- /dev/null +++ b/FinalEngine.Editor.ViewModels/Docking/Panes/ISceneViewModel.cs @@ -0,0 +1,16 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Editor.ViewModels.Docking.Panes; + +using System.Windows.Input; + +public interface ISceneViewModel +{ + int ProjectionHeight { get; set; } + + int ProjectionWidth { get; set; } + + ICommand RenderCommand { get; } +} diff --git a/FinalEngine.Editor.ViewModels/Docking/Panes/PaneViewModelBase.cs b/FinalEngine.Editor.ViewModels/Docking/Panes/PaneViewModelBase.cs new file mode 100644 index 00000000..79c6ef14 --- /dev/null +++ b/FinalEngine.Editor.ViewModels/Docking/Panes/PaneViewModelBase.cs @@ -0,0 +1,78 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Editor.ViewModels.Docking.Panes; + +using CommunityToolkit.Mvvm.ComponentModel; + +public partial class PaneViewModelBase : ObservableObject, IPaneViewModel +{ + /// + /// The content identifier. + /// + private string? contentID; + + /// + /// Indicates whether this instance is active. + /// + private bool isActive; + + /// + /// Indicates whether this instance is selected. + /// + private bool isSelected; + + /// + /// The title. + /// + private string? title; + + /// + /// Gets or sets the content identifier. + /// + /// + /// The content identifier. + /// + public string? ContentID + { + get { return this.contentID ?? string.Empty; } + set { this.SetProperty(ref this.contentID, value); } + } + + /// + /// Gets or sets a value indicating whether this instance is active. + /// + /// + /// true if this instance is active; otherwise, false. + /// + public bool IsActive + { + get { return this.isActive; } + set { this.SetProperty(ref this.isActive, value); } + } + + /// + /// Gets or sets a value indicating whether this instance is selected. + /// + /// + /// true if this instance is selected; otherwise, false. + /// + public bool IsSelected + { + get { return this.isSelected; } + set { this.SetProperty(ref this.isSelected, value); } + } + + /// + /// Gets or sets the title. + /// + /// + /// The title. + /// + public string Title + { + get { return this.title ?? string.Empty; } + set { this.SetProperty(ref this.title, value); } + } +} diff --git a/FinalEngine.Editor.ViewModels/Docking/Panes/SceneViewModel.cs b/FinalEngine.Editor.ViewModels/Docking/Panes/SceneViewModel.cs new file mode 100644 index 00000000..0b237974 --- /dev/null +++ b/FinalEngine.Editor.ViewModels/Docking/Panes/SceneViewModel.cs @@ -0,0 +1,66 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Editor.ViewModels.Docking.Panes; + +using System; +using System.Windows.Input; +using CommunityToolkit.Mvvm.Input; +using FinalEngine.Editor.Common.Services.Rendering; + +public partial class SceneViewModel : PaneViewModelBase, ISceneViewModel +{ + private readonly ISceneRenderer sceneRenderer; + + private int projectionHeight; + + private int projectionWidth; + + private ICommand? renderCommand; + + public SceneViewModel(ISceneRenderer sceneRenderer) + { + this.sceneRenderer = sceneRenderer ?? throw new ArgumentNullException(nameof(sceneRenderer)); + + this.Title = "Scene View"; + } + + public int ProjectionHeight + { + get + { + return this.projectionHeight; + } + + set + { + this.SetProperty(ref this.projectionHeight, value); + this.sceneRenderer.ChangeProjection(this.ProjectionWidth, this.ProjectionHeight); + } + } + + public int ProjectionWidth + { + get + { + return this.projectionWidth; + } + + set + { + this.SetProperty(ref this.projectionWidth, value); + this.sceneRenderer.ChangeProjection(this.ProjectionWidth, this.ProjectionHeight); + } + } + + public ICommand RenderCommand + { + get { return this.renderCommand ??= new RelayCommand(this.Render); } + } + + private void Render() + { + this.sceneRenderer.Render(); + } +} diff --git a/FinalEngine.Editor.ViewModels/Docking/Tools/IToolViewModel.cs b/FinalEngine.Editor.ViewModels/Docking/Tools/IToolViewModel.cs new file mode 100644 index 00000000..e1cc350e --- /dev/null +++ b/FinalEngine.Editor.ViewModels/Docking/Tools/IToolViewModel.cs @@ -0,0 +1,19 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Editor.ViewModels.Docking.Tools; + +using FinalEngine.Editor.ViewModels.Docking.Panes; + +/// +/// Defines an interface that represents a tool window view model. +/// +/// +/// A tool view is a view which is used as part of a dockable layout system. It represents any element that can be docked to the tool section of a dockable layout. +/// +/// +public interface IToolViewModel : IPaneViewModel +{ + public bool IsVisible { get; set; } +} diff --git a/FinalEngine.Editor.ViewModels/Docking/Tools/ToolViewModelBase.cs b/FinalEngine.Editor.ViewModels/Docking/Tools/ToolViewModelBase.cs new file mode 100644 index 00000000..7f2f3abe --- /dev/null +++ b/FinalEngine.Editor.ViewModels/Docking/Tools/ToolViewModelBase.cs @@ -0,0 +1,35 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Editor.ViewModels.Docking.Tools; + +using FinalEngine.Editor.ViewModels.Docking.Panes; + +public partial class ToolViewModelBase : PaneViewModelBase, IToolViewModel +{ + /// + /// Indicates whether this instance is visible. + /// + private bool isVisible; + + /// + /// Initializes a new instance of the class. + /// + protected ToolViewModelBase() + { + this.IsVisible = true; + } + + /// + /// Gets or sets a value indicating whether this instance is visible. + /// + /// + /// true if this instance is visible; otherwise, false. + /// + public bool IsVisible + { + get { return this.isVisible; } + set { this.SetProperty(ref this.isVisible, value); } + } +} diff --git a/FinalEngine.Editor.ViewModels/Extensions/ServiceCollectionExtensions.cs b/FinalEngine.Editor.ViewModels/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 00000000..b9611239 --- /dev/null +++ b/FinalEngine.Editor.ViewModels/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,32 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Editor.ViewModels.Extensions; + +using System; +using FinalEngine.Editor.ViewModels.Interaction; +using Microsoft.Extensions.DependencyInjection; + +public static class ServiceCollectionExtensions +{ + public static void AddViewModelFactory(this IServiceCollection services) + where TViewModel : class + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + services.AddTransient(); + services.AddSingleton>(x => + { + return () => + { + return x.GetRequiredService(); + }; + }); + + services.AddSingleton, AbstractFactory>(); + } +} diff --git a/FinalEngine.Editor.ViewModels/FinalEngine.Editor.ViewModels.csproj b/FinalEngine.Editor.ViewModels/FinalEngine.Editor.ViewModels.csproj index cee707c8..bd37817c 100644 --- a/FinalEngine.Editor.ViewModels/FinalEngine.Editor.ViewModels.csproj +++ b/FinalEngine.Editor.ViewModels/FinalEngine.Editor.ViewModels.csproj @@ -28,6 +28,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + all @@ -36,6 +37,7 @@ + diff --git a/FinalEngine.Editor.ViewModels/IMainViewModel.cs b/FinalEngine.Editor.ViewModels/IMainViewModel.cs index a133bb38..e47f6d8e 100644 --- a/FinalEngine.Editor.ViewModels/IMainViewModel.cs +++ b/FinalEngine.Editor.ViewModels/IMainViewModel.cs @@ -4,8 +4,10 @@ namespace FinalEngine.Editor.ViewModels; -using CommunityToolkit.Mvvm.Input; -using FinalEngine.Editor.ViewModels.Interaction; +using System.Collections.Generic; +using System.Windows.Input; +using FinalEngine.Editor.ViewModels.Docking.Panes; +using FinalEngine.Editor.ViewModels.Docking.Tools; /// /// Defines an interface that represents the main view. @@ -18,7 +20,15 @@ public interface IMainViewModel /// /// The exit command. /// - IRelayCommand ExitCommand { get; } + ICommand ExitCommand { get; } + + /// + /// Gets the documents attached to this . + /// + /// + /// The documents attached to this . + /// + IEnumerable Panes { get; } /// /// Gets the title. @@ -27,4 +37,12 @@ public interface IMainViewModel /// The title. /// string Title { get; } + + /// + /// Gets the tool windows attached to this . + /// + /// + /// The tool windows attached to this . + /// + IEnumerable Tools { get; } } diff --git a/FinalEngine.Editor.ViewModels/Interaction/AbstractFactory.cs b/FinalEngine.Editor.ViewModels/Interaction/AbstractFactory.cs new file mode 100644 index 00000000..67dafc1d --- /dev/null +++ b/FinalEngine.Editor.ViewModels/Interaction/AbstractFactory.cs @@ -0,0 +1,22 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Editor.ViewModels.Interaction; + +using System; + +public class AbstractFactory : IAbstractFactory +{ + private readonly Func factory; + + public AbstractFactory(Func factory) + { + this.factory = factory ?? throw new ArgumentNullException(nameof(factory)); + } + + public T Create() + { + return this.factory(); + } +} diff --git a/FinalEngine.Editor.ViewModels/Interaction/IAbstractFactory.cs b/FinalEngine.Editor.ViewModels/Interaction/IAbstractFactory.cs new file mode 100644 index 00000000..61f7c868 --- /dev/null +++ b/FinalEngine.Editor.ViewModels/Interaction/IAbstractFactory.cs @@ -0,0 +1,10 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Editor.ViewModels.Interaction; + +public interface IAbstractFactory +{ + T Create(); +} diff --git a/FinalEngine.Editor.ViewModels/MainViewModel.cs b/FinalEngine.Editor.ViewModels/MainViewModel.cs index 5f856f7a..cdd92c7a 100644 --- a/FinalEngine.Editor.ViewModels/MainViewModel.cs +++ b/FinalEngine.Editor.ViewModels/MainViewModel.cs @@ -5,9 +5,13 @@ namespace FinalEngine.Editor.ViewModels; using System; +using System.Collections.Generic; using System.Reflection; +using System.Windows.Input; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; +using FinalEngine.Editor.ViewModels.Docking.Panes; +using FinalEngine.Editor.ViewModels.Docking.Tools; using FinalEngine.Editor.ViewModels.Interaction; using FinalEngine.Utilities.Extensions; using Microsoft.Extensions.Logging; @@ -24,10 +28,8 @@ public partial class MainViewModel : ObservableObject, IMainViewModel /// private readonly ILogger logger; - /// - /// The main application title. - /// - [ObservableProperty] + private ICommand? exitCommand; + private string? title; /// @@ -39,12 +41,39 @@ public partial class MainViewModel : ObservableObject, IMainViewModel /// /// The specified parameter cannot be null. /// - public MainViewModel(ILogger logger) + public MainViewModel(ILogger logger, IAbstractFactory sceneViewModelFactory) { + if (sceneViewModelFactory == null) + { + throw new ArgumentNullException(nameof(sceneViewModelFactory)); + } + + this.Panes = new List() + { + sceneViewModelFactory.Create(), + }; + + this.Tools = new List(); + this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); this.Title = $"Final Engine - {Assembly.GetExecutingAssembly().GetVersionString()}"; } + public ICommand ExitCommand + { + get { return this.exitCommand ??= new RelayCommand(this.Exit); } + } + + public IEnumerable Panes { get; } + + public string Title + { + get { return this.title ?? string.Empty; } + private set { this.SetProperty(ref this.title, value); } + } + + public IEnumerable Tools { get; } + /// /// Attempts to the exit the main application. /// @@ -54,7 +83,6 @@ public MainViewModel(ILogger logger) /// /// The specified parameter cannot be null. /// - [RelayCommand] private void Exit(ICloseable? closeable) { if (closeable == null) diff --git a/FinalEngine.sln b/FinalEngine.sln index 4e853e44..26063458 100644 --- a/FinalEngine.sln +++ b/FinalEngine.sln @@ -64,10 +64,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FinalEngine.Audio.OpenAL", EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Editor", "Editor", "{37EAC441-4D26-49E2-884D-E1979650C873}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FinalEngine.Editor.Desktop", "FinalEngine.Editor.Desktop\FinalEngine.Editor.Desktop.csproj", "{8FF533B9-33BB-4E42-AAE1-95E8F2747264}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FinalEngine.Editor.Desktop", "FinalEngine.Editor.Desktop\FinalEngine.Editor.Desktop.csproj", "{8FF533B9-33BB-4E42-AAE1-95E8F2747264}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FinalEngine.Editor.ViewModels", "FinalEngine.Editor.ViewModels\FinalEngine.Editor.ViewModels.csproj", "{DB6A0D9E-7199-4721-AFCF-2774080012FD}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FinalEngine.Editor.Common", "FinalEngine.Editor.Common\FinalEngine.Editor.Common.csproj", "{5CD4CCAD-5645-43E2-A61F-E2882FEE3EF8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -154,6 +156,10 @@ Global {DB6A0D9E-7199-4721-AFCF-2774080012FD}.Debug|x64.Build.0 = Debug|x64 {DB6A0D9E-7199-4721-AFCF-2774080012FD}.Release|x64.ActiveCfg = Release|Any CPU {DB6A0D9E-7199-4721-AFCF-2774080012FD}.Release|x64.Build.0 = Release|Any CPU + {5CD4CCAD-5645-43E2-A61F-E2882FEE3EF8}.Debug|x64.ActiveCfg = Debug|x64 + {5CD4CCAD-5645-43E2-A61F-E2882FEE3EF8}.Debug|x64.Build.0 = Debug|x64 + {5CD4CCAD-5645-43E2-A61F-E2882FEE3EF8}.Release|x64.ActiveCfg = Release|Any CPU + {5CD4CCAD-5645-43E2-A61F-E2882FEE3EF8}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -179,6 +185,7 @@ Global {D67794A8-89AC-46E0-B303-94110BB382F8} = {B4084D99-8DC5-4E1C-B5BF-9C7351CE71B8} {8FF533B9-33BB-4E42-AAE1-95E8F2747264} = {37EAC441-4D26-49E2-884D-E1979650C873} {DB6A0D9E-7199-4721-AFCF-2774080012FD} = {37EAC441-4D26-49E2-884D-E1979650C873} + {5CD4CCAD-5645-43E2-A61F-E2882FEE3EF8} = {37EAC441-4D26-49E2-884D-E1979650C873} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A278B383-0D14-41B3-A71C-4505E1D503DF} diff --git a/SharedAssemblyInfo.cs b/SharedAssemblyInfo.cs index ad8784cb..c1c25c86 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.1.865.1326")] -[assembly: AssemblyFileVersion("2023.1.865.1326")] +[assembly: AssemblyVersion("2023.1.1111.0803")] +[assembly: AssemblyFileVersion("2023.1.1111.0803")] #if DEBUG [assembly: AssemblyConfiguration("Debug")] #else From bb5063d75a3162f540d88294de3696590495ceee Mon Sep 17 00:00:00 2001 From: Mathew O'Dwyer Date: Sat, 25 Mar 2023 22:03:29 +1100 Subject: [PATCH 03/11] Going to finish up this PR now --- FinalEngine.Editor.Desktop/App.xaml.cs | 3 -- .../Views/Docking/Panes/SceneView.xaml.cs | 16 +--------- .../Docking/Panes/ISceneViewModel.cs | 7 ++-- .../Docking/Panes/SceneViewModel.cs | 32 ++++++------------- SharedAssemblyInfo.cs | 4 +-- 5 files changed, 15 insertions(+), 47 deletions(-) diff --git a/FinalEngine.Editor.Desktop/App.xaml.cs b/FinalEngine.Editor.Desktop/App.xaml.cs index 9467b485..1f072a2e 100644 --- a/FinalEngine.Editor.Desktop/App.xaml.cs +++ b/FinalEngine.Editor.Desktop/App.xaml.cs @@ -19,7 +19,6 @@ namespace FinalEngine.Editor.Desktop; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using OpenTK.Windowing.Desktop; /// /// Interaction logic for App.xaml. @@ -78,8 +77,6 @@ private static IServiceProvider ConfigureServices() .AddFile(configuration.GetSection("LoggingOptions")); }); - services.AddSingleton(); - services.AddSingleton(); services.AddSingleton(); diff --git a/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml.cs index b6ff6634..8b2d6fc7 100644 --- a/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml.cs +++ b/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml.cs @@ -35,23 +35,9 @@ public SceneView() this.Render += this.SceneView_Render; } - protected override void OnRenderSizeChanged(SizeChangedInfo info) - { - // I hate to do this because I'm violating MVVM but GLWpfControl doesn't use dependency properties. - if (this.DataContext is not ISceneViewModel viewModel) - { - throw new InvalidOperationException($"The current {nameof(this.DataContext)} is not of type {nameof(ISceneViewModel)}."); - } - - viewModel.ProjectionWidth = (int)info.NewSize.Width; - viewModel.ProjectionHeight = (int)info.NewSize.Height; - - base.OnRenderSizeChanged(info); - } - - //// TODO: Add issue to GLWpfControl repo to support commands. private void SceneView_Render(System.TimeSpan obj) { + //// TODO: Create issue for this. GL.Finish(); } } diff --git a/FinalEngine.Editor.ViewModels/Docking/Panes/ISceneViewModel.cs b/FinalEngine.Editor.ViewModels/Docking/Panes/ISceneViewModel.cs index b3e208c4..312bced4 100644 --- a/FinalEngine.Editor.ViewModels/Docking/Panes/ISceneViewModel.cs +++ b/FinalEngine.Editor.ViewModels/Docking/Panes/ISceneViewModel.cs @@ -4,13 +4,12 @@ namespace FinalEngine.Editor.ViewModels.Docking.Panes; +using System.Drawing; using System.Windows.Input; public interface ISceneViewModel { - int ProjectionHeight { get; set; } - - int ProjectionWidth { get; set; } - ICommand RenderCommand { get; } + + Size ProjectionSize { get; } } diff --git a/FinalEngine.Editor.ViewModels/Docking/Panes/SceneViewModel.cs b/FinalEngine.Editor.ViewModels/Docking/Panes/SceneViewModel.cs index 0b237974..477c4a5a 100644 --- a/FinalEngine.Editor.ViewModels/Docking/Panes/SceneViewModel.cs +++ b/FinalEngine.Editor.ViewModels/Docking/Panes/SceneViewModel.cs @@ -5,6 +5,7 @@ namespace FinalEngine.Editor.ViewModels.Docking.Panes; using System; +using System.Drawing; using System.Windows.Input; using CommunityToolkit.Mvvm.Input; using FinalEngine.Editor.Common.Services.Rendering; @@ -13,12 +14,10 @@ public partial class SceneViewModel : PaneViewModelBase, ISceneViewModel { private readonly ISceneRenderer sceneRenderer; - private int projectionHeight; - - private int projectionWidth; - private ICommand? renderCommand; + private Size projectionSize; + public SceneViewModel(ISceneRenderer sceneRenderer) { this.sceneRenderer = sceneRenderer ?? throw new ArgumentNullException(nameof(sceneRenderer)); @@ -26,31 +25,18 @@ public SceneViewModel(ISceneRenderer sceneRenderer) this.Title = "Scene View"; } - public int ProjectionHeight - { - get - { - return this.projectionHeight; - } - - set - { - this.SetProperty(ref this.projectionHeight, value); - this.sceneRenderer.ChangeProjection(this.ProjectionWidth, this.ProjectionHeight); - } - } - - public int ProjectionWidth + //// TODO: Hook this up to GLWpfControl.RenderSize, waiting on: https://github.com/opentk/GLWpfControl/issues/108. + public Size ProjectionSize { get { - return this.projectionWidth; + return this.projectionSize; } - set + private set { - this.SetProperty(ref this.projectionWidth, value); - this.sceneRenderer.ChangeProjection(this.ProjectionWidth, this.ProjectionHeight); + this.SetProperty(ref this.projectionSize, value); + this.sceneRenderer.ChangeProjection(this.projectionSize.Width, this.projectionSize.Height); } } diff --git a/SharedAssemblyInfo.cs b/SharedAssemblyInfo.cs index c1c25c86..04b61945 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.1.1111.0803")] -[assembly: AssemblyFileVersion("2023.1.1111.0803")] +[assembly: AssemblyVersion("2023.1.1164.1046")] +[assembly: AssemblyFileVersion("2023.1.1164.1046")] #if DEBUG [assembly: AssemblyConfiguration("Debug")] #else From c26cd2fc2d7207027acfa04465b35eb94cbed6ce Mon Sep 17 00:00:00 2001 From: Mathew O'Dwyer Date: Sat, 25 Mar 2023 22:27:56 +1100 Subject: [PATCH 04/11] Using AppHost now --- .../Extensions/ServiceCollectionExtensions.cs | 24 +++++++ .../FinalEngine.Editor.Common.csproj | 1 + .../Services/Rendering/SceneRenderer.cs | 2 +- FinalEngine.Editor.Desktop/App.xaml.cs | 62 +++++++++---------- .../FinalEngine.Editor.Desktop.csproj | 2 + .../Extensions/ServiceCollectionExtensions.cs | 25 ++++++++ .../FinalEngine.Rendering.OpenGL.csproj | 1 + SharedAssemblyInfo.cs | 4 +- 8 files changed, 86 insertions(+), 35 deletions(-) create mode 100644 FinalEngine.Editor.Common/Extensions/ServiceCollectionExtensions.cs create mode 100644 FinalEngine.Rendering.OpenGL/Extensions/ServiceCollectionExtensions.cs diff --git a/FinalEngine.Editor.Common/Extensions/ServiceCollectionExtensions.cs b/FinalEngine.Editor.Common/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 00000000..ed871b90 --- /dev/null +++ b/FinalEngine.Editor.Common/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,24 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Editor.Common.Extensions; + +using System; +using FinalEngine.Editor.Common.Services.Rendering; +using Microsoft.Extensions.DependencyInjection; + +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddCommon(this IServiceCollection services) + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + services.AddSingleton(); + + return services; + } +} diff --git a/FinalEngine.Editor.Common/FinalEngine.Editor.Common.csproj b/FinalEngine.Editor.Common/FinalEngine.Editor.Common.csproj index bb7f75c5..c108b177 100644 --- a/FinalEngine.Editor.Common/FinalEngine.Editor.Common.csproj +++ b/FinalEngine.Editor.Common/FinalEngine.Editor.Common.csproj @@ -27,6 +27,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + all diff --git a/FinalEngine.Editor.Common/Services/Rendering/SceneRenderer.cs b/FinalEngine.Editor.Common/Services/Rendering/SceneRenderer.cs index 53f6c20f..ab938a45 100644 --- a/FinalEngine.Editor.Common/Services/Rendering/SceneRenderer.cs +++ b/FinalEngine.Editor.Common/Services/Rendering/SceneRenderer.cs @@ -24,7 +24,7 @@ public SceneRenderer(ILogger logger, IRenderDevice renderDevice) public void ChangeProjection(int projectionWidth, int projectionHeight) { - this.logger.LogInformation($"Changing projection to: ({projectionWidth}, {projectionHeight})."); + this.logger.LogDebug($"Changing projection to: ({projectionWidth}, {projectionHeight})."); this.renderDevice.Pipeline.SetUniform("u_projection", Matrix4x4.CreateOrthographicOffCenter(0, projectionWidth, 0, projectionHeight, -1, 1)); this.renderDevice.Rasterizer.SetViewport(new Rectangle(0, 0, projectionWidth, projectionHeight)); diff --git a/FinalEngine.Editor.Desktop/App.xaml.cs b/FinalEngine.Editor.Desktop/App.xaml.cs index 1f072a2e..94e1ab8b 100644 --- a/FinalEngine.Editor.Desktop/App.xaml.cs +++ b/FinalEngine.Editor.Desktop/App.xaml.cs @@ -4,20 +4,18 @@ namespace FinalEngine.Editor.Desktop; -using System; using System.Diagnostics; using System.IO; using System.Windows; -using FinalEngine.Editor.Common.Services.Rendering; +using FinalEngine.Editor.Common.Extensions; using FinalEngine.Editor.Desktop.Views; using FinalEngine.Editor.ViewModels; using FinalEngine.Editor.ViewModels.Docking.Panes; using FinalEngine.Editor.ViewModels.Extensions; -using FinalEngine.Rendering; -using FinalEngine.Rendering.OpenGL; -using FinalEngine.Rendering.OpenGL.Invocation; +using FinalEngine.Rendering.OpenGL.Extensions; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; /// @@ -25,15 +23,33 @@ namespace FinalEngine.Editor.Desktop; /// public partial class App : Application { + public App() + { + AppHost = Host.CreateDefaultBuilder() + .ConfigureAppConfiguration(ConfigureAppConfiguration) + .ConfigureServices(ConfigureServices) + .Build(); + } + + private static IHost? AppHost { get; set; } + + protected override async void OnExit(ExitEventArgs e) + { + await AppHost!.StopAsync(); + base.OnExit(e); + } + /// /// Starts up the main application on the current platform. /// /// /// A that contains the event data. /// - protected override void OnStartup(StartupEventArgs e) + protected override async void OnStartup(StartupEventArgs e) { - var viewModel = ConfigureServices().GetRequiredService(); + await AppHost!.StartAsync(); + + var viewModel = AppHost.Services.GetRequiredService(); var view = new MainView() { @@ -43,32 +59,18 @@ protected override void OnStartup(StartupEventArgs e) view.ShowDialog(); } - /// - /// Builds the configuration used throughout the lifetime of the application. - /// - /// - /// The newly created to be used throughout the lifetime of the application. - /// - private static IConfiguration BuildConfiguration() + private static void ConfigureAppConfiguration(IConfigurationBuilder builder) { string environment = Debugger.IsAttached ? "Development" : "Production"; - return new ConfigurationBuilder() + builder .SetBasePath(Directory.GetCurrentDirectory()) - .AddJsonFile($"appsettings.{environment}.json") - .Build(); + .AddJsonFile($"appsettings.{environment}.json"); } - /// - /// Configures the services to be consumed by the application. - /// - /// - /// The newly configured . - /// - private static IServiceProvider ConfigureServices() + private static void ConfigureServices(HostBuilderContext context, IServiceCollection services) { - var services = new ServiceCollection(); - var configuration = BuildConfiguration(); + var configuration = context.Configuration; services.AddLogging(builder => { @@ -77,14 +79,10 @@ private static IServiceProvider ConfigureServices() .AddFile(configuration.GetSection("LoggingOptions")); }); - services.AddSingleton(); - services.AddSingleton(); - - services.AddSingleton(); + services.AddCommon(); + services.AddRendering(); services.AddViewModelFactory(); services.AddSingleton(); - - return services.BuildServiceProvider(); } } diff --git a/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj b/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj index 6b1d7a03..6f498076 100644 --- a/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj +++ b/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj @@ -37,6 +37,8 @@ + + diff --git a/FinalEngine.Rendering.OpenGL/Extensions/ServiceCollectionExtensions.cs b/FinalEngine.Rendering.OpenGL/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 00000000..25a34773 --- /dev/null +++ b/FinalEngine.Rendering.OpenGL/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,25 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Rendering.OpenGL.Extensions; + +using System; +using FinalEngine.Rendering.OpenGL.Invocation; +using Microsoft.Extensions.DependencyInjection; + +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddRendering(this IServiceCollection services) + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + services.AddSingleton(); + services.AddSingleton(); + + return services; + } +} diff --git a/FinalEngine.Rendering.OpenGL/FinalEngine.Rendering.OpenGL.csproj b/FinalEngine.Rendering.OpenGL/FinalEngine.Rendering.OpenGL.csproj index 085eefbd..c8ad1b9a 100644 --- a/FinalEngine.Rendering.OpenGL/FinalEngine.Rendering.OpenGL.csproj +++ b/FinalEngine.Rendering.OpenGL/FinalEngine.Rendering.OpenGL.csproj @@ -23,6 +23,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/SharedAssemblyInfo.cs b/SharedAssemblyInfo.cs index 04b61945..658ab081 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.1.1164.1046")] -[assembly: AssemblyFileVersion("2023.1.1164.1046")] +[assembly: AssemblyVersion("2023.1.1176.1121")] +[assembly: AssemblyFileVersion("2023.1.1176.1121")] #if DEBUG [assembly: AssemblyConfiguration("Debug")] #else From a84f508770de6f0074b467df1c83a6492bbd44bc Mon Sep 17 00:00:00 2001 From: Mathew O'Dwyer Date: Sat, 25 Mar 2023 22:42:44 +1100 Subject: [PATCH 05/11] Cleanup --- .../Extensions/ServiceCollectionExtensions.cs | 15 +++++++ .../Services/Rendering/ISceneRenderer.cs | 15 +++++++ .../Services/Rendering/SceneRenderer.cs | 24 ++++++++++ FinalEngine.Editor.Desktop/App.xaml.cs | 38 +++++++++++++++- .../Docking/PanesTemplateSelector.cs | 22 ++++++++++ .../Views/Docking/Panes/SceneView.xaml.cs | 10 +++-- .../Docking/Panes/ISceneViewModel.cs | 19 +++++++- .../Docking/Panes/PaneViewModelBase.cs | 5 +++ .../Docking/Panes/SceneViewModel.cs | 44 +++++++++++++++++-- .../Docking/Tools/IToolViewModel.cs | 6 +++ .../Docking/Tools/ToolViewModelBase.cs | 5 +++ .../Extensions/ServiceCollectionExtensions.cs | 15 +++++++ .../Extensions/ServiceCollectionExtensions.cs | 25 ----------- .../FinalEngine.Rendering.OpenGL.csproj | 1 - SharedAssemblyInfo.cs | 4 +- 15 files changed, 210 insertions(+), 38 deletions(-) delete mode 100644 FinalEngine.Rendering.OpenGL/Extensions/ServiceCollectionExtensions.cs diff --git a/FinalEngine.Editor.Common/Extensions/ServiceCollectionExtensions.cs b/FinalEngine.Editor.Common/Extensions/ServiceCollectionExtensions.cs index ed871b90..d8dc6d3c 100644 --- a/FinalEngine.Editor.Common/Extensions/ServiceCollectionExtensions.cs +++ b/FinalEngine.Editor.Common/Extensions/ServiceCollectionExtensions.cs @@ -8,8 +8,23 @@ namespace FinalEngine.Editor.Common.Extensions; using FinalEngine.Editor.Common.Services.Rendering; using Microsoft.Extensions.DependencyInjection; +/// +/// Provides extension methods for an . +/// public static class ServiceCollectionExtensions { + /// + /// Adds all common services to specified collection. + /// + /// + /// The services collection. + /// + /// + /// The collection. + /// + /// + /// The specified parameter cannot be null. + /// public static IServiceCollection AddCommon(this IServiceCollection services) { if (services == null) diff --git a/FinalEngine.Editor.Common/Services/Rendering/ISceneRenderer.cs b/FinalEngine.Editor.Common/Services/Rendering/ISceneRenderer.cs index 0e2c39f5..f7dc7eec 100644 --- a/FinalEngine.Editor.Common/Services/Rendering/ISceneRenderer.cs +++ b/FinalEngine.Editor.Common/Services/Rendering/ISceneRenderer.cs @@ -4,9 +4,24 @@ namespace FinalEngine.Editor.Common.Services.Rendering; +/// +/// Defines an interface that represents a scene renderer. +/// public interface ISceneRenderer { + /// + /// Changes the current scene projection the specified and . + /// + /// + /// The width of the projection. + /// + /// + /// The height of the projection. + /// void ChangeProjection(int projectionWidth, int projectionHeight); + /// + /// Renders the currently active scene. + /// void Render(); } diff --git a/FinalEngine.Editor.Common/Services/Rendering/SceneRenderer.cs b/FinalEngine.Editor.Common/Services/Rendering/SceneRenderer.cs index ab938a45..5fed2e42 100644 --- a/FinalEngine.Editor.Common/Services/Rendering/SceneRenderer.cs +++ b/FinalEngine.Editor.Common/Services/Rendering/SceneRenderer.cs @@ -10,18 +10,41 @@ namespace FinalEngine.Editor.Common.Services.Rendering; using FinalEngine.Rendering; using Microsoft.Extensions.Logging; +/// +/// Provides a standard implementation of an . +/// +/// public sealed class SceneRenderer : ISceneRenderer { + /// + /// The logger. + /// private readonly ILogger logger; + /// + /// The render device. + /// private readonly IRenderDevice renderDevice; + /// + /// Initializes a new instance of the class. + /// + /// + /// The logger. + /// + /// + /// The render device. + /// + /// + /// The specified or parameter cannot be null. + /// public SceneRenderer(ILogger logger, IRenderDevice renderDevice) { this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); this.renderDevice = renderDevice ?? throw new ArgumentNullException(nameof(renderDevice)); } + /// public void ChangeProjection(int projectionWidth, int projectionHeight) { this.logger.LogDebug($"Changing projection to: ({projectionWidth}, {projectionHeight})."); @@ -30,6 +53,7 @@ public void ChangeProjection(int projectionWidth, int projectionHeight) this.renderDevice.Rasterizer.SetViewport(new Rectangle(0, 0, projectionWidth, projectionHeight)); } + /// 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 94e1ab8b..45f05bb8 100644 --- a/FinalEngine.Editor.Desktop/App.xaml.cs +++ b/FinalEngine.Editor.Desktop/App.xaml.cs @@ -12,7 +12,9 @@ namespace FinalEngine.Editor.Desktop; using FinalEngine.Editor.ViewModels; using FinalEngine.Editor.ViewModels.Docking.Panes; using FinalEngine.Editor.ViewModels.Extensions; -using FinalEngine.Rendering.OpenGL.Extensions; +using FinalEngine.Rendering; +using FinalEngine.Rendering.OpenGL; +using FinalEngine.Rendering.OpenGL.Invocation; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -23,6 +25,9 @@ namespace FinalEngine.Editor.Desktop; /// public partial class App : Application { + /// + /// Initializes a new instance of the class. + /// public App() { AppHost = Host.CreateDefaultBuilder() @@ -31,8 +36,20 @@ public App() .Build(); } + /// + /// Gets or sets the application host. + /// + /// + /// The application host. + /// private static IHost? AppHost { get; set; } + /// + /// Exits the main application, disposing of any existing resources. + /// + /// + /// The instance containing the event data. + /// protected override async void OnExit(ExitEventArgs e) { await AppHost!.StopAsync(); @@ -59,6 +76,12 @@ protected override async void OnStartup(StartupEventArgs e) view.ShowDialog(); } + /// + /// Configures the applications configuration. + /// + /// + /// The builder. + /// private static void ConfigureAppConfiguration(IConfigurationBuilder builder) { string environment = Debugger.IsAttached ? "Development" : "Production"; @@ -68,6 +91,15 @@ private static void ConfigureAppConfiguration(IConfigurationBuilder builder) .AddJsonFile($"appsettings.{environment}.json"); } + /// + /// Configures the services to be consumed by the application. + /// + /// + /// The context. + /// + /// + /// The services. + /// private static void ConfigureServices(HostBuilderContext context, IServiceCollection services) { var configuration = context.Configuration; @@ -79,8 +111,10 @@ private static void ConfigureServices(HostBuilderContext context, IServiceCollec .AddFile(configuration.GetSection("LoggingOptions")); }); + services.AddSingleton(); + services.AddSingleton(); + services.AddCommon(); - services.AddRendering(); services.AddViewModelFactory(); services.AddSingleton(); diff --git a/FinalEngine.Editor.Desktop/Selectors/Docking/PanesTemplateSelector.cs b/FinalEngine.Editor.Desktop/Selectors/Docking/PanesTemplateSelector.cs index b2ce4bd7..7dd2be8f 100644 --- a/FinalEngine.Editor.Desktop/Selectors/Docking/PanesTemplateSelector.cs +++ b/FinalEngine.Editor.Desktop/Selectors/Docking/PanesTemplateSelector.cs @@ -8,10 +8,32 @@ namespace FinalEngine.Editor.Desktop.Selectors.Docking; using System.Windows.Controls; using FinalEngine.Editor.ViewModels.Docking.Panes; +/// +/// Provides a pane template style selector. +/// +/// public class PanesTemplateSelector : DataTemplateSelector { + /// + /// Gets or sets the scene template. + /// + /// + /// The scene template. + /// public DataTemplate? SceneTemplate { get; set; } + /// + /// When overridden in a derived class, returns a based on custom logic. + /// + /// + /// The data object for which to select the template. + /// + /// + /// The data-bound object. + /// + /// + /// Returns a or null. The default value is null. + /// public override DataTemplate? SelectTemplate(object item, DependencyObject container) { if (item is ISceneViewModel) diff --git a/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml.cs index 8b2d6fc7..05590011 100644 --- a/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml.cs +++ b/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml.cs @@ -4,9 +4,6 @@ namespace FinalEngine.Editor.Desktop.Views.Docking.Panes; -using System; -using System.Windows; -using FinalEngine.Editor.ViewModels.Docking.Panes; using OpenTK.Graphics.OpenGL4; using OpenTK.Windowing.Common; using OpenTK.Wpf; @@ -23,6 +20,7 @@ public SceneView() { this.InitializeComponent(); + //// TODO: Use XAML and implement this in view model, waiting on: https://github.com/opentk/GLWpfControl/pull/106. this.Start(new GLWpfControlSettings() { MajorVersion = 4, @@ -35,6 +33,12 @@ public SceneView() this.Render += this.SceneView_Render; } + /// + /// Block and wait until the scene is rendered. + /// + /// + /// The delta time. + /// private void SceneView_Render(System.TimeSpan obj) { //// TODO: Create issue for this. diff --git a/FinalEngine.Editor.ViewModels/Docking/Panes/ISceneViewModel.cs b/FinalEngine.Editor.ViewModels/Docking/Panes/ISceneViewModel.cs index 312bced4..60c9eb58 100644 --- a/FinalEngine.Editor.ViewModels/Docking/Panes/ISceneViewModel.cs +++ b/FinalEngine.Editor.ViewModels/Docking/Panes/ISceneViewModel.cs @@ -7,9 +7,24 @@ namespace FinalEngine.Editor.ViewModels.Docking.Panes; using System.Drawing; using System.Windows.Input; +/// +/// Defines an interface that represents a scene view, view model. +/// public interface ISceneViewModel { - ICommand RenderCommand { get; } - + /// + /// Gets the size of the projection. + /// + /// + /// The size of the projection. + /// Size ProjectionSize { get; } + + /// + /// Gets the render command. + /// + /// + /// The render command. + /// + ICommand RenderCommand { get; } } diff --git a/FinalEngine.Editor.ViewModels/Docking/Panes/PaneViewModelBase.cs b/FinalEngine.Editor.ViewModels/Docking/Panes/PaneViewModelBase.cs index 79c6ef14..30115b6b 100644 --- a/FinalEngine.Editor.ViewModels/Docking/Panes/PaneViewModelBase.cs +++ b/FinalEngine.Editor.ViewModels/Docking/Panes/PaneViewModelBase.cs @@ -6,6 +6,11 @@ namespace FinalEngine.Editor.ViewModels.Docking.Panes; using CommunityToolkit.Mvvm.ComponentModel; +/// +/// The base class to be implemented for a document view. +/// +/// +/// public partial class PaneViewModelBase : ObservableObject, IPaneViewModel { /// diff --git a/FinalEngine.Editor.ViewModels/Docking/Panes/SceneViewModel.cs b/FinalEngine.Editor.ViewModels/Docking/Panes/SceneViewModel.cs index 477c4a5a..044c9aee 100644 --- a/FinalEngine.Editor.ViewModels/Docking/Panes/SceneViewModel.cs +++ b/FinalEngine.Editor.ViewModels/Docking/Panes/SceneViewModel.cs @@ -10,14 +10,37 @@ namespace FinalEngine.Editor.ViewModels.Docking.Panes; using CommunityToolkit.Mvvm.Input; using FinalEngine.Editor.Common.Services.Rendering; +/// +/// Represents a standard implementation of an . +/// +/// +/// public partial class SceneViewModel : PaneViewModelBase, ISceneViewModel { + /// + /// The scene renderer. + /// private readonly ISceneRenderer sceneRenderer; - private ICommand? renderCommand; - + /// + /// The projection size. + /// private Size projectionSize; + /// + /// The render command. + /// + private ICommand? renderCommand; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The scene renderer. + /// + /// + /// The specified parameter cannot be null. + /// public SceneViewModel(ISceneRenderer sceneRenderer) { this.sceneRenderer = sceneRenderer ?? throw new ArgumentNullException(nameof(sceneRenderer)); @@ -25,7 +48,12 @@ public SceneViewModel(ISceneRenderer sceneRenderer) this.Title = "Scene View"; } - //// TODO: Hook this up to GLWpfControl.RenderSize, waiting on: https://github.com/opentk/GLWpfControl/issues/108. + /// + /// Gets the size of the projection. + /// + /// + /// The size of the projection. + /// public Size ProjectionSize { get @@ -35,16 +63,26 @@ public Size ProjectionSize private set { + //// TODO: Hook this up to GLWpfControl.RenderSize, waiting on: https://github.com/opentk/GLWpfControl/issues/108. this.SetProperty(ref this.projectionSize, value); this.sceneRenderer.ChangeProjection(this.projectionSize.Width, this.projectionSize.Height); } } + /// + /// Gets the render command. + /// + /// + /// The render command. + /// public ICommand RenderCommand { get { return this.renderCommand ??= new RelayCommand(this.Render); } } + /// + /// Renders the scene to the view. + /// private void Render() { this.sceneRenderer.Render(); diff --git a/FinalEngine.Editor.ViewModels/Docking/Tools/IToolViewModel.cs b/FinalEngine.Editor.ViewModels/Docking/Tools/IToolViewModel.cs index e1cc350e..a45a1c27 100644 --- a/FinalEngine.Editor.ViewModels/Docking/Tools/IToolViewModel.cs +++ b/FinalEngine.Editor.ViewModels/Docking/Tools/IToolViewModel.cs @@ -15,5 +15,11 @@ namespace FinalEngine.Editor.ViewModels.Docking.Tools; /// public interface IToolViewModel : IPaneViewModel { + /// + /// Gets or sets a value indicating whether this instance is visible. + /// + /// + /// true if this instance is visible; otherwise, false. + /// public bool IsVisible { get; set; } } diff --git a/FinalEngine.Editor.ViewModels/Docking/Tools/ToolViewModelBase.cs b/FinalEngine.Editor.ViewModels/Docking/Tools/ToolViewModelBase.cs index 7f2f3abe..5b34aa4e 100644 --- a/FinalEngine.Editor.ViewModels/Docking/Tools/ToolViewModelBase.cs +++ b/FinalEngine.Editor.ViewModels/Docking/Tools/ToolViewModelBase.cs @@ -6,6 +6,11 @@ namespace FinalEngine.Editor.ViewModels.Docking.Tools; using FinalEngine.Editor.ViewModels.Docking.Panes; +/// +/// The base class to be implemented for a tool window view. +/// +/// +/// public partial class ToolViewModelBase : PaneViewModelBase, IToolViewModel { /// diff --git a/FinalEngine.Editor.ViewModels/Extensions/ServiceCollectionExtensions.cs b/FinalEngine.Editor.ViewModels/Extensions/ServiceCollectionExtensions.cs index b9611239..995fa656 100644 --- a/FinalEngine.Editor.ViewModels/Extensions/ServiceCollectionExtensions.cs +++ b/FinalEngine.Editor.ViewModels/Extensions/ServiceCollectionExtensions.cs @@ -8,8 +8,23 @@ namespace FinalEngine.Editor.ViewModels.Extensions; using FinalEngine.Editor.ViewModels.Interaction; using Microsoft.Extensions.DependencyInjection; +/// +/// Provides extension methods for an . +/// public static class ServiceCollectionExtensions { + /// + /// Adds a view model factory of type to the specified collection. + /// + /// + /// The type of the view model. + /// + /// + /// The services collection. + /// + /// + /// The specified parameter cannot be null. + /// public static void AddViewModelFactory(this IServiceCollection services) where TViewModel : class { diff --git a/FinalEngine.Rendering.OpenGL/Extensions/ServiceCollectionExtensions.cs b/FinalEngine.Rendering.OpenGL/Extensions/ServiceCollectionExtensions.cs deleted file mode 100644 index 25a34773..00000000 --- a/FinalEngine.Rendering.OpenGL/Extensions/ServiceCollectionExtensions.cs +++ /dev/null @@ -1,25 +0,0 @@ -// -// Copyright (c) Software Antics. All rights reserved. -// - -namespace FinalEngine.Rendering.OpenGL.Extensions; - -using System; -using FinalEngine.Rendering.OpenGL.Invocation; -using Microsoft.Extensions.DependencyInjection; - -public static class ServiceCollectionExtensions -{ - public static IServiceCollection AddRendering(this IServiceCollection services) - { - if (services == null) - { - throw new ArgumentNullException(nameof(services)); - } - - services.AddSingleton(); - services.AddSingleton(); - - return services; - } -} diff --git a/FinalEngine.Rendering.OpenGL/FinalEngine.Rendering.OpenGL.csproj b/FinalEngine.Rendering.OpenGL/FinalEngine.Rendering.OpenGL.csproj index c8ad1b9a..085eefbd 100644 --- a/FinalEngine.Rendering.OpenGL/FinalEngine.Rendering.OpenGL.csproj +++ b/FinalEngine.Rendering.OpenGL/FinalEngine.Rendering.OpenGL.csproj @@ -23,7 +23,6 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/SharedAssemblyInfo.cs b/SharedAssemblyInfo.cs index 658ab081..b2ec28b3 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.1.1176.1121")] -[assembly: AssemblyFileVersion("2023.1.1176.1121")] +[assembly: AssemblyVersion("2023.1.1180.1127")] +[assembly: AssemblyFileVersion("2023.1.1180.1127")] #if DEBUG [assembly: AssemblyConfiguration("Debug")] #else From 34dd888e10ec1c6892cccc8cbb2113628c9c56ba Mon Sep 17 00:00:00 2001 From: Mathew O'Dwyer Date: Sat, 25 Mar 2023 23:07:42 +1100 Subject: [PATCH 06/11] Good to go --- .../Interaction/AbstractFactory.cs | 20 +++++++++++++++++++ .../Interaction/IAbstractFactory.cs | 12 +++++++++++ .../MainViewModel.cs | 13 ++++++++++++ 3 files changed, 45 insertions(+) diff --git a/FinalEngine.Editor.ViewModels/Interaction/AbstractFactory.cs b/FinalEngine.Editor.ViewModels/Interaction/AbstractFactory.cs index 67dafc1d..5c33edd4 100644 --- a/FinalEngine.Editor.ViewModels/Interaction/AbstractFactory.cs +++ b/FinalEngine.Editor.ViewModels/Interaction/AbstractFactory.cs @@ -6,15 +6,35 @@ namespace FinalEngine.Editor.ViewModels.Interaction; using System; +/// +/// Provides a standard implementation of an . +/// +/// +/// The type of instance to create. +/// +/// public class AbstractFactory : IAbstractFactory { + /// + /// The function used to create the instance. + /// private readonly Func factory; + /// + /// Initializes a new instance of the class. + /// + /// + /// The function used to create the instance. + /// + /// + /// The specified parameter cannot be null. + /// public AbstractFactory(Func factory) { this.factory = factory ?? throw new ArgumentNullException(nameof(factory)); } + /// public T Create() { return this.factory(); diff --git a/FinalEngine.Editor.ViewModels/Interaction/IAbstractFactory.cs b/FinalEngine.Editor.ViewModels/Interaction/IAbstractFactory.cs index 61f7c868..b5f3ccb2 100644 --- a/FinalEngine.Editor.ViewModels/Interaction/IAbstractFactory.cs +++ b/FinalEngine.Editor.ViewModels/Interaction/IAbstractFactory.cs @@ -4,7 +4,19 @@ namespace FinalEngine.Editor.ViewModels.Interaction; +/// +/// Defines an interface that provides a method to create an instance of type . +/// +/// +/// The type of instance to create. +/// public interface IAbstractFactory { + /// + /// Creates an instance of type . + /// + /// + /// The newly created instance of type . + /// T Create(); } diff --git a/FinalEngine.Editor.ViewModels/MainViewModel.cs b/FinalEngine.Editor.ViewModels/MainViewModel.cs index cdd92c7a..b1fd602f 100644 --- a/FinalEngine.Editor.ViewModels/MainViewModel.cs +++ b/FinalEngine.Editor.ViewModels/MainViewModel.cs @@ -28,8 +28,14 @@ public partial class MainViewModel : ObservableObject, IMainViewModel /// private readonly ILogger logger; + /// + /// The exit command. + /// private ICommand? exitCommand; + /// + /// The application title. + /// private string? title; /// @@ -38,6 +44,9 @@ public partial class MainViewModel : ObservableObject, IMainViewModel /// /// The logger. /// + /// + /// The scene view model factory. + /// /// /// The specified parameter cannot be null. /// @@ -59,19 +68,23 @@ public MainViewModel(ILogger logger, IAbstractFactory public ICommand ExitCommand { get { return this.exitCommand ??= new RelayCommand(this.Exit); } } + /// public IEnumerable Panes { get; } + /// public string Title { get { return this.title ?? string.Empty; } private set { this.SetProperty(ref this.title, value); } } + /// public IEnumerable Tools { get; } /// From 8d2be6db34126874d72b0dff49dbb78a252a4ab3 Mon Sep 17 00:00:00 2001 From: Mathew O'Dwyer Date: Sat, 25 Mar 2023 23:43:16 +1100 Subject: [PATCH 07/11] Just gotta do unit tests now --- .../Extensions/ServiceCollectionExtensions.cs | 33 +++++++++++++ .../Services/Factories/Factory.cs | 14 +++--- .../Services/Factories/IFactory.cs | 6 +-- FinalEngine.Editor.Desktop/App.xaml.cs | 3 +- .../FinalEngine.Editor.Desktop.csproj | 1 - .../Extensions/ServiceCollectionExtensions.cs | 47 ------------------- .../MainViewModel.cs | 3 +- .../Editor/ViewModels/MainViewModelTests.cs | 20 +++++++- SharedAssemblyInfo.cs | 4 +- 9 files changed, 66 insertions(+), 65 deletions(-) rename FinalEngine.Editor.ViewModels/Interaction/AbstractFactory.cs => FinalEngine.Editor.Common/Services/Factories/Factory.cs (65%) rename FinalEngine.Editor.ViewModels/Interaction/IAbstractFactory.cs => FinalEngine.Editor.Common/Services/Factories/IFactory.cs (76%) delete mode 100644 FinalEngine.Editor.ViewModels/Extensions/ServiceCollectionExtensions.cs diff --git a/FinalEngine.Editor.Common/Extensions/ServiceCollectionExtensions.cs b/FinalEngine.Editor.Common/Extensions/ServiceCollectionExtensions.cs index d8dc6d3c..a760ec96 100644 --- a/FinalEngine.Editor.Common/Extensions/ServiceCollectionExtensions.cs +++ b/FinalEngine.Editor.Common/Extensions/ServiceCollectionExtensions.cs @@ -5,6 +5,7 @@ namespace FinalEngine.Editor.Common.Extensions; using System; +using FinalEngine.Editor.Common.Services.Factories; using FinalEngine.Editor.Common.Services.Rendering; using Microsoft.Extensions.DependencyInjection; @@ -36,4 +37,36 @@ public static IServiceCollection AddCommon(this IServiceCollection services) return services; } + + /// + /// Adds a factory that creates an instance of type to the specified collection. + /// + /// + /// The type of instance to create. + /// + /// + /// The services collection. + /// + /// + /// The specified parameter cannot be null. + /// + public static void AddFactory(this IServiceCollection services) + where TViewModel : class + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + services.AddTransient(); + services.AddSingleton>(x => + { + return () => + { + return x.GetRequiredService(); + }; + }); + + services.AddSingleton, Factory>(); + } } diff --git a/FinalEngine.Editor.ViewModels/Interaction/AbstractFactory.cs b/FinalEngine.Editor.Common/Services/Factories/Factory.cs similarity index 65% rename from FinalEngine.Editor.ViewModels/Interaction/AbstractFactory.cs rename to FinalEngine.Editor.Common/Services/Factories/Factory.cs index 5c33edd4..62496659 100644 --- a/FinalEngine.Editor.ViewModels/Interaction/AbstractFactory.cs +++ b/FinalEngine.Editor.Common/Services/Factories/Factory.cs @@ -1,19 +1,19 @@ -// +// // Copyright (c) Software Antics. All rights reserved. // -namespace FinalEngine.Editor.ViewModels.Interaction; +namespace FinalEngine.Editor.Common.Services.Factories; using System; /// -/// Provides a standard implementation of an . +/// Provides a standard implementation of an . /// /// /// The type of instance to create. /// -/// -public class AbstractFactory : IAbstractFactory +/// +public sealed class Factory : IFactory { /// /// The function used to create the instance. @@ -21,7 +21,7 @@ public class AbstractFactory : IAbstractFactory private readonly Func factory; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// /// The function used to create the instance. @@ -29,7 +29,7 @@ public class AbstractFactory : IAbstractFactory /// /// The specified parameter cannot be null. /// - public AbstractFactory(Func factory) + public Factory(Func factory) { this.factory = factory ?? throw new ArgumentNullException(nameof(factory)); } diff --git a/FinalEngine.Editor.ViewModels/Interaction/IAbstractFactory.cs b/FinalEngine.Editor.Common/Services/Factories/IFactory.cs similarity index 76% rename from FinalEngine.Editor.ViewModels/Interaction/IAbstractFactory.cs rename to FinalEngine.Editor.Common/Services/Factories/IFactory.cs index b5f3ccb2..d22f4f29 100644 --- a/FinalEngine.Editor.ViewModels/Interaction/IAbstractFactory.cs +++ b/FinalEngine.Editor.Common/Services/Factories/IFactory.cs @@ -1,8 +1,8 @@ -// +// // Copyright (c) Software Antics. All rights reserved. // -namespace FinalEngine.Editor.ViewModels.Interaction; +namespace FinalEngine.Editor.Common.Services.Factories; /// /// Defines an interface that provides a method to create an instance of type . @@ -10,7 +10,7 @@ namespace FinalEngine.Editor.ViewModels.Interaction; /// /// The type of instance to create. /// -public interface IAbstractFactory +public interface IFactory { /// /// Creates an instance of type . diff --git a/FinalEngine.Editor.Desktop/App.xaml.cs b/FinalEngine.Editor.Desktop/App.xaml.cs index 45f05bb8..7ea2be1c 100644 --- a/FinalEngine.Editor.Desktop/App.xaml.cs +++ b/FinalEngine.Editor.Desktop/App.xaml.cs @@ -11,7 +11,6 @@ namespace FinalEngine.Editor.Desktop; using FinalEngine.Editor.Desktop.Views; using FinalEngine.Editor.ViewModels; using FinalEngine.Editor.ViewModels.Docking.Panes; -using FinalEngine.Editor.ViewModels.Extensions; using FinalEngine.Rendering; using FinalEngine.Rendering.OpenGL; using FinalEngine.Rendering.OpenGL.Invocation; @@ -116,7 +115,7 @@ private static void ConfigureServices(HostBuilderContext context, IServiceCollec services.AddCommon(); - services.AddViewModelFactory(); + services.AddFactory(); services.AddSingleton(); } } diff --git a/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj b/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj index 6f498076..0b56b54e 100644 --- a/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj +++ b/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj @@ -38,7 +38,6 @@ - diff --git a/FinalEngine.Editor.ViewModels/Extensions/ServiceCollectionExtensions.cs b/FinalEngine.Editor.ViewModels/Extensions/ServiceCollectionExtensions.cs deleted file mode 100644 index 995fa656..00000000 --- a/FinalEngine.Editor.ViewModels/Extensions/ServiceCollectionExtensions.cs +++ /dev/null @@ -1,47 +0,0 @@ -// -// Copyright (c) Software Antics. All rights reserved. -// - -namespace FinalEngine.Editor.ViewModels.Extensions; - -using System; -using FinalEngine.Editor.ViewModels.Interaction; -using Microsoft.Extensions.DependencyInjection; - -/// -/// Provides extension methods for an . -/// -public static class ServiceCollectionExtensions -{ - /// - /// Adds a view model factory of type to the specified collection. - /// - /// - /// The type of the view model. - /// - /// - /// The services collection. - /// - /// - /// The specified parameter cannot be null. - /// - public static void AddViewModelFactory(this IServiceCollection services) - where TViewModel : class - { - if (services == null) - { - throw new ArgumentNullException(nameof(services)); - } - - services.AddTransient(); - services.AddSingleton>(x => - { - return () => - { - return x.GetRequiredService(); - }; - }); - - services.AddSingleton, AbstractFactory>(); - } -} diff --git a/FinalEngine.Editor.ViewModels/MainViewModel.cs b/FinalEngine.Editor.ViewModels/MainViewModel.cs index b1fd602f..dcef6445 100644 --- a/FinalEngine.Editor.ViewModels/MainViewModel.cs +++ b/FinalEngine.Editor.ViewModels/MainViewModel.cs @@ -10,6 +10,7 @@ namespace FinalEngine.Editor.ViewModels; using System.Windows.Input; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; +using FinalEngine.Editor.Common.Services.Factories; using FinalEngine.Editor.ViewModels.Docking.Panes; using FinalEngine.Editor.ViewModels.Docking.Tools; using FinalEngine.Editor.ViewModels.Interaction; @@ -50,7 +51,7 @@ public partial class MainViewModel : ObservableObject, IMainViewModel /// /// The specified parameter cannot be null. /// - public MainViewModel(ILogger logger, IAbstractFactory sceneViewModelFactory) + public MainViewModel(ILogger logger, IFactory sceneViewModelFactory) { if (sceneViewModelFactory == null) { diff --git a/FinalEngine.Tests/Editor/ViewModels/MainViewModelTests.cs b/FinalEngine.Tests/Editor/ViewModels/MainViewModelTests.cs index d0744435..907c0203 100644 --- a/FinalEngine.Tests/Editor/ViewModels/MainViewModelTests.cs +++ b/FinalEngine.Tests/Editor/ViewModels/MainViewModelTests.cs @@ -6,7 +6,9 @@ namespace FinalEngine.Tests.Editor.ViewModels; using System; using System.Reflection; +using FinalEngine.Editor.Common.Services.Factories; using FinalEngine.Editor.ViewModels; +using FinalEngine.Editor.ViewModels.Docking.Panes; using FinalEngine.Editor.ViewModels.Interaction; using FinalEngine.Utilities.Extensions; using Microsoft.Extensions.Logging; @@ -18,6 +20,8 @@ public sealed class MainViewModelTests { private Mock> logger; + private Mock> sceneViewModelFactory; + private MainViewModel viewModel; [Test] @@ -26,7 +30,17 @@ public void ConstructorShouldThrowArgumentNullExceptionWhenLoggerIsNull() // Act and assert Assert.Throws(() => { - new MainViewModel(null); + new MainViewModel(null, this.sceneViewModelFactory.Object); + }); + } + + [Test] + public void ConstructorShouldThrowArgumentNullExceptionWhenSceneViewModelFactoryIsNull() + { + // Act and assert + Assert.Throws(() => + { + new MainViewModel(this.logger.Object, null); }); } @@ -57,7 +71,9 @@ public void ExitCommandShouldThrowArgumentNullExceptionWhenCloseableIsNull() public void Setup() { this.logger = new Mock>(); - this.viewModel = new MainViewModel(this.logger.Object); + this.sceneViewModelFactory = new Mock>(); + + this.viewModel = new MainViewModel(this.logger.Object, this.sceneViewModelFactory.Object); } [Test] diff --git a/SharedAssemblyInfo.cs b/SharedAssemblyInfo.cs index b2ec28b3..40d18ee9 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.1.1180.1127")] -[assembly: AssemblyFileVersion("2023.1.1180.1127")] +[assembly: AssemblyVersion("2023.1.1244.1239")] +[assembly: AssemblyFileVersion("2023.1.1244.1239")] #if DEBUG [assembly: AssemblyConfiguration("Debug")] #else From 13d261c89eff920c5e3ca3cad4517204678b493e Mon Sep 17 00:00:00 2001 From: Mathew O'Dwyer Date: Sun, 26 Mar 2023 00:10:45 +1100 Subject: [PATCH 08/11] Added some unit tests --- .../Extensions/ServiceCollectionExtensions.cs | 2 + .../Common/Services/Factories/FactoryTests.cs | 57 +++++++++++++++++ .../Services/Rendering/SceneRendererTests.cs | 62 +++++++++++++++++++ SharedAssemblyInfo.cs | 4 +- 4 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 FinalEngine.Tests/Editor/Common/Services/Factories/FactoryTests.cs create mode 100644 FinalEngine.Tests/Editor/Common/Services/Rendering/SceneRendererTests.cs diff --git a/FinalEngine.Editor.Common/Extensions/ServiceCollectionExtensions.cs b/FinalEngine.Editor.Common/Extensions/ServiceCollectionExtensions.cs index a760ec96..0896a6c3 100644 --- a/FinalEngine.Editor.Common/Extensions/ServiceCollectionExtensions.cs +++ b/FinalEngine.Editor.Common/Extensions/ServiceCollectionExtensions.cs @@ -5,6 +5,7 @@ namespace FinalEngine.Editor.Common.Extensions; using System; +using System.Diagnostics.CodeAnalysis; using FinalEngine.Editor.Common.Services.Factories; using FinalEngine.Editor.Common.Services.Rendering; using Microsoft.Extensions.DependencyInjection; @@ -12,6 +13,7 @@ namespace FinalEngine.Editor.Common.Extensions; /// /// Provides extension methods for an . /// +[ExcludeFromCodeCoverage(Justification = "Extension Methods")] public static class ServiceCollectionExtensions { /// diff --git a/FinalEngine.Tests/Editor/Common/Services/Factories/FactoryTests.cs b/FinalEngine.Tests/Editor/Common/Services/Factories/FactoryTests.cs new file mode 100644 index 00000000..4fd9ec18 --- /dev/null +++ b/FinalEngine.Tests/Editor/Common/Services/Factories/FactoryTests.cs @@ -0,0 +1,57 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Tests.Editor.Common.Services.Factories; + +using System; +using FinalEngine.Editor.Common.Services.Factories; +using NUnit.Framework; + +[TestFixture] +public sealed class FactoryTests +{ + private Factory factory; + + [Test] + public void ConstructorShouldThrowArgumentNullExceptionWhenFactoryIsNull() + { + // Act and assert + Assert.Throws(() => + { + new Factory(null); + }); + } + + [Test] + public void CreateShouldReturnDifferentReferenceWhenInvoked() + { + // Arrange + var expected = this.factory.Create(); + + // Act + var actual = this.factory.Create(); + + // Assert + Assert.That(actual, Is.Not.SameAs(expected)); + } + + [Test] + public void CreateShouldReturnFactoryTestsWhenInvoked() + { + // Act + var actual = this.factory.Create(); + + // Assert + Assert.That(actual, Is.TypeOf()); + } + + [SetUp] + public void Setup() + { + this.factory = new Factory(() => + { + return new FactoryTests(); + }); + } +} 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..fe0c97f3 --- /dev/null +++ b/FinalEngine.Tests/Editor/Common/Services/Rendering/SceneRendererTests.cs @@ -0,0 +1,62 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Tests.Editor.Common.Services.Rendering; + +using System; +using System.Drawing; +using FinalEngine.Editor.Common.Services.Rendering; +using FinalEngine.Rendering; +using Microsoft.Extensions.Logging; +using Moq; +using NUnit.Framework; + +[TestFixture] +public sealed class SceneRendererTests +{ + private Mock> logger; + + private Mock renderDevice; + + private SceneRenderer sceneRenderer; + + [Test] + public void ConstructorShouldThrowArgumentNullExceptionWhenLoggerIsNull() + { + // Act and assert + Assert.Throws(() => + { + new SceneRenderer(null, this.renderDevice.Object); + }); + } + + [Test] + public void ConstructorShouldThrowArgumentNullExceptionWhenRenderDeviceIsNull() + { + // Act and assert + Assert.Throws(() => + { + new SceneRenderer(this.logger.Object, null); + }); + } + + [Test] + public void RenderShouldInvokeClearWhenInvoked() + { + // Act + this.sceneRenderer.Render(); + + // Assert + this.renderDevice.Verify(x => x.Clear(It.IsAny(), 1, 0), Times.Once); + } + + [SetUp] + public void Setup() + { + this.logger = new Mock>(); + this.renderDevice = new Mock(); + + this.sceneRenderer = new SceneRenderer(this.logger.Object, this.renderDevice.Object); + } +} diff --git a/SharedAssemblyInfo.cs b/SharedAssemblyInfo.cs index 40d18ee9..c4d46ff7 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.1.1244.1239")] -[assembly: AssemblyFileVersion("2023.1.1244.1239")] +[assembly: AssemblyVersion("2023.1.1253.1306")] +[assembly: AssemblyFileVersion("2023.1.1253.1306")] #if DEBUG [assembly: AssemblyConfiguration("Debug")] #else From e155bc3013233e8b94d138341b918f5cd3ca8311 Mon Sep 17 00:00:00 2001 From: Mathew O'Dwyer Date: Sun, 26 Mar 2023 03:59:14 +1100 Subject: [PATCH 09/11] added more tests --- .../MainViewModel.cs | 2 +- .../Services/Rendering/SceneRendererTests.cs | 49 +++++++++++++++++++ SharedAssemblyInfo.cs | 4 +- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/FinalEngine.Editor.ViewModels/MainViewModel.cs b/FinalEngine.Editor.ViewModels/MainViewModel.cs index dcef6445..574eea50 100644 --- a/FinalEngine.Editor.ViewModels/MainViewModel.cs +++ b/FinalEngine.Editor.ViewModels/MainViewModel.cs @@ -81,7 +81,7 @@ public ICommand ExitCommand /// public string Title { - get { return this.title ?? string.Empty; } + get { return this.title!; } private set { this.SetProperty(ref this.title, value); } } diff --git a/FinalEngine.Tests/Editor/Common/Services/Rendering/SceneRendererTests.cs b/FinalEngine.Tests/Editor/Common/Services/Rendering/SceneRendererTests.cs index fe0c97f3..f73158ba 100644 --- a/FinalEngine.Tests/Editor/Common/Services/Rendering/SceneRendererTests.cs +++ b/FinalEngine.Tests/Editor/Common/Services/Rendering/SceneRendererTests.cs @@ -6,6 +6,8 @@ namespace FinalEngine.Tests.Editor.Common.Services.Rendering; using System; using System.Drawing; +using System.Linq.Expressions; +using System.Numerics; using FinalEngine.Editor.Common.Services.Rendering; using FinalEngine.Rendering; using Microsoft.Extensions.Logging; @@ -17,10 +19,52 @@ public sealed class SceneRendererTests { private Mock> logger; + private Mock pipeline; + + private Mock rasterizer; + private Mock renderDevice; private SceneRenderer sceneRenderer; + [Test] + public void ChangeProjectionShouldSetUniformProjectionWhenInvoked() + { + // Arrange + const int width = 1280; + const int height = 720; + + var projection = Matrix4x4.CreateOrthographicOffCenter(0, width, 0, height, -1, 1); + + Expression> match = (mat) => mat.Equals(projection); + + // Act + this.sceneRenderer.ChangeProjection(width, height); + + // Assert + this.pipeline.Verify(x => x.SetUniform("u_projection", It.Is(match)), Times.Once); + } + + [Test] + public void ChangeProjectionShouldSetViewportWhenInvoked() + { + // Arrange + const int width = 1280; + const int height = 720; + + Expression> match = (rect) => + rect.X == 0 && + rect.Y == 0 && + rect.Width == width + && rect.Height == height; + + // Act + this.sceneRenderer.ChangeProjection(width, height); + + // Assert + this.rasterizer.Verify(x => x.SetViewport(It.Is(match), 0, 1), Times.Once); + } + [Test] public void ConstructorShouldThrowArgumentNullExceptionWhenLoggerIsNull() { @@ -56,6 +100,11 @@ public void Setup() { this.logger = new Mock>(); this.renderDevice = new Mock(); + this.pipeline = new Mock(); + this.rasterizer = new Mock(); + + this.renderDevice.SetupGet(x => x.Pipeline).Returns(this.pipeline.Object); + this.renderDevice.SetupGet(x => x.Rasterizer).Returns(this.rasterizer.Object); this.sceneRenderer = new SceneRenderer(this.logger.Object, this.renderDevice.Object); } diff --git a/SharedAssemblyInfo.cs b/SharedAssemblyInfo.cs index c4d46ff7..6fa8a2d4 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.1.1253.1306")] -[assembly: AssemblyFileVersion("2023.1.1253.1306")] +[assembly: AssemblyVersion("2023.1.1280.1652")] +[assembly: AssemblyFileVersion("2023.1.1280.1652")] #if DEBUG [assembly: AssemblyConfiguration("Debug")] #else From 1303ae79609c9b2ea0e66cfc039d9fb983728560 Mon Sep 17 00:00:00 2001 From: Mathew O'Dwyer Date: Sun, 26 Mar 2023 21:44:00 +1100 Subject: [PATCH 10/11] Finished up unit tests --- .../Docking/Panes/IPaneViewModel.cs | 2 +- .../Docking/Panes/PaneViewModelBase.cs | 2 +- .../Docking/Panes/SceneViewModel.cs | 2 +- .../Docking/Panes/PaneViewModelBaseTests.cs | 117 ++++++++++++++++++ .../Docking/Panes/SceneViewModelTests.cs | 96 ++++++++++++++ .../Docking/Tools/ToolViewModelBaseTests.cs | 51 ++++++++ .../Editor/ViewModels/MainViewModelTests.cs | 47 ++++++- SharedAssemblyInfo.cs | 4 +- 8 files changed, 315 insertions(+), 6 deletions(-) create mode 100644 FinalEngine.Tests/Editor/ViewModels/Docking/Panes/PaneViewModelBaseTests.cs create mode 100644 FinalEngine.Tests/Editor/ViewModels/Docking/Panes/SceneViewModelTests.cs create mode 100644 FinalEngine.Tests/Editor/ViewModels/Docking/Tools/ToolViewModelBaseTests.cs diff --git a/FinalEngine.Editor.ViewModels/Docking/Panes/IPaneViewModel.cs b/FinalEngine.Editor.ViewModels/Docking/Panes/IPaneViewModel.cs index 797d7a1e..79d8e431 100644 --- a/FinalEngine.Editor.ViewModels/Docking/Panes/IPaneViewModel.cs +++ b/FinalEngine.Editor.ViewModels/Docking/Panes/IPaneViewModel.cs @@ -18,7 +18,7 @@ public interface IPaneViewModel /// /// The content identifier. /// - string? ContentID { get; set; } + string ContentID { get; set; } /// /// Gets or sets a value indicating whether this instance is active. diff --git a/FinalEngine.Editor.ViewModels/Docking/Panes/PaneViewModelBase.cs b/FinalEngine.Editor.ViewModels/Docking/Panes/PaneViewModelBase.cs index 30115b6b..100e4fc5 100644 --- a/FinalEngine.Editor.ViewModels/Docking/Panes/PaneViewModelBase.cs +++ b/FinalEngine.Editor.ViewModels/Docking/Panes/PaneViewModelBase.cs @@ -39,7 +39,7 @@ public partial class PaneViewModelBase : ObservableObject, IPaneViewModel /// /// The content identifier. /// - public string? ContentID + public string ContentID { get { return this.contentID ?? string.Empty; } set { this.SetProperty(ref this.contentID, value); } diff --git a/FinalEngine.Editor.ViewModels/Docking/Panes/SceneViewModel.cs b/FinalEngine.Editor.ViewModels/Docking/Panes/SceneViewModel.cs index 044c9aee..d6aa18cc 100644 --- a/FinalEngine.Editor.ViewModels/Docking/Panes/SceneViewModel.cs +++ b/FinalEngine.Editor.ViewModels/Docking/Panes/SceneViewModel.cs @@ -61,7 +61,7 @@ public Size ProjectionSize return this.projectionSize; } - private set + set { //// TODO: Hook this up to GLWpfControl.RenderSize, waiting on: https://github.com/opentk/GLWpfControl/issues/108. this.SetProperty(ref this.projectionSize, value); diff --git a/FinalEngine.Tests/Editor/ViewModels/Docking/Panes/PaneViewModelBaseTests.cs b/FinalEngine.Tests/Editor/ViewModels/Docking/Panes/PaneViewModelBaseTests.cs new file mode 100644 index 00000000..4a37e35e --- /dev/null +++ b/FinalEngine.Tests/Editor/ViewModels/Docking/Panes/PaneViewModelBaseTests.cs @@ -0,0 +1,117 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Tests.Editor.ViewModels.Docking.Panes; + +using FinalEngine.Editor.ViewModels.Docking.Panes; +using Moq; +using NUnit.Framework; + +[TestFixture] +public sealed class PaneViewModelBaseTests +{ + private Mock viewModel; + + [Test] + public void ConstructorShouldNotThrowExceptionWhenInvoked() + { + // Act and assert + Assert.DoesNotThrow(() => + { + this.viewModel = new Mock(); + }); + } + + [Test] + public void ContentIDShouldReturnEmptyWhenNotSet() + { + // Act + string actual = this.viewModel.Object.ContentID; + + // Assert + Assert.That(actual, Is.Empty); + } + + [Test] + public void ContentIDShouldReturnHelloWorldWhenSet() + { + // Arrange + string expected = "Hello, World!"; + + // Act + this.viewModel.Object.ContentID = expected; + + // Assert + Assert.That(this.viewModel.Object.ContentID, Is.EqualTo(expected)); + } + + [Test] + public void IsActiveShouldReturnFalseWhenNotSet() + { + // Act + bool actual = this.viewModel.Object.IsActive; + + // Assert + Assert.That(actual, Is.False); + } + + [Test] + public void IsActiveShouldReturnTrueWhenSetToTrue() + { + // Act + this.viewModel.Object.IsActive = true; + + // Assert + Assert.That(this.viewModel.Object.IsActive, Is.True); + } + + [Test] + public void IsSelectedeShouldReturnTrueWhenSetToTrue() + { + // Act + this.viewModel.Object.IsSelected = true; + + // Assert + Assert.That(this.viewModel.Object.IsSelected, Is.True); + } + + [Test] + public void IsSelectedShouldReturnFalseWhenNotSet() + { + // Act + bool actual = this.viewModel.Object.IsSelected; + + // Assert + Assert.That(actual, Is.False); + } + + [SetUp] + public void Setup() + { + this.viewModel = new Mock(); + } + + [Test] + public void TitleShouldReturnEmptyWhenNotSet() + { + // Act + string actual = this.viewModel.Object.Title; + + // Assert + Assert.That(actual, Is.Empty); + } + + [Test] + public void TitleShouldReturnHelloWorldWhenSet() + { + // Arrange + string expected = "Hello, World!"; + + // Act + this.viewModel.Object.Title = expected; + + // Assert + Assert.That(this.viewModel.Object.Title, Is.EqualTo(expected)); + } +} diff --git a/FinalEngine.Tests/Editor/ViewModels/Docking/Panes/SceneViewModelTests.cs b/FinalEngine.Tests/Editor/ViewModels/Docking/Panes/SceneViewModelTests.cs new file mode 100644 index 00000000..37cee96f --- /dev/null +++ b/FinalEngine.Tests/Editor/ViewModels/Docking/Panes/SceneViewModelTests.cs @@ -0,0 +1,96 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Tests.Editor.ViewModels.Docking.Panes; + +using System; +using System.Drawing; +using FinalEngine.Editor.Common.Services.Rendering; +using FinalEngine.Editor.ViewModels.Docking.Panes; +using Moq; +using NUnit.Framework; + +[TestFixture] +public sealed class SceneViewModelTests +{ + private Mock sceneRenderer; + + private SceneViewModel viewModel; + + [Test] + public void ConstructorShouldThrowArgumentNullExceptionWhenSceneRendererIsNull() + { + // Act and assert + Assert.Throws(() => + { + new SceneViewModel(null); + }); + } + + [Test] + public void ProjectionSizeShouldInvokeSceneRendererChangeProjectionWhenSet() + { + // Arrange + var projection = new Size(1280, 720); + + // Act + this.viewModel.ProjectionSize = projection; + + // Assert + this.sceneRenderer.Verify(x => x.ChangeProjection(1280, 720), Times.Once()); + } + + [Test] + public void ProjectionSizeShouldReturnHighDefinitionWhenSetToHighDefinition() + { + // Arrange + var expected = new Size(1280, 720); + + // Act + this.viewModel.ProjectionSize = expected; + + // Assert + Assert.That(this.viewModel.ProjectionSize, Is.EqualTo(expected)); + } + + [Test] + public void ProjectionSizeShouldReturnZeroWhenNotSet() + { + // Act + var actual = this.viewModel.ProjectionSize; + + // Assert + Assert.That(actual, Is.EqualTo(Size.Empty)); + } + + [Test] + public void RenderCommandShouldInvokeSceneRendererRenderWhenInvoked() + { + // Act + this.viewModel.RenderCommand.Execute(null); + + // Assert + this.sceneRenderer.Verify(x => x.Render(), Times.Once()); + } + + [SetUp] + public void Setup() + { + this.sceneRenderer = new Mock(); + this.viewModel = new SceneViewModel(this.sceneRenderer.Object); + } + + [Test] + public void TitleShouldReturnSceneViewWhenSet() + { + // Arrange + string expected = "Scene View"; + + // Act + string actual = this.viewModel.Title; + + // Assert + Assert.That(actual, Is.EqualTo(expected)); + } +} diff --git a/FinalEngine.Tests/Editor/ViewModels/Docking/Tools/ToolViewModelBaseTests.cs b/FinalEngine.Tests/Editor/ViewModels/Docking/Tools/ToolViewModelBaseTests.cs new file mode 100644 index 00000000..187f86aa --- /dev/null +++ b/FinalEngine.Tests/Editor/ViewModels/Docking/Tools/ToolViewModelBaseTests.cs @@ -0,0 +1,51 @@ +// +// Copyright (c) Software Antics. All rights reserved. +// + +namespace FinalEngine.Tests.Editor.ViewModels.Docking.Tools; + +using FinalEngine.Editor.ViewModels.Docking.Tools; +using Moq; +using NUnit.Framework; + +[TestFixture] +public sealed class ToolViewModelBaseTests +{ + private Mock viewModel; + + [Test] + public void ConstructorShouldNotThrowExceptionWhenInvoked() + { + // Act and assert + Assert.DoesNotThrow(() => + { + new Mock(); + }); + } + + [Test] + public void IsVisibleShouldReturnFalseWhenSetToFalse() + { + // Act + this.viewModel.Object.IsVisible = false; + + // Assert + Assert.That(this.viewModel.Object.IsVisible, Is.False); + } + + [Test] + public void IsVisibleShouldReturnTrueWhenNotSet() + { + // Act + bool actual = this.viewModel.Object.IsVisible; + + // Assert + Assert.That(actual, Is.True); + } + + [SetUp] + public void Setup() + { + this.viewModel = new Mock(); + } +} diff --git a/FinalEngine.Tests/Editor/ViewModels/MainViewModelTests.cs b/FinalEngine.Tests/Editor/ViewModels/MainViewModelTests.cs index 907c0203..13293023 100644 --- a/FinalEngine.Tests/Editor/ViewModels/MainViewModelTests.cs +++ b/FinalEngine.Tests/Editor/ViewModels/MainViewModelTests.cs @@ -5,8 +5,10 @@ namespace FinalEngine.Tests.Editor.ViewModels; using System; +using System.Linq; using System.Reflection; using FinalEngine.Editor.Common.Services.Factories; +using FinalEngine.Editor.Common.Services.Rendering; using FinalEngine.Editor.ViewModels; using FinalEngine.Editor.ViewModels.Docking.Panes; using FinalEngine.Editor.ViewModels.Interaction; @@ -20,10 +22,19 @@ public sealed class MainViewModelTests { private Mock> logger; + private Mock sceneRenderer; + private Mock> sceneViewModelFactory; private MainViewModel viewModel; + [Test] + public void ConstructorShouldInvokeSceneViewModelFactoryCreateWhenInvoked() + { + // Assert + this.sceneViewModelFactory.Verify(x => x.Create(), Times.Once()); + } + [Test] public void ConstructorShouldThrowArgumentNullExceptionWhenLoggerIsNull() { @@ -67,12 +78,36 @@ public void ExitCommandShouldThrowArgumentNullExceptionWhenCloseableIsNull() }); } + [Test] + public void PanesShouldContainSceneViewModelWhenCreated() + { + // Act + var actual = this.viewModel.Panes.FirstOrDefault(x => + { + return x.GetType() == typeof(SceneViewModel); + }); + + // Assert + Assert.That(actual, Is.Not.Null); + } + + [Test] + public void PanesShouldNotBeNullWhenCreated() + { + // Act + var actual = this.viewModel.Panes; + + // Assert + Assert.That(actual, Is.Not.Null); + } + [SetUp] public void Setup() { this.logger = new Mock>(); this.sceneViewModelFactory = new Mock>(); - + this.sceneRenderer = new Mock(); + this.sceneViewModelFactory.Setup(x => x.Create()).Returns(new SceneViewModel(this.sceneRenderer.Object)); this.viewModel = new MainViewModel(this.logger.Object, this.sceneViewModelFactory.Object); } @@ -88,4 +123,14 @@ public void TitleShouldReturnCorrectTitleOnStartup() // Assert Assert.That(actual, Is.EqualTo(expected)); } + + [Test] + public void ToolsShouldNotBeNullWhenCreated() + { + // Act + var actual = this.viewModel.Tools; + + // Assert + Assert.That(actual, Is.Not.Null); + } } diff --git a/SharedAssemblyInfo.cs b/SharedAssemblyInfo.cs index 6fa8a2d4..e2404449 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.1.1280.1652")] -[assembly: AssemblyFileVersion("2023.1.1280.1652")] +[assembly: AssemblyVersion("2023.1.1333.1039")] +[assembly: AssemblyFileVersion("2023.1.1333.1039")] #if DEBUG [assembly: AssemblyConfiguration("Debug")] #else From a378d688bf4da22cf609607fa535247c4beb442f Mon Sep 17 00:00:00 2001 From: Mathew O'Dwyer Date: Sun, 26 Mar 2023 22:00:01 +1100 Subject: [PATCH 11/11] Remove TODOs and created issues --- .../Views/Docking/Panes/SceneView.xaml.cs | 2 -- FinalEngine.Editor.ViewModels/Docking/Panes/SceneViewModel.cs | 3 +-- SharedAssemblyInfo.cs | 4 ++-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml.cs index 05590011..7b6c3e58 100644 --- a/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml.cs +++ b/FinalEngine.Editor.Desktop/Views/Docking/Panes/SceneView.xaml.cs @@ -20,7 +20,6 @@ public SceneView() { this.InitializeComponent(); - //// TODO: Use XAML and implement this in view model, waiting on: https://github.com/opentk/GLWpfControl/pull/106. this.Start(new GLWpfControlSettings() { MajorVersion = 4, @@ -41,7 +40,6 @@ public SceneView() /// private void SceneView_Render(System.TimeSpan obj) { - //// TODO: Create issue for this. GL.Finish(); } } diff --git a/FinalEngine.Editor.ViewModels/Docking/Panes/SceneViewModel.cs b/FinalEngine.Editor.ViewModels/Docking/Panes/SceneViewModel.cs index d6aa18cc..6c5aafae 100644 --- a/FinalEngine.Editor.ViewModels/Docking/Panes/SceneViewModel.cs +++ b/FinalEngine.Editor.ViewModels/Docking/Panes/SceneViewModel.cs @@ -49,7 +49,7 @@ public SceneViewModel(ISceneRenderer sceneRenderer) } /// - /// Gets the size of the projection. + /// Gets or sets the size of the projection. /// /// /// The size of the projection. @@ -63,7 +63,6 @@ public Size ProjectionSize set { - //// TODO: Hook this up to GLWpfControl.RenderSize, waiting on: https://github.com/opentk/GLWpfControl/issues/108. this.SetProperty(ref this.projectionSize, value); this.sceneRenderer.ChangeProjection(this.projectionSize.Width, this.projectionSize.Height); } diff --git a/SharedAssemblyInfo.cs b/SharedAssemblyInfo.cs index e2404449..3ae3960b 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.1.1333.1039")] -[assembly: AssemblyFileVersion("2023.1.1333.1039")] +[assembly: AssemblyVersion("2023.1.1337.1042")] +[assembly: AssemblyFileVersion("2023.1.1337.1042")] #if DEBUG [assembly: AssemblyConfiguration("Debug")] #else