diff --git a/FinalEngine.ECS/Components/Core/TagComponent.cs b/FinalEngine.ECS/Components/Core/TagComponent.cs
index 49a8104d..db84af1f 100644
--- a/FinalEngine.ECS/Components/Core/TagComponent.cs
+++ b/FinalEngine.ECS/Components/Core/TagComponent.cs
@@ -9,26 +9,26 @@ namespace FinalEngine.ECS.Components.Core;
[Category("Core")]
public sealed class TagComponent : IEntityComponent, INotifyPropertyChanged
{
- private string? tag;
+ private string? name;
public event PropertyChangedEventHandler? PropertyChanged;
- public string? Tag
+ public string? Name
{
get
{
- return this.tag;
+ return this.name;
}
set
{
- if (this.tag == value)
+ if (this.name == value)
{
return;
}
- this.tag = value;
- this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Tag)));
+ this.name = value;
+ this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Name)));
}
}
}
diff --git a/FinalEngine.ECS/FinalEngine.ECS.csproj b/FinalEngine.ECS/FinalEngine.ECS.csproj
index e9c3a119..3ff4cad7 100644
--- a/FinalEngine.ECS/FinalEngine.ECS.csproj
+++ b/FinalEngine.ECS/FinalEngine.ECS.csproj
@@ -29,8 +29,4 @@
-
-
-
-
diff --git a/FinalEngine.Editor.Common/Extensions/ServiceCollectionExtensions.cs b/FinalEngine.Editor.Common/Extensions/ServiceCollectionExtensions.cs
new file mode 100644
index 00000000..e2063cc8
--- /dev/null
+++ b/FinalEngine.Editor.Common/Extensions/ServiceCollectionExtensions.cs
@@ -0,0 +1,32 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Common.Extensions;
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using FinalEngine.Editor.Common.Services.Factories;
+using Microsoft.Extensions.DependencyInjection;
+
+[ExcludeFromCodeCoverage(Justification = "Extensions")]
+public static class ServiceCollectionExtensions
+{
+ public static void AddFactory(this IServiceCollection services)
+ where TService : class
+ where TImplementation : class, TService
+ {
+ ArgumentNullException.ThrowIfNull(services, nameof(services));
+
+ services.AddTransient();
+ services.AddSingleton>(x =>
+ {
+ return () =>
+ {
+ return x.GetRequiredService();
+ };
+ });
+
+ services.AddSingleton, Factory>();
+ }
+}
diff --git a/FinalEngine.Editor.Common/FinalEngine.Editor.Common.csproj b/FinalEngine.Editor.Common/FinalEngine.Editor.Common.csproj
new file mode 100644
index 00000000..caad47c4
--- /dev/null
+++ b/FinalEngine.Editor.Common/FinalEngine.Editor.Common.csproj
@@ -0,0 +1,40 @@
+
+
+
+ net8.0
+ enable
+ All
+ SA0001
+ false
+ x64
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
diff --git a/FinalEngine.Editor.Common/Models/Scenes/IScene.cs b/FinalEngine.Editor.Common/Models/Scenes/IScene.cs
new file mode 100644
index 00000000..cc98c682
--- /dev/null
+++ b/FinalEngine.Editor.Common/Models/Scenes/IScene.cs
@@ -0,0 +1,20 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Common.Models.Scenes;
+
+using System;
+using System.Collections.Generic;
+using FinalEngine.ECS;
+
+public interface IScene
+{
+ IReadOnlyCollection Entities { get; }
+
+ void AddEntity(string tag, Guid uniqueID);
+
+ void RemoveEntity(Guid uniqueIdentifier);
+
+ void Render();
+}
diff --git a/FinalEngine.Editor.Common/Models/Scenes/Scene.cs b/FinalEngine.Editor.Common/Models/Scenes/Scene.cs
new file mode 100644
index 00000000..0d589830
--- /dev/null
+++ b/FinalEngine.Editor.Common/Models/Scenes/Scene.cs
@@ -0,0 +1,83 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Common.Models.Scenes;
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using FinalEngine.ECS;
+using FinalEngine.ECS.Components.Core;
+using FinalEngine.ECS.Exceptions;
+using FinalEngine.Rendering.Components.Core;
+using Microsoft.Extensions.Logging;
+
+public sealed class Scene : IScene
+{
+ private readonly ObservableCollection entities;
+
+ private readonly ILogger logger;
+
+ private readonly IEntityWorld world;
+
+ public Scene(ILogger logger, IEntityWorld world)
+ {
+ this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ this.world = world ?? throw new ArgumentNullException(nameof(world));
+ this.entities = [];
+ }
+
+ public IReadOnlyCollection Entities
+ {
+ get { return this.entities; }
+ }
+
+ public void AddEntity(string tag, Guid uniqueID)
+ {
+ this.logger.LogInformation($"Adding new {nameof(Entity)} to {nameof(Scene)} with ID: '{uniqueID}'.");
+
+ ArgumentException.ThrowIfNullOrWhiteSpace(tag, nameof(tag));
+
+ var entity = new Entity(uniqueID);
+
+ entity.AddComponent(new TagComponent()
+ {
+ Name = tag,
+ });
+
+ entity.AddComponent(new TransformComponent());
+
+ this.world.AddEntity(entity);
+ this.entities.Add(entity);
+
+ this.logger.LogInformation($"Added {nameof(Entity)} to {nameof(Scene)} with ID: '{uniqueID}'.");
+ }
+
+ public void RemoveEntity(Guid uniqueIdentifier)
+ {
+ this.logger.LogInformation($"Removing {nameof(Entity)} from {nameof(Scene)} with ID: '{uniqueIdentifier}'.");
+
+ var entity = this.entities.FirstOrDefault(x =>
+ {
+ return x.UniqueIdentifier == uniqueIdentifier;
+ });
+
+ if (entity == null)
+ {
+ this.logger.LogError($"Failed to locate entity with ID: '{uniqueIdentifier}'.");
+ throw new EntityNotFoundException(uniqueIdentifier);
+ }
+
+ this.world.RemoveEntity(entity);
+ this.entities.Remove(entity);
+
+ this.logger.LogInformation($"Removed {nameof(Entity)} from {nameof(Scene)} with ID: '{uniqueIdentifier}'.");
+ }
+
+ public void Render()
+ {
+ this.world.ProcessAll(GameLoopType.Render);
+ }
+}
diff --git a/FinalEngine.Editor.Common/Properties/AssemblyInfo.cs b/FinalEngine.Editor.Common/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..18cf0906
--- /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 library containing services to connect view models to view for the Final Engine editor.")]
+[assembly: Guid("3D606010-8CAF-4781-98D1-EB67BCDD8CC1")]
diff --git a/FinalEngine.Editor.Common/Services/Application/ApplicationContext.cs b/FinalEngine.Editor.Common/Services/Application/ApplicationContext.cs
new file mode 100644
index 00000000..6f8b633f
--- /dev/null
+++ b/FinalEngine.Editor.Common/Services/Application/ApplicationContext.cs
@@ -0,0 +1,48 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Common.Services.Application;
+
+using System;
+using System.IO.Abstractions;
+using System.Reflection;
+using FinalEngine.Editor.Common.Services.Environment;
+
+public sealed class ApplicationContext : IApplicationContext
+{
+ private readonly IEnvironmentContext environment;
+
+ private readonly IFileSystem fileSystem;
+
+ public ApplicationContext(IFileSystem fileSystem, IEnvironmentContext environment)
+ {
+ this.fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem));
+ this.environment = environment ?? throw new ArgumentNullException(nameof(environment));
+ }
+
+ public string DataDirectory
+ {
+ get
+ {
+ string directory = this.fileSystem.Path.Combine(this.environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Final Engine");
+
+ if (!this.fileSystem.Directory.Exists(directory))
+ {
+ this.fileSystem.Directory.CreateDirectory(directory);
+ }
+
+ return directory;
+ }
+ }
+
+ public string Title
+ {
+ get { return $"Final Engine - {this.Version}"; }
+ }
+
+ public Version Version
+ {
+ get { return Assembly.GetExecutingAssembly().GetName().Version!; }
+ }
+}
diff --git a/FinalEngine.Editor.Common/Services/Application/IApplicationContext.cs b/FinalEngine.Editor.Common/Services/Application/IApplicationContext.cs
new file mode 100644
index 00000000..70af45ec
--- /dev/null
+++ b/FinalEngine.Editor.Common/Services/Application/IApplicationContext.cs
@@ -0,0 +1,16 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Common.Services.Application;
+
+using System;
+
+public interface IApplicationContext
+{
+ string DataDirectory { get; }
+
+ string Title { get; }
+
+ Version Version { get; }
+}
diff --git a/FinalEngine.Editor.Common/Services/Environment/EnvironmentContext.cs b/FinalEngine.Editor.Common/Services/Environment/EnvironmentContext.cs
new file mode 100644
index 00000000..3a059819
--- /dev/null
+++ b/FinalEngine.Editor.Common/Services/Environment/EnvironmentContext.cs
@@ -0,0 +1,17 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Common.Services.Environment;
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+
+[ExcludeFromCodeCoverage(Justification = "Invocation")]
+public sealed class EnvironmentContext : IEnvironmentContext
+{
+ public string GetFolderPath(Environment.SpecialFolder folder)
+ {
+ return Environment.GetFolderPath(folder);
+ }
+}
diff --git a/FinalEngine.Editor.Common/Services/Environment/IEnvironmentContext.cs b/FinalEngine.Editor.Common/Services/Environment/IEnvironmentContext.cs
new file mode 100644
index 00000000..2cb9822d
--- /dev/null
+++ b/FinalEngine.Editor.Common/Services/Environment/IEnvironmentContext.cs
@@ -0,0 +1,12 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Common.Services.Environment;
+
+using System;
+
+public interface IEnvironmentContext
+{
+ string GetFolderPath(Environment.SpecialFolder folder);
+}
diff --git a/FinalEngine.Editor.Common/Services/Factories/Factory.cs b/FinalEngine.Editor.Common/Services/Factories/Factory.cs
new file mode 100644
index 00000000..03eb6138
--- /dev/null
+++ b/FinalEngine.Editor.Common/Services/Factories/Factory.cs
@@ -0,0 +1,22 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Common.Services.Factories;
+
+using System;
+
+public sealed class Factory : IFactory
+{
+ private readonly Func factory;
+
+ public Factory(Func factory)
+ {
+ this.factory = factory ?? throw new ArgumentNullException(nameof(factory));
+ }
+
+ public T Create()
+ {
+ return this.factory();
+ }
+}
diff --git a/FinalEngine.Editor.Common/Services/Factories/IFactory.cs b/FinalEngine.Editor.Common/Services/Factories/IFactory.cs
new file mode 100644
index 00000000..0905d49b
--- /dev/null
+++ b/FinalEngine.Editor.Common/Services/Factories/IFactory.cs
@@ -0,0 +1,10 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Common.Services.Factories;
+
+public interface IFactory
+{
+ T Create();
+}
diff --git a/FinalEngine.Editor.Common/Services/Scenes/ISceneManager.cs b/FinalEngine.Editor.Common/Services/Scenes/ISceneManager.cs
new file mode 100644
index 00000000..2df06403
--- /dev/null
+++ b/FinalEngine.Editor.Common/Services/Scenes/ISceneManager.cs
@@ -0,0 +1,12 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Common.Services.Scenes;
+
+using FinalEngine.Editor.Common.Models.Scenes;
+
+public interface ISceneManager
+{
+ IScene ActiveScene { get; }
+}
diff --git a/FinalEngine.Editor.Common/Services/Scenes/ISceneRenderer.cs b/FinalEngine.Editor.Common/Services/Scenes/ISceneRenderer.cs
new file mode 100644
index 00000000..23dd2071
--- /dev/null
+++ b/FinalEngine.Editor.Common/Services/Scenes/ISceneRenderer.cs
@@ -0,0 +1,10 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Common.Services.Scenes;
+
+public interface ISceneRenderer
+{
+ void Render();
+}
diff --git a/FinalEngine.Editor.Common/Services/Scenes/SceneManager.cs b/FinalEngine.Editor.Common/Services/Scenes/SceneManager.cs
new file mode 100644
index 00000000..9dec3152
--- /dev/null
+++ b/FinalEngine.Editor.Common/Services/Scenes/SceneManager.cs
@@ -0,0 +1,18 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Common.Services.Scenes;
+
+using System;
+using FinalEngine.Editor.Common.Models.Scenes;
+
+public sealed class SceneManager : ISceneManager
+{
+ public SceneManager(IScene scene)
+ {
+ this.ActiveScene = scene ?? throw new ArgumentNullException(nameof(scene));
+ }
+
+ public IScene ActiveScene { get; }
+}
diff --git a/FinalEngine.Editor.Common/Services/Scenes/SceneRenderer.cs b/FinalEngine.Editor.Common/Services/Scenes/SceneRenderer.cs
new file mode 100644
index 00000000..fac58e40
--- /dev/null
+++ b/FinalEngine.Editor.Common/Services/Scenes/SceneRenderer.cs
@@ -0,0 +1,47 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Common.Services.Scenes;
+
+using System;
+using System.Drawing;
+using FinalEngine.Rendering;
+
+public sealed class SceneRenderer : ISceneRenderer
+{
+ private readonly IRenderDevice renderDevice;
+
+ private readonly IRenderPipeline renderPipeline;
+
+ private readonly ISceneManager sceneManager;
+
+ private bool isInitialized;
+
+ public SceneRenderer(IRenderPipeline renderPipeline, IRenderDevice renderDevice, ISceneManager sceneManager)
+ {
+ this.renderPipeline = renderPipeline ?? throw new ArgumentNullException(nameof(renderPipeline));
+ this.renderDevice = renderDevice ?? throw new ArgumentNullException(nameof(renderDevice));
+ this.sceneManager = sceneManager ?? throw new ArgumentNullException(nameof(sceneManager));
+ }
+
+ public void Render()
+ {
+ this.Initialize();
+
+ this.renderDevice.Clear(Color.FromArgb(255, 30, 30, 30));
+ this.sceneManager.ActiveScene.Render();
+ }
+
+ private void Initialize()
+ {
+ if (this.isInitialized)
+ {
+ return;
+ }
+
+ this.renderPipeline.Initialize();
+
+ this.isInitialized = true;
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/App.xaml b/FinalEngine.Editor.Desktop/App.xaml
new file mode 100644
index 00000000..3c353475
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/App.xaml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FinalEngine.Editor.Desktop/App.xaml.cs b/FinalEngine.Editor.Desktop/App.xaml.cs
new file mode 100644
index 00000000..0cacd5dd
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/App.xaml.cs
@@ -0,0 +1,122 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop;
+
+using System.Diagnostics;
+using System.IO.Abstractions;
+using System.Windows;
+using CommunityToolkit.Mvvm.Messaging;
+using FinalEngine.ECS;
+using FinalEngine.Editor.Common.Extensions;
+using FinalEngine.Editor.Common.Models.Scenes;
+using FinalEngine.Editor.Common.Services.Application;
+using FinalEngine.Editor.Common.Services.Environment;
+using FinalEngine.Editor.Common.Services.Scenes;
+using FinalEngine.Editor.Desktop.Services.Actions;
+using FinalEngine.Editor.Desktop.Services.Layout;
+using FinalEngine.Editor.Desktop.Views;
+using FinalEngine.Editor.Desktop.Views.Dialogs.Entities;
+using FinalEngine.Editor.Desktop.Views.Dialogs.Layout;
+using FinalEngine.Editor.ViewModels;
+using FinalEngine.Editor.ViewModels.Dialogs.Entities;
+using FinalEngine.Editor.ViewModels.Dialogs.Layout;
+using FinalEngine.Editor.ViewModels.Docking;
+using FinalEngine.Editor.ViewModels.Inspectors;
+using FinalEngine.Editor.ViewModels.Projects;
+using FinalEngine.Editor.ViewModels.Scenes;
+using FinalEngine.Editor.ViewModels.Services;
+using FinalEngine.Editor.ViewModels.Services.Actions;
+using FinalEngine.Editor.ViewModels.Services.Entities;
+using FinalEngine.Editor.ViewModels.Services.Interactions;
+using FinalEngine.Editor.ViewModels.Services.Layout;
+using FinalEngine.Rendering;
+using FinalEngine.Rendering.OpenGL;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+public partial class App : Application
+{
+ public App()
+ {
+ AppHost = Host.CreateDefaultBuilder()
+ .ConfigureServices(ConfigureServices)
+ .Build();
+ }
+
+ private static IHost? AppHost { get; set; }
+
+ protected override async void OnExit(ExitEventArgs e)
+ {
+ await AppHost!.StopAsync().ConfigureAwait(false);
+ base.OnExit(e);
+ }
+
+ protected override async void OnStartup(StartupEventArgs e)
+ {
+ await AppHost!.StartAsync().ConfigureAwait(false);
+
+ var viewModel = AppHost.Services.GetRequiredService();
+
+ var view = new MainView()
+ {
+ DataContext = viewModel,
+ };
+
+ view.ShowDialog();
+
+ base.OnStartup(e);
+ }
+
+ private static void ConfigureServices(HostBuilderContext context, IServiceCollection services)
+ {
+ services.AddLogging(builder =>
+ {
+ builder.AddConsole().SetMinimumLevel(Debugger.IsAttached ? LogLevel.Debug : LogLevel.Information);
+ });
+
+ services.AddSingleton(WeakReferenceMessenger.Default);
+
+ services.AddTransient();
+
+ services.AddSingleton();
+ services.AddSingleton();
+
+ services.AddSingleton();
+
+ services.AddTransient();
+
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+
+ services.AddFactory();
+ services.AddFactory();
+ services.AddFactory();
+ services.AddFactory();
+ services.AddFactory();
+ services.AddFactory();
+ services.AddFactory();
+ services.AddFactory();
+ services.AddFactory();
+ services.AddFactory();
+ services.AddSingleton();
+
+ services.AddTransient, SaveWindowLayoutView>();
+ services.AddTransient, ManageWindowLayoutsView>();
+ services.AddTransient, CreateEntityView>();
+
+ services.AddSingleton();
+
+ services.AddSingleton();
+ services.AddSingleton();
+
+ services.AddSingleton(x =>
+ {
+ return new ViewPresenter(x.GetRequiredService>(), x);
+ });
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Controls/Common/IconButton.xaml b/FinalEngine.Editor.Desktop/Controls/Common/IconButton.xaml
new file mode 100644
index 00000000..f850d18c
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Controls/Common/IconButton.xaml
@@ -0,0 +1,7 @@
+
diff --git a/FinalEngine.Editor.Desktop/Controls/Common/IconButton.xaml.cs b/FinalEngine.Editor.Desktop/Controls/Common/IconButton.xaml.cs
new file mode 100644
index 00000000..70008906
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Controls/Common/IconButton.xaml.cs
@@ -0,0 +1,34 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Controls.Common;
+
+using System.Windows.Controls;
+using System.Windows.Media;
+
+///
+/// Interaction logic for IconButton.xaml.
+///
+public partial class IconButton : Button
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public IconButton()
+ {
+ this.InitializeComponent();
+ }
+
+ ///
+ /// Gets or sets the URI source for the icon.
+ ///
+ ///
+ /// The URI source for the icon.
+ ///
+ public ImageSource UriSource
+ {
+ get { return this.image.Source; }
+ set { this.image.Source = value; }
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Exceptions/Layout/ToolPaneNotFoundException.cs b/FinalEngine.Editor.Desktop/Exceptions/Layout/ToolPaneNotFoundException.cs
new file mode 100644
index 00000000..bb86d3df
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Exceptions/Layout/ToolPaneNotFoundException.cs
@@ -0,0 +1,29 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Exceptions.Layout;
+
+using System;
+
+[Serializable]
+public class ToolPaneNotFoundException : Exception
+{
+ public ToolPaneNotFoundException()
+ : base("The content identifier could not be matched to a tool pane.")
+ {
+ }
+
+ public ToolPaneNotFoundException(string? contentID)
+ : base($"The content identifier '{contentID}' could not be matched to a tool pane.")
+ {
+ this.ContentID = contentID;
+ }
+
+ public ToolPaneNotFoundException(string? message, Exception? innerException)
+ : base(message, innerException)
+ {
+ }
+
+ public string? ContentID { get; }
+}
diff --git a/FinalEngine.Editor.Desktop/Exceptions/Layout/WindowLayoutNotFoundException.cs b/FinalEngine.Editor.Desktop/Exceptions/Layout/WindowLayoutNotFoundException.cs
new file mode 100644
index 00000000..9d63face
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Exceptions/Layout/WindowLayoutNotFoundException.cs
@@ -0,0 +1,29 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Exceptions.Layout;
+
+using System;
+
+[Serializable]
+public class WindowLayoutNotFoundException : Exception
+{
+ public WindowLayoutNotFoundException()
+ : base("Failed to locate a window layout.")
+ {
+ }
+
+ public WindowLayoutNotFoundException(string layoutName)
+ : base($"Failed to locate a window layout that matches: '{layoutName}'.")
+ {
+ this.LayoutName = layoutName;
+ }
+
+ public WindowLayoutNotFoundException(string? message, Exception? innerException)
+ : base(message, innerException)
+ {
+ }
+
+ public string? LayoutName { get; }
+}
diff --git a/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj b/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj
new file mode 100644
index 00000000..1ada7915
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/FinalEngine.Editor.Desktop.csproj
@@ -0,0 +1,66 @@
+
+
+
+ Exe
+ net8.0-windows
+ enable
+ SA0001
+ true
+ All
+ false
+ x64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+ Never
+
+
+
+
+
+
+
+
+
+ Always
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Properties/AssemblyInfo.cs b/FinalEngine.Editor.Desktop/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..29e1d2e2
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Properties/AssemblyInfo.cs
@@ -0,0 +1,17 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+using System;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
+using System.Windows;
+
+[assembly: SupportedOSPlatform("windows")]
+[assembly: CLSCompliant(false)]
+[assembly: ComVisible(false)]
+[assembly: AssemblyTitle("FinalEngine.Editor.Desktop")]
+[assembly: AssemblyDescription("The main editor application for Final Engine")]
+[assembly: Guid("18F55601-F1DE-4260-88A8-2F54CA08CA93")]
+[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
diff --git a/FinalEngine.Editor.Desktop/Resources/Images/Icons/Settings.png b/FinalEngine.Editor.Desktop/Resources/Images/Icons/Settings.png
new file mode 100644
index 00000000..2f263a29
Binary files /dev/null and b/FinalEngine.Editor.Desktop/Resources/Images/Icons/Settings.png differ
diff --git a/FinalEngine.Editor.Desktop/Resources/Images/Splashes/splash.png b/FinalEngine.Editor.Desktop/Resources/Images/Splashes/splash.png
new file mode 100644
index 00000000..bbd0a3f3
Binary files /dev/null and b/FinalEngine.Editor.Desktop/Resources/Images/Splashes/splash.png differ
diff --git a/FinalEngine.Editor.Desktop/Resources/Layouts/default.config b/FinalEngine.Editor.Desktop/Resources/Layouts/default.config
new file mode 100644
index 00000000..85106f19
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Resources/Layouts/default.config
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/FinalEngine.Editor.Desktop/Selectors/Data/Docking/Panes/PaneTemplateSelector.cs b/FinalEngine.Editor.Desktop/Selectors/Data/Docking/Panes/PaneTemplateSelector.cs
new file mode 100644
index 00000000..85a9a739
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Selectors/Data/Docking/Panes/PaneTemplateSelector.cs
@@ -0,0 +1,40 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Selectors.Data.Docking.Panes;
+
+using System.Windows;
+using System.Windows.Controls;
+using FinalEngine.Editor.ViewModels.Inspectors;
+using FinalEngine.Editor.ViewModels.Projects;
+using FinalEngine.Editor.ViewModels.Scenes;
+
+public sealed class PaneTemplateSelector : DataTemplateSelector
+{
+ public DataTemplate? ConsoleTemplate { get; set; }
+
+ public DataTemplate? EntitySystemsTemplate { get; set; }
+
+ public DataTemplate? ProjectExplorerTemplate { get; set; }
+
+ public DataTemplate? PropertiesTemplate { get; set; }
+
+ public DataTemplate? SceneHierarchyTemplate { get; set; }
+
+ public DataTemplate? SceneViewTemplate { get; set; }
+
+ public override DataTemplate? SelectTemplate(object item, DependencyObject container)
+ {
+ return item switch
+ {
+ IConsoleToolViewModel => this.ConsoleTemplate,
+ IEntitySystemsToolViewModel => this.EntitySystemsTemplate,
+ IProjectExplorerToolViewModel => this.ProjectExplorerTemplate,
+ IPropertiesToolViewModel => this.PropertiesTemplate,
+ ISceneHierarchyToolViewModel => this.SceneHierarchyTemplate,
+ ISceneViewPaneViewModel => this.SceneViewTemplate,
+ _ => base.SelectTemplate(item, container)
+ };
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Selectors/Data/Editing/PropertyTemplateSelector.cs b/FinalEngine.Editor.Desktop/Selectors/Data/Editing/PropertyTemplateSelector.cs
new file mode 100644
index 00000000..233394c5
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Selectors/Data/Editing/PropertyTemplateSelector.cs
@@ -0,0 +1,47 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Selectors.Data.Editing;
+
+using System.Windows;
+using System.Windows.Controls;
+using FinalEngine.Editor.ViewModels.Editing.DataTypes;
+
+public sealed class PropertyTemplateSelector : DataTemplateSelector
+{
+ public DataTemplate? BoolPropertyTemplate { get; set; }
+
+ public DataTemplate? DoublePropertyTemplate { get; set; }
+
+ public DataTemplate? FloatPropertyTemplate { get; set; }
+
+ public DataTemplate? IntPropertyTemplate { get; set; }
+
+ public DataTemplate? QuaternionPropertyTemplate { get; set; }
+
+ public DataTemplate? StringPropertyTemplate { get; set; }
+
+ public DataTemplate? Vector2PropertyTemplate { get; set; }
+
+ public DataTemplate? Vector3PropertyTemplate { get; set; }
+
+ public DataTemplate? Vector4PropertyTemplate { get; set; }
+
+ public override DataTemplate? SelectTemplate(object item, DependencyObject container)
+ {
+ return item switch
+ {
+ StringPropertyViewModel => this.StringPropertyTemplate,
+ BoolPropertyViewModel => this.BoolPropertyTemplate,
+ IntPropertyViewModel => this.IntPropertyTemplate,
+ DoublePropertyViewModel => this.DoublePropertyTemplate,
+ FloatPropertyViewModel => this.FloatPropertyTemplate,
+ Vector2PropertyViewModel => this.Vector2PropertyTemplate,
+ Vector3PropertyViewModel => this.Vector3PropertyTemplate,
+ Vector4PropertyViewModel => this.Vector4PropertyTemplate,
+ QuaternionPropertyViewModel => this.QuaternionPropertyTemplate,
+ _ => base.SelectTemplate(item, container),
+ };
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Selectors/Styles/Docking/Panes/PaneStyleSelector.cs b/FinalEngine.Editor.Desktop/Selectors/Styles/Docking/Panes/PaneStyleSelector.cs
new file mode 100644
index 00000000..3f7e9642
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Selectors/Styles/Docking/Panes/PaneStyleSelector.cs
@@ -0,0 +1,27 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Selectors.Styles.Docking.Panes;
+
+using System.Windows;
+using System.Windows.Controls;
+using FinalEngine.Editor.ViewModels.Docking.Panes;
+using FinalEngine.Editor.ViewModels.Docking.Tools;
+
+public sealed class PaneStyleSelector : StyleSelector
+{
+ public Style? PaneStyle { get; set; }
+
+ public Style? ToolStyle { get; set; }
+
+ public override Style? SelectStyle(object item, DependencyObject container)
+ {
+ return item switch
+ {
+ IToolViewModel => this.ToolStyle,
+ IPaneViewModel => this.PaneStyle,
+ _ => base.SelectStyle(item, container)
+ };
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Services/Actions/UserActionRequester.cs b/FinalEngine.Editor.Desktop/Services/Actions/UserActionRequester.cs
new file mode 100644
index 00000000..0df9203f
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Services/Actions/UserActionRequester.cs
@@ -0,0 +1,32 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Services.Actions;
+
+using System;
+using System.Windows;
+using FinalEngine.Editor.ViewModels.Services.Actions;
+using Microsoft.Extensions.Logging;
+
+public sealed class UserActionRequester : IUserActionRequester
+{
+ private readonly ILogger logger;
+
+ public UserActionRequester(ILogger logger)
+ {
+ this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ }
+
+ public void RequestOk(string caption, string message)
+ {
+ this.logger.LogInformation($"Requesting OK response from user for request: '{message}'.");
+ MessageBox.Show(message, caption);
+ }
+
+ public bool RequestYesNo(string caption, string message)
+ {
+ this.logger.LogInformation($"Requesting YES/NO response from user for request: '{message}'.");
+ return MessageBox.Show(message, caption, MessageBoxButton.YesNo) == MessageBoxResult.Yes;
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Services/Layout/LayoutManager.cs b/FinalEngine.Editor.Desktop/Services/Layout/LayoutManager.cs
new file mode 100644
index 00000000..07e0daed
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Services/Layout/LayoutManager.cs
@@ -0,0 +1,150 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Services.Layout;
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.IO.Abstractions;
+using System.Linq;
+using System.Windows;
+using AvalonDock;
+using AvalonDock.Layout.Serialization;
+using FinalEngine.Editor.Common.Services.Application;
+using FinalEngine.Editor.Desktop.Exceptions.Layout;
+using FinalEngine.Editor.Desktop.Views.Docking;
+using FinalEngine.Editor.ViewModels.Docking.Tools;
+using FinalEngine.Editor.ViewModels.Services.Layout;
+using MahApps.Metro.Controls;
+using Microsoft.Extensions.Logging;
+
+public sealed class LayoutManager : ILayoutManager
+{
+ private static readonly DockingManager Instance = Application.Current.MainWindow.FindChild().DockManager;
+
+ private readonly IApplicationContext application;
+
+ private readonly IFileSystem fileSystem;
+
+ private readonly ILogger logger;
+
+ public LayoutManager(
+ ILogger logger,
+ IApplicationContext application,
+ IFileSystem fileSystem)
+ {
+ this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ this.application = application ?? throw new ArgumentNullException(nameof(application));
+ this.fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem));
+ }
+
+ private string LayoutDirectory
+ {
+ get
+ {
+ string directory = this.fileSystem.Path.Combine(this.application.DataDirectory, "Layouts");
+
+ if (!this.fileSystem.Directory.Exists(directory))
+ {
+ this.fileSystem.Directory.CreateDirectory(directory);
+ }
+
+ return directory;
+ }
+ }
+
+ public bool ContainsLayout(string layoutName)
+ {
+ ArgumentException.ThrowIfNullOrWhiteSpace(layoutName, nameof(layoutName));
+ return this.LoadLayoutNames().Contains(layoutName);
+ }
+
+ public void DeleteLayout(string layoutName)
+ {
+ ArgumentException.ThrowIfNullOrWhiteSpace(layoutName, nameof(layoutName));
+
+ if (!this.ContainsLayout(layoutName))
+ {
+ throw new WindowLayoutNotFoundException(layoutName);
+ }
+
+ this.logger.LogInformation($"Deleting window layout: '{layoutName}'.");
+
+ this.fileSystem.File.Delete(this.GetLayoutPath(layoutName));
+
+ this.logger.LogInformation($"Layout deleted.");
+ }
+
+ public void LoadLayout(string layoutName)
+ {
+ ArgumentException.ThrowIfNullOrWhiteSpace(layoutName, nameof(layoutName));
+
+ if (!this.ContainsLayout(layoutName))
+ {
+ throw new WindowLayoutNotFoundException(layoutName);
+ }
+
+ this.logger.LogInformation($"Loading window layout: '{layoutName}'.");
+
+ var serializer = new XmlLayoutSerializer(Instance);
+ serializer.Deserialize(this.GetLayoutPath(layoutName));
+
+ this.logger.LogInformation("Layout loaded.");
+ }
+
+ public IEnumerable LoadLayoutNames()
+ {
+ var directoryInfo = this.fileSystem.DirectoryInfo.New(this.LayoutDirectory);
+ var files = directoryInfo.GetFiles("*.config", SearchOption.TopDirectoryOnly);
+
+ return files.Select(x =>
+ {
+ return this.fileSystem.Path.GetFileNameWithoutExtension(x.Name);
+ }).ToArray();
+ }
+
+ public void ResetLayout()
+ {
+ const string defaultLayoutPath = "Resources\\Layouts\\default.config";
+
+ this.logger.LogInformation("Resting window layout to default layout...");
+
+ var serializer = new XmlLayoutSerializer(Instance);
+ serializer.Deserialize(defaultLayoutPath);
+
+ this.logger.LogInformation("Layout reset.");
+ }
+
+ public void SaveLayout(string layoutName)
+ {
+ ArgumentException.ThrowIfNullOrWhiteSpace(layoutName, nameof(layoutName));
+
+ this.logger.LogInformation($"Saving window layout: '{layoutName}'...");
+
+ var serializer = new XmlLayoutSerializer(Instance);
+ serializer.Serialize(this.GetLayoutPath(layoutName));
+
+ this.logger.LogInformation("Layout saved.");
+ }
+
+ public void ToggleToolWindow(string contentID)
+ {
+ ArgumentException.ThrowIfNullOrWhiteSpace(contentID, nameof(contentID));
+
+ var tool = Instance.AnchorablesSource.Cast().FirstOrDefault(x =>
+ {
+ return x.ContentID == contentID;
+ }) ?? throw new ToolPaneNotFoundException(contentID);
+
+ this.logger.LogInformation($"Toggling tool view visibility for view with ID: '{contentID}'");
+
+ tool.IsVisible = !tool.IsVisible;
+ }
+
+ private string GetLayoutPath(string layoutName)
+ {
+ return this.fileSystem.Path.Combine(this.LayoutDirectory, $"{layoutName}.config");
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Styles/Controls/ButtonStyle.xaml b/FinalEngine.Editor.Desktop/Styles/Controls/ButtonStyle.xaml
new file mode 100644
index 00000000..779250f0
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Styles/Controls/ButtonStyle.xaml
@@ -0,0 +1,14 @@
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Styles/Controls/IconButtonStyle.xaml b/FinalEngine.Editor.Desktop/Styles/Controls/IconButtonStyle.xaml
new file mode 100644
index 00000000..a4439bda
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Styles/Controls/IconButtonStyle.xaml
@@ -0,0 +1,27 @@
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Styles/Controls/LabelStyle.xaml b/FinalEngine.Editor.Desktop/Styles/Controls/LabelStyle.xaml
new file mode 100644
index 00000000..98d1c706
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Styles/Controls/LabelStyle.xaml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Styles/Controls/ListBoxItemStyle.xaml b/FinalEngine.Editor.Desktop/Styles/Controls/ListBoxItemStyle.xaml
new file mode 100644
index 00000000..74d4d1c9
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Styles/Controls/ListBoxItemStyle.xaml
@@ -0,0 +1,7 @@
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Styles/Controls/ListBoxStyle.xaml b/FinalEngine.Editor.Desktop/Styles/Controls/ListBoxStyle.xaml
new file mode 100644
index 00000000..ceb96717
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Styles/Controls/ListBoxStyle.xaml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Styles/Controls/TextBoxStyle.xaml b/FinalEngine.Editor.Desktop/Styles/Controls/TextBoxStyle.xaml
new file mode 100644
index 00000000..d1e79d9d
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Styles/Controls/TextBoxStyle.xaml
@@ -0,0 +1,20 @@
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Styles/Controls/ToggleButtonStyle.xaml b/FinalEngine.Editor.Desktop/Styles/Controls/ToggleButtonStyle.xaml
new file mode 100644
index 00000000..0e6bc3f6
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Styles/Controls/ToggleButtonStyle.xaml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Styles/Controls/TransparentListBoxItemStyle.xaml b/FinalEngine.Editor.Desktop/Styles/Controls/TransparentListBoxItemStyle.xaml
new file mode 100644
index 00000000..538cb6d0
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Styles/Controls/TransparentListBoxItemStyle.xaml
@@ -0,0 +1,12 @@
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Styles/Controls/TransparentListBoxStyle.xaml b/FinalEngine.Editor.Desktop/Styles/Controls/TransparentListBoxStyle.xaml
new file mode 100644
index 00000000..c3c9c49b
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Styles/Controls/TransparentListBoxStyle.xaml
@@ -0,0 +1,7 @@
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Styles/Docking/Panes/PaneStyle.xaml b/FinalEngine.Editor.Desktop/Styles/Docking/Panes/PaneStyle.xaml
new file mode 100644
index 00000000..3a064acc
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Styles/Docking/Panes/PaneStyle.xaml
@@ -0,0 +1,14 @@
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Styles/Docking/Tools/ToolStyle.xaml b/FinalEngine.Editor.Desktop/Styles/Docking/Tools/ToolStyle.xaml
new file mode 100644
index 00000000..cb3f0a7d
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Styles/Docking/Tools/ToolStyle.xaml
@@ -0,0 +1,18 @@
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/Dialogs/Entities/CreateEntityView.xaml b/FinalEngine.Editor.Desktop/Views/Dialogs/Entities/CreateEntityView.xaml
new file mode 100644
index 00000000..cfae2d6f
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Dialogs/Entities/CreateEntityView.xaml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/Dialogs/Entities/CreateEntityView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Dialogs/Entities/CreateEntityView.xaml.cs
new file mode 100644
index 00000000..08e48c5b
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Dialogs/Entities/CreateEntityView.xaml.cs
@@ -0,0 +1,17 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Views.Dialogs.Entities;
+
+using FinalEngine.Editor.ViewModels.Dialogs.Entities;
+using FinalEngine.Editor.ViewModels.Services.Interactions;
+using MahApps.Metro.Controls;
+
+public partial class CreateEntityView : MetroWindow, IViewable, ICloseable
+{
+ public CreateEntityView()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Views/Dialogs/Layout/ManageWindowLayoutsView.xaml b/FinalEngine.Editor.Desktop/Views/Dialogs/Layout/ManageWindowLayoutsView.xaml
new file mode 100644
index 00000000..66f80bd8
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Dialogs/Layout/ManageWindowLayoutsView.xaml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/Dialogs/Layout/ManageWindowLayoutsView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Dialogs/Layout/ManageWindowLayoutsView.xaml.cs
new file mode 100644
index 00000000..b58b6d28
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Dialogs/Layout/ManageWindowLayoutsView.xaml.cs
@@ -0,0 +1,17 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Views.Dialogs.Layout;
+
+using FinalEngine.Editor.ViewModels.Dialogs.Layout;
+using FinalEngine.Editor.ViewModels.Services.Interactions;
+using MahApps.Metro.Controls;
+
+public partial class ManageWindowLayoutsView : MetroWindow, IViewable
+{
+ public ManageWindowLayoutsView()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Views/Dialogs/Layout/SaveWindowLayoutView.xaml b/FinalEngine.Editor.Desktop/Views/Dialogs/Layout/SaveWindowLayoutView.xaml
new file mode 100644
index 00000000..6cb859e1
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Dialogs/Layout/SaveWindowLayoutView.xaml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/Dialogs/Layout/SaveWindowLayoutView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Dialogs/Layout/SaveWindowLayoutView.xaml.cs
new file mode 100644
index 00000000..c5141199
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Dialogs/Layout/SaveWindowLayoutView.xaml.cs
@@ -0,0 +1,17 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Views.Dialogs.Layout;
+
+using FinalEngine.Editor.ViewModels.Dialogs.Layout;
+using FinalEngine.Editor.ViewModels.Services.Interactions;
+using MahApps.Metro.Controls;
+
+public partial class SaveWindowLayoutView : MetroWindow, IViewable, ICloseable
+{
+ public SaveWindowLayoutView()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Views/Docking/DockView.xaml b/FinalEngine.Editor.Desktop/Views/Docking/DockView.xaml
new file mode 100644
index 00000000..ff3a2528
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Docking/DockView.xaml
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/Docking/DockView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Docking/DockView.xaml.cs
new file mode 100644
index 00000000..5fcde432
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Docking/DockView.xaml.cs
@@ -0,0 +1,23 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Views.Docking;
+
+using System;
+using System.Windows;
+using System.Windows.Controls;
+
+public partial class DockView : UserControl
+{
+ public DockView()
+ {
+ this.InitializeComponent();
+ this.Dispatcher.ShutdownStarted += this.Dispatcher_ShutdownStarted;
+ }
+
+ private void Dispatcher_ShutdownStarted(object? sender, EventArgs e)
+ {
+ this.DockManager.RaiseEvent(new RoutedEventArgs(UnloadedEvent));
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/BoolPropertyView.xaml b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/BoolPropertyView.xaml
new file mode 100644
index 00000000..01d8a795
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/BoolPropertyView.xaml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/BoolPropertyView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/BoolPropertyView.xaml.cs
new file mode 100644
index 00000000..96481e93
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/BoolPropertyView.xaml.cs
@@ -0,0 +1,15 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Views.Editing.DataTypes;
+
+using System.Windows.Controls;
+
+public partial class BoolPropertyView : UserControl
+{
+ public BoolPropertyView()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/DoublePropertyView.xaml b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/DoublePropertyView.xaml
new file mode 100644
index 00000000..e2831508
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/DoublePropertyView.xaml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/DoublePropertyView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/DoublePropertyView.xaml.cs
new file mode 100644
index 00000000..554cee4a
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/DoublePropertyView.xaml.cs
@@ -0,0 +1,15 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Views.Editing.DataTypes;
+
+using System.Windows.Controls;
+
+public partial class DoublePropertyView : UserControl
+{
+ public DoublePropertyView()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/FloatPropertyView.xaml b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/FloatPropertyView.xaml
new file mode 100644
index 00000000..ea3e8403
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/FloatPropertyView.xaml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/FloatPropertyView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/FloatPropertyView.xaml.cs
new file mode 100644
index 00000000..5a18e005
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/FloatPropertyView.xaml.cs
@@ -0,0 +1,15 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Views.Editing.DataTypes;
+
+using System.Windows.Controls;
+
+public partial class FloatPropertyView : UserControl
+{
+ public FloatPropertyView()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/IntPropertyView.xaml b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/IntPropertyView.xaml
new file mode 100644
index 00000000..335d93d8
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/IntPropertyView.xaml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/IntPropertyView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/IntPropertyView.xaml.cs
new file mode 100644
index 00000000..85e50969
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/IntPropertyView.xaml.cs
@@ -0,0 +1,15 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Views.Editing.DataTypes;
+
+using System.Windows.Controls;
+
+public partial class IntPropertyView : UserControl
+{
+ public IntPropertyView()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/QuaternionPropertyView.xaml b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/QuaternionPropertyView.xaml
new file mode 100644
index 00000000..9acc3fb1
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/QuaternionPropertyView.xaml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/QuaternionPropertyView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/QuaternionPropertyView.xaml.cs
new file mode 100644
index 00000000..c5fa8edd
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/QuaternionPropertyView.xaml.cs
@@ -0,0 +1,15 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Views.Editing.DataTypes;
+
+using System.Windows.Controls;
+
+public partial class QuaternionPropertyView : UserControl
+{
+ public QuaternionPropertyView()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/StringPropertyView.xaml b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/StringPropertyView.xaml
new file mode 100644
index 00000000..26b2bdbb
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/StringPropertyView.xaml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/StringPropertyView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/StringPropertyView.xaml.cs
new file mode 100644
index 00000000..74c7bd8d
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/StringPropertyView.xaml.cs
@@ -0,0 +1,15 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Views.Editing.DataTypes;
+
+using System.Windows.Controls;
+
+public partial class StringPropertyView : UserControl
+{
+ public StringPropertyView()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/Vector2PropertyView.xaml b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/Vector2PropertyView.xaml
new file mode 100644
index 00000000..ecf51d02
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/Vector2PropertyView.xaml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/Vector2PropertyView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/Vector2PropertyView.xaml.cs
new file mode 100644
index 00000000..98bec38d
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/Vector2PropertyView.xaml.cs
@@ -0,0 +1,15 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Views.Editing.DataTypes;
+
+using System.Windows.Controls;
+
+public partial class Vector2PropertyView : UserControl
+{
+ public Vector2PropertyView()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/Vector3PropertyView.xaml b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/Vector3PropertyView.xaml
new file mode 100644
index 00000000..faab4610
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/Vector3PropertyView.xaml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/Vector3PropertyView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/Vector3PropertyView.xaml.cs
new file mode 100644
index 00000000..a7c121c6
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/Vector3PropertyView.xaml.cs
@@ -0,0 +1,15 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Views.Editing.DataTypes;
+
+using System.Windows.Controls;
+
+public partial class Vector3PropertyView : UserControl
+{
+ public Vector3PropertyView()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/Vector4PropertyView.xaml b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/Vector4PropertyView.xaml
new file mode 100644
index 00000000..3aeaf45e
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/Vector4PropertyView.xaml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/Vector4PropertyView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/Vector4PropertyView.xaml.cs
new file mode 100644
index 00000000..018f503a
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Editing/DataTypes/Vector4PropertyView.xaml.cs
@@ -0,0 +1,15 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Views.Editing.DataTypes;
+
+using System.Windows.Controls;
+
+public partial class Vector4PropertyView : UserControl
+{
+ public Vector4PropertyView()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Views/Inspectors/ConsoleView.xaml b/FinalEngine.Editor.Desktop/Views/Inspectors/ConsoleView.xaml
new file mode 100644
index 00000000..7d1d7c4f
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Inspectors/ConsoleView.xaml
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/Inspectors/ConsoleView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Inspectors/ConsoleView.xaml.cs
new file mode 100644
index 00000000..1f712984
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Inspectors/ConsoleView.xaml.cs
@@ -0,0 +1,15 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Views.Inspectors;
+
+using System.Windows.Controls;
+
+public partial class ConsoleView : UserControl
+{
+ public ConsoleView()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Views/Inspectors/EntityComponentView.xaml b/FinalEngine.Editor.Desktop/Views/Inspectors/EntityComponentView.xaml
new file mode 100644
index 00000000..f1946f6e
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Inspectors/EntityComponentView.xaml
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/Inspectors/EntityComponentView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Inspectors/EntityComponentView.xaml.cs
new file mode 100644
index 00000000..fa032524
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Inspectors/EntityComponentView.xaml.cs
@@ -0,0 +1,15 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Views.Inspectors;
+
+using System.Windows.Controls;
+
+public partial class EntityComponentView : UserControl
+{
+ public EntityComponentView()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Views/Inspectors/EntityInspectorView.xaml b/FinalEngine.Editor.Desktop/Views/Inspectors/EntityInspectorView.xaml
new file mode 100644
index 00000000..91d35aea
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Inspectors/EntityInspectorView.xaml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/Inspectors/EntityInspectorView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Inspectors/EntityInspectorView.xaml.cs
new file mode 100644
index 00000000..63837364
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Inspectors/EntityInspectorView.xaml.cs
@@ -0,0 +1,15 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Views.Inspectors;
+
+using System.Windows.Controls;
+
+public partial class EntityInspectorView : UserControl
+{
+ public EntityInspectorView()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Views/Inspectors/PropertiesView.xaml b/FinalEngine.Editor.Desktop/Views/Inspectors/PropertiesView.xaml
new file mode 100644
index 00000000..660119af
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Inspectors/PropertiesView.xaml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/Inspectors/PropertiesView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Inspectors/PropertiesView.xaml.cs
new file mode 100644
index 00000000..d242d660
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Inspectors/PropertiesView.xaml.cs
@@ -0,0 +1,15 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Views.Inspectors;
+
+using System.Windows.Controls;
+
+public partial class PropertiesView : UserControl
+{
+ public PropertiesView()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Views/MainView.xaml b/FinalEngine.Editor.Desktop/Views/MainView.xaml
new file mode 100644
index 00000000..b1911edf
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/MainView.xaml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/MainView.xaml.cs b/FinalEngine.Editor.Desktop/Views/MainView.xaml.cs
new file mode 100644
index 00000000..9a73c07d
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/MainView.xaml.cs
@@ -0,0 +1,16 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Views;
+
+using FinalEngine.Editor.ViewModels.Services.Interactions;
+using MahApps.Metro.Controls;
+
+public partial class MainView : MetroWindow, ICloseable
+{
+ public MainView()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Views/Projects/ProjectExplorerView.xaml b/FinalEngine.Editor.Desktop/Views/Projects/ProjectExplorerView.xaml
new file mode 100644
index 00000000..3f0edcfe
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Projects/ProjectExplorerView.xaml
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/Projects/ProjectExplorerView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Projects/ProjectExplorerView.xaml.cs
new file mode 100644
index 00000000..07b3a38a
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Projects/ProjectExplorerView.xaml.cs
@@ -0,0 +1,15 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Views.Projects;
+
+using System.Windows.Controls;
+
+public partial class ProjectExplorerView : UserControl
+{
+ public ProjectExplorerView()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Views/Scenes/EntitySystemsView.xaml b/FinalEngine.Editor.Desktop/Views/Scenes/EntitySystemsView.xaml
new file mode 100644
index 00000000..ce437ca7
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Scenes/EntitySystemsView.xaml
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/Scenes/EntitySystemsView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Scenes/EntitySystemsView.xaml.cs
new file mode 100644
index 00000000..4aebfd95
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Scenes/EntitySystemsView.xaml.cs
@@ -0,0 +1,15 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Views.Scenes;
+
+using System.Windows.Controls;
+
+public partial class EntitySystemsView : UserControl
+{
+ public EntitySystemsView()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Views/Scenes/SceneHierarchyView.xaml b/FinalEngine.Editor.Desktop/Views/Scenes/SceneHierarchyView.xaml
new file mode 100644
index 00000000..9ea8a64f
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Scenes/SceneHierarchyView.xaml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/Scenes/SceneHierarchyView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Scenes/SceneHierarchyView.xaml.cs
new file mode 100644
index 00000000..74014831
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Scenes/SceneHierarchyView.xaml.cs
@@ -0,0 +1,15 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Views.Scenes;
+
+using System.Windows.Controls;
+
+public partial class SceneHierarchyView : UserControl
+{
+ public SceneHierarchyView()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/FinalEngine.Editor.Desktop/Views/Scenes/SceneView.xaml b/FinalEngine.Editor.Desktop/Views/Scenes/SceneView.xaml
new file mode 100644
index 00000000..5ce266ea
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Scenes/SceneView.xaml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
diff --git a/FinalEngine.Editor.Desktop/Views/Scenes/SceneView.xaml.cs b/FinalEngine.Editor.Desktop/Views/Scenes/SceneView.xaml.cs
new file mode 100644
index 00000000..5eae796e
--- /dev/null
+++ b/FinalEngine.Editor.Desktop/Views/Scenes/SceneView.xaml.cs
@@ -0,0 +1,16 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.Desktop.Views.Scenes;
+
+using System.Windows.Controls;
+
+public partial class SceneView : UserControl
+{
+ public SceneView()
+ {
+ this.InitializeComponent();
+ this.glWpfControl.Start();
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Dialogs/Entities/CreateEntityViewModel.cs b/FinalEngine.Editor.ViewModels/Dialogs/Entities/CreateEntityViewModel.cs
new file mode 100644
index 00000000..30f00515
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Dialogs/Entities/CreateEntityViewModel.cs
@@ -0,0 +1,82 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Dialogs.Entities;
+
+using System;
+using System.ComponentModel.DataAnnotations;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using FinalEngine.Editor.Common.Services.Scenes;
+using FinalEngine.Editor.ViewModels.Services.Interactions;
+using Microsoft.Extensions.Logging;
+
+public sealed class CreateEntityViewModel : ObservableValidator, ICreateEntityViewModel
+{
+ private readonly ILogger logger;
+
+ private readonly ISceneManager sceneManager;
+
+ private IRelayCommand? createCommand;
+
+ private string? entityName;
+
+ public CreateEntityViewModel(
+ ILogger logger,
+ ISceneManager sceneManager)
+ {
+ this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ this.sceneManager = sceneManager ?? throw new ArgumentNullException(nameof(sceneManager));
+
+ this.EntityName = "Entity";
+ this.EntityGuid = Guid.NewGuid();
+ }
+
+ public IRelayCommand CreateCommand
+ {
+ get
+ {
+ return this.createCommand ??= new RelayCommand(this.Create, x =>
+ {
+ return !this.HasErrors;
+ });
+ }
+ }
+
+ public Guid EntityGuid { get; }
+
+ [Required(ErrorMessage = "You must provide an entity name.")]
+ public string EntityName
+ {
+ get
+ {
+ return this.entityName ?? string.Empty;
+ }
+
+ set
+ {
+ this.SetProperty(ref this.entityName, value, true);
+ this.CreateCommand.NotifyCanExecuteChanged();
+ }
+ }
+
+ public string Title
+ {
+ get { return "Create New Entity"; }
+ }
+
+ private void Create(ICloseable? closeable)
+ {
+ ArgumentNullException.ThrowIfNull(closeable, nameof(closeable));
+
+ this.logger.LogInformation($"Creating new entity...");
+
+ var scene = this.sceneManager.ActiveScene;
+ scene.AddEntity(this.EntityName, this.EntityGuid);
+
+ this.logger.LogInformation($"Entity with ID: '{this.EntityGuid}' created!");
+
+ closeable.Close();
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Dialogs/Entities/ICreateEntityViewModel.cs b/FinalEngine.Editor.ViewModels/Dialogs/Entities/ICreateEntityViewModel.cs
new file mode 100644
index 00000000..4ce236fb
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Dialogs/Entities/ICreateEntityViewModel.cs
@@ -0,0 +1,19 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Dialogs.Entities;
+
+using System;
+using CommunityToolkit.Mvvm.Input;
+
+public interface ICreateEntityViewModel
+{
+ IRelayCommand CreateCommand { get; }
+
+ Guid EntityGuid { get; }
+
+ string EntityName { get; set; }
+
+ string Title { get; }
+}
diff --git a/FinalEngine.Editor.ViewModels/Dialogs/Layout/IManageWindowLayoutsViewModel.cs b/FinalEngine.Editor.ViewModels/Dialogs/Layout/IManageWindowLayoutsViewModel.cs
new file mode 100644
index 00000000..beee7ffc
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Dialogs/Layout/IManageWindowLayoutsViewModel.cs
@@ -0,0 +1,21 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Dialogs.Layout;
+
+using System.Collections.Generic;
+using CommunityToolkit.Mvvm.Input;
+
+public interface IManageWindowLayoutsViewModel
+{
+ IRelayCommand ApplyCommand { get; }
+
+ IRelayCommand DeleteCommand { get; }
+
+ IEnumerable LayoutNames { get; }
+
+ string? SelectedItem { get; }
+
+ string Title { get; }
+}
diff --git a/FinalEngine.Editor.ViewModels/Dialogs/Layout/ISaveWindowLayoutViewModel.cs b/FinalEngine.Editor.ViewModels/Dialogs/Layout/ISaveWindowLayoutViewModel.cs
new file mode 100644
index 00000000..141f600e
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Dialogs/Layout/ISaveWindowLayoutViewModel.cs
@@ -0,0 +1,16 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Dialogs.Layout;
+
+using CommunityToolkit.Mvvm.Input;
+
+public interface ISaveWindowLayoutViewModel
+{
+ string LayoutName { get; set; }
+
+ IRelayCommand SaveCommand { get; }
+
+ string Title { get; }
+}
diff --git a/FinalEngine.Editor.ViewModels/Dialogs/Layout/ManageWindowLayoutsViewModel.cs b/FinalEngine.Editor.ViewModels/Dialogs/Layout/ManageWindowLayoutsViewModel.cs
new file mode 100644
index 00000000..83b44064
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Dialogs/Layout/ManageWindowLayoutsViewModel.cs
@@ -0,0 +1,106 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Dialogs.Layout;
+
+using System;
+using System.Collections.Generic;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using FinalEngine.Editor.ViewModels.Services.Actions;
+using FinalEngine.Editor.ViewModels.Services.Layout;
+using Microsoft.Extensions.Logging;
+
+public sealed class ManageWindowLayoutsViewModel : ObservableObject, IManageWindowLayoutsViewModel
+{
+ private readonly ILayoutManager layoutManager;
+
+ private readonly ILogger logger;
+
+ private readonly IUserActionRequester userActionRequester;
+
+ private IRelayCommand? applyCommand;
+
+ private IRelayCommand? deleteCommand;
+
+ private IEnumerable? layoutNames;
+
+ private string? selectedItem;
+
+ public ManageWindowLayoutsViewModel(
+ ILogger logger,
+ IUserActionRequester userActionRequester,
+ ILayoutManager layoutManager)
+ {
+ this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ this.userActionRequester = userActionRequester ?? throw new ArgumentNullException(nameof(userActionRequester));
+ this.layoutManager = layoutManager ?? throw new ArgumentNullException(nameof(layoutManager));
+
+ this.LayoutNames = this.layoutManager.LoadLayoutNames();
+ }
+
+ public IRelayCommand ApplyCommand
+ {
+ get { return this.applyCommand ??= new RelayCommand(this.Apply, this.CanModify); }
+ }
+
+ public IRelayCommand DeleteCommand
+ {
+ get { return this.deleteCommand ??= new RelayCommand(this.Delete, this.CanModify); }
+ }
+
+ public IEnumerable LayoutNames
+ {
+ get { return this.layoutNames ?? Array.Empty(); }
+ private set { this.SetProperty(ref this.layoutNames, value); }
+ }
+
+ public string? SelectedItem
+ {
+ get
+ {
+ return this.selectedItem;
+ }
+
+ set
+ {
+ this.SetProperty(ref this.selectedItem, value);
+
+ this.DeleteCommand.NotifyCanExecuteChanged();
+ this.ApplyCommand.NotifyCanExecuteChanged();
+ }
+ }
+
+ public string Title
+ {
+ get { return "Manage Window Layouts"; }
+ }
+
+ private void Apply()
+ {
+ this.logger.LogInformation($"Applying selected window layout...");
+ this.layoutManager.LoadLayout(this.SelectedItem!);
+ }
+
+ private bool CanModify()
+ {
+ return !string.IsNullOrWhiteSpace(this.SelectedItem);
+ }
+
+ private void Delete()
+ {
+ this.logger.LogInformation("Deleting selected window layout...");
+
+ if (!this.userActionRequester.RequestYesNo(
+ this.Title,
+ $"Are you sure you want to delete the '{this.SelectedItem}' window layout?"))
+ {
+ this.logger.LogInformation("User cancelled delete operation.");
+ return;
+ }
+
+ this.layoutManager.DeleteLayout(this.SelectedItem!);
+ this.LayoutNames = this.layoutManager.LoadLayoutNames();
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Dialogs/Layout/SaveWindowLayoutViewModel.cs b/FinalEngine.Editor.ViewModels/Dialogs/Layout/SaveWindowLayoutViewModel.cs
new file mode 100644
index 00000000..3be52992
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Dialogs/Layout/SaveWindowLayoutViewModel.cs
@@ -0,0 +1,96 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Dialogs.Layout;
+
+using System;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using FinalEngine.Editor.ViewModels.Services.Actions;
+using FinalEngine.Editor.ViewModels.Services.Interactions;
+using FinalEngine.Editor.ViewModels.Services.Layout;
+using FinalEngine.Editor.ViewModels.Validation;
+using Microsoft.Extensions.Logging;
+
+public sealed class SaveWindowLayoutViewModel : ObservableValidator, ISaveWindowLayoutViewModel
+{
+ private readonly ILayoutManager layoutManager;
+
+ private readonly ILogger logger;
+
+ private readonly IUserActionRequester userActionRequester;
+
+ private string? layoutName;
+
+ private IRelayCommand? saveCommand;
+
+ public SaveWindowLayoutViewModel(
+ ILogger logger,
+ ILayoutManager layoutManager,
+ IUserActionRequester userActionRequester)
+ {
+ this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ this.userActionRequester = userActionRequester ?? throw new ArgumentNullException(nameof(userActionRequester));
+ this.layoutManager = layoutManager ?? throw new ArgumentNullException(nameof(layoutManager));
+
+ this.LayoutName = "Layout Name";
+ }
+
+ [FileName(ErrorMessage = "You must provide a valid layout name.")]
+ public string LayoutName
+ {
+ get
+ {
+ return this.layoutName ?? string.Empty;
+ }
+
+ set
+ {
+ this.SetProperty(ref this.layoutName, value, true);
+ this.SaveCommand.NotifyCanExecuteChanged();
+ }
+ }
+
+ public IRelayCommand SaveCommand
+ {
+ get
+ {
+ return this.saveCommand ??= new RelayCommand(this.Save, (o) =>
+ {
+ return this.CanSave();
+ });
+ }
+ }
+
+ public string Title
+ {
+ get { return "Save Window Layout"; }
+ }
+
+ private bool CanSave()
+ {
+ return !this.HasErrors;
+ }
+
+ private void Save(ICloseable? closeable)
+ {
+ ArgumentNullException.ThrowIfNull(closeable, nameof(closeable));
+
+ this.logger.LogInformation("Saving current window layout...");
+
+ string requestMessage = $"A window layout named '{this.LayoutName}' already exists. Do you want to replace it?";
+
+ if (this.layoutManager.ContainsLayout(this.LayoutName) && !this.userActionRequester.RequestYesNo(this.Title, requestMessage))
+ {
+ this.logger.LogInformation("User or manager cancelled the save operation.");
+ return;
+ }
+
+ this.layoutManager.SaveLayout(this.LayoutName);
+
+ this.logger.LogInformation($"Closing the {this.Title} view...");
+
+ closeable.Close();
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Docking/DockViewModel.cs b/FinalEngine.Editor.ViewModels/Docking/DockViewModel.cs
new file mode 100644
index 00000000..0c3ecb4b
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Docking/DockViewModel.cs
@@ -0,0 +1,106 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Docking;
+
+using System;
+using System.Collections.Generic;
+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.Inspectors;
+using FinalEngine.Editor.ViewModels.Projects;
+using FinalEngine.Editor.ViewModels.Scenes;
+using FinalEngine.Editor.ViewModels.Services.Layout;
+using Microsoft.Extensions.Logging;
+
+public sealed class DockViewModel : ObservableObject, IDockViewModel
+{
+ private const string StartupLayoutName = "startup";
+
+ private readonly ILayoutManager layoutManager;
+
+ private readonly ILogger logger;
+
+ private ICommand? loadCommand;
+
+ private ICommand? unloadCommand;
+
+ public DockViewModel(
+ ILogger logger,
+ ILayoutManager layoutManager,
+ IFactory projectExplorerFactory,
+ IFactory sceneHierarchyFactory,
+ IFactory propertiesFactory,
+ IFactory consoleFactory,
+ IFactory entitySystemsFactory,
+ IFactory sceneViewFactory)
+ {
+ ArgumentNullException.ThrowIfNull(projectExplorerFactory, nameof(projectExplorerFactory));
+ ArgumentNullException.ThrowIfNull(sceneHierarchyFactory, nameof(sceneHierarchyFactory));
+ ArgumentNullException.ThrowIfNull(propertiesFactory, nameof(propertiesFactory));
+ ArgumentNullException.ThrowIfNull(consoleFactory, nameof(consoleFactory));
+ ArgumentNullException.ThrowIfNull(entitySystemsFactory, nameof(entitySystemsFactory));
+ ArgumentNullException.ThrowIfNull(sceneViewFactory, nameof(sceneViewFactory));
+
+ this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ this.layoutManager = layoutManager ?? throw new ArgumentNullException(nameof(layoutManager));
+
+ this.logger.LogInformation("Creating tool views...");
+
+ this.Tools = new List()
+ {
+ projectExplorerFactory.Create(),
+ sceneHierarchyFactory.Create(),
+ propertiesFactory.Create(),
+ consoleFactory.Create(),
+ entitySystemsFactory.Create(),
+ };
+
+ this.logger.LogInformation("Creating pane views...");
+
+ this.Panes = new List()
+ {
+ sceneViewFactory.Create(),
+ };
+ }
+
+ public ICommand LoadCommand
+ {
+ get { return this.loadCommand ??= new RelayCommand(this.Load); }
+ }
+
+ public IEnumerable Panes { get; }
+
+ public IEnumerable Tools { get; }
+
+ public ICommand UnloadCommand
+ {
+ get { return this.unloadCommand ??= new RelayCommand(this.Unload); }
+ }
+
+ private void Load()
+ {
+ this.logger.LogInformation("Loading the window layout...");
+
+ if (!this.layoutManager.ContainsLayout(StartupLayoutName))
+ {
+ this.logger.LogInformation("No startup window layout was found, resolving to default layout...");
+ this.layoutManager.ResetLayout();
+
+ return;
+ }
+
+ this.layoutManager.LoadLayout(StartupLayoutName);
+ }
+
+ private void Unload()
+ {
+ this.logger.LogInformation("Saving the startup window layout...");
+ this.layoutManager.SaveLayout(StartupLayoutName);
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Docking/IDockViewModel.cs b/FinalEngine.Editor.ViewModels/Docking/IDockViewModel.cs
new file mode 100644
index 00000000..bc950b32
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Docking/IDockViewModel.cs
@@ -0,0 +1,21 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Docking;
+
+using System.Collections.Generic;
+using System.Windows.Input;
+using FinalEngine.Editor.ViewModels.Docking.Panes;
+using FinalEngine.Editor.ViewModels.Docking.Tools;
+
+public interface IDockViewModel
+{
+ ICommand LoadCommand { get; }
+
+ IEnumerable Panes { get; }
+
+ IEnumerable Tools { get; }
+
+ ICommand UnloadCommand { get; }
+}
diff --git a/FinalEngine.Editor.ViewModels/Docking/Panes/IPaneViewModel.cs b/FinalEngine.Editor.ViewModels/Docking/Panes/IPaneViewModel.cs
new file mode 100644
index 00000000..6df7b082
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Docking/Panes/IPaneViewModel.cs
@@ -0,0 +1,16 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Docking.Panes;
+
+public interface IPaneViewModel
+{
+ string ContentID { get; set; }
+
+ bool IsActive { get; set; }
+
+ bool IsSelected { get; set; }
+
+ string Title { get; set; }
+}
diff --git a/FinalEngine.Editor.ViewModels/Docking/Panes/PaneViewModelBase.cs b/FinalEngine.Editor.ViewModels/Docking/Panes/PaneViewModelBase.cs
new file mode 100644
index 00000000..8fcb8b1f
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Docking/Panes/PaneViewModelBase.cs
@@ -0,0 +1,47 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Docking.Panes;
+
+using CommunityToolkit.Mvvm.ComponentModel;
+
+public abstract class PaneViewModelBase : ObservableObject, IPaneViewModel
+{
+ private string? contentID;
+
+ private bool isActive;
+
+ private bool isSelected;
+
+ private string? title;
+
+ protected PaneViewModelBase()
+ {
+ this.IsActive = true;
+ }
+
+ public string ContentID
+ {
+ get { return this.contentID ?? string.Empty; }
+ set { this.SetProperty(ref this.contentID, value); }
+ }
+
+ public bool IsActive
+ {
+ get { return this.isActive; }
+ set { this.SetProperty(ref this.isActive, value); }
+ }
+
+ public bool IsSelected
+ {
+ get { return this.isSelected; }
+ set { this.SetProperty(ref this.isSelected, value); }
+ }
+
+ public string Title
+ {
+ get { return this.title ?? string.Empty; }
+ set { this.SetProperty(ref this.title, value); }
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Docking/Tools/IToolViewModel.cs b/FinalEngine.Editor.ViewModels/Docking/Tools/IToolViewModel.cs
new file mode 100644
index 00000000..36c550db
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Docking/Tools/IToolViewModel.cs
@@ -0,0 +1,12 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Docking.Tools;
+
+using FinalEngine.Editor.ViewModels.Docking.Panes;
+
+public interface IToolViewModel : IPaneViewModel
+{
+ 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..f1cc2f9e
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Docking/Tools/ToolViewModelBase.cs
@@ -0,0 +1,23 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Docking.Tools;
+
+using FinalEngine.Editor.ViewModels.Docking.Panes;
+
+public abstract class ToolViewModelBase : PaneViewModelBase, IToolViewModel
+{
+ private bool isVisible;
+
+ protected ToolViewModelBase()
+ {
+ this.IsVisible = true;
+ }
+
+ public bool IsVisible
+ {
+ get { return this.isVisible; }
+ set { this.SetProperty(ref this.isVisible, value); }
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Editing/DataTypes/BoolPropertyViewModel.cs b/FinalEngine.Editor.ViewModels/Editing/DataTypes/BoolPropertyViewModel.cs
new file mode 100644
index 00000000..db4062b7
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Editing/DataTypes/BoolPropertyViewModel.cs
@@ -0,0 +1,15 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Editing.DataTypes;
+
+using System.Reflection;
+
+public sealed class BoolPropertyViewModel : PropertyViewModel
+{
+ public BoolPropertyViewModel(object component, PropertyInfo property)
+ : base(component, property)
+ {
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Editing/DataTypes/DoublePropertyViewModel.cs b/FinalEngine.Editor.ViewModels/Editing/DataTypes/DoublePropertyViewModel.cs
new file mode 100644
index 00000000..d49f4035
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Editing/DataTypes/DoublePropertyViewModel.cs
@@ -0,0 +1,23 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Editing.DataTypes;
+
+using System.ComponentModel.DataAnnotations;
+using System.Reflection;
+
+public sealed class DoublePropertyViewModel : PropertyViewModel
+{
+ public DoublePropertyViewModel(object component, PropertyInfo property)
+ : base(component, property)
+ {
+ }
+
+ [Range(0, double.MaxValue, ErrorMessage = "You must enter a valid double.")]
+ public override double Value
+ {
+ get { return base.Value; }
+ set { base.Value = value; }
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Editing/DataTypes/FloatPropertyViewModel.cs b/FinalEngine.Editor.ViewModels/Editing/DataTypes/FloatPropertyViewModel.cs
new file mode 100644
index 00000000..180712b3
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Editing/DataTypes/FloatPropertyViewModel.cs
@@ -0,0 +1,23 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Editing.DataTypes;
+
+using System.ComponentModel.DataAnnotations;
+using System.Reflection;
+
+public sealed class FloatPropertyViewModel : PropertyViewModel
+{
+ public FloatPropertyViewModel(object component, PropertyInfo property)
+ : base(component, property)
+ {
+ }
+
+ [Range(0, float.MaxValue, ErrorMessage = "You must enter a valid float.")]
+ public override float Value
+ {
+ get { return base.Value; }
+ set { base.Value = value; }
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Editing/DataTypes/IntPropertyViewModel.cs b/FinalEngine.Editor.ViewModels/Editing/DataTypes/IntPropertyViewModel.cs
new file mode 100644
index 00000000..e1af30f8
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Editing/DataTypes/IntPropertyViewModel.cs
@@ -0,0 +1,23 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Editing.DataTypes;
+
+using System.ComponentModel.DataAnnotations;
+using System.Reflection;
+
+public sealed class IntPropertyViewModel : PropertyViewModel
+{
+ public IntPropertyViewModel(object component, PropertyInfo property)
+ : base(component, property)
+ {
+ }
+
+ [Range(0, int.MaxValue, ErrorMessage = "You must enter a valid integer.")]
+ public override int Value
+ {
+ get { return base.Value; }
+ set { base.Value = value; }
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Editing/DataTypes/QuaternionPropertyViewModel.cs b/FinalEngine.Editor.ViewModels/Editing/DataTypes/QuaternionPropertyViewModel.cs
new file mode 100644
index 00000000..e1c61a5b
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Editing/DataTypes/QuaternionPropertyViewModel.cs
@@ -0,0 +1,65 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Editing.DataTypes;
+
+using System.ComponentModel.DataAnnotations;
+using System.Numerics;
+using System.Reflection;
+
+public sealed class QuaternionPropertyViewModel : PropertyViewModel
+{
+ public QuaternionPropertyViewModel(object component, PropertyInfo property)
+ : base(component, property)
+ {
+ }
+
+ [Range(0, float.MaxValue, ErrorMessage = "You must enter a valid float.")]
+ public float X
+ {
+ get
+ {
+ return this.Value.X;
+ }
+
+ set
+ {
+ var temp = this.Value;
+ temp.X = value;
+ this.Value = temp;
+ }
+ }
+
+ [Range(0, float.MaxValue, ErrorMessage = "You must enter a valid float.")]
+ public float Y
+ {
+ get
+ {
+ return this.Value.Y;
+ }
+
+ set
+ {
+ var temp = this.Value;
+ temp.Y = value;
+ this.Value = temp;
+ }
+ }
+
+ [Range(0, float.MaxValue, ErrorMessage = "You must enter a valid float.")]
+ public float Z
+ {
+ get
+ {
+ return this.Value.Z;
+ }
+
+ set
+ {
+ var temp = this.Value;
+ temp.Z = value;
+ this.Value = temp;
+ }
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Editing/DataTypes/StringPropertyViewModel.cs b/FinalEngine.Editor.ViewModels/Editing/DataTypes/StringPropertyViewModel.cs
new file mode 100644
index 00000000..146bc8fa
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Editing/DataTypes/StringPropertyViewModel.cs
@@ -0,0 +1,15 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Editing.DataTypes;
+
+using System.Reflection;
+
+public sealed class StringPropertyViewModel : PropertyViewModel
+{
+ public StringPropertyViewModel(object component, PropertyInfo property)
+ : base(component, property)
+ {
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Editing/DataTypes/Vector2PropertyViewModel.cs b/FinalEngine.Editor.ViewModels/Editing/DataTypes/Vector2PropertyViewModel.cs
new file mode 100644
index 00000000..e8403ebd
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Editing/DataTypes/Vector2PropertyViewModel.cs
@@ -0,0 +1,49 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Editing.DataTypes;
+
+using System.ComponentModel.DataAnnotations;
+using System.Numerics;
+using System.Reflection;
+
+public sealed class Vector2PropertyViewModel : PropertyViewModel
+{
+ public Vector2PropertyViewModel(object component, PropertyInfo property)
+ : base(component, property)
+ {
+ }
+
+ [Range(0, float.MaxValue, ErrorMessage = "You must enter a valid float.")]
+ public float X
+ {
+ get
+ {
+ return this.Value.X;
+ }
+
+ set
+ {
+ var temp = this.Value;
+ temp.X = value;
+ this.Value = temp;
+ }
+ }
+
+ [Range(0, float.MaxValue, ErrorMessage = "You must enter a valid float.")]
+ public float Y
+ {
+ get
+ {
+ return this.Value.Y;
+ }
+
+ set
+ {
+ var temp = this.Value;
+ temp.Y = value;
+ this.Value = temp;
+ }
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Editing/DataTypes/Vector3PropertyViewModel.cs b/FinalEngine.Editor.ViewModels/Editing/DataTypes/Vector3PropertyViewModel.cs
new file mode 100644
index 00000000..c170eff1
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Editing/DataTypes/Vector3PropertyViewModel.cs
@@ -0,0 +1,66 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Editing.DataTypes;
+
+using System.ComponentModel.DataAnnotations;
+using System.Numerics;
+
+using System.Reflection;
+
+public sealed class Vector3PropertyViewModel : PropertyViewModel
+{
+ public Vector3PropertyViewModel(object component, PropertyInfo property)
+ : base(component, property)
+ {
+ }
+
+ [Range(0, float.MaxValue, ErrorMessage = "You must enter a valid float.")]
+ public float X
+ {
+ get
+ {
+ return this.Value.X;
+ }
+
+ set
+ {
+ var temp = this.Value;
+ temp.X = value;
+ this.Value = temp;
+ }
+ }
+
+ [Range(0, float.MaxValue, ErrorMessage = "You must enter a valid float.")]
+ public float Y
+ {
+ get
+ {
+ return this.Value.Y;
+ }
+
+ set
+ {
+ var temp = this.Value;
+ temp.Y = value;
+ this.Value = temp;
+ }
+ }
+
+ [Range(0, float.MaxValue, ErrorMessage = "You must enter a valid float.")]
+ public float Z
+ {
+ get
+ {
+ return this.Value.Z;
+ }
+
+ set
+ {
+ var temp = this.Value;
+ temp.Z = value;
+ this.Value = temp;
+ }
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Editing/DataTypes/Vector4PropertyViewModel.cs b/FinalEngine.Editor.ViewModels/Editing/DataTypes/Vector4PropertyViewModel.cs
new file mode 100644
index 00000000..2b847a64
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Editing/DataTypes/Vector4PropertyViewModel.cs
@@ -0,0 +1,82 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Editing.DataTypes;
+
+using System.ComponentModel.DataAnnotations;
+using System.Numerics;
+
+using System.Reflection;
+
+public sealed class Vector4PropertyViewModel : PropertyViewModel
+{
+ public Vector4PropertyViewModel(object component, PropertyInfo property)
+ : base(component, property)
+ {
+ }
+
+ [Range(0, float.MaxValue, ErrorMessage = "You must enter a valid float.")]
+ public float W
+ {
+ get
+ {
+ return this.Value.W;
+ }
+
+ set
+ {
+ var temp = this.Value;
+ temp.W = value;
+ this.Value = temp;
+ }
+ }
+
+ [Range(0, float.MaxValue, ErrorMessage = "You must enter a valid float.")]
+ public float X
+ {
+ get
+ {
+ return this.Value.X;
+ }
+
+ set
+ {
+ var temp = this.Value;
+ temp.X = value;
+ this.Value = temp;
+ }
+ }
+
+ [Range(0, float.MaxValue, ErrorMessage = "You must enter a valid float.")]
+ public float Y
+ {
+ get
+ {
+ return this.Value.Y;
+ }
+
+ set
+ {
+ var temp = this.Value;
+ temp.Y = value;
+ this.Value = temp;
+ }
+ }
+
+ [Range(0, float.MaxValue, ErrorMessage = "You must enter a valid float.")]
+ public float Z
+ {
+ get
+ {
+ return this.Value.Z;
+ }
+
+ set
+ {
+ var temp = this.Value;
+ temp.Z = value;
+ this.Value = temp;
+ }
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Editing/IPropertyViewModel.cs b/FinalEngine.Editor.ViewModels/Editing/IPropertyViewModel.cs
new file mode 100644
index 00000000..9ce364aa
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Editing/IPropertyViewModel.cs
@@ -0,0 +1,12 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Editing;
+
+public interface IPropertyViewModel
+{
+ string Name { get; }
+
+ T? Value { get; set; }
+}
diff --git a/FinalEngine.Editor.ViewModels/Editing/PropertyViewModel.cs b/FinalEngine.Editor.ViewModels/Editing/PropertyViewModel.cs
new file mode 100644
index 00000000..b4fdaf6b
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Editing/PropertyViewModel.cs
@@ -0,0 +1,56 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Editing;
+
+using System;
+using System.Reflection;
+using CommunityToolkit.Mvvm.ComponentModel;
+
+public class PropertyViewModel : ObservableValidator, IPropertyViewModel
+{
+ private readonly object component;
+
+ private readonly Func getValue;
+
+ private readonly Action setValue;
+
+ public PropertyViewModel(object component, PropertyInfo property)
+ {
+ ArgumentNullException.ThrowIfNull(property, nameof(property));
+
+ this.component = component ?? throw new ArgumentNullException(nameof(component));
+
+ this.getValue = new Func(() =>
+ {
+ return (T?)property.GetValue(this.component);
+ });
+
+ this.setValue = new Action(x =>
+ {
+ property.SetValue(this.component, x);
+ });
+
+ this.Name = property.Name;
+ this.Value = this.getValue();
+ }
+
+ public string Name { get; }
+
+ public virtual T? Value
+ {
+ get
+ {
+ return this.getValue();
+ }
+
+ set
+ {
+ this.OnPropertyChanging(nameof(this.Value));
+ this.setValue(value);
+ this.OnPropertyChanged(nameof(this.Value));
+ this.ValidateProperty(this.Value, nameof(this.Value));
+ }
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Exceptions/Inspectors/PropertyTypeNotFoundException.cs b/FinalEngine.Editor.ViewModels/Exceptions/Inspectors/PropertyTypeNotFoundException.cs
new file mode 100644
index 00000000..d665377f
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Exceptions/Inspectors/PropertyTypeNotFoundException.cs
@@ -0,0 +1,29 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Exceptions.Inspectors;
+
+using System;
+
+[Serializable]
+public class PropertyTypeNotFoundException : Exception
+{
+ public PropertyTypeNotFoundException()
+ : base("A property tpye was not found.")
+ {
+ }
+
+ public PropertyTypeNotFoundException(string? typeName)
+ : base($"A property type of name: '{typeName}' was not found.")
+ {
+ this.TypeName = typeName;
+ }
+
+ public PropertyTypeNotFoundException(string? message, Exception? innerException)
+ : base(message, innerException)
+ {
+ }
+
+ public string? TypeName { get; }
+}
diff --git a/FinalEngine.Editor.ViewModels/FinalEngine.Editor.ViewModels.csproj b/FinalEngine.Editor.ViewModels/FinalEngine.Editor.ViewModels.csproj
new file mode 100644
index 00000000..9ea721fa
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/FinalEngine.Editor.ViewModels.csproj
@@ -0,0 +1,37 @@
+
+
+
+ net8.0
+ enable
+ SA0001
+ All
+ false
+ x64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
diff --git a/FinalEngine.Editor.ViewModels/IMainViewModel.cs b/FinalEngine.Editor.ViewModels/IMainViewModel.cs
new file mode 100644
index 00000000..dc264b91
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/IMainViewModel.cs
@@ -0,0 +1,27 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels;
+
+using System.Windows.Input;
+using FinalEngine.Editor.ViewModels.Docking;
+
+public interface IMainViewModel
+{
+ ICommand CreateEntityCommand { get; }
+
+ IDockViewModel DockViewModel { get; }
+
+ ICommand ExitCommand { get; }
+
+ ICommand ManageWindowLayoutsCommand { get; }
+
+ ICommand ResetWindowLayoutCommand { get; }
+
+ ICommand SaveWindowLayoutCommand { get; }
+
+ string Title { get; }
+
+ ICommand ToggleToolWindowCommand { get; }
+}
diff --git a/FinalEngine.Editor.ViewModels/Inspectors/ConsoleToolViewModel.cs b/FinalEngine.Editor.ViewModels/Inspectors/ConsoleToolViewModel.cs
new file mode 100644
index 00000000..1cd56e6a
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Inspectors/ConsoleToolViewModel.cs
@@ -0,0 +1,22 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Inspectors;
+
+using System;
+using FinalEngine.Editor.ViewModels.Docking.Tools;
+using Microsoft.Extensions.Logging;
+
+public sealed class ConsoleToolViewModel : ToolViewModelBase, IConsoleToolViewModel
+{
+ public ConsoleToolViewModel(ILogger logger)
+ {
+ ArgumentNullException.ThrowIfNull(logger, nameof(logger));
+
+ this.Title = "Console";
+ this.ContentID = "Console";
+
+ logger.LogInformation($"Initializing {this.Title}...");
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Inspectors/EntityComponentCategoryViewModel.cs b/FinalEngine.Editor.ViewModels/Inspectors/EntityComponentCategoryViewModel.cs
new file mode 100644
index 00000000..a973eb18
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Inspectors/EntityComponentCategoryViewModel.cs
@@ -0,0 +1,24 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Inspectors;
+
+using System;
+using System.Collections.Generic;
+using CommunityToolkit.Mvvm.ComponentModel;
+
+public sealed class EntityComponentCategoryViewModel : ObservableObject, IEntityComponentCategoryViewModel
+{
+ public EntityComponentCategoryViewModel(string name, IEnumerable componentTypes)
+ {
+ ArgumentException.ThrowIfNullOrWhiteSpace(name, nameof(name));
+
+ this.Name = name;
+ this.ComponentTypes = componentTypes ?? throw new ArgumentNullException(nameof(componentTypes));
+ }
+
+ public IEnumerable ComponentTypes { get; }
+
+ public string Name { get; }
+}
diff --git a/FinalEngine.Editor.ViewModels/Inspectors/EntityComponentTypeViewModel.cs b/FinalEngine.Editor.ViewModels/Inspectors/EntityComponentTypeViewModel.cs
new file mode 100644
index 00000000..b2450750
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Inspectors/EntityComponentTypeViewModel.cs
@@ -0,0 +1,70 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Inspectors;
+
+using System;
+using System.Windows.Input;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using CommunityToolkit.Mvvm.Messaging;
+using FinalEngine.ECS;
+using FinalEngine.Editor.ViewModels.Messages.Entities;
+
+public sealed class EntityComponentTypeViewModel : ObservableObject, IEntityComponentTypeViewModel
+{
+ private readonly Entity entity;
+
+ private readonly IMessenger messenger;
+
+ private readonly Type type;
+
+ private ICommand? addCommand;
+
+ public EntityComponentTypeViewModel(IMessenger messenger, Entity entity, Type type)
+ {
+ ArgumentNullException.ThrowIfNull(type, nameof(type));
+
+ this.messenger = messenger ?? throw new ArgumentNullException(nameof(messenger));
+ this.entity = entity ?? throw new ArgumentNullException(nameof(entity));
+
+ if (!typeof(IEntityComponent).IsAssignableFrom(type))
+ {
+ throw new ArgumentException($"The specified {nameof(type)} parameter does not implement {nameof(IEntityComponent)}.");
+ }
+
+ this.type = type;
+ this.Name = this.type.Name;
+ }
+
+ public ICommand AddCommand
+ {
+ get { return this.addCommand ??= new RelayCommand(this.AddComponent, this.CanAddComponent); }
+ }
+
+ public string Name { get; }
+
+ private void AddComponent()
+ {
+ object? instance = Activator.CreateInstance(this.type) ?? throw new InvalidOperationException($"The entity component couldn't be instantiated for the specified type: '{this.type}'. Please ensure the component contains a default empty constructor.");
+
+ if (instance is not IEntityComponent component)
+ {
+ throw new InvalidCastException($"The created instance of type '{instance.GetType()}' does not implement the {nameof(IEntityComponent)} interface.");
+ }
+
+ if (this.entity.ContainsComponent(this.type))
+ {
+ return;
+ }
+
+ this.entity.AddComponent(component);
+ this.messenger.Send(new EntityModifiedMessage(this.entity));
+ }
+
+ private bool CanAddComponent()
+ {
+ return !this.entity.ContainsComponent(this.type);
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Inspectors/EntityComponentViewModel.cs b/FinalEngine.Editor.ViewModels/Inspectors/EntityComponentViewModel.cs
new file mode 100644
index 00000000..27ce2a1b
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Inspectors/EntityComponentViewModel.cs
@@ -0,0 +1,155 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Inspectors;
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Linq;
+using System.Reflection;
+using System.Windows.Input;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using CommunityToolkit.Mvvm.Messaging;
+using FinalEngine.ECS;
+using FinalEngine.ECS.Components.Core;
+using FinalEngine.Editor.ViewModels.Editing.DataTypes;
+using FinalEngine.Editor.ViewModels.Exceptions.Inspectors;
+using FinalEngine.Editor.ViewModels.Messages.Entities;
+
+public sealed class EntityComponentViewModel : ObservableObject, IEntityComponentViewModel
+{
+ private readonly IEntityComponent component;
+
+ private readonly Entity entity;
+
+ private readonly IMessenger messenger;
+
+ private readonly ObservableCollection propertyViewModels;
+
+ private bool isVisible;
+
+ private ICommand? removeCommand;
+
+ private ICommand? toggleCommand;
+
+ public EntityComponentViewModel(IMessenger messenger, Entity entity, IEntityComponent component)
+ {
+ this.messenger = messenger ?? throw new ArgumentNullException(nameof(messenger));
+ this.entity = entity ?? throw new ArgumentNullException(nameof(entity));
+ this.component = component ?? throw new ArgumentNullException(nameof(component));
+
+ this.propertyViewModels = [];
+
+ this.Name = component.GetType().Name;
+ this.IsVisible = true;
+
+ foreach (var property in component.GetType().GetProperties().OrderBy(x =>
+ {
+ return x.Name;
+ }))
+ {
+ if (property.GetSetMethod() == null || property.GetGetMethod() == null)
+ {
+ continue;
+ }
+
+ var type = property.PropertyType;
+ var browsable = property.GetCustomAttribute();
+
+ if (browsable != null && !browsable.Browsable)
+ {
+ continue;
+ }
+
+ switch (type.Name.ToUpperInvariant())
+ {
+ case "STRING":
+ this.propertyViewModels.Add(new StringPropertyViewModel(component, property));
+ break;
+
+ case "BOOLEAN":
+ this.propertyViewModels.Add(new BoolPropertyViewModel(component, property));
+ break;
+
+ case "INT32":
+ this.propertyViewModels.Add(new IntPropertyViewModel(component, property));
+ break;
+
+ case "DOUBLE":
+ this.propertyViewModels.Add(new DoublePropertyViewModel(component, property));
+ break;
+
+ case "SINGLE":
+ this.propertyViewModels.Add(new FloatPropertyViewModel(component, property));
+ break;
+
+ case "VECTOR2":
+ this.propertyViewModels.Add(new Vector2PropertyViewModel(component, property));
+ break;
+
+ case "VECTOR3":
+ this.propertyViewModels.Add(new Vector3PropertyViewModel(component, property));
+ break;
+
+ case "VECTOR4":
+ this.propertyViewModels.Add(new Vector4PropertyViewModel(component, property));
+ break;
+
+ case "QUATERNION":
+ this.propertyViewModels.Add(new QuaternionPropertyViewModel(component, property));
+ break;
+
+ default:
+ throw new PropertyTypeNotFoundException(type.Name);
+ }
+ }
+ }
+
+ public bool IsVisible
+ {
+ get { return this.isVisible; }
+ private set { this.SetProperty(ref this.isVisible, value); }
+ }
+
+ public string Name { get; }
+
+ public ICollection PropertyViewModels
+ {
+ get { return this.propertyViewModels; }
+ }
+
+ public ICommand RemoveCommand
+ {
+ get { return this.removeCommand ??= new RelayCommand(this.Remove, this.CanRemove); }
+ }
+
+ public ICommand ToggleCommand
+ {
+ get { return this.toggleCommand ??= new RelayCommand(this.Toggle); }
+ }
+
+ private bool CanRemove()
+ {
+ return this.component.GetType() != typeof(TagComponent);
+ }
+
+ private void Remove()
+ {
+ if (!this.entity.ContainsComponent(this.component))
+ {
+ throw new InvalidOperationException($"The {nameof(Entity)} provided to this instance does not contain an {nameof(IEntityComponent)} of type: '{this.component.GetType()}'");
+ }
+
+ this.entity.RemoveComponent(this.component);
+ this.messenger.Send(new EntityModifiedMessage(this.entity));
+ }
+
+ private void Toggle()
+ {
+ this.IsVisible = !this.IsVisible;
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Inspectors/EntityInspectorViewModel.cs b/FinalEngine.Editor.ViewModels/Inspectors/EntityInspectorViewModel.cs
new file mode 100644
index 00000000..b46a0a7f
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Inspectors/EntityInspectorViewModel.cs
@@ -0,0 +1,95 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Inspectors;
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Reflection;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Messaging;
+using FinalEngine.ECS;
+using FinalEngine.ECS.Components.Core;
+using FinalEngine.Editor.ViewModels.Messages.Entities;
+using FinalEngine.Editor.ViewModels.Services.Entities;
+
+public sealed class EntityInspectorViewModel : ObservableObject, IEntityInspectorViewModel
+{
+ private readonly ObservableCollection categorizedComponentTypes;
+
+ private readonly ObservableCollection componentViewModels;
+
+ private readonly Entity entity;
+
+ private readonly IMessenger messenger;
+
+ private readonly IEntityComponentTypeResolver typeResolver;
+
+ public EntityInspectorViewModel(IMessenger messenger, IEntityComponentTypeResolver typeResolver, Entity entity)
+ {
+ this.messenger = messenger ?? throw new ArgumentNullException(nameof(messenger));
+ this.typeResolver = typeResolver ?? throw new ArgumentNullException(nameof(typeResolver));
+ this.entity = entity ?? throw new ArgumentNullException(nameof(entity));
+
+ this.componentViewModels = [];
+ this.categorizedComponentTypes = [];
+
+ this.messenger.Register(this, this.HandleEntityModified);
+
+ this.InitializeEntityComponents();
+ this.IntializeComponentTypes();
+ }
+
+ public ICollection CategorizedComponentTypes
+ {
+ get { return this.categorizedComponentTypes; }
+ }
+
+ public ICollection ComponentViewModels
+ {
+ get { return this.componentViewModels; }
+ }
+
+ private void HandleEntityModified(object recipient, EntityModifiedMessage message)
+ {
+ if (!ReferenceEquals(this.entity, message.Entity))
+ {
+ return;
+ }
+
+ this.InitializeEntityComponents();
+ this.IntializeComponentTypes();
+ }
+
+ private void InitializeEntityComponents()
+ {
+ this.componentViewModels.Clear();
+
+ foreach (var component in this.entity.Components)
+ {
+ this.componentViewModels.Add(new EntityComponentViewModel(this.messenger, this.entity, component));
+ }
+ }
+
+ private void IntializeComponentTypes()
+ {
+ this.categorizedComponentTypes.Clear();
+
+ var assembly = Assembly.GetAssembly(typeof(TagComponent)) ?? throw new TypeAccessException("Failed to initialize core engine components.");
+
+ var categoryToTypeMap = this.typeResolver.GetCategorizedTypes(assembly);
+
+ foreach (var kvp in categoryToTypeMap)
+ {
+ var typeViewModels = kvp.Value.Select(x =>
+ {
+ return new EntityComponentTypeViewModel(this.messenger, this.entity, x);
+ });
+
+ this.categorizedComponentTypes.Add(new EntityComponentCategoryViewModel(kvp.Key, typeViewModels));
+ }
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Inspectors/IConsoleToolViewModel.cs b/FinalEngine.Editor.ViewModels/Inspectors/IConsoleToolViewModel.cs
new file mode 100644
index 00000000..9746981b
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Inspectors/IConsoleToolViewModel.cs
@@ -0,0 +1,11 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Inspectors;
+
+using FinalEngine.Editor.ViewModels.Docking.Tools;
+
+public interface IConsoleToolViewModel : IToolViewModel
+{
+}
diff --git a/FinalEngine.Editor.ViewModels/Inspectors/IEntityComponentCategoryViewModel.cs b/FinalEngine.Editor.ViewModels/Inspectors/IEntityComponentCategoryViewModel.cs
new file mode 100644
index 00000000..230c3b62
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Inspectors/IEntityComponentCategoryViewModel.cs
@@ -0,0 +1,14 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Inspectors;
+
+using System.Collections.Generic;
+
+public interface IEntityComponentCategoryViewModel
+{
+ IEnumerable ComponentTypes { get; }
+
+ string Name { get; }
+}
diff --git a/FinalEngine.Editor.ViewModels/Inspectors/IEntityComponentTypeViewModel.cs b/FinalEngine.Editor.ViewModels/Inspectors/IEntityComponentTypeViewModel.cs
new file mode 100644
index 00000000..86d3bcff
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Inspectors/IEntityComponentTypeViewModel.cs
@@ -0,0 +1,14 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Inspectors;
+
+using System.Windows.Input;
+
+public interface IEntityComponentTypeViewModel
+{
+ ICommand AddCommand { get; }
+
+ string Name { get; }
+}
diff --git a/FinalEngine.Editor.ViewModels/Inspectors/IEntityComponentViewModel.cs b/FinalEngine.Editor.ViewModels/Inspectors/IEntityComponentViewModel.cs
new file mode 100644
index 00000000..cbab4717
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Inspectors/IEntityComponentViewModel.cs
@@ -0,0 +1,22 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Inspectors;
+
+using System.Collections.Generic;
+using System.Windows.Input;
+using CommunityToolkit.Mvvm.ComponentModel;
+
+public interface IEntityComponentViewModel
+{
+ bool IsVisible { get; }
+
+ string Name { get; }
+
+ ICollection PropertyViewModels { get; }
+
+ ICommand RemoveCommand { get; }
+
+ ICommand ToggleCommand { get; }
+}
diff --git a/FinalEngine.Editor.ViewModels/Inspectors/IEntityInspectorViewModel.cs b/FinalEngine.Editor.ViewModels/Inspectors/IEntityInspectorViewModel.cs
new file mode 100644
index 00000000..091d08e1
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Inspectors/IEntityInspectorViewModel.cs
@@ -0,0 +1,14 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Inspectors;
+
+using System.Collections.Generic;
+
+public interface IEntityInspectorViewModel
+{
+ ICollection CategorizedComponentTypes { get; }
+
+ ICollection ComponentViewModels { get; }
+}
diff --git a/FinalEngine.Editor.ViewModels/Inspectors/IPropertiesToolViewModel.cs b/FinalEngine.Editor.ViewModels/Inspectors/IPropertiesToolViewModel.cs
new file mode 100644
index 00000000..fbb1f4fb
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Inspectors/IPropertiesToolViewModel.cs
@@ -0,0 +1,13 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Inspectors;
+
+using CommunityToolkit.Mvvm.ComponentModel;
+using FinalEngine.Editor.ViewModels.Docking.Tools;
+
+public interface IPropertiesToolViewModel : IToolViewModel
+{
+ ObservableObject? CurrentViewModel { get; }
+}
diff --git a/FinalEngine.Editor.ViewModels/Inspectors/PropertiesToolViewModel.cs b/FinalEngine.Editor.ViewModels/Inspectors/PropertiesToolViewModel.cs
new file mode 100644
index 00000000..bde62c5d
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Inspectors/PropertiesToolViewModel.cs
@@ -0,0 +1,69 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Inspectors;
+
+using System;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Messaging;
+using FinalEngine.Editor.ViewModels.Docking.Tools;
+using FinalEngine.Editor.ViewModels.Messages.Entities;
+using FinalEngine.Editor.ViewModels.Services.Entities;
+using Microsoft.Extensions.Logging;
+
+public sealed class PropertiesToolViewModel : ToolViewModelBase, IPropertiesToolViewModel
+{
+ private readonly ILogger logger;
+
+ private readonly IMessenger messenger;
+
+ private readonly IEntityComponentTypeResolver typeResolver;
+
+ private ObservableObject? currentViewModel;
+
+ public PropertiesToolViewModel(
+ ILogger logger,
+ IEntityComponentTypeResolver typeResolver,
+ IMessenger messenger)
+ {
+ this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ this.typeResolver = typeResolver ?? throw new ArgumentNullException(nameof(typeResolver));
+ this.messenger = messenger ?? throw new ArgumentNullException(nameof(messenger));
+
+ this.Title = "Properties";
+ this.ContentID = "Properties";
+
+ this.logger.LogInformation($"Initializing {this.Title}...");
+
+ this.messenger.Register(this, this.HandleEntitySelected);
+ this.messenger.Register(this, this.HandleEntityDeleted);
+ }
+
+ public ObservableObject? CurrentViewModel
+ {
+ get { return this.currentViewModel; }
+ private set { this.SetProperty(ref this.currentViewModel, value); }
+ }
+
+ private void HandleEntityDeleted(object recipient, EntityDeletedMessage message)
+ {
+ this.ResetCurrentViewModel();
+ }
+
+ private void HandleEntitySelected(object recipient, EntitySelectedMessage message)
+ {
+ this.logger.LogInformation($"Changing properties view to: '{nameof(EntityInspectorViewModel)}'.");
+
+ this.Title = "Entity Inspector";
+ this.CurrentViewModel = new EntityInspectorViewModel(this.messenger, this.typeResolver, message.Entity);
+ }
+
+ private void ResetCurrentViewModel()
+ {
+ this.logger.LogInformation($"Reseting the properties view to: `{nameof(PropertiesToolViewModel)}`.");
+
+ this.Title = "Properties";
+ this.CurrentViewModel = null;
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/MainViewModel.cs b/FinalEngine.Editor.ViewModels/MainViewModel.cs
new file mode 100644
index 00000000..1a2b708e
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/MainViewModel.cs
@@ -0,0 +1,133 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels;
+
+using System;
+using System.Windows.Input;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using FinalEngine.Editor.Common.Services.Application;
+using FinalEngine.Editor.Common.Services.Factories;
+using FinalEngine.Editor.ViewModels.Dialogs.Entities;
+using FinalEngine.Editor.ViewModels.Dialogs.Layout;
+using FinalEngine.Editor.ViewModels.Docking;
+using FinalEngine.Editor.ViewModels.Services;
+using FinalEngine.Editor.ViewModels.Services.Interactions;
+using FinalEngine.Editor.ViewModels.Services.Layout;
+using Microsoft.Extensions.Logging;
+
+public sealed class MainViewModel : ObservableObject, IMainViewModel
+{
+ private readonly ILayoutManager layoutManager;
+
+ private readonly ILogger logger;
+
+ private readonly IViewPresenter viewPresenter;
+
+ private ICommand? createEntityCommand;
+
+ private ICommand? exitCommand;
+
+ private ICommand? manageWindowLayoutsCommand;
+
+ private ICommand? resetWindowLayoutCommand;
+
+ private ICommand? saveWindowLayoutCommand;
+
+ private ICommand? toggleToolWindowCommand;
+
+ public MainViewModel(
+ ILogger logger,
+ IViewPresenter viewPresenter,
+ IApplicationContext applicationContext,
+ ILayoutManager layoutManager,
+ IFactory dockViewModelFactory)
+ {
+ ArgumentNullException.ThrowIfNull(applicationContext, nameof(applicationContext));
+ ArgumentNullException.ThrowIfNull(dockViewModelFactory, nameof(dockViewModelFactory));
+
+ this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ this.viewPresenter = viewPresenter ?? throw new ArgumentNullException(nameof(viewPresenter));
+ this.layoutManager = layoutManager ?? throw new ArgumentNullException(nameof(layoutManager));
+
+ this.DockViewModel = dockViewModelFactory.Create();
+ this.Title = applicationContext.Title;
+ }
+
+ public ICommand CreateEntityCommand
+ {
+ get { return this.createEntityCommand ??= new RelayCommand(this.CreateEntity); }
+ }
+
+ public IDockViewModel DockViewModel { get; }
+
+ public ICommand ExitCommand
+ {
+ get { return this.exitCommand ??= new RelayCommand(this.Close); }
+ }
+
+ public ICommand ManageWindowLayoutsCommand
+ {
+ get { return this.manageWindowLayoutsCommand ??= new RelayCommand(this.ShowManageWindowLayoutsView); }
+ }
+
+ public ICommand ResetWindowLayoutCommand
+ {
+ get { return this.resetWindowLayoutCommand ??= new RelayCommand(this.ResetWindowLayout); }
+ }
+
+ public ICommand SaveWindowLayoutCommand
+ {
+ get { return this.saveWindowLayoutCommand ??= new RelayCommand(this.ShowSaveWindowLayoutView); }
+ }
+
+ public string Title { get; }
+
+ public ICommand ToggleToolWindowCommand
+ {
+ get { return this.toggleToolWindowCommand ??= new RelayCommand(this.ToggleToolWindow); }
+ }
+
+ private void Close(ICloseable? closeable)
+ {
+ ArgumentNullException.ThrowIfNull(closeable, nameof(closeable));
+
+ this.logger.LogInformation($"Closing {nameof(MainViewModel)}...");
+
+ closeable.Close();
+ }
+
+ private void CreateEntity()
+ {
+ this.viewPresenter.ShowView();
+ }
+
+ private void ResetWindowLayout()
+ {
+ this.layoutManager.ResetLayout();
+ }
+
+ private void ShowManageWindowLayoutsView()
+ {
+ this.viewPresenter.ShowView();
+ }
+
+ private void ShowSaveWindowLayoutView()
+ {
+ this.viewPresenter.ShowView();
+ }
+
+ private void ToggleToolWindow(string? contentID)
+ {
+ this.logger.LogInformation($"Toggling tool view with ID: '{contentID}'...");
+
+ if (string.IsNullOrWhiteSpace(contentID))
+ {
+ throw new ArgumentException($"'{nameof(contentID)}' cannot be null or whitespace.", nameof(contentID));
+ }
+
+ this.layoutManager.ToggleToolWindow(contentID);
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Messages/Entities/EntityDeletedMessage.cs b/FinalEngine.Editor.ViewModels/Messages/Entities/EntityDeletedMessage.cs
new file mode 100644
index 00000000..e0de091b
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Messages/Entities/EntityDeletedMessage.cs
@@ -0,0 +1,9 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Messages.Entities;
+
+public sealed class EntityDeletedMessage
+{
+}
diff --git a/FinalEngine.Editor.ViewModels/Messages/Entities/EntityModifiedMessage.cs b/FinalEngine.Editor.ViewModels/Messages/Entities/EntityModifiedMessage.cs
new file mode 100644
index 00000000..c61b3b82
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Messages/Entities/EntityModifiedMessage.cs
@@ -0,0 +1,18 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Messages.Entities;
+
+using System;
+using FinalEngine.ECS;
+
+public sealed class EntityModifiedMessage
+{
+ public EntityModifiedMessage(Entity entity)
+ {
+ this.Entity = entity ?? throw new ArgumentNullException(nameof(entity));
+ }
+
+ public Entity Entity { get; }
+}
diff --git a/FinalEngine.Editor.ViewModels/Messages/Entities/EntitySelectedMessage.cs b/FinalEngine.Editor.ViewModels/Messages/Entities/EntitySelectedMessage.cs
new file mode 100644
index 00000000..f1cb7077
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Messages/Entities/EntitySelectedMessage.cs
@@ -0,0 +1,18 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Messages.Entities;
+
+using System;
+using FinalEngine.ECS;
+
+public sealed class EntitySelectedMessage
+{
+ public EntitySelectedMessage(Entity entity)
+ {
+ this.Entity = entity ?? throw new ArgumentNullException(nameof(entity));
+ }
+
+ public Entity Entity { get; }
+}
diff --git a/FinalEngine.Editor.ViewModels/Projects/IProjectExplorerToolViewModel.cs b/FinalEngine.Editor.ViewModels/Projects/IProjectExplorerToolViewModel.cs
new file mode 100644
index 00000000..74c21aa7
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Projects/IProjectExplorerToolViewModel.cs
@@ -0,0 +1,11 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Projects;
+
+using FinalEngine.Editor.ViewModels.Docking.Tools;
+
+public interface IProjectExplorerToolViewModel : IToolViewModel
+{
+}
diff --git a/FinalEngine.Editor.ViewModels/Projects/ProjectExplorerToolViewModel.cs b/FinalEngine.Editor.ViewModels/Projects/ProjectExplorerToolViewModel.cs
new file mode 100644
index 00000000..0bca1b20
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Projects/ProjectExplorerToolViewModel.cs
@@ -0,0 +1,22 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Projects;
+
+using System;
+using FinalEngine.Editor.ViewModels.Docking.Tools;
+using Microsoft.Extensions.Logging;
+
+public sealed class ProjectExplorerToolViewModel : ToolViewModelBase, IProjectExplorerToolViewModel
+{
+ public ProjectExplorerToolViewModel(ILogger logger)
+ {
+ ArgumentNullException.ThrowIfNull(logger, nameof(logger));
+
+ this.Title = "Project Explorer";
+ this.ContentID = "ProjectExplorer";
+
+ logger.LogInformation($"Initializing {this.Title}...");
+ }
+}
diff --git a/FinalEngine.Rendering.Vapor/Properties/AssemblyInfo.cs b/FinalEngine.Editor.ViewModels/Properties/AssemblyInfo.cs
similarity index 51%
rename from FinalEngine.Rendering.Vapor/Properties/AssemblyInfo.cs
rename to FinalEngine.Editor.ViewModels/Properties/AssemblyInfo.cs
index 2b1a46e6..8d81eb98 100644
--- a/FinalEngine.Rendering.Vapor/Properties/AssemblyInfo.cs
+++ b/FinalEngine.Editor.ViewModels/Properties/AssemblyInfo.cs
@@ -8,6 +8,6 @@
[assembly: CLSCompliant(false)]
[assembly: ComVisible(false)]
-[assembly: AssemblyTitle("FinalEngine.Rendering.Vapor")]
-[assembly: AssemblyDescription("A core rendering engine built ontop of the rendering API layer used to render complex scenes for Final Engine games.")]
-[assembly: Guid("EB798584-20CE-4C99-BD08-2D3A872BCFA2")]
+[assembly: AssemblyTitle("FinalEngine.Editor.ViewModels")]
+[assembly: AssemblyDescription("A library containing view models for the Final Engine editor.")]
+[assembly: Guid("BDA4CEFA-DD44-4FD7-AE54-330C571809C9")]
diff --git a/FinalEngine.Editor.ViewModels/Scenes/EntitySystemsToolViewModel.cs b/FinalEngine.Editor.ViewModels/Scenes/EntitySystemsToolViewModel.cs
new file mode 100644
index 00000000..27cf90a4
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Scenes/EntitySystemsToolViewModel.cs
@@ -0,0 +1,22 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Scenes;
+
+using System;
+using FinalEngine.Editor.ViewModels.Docking.Tools;
+using Microsoft.Extensions.Logging;
+
+public sealed class EntitySystemsToolViewModel : ToolViewModelBase, IEntitySystemsToolViewModel
+{
+ public EntitySystemsToolViewModel(ILogger logger)
+ {
+ ArgumentNullException.ThrowIfNull(logger, nameof(logger));
+
+ this.Title = "Entity Systems";
+ this.ContentID = "EntitySystems";
+
+ logger.LogInformation($"Initializing {this.Title}...");
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Scenes/IEntitySystemsToolViewModel.cs b/FinalEngine.Editor.ViewModels/Scenes/IEntitySystemsToolViewModel.cs
new file mode 100644
index 00000000..3e089906
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Scenes/IEntitySystemsToolViewModel.cs
@@ -0,0 +1,11 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Scenes;
+
+using FinalEngine.Editor.ViewModels.Docking.Tools;
+
+public interface IEntitySystemsToolViewModel : IToolViewModel
+{
+}
diff --git a/FinalEngine.Editor.ViewModels/Scenes/ISceneHierarchyToolViewModel.cs b/FinalEngine.Editor.ViewModels/Scenes/ISceneHierarchyToolViewModel.cs
new file mode 100644
index 00000000..362a8de1
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Scenes/ISceneHierarchyToolViewModel.cs
@@ -0,0 +1,19 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Scenes;
+
+using System.Collections.Generic;
+using CommunityToolkit.Mvvm.Input;
+using FinalEngine.ECS;
+using FinalEngine.Editor.ViewModels.Docking.Tools;
+
+public interface ISceneHierarchyToolViewModel : IToolViewModel
+{
+ IRelayCommand DeleteEntityCommand { get; }
+
+ IReadOnlyCollection Entities { get; }
+
+ Entity? SelectedEntity { get; set; }
+}
diff --git a/FinalEngine.Editor.ViewModels/Scenes/ISceneViewPaneViewModel.cs b/FinalEngine.Editor.ViewModels/Scenes/ISceneViewPaneViewModel.cs
new file mode 100644
index 00000000..7694b6e8
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Scenes/ISceneViewPaneViewModel.cs
@@ -0,0 +1,13 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Scenes;
+
+using System.Windows.Input;
+using FinalEngine.Editor.ViewModels.Docking.Panes;
+
+public interface ISceneViewPaneViewModel : IPaneViewModel
+{
+ ICommand RenderCommand { get; }
+}
diff --git a/FinalEngine.Editor.ViewModels/Scenes/SceneHierarchyToolViewModel.cs b/FinalEngine.Editor.ViewModels/Scenes/SceneHierarchyToolViewModel.cs
new file mode 100644
index 00000000..a1aebf59
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Scenes/SceneHierarchyToolViewModel.cs
@@ -0,0 +1,88 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Scenes;
+
+using System;
+using System.Collections.Generic;
+using CommunityToolkit.Mvvm.Input;
+using CommunityToolkit.Mvvm.Messaging;
+using FinalEngine.ECS;
+using FinalEngine.Editor.Common.Services.Scenes;
+using FinalEngine.Editor.ViewModels.Docking.Tools;
+using FinalEngine.Editor.ViewModels.Messages.Entities;
+using Microsoft.Extensions.Logging;
+
+public sealed class SceneHierarchyToolViewModel : ToolViewModelBase, ISceneHierarchyToolViewModel
+{
+ private readonly ILogger logger;
+
+ private readonly IMessenger messenger;
+
+ private readonly ISceneManager sceneManager;
+
+ private IRelayCommand? deleteEntityCommand;
+
+ private Entity? selectedEntity;
+
+ public SceneHierarchyToolViewModel(
+ ILogger logger,
+ IMessenger messenger,
+ ISceneManager sceneManager)
+ {
+ this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ this.messenger = messenger ?? throw new ArgumentNullException(nameof(messenger));
+ this.sceneManager = sceneManager ?? throw new ArgumentNullException(nameof(sceneManager));
+
+ this.Title = "Scene Hierarchy";
+ this.ContentID = "SceneHierarchy";
+
+ this.logger.LogInformation($"Initializing {this.Title}...");
+ }
+
+ public IRelayCommand DeleteEntityCommand
+ {
+ get { return this.deleteEntityCommand ??= new RelayCommand(this.DeleteEntity, this.CanDeleteEntity); }
+ }
+
+ public IReadOnlyCollection Entities
+ {
+ get { return this.sceneManager.ActiveScene.Entities; }
+ }
+
+ public Entity? SelectedEntity
+ {
+ get
+ {
+ return this.selectedEntity;
+ }
+
+ set
+ {
+ this.SetProperty(ref this.selectedEntity, value);
+ this.DeleteEntityCommand.NotifyCanExecuteChanged();
+
+ if (this.SelectedEntity != null)
+ {
+ this.messenger.Send(new EntitySelectedMessage(this.SelectedEntity));
+ }
+ }
+ }
+
+ private bool CanDeleteEntity()
+ {
+ return this.SelectedEntity != null;
+ }
+
+ private void DeleteEntity()
+ {
+ if (this.SelectedEntity == null)
+ {
+ return;
+ }
+
+ this.sceneManager.ActiveScene.RemoveEntity(this.SelectedEntity.UniqueIdentifier);
+ this.messenger.Send(new EntityDeletedMessage());
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Scenes/SceneViewPaneViewModel.cs b/FinalEngine.Editor.ViewModels/Scenes/SceneViewPaneViewModel.cs
new file mode 100644
index 00000000..4cb3b4ee
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Scenes/SceneViewPaneViewModel.cs
@@ -0,0 +1,43 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Scenes;
+
+using System;
+using System.Windows.Input;
+using CommunityToolkit.Mvvm.Input;
+using FinalEngine.Editor.Common.Services.Scenes;
+using FinalEngine.Editor.ViewModels.Docking.Panes;
+using Microsoft.Extensions.Logging;
+
+public sealed class SceneViewPaneViewModel : PaneViewModelBase, ISceneViewPaneViewModel
+{
+ private readonly ISceneRenderer sceneRenderer;
+
+ private ICommand? renderCommand;
+
+ public SceneViewPaneViewModel(
+ ILogger logger,
+ ISceneRenderer sceneRenderer)
+ {
+ ArgumentNullException.ThrowIfNull(logger, nameof(logger));
+
+ this.sceneRenderer = sceneRenderer ?? throw new ArgumentNullException(nameof(sceneRenderer));
+
+ this.Title = "Scene View";
+ this.ContentID = "SceneView";
+
+ logger.LogInformation($"Initializing {this.Title}...");
+ }
+
+ public ICommand RenderCommand
+ {
+ get { return this.renderCommand ??= new RelayCommand(this.Render); }
+ }
+
+ private void Render()
+ {
+ this.sceneRenderer.Render();
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Services/Actions/IUserActionRequester.cs b/FinalEngine.Editor.ViewModels/Services/Actions/IUserActionRequester.cs
new file mode 100644
index 00000000..5ce0c0a2
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Services/Actions/IUserActionRequester.cs
@@ -0,0 +1,12 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Services.Actions;
+
+public interface IUserActionRequester
+{
+ void RequestOk(string caption, string message);
+
+ bool RequestYesNo(string caption, string message);
+}
diff --git a/FinalEngine.Editor.ViewModels/Services/Entities/EntityComponentTypeResolver.cs b/FinalEngine.Editor.ViewModels/Services/Entities/EntityComponentTypeResolver.cs
new file mode 100644
index 00000000..406a1052
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Services/Entities/EntityComponentTypeResolver.cs
@@ -0,0 +1,44 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Services.Entities;
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Reflection;
+using FinalEngine.ECS;
+
+public sealed class EntityComponentTypeResolver : IEntityComponentTypeResolver
+{
+ public IReadOnlyDictionary> GetCategorizedTypes(Assembly assembly)
+ {
+ ArgumentNullException.ThrowIfNull(assembly, nameof(assembly));
+
+ var categoryToTypeMap = new Dictionary>();
+
+ var componentTypes = assembly.GetTypes()
+ .Where(x =>
+ {
+ return typeof(IEntityComponent).IsAssignableFrom(x) && x.GetConstructor(Type.EmptyTypes) != null;
+ });
+
+ foreach (var componentType in componentTypes)
+ {
+ var categoryAttribute = componentType.GetCustomAttribute();
+ string category = categoryAttribute?.Category ?? "Uncategorized";
+
+ if (!categoryToTypeMap.TryGetValue(category, out var types))
+ {
+ types = [];
+ categoryToTypeMap.Add(category, types);
+ }
+
+ types.Add(componentType);
+ }
+
+ return categoryToTypeMap;
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Services/Entities/IEntityComponentTypeResolver.cs b/FinalEngine.Editor.ViewModels/Services/Entities/IEntityComponentTypeResolver.cs
new file mode 100644
index 00000000..dbcbf793
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Services/Entities/IEntityComponentTypeResolver.cs
@@ -0,0 +1,14 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Services.Entities;
+
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+
+public interface IEntityComponentTypeResolver
+{
+ IReadOnlyDictionary> GetCategorizedTypes(Assembly assembly);
+}
diff --git a/FinalEngine.Editor.ViewModels/Services/IViewPresenter.cs b/FinalEngine.Editor.ViewModels/Services/IViewPresenter.cs
new file mode 100644
index 00000000..2380a7f4
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Services/IViewPresenter.cs
@@ -0,0 +1,12 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Services;
+
+public interface IViewPresenter
+{
+ void ShowView();
+
+ void ShowView(TViewModel viewModel);
+}
diff --git a/FinalEngine.Editor.ViewModels/Services/Interactions/ICloseable.cs b/FinalEngine.Editor.ViewModels/Services/Interactions/ICloseable.cs
new file mode 100644
index 00000000..993be0d4
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Services/Interactions/ICloseable.cs
@@ -0,0 +1,10 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Services.Interactions;
+
+public interface ICloseable
+{
+ void Close();
+}
diff --git a/FinalEngine.Editor.ViewModels/Services/Interactions/IViewable.cs b/FinalEngine.Editor.ViewModels/Services/Interactions/IViewable.cs
new file mode 100644
index 00000000..a8fefaf8
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Services/Interactions/IViewable.cs
@@ -0,0 +1,12 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Services.Interactions;
+
+public interface IViewable
+{
+ object DataContext { get; set; }
+
+ bool? ShowDialog();
+}
diff --git a/FinalEngine.Editor.ViewModels/Services/Layout/ILayoutManager.cs b/FinalEngine.Editor.ViewModels/Services/Layout/ILayoutManager.cs
new file mode 100644
index 00000000..04489176
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Services/Layout/ILayoutManager.cs
@@ -0,0 +1,24 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Services.Layout;
+
+using System.Collections.Generic;
+
+public interface ILayoutManager
+{
+ bool ContainsLayout(string layoutName);
+
+ void DeleteLayout(string layoutName);
+
+ void LoadLayout(string layoutName);
+
+ IEnumerable LoadLayoutNames();
+
+ void ResetLayout();
+
+ void SaveLayout(string layoutName);
+
+ void ToggleToolWindow(string contentID);
+}
diff --git a/FinalEngine.Editor.ViewModels/Services/ViewPresenter.cs b/FinalEngine.Editor.ViewModels/Services/ViewPresenter.cs
new file mode 100644
index 00000000..eec21479
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Services/ViewPresenter.cs
@@ -0,0 +1,48 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Services;
+
+using System;
+using FinalEngine.Editor.Common.Services.Factories;
+using FinalEngine.Editor.ViewModels.Services.Interactions;
+using Microsoft.Extensions.Logging;
+
+public sealed class ViewPresenter : IViewPresenter
+{
+ private readonly ILogger logger;
+
+ private readonly IServiceProvider provider;
+
+ public ViewPresenter(ILogger logger, IServiceProvider provider)
+ {
+ this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ this.provider = provider ?? throw new ArgumentNullException(nameof(provider));
+ }
+
+ public void ShowView()
+ {
+ if (this.provider.GetService(typeof(IFactory)) is not IFactory factory)
+ {
+ throw new ArgumentException($"The specified {nameof(TViewModel)} has not been registered with an {nameof(IFactory)}.");
+ }
+
+ this.ShowView(factory.Create());
+ }
+
+ public void ShowView(TViewModel viewModel)
+ {
+ ArgumentNullException.ThrowIfNull(viewModel, nameof(viewModel));
+
+ this.logger.LogInformation($"Showing dialog view for {typeof(TViewModel)}...");
+
+ if (this.provider.GetService(typeof(IViewable)) is not IViewable view)
+ {
+ throw new ArgumentException($"The specified {nameof(TViewModel)} couldn't be converted to an {nameof(IViewable)}.");
+ }
+
+ view.DataContext = viewModel;
+ view.ShowDialog();
+ }
+}
diff --git a/FinalEngine.Editor.ViewModels/Validation/FileNameAttribute.cs b/FinalEngine.Editor.ViewModels/Validation/FileNameAttribute.cs
new file mode 100644
index 00000000..8d1b8a40
--- /dev/null
+++ b/FinalEngine.Editor.ViewModels/Validation/FileNameAttribute.cs
@@ -0,0 +1,46 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Editor.ViewModels.Validation;
+
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.IO.Abstractions;
+
+public sealed class FileNameAttribute : ValidationAttribute
+{
+ public FileNameAttribute()
+ : this(new FileSystem())
+ {
+ }
+
+ public FileNameAttribute(IFileSystem fileSystem)
+ {
+ this.FileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem));
+ }
+
+ public IFileSystem FileSystem { get; }
+
+ protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
+ {
+ if (value == null)
+ {
+ return new ValidationResult(this.ErrorMessage);
+ }
+
+ string? fileName = value.ToString();
+
+ if (string.IsNullOrWhiteSpace(fileName))
+ {
+ return new ValidationResult(this.ErrorMessage);
+ }
+
+ if (fileName.IndexOfAny(this.FileSystem.Path.GetInvalidFileNameChars()) < 0)
+ {
+ return ValidationResult.Success;
+ }
+
+ return new ValidationResult(this.ErrorMessage);
+ }
+}
diff --git a/FinalEngine.Examples.Sponza/Camera.cs b/FinalEngine.Examples.Sponza/Camera.cs
index 00b06cb8..cd79d017 100644
--- a/FinalEngine.Examples.Sponza/Camera.cs
+++ b/FinalEngine.Examples.Sponza/Camera.cs
@@ -6,7 +6,7 @@ namespace FinalEngine.Examples.Sponza;
using FinalEngine.Input.Mouses;
using FinalEngine.Maths;
using FinalEngine.Rendering;
-using FinalEngine.Rendering.Vapor.Core;
+using FinalEngine.Rendering.Core;
public sealed class Camera : ICamera
{
diff --git a/FinalEngine.Examples.Sponza/FinalEngine.Examples.Sponza.csproj b/FinalEngine.Examples.Sponza/FinalEngine.Examples.Sponza.csproj
index 18b163ff..19c87be5 100644
--- a/FinalEngine.Examples.Sponza/FinalEngine.Examples.Sponza.csproj
+++ b/FinalEngine.Examples.Sponza/FinalEngine.Examples.Sponza.csproj
@@ -16,7 +16,6 @@
-
diff --git a/FinalEngine.Examples.Sponza/Loaders/ModelResourceLoader.cs b/FinalEngine.Examples.Sponza/Loaders/ModelResourceLoader.cs
index 5af26e4f..6dd07156 100644
--- a/FinalEngine.Examples.Sponza/Loaders/ModelResourceLoader.cs
+++ b/FinalEngine.Examples.Sponza/Loaders/ModelResourceLoader.cs
@@ -7,12 +7,12 @@ namespace FinalEngine.Examples.Sponza.Loaders;
using System.Numerics;
using Assimp;
using FinalEngine.Rendering;
+using FinalEngine.Rendering.Geometry;
+using FinalEngine.Rendering.Primitives;
using FinalEngine.Rendering.Textures;
-using FinalEngine.Rendering.Vapor.Geometry;
-using FinalEngine.Rendering.Vapor.Primitives;
using FinalEngine.Resources;
-using Material = Rendering.Vapor.Geometry.Material;
-using Mesh = Rendering.Vapor.Geometry.Mesh;
+using Material = Rendering.Geometry.Material;
+using Mesh = Rendering.Geometry.Mesh;
public class ModelResource : IResource
{
diff --git a/FinalEngine.Examples.Sponza/Program.cs b/FinalEngine.Examples.Sponza/Program.cs
index dc8b96b6..ded172b4 100644
--- a/FinalEngine.Examples.Sponza/Program.cs
+++ b/FinalEngine.Examples.Sponza/Program.cs
@@ -6,20 +6,17 @@
using FinalEngine.Examples.Sponza.Loaders;
using FinalEngine.Input.Keyboards;
using FinalEngine.Input.Mouses;
-using FinalEngine.Maths;
using FinalEngine.Platform.Desktop.OpenTK;
using FinalEngine.Platform.Desktop.OpenTK.Invocation;
+using FinalEngine.Rendering;
+using FinalEngine.Rendering.Core;
+using FinalEngine.Rendering.Geometry;
+using FinalEngine.Rendering.Loaders.Shaders;
+using FinalEngine.Rendering.Loaders.Textures;
using FinalEngine.Rendering.OpenGL;
using FinalEngine.Rendering.OpenGL.Invocation;
-using FinalEngine.Rendering.Textures;
-using FinalEngine.Rendering.Vapor;
-using FinalEngine.Rendering.Vapor.Core;
-using FinalEngine.Rendering.Vapor.Geometry;
-using FinalEngine.Rendering.Vapor.Lighting;
-using FinalEngine.Rendering.Vapor.Loaders.Shaders;
-using FinalEngine.Rendering.Vapor.Loaders.Textures;
-using FinalEngine.Rendering.Vapor.Primitives;
-using FinalEngine.Rendering.Vapor.Renderers;
+using FinalEngine.Rendering.Primitives;
+using FinalEngine.Rendering.Renderers;
using FinalEngine.Resources;
using FinalEngine.Runtime;
using FinalEngine.Runtime.Invocation;
@@ -140,47 +137,8 @@ private static void Main()
var lightRenderer = new LightRenderer(renderDevice.Pipeline);
var renderingEngine = new RenderingEngine(renderDevice, geometryRenderer, lightRenderer);
- var light1 = new Light()
- {
- Color = new Vector3(1.0f, 0.0f, 0.0f),
- };
-
- var light2 = new Light()
- {
- Color = new Vector3(0.0f, 1.0f, 0.0f),
- };
-
- var light3 = new Light()
- {
- Color = new Vector3(0.0f, 0.0f, 1.0f),
- };
-
- var light4 = new Light()
- {
- Color = new Vector3(1.0f, 0.0f, 1.0f),
- };
-
- float move = 0.0f;
-
var modelResource = ResourceManager.Instance.LoadResource("Resources\\Models\\Dabrovic\\Sponza.obj");
- var colorTarget = renderDevice.Factory.CreateTexture2D(
- new Texture2DDescription()
- {
- GenerateMipmaps = false,
- Height = window.ClientSize.Height,
- Width = window.ClientSize.Width,
- MinFilter = TextureFilterMode.Linear,
- MagFilter = TextureFilterMode.Linear,
- PixelType = PixelType.Byte,
- WrapS = TextureWrapMode.Clamp,
- WrapT = TextureWrapMode.Clamp,
- },
- null);
-
- var renderTarget = renderDevice.Factory.CreateFrameBuffer(
- new[] { colorTarget });
-
while (isRunning)
{
if (!gameTime.CanProcessNextFrame())
@@ -195,8 +153,6 @@ private static void Main()
keyboard.Update();
mouse.Update();
- //renderDevice.Pipeline.SetFrameBuffer(renderTarget);
-
foreach (var model in modelResource.Models)
{
renderingEngine.Enqueue(model, new Transform()
@@ -205,58 +161,8 @@ private static void Main()
});
}
- //renderingEngine.Enqueue(new Model()
- //{
- // Mesh = mesh,
- // Material = material,
- //}, new Transform()
- //{
- // Scale = new Vector3(20, 20, 20),
- //});
-
- renderingEngine.Enqueue(new Light()
- {
- Type = LightType.Spot,
- Color = new Vector3(1.0f),
- Intensity = 0.8f,
- Position = camera.Transform.Position,
- Direction = camera.Transform.Forward,
- Attenuation = new Attenuation()
- {
- Linear = 0.014f,
- Quadratic = 0.0007f,
- }
- });
-
- move += 0.4f;
-
- float cos = MathF.Cos(MathHelper.DegreesToRadians(move));
-
- light1.Position = new Vector3(cos * 40, 10, -cos * 40);
- light2.Position = new Vector3(-cos * 40, 10, cos * 40);
- light3.Position = new Vector3(-cos * 40, 10, -cos * 40);
- light4.Position = new Vector3(cos * 40, 10, cos * 40);
-
- renderingEngine.Enqueue(light1);
- renderingEngine.Enqueue(light2);
- renderingEngine.Enqueue(light3);
- renderingEngine.Enqueue(light4);
-
renderingEngine.Render(camera);
- //renderDevice.Pipeline.SetFrameBuffer(null);
-
- //renderingEngine.Enqueue(new Model()
- //{
- // Mesh = mesh,
- // Material = new Material()
- // {
- // DiffuseTexture = renderTarget.ColorTargets.FirstOrDefault(),
- // },
- //}, new Transform());
-
- //renderingEngine.Render(camera);
-
renderContext.SwapBuffers();
window.ProcessEvents();
}
diff --git a/FinalEngine.Rendering.Components/Core/TransformComponent.cs b/FinalEngine.Rendering.Components/Core/TransformComponent.cs
new file mode 100644
index 00000000..b1616790
--- /dev/null
+++ b/FinalEngine.Rendering.Components/Core/TransformComponent.cs
@@ -0,0 +1,12 @@
+//
+// Copyright (c) Software Antics. All rights reserved.
+//
+
+namespace FinalEngine.Rendering.Components.Core;
+
+using FinalEngine.ECS;
+using FinalEngine.Rendering.Core;
+
+public sealed class TransformComponent : Transform, IEntityComponent
+{
+}
diff --git a/FinalEngine.Rendering.Components/FinalEngine.Rendering.Components.csproj b/FinalEngine.Rendering.Components/FinalEngine.Rendering.Components.csproj
new file mode 100644
index 00000000..c6985cd9
--- /dev/null
+++ b/FinalEngine.Rendering.Components/FinalEngine.Rendering.Components.csproj
@@ -0,0 +1,36 @@
+
+
+
+ net8.0
+ enable
+ All
+ SA0001
+ false
+ x64
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FinalEngine.Rendering.Vapor/FinalEngine.Rendering.Vapor.csproj b/FinalEngine.Rendering.Vapor/FinalEngine.Rendering.Vapor.csproj
deleted file mode 100644
index aa95aeda..00000000
--- a/FinalEngine.Rendering.Vapor/FinalEngine.Rendering.Vapor.csproj
+++ /dev/null
@@ -1,103 +0,0 @@
-
-
-
- net8.0
- enable
- All
- false
- SA0001
- x64
-
-
-
-
-
-
-
-
-
-
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
-
-
-
-
-
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
-
diff --git a/FinalEngine.Rendering.Vapor/Batching/ISpriteBatcher.cs b/FinalEngine.Rendering/Batching/ISpriteBatcher.cs
similarity index 93%
rename from FinalEngine.Rendering.Vapor/Batching/ISpriteBatcher.cs
rename to FinalEngine.Rendering/Batching/ISpriteBatcher.cs
index 559fce76..5861878a 100644
--- a/FinalEngine.Rendering.Vapor/Batching/ISpriteBatcher.cs
+++ b/FinalEngine.Rendering/Batching/ISpriteBatcher.cs
@@ -2,7 +2,7 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Batching;
+namespace FinalEngine.Rendering.Batching;
using System.Drawing;
using System.Numerics;
diff --git a/FinalEngine.Rendering.Vapor/Batching/ISpriteDrawer.cs b/FinalEngine.Rendering/Batching/ISpriteDrawer.cs
similarity index 93%
rename from FinalEngine.Rendering.Vapor/Batching/ISpriteDrawer.cs
rename to FinalEngine.Rendering/Batching/ISpriteDrawer.cs
index 627a7152..e69e15d4 100644
--- a/FinalEngine.Rendering.Vapor/Batching/ISpriteDrawer.cs
+++ b/FinalEngine.Rendering/Batching/ISpriteDrawer.cs
@@ -2,7 +2,7 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Batching;
+namespace FinalEngine.Rendering.Batching;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
diff --git a/FinalEngine.Rendering.Vapor/Batching/ITextureBinder.cs b/FinalEngine.Rendering/Batching/ITextureBinder.cs
similarity index 86%
rename from FinalEngine.Rendering.Vapor/Batching/ITextureBinder.cs
rename to FinalEngine.Rendering/Batching/ITextureBinder.cs
index bd150b32..ff7cf173 100644
--- a/FinalEngine.Rendering.Vapor/Batching/ITextureBinder.cs
+++ b/FinalEngine.Rendering/Batching/ITextureBinder.cs
@@ -2,7 +2,7 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Batching;
+namespace FinalEngine.Rendering.Batching;
using FinalEngine.Rendering.Textures;
diff --git a/FinalEngine.Rendering.Vapor/Batching/SpriteBatcher.cs b/FinalEngine.Rendering/Batching/SpriteBatcher.cs
similarity index 97%
rename from FinalEngine.Rendering.Vapor/Batching/SpriteBatcher.cs
rename to FinalEngine.Rendering/Batching/SpriteBatcher.cs
index 308003a8..b7d2fcf7 100644
--- a/FinalEngine.Rendering.Vapor/Batching/SpriteBatcher.cs
+++ b/FinalEngine.Rendering/Batching/SpriteBatcher.cs
@@ -2,14 +2,14 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Batching;
+namespace FinalEngine.Rendering.Batching;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Numerics;
using FinalEngine.Rendering.Buffers;
-using FinalEngine.Rendering.Vapor.Primitives;
+using FinalEngine.Rendering.Primitives;
public class SpriteBatcher : ISpriteBatcher
{
diff --git a/FinalEngine.Rendering.Vapor/Batching/SpriteDrawer.cs b/FinalEngine.Rendering/Batching/SpriteDrawer.cs
similarity index 98%
rename from FinalEngine.Rendering.Vapor/Batching/SpriteDrawer.cs
rename to FinalEngine.Rendering/Batching/SpriteDrawer.cs
index 1b3255e5..28a29278 100644
--- a/FinalEngine.Rendering.Vapor/Batching/SpriteDrawer.cs
+++ b/FinalEngine.Rendering/Batching/SpriteDrawer.cs
@@ -2,15 +2,15 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Batching;
+namespace FinalEngine.Rendering.Batching;
using System;
using System.Drawing;
using System.Numerics;
using FinalEngine.Rendering.Buffers;
using FinalEngine.Rendering.Pipeline;
+using FinalEngine.Rendering.Primitives;
using FinalEngine.Rendering.Textures;
-using FinalEngine.Rendering.Vapor.Primitives;
using FinalEngine.Resources;
public class SpriteDrawer : ISpriteDrawer, IDisposable
diff --git a/FinalEngine.Rendering.Vapor/Batching/TextureBinder.cs b/FinalEngine.Rendering/Batching/TextureBinder.cs
similarity index 96%
rename from FinalEngine.Rendering.Vapor/Batching/TextureBinder.cs
rename to FinalEngine.Rendering/Batching/TextureBinder.cs
index 57f78212..d26cd54e 100644
--- a/FinalEngine.Rendering.Vapor/Batching/TextureBinder.cs
+++ b/FinalEngine.Rendering/Batching/TextureBinder.cs
@@ -2,7 +2,7 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Batching;
+namespace FinalEngine.Rendering.Batching;
using System;
using System.Collections.Generic;
diff --git a/FinalEngine.Rendering.Vapor/Core/ICamera.cs b/FinalEngine.Rendering/Core/ICamera.cs
similarity index 86%
rename from FinalEngine.Rendering.Vapor/Core/ICamera.cs
rename to FinalEngine.Rendering/Core/ICamera.cs
index 1333f9a6..1f308821 100644
--- a/FinalEngine.Rendering.Vapor/Core/ICamera.cs
+++ b/FinalEngine.Rendering/Core/ICamera.cs
@@ -2,7 +2,7 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Core;
+namespace FinalEngine.Rendering.Core;
using System.Numerics;
diff --git a/FinalEngine.Rendering.Vapor/Core/Transform.cs b/FinalEngine.Rendering/Core/Transform.cs
similarity index 97%
rename from FinalEngine.Rendering.Vapor/Core/Transform.cs
rename to FinalEngine.Rendering/Core/Transform.cs
index e9c45787..0028395c 100644
--- a/FinalEngine.Rendering.Vapor/Core/Transform.cs
+++ b/FinalEngine.Rendering/Core/Transform.cs
@@ -2,7 +2,7 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Core;
+namespace FinalEngine.Rendering.Core;
using System.Numerics;
diff --git a/FinalEngine.Rendering/FinalEngine.Rendering.csproj b/FinalEngine.Rendering/FinalEngine.Rendering.csproj
index 64129eb4..b5450fb1 100644
--- a/FinalEngine.Rendering/FinalEngine.Rendering.csproj
+++ b/FinalEngine.Rendering/FinalEngine.Rendering.csproj
@@ -35,4 +35,70 @@
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
diff --git a/FinalEngine.Rendering.Vapor/Geometry/IMaterial.cs b/FinalEngine.Rendering/Geometry/IMaterial.cs
similarity index 89%
rename from FinalEngine.Rendering.Vapor/Geometry/IMaterial.cs
rename to FinalEngine.Rendering/Geometry/IMaterial.cs
index 0e65c0e7..53f6a02c 100644
--- a/FinalEngine.Rendering.Vapor/Geometry/IMaterial.cs
+++ b/FinalEngine.Rendering/Geometry/IMaterial.cs
@@ -2,7 +2,7 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Geometry;
+namespace FinalEngine.Rendering.Geometry;
using FinalEngine.Rendering.Textures;
diff --git a/FinalEngine.Rendering.Vapor/Geometry/IMesh.cs b/FinalEngine.Rendering/Geometry/IMesh.cs
similarity index 85%
rename from FinalEngine.Rendering.Vapor/Geometry/IMesh.cs
rename to FinalEngine.Rendering/Geometry/IMesh.cs
index f3d49985..19ce94a4 100644
--- a/FinalEngine.Rendering.Vapor/Geometry/IMesh.cs
+++ b/FinalEngine.Rendering/Geometry/IMesh.cs
@@ -2,7 +2,7 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Geometry;
+namespace FinalEngine.Rendering.Geometry;
using System;
diff --git a/FinalEngine.Rendering.Vapor/Geometry/Material.cs b/FinalEngine.Rendering/Geometry/Material.cs
similarity index 97%
rename from FinalEngine.Rendering.Vapor/Geometry/Material.cs
rename to FinalEngine.Rendering/Geometry/Material.cs
index ac71b165..e0d8cb80 100644
--- a/FinalEngine.Rendering.Vapor/Geometry/Material.cs
+++ b/FinalEngine.Rendering/Geometry/Material.cs
@@ -2,7 +2,7 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Geometry;
+namespace FinalEngine.Rendering.Geometry;
using System;
using FinalEngine.Rendering.Textures;
diff --git a/FinalEngine.Rendering.Vapor/Geometry/Mesh.cs b/FinalEngine.Rendering/Geometry/Mesh.cs
similarity index 98%
rename from FinalEngine.Rendering.Vapor/Geometry/Mesh.cs
rename to FinalEngine.Rendering/Geometry/Mesh.cs
index e8f5edb6..d791c7c1 100644
--- a/FinalEngine.Rendering.Vapor/Geometry/Mesh.cs
+++ b/FinalEngine.Rendering/Geometry/Mesh.cs
@@ -2,12 +2,12 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Geometry;
+namespace FinalEngine.Rendering.Geometry;
using System;
using System.Numerics;
using FinalEngine.Rendering.Buffers;
-using FinalEngine.Rendering.Vapor.Primitives;
+using FinalEngine.Rendering.Primitives;
public sealed class Mesh : IMesh
{
diff --git a/FinalEngine.Rendering.Vapor/Geometry/Model.cs b/FinalEngine.Rendering/Geometry/Model.cs
similarity index 88%
rename from FinalEngine.Rendering.Vapor/Geometry/Model.cs
rename to FinalEngine.Rendering/Geometry/Model.cs
index 612187e8..ab1c9423 100644
--- a/FinalEngine.Rendering.Vapor/Geometry/Model.cs
+++ b/FinalEngine.Rendering/Geometry/Model.cs
@@ -2,7 +2,7 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Geometry;
+namespace FinalEngine.Rendering.Geometry;
public sealed class Model
{
diff --git a/FinalEngine.Rendering.Vapor/IRenderingEngine.cs b/FinalEngine.Rendering/IRenderingEngine.cs
similarity index 69%
rename from FinalEngine.Rendering.Vapor/IRenderingEngine.cs
rename to FinalEngine.Rendering/IRenderingEngine.cs
index 8fdc1b98..ee53628d 100644
--- a/FinalEngine.Rendering.Vapor/IRenderingEngine.cs
+++ b/FinalEngine.Rendering/IRenderingEngine.cs
@@ -2,12 +2,12 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor;
+namespace FinalEngine.Rendering;
using System.Numerics;
-using FinalEngine.Rendering.Vapor.Core;
-using FinalEngine.Rendering.Vapor.Geometry;
-using FinalEngine.Rendering.Vapor.Lighting;
+using FinalEngine.Rendering.Core;
+using FinalEngine.Rendering.Geometry;
+using FinalEngine.Rendering.Lighting;
public interface IRenderingEngine
{
diff --git a/FinalEngine.Rendering.Vapor/Lighting/Attenuation.cs b/FinalEngine.Rendering/Lighting/Attenuation.cs
similarity index 89%
rename from FinalEngine.Rendering.Vapor/Lighting/Attenuation.cs
rename to FinalEngine.Rendering/Lighting/Attenuation.cs
index 09d18bed..f2a2f76b 100644
--- a/FinalEngine.Rendering.Vapor/Lighting/Attenuation.cs
+++ b/FinalEngine.Rendering/Lighting/Attenuation.cs
@@ -2,7 +2,7 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Lighting;
+namespace FinalEngine.Rendering.Lighting;
public sealed class Attenuation
{
diff --git a/FinalEngine.Rendering.Vapor/Lighting/Light.cs b/FinalEngine.Rendering/Lighting/Light.cs
similarity index 95%
rename from FinalEngine.Rendering.Vapor/Lighting/Light.cs
rename to FinalEngine.Rendering/Lighting/Light.cs
index 87b93e02..b88dedd5 100644
--- a/FinalEngine.Rendering.Vapor/Lighting/Light.cs
+++ b/FinalEngine.Rendering/Lighting/Light.cs
@@ -2,7 +2,7 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Lighting;
+namespace FinalEngine.Rendering.Lighting;
using System;
using System.Numerics;
diff --git a/FinalEngine.Rendering.Vapor/Loaders/Invocation/IImageInvoker.cs b/FinalEngine.Rendering/Loaders/Invocation/IImageInvoker.cs
similarity index 86%
rename from FinalEngine.Rendering.Vapor/Loaders/Invocation/IImageInvoker.cs
rename to FinalEngine.Rendering/Loaders/Invocation/IImageInvoker.cs
index 71fda99d..959a41d4 100644
--- a/FinalEngine.Rendering.Vapor/Loaders/Invocation/IImageInvoker.cs
+++ b/FinalEngine.Rendering/Loaders/Invocation/IImageInvoker.cs
@@ -2,7 +2,7 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Loaders.Invocation;
+namespace FinalEngine.Rendering.Loaders.Invocation;
using System.IO;
using SixLabors.ImageSharp;
diff --git a/FinalEngine.Rendering.Vapor/Loaders/Invocation/ImageInvoker.cs b/FinalEngine.Rendering/Loaders/Invocation/ImageInvoker.cs
similarity index 90%
rename from FinalEngine.Rendering.Vapor/Loaders/Invocation/ImageInvoker.cs
rename to FinalEngine.Rendering/Loaders/Invocation/ImageInvoker.cs
index c7e25787..1e2d00ff 100644
--- a/FinalEngine.Rendering.Vapor/Loaders/Invocation/ImageInvoker.cs
+++ b/FinalEngine.Rendering/Loaders/Invocation/ImageInvoker.cs
@@ -2,7 +2,7 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Loaders.Invocation;
+namespace FinalEngine.Rendering.Loaders.Invocation;
using System.Diagnostics.CodeAnalysis;
using System.IO;
diff --git a/FinalEngine.Rendering.Vapor/Loaders/Shaders/ShaderProgramResourceLoader.cs b/FinalEngine.Rendering/Loaders/Shaders/ShaderProgramResourceLoader.cs
similarity index 97%
rename from FinalEngine.Rendering.Vapor/Loaders/Shaders/ShaderProgramResourceLoader.cs
rename to FinalEngine.Rendering/Loaders/Shaders/ShaderProgramResourceLoader.cs
index 477f7617..937e6576 100644
--- a/FinalEngine.Rendering.Vapor/Loaders/Shaders/ShaderProgramResourceLoader.cs
+++ b/FinalEngine.Rendering/Loaders/Shaders/ShaderProgramResourceLoader.cs
@@ -2,7 +2,7 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Loaders.Shaders;
+namespace FinalEngine.Rendering.Loaders.Shaders;
using System;
using System.IO;
diff --git a/FinalEngine.Rendering.Vapor/Loaders/Shaders/ShaderResourceLoader.cs b/FinalEngine.Rendering/Loaders/Shaders/ShaderResourceLoader.cs
similarity index 98%
rename from FinalEngine.Rendering.Vapor/Loaders/Shaders/ShaderResourceLoader.cs
rename to FinalEngine.Rendering/Loaders/Shaders/ShaderResourceLoader.cs
index 3e1413cc..a29b6ca4 100644
--- a/FinalEngine.Rendering.Vapor/Loaders/Shaders/ShaderResourceLoader.cs
+++ b/FinalEngine.Rendering/Loaders/Shaders/ShaderResourceLoader.cs
@@ -2,7 +2,7 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Loaders.Shaders;
+namespace FinalEngine.Rendering.Loaders.Shaders;
using System;
using System.IO;
diff --git a/FinalEngine.Rendering.Vapor/Loaders/Textures/Texture2DResourceLoader.cs b/FinalEngine.Rendering/Loaders/Textures/Texture2DResourceLoader.cs
similarity index 96%
rename from FinalEngine.Rendering.Vapor/Loaders/Textures/Texture2DResourceLoader.cs
rename to FinalEngine.Rendering/Loaders/Textures/Texture2DResourceLoader.cs
index 0cc168b2..19b8bb27 100644
--- a/FinalEngine.Rendering.Vapor/Loaders/Textures/Texture2DResourceLoader.cs
+++ b/FinalEngine.Rendering/Loaders/Textures/Texture2DResourceLoader.cs
@@ -2,15 +2,15 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Loaders.Textures;
+namespace FinalEngine.Rendering.Loaders.Textures;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Abstractions;
using FinalEngine.Rendering;
+using FinalEngine.Rendering.Loaders.Invocation;
using FinalEngine.Rendering.Textures;
-using FinalEngine.Rendering.Vapor.Loaders.Invocation;
using FinalEngine.Rendering.Vapor.Settings;
using FinalEngine.Resources;
using SixLabors.ImageSharp.PixelFormats;
diff --git a/FinalEngine.Rendering.Vapor/Primitives/MeshVertex.cs b/FinalEngine.Rendering/Primitives/MeshVertex.cs
similarity index 97%
rename from FinalEngine.Rendering.Vapor/Primitives/MeshVertex.cs
rename to FinalEngine.Rendering/Primitives/MeshVertex.cs
index 644c1f17..0d12b9c6 100644
--- a/FinalEngine.Rendering.Vapor/Primitives/MeshVertex.cs
+++ b/FinalEngine.Rendering/Primitives/MeshVertex.cs
@@ -2,7 +2,7 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Primitives;
+namespace FinalEngine.Rendering.Primitives;
using System;
using System.Collections.Generic;
diff --git a/FinalEngine.Rendering.Vapor/Primitives/SpriteVertex.cs b/FinalEngine.Rendering/Primitives/SpriteVertex.cs
similarity index 97%
rename from FinalEngine.Rendering.Vapor/Primitives/SpriteVertex.cs
rename to FinalEngine.Rendering/Primitives/SpriteVertex.cs
index cd13306b..18913f97 100644
--- a/FinalEngine.Rendering.Vapor/Primitives/SpriteVertex.cs
+++ b/FinalEngine.Rendering/Primitives/SpriteVertex.cs
@@ -2,7 +2,7 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Primitives;
+namespace FinalEngine.Rendering.Primitives;
using System;
using System.Collections.Generic;
diff --git a/FinalEngine.Rendering.Vapor/Renderers/GeometryRenderer.cs b/FinalEngine.Rendering/Renderers/GeometryRenderer.cs
similarity index 93%
rename from FinalEngine.Rendering.Vapor/Renderers/GeometryRenderer.cs
rename to FinalEngine.Rendering/Renderers/GeometryRenderer.cs
index 1a59b3c1..f2e4b799 100644
--- a/FinalEngine.Rendering.Vapor/Renderers/GeometryRenderer.cs
+++ b/FinalEngine.Rendering/Renderers/GeometryRenderer.cs
@@ -2,12 +2,12 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Renderers;
+namespace FinalEngine.Rendering.Renderers;
using System;
using System.Collections.Generic;
-using FinalEngine.Rendering.Vapor.Core;
-using FinalEngine.Rendering.Vapor.Geometry;
+using FinalEngine.Rendering.Core;
+using FinalEngine.Rendering.Geometry;
public sealed class GeometryRenderer : IGeometryRenderer
{
diff --git a/FinalEngine.Rendering.Vapor/Renderers/IGeometryRenderer.cs b/FinalEngine.Rendering/Renderers/IGeometryRenderer.cs
similarity index 69%
rename from FinalEngine.Rendering.Vapor/Renderers/IGeometryRenderer.cs
rename to FinalEngine.Rendering/Renderers/IGeometryRenderer.cs
index 887fa9b9..3f091fa1 100644
--- a/FinalEngine.Rendering.Vapor/Renderers/IGeometryRenderer.cs
+++ b/FinalEngine.Rendering/Renderers/IGeometryRenderer.cs
@@ -2,11 +2,11 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Renderers;
+namespace FinalEngine.Rendering.Renderers;
using System.Collections.Generic;
-using FinalEngine.Rendering.Vapor.Core;
-using FinalEngine.Rendering.Vapor.Geometry;
+using FinalEngine.Rendering.Core;
+using FinalEngine.Rendering.Geometry;
public interface IGeometryRenderer
{
diff --git a/FinalEngine.Rendering.Vapor/Renderers/ILightRenderer.cs b/FinalEngine.Rendering/Renderers/ILightRenderer.cs
similarity index 69%
rename from FinalEngine.Rendering.Vapor/Renderers/ILightRenderer.cs
rename to FinalEngine.Rendering/Renderers/ILightRenderer.cs
index 027ef289..6c9cdf9c 100644
--- a/FinalEngine.Rendering.Vapor/Renderers/ILightRenderer.cs
+++ b/FinalEngine.Rendering/Renderers/ILightRenderer.cs
@@ -2,9 +2,9 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Renderers;
+namespace FinalEngine.Rendering.Renderers;
-using FinalEngine.Rendering.Vapor.Lighting;
+using FinalEngine.Rendering.Lighting;
public interface ILightRenderer
{
diff --git a/FinalEngine.Rendering.Vapor/Renderers/LightRenderer.cs b/FinalEngine.Rendering/Renderers/LightRenderer.cs
similarity index 97%
rename from FinalEngine.Rendering.Vapor/Renderers/LightRenderer.cs
rename to FinalEngine.Rendering/Renderers/LightRenderer.cs
index 106a1984..7b56f9c4 100644
--- a/FinalEngine.Rendering.Vapor/Renderers/LightRenderer.cs
+++ b/FinalEngine.Rendering/Renderers/LightRenderer.cs
@@ -2,11 +2,11 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor.Renderers;
+namespace FinalEngine.Rendering.Renderers;
using System;
+using FinalEngine.Rendering.Lighting;
using FinalEngine.Rendering.Pipeline;
-using FinalEngine.Rendering.Vapor.Lighting;
using FinalEngine.Resources;
public sealed class LightRenderer : ILightRenderer
diff --git a/FinalEngine.Rendering.Vapor/RenderingEngine.cs b/FinalEngine.Rendering/RenderingEngine.cs
similarity index 96%
rename from FinalEngine.Rendering.Vapor/RenderingEngine.cs
rename to FinalEngine.Rendering/RenderingEngine.cs
index 22e1e6f9..a08b6b85 100644
--- a/FinalEngine.Rendering.Vapor/RenderingEngine.cs
+++ b/FinalEngine.Rendering/RenderingEngine.cs
@@ -2,17 +2,17 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Rendering.Vapor;
+namespace FinalEngine.Rendering;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Numerics;
+using FinalEngine.Rendering.Core;
+using FinalEngine.Rendering.Geometry;
+using FinalEngine.Rendering.Lighting;
using FinalEngine.Rendering.Pipeline;
-using FinalEngine.Rendering.Vapor.Core;
-using FinalEngine.Rendering.Vapor.Geometry;
-using FinalEngine.Rendering.Vapor.Lighting;
-using FinalEngine.Rendering.Vapor.Renderers;
+using FinalEngine.Rendering.Renderers;
using FinalEngine.Resources;
public sealed class RenderingEngine : IRenderingEngine
diff --git a/FinalEngine.Rendering.Vapor/Resources/Shaders/Includes/lighting.glsl b/FinalEngine.Rendering/Resources/Shaders/Includes/lighting.glsl
similarity index 100%
rename from FinalEngine.Rendering.Vapor/Resources/Shaders/Includes/lighting.glsl
rename to FinalEngine.Rendering/Resources/Shaders/Includes/lighting.glsl
diff --git a/FinalEngine.Rendering.Vapor/Resources/Shaders/Includes/material.glsl b/FinalEngine.Rendering/Resources/Shaders/Includes/material.glsl
similarity index 100%
rename from FinalEngine.Rendering.Vapor/Resources/Shaders/Includes/material.glsl
rename to FinalEngine.Rendering/Resources/Shaders/Includes/material.glsl
diff --git a/FinalEngine.Rendering.Vapor/Resources/Shaders/Lighting/lighting-ambient.fesp b/FinalEngine.Rendering/Resources/Shaders/Lighting/lighting-ambient.fesp
similarity index 100%
rename from FinalEngine.Rendering.Vapor/Resources/Shaders/Lighting/lighting-ambient.fesp
rename to FinalEngine.Rendering/Resources/Shaders/Lighting/lighting-ambient.fesp
diff --git a/FinalEngine.Rendering.Vapor/Resources/Shaders/Lighting/lighting-ambient.frag b/FinalEngine.Rendering/Resources/Shaders/Lighting/lighting-ambient.frag
similarity index 100%
rename from FinalEngine.Rendering.Vapor/Resources/Shaders/Lighting/lighting-ambient.frag
rename to FinalEngine.Rendering/Resources/Shaders/Lighting/lighting-ambient.frag
diff --git a/FinalEngine.Rendering.Vapor/Resources/Shaders/Lighting/lighting-directional.fesp b/FinalEngine.Rendering/Resources/Shaders/Lighting/lighting-directional.fesp
similarity index 100%
rename from FinalEngine.Rendering.Vapor/Resources/Shaders/Lighting/lighting-directional.fesp
rename to FinalEngine.Rendering/Resources/Shaders/Lighting/lighting-directional.fesp
diff --git a/FinalEngine.Rendering.Vapor/Resources/Shaders/Lighting/lighting-directional.frag b/FinalEngine.Rendering/Resources/Shaders/Lighting/lighting-directional.frag
similarity index 100%
rename from FinalEngine.Rendering.Vapor/Resources/Shaders/Lighting/lighting-directional.frag
rename to FinalEngine.Rendering/Resources/Shaders/Lighting/lighting-directional.frag
diff --git a/FinalEngine.Rendering.Vapor/Resources/Shaders/Lighting/lighting-main.vert b/FinalEngine.Rendering/Resources/Shaders/Lighting/lighting-main.vert
similarity index 100%
rename from FinalEngine.Rendering.Vapor/Resources/Shaders/Lighting/lighting-main.vert
rename to FinalEngine.Rendering/Resources/Shaders/Lighting/lighting-main.vert
diff --git a/FinalEngine.Rendering.Vapor/Resources/Shaders/Lighting/lighting-point.fesp b/FinalEngine.Rendering/Resources/Shaders/Lighting/lighting-point.fesp
similarity index 100%
rename from FinalEngine.Rendering.Vapor/Resources/Shaders/Lighting/lighting-point.fesp
rename to FinalEngine.Rendering/Resources/Shaders/Lighting/lighting-point.fesp
diff --git a/FinalEngine.Rendering.Vapor/Resources/Shaders/Lighting/lighting-point.frag b/FinalEngine.Rendering/Resources/Shaders/Lighting/lighting-point.frag
similarity index 100%
rename from FinalEngine.Rendering.Vapor/Resources/Shaders/Lighting/lighting-point.frag
rename to FinalEngine.Rendering/Resources/Shaders/Lighting/lighting-point.frag
diff --git a/FinalEngine.Rendering.Vapor/Resources/Shaders/Lighting/lighting-spot.fesp b/FinalEngine.Rendering/Resources/Shaders/Lighting/lighting-spot.fesp
similarity index 100%
rename from FinalEngine.Rendering.Vapor/Resources/Shaders/Lighting/lighting-spot.fesp
rename to FinalEngine.Rendering/Resources/Shaders/Lighting/lighting-spot.fesp
diff --git a/FinalEngine.Rendering.Vapor/Resources/Shaders/Lighting/lighting-spot.frag b/FinalEngine.Rendering/Resources/Shaders/Lighting/lighting-spot.frag
similarity index 100%
rename from FinalEngine.Rendering.Vapor/Resources/Shaders/Lighting/lighting-spot.frag
rename to FinalEngine.Rendering/Resources/Shaders/Lighting/lighting-spot.frag
diff --git a/FinalEngine.Rendering.Vapor/Resources/Shaders/Lighting/lighting.point.frag b/FinalEngine.Rendering/Resources/Shaders/Lighting/lighting.point.frag
similarity index 100%
rename from FinalEngine.Rendering.Vapor/Resources/Shaders/Lighting/lighting.point.frag
rename to FinalEngine.Rendering/Resources/Shaders/Lighting/lighting.point.frag
diff --git a/FinalEngine.Rendering.Vapor/Resources/Shaders/sprite-geometry.fesp b/FinalEngine.Rendering/Resources/Shaders/sprite-geometry.fesp
similarity index 100%
rename from FinalEngine.Rendering.Vapor/Resources/Shaders/sprite-geometry.fesp
rename to FinalEngine.Rendering/Resources/Shaders/sprite-geometry.fesp
diff --git a/FinalEngine.Rendering.Vapor/Resources/Shaders/sprite-geometry.frag b/FinalEngine.Rendering/Resources/Shaders/sprite-geometry.frag
similarity index 100%
rename from FinalEngine.Rendering.Vapor/Resources/Shaders/sprite-geometry.frag
rename to FinalEngine.Rendering/Resources/Shaders/sprite-geometry.frag
diff --git a/FinalEngine.Rendering.Vapor/Resources/Shaders/sprite-geometry.vert b/FinalEngine.Rendering/Resources/Shaders/sprite-geometry.vert
similarity index 100%
rename from FinalEngine.Rendering.Vapor/Resources/Shaders/sprite-geometry.vert
rename to FinalEngine.Rendering/Resources/Shaders/sprite-geometry.vert
diff --git a/FinalEngine.Rendering.Vapor/Resources/Shaders/standard-geometry.fesp b/FinalEngine.Rendering/Resources/Shaders/standard-geometry.fesp
similarity index 100%
rename from FinalEngine.Rendering.Vapor/Resources/Shaders/standard-geometry.fesp
rename to FinalEngine.Rendering/Resources/Shaders/standard-geometry.fesp
diff --git a/FinalEngine.Rendering.Vapor/Resources/Shaders/standard-geometry.frag b/FinalEngine.Rendering/Resources/Shaders/standard-geometry.frag
similarity index 100%
rename from FinalEngine.Rendering.Vapor/Resources/Shaders/standard-geometry.frag
rename to FinalEngine.Rendering/Resources/Shaders/standard-geometry.frag
diff --git a/FinalEngine.Rendering.Vapor/Resources/Shaders/standard-geometry.vert b/FinalEngine.Rendering/Resources/Shaders/standard-geometry.vert
similarity index 100%
rename from FinalEngine.Rendering.Vapor/Resources/Shaders/standard-geometry.vert
rename to FinalEngine.Rendering/Resources/Shaders/standard-geometry.vert
diff --git a/FinalEngine.Rendering.Vapor/Resources/Textures/default_diffuse.png b/FinalEngine.Rendering/Resources/Textures/default_diffuse.png
similarity index 100%
rename from FinalEngine.Rendering.Vapor/Resources/Textures/default_diffuse.png
rename to FinalEngine.Rendering/Resources/Textures/default_diffuse.png
diff --git a/FinalEngine.Rendering.Vapor/Resources/Textures/default_normal.jpg b/FinalEngine.Rendering/Resources/Textures/default_normal.jpg
similarity index 100%
rename from FinalEngine.Rendering.Vapor/Resources/Textures/default_normal.jpg
rename to FinalEngine.Rendering/Resources/Textures/default_normal.jpg
diff --git a/FinalEngine.Rendering.Vapor/Resources/Textures/default_specular.png b/FinalEngine.Rendering/Resources/Textures/default_specular.png
similarity index 100%
rename from FinalEngine.Rendering.Vapor/Resources/Textures/default_specular.png
rename to FinalEngine.Rendering/Resources/Textures/default_specular.png
diff --git a/FinalEngine.Rendering.Vapor/Settings/TextureQualitySettings.cs b/FinalEngine.Rendering/Settings/TextureQualitySettings.cs
similarity index 100%
rename from FinalEngine.Rendering.Vapor/Settings/TextureQualitySettings.cs
rename to FinalEngine.Rendering/Settings/TextureQualitySettings.cs
diff --git a/FinalEngine.Tests/ECS/Components/TagComponentTests.cs b/FinalEngine.Tests/ECS/Components/TagComponentTests.cs
index aec76732..48f55d1e 100644
--- a/FinalEngine.Tests/ECS/Components/TagComponentTests.cs
+++ b/FinalEngine.Tests/ECS/Components/TagComponentTests.cs
@@ -23,10 +23,10 @@ public void TagShouldReturnHelloWorldWhenSetToHelloWorld()
{
// Arrange
string expected = "Hello, World!";
- this.component.Tag = expected;
+ this.component.Name = expected;
// Act
- string actual = this.component.Tag;
+ string actual = this.component.Name;
// Assert
Assert.That(actual, Is.EqualTo(expected));
@@ -36,7 +36,7 @@ public void TagShouldReturnHelloWorldWhenSetToHelloWorld()
public void TagShouldReturnNullWhenNotSet()
{
// Act
- string actual = this.component.Tag;
+ string actual = this.component.Name;
// Assert
Assert.That(actual, Is.Null);
diff --git a/FinalEngine.Tests/ECS/EntitySystemProcessAttributeTests.cs b/FinalEngine.Tests/ECS/EntitySystemProcessAttributeTests.cs
index f258fa45..b1d1caa6 100644
--- a/FinalEngine.Tests/ECS/EntitySystemProcessAttributeTests.cs
+++ b/FinalEngine.Tests/ECS/EntitySystemProcessAttributeTests.cs
@@ -1,10 +1,11 @@
//
-// Copyright (c) Software Antics. All rights reserved.
+// Copyright (c) Software Antics. All rights reserved.
//
namespace FinalEngine.Tests.ECS;
using FinalEngine.ECS;
+using FinalEngine.ECS.Attributes;
using NUnit.Framework;
[TestFixture]
diff --git a/FinalEngine.Tests/ECS/Mocks/MockEntitySystemB.cs b/FinalEngine.Tests/ECS/Mocks/MockEntitySystemB.cs
index b4711648..5cda9084 100644
--- a/FinalEngine.Tests/ECS/Mocks/MockEntitySystemB.cs
+++ b/FinalEngine.Tests/ECS/Mocks/MockEntitySystemB.cs
@@ -8,6 +8,7 @@ namespace FinalEngine.Tests.ECS.Mocks;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using FinalEngine.ECS;
+using FinalEngine.ECS.Attributes;
[EntitySystemProcess(ExecutionType = GameLoopType.Render)]
public class MockEntitySystemB : EntitySystemBase
diff --git a/FinalEngine.Tests/FinalEngine.Tests.csproj b/FinalEngine.Tests/FinalEngine.Tests.csproj
index 14f29d9d..02e4f684 100644
--- a/FinalEngine.Tests/FinalEngine.Tests.csproj
+++ b/FinalEngine.Tests/FinalEngine.Tests.csproj
@@ -35,8 +35,8 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
diff --git a/FinalEngine.Tests/Rendering/Vapor/Batching/SpriteBatcherTests.cs b/FinalEngine.Tests/Rendering/Batching/SpriteBatcherTests.cs
similarity index 97%
rename from FinalEngine.Tests/Rendering/Vapor/Batching/SpriteBatcherTests.cs
rename to FinalEngine.Tests/Rendering/Batching/SpriteBatcherTests.cs
index 2e36933e..0ccb5bcb 100644
--- a/FinalEngine.Tests/Rendering/Vapor/Batching/SpriteBatcherTests.cs
+++ b/FinalEngine.Tests/Rendering/Batching/SpriteBatcherTests.cs
@@ -2,14 +2,16 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Tests.Rendering.Vapor.Batching;
+namespace FinalEngine.Tests.Rendering.Batching;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Numerics;
using FinalEngine.Rendering;
+using FinalEngine.Rendering.Batching;
using FinalEngine.Rendering.Buffers;
+using FinalEngine.Rendering.Primitives;
using Moq;
using NUnit.Framework;
diff --git a/FinalEngine.Tests/Rendering/Vapor/Batching/SpriteDrawerTests.cs b/FinalEngine.Tests/Rendering/Batching/SpriteDrawerTests.cs
similarity index 98%
rename from FinalEngine.Tests/Rendering/Vapor/Batching/SpriteDrawerTests.cs
rename to FinalEngine.Tests/Rendering/Batching/SpriteDrawerTests.cs
index 68758020..09ac5e55 100644
--- a/FinalEngine.Tests/Rendering/Vapor/Batching/SpriteDrawerTests.cs
+++ b/FinalEngine.Tests/Rendering/Batching/SpriteDrawerTests.cs
@@ -2,14 +2,16 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Tests.Rendering.Vapor.Batching;
+namespace FinalEngine.Tests.Rendering.Batching;
using System;
using System.Drawing;
using System.Numerics;
using FinalEngine.Rendering;
+using FinalEngine.Rendering.Batching;
using FinalEngine.Rendering.Buffers;
using FinalEngine.Rendering.Pipeline;
+using FinalEngine.Rendering.Primitives;
using FinalEngine.Rendering.Textures;
using FinalEngine.Resources;
using Moq;
diff --git a/FinalEngine.Tests/Rendering/Vapor/Batching/TextureBinderTests.cs b/FinalEngine.Tests/Rendering/Batching/TextureBinderTests.cs
similarity index 98%
rename from FinalEngine.Tests/Rendering/Vapor/Batching/TextureBinderTests.cs
rename to FinalEngine.Tests/Rendering/Batching/TextureBinderTests.cs
index ec686a88..aa2d8a38 100644
--- a/FinalEngine.Tests/Rendering/Vapor/Batching/TextureBinderTests.cs
+++ b/FinalEngine.Tests/Rendering/Batching/TextureBinderTests.cs
@@ -2,10 +2,11 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Tests.Rendering.Vapor.Batching;
+namespace FinalEngine.Tests.Rendering.Batching;
using System;
using FinalEngine.Rendering;
+using FinalEngine.Rendering.Batching;
using FinalEngine.Rendering.Textures;
using Moq;
using NUnit.Framework;
diff --git a/FinalEngine.Tests/Rendering/Vapor/Geometry/MaterialTests.cs b/FinalEngine.Tests/Rendering/Geometry/MaterialTests.cs
similarity index 98%
rename from FinalEngine.Tests/Rendering/Vapor/Geometry/MaterialTests.cs
rename to FinalEngine.Tests/Rendering/Geometry/MaterialTests.cs
index 723826ea..a6d08b8e 100644
--- a/FinalEngine.Tests/Rendering/Vapor/Geometry/MaterialTests.cs
+++ b/FinalEngine.Tests/Rendering/Geometry/MaterialTests.cs
@@ -2,10 +2,11 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Tests.Rendering.Vapor.Geometry;
+namespace FinalEngine.Tests.Rendering.Geometry;
using System;
using FinalEngine.Rendering;
+using FinalEngine.Rendering.Geometry;
using FinalEngine.Rendering.Textures;
using FinalEngine.Resources;
using Moq;
diff --git a/FinalEngine.Tests/Rendering/Vapor/Geometry/MeshTests.cs b/FinalEngine.Tests/Rendering/Geometry/MeshTests.cs
similarity index 97%
rename from FinalEngine.Tests/Rendering/Vapor/Geometry/MeshTests.cs
rename to FinalEngine.Tests/Rendering/Geometry/MeshTests.cs
index 0b63d5fc..355922db 100644
--- a/FinalEngine.Tests/Rendering/Vapor/Geometry/MeshTests.cs
+++ b/FinalEngine.Tests/Rendering/Geometry/MeshTests.cs
@@ -2,13 +2,15 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Tests.Rendering.Vapor.Geometry;
+namespace FinalEngine.Tests.Rendering.Geometry;
using System;
using System.Collections.Generic;
using System.Numerics;
using FinalEngine.Rendering;
using FinalEngine.Rendering.Buffers;
+using FinalEngine.Rendering.Geometry;
+using FinalEngine.Rendering.Primitives;
using Moq;
using NUnit.Framework;
@@ -231,21 +233,18 @@ public void Setup()
new MeshVertex()
{
Position = new Vector3(-1, -1, 0),
- Color = new Vector4(1, 0, 0, 1),
TextureCoordinate = new Vector2(0, 0),
},
new MeshVertex()
{
Position = new Vector3(1, -1, 0),
- Color = new Vector4(0, 1, 0, 1),
TextureCoordinate = new Vector2(1, 0),
},
new MeshVertex()
{
Position = new Vector3(0, 1, 0),
- Color = new Vector4(0, 0, 1, 1),
TextureCoordinate = new Vector2(0.5f, 1),
},
};
diff --git a/FinalEngine.Tests/Rendering/Loaders/Shaders/ShaderResourceLoaderTests.cs b/FinalEngine.Tests/Rendering/Loaders/Shaders/ShaderResourceLoaderTests.cs
deleted file mode 100644
index ff1bd30d..00000000
--- a/FinalEngine.Tests/Rendering/Loaders/Shaders/ShaderResourceLoaderTests.cs
+++ /dev/null
@@ -1,153 +0,0 @@
-//
-// Copyright (c) Software Antics. All rights reserved.
-//
-
-namespace FinalEngine.Tests.Rendering.Loaders.Shaders;
-
-using System;
-using System.IO;
-using System.IO.Abstractions.TestingHelpers;
-using FinalEngine.Rendering;
-using FinalEngine.Rendering.Pipeline;
-using Moq;
-using NUnit.Framework;
-
-[TestFixture]
-public sealed class ShaderResourceLoaderTests
-{
- private Mock factory;
-
- private MockFileSystem fileSystem;
-
- private ShaderResourceLoader loader;
-
- private Mock shader;
-
- [Test]
- public void ConstructorShouldThrowArgumentNullExceptionWhenFactoryIsNull()
- {
- // Act and assert
- Assert.Throws(() =>
- {
- new ShaderResourceLoader(this.fileSystem, null);
- });
- }
-
- [Test]
- public void ConstructorShouldThrowArgumentNullExceptionWhenFileSystemIsNull()
- {
- // Act and assert
- Assert.Throws(() =>
- {
- new ShaderResourceLoader(null, this.factory.Object);
- });
- }
-
- [Test]
- public void LoadResourceShouldInvokeCreateShaderFragmentWhenFileIsOpenedAndRead()
- {
- // Act
- this.loader.LoadResource("test.frag");
-
- // Assert
- this.factory.Verify(x => x.CreateShader(PipelineTarget.Fragment, string.Empty), Times.Once);
- }
-
- [Test]
- public void LoadResourceShouldInvokeCreateShaderFSWhenFileIsOpenedAndRead()
- {
- // Act
- this.loader.LoadResource("test.fs");
-
- // Assert
- this.factory.Verify(x => x.CreateShader(PipelineTarget.Fragment, string.Empty), Times.Once);
- }
-
- [Test]
- public void LoadResourceShouldInvokeCreateShaderVertexWhenFileIsOpenedAndRead()
- {
- // Act
- this.loader.LoadResource("test.vert");
-
- // Assert
- this.factory.Verify(x => x.CreateShader(PipelineTarget.Vertex, string.Empty), Times.Once);
- }
-
- [Test]
- public void LoadResourceShouldInvokeCreateShaderVSWhenFileIsOpenedAndRead()
- {
- // Act
- this.loader.LoadResource("test.vs");
-
- // Assert
- this.factory.Verify(x => x.CreateShader(PipelineTarget.Vertex, string.Empty), Times.Once);
- }
-
- [Test]
- public void LoadResourceShouldThrowArgumentExceptionWhenFilePathIsEmpty()
- {
- // Act and assert
- Assert.Throws(() =>
- {
- this.loader.LoadResource(string.Empty);
- });
- }
-
- [Test]
- public void LoadResourceShouldThrowArgumentExceptionWhenFilePathIsWhitespace()
- {
- // Act and assert
- Assert.Throws(() =>
- {
- this.loader.LoadResource("\t\n\r ");
- });
- }
-
- [Test]
- public void LoadResourceShouldThrowArgumentNullExceptionWhenFilePathIsNull()
- {
- // Act and assert
- Assert.Throws(() =>
- {
- this.loader.LoadResource(null);
- });
- }
-
- [Test]
- public void LoadResourceShouldThrowFileNotFoundExceptionWhenFileExistsReturnsFalse()
- {
- // Act and assert
- Assert.Throws(() =>
- {
- this.loader.LoadResource("test");
- });
- }
-
- [Test]
- public void LoadResourceShouldThrowNotSupportedExceptionWhenExtensionDoesNotExist()
- {
- // Act and assert
- Assert.Throws(() =>
- {
- this.loader.LoadResource("test.txt");
- });
- }
-
- [SetUp]
- public void Setup()
- {
- this.factory = new Mock();
- this.shader = new Mock();
- this.fileSystem = new MockFileSystem();
-
- this.fileSystem.AddEmptyFile("test.vert");
- this.fileSystem.AddEmptyFile("test.frag");
- this.fileSystem.AddEmptyFile("test.vs");
- this.fileSystem.AddEmptyFile("test.fs");
- this.fileSystem.AddEmptyFile("test.txt");
-
- this.factory.Setup(x => x.CreateShader(It.IsAny(), It.IsAny())).Returns(this.shader.Object);
-
- this.loader = new ShaderResourceLoader(this.fileSystem, this.factory.Object);
- }
-}
diff --git a/FinalEngine.Tests/Rendering/Loaders/Textures/Texture2DLoaderTests.cs b/FinalEngine.Tests/Rendering/Loaders/Textures/Texture2DLoaderTests.cs
deleted file mode 100644
index e9b4d676..00000000
--- a/FinalEngine.Tests/Rendering/Loaders/Textures/Texture2DLoaderTests.cs
+++ /dev/null
@@ -1,160 +0,0 @@
-//
-// Copyright (c) Software Antics. All rights reserved.
-//
-
-namespace FinalEngine.Tests.Rendering.Loaders.Textures;
-
-using System;
-using System.IO;
-using System.IO.Abstractions.TestingHelpers;
-using FinalEngine.Rendering;
-using FinalEngine.Rendering.Textures;
-using Moq;
-using NUnit.Framework;
-using SixLabors.ImageSharp;
-using SixLabors.ImageSharp.PixelFormats;
-
-public class Texture2DLoaderTests
-{
- private Mock factory;
-
- private MockFileSystem fileSystem;
-
- private Image image;
-
- private Mock invoker;
-
- private Texture2DResourceLoader loader;
-
- private MemoryStream stream;
-
- private Mock texture;
-
- [Test]
- public void ConstructorShouldThrowArgumentNullExceptionWhenFactoryIsNull()
- {
- // Arrange, act and assert
- Assert.Throws(() =>
- {
- new Texture2DResourceLoader(this.fileSystem, null, this.invoker.Object);
- });
- }
-
- [Test]
- public void ConstructorShouldThrowArgumentNullExceptionWhenFileSystemIsNull()
- {
- // Arrange, act and assert
- Assert.Throws(() =>
- {
- new Texture2DResourceLoader(null, this.factory.Object, this.invoker.Object);
- });
- }
-
- [Test]
- public void ConstructorShouldThrowArgumentNullExceptionWhenInvokerIsNull()
- {
- // Arrange, act and assert
- Assert.Throws(() =>
- {
- new Texture2DResourceLoader(this.fileSystem, this.factory.Object, null);
- });
- }
-
- [Test]
- public void LoadResourceShouldInvokeCreateTexture2DWhenLoaded()
- {
- // Act
- this.loader.LoadResource("texture");
-
- // Assert
- this.factory.Verify(x => x.CreateTexture2D(
- It.IsAny(),
- It.IsAny(),
- PixelFormat.Rgba,
- SizedFormat.Rgba8));
- }
-
- [Test]
- public void LoadResourceShouldReturnTextureWhenLoaded()
- {
- // Act
- var texture = this.loader.LoadResource("texture");
-
- // Assert
- Assert.AreSame(this.texture.Object, texture);
- }
-
- [Test]
- public void LoadResourceShouldThrowArgumentExceptionWhenFilePathIsEmpty()
- {
- // Act and assert
- Assert.Throws(() =>
- {
- this.loader.LoadResource(string.Empty);
- });
- }
-
- [Test]
- public void LoadResourceShouldThrowArgumentExceptionWhenFilePathIsWhitespace()
- {
- // Act and assert
- Assert.Throws(() =>
- {
- this.loader.LoadResource("\t\n\r");
- });
- }
-
- [Test]
- public void LoadResourceShouldThrowArgumentNullExceptionWhenFilePathIsNull()
- {
- // Act and assert
- Assert.Throws(() =>
- {
- this.loader.LoadResource(null);
- });
- }
-
- [Test]
- public void LoadResourceShouldThrowFileNotFoundExceptionWhenFileExistsReturnsFalse()
- {
- // Act and assert
- Assert.Throws(() =>
- {
- this.loader.LoadResource("texture2");
- });
- }
-
- [SetUp]
- public void Setup()
- {
- // Setup
- this.fileSystem = new MockFileSystem();
- this.stream = new MemoryStream();
-
- this.fileSystem.AddFile("test", new MockFileData(this.stream.ToArray()));
-
- this.fileSystem.AddFile(new MockFileInfo(this.fileSystem, "texture"), new MockFileData(this.stream.ToArray()));
-
- this.invoker = new Mock();
-
- this.image = new Image(1, 24);
- this.invoker.Setup(x => x.Load(It.IsAny())).Returns(this.image);
-
- this.factory = new Mock();
-
- this.texture = new Mock();
- this.factory.Setup(x => x.CreateTexture2D(
- It.IsAny(),
- It.IsAny(),
- PixelFormat.Rgba,
- SizedFormat.Rgba8)).Returns(this.texture.Object);
-
- this.loader = new Texture2DResourceLoader(this.fileSystem, this.factory.Object, this.invoker.Object);
- }
-
- [TearDown]
- public void Teardown()
- {
- this.image.Dispose();
- }
-}
diff --git a/FinalEngine.Tests/Rendering/Vapor/Primitives/MeshVertexTests.cs b/FinalEngine.Tests/Rendering/Primitives/MeshVertexTests.cs
similarity index 89%
rename from FinalEngine.Tests/Rendering/Vapor/Primitives/MeshVertexTests.cs
rename to FinalEngine.Tests/Rendering/Primitives/MeshVertexTests.cs
index 1c1a8bf8..d7ab48cf 100644
--- a/FinalEngine.Tests/Rendering/Vapor/Primitives/MeshVertexTests.cs
+++ b/FinalEngine.Tests/Rendering/Primitives/MeshVertexTests.cs
@@ -2,11 +2,12 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Tests.Rendering.Vapor.Primitives;
+namespace FinalEngine.Tests.Rendering.Primitives;
using System.Linq;
using System.Numerics;
using FinalEngine.Rendering.Buffers;
+using FinalEngine.Rendering.Primitives;
using NUnit.Framework;
[TestFixture]
@@ -14,32 +15,6 @@ public sealed class MeshVertexTests
{
private MeshVertex vertex;
- [Test]
- public void ColorShouldReturnTwoWhenSetToTwo()
- {
- // Arrange
- var expected = new Vector4(2, 2, 2, 2);
-
- // Act
- this.vertex.Color = expected;
-
- // Assert
- Assert.That(this.vertex.Color, Is.EqualTo(expected));
- }
-
- [Test]
- public void ColorShouldReturnZeroWhenNotSet()
- {
- // Arrange
- var expected = Vector4.Zero;
-
- // Act
- var actual = this.vertex.Color;
-
- // Assert
- Assert.That(actual, Is.EqualTo(expected));
- }
-
[Test]
public void EqualityOperatorShouldReturnFalseWhenPropertiesDontMatch()
{
@@ -47,7 +22,6 @@ public void EqualityOperatorShouldReturnFalseWhenPropertiesDontMatch()
var left = new MeshVertex()
{
Position = new Vector3(1, 2, 2),
- Color = new Vector4(1, 2, 3, 4),
TextureCoordinate = new Vector2(5, 6),
Tangent = new Vector3(1, 2, 3),
Normal = new Vector3(3, 4, 5),
@@ -56,7 +30,6 @@ public void EqualityOperatorShouldReturnFalseWhenPropertiesDontMatch()
var right = new MeshVertex()
{
Position = new Vector3(2, 2, 2),
- Color = new Vector4(1, 55, 33, 1),
TextureCoordinate = new Vector2(33, 6),
Normal = new Vector3(1, 1, 2),
Tangent = new Vector3(3, 4, 4),
@@ -76,7 +49,6 @@ public void EqualityOperatorShouldReturnTrueWhenPropertiesDoMatch()
var left = new MeshVertex()
{
Position = new Vector3(1, 2, 2),
- Color = new Vector4(1, 2, 3, 4),
TextureCoordinate = new Vector2(5, 6),
Tangent = new Vector3(1, 2, 3),
Normal = new Vector3(3, 4, 5),
@@ -85,7 +57,6 @@ public void EqualityOperatorShouldReturnTrueWhenPropertiesDoMatch()
var right = new MeshVertex()
{
Position = new Vector3(1, 2, 2),
- Color = new Vector4(1, 2, 3, 4),
TextureCoordinate = new Vector2(5, 6),
Tangent = new Vector3(1, 2, 3),
Normal = new Vector3(3, 4, 5),
@@ -129,7 +100,6 @@ public void EqualsShouldReturnFalseWhenPropertiesDontMatch()
var left = new MeshVertex()
{
Position = new Vector3(1, 2, 2),
- Color = new Vector4(1, 2, 3, 4),
TextureCoordinate = new Vector2(5, 6),
Tangent = new Vector3(1, 2, 3),
Normal = new Vector3(3, 4, 5),
@@ -138,7 +108,6 @@ public void EqualsShouldReturnFalseWhenPropertiesDontMatch()
var right = new MeshVertex()
{
Position = new Vector3(1, 12, 2),
- Color = new Vector4(1, 2, 33, 4),
TextureCoordinate = new Vector2(455, 6),
Tangent = new Vector3(1, 12, 3),
Normal = new Vector3(3, 4, 5),
@@ -158,7 +127,6 @@ public void EqualsShouldReturnTrueWhenObjectIsVertexAndHasSameProperties()
var left = new MeshVertex()
{
Position = new Vector3(1, 2, 2),
- Color = new Vector4(1, 2, 3, 4),
TextureCoordinate = new Vector2(5, 6),
Tangent = new Vector3(1, 2, 3),
Normal = new Vector3(3, 4, 5),
@@ -167,7 +135,6 @@ public void EqualsShouldReturnTrueWhenObjectIsVertexAndHasSameProperties()
object right = new MeshVertex()
{
Position = new Vector3(1, 2, 2),
- Color = new Vector4(1, 2, 3, 4),
TextureCoordinate = new Vector2(5, 6),
Tangent = new Vector3(1, 2, 3),
Normal = new Vector3(3, 4, 5),
@@ -187,7 +154,6 @@ public void EqualsShouldReturnTrueWhenPropertiesDoMatch()
var left = new MeshVertex()
{
Position = new Vector3(1, 2, 2),
- Color = new Vector4(1, 2, 3, 4),
TextureCoordinate = new Vector2(5, 6),
Tangent = new Vector3(1, 2, 3),
Normal = new Vector3(3, 4, 5),
@@ -196,7 +162,6 @@ public void EqualsShouldReturnTrueWhenPropertiesDoMatch()
var right = new MeshVertex()
{
Position = new Vector3(1, 2, 2),
- Color = new Vector4(1, 2, 3, 4),
TextureCoordinate = new Vector2(5, 6),
Tangent = new Vector3(1, 2, 3),
Normal = new Vector3(3, 4, 5),
@@ -216,7 +181,6 @@ public void GetHashCodeShouldReturnSameAsOtherObjectWhenPropertiesAreEqual()
var left = new MeshVertex()
{
Position = new Vector3(1, 2, 2),
- Color = new Vector4(1, 2, 3, 4),
TextureCoordinate = new Vector2(5, 6),
Tangent = new Vector3(1, 2, 3),
Normal = new Vector3(3, 4, 5),
@@ -225,7 +189,6 @@ public void GetHashCodeShouldReturnSameAsOtherObjectWhenPropertiesAreEqual()
var right = new MeshVertex()
{
Position = new Vector3(1, 2, 2),
- Color = new Vector4(1, 2, 3, 4),
TextureCoordinate = new Vector2(5, 6),
Tangent = new Vector3(1, 2, 3),
Normal = new Vector3(3, 4, 5),
@@ -246,7 +209,6 @@ public void InEqualityOperatorShouldReturnFalseWhenPropertiesDoMatch()
var left = new MeshVertex()
{
Position = new Vector3(1, 2, 2),
- Color = new Vector4(1, 2, 3, 4),
TextureCoordinate = new Vector2(5, 6),
Tangent = new Vector3(1, 2, 3),
Normal = new Vector3(3, 4, 5),
@@ -255,7 +217,6 @@ public void InEqualityOperatorShouldReturnFalseWhenPropertiesDoMatch()
var right = new MeshVertex()
{
Position = new Vector3(1, 2, 2),
- Color = new Vector4(1, 2, 3, 4),
TextureCoordinate = new Vector2(5, 6),
Tangent = new Vector3(1, 2, 3),
Normal = new Vector3(3, 4, 5),
@@ -275,7 +236,6 @@ public void InEqualityOperatorShouldReturnTrueWhenPropertiesDontMatch()
var left = new MeshVertex()
{
Position = new Vector3(1, 2, 2),
- Color = new Vector4(1, 2, 3, 4),
TextureCoordinate = new Vector2(5, 6),
Tangent = new Vector3(1, 2, 3),
Normal = new Vector3(3, 4, 5),
@@ -284,7 +244,6 @@ public void InEqualityOperatorShouldReturnTrueWhenPropertiesDontMatch()
var right = new MeshVertex()
{
Position = new Vector3(31, 2, 2),
- Color = new Vector4(1, 42, 3, 4),
TextureCoordinate = new Vector2(5, 6),
Tangent = new Vector3(1, 12, 3),
Normal = new Vector3(3, 4, 15),
diff --git a/FinalEngine.Tests/Rendering/Vapor/Primitives/SpriteVertexTests.cs b/FinalEngine.Tests/Rendering/Primitives/SpriteVertexTests.cs
similarity index 99%
rename from FinalEngine.Tests/Rendering/Vapor/Primitives/SpriteVertexTests.cs
rename to FinalEngine.Tests/Rendering/Primitives/SpriteVertexTests.cs
index efe98920..35758f02 100644
--- a/FinalEngine.Tests/Rendering/Vapor/Primitives/SpriteVertexTests.cs
+++ b/FinalEngine.Tests/Rendering/Primitives/SpriteVertexTests.cs
@@ -2,11 +2,12 @@
// Copyright (c) Software Antics. All rights reserved.
//
-namespace FinalEngine.Tests.Rendering.Vapor.Primitives;
+namespace FinalEngine.Tests.Rendering.Primitives;
using System.Collections.Generic;
using System.Numerics;
using FinalEngine.Rendering.Buffers;
+using FinalEngine.Rendering.Primitives;
using NUnit.Framework;
public class SpriteVertexTests
diff --git a/FinalEngine.Tests/Rendering/Settings/TextureQualitySettingsTests.cs b/FinalEngine.Tests/Rendering/Settings/TextureQualitySettingsTests.cs
index 6161a636..21786ea6 100644
--- a/FinalEngine.Tests/Rendering/Settings/TextureQualitySettingsTests.cs
+++ b/FinalEngine.Tests/Rendering/Settings/TextureQualitySettingsTests.cs
@@ -1,11 +1,11 @@
//
-// Copyright (c) Software Antics. All rights reserved.
+// Copyright (c) Software Antics. All rights reserved.
//
namespace FinalEngine.Tests.Rendering.Settings;
-using FinalEngine.Rendering.Settings;
using FinalEngine.Rendering.Textures;
+using FinalEngine.Rendering.Vapor.Settings;
using NUnit.Framework;
[TestFixture]
diff --git a/FinalEngine.sln b/FinalEngine.sln
index 160e07a6..388ea187 100644
--- a/FinalEngine.sln
+++ b/FinalEngine.sln
@@ -51,7 +51,15 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{10
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FinalEngine.Examples.Sponza", "FinalEngine.Examples.Sponza\FinalEngine.Examples.Sponza.csproj", "{499177E3-A5C5-4845-B81A-F7F57004A9C4}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FinalEngine.Rendering.Vapor", "FinalEngine.Rendering.Vapor\FinalEngine.Rendering.Vapor.csproj", "{BFEE9F4F-1735-46FD-AA03-F0264620CFBD}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Editor", "Editor", "{E560C356-F5BC-435B-9CA0-133C421DB04F}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FinalEngine.Editor.Common", "FinalEngine.Editor.Common\FinalEngine.Editor.Common.csproj", "{8CD32B3A-FE76-432F-9B0E-382A4D91A46D}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FinalEngine.Editor.Desktop", "FinalEngine.Editor.Desktop\FinalEngine.Editor.Desktop.csproj", "{99DC2107-26CF-407B-8D09-6540E16DB20E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FinalEngine.Editor.ViewModels", "FinalEngine.Editor.ViewModels\FinalEngine.Editor.ViewModels.csproj", "{30AA51B6-3E6D-455D-8635-5A4034896E9F}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FinalEngine.Rendering.Components", "FinalEngine.Rendering.Components\FinalEngine.Rendering.Components.csproj", "{B05CD0CD-A686-4516-A0DC-614506F97592}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -114,10 +122,23 @@ Global
{499177E3-A5C5-4845-B81A-F7F57004A9C4}.Debug|x64.ActiveCfg = Debug|x64
{499177E3-A5C5-4845-B81A-F7F57004A9C4}.Debug|x64.Build.0 = Debug|x64
{499177E3-A5C5-4845-B81A-F7F57004A9C4}.Release|x64.ActiveCfg = Release|x64
- {BFEE9F4F-1735-46FD-AA03-F0264620CFBD}.Debug|x64.ActiveCfg = Debug|x64
- {BFEE9F4F-1735-46FD-AA03-F0264620CFBD}.Debug|x64.Build.0 = Debug|x64
- {BFEE9F4F-1735-46FD-AA03-F0264620CFBD}.Release|x64.ActiveCfg = Release|Any CPU
- {BFEE9F4F-1735-46FD-AA03-F0264620CFBD}.Release|x64.Build.0 = Release|Any CPU
+ {499177E3-A5C5-4845-B81A-F7F57004A9C4}.Release|x64.Build.0 = Release|x64
+ {8CD32B3A-FE76-432F-9B0E-382A4D91A46D}.Debug|x64.ActiveCfg = Debug|x64
+ {8CD32B3A-FE76-432F-9B0E-382A4D91A46D}.Debug|x64.Build.0 = Debug|x64
+ {8CD32B3A-FE76-432F-9B0E-382A4D91A46D}.Release|x64.ActiveCfg = Release|x64
+ {8CD32B3A-FE76-432F-9B0E-382A4D91A46D}.Release|x64.Build.0 = Release|x64
+ {99DC2107-26CF-407B-8D09-6540E16DB20E}.Debug|x64.ActiveCfg = Debug|x64
+ {99DC2107-26CF-407B-8D09-6540E16DB20E}.Debug|x64.Build.0 = Debug|x64
+ {99DC2107-26CF-407B-8D09-6540E16DB20E}.Release|x64.ActiveCfg = Release|x64
+ {99DC2107-26CF-407B-8D09-6540E16DB20E}.Release|x64.Build.0 = Release|x64
+ {30AA51B6-3E6D-455D-8635-5A4034896E9F}.Debug|x64.ActiveCfg = Debug|x64
+ {30AA51B6-3E6D-455D-8635-5A4034896E9F}.Debug|x64.Build.0 = Debug|x64
+ {30AA51B6-3E6D-455D-8635-5A4034896E9F}.Release|x64.ActiveCfg = Release|x64
+ {30AA51B6-3E6D-455D-8635-5A4034896E9F}.Release|x64.Build.0 = Release|x64
+ {B05CD0CD-A686-4516-A0DC-614506F97592}.Debug|x64.ActiveCfg = Debug|x64
+ {B05CD0CD-A686-4516-A0DC-614506F97592}.Debug|x64.Build.0 = Debug|x64
+ {B05CD0CD-A686-4516-A0DC-614506F97592}.Release|x64.ActiveCfg = Release|Any CPU
+ {B05CD0CD-A686-4516-A0DC-614506F97592}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -137,7 +158,10 @@ Global
{E153C9B7-F8A5-43B6-B112-84739E7E9224} = {B4084D99-8DC5-4E1C-B5BF-9C7351CE71B8}
{D67794A8-89AC-46E0-B303-94110BB382F8} = {B4084D99-8DC5-4E1C-B5BF-9C7351CE71B8}
{499177E3-A5C5-4845-B81A-F7F57004A9C4} = {100655BE-7C84-4A92-B37F-DCC0585FB951}
- {BFEE9F4F-1735-46FD-AA03-F0264620CFBD} = {B2CD257E-E2BC-4259-A9B5-4DA90A7DE0B3}
+ {8CD32B3A-FE76-432F-9B0E-382A4D91A46D} = {E560C356-F5BC-435B-9CA0-133C421DB04F}
+ {99DC2107-26CF-407B-8D09-6540E16DB20E} = {E560C356-F5BC-435B-9CA0-133C421DB04F}
+ {30AA51B6-3E6D-455D-8635-5A4034896E9F} = {E560C356-F5BC-435B-9CA0-133C421DB04F}
+ {B05CD0CD-A686-4516-A0DC-614506F97592} = {B2CD257E-E2BC-4259-A9B5-4DA90A7DE0B3}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A278B383-0D14-41B3-A71C-4505E1D503DF}