From 24f929ed9d70e2bbf7487219c06c281cc7432695 Mon Sep 17 00:00:00 2001 From: Amin Delavar Date: Thu, 18 Jul 2019 03:50:58 +0200 Subject: [PATCH] Small game refactor --- DirectX12CoreWindowApp/App.cs | 4 +- DirectX12Game/MyGame.cs | 16 ++- DirectX12GameEngine.Assets/MaterialAsset.cs | 20 ++- DirectX12GameEngine.Assets/ModelAsset.cs | 17 ++- DirectX12GameEngine.Assets/TextureAsset.cs | 17 ++- DirectX12GameEngine.Core.Assets/Asset.cs | 6 +- .../ContentManager.Deserializing.cs | 2 +- DirectX12GameEngine.Core/WindowHandle.cs | 2 +- .../DirectX12GameEngine.Editor.csproj | 25 +--- DirectX12GameEngine.Editor/EditorGame.cs | 14 +- .../Factories/SceneViewFactory.cs | 2 +- .../ViewModels/EditorViewModel.cs | 7 - .../ViewModels/MainViewModel.cs | 37 +++++ .../ViewModels/SceneViewModel.cs | 31 +++++ .../ViewModels/SolutionExplorerViewModel.cs | 31 ----- .../Views/EditorMenuBar.xaml | 73 +++++++++- .../Views/EditorMenuBar.xaml.cs | 2 +- .../Views/MenuBarItems/EditMenuBarItem.xaml | 48 ------- .../MenuBarItems/EditMenuBarItem.xaml.cs | 14 -- .../Views/MenuBarItems/FileMenuBarItem.xaml | 46 ------- .../MenuBarItems/FileMenuBarItem.xaml.cs | 14 -- .../Views/MenuBarItems/ViewMenuBarItem.xaml | 19 --- .../MenuBarItems/ViewMenuBarItem.xaml.cs | 22 --- .../Views/SceneView.xaml | 4 +- .../Views/SceneView.xaml.cs | 24 +--- DirectX12GameEngine.Editor/Views/Shell.xaml | 4 +- .../Views/Shell.xaml.cs | 2 +- .../Views/SolutionExplorerView.xaml | 4 - .../Views/SolutionExplorerView.xaml.cs | 7 + .../EntityComponents/ScriptComponent.cs | 11 +- .../EntitySystems/CameraSystem.cs | 13 +- .../EntitySystems/RenderSystem.cs | 14 +- DirectX12GameEngine.Engine/Game.cs | 110 +++++++++------ DirectX12GameEngine.Engine/GameSystem.cs | 17 --- .../GraphicsDeviceManager.cs | 54 ++++++++ .../IGraphicsDeviceManager.cs | 15 +++ DirectX12GameEngine.Engine/SceneSystem.cs | 2 +- DirectX12GameEngine.Games/GameBase.cs | 94 ++++++++++--- DirectX12GameEngine.Games/GameContext.Uwp.cs | 4 + .../GameContext.WindowsDesktop.cs | 2 + DirectX12GameEngine.Games/GameContext.cs | 2 + DirectX12GameEngine.Games/GameWindow.cs | 18 +-- .../GameWindowCoreWindow.cs | 62 +++++++++ DirectX12GameEngine.Games/GameWindowUwp.cs | 127 ------------------ .../GameWindowWinForms.cs | 5 +- DirectX12GameEngine.Games/GameWindowXaml.cs | 61 +++++++++ .../GraphicsDevice.cs | 1 - .../Materials/CompiledShaderAsset.cs | 36 +++-- .../Materials/MaterialGeneratorContext.cs | 2 +- DirectX12WinFormsApp/Program.cs | 4 +- DirectX12XamlApp/MainPage.xaml.cs | 4 +- 51 files changed, 607 insertions(+), 565 deletions(-) delete mode 100644 DirectX12GameEngine.Editor/ViewModels/EditorViewModel.cs create mode 100644 DirectX12GameEngine.Editor/ViewModels/MainViewModel.cs create mode 100644 DirectX12GameEngine.Editor/ViewModels/SceneViewModel.cs delete mode 100644 DirectX12GameEngine.Editor/ViewModels/SolutionExplorerViewModel.cs delete mode 100644 DirectX12GameEngine.Editor/Views/MenuBarItems/EditMenuBarItem.xaml delete mode 100644 DirectX12GameEngine.Editor/Views/MenuBarItems/EditMenuBarItem.xaml.cs delete mode 100644 DirectX12GameEngine.Editor/Views/MenuBarItems/FileMenuBarItem.xaml delete mode 100644 DirectX12GameEngine.Editor/Views/MenuBarItems/FileMenuBarItem.xaml.cs delete mode 100644 DirectX12GameEngine.Editor/Views/MenuBarItems/ViewMenuBarItem.xaml delete mode 100644 DirectX12GameEngine.Editor/Views/MenuBarItems/ViewMenuBarItem.xaml.cs delete mode 100644 DirectX12GameEngine.Engine/GameSystem.cs create mode 100644 DirectX12GameEngine.Engine/GraphicsDeviceManager.cs create mode 100644 DirectX12GameEngine.Engine/IGraphicsDeviceManager.cs create mode 100644 DirectX12GameEngine.Games/GameWindowCoreWindow.cs delete mode 100644 DirectX12GameEngine.Games/GameWindowUwp.cs create mode 100644 DirectX12GameEngine.Games/GameWindowXaml.cs diff --git a/DirectX12CoreWindowApp/App.cs b/DirectX12CoreWindowApp/App.cs index df5c543..81b41eb 100644 --- a/DirectX12CoreWindowApp/App.cs +++ b/DirectX12CoreWindowApp/App.cs @@ -56,8 +56,8 @@ public void Run() { if (gameContext is null) throw new InvalidOperationException(); - game = new MyGame(gameContext); - game.Run(); + game = new MyGame(); + game.Run(gameContext); } public void Uninitialize() diff --git a/DirectX12Game/MyGame.cs b/DirectX12Game/MyGame.cs index 559442b..2938bc5 100644 --- a/DirectX12Game/MyGame.cs +++ b/DirectX12Game/MyGame.cs @@ -4,7 +4,6 @@ using System.Threading.Tasks; using DirectX12GameEngine.Assets; using DirectX12GameEngine.Engine; -using DirectX12GameEngine.Games; using DirectX12GameEngine.Graphics; using Windows.Storage; @@ -12,14 +11,19 @@ namespace DirectX12Game { public sealed class MyGame : Game { - public MyGame(GameContext gameContext) : base(gameContext) + public MyGame() { - if (GraphicsDevice.Presenter != null) + SceneSystem.InitialScenePath = @"Assets\Scenes\Scene1"; + } + + protected override void Initialize() + { + base.Initialize(); + + if (GraphicsDevice?.Presenter != null) { GraphicsDevice.Presenter.PresentationParameters.SyncInterval = 1; } - - SceneSystem.InitialScenePath = @"Assets\Scenes\Scene1"; } protected override void BeginDraw() @@ -51,7 +55,7 @@ protected override async Task LoadContentAsync() ShaderContent.RootFolder = await temporaryFolder.CreateFolderAsync("ShaderCache", CreationCollisionOption.OpenIfExists); // TODO: DirectX12GameEngine.Assets.dll does not get copied to the output directory if it is never used. - MaterialAsset materialAsset = new MaterialAsset(Content, ShaderContent, GraphicsDevice); + MaterialAsset materialAsset = new MaterialAsset(); materialAsset.ToString(); await base.LoadContentAsync(); diff --git a/DirectX12GameEngine.Assets/MaterialAsset.cs b/DirectX12GameEngine.Assets/MaterialAsset.cs index 10801c5..820f16b 100644 --- a/DirectX12GameEngine.Assets/MaterialAsset.cs +++ b/DirectX12GameEngine.Assets/MaterialAsset.cs @@ -3,30 +3,28 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using DirectX12GameEngine.Core.Assets; +using DirectX12GameEngine.Engine; using DirectX12GameEngine.Graphics; using DirectX12GameEngine.Rendering; using DirectX12GameEngine.Rendering.Materials; +using Microsoft.Extensions.DependencyInjection; namespace DirectX12GameEngine.Assets { [AssetContentType(typeof(Material))] public class MaterialAsset : AssetWithSource { - private readonly ContentManager contentManager; - private readonly ShaderContentManager shaderContentManager; - private readonly GraphicsDevice device; + public MaterialAttributes Attributes { get; set; } = new MaterialAttributes(); - public MaterialAsset(ContentManager contentManager, ShaderContentManager shaderContentManager, GraphicsDevice device) + public async override Task CreateAssetAsync(Material material, IServiceProvider services) { - this.contentManager = contentManager; - this.shaderContentManager = shaderContentManager; - this.device = device; - } + ContentManager contentManager = services.GetRequiredService(); + ShaderContentManager shaderContentManager = services.GetRequiredService(); + IGraphicsDeviceManager graphicsDeviceManager = services.GetRequiredService(); + GraphicsDevice? device = graphicsDeviceManager.GraphicsDevice; - public MaterialAttributes Attributes { get; set; } = new MaterialAttributes(); + if (device is null) throw new InvalidOperationException(); - public async override Task CreateAssetAsync(Material material) - { MaterialDescriptor descriptor; if (string.IsNullOrEmpty(Source)) diff --git a/DirectX12GameEngine.Assets/ModelAsset.cs b/DirectX12GameEngine.Assets/ModelAsset.cs index 0217dda..14c5861 100644 --- a/DirectX12GameEngine.Assets/ModelAsset.cs +++ b/DirectX12GameEngine.Assets/ModelAsset.cs @@ -3,27 +3,26 @@ using System.IO; using System.Threading.Tasks; using DirectX12GameEngine.Core.Assets; +using DirectX12GameEngine.Engine; using DirectX12GameEngine.Graphics; using DirectX12GameEngine.Rendering; +using Microsoft.Extensions.DependencyInjection; namespace DirectX12GameEngine.Assets { [AssetContentType(typeof(Model))] public class ModelAsset : AssetWithSource { - private readonly ContentManager contentManager; - private readonly GraphicsDevice device; + public IList Materials { get; } = new List(); - public ModelAsset(ContentManager contentManager, GraphicsDevice device) + public async override Task CreateAssetAsync(Model model, IServiceProvider services) { - this.contentManager = contentManager; - this.device = device; - } + ContentManager contentManager = services.GetRequiredService(); + IGraphicsDeviceManager graphicsDeviceManager = services.GetRequiredService(); + GraphicsDevice? device = graphicsDeviceManager.GraphicsDevice; - public IList Materials { get; } = new List(); + if (device is null) throw new InvalidOperationException(); - public async override Task CreateAssetAsync(Model model) - { string extension = Path.GetExtension(Source); if (extension == ".glb") diff --git a/DirectX12GameEngine.Assets/TextureAsset.cs b/DirectX12GameEngine.Assets/TextureAsset.cs index 873c82c..d1def6e 100644 --- a/DirectX12GameEngine.Assets/TextureAsset.cs +++ b/DirectX12GameEngine.Assets/TextureAsset.cs @@ -2,24 +2,23 @@ using System.IO; using System.Threading.Tasks; using DirectX12GameEngine.Core.Assets; +using DirectX12GameEngine.Engine; using DirectX12GameEngine.Graphics; +using Microsoft.Extensions.DependencyInjection; namespace DirectX12GameEngine.Assets { [AssetContentType(typeof(Texture))] public class TextureAsset : AssetWithSource { - private readonly ContentManager contentManager; - private readonly GraphicsDevice device; - - public TextureAsset(ContentManager contentManager, GraphicsDevice device) + public async override Task CreateAssetAsync(Texture texture, IServiceProvider services) { - this.contentManager = contentManager; - this.device = device; - } + ContentManager contentManager = services.GetRequiredService(); + IGraphicsDeviceManager graphicsDeviceManager = services.GetRequiredService(); + GraphicsDevice? device = graphicsDeviceManager.GraphicsDevice; + + if (device is null) throw new InvalidOperationException(); - public async override Task CreateAssetAsync(Texture texture) - { string extension = Path.GetExtension(Source); if (extension == ".png" || extension == ".jpg" || extension == ".jpeg") diff --git a/DirectX12GameEngine.Core.Assets/Asset.cs b/DirectX12GameEngine.Core.Assets/Asset.cs index ecd15cb..eea0c85 100644 --- a/DirectX12GameEngine.Core.Assets/Asset.cs +++ b/DirectX12GameEngine.Core.Assets/Asset.cs @@ -9,13 +9,13 @@ public abstract class Asset public virtual string? MainSource => null; - public abstract Task CreateAssetAsync(object obj); + public abstract Task CreateAssetAsync(object obj, IServiceProvider services); } public abstract class Asset : Asset { - public abstract Task CreateAssetAsync(T obj); + public abstract Task CreateAssetAsync(T obj, IServiceProvider services); - public override Task CreateAssetAsync(object obj) => CreateAssetAsync((T)obj); + public override Task CreateAssetAsync(object obj, IServiceProvider services) => CreateAssetAsync((T)obj, services); } } diff --git a/DirectX12GameEngine.Core.Assets/ContentManager.Deserializing.cs b/DirectX12GameEngine.Core.Assets/ContentManager.Deserializing.cs index 8457aa7..d04d1e7 100644 --- a/DirectX12GameEngine.Core.Assets/ContentManager.Deserializing.cs +++ b/DirectX12GameEngine.Core.Assets/ContentManager.Deserializing.cs @@ -166,7 +166,7 @@ internal async Task DeserializeAsync(string path, Type type, Reference? if (asset != null) { await DeserializeAsync(root, operation, asset); - await asset.CreateAssetAsync(result); + await asset.CreateAssetAsync(result, Services); } else { diff --git a/DirectX12GameEngine.Core/WindowHandle.cs b/DirectX12GameEngine.Core/WindowHandle.cs index e830e07..9314477 100644 --- a/DirectX12GameEngine.Core/WindowHandle.cs +++ b/DirectX12GameEngine.Core/WindowHandle.cs @@ -4,7 +4,7 @@ namespace DirectX12GameEngine.Core { public sealed class WindowHandle { - public WindowHandle(AppContextType contextType, object nativeWindow, IntPtr handle) + public WindowHandle(AppContextType contextType, object nativeWindow, IntPtr handle = default) { ContextType = contextType; NativeWindow = nativeWindow; diff --git a/DirectX12GameEngine.Editor/DirectX12GameEngine.Editor.csproj b/DirectX12GameEngine.Editor/DirectX12GameEngine.Editor.csproj index 08b9a35..28a72a0 100644 --- a/DirectX12GameEngine.Editor/DirectX12GameEngine.Editor.csproj +++ b/DirectX12GameEngine.Editor/DirectX12GameEngine.Editor.csproj @@ -126,14 +126,9 @@ - + - - EditMenuBarItem.xaml - - - FileMenuBarItem.xaml - + EditorMenuBar.xaml @@ -154,7 +149,6 @@ Shell.xaml - SolutionExplorerView.xaml @@ -162,9 +156,6 @@ - - ViewMenuBarItem.xaml - @@ -191,14 +182,6 @@ MSBuild:Compile Designer - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - Designer MSBuild:Compile @@ -215,10 +198,6 @@ Designer MSBuild:Compile - - Designer - MSBuild:Compile - diff --git a/DirectX12GameEngine.Editor/EditorGame.cs b/DirectX12GameEngine.Editor/EditorGame.cs index 86ad2b3..1eb5e4e 100644 --- a/DirectX12GameEngine.Editor/EditorGame.cs +++ b/DirectX12GameEngine.Editor/EditorGame.cs @@ -2,19 +2,25 @@ using System.Numerics; using System.Threading.Tasks; using DirectX12GameEngine.Engine; -using DirectX12GameEngine.Games; using DirectX12GameEngine.Graphics; using Windows.Storage; +#nullable enable + namespace DirectX12GameEngine.Editor { public class EditorGame : Game { - public EditorGame(GameContext gameContext, StorageFolder rootFolder) : base(gameContext) + public EditorGame(StorageFolder rootFolder) { Content.RootFolder = rootFolder; + } + + protected override void Initialize() + { + base.Initialize(); - if (GraphicsDevice.Presenter != null) + if (GraphicsDevice?.Presenter != null) { GraphicsDevice.Presenter.PresentationParameters.SyncInterval = 1; } @@ -24,7 +30,7 @@ protected override void BeginDraw() { base.BeginDraw(); - if (GraphicsDevice.Presenter != null) + if (GraphicsDevice?.Presenter != null) { GraphicsDevice.CommandList.Clear(GraphicsDevice.Presenter.BackBuffer, new Vector4(0.0f, 0.0f, 0.0f, 0.0f)); GraphicsDevice.CommandList.Clear(GraphicsDevice.Presenter.DepthStencilBuffer, ClearFlags.FlagsDepth); diff --git a/DirectX12GameEngine.Editor/Factories/SceneViewFactory.cs b/DirectX12GameEngine.Editor/Factories/SceneViewFactory.cs index de3757a..d0d0561 100644 --- a/DirectX12GameEngine.Editor/Factories/SceneViewFactory.cs +++ b/DirectX12GameEngine.Editor/Factories/SceneViewFactory.cs @@ -27,7 +27,7 @@ public class SceneViewFactory : IAssetViewFactory if (rootItem.Model is StorageFolder rootFolder) { SceneView sceneView = new SceneView(rootFolder); - await sceneView.LoadAsync(path); + Task sceneTask = sceneView.ViewModel.LoadAsync(path); return sceneView; } diff --git a/DirectX12GameEngine.Editor/ViewModels/EditorViewModel.cs b/DirectX12GameEngine.Editor/ViewModels/EditorViewModel.cs deleted file mode 100644 index f4ebfe2..0000000 --- a/DirectX12GameEngine.Editor/ViewModels/EditorViewModel.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace DirectX12GameEngine.Editor.ViewModels -{ - public class EditorViewModel - { - public EditorViewsViewModel EditorViews { get; } = new EditorViewsViewModel(); - } -} diff --git a/DirectX12GameEngine.Editor/ViewModels/MainViewModel.cs b/DirectX12GameEngine.Editor/ViewModels/MainViewModel.cs new file mode 100644 index 0000000..1abefb8 --- /dev/null +++ b/DirectX12GameEngine.Editor/ViewModels/MainViewModel.cs @@ -0,0 +1,37 @@ +#nullable enable + +using DirectX12GameEngine.Editor.Messages; +using DirectX12GameEngine.Editor.Messaging; + +namespace DirectX12GameEngine.Editor.ViewModels +{ + public class MainViewModel : ViewModelBase + { + private StorageItemViewModel? rootFolder; + + public MainViewModel() + { + RegisterMessages(); + } + + public EditorViewsViewModel EditorViews { get; } = new EditorViewsViewModel(); + + public ProjectLoaderViewModel ProjectLoader { get; } = new ProjectLoaderViewModel(); + + public StorageItemViewModel? RootFolder + { + get => rootFolder; + set => Set(ref rootFolder, value); + } + + private void RegisterMessages() + { + Messenger.Default.Register(this, async m => + { + RootFolder = m.RootFolder; + RootFolder.HasUnrealizedChildren = true; + await RootFolder.FillAsync(); + }); + } + } +} diff --git a/DirectX12GameEngine.Editor/ViewModels/SceneViewModel.cs b/DirectX12GameEngine.Editor/ViewModels/SceneViewModel.cs new file mode 100644 index 0000000..fb0c834 --- /dev/null +++ b/DirectX12GameEngine.Editor/ViewModels/SceneViewModel.cs @@ -0,0 +1,31 @@ +using System.Threading.Tasks; +using DirectX12GameEngine.Engine; + +#nullable enable + +namespace DirectX12GameEngine.Editor.ViewModels +{ + public class SceneViewModel : ViewModelBase + { + private readonly EditorGame game; + + public SceneViewModel(EditorGame game) + { + this.game = game; + + game.SceneSystem.SceneInstance.RootEntity = RootEntity.Model; + } + + public EntityViewModel RootEntity { get; } = new EntityViewModel(new Entity("RootEntity")); + + public async Task LoadAsync(string path) + { + RootEntity.Children.Clear(); + + Entity scene = await game.Content.LoadAsync(path); + EntityViewModel sceneViewModel = new EntityViewModel(scene); + + RootEntity.Children.Add(sceneViewModel); + } + } +} diff --git a/DirectX12GameEngine.Editor/ViewModels/SolutionExplorerViewModel.cs b/DirectX12GameEngine.Editor/ViewModels/SolutionExplorerViewModel.cs deleted file mode 100644 index a354587..0000000 --- a/DirectX12GameEngine.Editor/ViewModels/SolutionExplorerViewModel.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Threading.Tasks; -using DirectX12GameEngine.Editor.Messages; -using DirectX12GameEngine.Editor.Messaging; - -#nullable enable - -namespace DirectX12GameEngine.Editor.ViewModels -{ - public class SolutionExplorerViewModel : ViewModelBase - { - private StorageItemViewModel? rootFolder; - - public SolutionExplorerViewModel() - { - Messenger.Default.Register(this, async m => await SetRootFolderAsync(m.RootFolder)); - } - - public StorageItemViewModel? RootFolder - { - get => rootFolder; - private set => Set(ref rootFolder, value); - } - - public async Task SetRootFolderAsync(StorageItemViewModel folder) - { - RootFolder = folder; - RootFolder.HasUnrealizedChildren = true; - await RootFolder.FillAsync(); - } - } -} diff --git a/DirectX12GameEngine.Editor/Views/EditorMenuBar.xaml b/DirectX12GameEngine.Editor/Views/EditorMenuBar.xaml index a1eac31..d36e19f 100644 --- a/DirectX12GameEngine.Editor/Views/EditorMenuBar.xaml +++ b/DirectX12GameEngine.Editor/Views/EditorMenuBar.xaml @@ -5,17 +5,80 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="using:DirectX12GameEngine.Editor.Views" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:viewmodels="using:DirectX12GameEngine.Editor.ViewModels" xmlns:winui="using:Microsoft.UI.Xaml.Controls" d:DesignHeight="40" d:DesignWidth="400" mc:Ignorable="d"> - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + diff --git a/DirectX12GameEngine.Editor/Views/EditorMenuBar.xaml.cs b/DirectX12GameEngine.Editor/Views/EditorMenuBar.xaml.cs index affb9c9..42201ed 100644 --- a/DirectX12GameEngine.Editor/Views/EditorMenuBar.xaml.cs +++ b/DirectX12GameEngine.Editor/Views/EditorMenuBar.xaml.cs @@ -19,6 +19,6 @@ public EditorMenuBar() }; } - public EditorViewModel ViewModel => (EditorViewModel)DataContext; + public MainViewModel ViewModel => (MainViewModel)DataContext; } } diff --git a/DirectX12GameEngine.Editor/Views/MenuBarItems/EditMenuBarItem.xaml b/DirectX12GameEngine.Editor/Views/MenuBarItems/EditMenuBarItem.xaml deleted file mode 100644 index 8c050cf..0000000 --- a/DirectX12GameEngine.Editor/Views/MenuBarItems/EditMenuBarItem.xaml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/DirectX12GameEngine.Editor/Views/MenuBarItems/EditMenuBarItem.xaml.cs b/DirectX12GameEngine.Editor/Views/MenuBarItems/EditMenuBarItem.xaml.cs deleted file mode 100644 index 65f483f..0000000 --- a/DirectX12GameEngine.Editor/Views/MenuBarItems/EditMenuBarItem.xaml.cs +++ /dev/null @@ -1,14 +0,0 @@ -using WinUI = Microsoft.UI.Xaml.Controls; - -// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236 - -namespace DirectX12GameEngine.Editor.Views -{ - public sealed partial class EditMenuBarItem : WinUI.MenuBarItem - { - public EditMenuBarItem() - { - InitializeComponent(); - } - } -} diff --git a/DirectX12GameEngine.Editor/Views/MenuBarItems/FileMenuBarItem.xaml b/DirectX12GameEngine.Editor/Views/MenuBarItems/FileMenuBarItem.xaml deleted file mode 100644 index b61f7d4..0000000 --- a/DirectX12GameEngine.Editor/Views/MenuBarItems/FileMenuBarItem.xaml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/DirectX12GameEngine.Editor/Views/MenuBarItems/FileMenuBarItem.xaml.cs b/DirectX12GameEngine.Editor/Views/MenuBarItems/FileMenuBarItem.xaml.cs deleted file mode 100644 index 72dc9ea..0000000 --- a/DirectX12GameEngine.Editor/Views/MenuBarItems/FileMenuBarItem.xaml.cs +++ /dev/null @@ -1,14 +0,0 @@ -using WinUI = Microsoft.UI.Xaml.Controls; - -// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236 - -namespace DirectX12GameEngine.Editor.Views -{ - public sealed partial class FileMenuBarItem : WinUI.MenuBarItem - { - public FileMenuBarItem() - { - InitializeComponent(); - } - } -} diff --git a/DirectX12GameEngine.Editor/Views/MenuBarItems/ViewMenuBarItem.xaml b/DirectX12GameEngine.Editor/Views/MenuBarItems/ViewMenuBarItem.xaml deleted file mode 100644 index 1ef1895..0000000 --- a/DirectX12GameEngine.Editor/Views/MenuBarItems/ViewMenuBarItem.xaml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - diff --git a/DirectX12GameEngine.Editor/Views/MenuBarItems/ViewMenuBarItem.xaml.cs b/DirectX12GameEngine.Editor/Views/MenuBarItems/ViewMenuBarItem.xaml.cs deleted file mode 100644 index b2f4713..0000000 --- a/DirectX12GameEngine.Editor/Views/MenuBarItems/ViewMenuBarItem.xaml.cs +++ /dev/null @@ -1,22 +0,0 @@ -using DirectX12GameEngine.Editor.ViewModels; -using WinUI = Microsoft.UI.Xaml.Controls; - -// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236 - -namespace DirectX12GameEngine.Editor.Views -{ - public sealed partial class ViewMenuBarItem : WinUI.MenuBarItem - { - public ViewMenuBarItem() - { - InitializeComponent(); - - DataContextChanged += (s, e) => - { - Bindings.Update(); - }; - } - - public EditorViewsViewModel ViewModel => (EditorViewsViewModel)DataContext; - } -} diff --git a/DirectX12GameEngine.Editor/Views/SceneView.xaml b/DirectX12GameEngine.Editor/Views/SceneView.xaml index 5e7537f..29f24cd 100644 --- a/DirectX12GameEngine.Editor/Views/SceneView.xaml +++ b/DirectX12GameEngine.Editor/Views/SceneView.xaml @@ -17,9 +17,7 @@ - + diff --git a/DirectX12GameEngine.Editor/Views/SceneView.xaml.cs b/DirectX12GameEngine.Editor/Views/SceneView.xaml.cs index 1840577..250d655 100644 --- a/DirectX12GameEngine.Editor/Views/SceneView.xaml.cs +++ b/DirectX12GameEngine.Editor/Views/SceneView.xaml.cs @@ -1,6 +1,4 @@ -using System.Threading.Tasks; -using DirectX12GameEngine.Editor.ViewModels; -using DirectX12GameEngine.Engine; +using DirectX12GameEngine.Editor.ViewModels; using DirectX12GameEngine.Games; using Windows.Storage; using Windows.UI.Xaml.Controls; @@ -13,28 +11,16 @@ namespace DirectX12GameEngine.Editor.Views { public sealed partial class SceneView : UserControl { - private readonly EditorGame game; - public SceneView(StorageFolder rootFolder) { InitializeComponent(); - game = new EditorGame(new GameContextXaml(swapChainPanel), rootFolder); - game.Run(); + EditorGame game = new EditorGame(rootFolder); + game.Run(new GameContextXaml(swapChainPanel)); - game.SceneSystem.SceneInstance.RootEntity = ViewModel.Model; + ViewModel = new SceneViewModel(game); } - public EntityViewModel ViewModel { get; } = new EntityViewModel(new Entity("RootEntity")); - - public async Task LoadAsync(string path) - { - ViewModel.Children.Clear(); - - Entity scene = await game.Content.LoadAsync(path); - - EntityViewModel sceneViewModel = new EntityViewModel(scene); - ViewModel.Children.Add(sceneViewModel); - } + public SceneViewModel ViewModel { get; } } } diff --git a/DirectX12GameEngine.Editor/Views/Shell.xaml b/DirectX12GameEngine.Editor/Views/Shell.xaml index a8045ac..a68edcb 100644 --- a/DirectX12GameEngine.Editor/Views/Shell.xaml +++ b/DirectX12GameEngine.Editor/Views/Shell.xaml @@ -2,10 +2,10 @@ x:Class="DirectX12GameEngine.Editor.Views.Shell" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="using:DirectX12GameEngine.Editor.Views" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls" d:DesignHeight="300" d:DesignWidth="400" mc:Ignorable="d"> @@ -34,7 +34,7 @@ - + diff --git a/DirectX12GameEngine.Editor/Views/Shell.xaml.cs b/DirectX12GameEngine.Editor/Views/Shell.xaml.cs index 5699266..6e55ccf 100644 --- a/DirectX12GameEngine.Editor/Views/Shell.xaml.cs +++ b/DirectX12GameEngine.Editor/Views/Shell.xaml.cs @@ -61,6 +61,6 @@ public Shell() }); } - public EditorViewModel ViewModel { get; } = new EditorViewModel(); + public MainViewModel ViewModel { get; } = new MainViewModel(); } } diff --git a/DirectX12GameEngine.Editor/Views/SolutionExplorerView.xaml b/DirectX12GameEngine.Editor/Views/SolutionExplorerView.xaml index 88d6853..a0d973c 100644 --- a/DirectX12GameEngine.Editor/Views/SolutionExplorerView.xaml +++ b/DirectX12GameEngine.Editor/Views/SolutionExplorerView.xaml @@ -11,10 +11,6 @@ d:DesignWidth="400" mc:Ignorable="d"> - - - - + { + Bindings.Update(); + }; } + public MainViewModel ViewModel => (MainViewModel)DataContext; + private void SolutionExplorer_Collapsed(WinUI.TreeView sender, WinUI.TreeViewCollapsedEventArgs args) { if (args.Item is StorageItemViewModel item) diff --git a/DirectX12GameEngine.Engine/EntityComponents/ScriptComponent.cs b/DirectX12GameEngine.Engine/EntityComponents/ScriptComponent.cs index e5bf782..acbc04f 100644 --- a/DirectX12GameEngine.Engine/EntityComponents/ScriptComponent.cs +++ b/DirectX12GameEngine.Engine/EntityComponents/ScriptComponent.cs @@ -10,6 +10,11 @@ namespace DirectX12GameEngine.Engine [DefaultEntitySystem(typeof(ScriptProcessor))] public abstract class ScriptComponent : EntityComponent { + private IGraphicsDeviceManager? graphicsDeviceManager; + + [IgnoreDataMember] + public GraphicsDevice? GraphicsDevice => graphicsDeviceManager?.GraphicsDevice; + #nullable disable [IgnoreDataMember] public IServiceProvider Services { get; private set; } @@ -20,9 +25,6 @@ public abstract class ScriptComponent : EntityComponent [IgnoreDataMember] public GameBase Game { get; private set; } - [IgnoreDataMember] - public GraphicsDevice GraphicsDevice { get; private set; } - [IgnoreDataMember] public SceneSystem SceneSystem { get; private set; } @@ -34,9 +36,10 @@ internal void Initialize(IServiceProvider services) { Services = services; + graphicsDeviceManager = Services.GetRequiredService(); + Content = Services.GetRequiredService(); Game = Services.GetRequiredService(); - GraphicsDevice = Services.GetRequiredService(); SceneSystem = Services.GetRequiredService(); Script = Services.GetRequiredService(); } diff --git a/DirectX12GameEngine.Engine/EntitySystems/CameraSystem.cs b/DirectX12GameEngine.Engine/EntitySystems/CameraSystem.cs index 231e964..e4ac25c 100644 --- a/DirectX12GameEngine.Engine/EntitySystems/CameraSystem.cs +++ b/DirectX12GameEngine.Engine/EntitySystems/CameraSystem.cs @@ -7,20 +7,27 @@ namespace DirectX12GameEngine.Engine { public sealed class CameraSystem : EntitySystem { + private readonly IGraphicsDeviceManager graphicsDeviceManager; + public CameraSystem(IServiceProvider services) : base(services, typeof(TransformComponent)) { Order = -10; - GraphicsDevice = services.GetRequiredService(); + graphicsDeviceManager = services.GetRequiredService(); } - public GraphicsDevice GraphicsDevice { get; } + public GraphicsDevice? GraphicsDevice => graphicsDeviceManager.GraphicsDevice; public override void Draw(GameTime gameTime) { foreach (CameraComponent cameraComponent in Components) { - float screenAspectRatio = GraphicsDevice.CommandList.Viewports[0].Width / GraphicsDevice.CommandList.Viewports[0].Height; + float? screenAspectRatio = null; + + if (GraphicsDevice != null) + { + screenAspectRatio = GraphicsDevice.CommandList.Viewports[0].Width / GraphicsDevice.CommandList.Viewports[0].Height; + } cameraComponent.Update(screenAspectRatio); } diff --git a/DirectX12GameEngine.Engine/EntitySystems/RenderSystem.cs b/DirectX12GameEngine.Engine/EntitySystems/RenderSystem.cs index 643033d..9b8333c 100644 --- a/DirectX12GameEngine.Engine/EntitySystems/RenderSystem.cs +++ b/DirectX12GameEngine.Engine/EntitySystems/RenderSystem.cs @@ -19,6 +19,8 @@ namespace DirectX12GameEngine.Engine { public sealed class RenderSystem : EntitySystem { + private IGraphicsDeviceManager? graphicsDeviceManager; + private const int MaxLights = 512; private readonly List commandLists = new List(); @@ -27,9 +29,11 @@ public sealed class RenderSystem : EntitySystem public unsafe RenderSystem(IServiceProvider services) : base(services, typeof(TransformComponent)) { - GraphicsDevice = services.GetRequiredService(); + graphicsDeviceManager = Services.GetRequiredService(); SceneSystem = services.GetRequiredService(); + if (GraphicsDevice is null) throw new InvalidOperationException(); + DirectionalLightGroupBuffer = Buffer.Constant.New(GraphicsDevice, sizeof(int) + sizeof(DirectionalLightData) * MaxLights); GlobalBuffer = Buffer.Constant.New(GraphicsDevice, sizeof(GlobalBuffer)); ViewProjectionTransformBuffer = Buffer.Constant.New(GraphicsDevice, sizeof(StereoViewProjectionTransform)); @@ -41,12 +45,14 @@ public unsafe RenderSystem(IServiceProvider services) : base(services, typeof(Tr public Buffer ViewProjectionTransformBuffer { get; } - public GraphicsDevice GraphicsDevice { get; } + public GraphicsDevice? GraphicsDevice => graphicsDeviceManager?.GraphicsDevice; public SceneSystem SceneSystem { get; } public override void Draw(GameTime gameTime) { + if (GraphicsDevice is null) return; + UpdateGlobals(gameTime); UpdateLights(); UpdateViewProjectionMatrices(); @@ -233,7 +239,7 @@ private static void DisposeModel(CompiledCommandList[] bundles, Buffer[] worldMa private void RecordCommandList(Model model, CommandList commandList, Buffer[] worldMatrixBuffers, int instanceCount, int passIndex) { - int renderTargetCount = GraphicsDevice.Presenter is null ? 1 : GraphicsDevice.Presenter.PresentationParameters.Stereo ? 2 : 1; + int renderTargetCount = GraphicsDevice?.Presenter is null ? 1 : GraphicsDevice.Presenter.PresentationParameters.Stereo ? 2 : 1; instanceCount *= renderTargetCount; for (int i = 0; i < model.Meshes.Count; i++) @@ -327,7 +333,7 @@ private void UpdateViewProjectionMatrices() if (SceneSystem.CurrentCamera != null && SceneSystem.CurrentCamera.Entity != null) { #if WINDOWS_UWP - if (GraphicsDevice.Presenter is Graphics.Holographic.HolographicGraphicsPresenter graphicsPresenter) + if (GraphicsDevice?.Presenter is Graphics.Holographic.HolographicGraphicsPresenter graphicsPresenter) { var cameraPose = graphicsPresenter.HolographicFrame.CurrentPrediction.CameraPoses[0]; diff --git a/DirectX12GameEngine.Engine/Game.cs b/DirectX12GameEngine.Engine/Game.cs index 63efbfa..2d092b5 100644 --- a/DirectX12GameEngine.Engine/Game.cs +++ b/DirectX12GameEngine.Engine/Game.cs @@ -1,4 +1,5 @@ -using DirectX12GameEngine.Games; +using System; +using DirectX12GameEngine.Games; using DirectX12GameEngine.Graphics; using DirectX12GameEngine.Rendering.Materials; using Microsoft.Extensions.DependencyInjection; @@ -7,23 +8,11 @@ namespace DirectX12GameEngine.Engine { public class Game : GameBase { - public Game(GameContext gameContext) : base(gameContext) - { - PresentationParameters presentationParameters = new PresentationParameters( - Window.ClientBounds.Width, Window.ClientBounds.Height, Window.NativeWindow); + private readonly IGraphicsDeviceManager graphicsDeviceManager; - switch (Context) - { -#if WINDOWS_UWP - case GameContextHolographic context: - presentationParameters.Stereo = Windows.Graphics.Holographic.HolographicDisplay.GetDefault().IsStereo; - GraphicsDevice.Presenter = new Graphics.Holographic.HolographicGraphicsPresenter(GraphicsDevice, presentationParameters, context.HolographicSpace); - break; -#endif - default: - GraphicsDevice.Presenter = new SwapChainGraphicsPresenter(GraphicsDevice, presentationParameters); - break; - } + public Game() + { + graphicsDeviceManager = Services.GetRequiredService(); SceneSystem = Services.GetRequiredService(); Script = Services.GetRequiredService(); @@ -33,7 +22,7 @@ public Game(GameContext gameContext) : base(gameContext) GameSystems.Add(Script); } - public GraphicsDevice GraphicsDevice { get; } = new GraphicsDevice(); + public GraphicsDevice? GraphicsDevice => graphicsDeviceManager.GraphicsDevice; public SceneSystem SceneSystem { get; } @@ -45,45 +34,80 @@ public override void Dispose() { base.Dispose(); - GraphicsDevice.Dispose(); + + if (graphicsDeviceManager is IDisposable disposableGraphicsDeviceManager) + { + disposableGraphicsDeviceManager.Dispose(); + } } - protected override void BeginDraw() + protected override void Initialize() { - GraphicsDevice.CommandList.Reset(); + graphicsDeviceManager.CreateDevice(); -#if WINDOWS_UWP - if (Context is GameContextXaml xamlContext && GraphicsDevice.Presenter is SwapChainGraphicsPresenter swapChainGraphicsPresenter) + if (Window is null || GraphicsDevice is null) return; + + PresentationParameters presentationParameters = new PresentationParameters( + Window.ClientBounds.Width, Window.ClientBounds.Height, Window.NativeWindow); + + switch (Context) { - var swapChainPanel = xamlContext.Control; + case GameContextHolographic context: + presentationParameters.Stereo = Windows.Graphics.Holographic.HolographicDisplay.GetDefault().IsStereo; + GraphicsDevice.Presenter = new Graphics.Holographic.HolographicGraphicsPresenter(GraphicsDevice, presentationParameters, context.HolographicSpace); + break; + default: + GraphicsDevice.Presenter = new SwapChainGraphicsPresenter(GraphicsDevice, presentationParameters); + break; + } - swapChainGraphicsPresenter.MatrixTransform = new System.Numerics.Matrix3x2 - { - M11 = 1.0f / swapChainPanel.CompositionScaleX, - M22 = 1.0f / swapChainPanel.CompositionScaleY - }; + base.Initialize(); + } + + protected override void BeginDraw() + { + if (!graphicsDeviceManager.BeginDraw()) + { + return; } -#endif - if (GraphicsDevice.Presenter != null) + if (GraphicsDevice != null) { - int width = Window.ClientBounds.Width; - int height = Window.ClientBounds.Height; + GraphicsDevice.CommandList.Reset(); - if (width != GraphicsDevice.Presenter.BackBuffer.Width || height != GraphicsDevice.Presenter.BackBuffer.Height) - { #if WINDOWS_UWP - if (!(Context is GameContextHolographic)) + if (Context is GameContextXaml xamlContext && GraphicsDevice.Presenter is SwapChainGraphicsPresenter swapChainGraphicsPresenter) + { + var swapChainPanel = xamlContext.Control; + + swapChainGraphicsPresenter.MatrixTransform = new System.Numerics.Matrix3x2 + { + M11 = 1.0f / swapChainPanel.CompositionScaleX, + M22 = 1.0f / swapChainPanel.CompositionScaleY + }; + } #endif + + if (Window != null && GraphicsDevice.Presenter != null) + { + int width = Window.ClientBounds.Width; + int height = Window.ClientBounds.Height; + + if (width != GraphicsDevice.Presenter.BackBuffer.Width || height != GraphicsDevice.Presenter.BackBuffer.Height) { - GraphicsDevice.Presenter.Resize(width, height); +#if WINDOWS_UWP + if (!(Context is GameContextHolographic)) +#endif + { + GraphicsDevice.Presenter.Resize(width, height); + } } } - } - GraphicsDevice.CommandList.ClearState(); + GraphicsDevice.CommandList.ClearState(); - GraphicsDevice.Presenter?.BeginDraw(GraphicsDevice.CommandList); + GraphicsDevice.Presenter?.BeginDraw(GraphicsDevice.CommandList); + } base.BeginDraw(); } @@ -92,15 +116,15 @@ protected override void EndDraw() { base.EndDraw(); - GraphicsDevice.CommandList.Flush(true); - GraphicsDevice.Presenter?.Present(); + GraphicsDevice?.CommandList.Flush(true); + graphicsDeviceManager.EndDraw(); } protected override void ConfigureServices(IServiceCollection services) { base.ConfigureServices(services); - services.AddSingleton(GraphicsDevice); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/DirectX12GameEngine.Engine/GameSystem.cs b/DirectX12GameEngine.Engine/GameSystem.cs deleted file mode 100644 index 475537c..0000000 --- a/DirectX12GameEngine.Engine/GameSystem.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using DirectX12GameEngine.Games; -using DirectX12GameEngine.Graphics; -using Microsoft.Extensions.DependencyInjection; - -namespace DirectX12GameEngine.Engine -{ - public abstract class GameSystem : GameSystemBase - { - public GameSystem(IServiceProvider services) : base(services) - { - GraphicsDevice = services.GetRequiredService(); - } - - protected GraphicsDevice GraphicsDevice { get; } - } -} diff --git a/DirectX12GameEngine.Engine/GraphicsDeviceManager.cs b/DirectX12GameEngine.Engine/GraphicsDeviceManager.cs new file mode 100644 index 0000000..7dcf937 --- /dev/null +++ b/DirectX12GameEngine.Engine/GraphicsDeviceManager.cs @@ -0,0 +1,54 @@ +using System; +using DirectX12GameEngine.Graphics; + +namespace DirectX12GameEngine.Engine +{ + public class GraphicsDeviceManager : IGraphicsDeviceManager, IDisposable + { + private bool isDrawing; + + public GraphicsDevice? GraphicsDevice { get; private set; } + + public bool BeginDraw() + { + if (GraphicsDevice != null) + { + isDrawing = true; + return true; + } + else + { + return false; + } + } + + public void CreateDevice() + { + GraphicsDevice = new GraphicsDevice(); + } + + public void Dispose() + { + if (GraphicsDevice != null) + { + if (GraphicsDevice.Presenter != null) + { + GraphicsDevice.Presenter.Dispose(); + GraphicsDevice.Presenter = null; + } + + GraphicsDevice.Dispose(); + GraphicsDevice = null; + } + } + + public void EndDraw() + { + if (isDrawing) + { + isDrawing = false; + GraphicsDevice?.Presenter?.Present(); + } + } + } +} diff --git a/DirectX12GameEngine.Engine/IGraphicsDeviceManager.cs b/DirectX12GameEngine.Engine/IGraphicsDeviceManager.cs new file mode 100644 index 0000000..8b95750 --- /dev/null +++ b/DirectX12GameEngine.Engine/IGraphicsDeviceManager.cs @@ -0,0 +1,15 @@ +using DirectX12GameEngine.Graphics; + +namespace DirectX12GameEngine.Engine +{ + public interface IGraphicsDeviceManager + { + GraphicsDevice? GraphicsDevice { get; } + + bool BeginDraw(); + + void CreateDevice(); + + void EndDraw(); + } +} diff --git a/DirectX12GameEngine.Engine/SceneSystem.cs b/DirectX12GameEngine.Engine/SceneSystem.cs index 9ee5330..c24cc77 100644 --- a/DirectX12GameEngine.Engine/SceneSystem.cs +++ b/DirectX12GameEngine.Engine/SceneSystem.cs @@ -4,7 +4,7 @@ namespace DirectX12GameEngine.Engine { - public sealed class SceneSystem : GameSystem + public sealed class SceneSystem : GameSystemBase { public SceneSystem(IServiceProvider services) : base(services) { diff --git a/DirectX12GameEngine.Games/GameBase.cs b/DirectX12GameEngine.Games/GameBase.cs index ff1c7f2..d65fb76 100644 --- a/DirectX12GameEngine.Games/GameBase.cs +++ b/DirectX12GameEngine.Games/GameBase.cs @@ -10,75 +10,112 @@ public abstract class GameBase : IDisposable { private readonly object tickLock = new object(); + private bool isExiting; private DateTime previousTime; private TimeSpan totalTime; - public GameBase(GameContext gameContext) + public GameBase() { - Context = gameContext; - ServiceCollection services = new ServiceCollection(); ConfigureServices(services); Services = services.BuildServiceProvider(); - Window = GameWindow.Create(this); - Content = Services.GetRequiredService(); GameSystems = Services.GetRequiredService>(); } public ContentManager Content { get; } - public GameContext Context { get; } - public IList GameSystems { get; } - public GameWindow Window { get; } + public GameContext? Context { get; private set; } + + public GameWindow? Window { get; private set; } public IServiceProvider Services { get; } public GameTime Time { get; } = new GameTime(); + public bool IsRunning { get; private set; } + public virtual void Dispose() { foreach (GameSystemBase gameSystem in GameSystems) { gameSystem.Dispose(); } + + Window?.Exit(); + Window = null; } - public void Run() + public void Run(GameContext? context = null) { + if (IsRunning) + { + throw new InvalidOperationException("This game is already running."); + } + + IsRunning = true; + + Context = context; + Window = Context?.CreateWindow(this); + Initialize(); LoadContentAsync(); previousTime = DateTime.Now; - Window.Run(); + BeginRun(); + + Window?.Run(); + } + + public void Exit() + { + if (IsRunning) + { + isExiting = true; + Window?.Exit(); + } } public void Tick() { - lock (tickLock) + try { - DateTime currentTime = DateTime.Now; - TimeSpan elapsedTime = currentTime - previousTime; + lock (tickLock) + { + if (isExiting) + { + CheckEndRun(); + return; + } + + DateTime currentTime = DateTime.Now; + TimeSpan elapsedTime = currentTime - previousTime; - previousTime = currentTime; - totalTime += elapsedTime; + previousTime = currentTime; + totalTime += elapsedTime; - Time.Update(totalTime, elapsedTime); + Time.Update(totalTime, elapsedTime); - Update(Time); + Update(Time); - BeginDraw(); - Draw(Time); + BeginDraw(); + Draw(Time); + } + } + finally + { EndDraw(); + + CheckEndRun(); } } - protected void Initialize() + protected virtual void Initialize() { foreach (GameSystemBase gameSystem in GameSystems) { @@ -98,6 +135,10 @@ protected virtual Task LoadContentAsync() return Task.WhenAll(loadingTasks); } + protected virtual void BeginRun() + { + } + protected virtual void Update(GameTime gameTime) { foreach (GameSystemBase gameSystem in GameSystems) @@ -130,11 +171,24 @@ protected virtual void EndDraw() } } + protected virtual void EndRun() + { + } + protected virtual void ConfigureServices(IServiceCollection services) { services.AddSingleton(this); services.AddSingleton(); services.AddSingleton>(); } + + private void CheckEndRun() + { + if (isExiting && IsRunning) + { + EndRun(); + IsRunning = false; + } + } } } diff --git a/DirectX12GameEngine.Games/GameContext.Uwp.cs b/DirectX12GameEngine.Games/GameContext.Uwp.cs index c3c661b..b012f30 100644 --- a/DirectX12GameEngine.Games/GameContext.Uwp.cs +++ b/DirectX12GameEngine.Games/GameContext.Uwp.cs @@ -13,6 +13,8 @@ public GameContextCoreWindow(CoreWindow? control = null, int requestedWidth = 0, { ContextType = AppContextType.CoreWindow; } + + public override GameWindow CreateWindow(GameBase game) => new GameWindowCoreWindow(game, this); } public class GameContextHolographic : GameContextCoreWindow @@ -33,6 +35,8 @@ public GameContextXaml(SwapChainPanel control, int requestedWidth = 0, int reque { ContextType = AppContextType.Xaml; } + + public override GameWindow CreateWindow(GameBase game) => new GameWindowXaml(game, this); } } #endif diff --git a/DirectX12GameEngine.Games/GameContext.WindowsDesktop.cs b/DirectX12GameEngine.Games/GameContext.WindowsDesktop.cs index 115176a..c26f7a0 100644 --- a/DirectX12GameEngine.Games/GameContext.WindowsDesktop.cs +++ b/DirectX12GameEngine.Games/GameContext.WindowsDesktop.cs @@ -11,6 +11,8 @@ public GameContextWinForms(Control? control = null, int requestedWidth = 0, int { ContextType = AppContextType.WinForms; } + + public override GameWindow CreateWindow(GameBase game) => new GameWindowWinForms(game, this); } } #endif diff --git a/DirectX12GameEngine.Games/GameContext.cs b/DirectX12GameEngine.Games/GameContext.cs index 5909a52..a979174 100644 --- a/DirectX12GameEngine.Games/GameContext.cs +++ b/DirectX12GameEngine.Games/GameContext.cs @@ -9,6 +9,8 @@ public abstract class GameContext public int RequestedHeight { get; private protected set; } public int RequestedWidth { get; private protected set; } + + public abstract GameWindow CreateWindow(GameBase game); } public abstract class GameContext : GameContext diff --git a/DirectX12GameEngine.Games/GameWindow.cs b/DirectX12GameEngine.Games/GameWindow.cs index 9520fcd..1146bfa 100644 --- a/DirectX12GameEngine.Games/GameWindow.cs +++ b/DirectX12GameEngine.Games/GameWindow.cs @@ -14,17 +14,7 @@ protected GameWindow(GameBase game) Services = game.Services; } - public static GameWindow Create(GameBase game) => game.Context.ContextType switch - { -#if WINDOWS_UWP - AppContextType.CoreWindow => new GameWindowUwp(game), - AppContextType.Xaml => new GameWindowUwp(game), -#endif -#if NETCOREAPP - AppContextType.WinForms => (GameWindow)new GameWindowWinForms(game), -#endif - _ => throw new PlatformNotSupportedException("This context is not supported on this platform.") - }; + public bool IsExiting { get; private set; } public event EventHandler SizeChanged; @@ -38,6 +28,12 @@ public virtual void Dispose() { } + public void Exit() + { + IsExiting = true; + Dispose(); + } + internal abstract void Run(); protected virtual void OnSizeChanged(EventArgs e) diff --git a/DirectX12GameEngine.Games/GameWindowCoreWindow.cs b/DirectX12GameEngine.Games/GameWindowCoreWindow.cs new file mode 100644 index 0000000..64aab7d --- /dev/null +++ b/DirectX12GameEngine.Games/GameWindowCoreWindow.cs @@ -0,0 +1,62 @@ +#if WINDOWS_UWP +using System; +using System.Drawing; +using DirectX12GameEngine.Core; +using Windows.Graphics.Display; +using Windows.UI.Core; +using Windows.UI.ViewManagement; + +namespace DirectX12GameEngine.Games +{ + internal class GameWindowCoreWindow : GameWindow + { + private readonly ApplicationView applicationView; + private readonly CoreWindow coreWindow; + private readonly WindowHandle windowHandle; + + public GameWindowCoreWindow(GameBase game, GameContextCoreWindow context) : base(game) + { + coreWindow = context.Control; + + windowHandle = new WindowHandle(AppContextType.CoreWindow, coreWindow); + + coreWindow.SizeChanged += CoreWindow_SizeChanged; + + applicationView = ApplicationView.GetForCurrentView(); + + if (context.RequestedWidth != 0 && context.RequestedHeight != 0) + { + applicationView.SetPreferredMinSize(new Windows.Foundation.Size(context.RequestedWidth, context.RequestedHeight)); + applicationView.TryResizeView(new Windows.Foundation.Size(context.RequestedWidth, context.RequestedHeight)); + } + } + + public override Rectangle ClientBounds + { + get + { + double resolutionScale = DisplayInformation.GetForCurrentView().RawPixelsPerViewPixel; + + return new Rectangle((int)coreWindow.Bounds.X, (int)coreWindow.Bounds.X, + Math.Max(1, (int)(coreWindow.Bounds.Width * resolutionScale)), Math.Max(1, (int)(coreWindow.Bounds.Height * resolutionScale))); + } + } + + public override WindowHandle NativeWindow => windowHandle; + + internal override void Run() + { + while (!IsExiting) + { + coreWindow.Dispatcher.ProcessEvents(CoreProcessEventsOption.ProcessAllIfPresent); + Tick(); + } + } + + private void CoreWindow_SizeChanged(CoreWindow sender, WindowSizeChangedEventArgs args) + { + OnSizeChanged(EventArgs.Empty); + } + } +} +#endif diff --git a/DirectX12GameEngine.Games/GameWindowUwp.cs b/DirectX12GameEngine.Games/GameWindowUwp.cs deleted file mode 100644 index e511f5f..0000000 --- a/DirectX12GameEngine.Games/GameWindowUwp.cs +++ /dev/null @@ -1,127 +0,0 @@ -#if WINDOWS_UWP -using System; -using System.Drawing; -using DirectX12GameEngine.Core; -using Windows.Graphics.Display; -using Windows.UI.Core; -using Windows.UI.ViewManagement; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Media; - -namespace DirectX12GameEngine.Games -{ - internal class GameWindowUwp : GameWindow - { - private readonly ApplicationView applicationView; - private readonly CoreWindow? coreWindow; - private readonly SwapChainPanel? swapChainPanel; - private readonly WindowHandle windowHandle; - - public GameWindowUwp(GameBase game) : base(game) - { - GameContext gameContext = game.Context; - - switch (gameContext) - { - case GameContextCoreWindow coreWindowContext: - coreWindow = coreWindowContext.Control; - - windowHandle = new WindowHandle(AppContextType.CoreWindow, coreWindow, IntPtr.Zero); - - coreWindow.SizeChanged += CoreWindow_SizeChanged; - break; - case GameContextXaml xamlContext: - swapChainPanel = xamlContext.Control; - - windowHandle = new WindowHandle(AppContextType.Xaml, swapChainPanel, IntPtr.Zero); - - swapChainPanel.SizeChanged += SwapChainPanel_SizeChanged; - swapChainPanel.CompositionScaleChanged += SwapChainPanel_CompositionScaleChanged; - break; - default: - throw new ArgumentException(); - } - - applicationView = ApplicationView.GetForCurrentView(); - - if (gameContext.RequestedWidth != 0 && gameContext.RequestedHeight != 0) - { - applicationView.SetPreferredMinSize(new Windows.Foundation.Size(gameContext.RequestedWidth, gameContext.RequestedHeight)); - applicationView.TryResizeView(new Windows.Foundation.Size(gameContext.RequestedWidth, gameContext.RequestedHeight)); - } - } - - public override Rectangle ClientBounds - { - get - { - if (swapChainPanel != null) - { - return new Rectangle(0, 0, - Math.Max(1, (int)(swapChainPanel.ActualWidth * swapChainPanel.CompositionScaleX + 0.5f)), - Math.Max(1, (int)(swapChainPanel.ActualHeight * swapChainPanel.CompositionScaleY + 0.5f))); - } - else if (coreWindow != null) - { - double resolutionScale = DisplayInformation.GetForCurrentView().RawPixelsPerViewPixel; - - return new Rectangle((int)coreWindow.Bounds.X, (int)coreWindow.Bounds.X, - Math.Max(1, (int)(coreWindow.Bounds.Width * resolutionScale)), Math.Max(1, (int)(coreWindow.Bounds.Height * resolutionScale))); - } - else - { - throw new InvalidOperationException(); - } - } - } - - public override WindowHandle NativeWindow => windowHandle; - - public override void Dispose() - { - CompositionTarget.Rendering -= CompositionTarget_Rendering; - } - - internal override void Run() - { - if (swapChainPanel != null) - { - CompositionTarget.Rendering += CompositionTarget_Rendering; - return; - } - else if (coreWindow != null) - { - while (true) - { - coreWindow.Dispatcher.ProcessEvents(CoreProcessEventsOption.ProcessAllIfPresent); - Tick(); - } - } - else - { - throw new InvalidOperationException(); - } - } - - private void CompositionTarget_Rendering(object sender, object e) - { - Tick(); - } - - private void SwapChainPanel_CompositionScaleChanged(SwapChainPanel sender, object args) - { - OnSizeChanged(EventArgs.Empty); - } - - private void SwapChainPanel_SizeChanged(object sender, Windows.UI.Xaml.SizeChangedEventArgs e) - { - OnSizeChanged(EventArgs.Empty); - } - - private void CoreWindow_SizeChanged(CoreWindow sender, WindowSizeChangedEventArgs args) - { - OnSizeChanged(EventArgs.Empty); - } - } -} -#endif diff --git a/DirectX12GameEngine.Games/GameWindowWinForms.cs b/DirectX12GameEngine.Games/GameWindowWinForms.cs index f28523b..fd1b6ce 100644 --- a/DirectX12GameEngine.Games/GameWindowWinForms.cs +++ b/DirectX12GameEngine.Games/GameWindowWinForms.cs @@ -12,10 +12,9 @@ internal class GameWindowWinForms : GameWindow private readonly Control control; private readonly WindowHandle windowHandle; - public GameWindowWinForms(GameBase game) : base(game) + public GameWindowWinForms(GameBase game, GameContextWinForms context) : base(game) { - GameContextWinForms gameContext = (GameContextWinForms)game.Context; - control = gameContext.Control; + control = context.Control; windowHandle = new WindowHandle(AppContextType.WinForms, control, control.Handle); diff --git a/DirectX12GameEngine.Games/GameWindowXaml.cs b/DirectX12GameEngine.Games/GameWindowXaml.cs new file mode 100644 index 0000000..69beeac --- /dev/null +++ b/DirectX12GameEngine.Games/GameWindowXaml.cs @@ -0,0 +1,61 @@ +using System; +using System.Drawing; +using DirectX12GameEngine.Core; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Media; + +namespace DirectX12GameEngine.Games +{ + internal class GameWindowXaml : GameWindow + { + private readonly SwapChainPanel swapChainPanel; + private readonly WindowHandle windowHandle; + + public GameWindowXaml(GameBase game, GameContextXaml context) : base(game) + { + swapChainPanel = context.Control; + + windowHandle = new WindowHandle(AppContextType.Xaml, swapChainPanel); + + swapChainPanel.SizeChanged += SwapChainPanel_SizeChanged; + swapChainPanel.CompositionScaleChanged += SwapChainPanel_CompositionScaleChanged; + } + + public override Rectangle ClientBounds + { + get + { + return new Rectangle(0, 0, + Math.Max(1, (int)(swapChainPanel.ActualWidth * swapChainPanel.CompositionScaleX + 0.5f)), + Math.Max(1, (int)(swapChainPanel.ActualHeight * swapChainPanel.CompositionScaleY + 0.5f))); + } + } + + public override WindowHandle NativeWindow => windowHandle; + + public override void Dispose() + { + CompositionTarget.Rendering -= CompositionTarget_Rendering; + } + + internal override void Run() + { + CompositionTarget.Rendering += CompositionTarget_Rendering; + } + + private void CompositionTarget_Rendering(object sender, object e) + { + Tick(); + } + + private void SwapChainPanel_CompositionScaleChanged(SwapChainPanel sender, object args) + { + OnSizeChanged(EventArgs.Empty); + } + + private void SwapChainPanel_SizeChanged(object sender, Windows.UI.Xaml.SizeChangedEventArgs e) + { + OnSizeChanged(EventArgs.Empty); + } + } +} diff --git a/DirectX12GameEngine.Graphics/GraphicsDevice.cs b/DirectX12GameEngine.Graphics/GraphicsDevice.cs index 3abbecd..e654860 100644 --- a/DirectX12GameEngine.Graphics/GraphicsDevice.cs +++ b/DirectX12GameEngine.Graphics/GraphicsDevice.cs @@ -137,7 +137,6 @@ public void Dispose() NativeCopyCommandQueue.Dispose(); NativeCommandQueue.Dispose(); NativeFence.Dispose(); - Presenter?.Dispose(); DepthStencilViewAllocator.Dispose(); ShaderResourceViewAllocator.Dispose(); RenderTargetViewAllocator.Dispose(); diff --git a/DirectX12GameEngine.Rendering/Materials/CompiledShaderAsset.cs b/DirectX12GameEngine.Rendering/Materials/CompiledShaderAsset.cs index d5af3e6..562c482 100644 --- a/DirectX12GameEngine.Rendering/Materials/CompiledShaderAsset.cs +++ b/DirectX12GameEngine.Rendering/Materials/CompiledShaderAsset.cs @@ -2,19 +2,13 @@ using System.Runtime.InteropServices.WindowsRuntime; using System.Threading.Tasks; using DirectX12GameEngine.Core.Assets; +using Microsoft.Extensions.DependencyInjection; using Windows.Storage; namespace DirectX12GameEngine.Rendering.Materials { public class CompiledShaderAsset : Asset { - private readonly ShaderContentManager contentManager; - - public CompiledShaderAsset(ShaderContentManager contentManager) - { - this.contentManager = contentManager; - } - public string? ComputeShaderSource { get; set; } public string? VertexShaderSource { get; set; } @@ -39,20 +33,22 @@ public CompiledShaderAsset(ShaderContentManager contentManager) public string? CallableShaderSource { get; set; } - public override async Task CreateAssetAsync(CompiledShader obj) + public override async Task CreateAssetAsync(CompiledShader obj, IServiceProvider services) { - obj.ComputeShader = ComputeShaderSource is null ? null : (await FileIO.ReadBufferAsync(await contentManager.RootFolder.GetFileAsync(ComputeShaderSource))).ToArray(); - obj.VertexShader = VertexShaderSource is null ? null : (await FileIO.ReadBufferAsync(await contentManager.RootFolder.GetFileAsync(VertexShaderSource))).ToArray(); - obj.PixelShader = PixelShaderSource is null ? null : (await FileIO.ReadBufferAsync(await contentManager.RootFolder.GetFileAsync(PixelShaderSource))).ToArray(); - obj.HullShader = HullShaderSource is null ? null : (await FileIO.ReadBufferAsync(await contentManager.RootFolder.GetFileAsync(HullShaderSource))).ToArray(); - obj.DomainShader = DomainShaderSource is null ? null : (await FileIO.ReadBufferAsync(await contentManager.RootFolder.GetFileAsync(DomainShaderSource))).ToArray(); - obj.GeometryShader = GeometryShaderSource is null ? null : (await FileIO.ReadBufferAsync(await contentManager.RootFolder.GetFileAsync(GeometryShaderSource))).ToArray(); - obj.RayGenerationShader = RayGenerationShaderSource is null ? null : (await FileIO.ReadBufferAsync(await contentManager.RootFolder.GetFileAsync(RayGenerationShaderSource))).ToArray(); - obj.IntersectionShader = IntersectionShaderSource is null ? null : (await FileIO.ReadBufferAsync(await contentManager.RootFolder.GetFileAsync(IntersectionShaderSource))).ToArray(); - obj.AnyHitShader = AnyHitShaderSource is null ? null : (await FileIO.ReadBufferAsync(await contentManager.RootFolder.GetFileAsync(AnyHitShaderSource))).ToArray(); - obj.ClosestHitShader = ClosestHitShaderSource is null ? null : (await FileIO.ReadBufferAsync(await contentManager.RootFolder.GetFileAsync(ClosestHitShaderSource))).ToArray(); - obj.MissShader = MissShaderSource is null ? null : (await FileIO.ReadBufferAsync(await contentManager.RootFolder.GetFileAsync(MissShaderSource))).ToArray(); - obj.CallableShader = CallableShaderSource is null ? null : (await FileIO.ReadBufferAsync(await contentManager.RootFolder.GetFileAsync(CallableShaderSource))).ToArray(); + ShaderContentManager shaderContentManager = services.GetRequiredService(); + + obj.ComputeShader = ComputeShaderSource is null ? null : (await FileIO.ReadBufferAsync(await shaderContentManager.RootFolder.GetFileAsync(ComputeShaderSource))).ToArray(); + obj.VertexShader = VertexShaderSource is null ? null : (await FileIO.ReadBufferAsync(await shaderContentManager.RootFolder.GetFileAsync(VertexShaderSource))).ToArray(); + obj.PixelShader = PixelShaderSource is null ? null : (await FileIO.ReadBufferAsync(await shaderContentManager.RootFolder.GetFileAsync(PixelShaderSource))).ToArray(); + obj.HullShader = HullShaderSource is null ? null : (await FileIO.ReadBufferAsync(await shaderContentManager.RootFolder.GetFileAsync(HullShaderSource))).ToArray(); + obj.DomainShader = DomainShaderSource is null ? null : (await FileIO.ReadBufferAsync(await shaderContentManager.RootFolder.GetFileAsync(DomainShaderSource))).ToArray(); + obj.GeometryShader = GeometryShaderSource is null ? null : (await FileIO.ReadBufferAsync(await shaderContentManager.RootFolder.GetFileAsync(GeometryShaderSource))).ToArray(); + obj.RayGenerationShader = RayGenerationShaderSource is null ? null : (await FileIO.ReadBufferAsync(await shaderContentManager.RootFolder.GetFileAsync(RayGenerationShaderSource))).ToArray(); + obj.IntersectionShader = IntersectionShaderSource is null ? null : (await FileIO.ReadBufferAsync(await shaderContentManager.RootFolder.GetFileAsync(IntersectionShaderSource))).ToArray(); + obj.AnyHitShader = AnyHitShaderSource is null ? null : (await FileIO.ReadBufferAsync(await shaderContentManager.RootFolder.GetFileAsync(AnyHitShaderSource))).ToArray(); + obj.ClosestHitShader = ClosestHitShaderSource is null ? null : (await FileIO.ReadBufferAsync(await shaderContentManager.RootFolder.GetFileAsync(ClosestHitShaderSource))).ToArray(); + obj.MissShader = MissShaderSource is null ? null : (await FileIO.ReadBufferAsync(await shaderContentManager.RootFolder.GetFileAsync(MissShaderSource))).ToArray(); + obj.CallableShader = CallableShaderSource is null ? null : (await FileIO.ReadBufferAsync(await shaderContentManager.RootFolder.GetFileAsync(CallableShaderSource))).ToArray(); } } } diff --git a/DirectX12GameEngine.Rendering/Materials/MaterialGeneratorContext.cs b/DirectX12GameEngine.Rendering/Materials/MaterialGeneratorContext.cs index 6c8b2ae..ad991d5 100644 --- a/DirectX12GameEngine.Rendering/Materials/MaterialGeneratorContext.cs +++ b/DirectX12GameEngine.Rendering/Materials/MaterialGeneratorContext.cs @@ -103,7 +103,7 @@ public async Task CreateGraphicsPipelineStateAsync() compiledShader.DomainShader = result.DomainShader is null ? default : ShaderCompiler.CompileShader(shaderSource, SharpDX.D3DCompiler.ShaderVersion.DomainShader, result.DomainShader); compiledShader.GeometryShader = result.GeometryShader is null ? default : ShaderCompiler.CompileShader(shaderSource, SharpDX.D3DCompiler.ShaderVersion.GeometryShader, result.GeometryShader); - CompiledShaderAsset shaderAsset = new CompiledShaderAsset(Content) + CompiledShaderAsset shaderAsset = new CompiledShaderAsset { VertexShaderSource = $"VertexShader_{MaterialDescriptor.MaterialId}.cso", PixelShaderSource = $"PixelShader_{MaterialDescriptor.MaterialId}.cso", diff --git a/DirectX12WinFormsApp/Program.cs b/DirectX12WinFormsApp/Program.cs index a89c171..1ebca91 100644 --- a/DirectX12WinFormsApp/Program.cs +++ b/DirectX12WinFormsApp/Program.cs @@ -17,9 +17,9 @@ public MyForm() private void MyForm_Load(object sender, EventArgs e) { - MyGame game = new MyGame(new GameContextWinForms(this)); + MyGame game = new MyGame(); - game.Run(); + game.Run(new GameContextWinForms(this)); } } diff --git a/DirectX12XamlApp/MainPage.xaml.cs b/DirectX12XamlApp/MainPage.xaml.cs index eb05e4b..0f08218 100644 --- a/DirectX12XamlApp/MainPage.xaml.cs +++ b/DirectX12XamlApp/MainPage.xaml.cs @@ -21,8 +21,8 @@ public MainPage() private void MainPage_Loaded(object sender, RoutedEventArgs e) { - MyGame game = new MyGame(new GameContextXaml(swapChainPanel)); - game.Run(); + MyGame game = new MyGame(); + game.Run(new GameContextXaml(swapChainPanel)); } } }