Refactor and enhance graphics and audio systems
Updated target frameworks to .NET 10.0 across multiple projects for compatibility with the latest features. Refactored namespaces and introduced new classes for shader descriptors, FMOD integration, and DirectX 12 utilities using TerraFX. Replaced `Win32` bindings with TerraFX equivalents for DirectX 12. Added a C# wrapper for FMOD Studio API, including DSP and error handling. Enhanced entity queries, component storage, and query filters for better performance and type safety. Introduced new test projects and updated the solution structure. Added `meshoptimizer` bindings and integrated `meshoptimizer_native.dll`. Improved code readability, maintainability, and performance.
|
Before Width: | Height: | Size: 432 B |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 637 B |
|
Before Width: | Height: | Size: 283 B |
|
Before Width: | Height: | Size: 456 B |
|
Before Width: | Height: | Size: 2.0 KiB |
@@ -1,120 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<UserControl
|
||||
x:Class="Ghost.UnitTest.Controls.DebugConsole"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Ghost.UnitTest.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<local:LogLevelToColorConverter x:Key="LogLevelToColorConverter" />
|
||||
<local:LogLevelToSymbolConverter x:Key="LogLevelToSymbolConverter" />
|
||||
|
||||
<DataTemplate x:Key="LogItemTemplate">
|
||||
<Border Padding="8,4" Background="Transparent">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Column="0"
|
||||
Margin="0,0,8,0"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="Segoe UI Symbol"
|
||||
Foreground="{Binding Level, Converter={StaticResource LogLevelToColorConverter}}"
|
||||
Text="{Binding Level, Converter={StaticResource LogLevelToSymbolConverter}}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
Margin="0,0,8,0"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="Consolas"
|
||||
Foreground="Gray"
|
||||
Text="{Binding Timestamp}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Message}"
|
||||
TextWrapping="Wrap" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Toolbar -->
|
||||
<Border
|
||||
Grid.Row="0"
|
||||
Background="{ThemeResource SystemControlBackgroundAltMediumBrush}"
|
||||
BorderBrush="{ThemeResource SystemControlForegroundBaseLowBrush}"
|
||||
BorderThickness="0,0,0,1">
|
||||
<StackPanel Margin="8,4" Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="ClearButton"
|
||||
Margin="0,0,8,0"
|
||||
Click="ClearButton_Click"
|
||||
Content="Clear" />
|
||||
<CheckBox
|
||||
x:Name="AutoScrollCheckBox"
|
||||
Margin="0,0,8,0"
|
||||
Content="Auto Scroll"
|
||||
IsChecked="True" />
|
||||
<CheckBox
|
||||
x:Name="ShowStackTraceCheckBox"
|
||||
Margin="0,0,8,0"
|
||||
Checked="ShowStackTraceCheckBox_Checked"
|
||||
Content="Stack Trace"
|
||||
Unchecked="ShowStackTraceCheckBox_Unchecked" />
|
||||
|
||||
<!-- Log level filters -->
|
||||
<TextBlock
|
||||
Margin="16,0,8,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="Show:" />
|
||||
<CheckBox
|
||||
x:Name="ShowInfoCheckBox"
|
||||
Margin="0,0,4,0"
|
||||
Content="Info"
|
||||
IsChecked="True" />
|
||||
<CheckBox
|
||||
x:Name="ShowWarningCheckBox"
|
||||
Margin="0,0,4,0"
|
||||
Content="Warning"
|
||||
IsChecked="True" />
|
||||
<CheckBox
|
||||
x:Name="ShowErrorCheckBox"
|
||||
Margin="0,0,4,0"
|
||||
Content="Error"
|
||||
IsChecked="True" />
|
||||
<CheckBox
|
||||
x:Name="ShowDebugCheckBox"
|
||||
Margin="0,0,4,0"
|
||||
Content="Debug"
|
||||
IsChecked="True" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Log display -->
|
||||
<ScrollViewer
|
||||
x:Name="LogScrollViewer"
|
||||
Grid.Row="1"
|
||||
HorizontalScrollBarVisibility="Auto"
|
||||
HorizontalScrollMode="Auto"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
VerticalScrollMode="Auto"
|
||||
ZoomMode="Disabled">
|
||||
<ItemsRepeater x:Name="LogItemsRepeater" ItemTemplate="{StaticResource LogItemTemplate}" />
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -1,165 +0,0 @@
|
||||
using Ghost.UnitTest.Models;
|
||||
using Ghost.UnitTest.Services;
|
||||
using Microsoft.UI;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Ghost.UnitTest.Controls;
|
||||
|
||||
public sealed partial class DebugConsole : UserControl
|
||||
{
|
||||
private readonly ObservableCollection<LogItem> _filteredLogs = [];
|
||||
private readonly LoggingService _loggingService;
|
||||
|
||||
public DebugConsole()
|
||||
{
|
||||
InitializeComponent();
|
||||
_loggingService = LoggingService.Instance;
|
||||
|
||||
LogItemsRepeater.ItemsSource = _filteredLogs;
|
||||
|
||||
// Subscribe to logging events
|
||||
_loggingService.LogAdded += OnLogAdded;
|
||||
_loggingService.LogsCleared += OnLogsCleared;
|
||||
|
||||
// Subscribe to filter changes
|
||||
ShowInfoCheckBox.Checked += OnFilterChanged;
|
||||
ShowInfoCheckBox.Unchecked += OnFilterChanged;
|
||||
ShowWarningCheckBox.Checked += OnFilterChanged;
|
||||
ShowWarningCheckBox.Unchecked += OnFilterChanged;
|
||||
ShowErrorCheckBox.Checked += OnFilterChanged;
|
||||
ShowErrorCheckBox.Unchecked += OnFilterChanged;
|
||||
ShowDebugCheckBox.Checked += OnFilterChanged;
|
||||
ShowDebugCheckBox.Unchecked += OnFilterChanged;
|
||||
|
||||
// Load existing logs
|
||||
RefreshLogs();
|
||||
}
|
||||
|
||||
private void OnLogAdded(LogItem logItem)
|
||||
{
|
||||
DispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
if (ShouldShowLogItem(logItem))
|
||||
{
|
||||
_filteredLogs.Add(logItem);
|
||||
|
||||
if (AutoScrollCheckBox.IsChecked == true)
|
||||
{
|
||||
LogScrollViewer.ScrollToVerticalOffset(LogScrollViewer.ScrollableHeight);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void OnLogsCleared()
|
||||
{
|
||||
DispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
_filteredLogs.Clear();
|
||||
});
|
||||
}
|
||||
|
||||
private void OnFilterChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
RefreshLogs();
|
||||
}
|
||||
|
||||
private bool ShouldShowLogItem(LogItem logItem)
|
||||
{
|
||||
return logItem.Level switch
|
||||
{
|
||||
LogLevel.Info => ShowInfoCheckBox.IsChecked == true,
|
||||
LogLevel.Warning => ShowWarningCheckBox.IsChecked == true,
|
||||
LogLevel.Error => ShowErrorCheckBox.IsChecked == true,
|
||||
LogLevel.Debug => ShowDebugCheckBox.IsChecked == true,
|
||||
_ => true
|
||||
};
|
||||
}
|
||||
|
||||
private void RefreshLogs()
|
||||
{
|
||||
_filteredLogs.Clear();
|
||||
|
||||
foreach (var log in _loggingService.Logs)
|
||||
{
|
||||
if (ShouldShowLogItem(log))
|
||||
{
|
||||
_filteredLogs.Add(log);
|
||||
}
|
||||
}
|
||||
|
||||
if (AutoScrollCheckBox.IsChecked == true)
|
||||
{
|
||||
LogScrollViewer.ScrollToVerticalOffset(LogScrollViewer.ScrollableHeight);
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_loggingService.Clear();
|
||||
}
|
||||
|
||||
private void ShowStackTraceCheckBox_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_loggingService.CaptureStackTrace = true;
|
||||
}
|
||||
|
||||
private void ShowStackTraceCheckBox_Unchecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_loggingService.CaptureStackTrace = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Converter for log level to color
|
||||
public class LogLevelToColorConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if (value is LogLevel level)
|
||||
{
|
||||
return level switch
|
||||
{
|
||||
LogLevel.Info => new SolidColorBrush(Colors.DodgerBlue),
|
||||
LogLevel.Warning => new SolidColorBrush(Colors.Orange),
|
||||
LogLevel.Error => new SolidColorBrush(Colors.Red),
|
||||
LogLevel.Debug => new SolidColorBrush(Colors.Gray),
|
||||
_ => new SolidColorBrush(Colors.Black)
|
||||
};
|
||||
}
|
||||
return new SolidColorBrush(Colors.Black);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
// Converter for log level to symbol
|
||||
public class LogLevelToSymbolConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if (value is LogLevel level)
|
||||
{
|
||||
return level switch
|
||||
{
|
||||
LogLevel.Info => "ℹ",
|
||||
LogLevel.Warning => "⚠",
|
||||
LogLevel.Error => "✖",
|
||||
LogLevel.Debug => "🐛",
|
||||
_ => "•"
|
||||
};
|
||||
}
|
||||
return "•";
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net9.0-windows10.0.22621.0</TargetFramework>
|
||||
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
|
||||
<RootNamespace>Ghost.UnitTest</RootNamespace>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<Platforms>x86;x64;ARM64</Platforms>
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
|
||||
<PublishProfile>win-$(Platform).pubxml</PublishProfile>
|
||||
<UseWinUI>true</UseWinUI>
|
||||
<EnableMsixTooling>true</EnableMsixTooling>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Controls\DebugConsole.xaml" />
|
||||
<None Remove="Windows\DebugOutputWindow.xaml" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Remove="UnitTestApp.xaml" />
|
||||
<ApplicationDefinition Include="UnitTestApp.xaml" />
|
||||
<ProjectCapability Include="TestContainer" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="Assets\SplashScreen.scale-200.png" />
|
||||
<Content Include="Assets\LockScreenLogo.scale-200.png" />
|
||||
<Content Include="Assets\Square150x150Logo.scale-200.png" />
|
||||
<Content Include="Assets\Square44x44Logo.scale-200.png" />
|
||||
<Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
|
||||
<Content Include="Assets\StoreLogo.png" />
|
||||
<Content Include="Assets\Wide310x150Logo.scale-200.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Manifest Include="$(ApplicationManifest)" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--
|
||||
Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging
|
||||
Tools extension to be activated for this project even if the Windows App SDK Nuget
|
||||
package has not yet been restored.
|
||||
-->
|
||||
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
|
||||
<ProjectCapability Include="Msix" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.TestPlatform.TestHost" Version="17.14.1" />
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.4188" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.7.250606001" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.9.3" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.9.3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ghost.Editor.Core\Ghost.Editor.Core.csproj" />
|
||||
<ProjectReference Include="..\Ghost.Engine\Ghost.Engine.csproj" />
|
||||
<ProjectReference Include="..\Ghost.Entities\Ghost.Entities.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Misaki.HighPerformance.Unsafe">
|
||||
<HintPath>..\..\Class\Misaki.HighPerformance\Misaki.HighPerformance.LowLevel\bin\Release\net9.0\Misaki.HighPerformance.LowLevel.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="Windows\DebugOutputWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\DebugConsole.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<!--
|
||||
Defining the "HasPackageAndPublishMenuAddedByProject" property here allows the Solution
|
||||
Explorer "Package and Publish" context menu entry to be enabled for this project even if
|
||||
the Windows App SDK Nuget package has not yet been restored.
|
||||
-->
|
||||
<PropertyGroup Condition="'$(DisableHasPackageAndPublishMenuAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
|
||||
<HasPackageAndPublishMenu>true</HasPackageAndPublishMenu>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Publish Properties -->
|
||||
<PropertyGroup>
|
||||
<PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>
|
||||
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
|
||||
<PublishTrimmed>False</PublishTrimmed>
|
||||
<SupportedOSPlatformVersion>10.0.20348.0</SupportedOSPlatformVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,52 +0,0 @@
|
||||
namespace Ghost.UnitTest.Models;
|
||||
|
||||
public enum LogLevel
|
||||
{
|
||||
Info,
|
||||
Warning,
|
||||
Error,
|
||||
Debug
|
||||
}
|
||||
|
||||
internal struct LogItem
|
||||
{
|
||||
public LogLevel Level
|
||||
{
|
||||
get; init;
|
||||
}
|
||||
public string Message
|
||||
{
|
||||
get; init;
|
||||
}
|
||||
public DateTime Timestamp
|
||||
{
|
||||
get; init;
|
||||
}
|
||||
public string? StackTrace
|
||||
{
|
||||
get; init;
|
||||
}
|
||||
|
||||
public LogItem(LogLevel level, string message, string? stackTrace = null)
|
||||
{
|
||||
Level = level;
|
||||
Message = message;
|
||||
StackTrace = stackTrace;
|
||||
Timestamp = DateTime.Now;
|
||||
}
|
||||
|
||||
public override readonly string ToString()
|
||||
{
|
||||
return $"{Timestamp:HH:mm:ss.fff} [{Level}] {Message}";
|
||||
}
|
||||
|
||||
public readonly string ToStringWithStackTrace()
|
||||
{
|
||||
if (string.IsNullOrEmpty(StackTrace))
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
|
||||
return $"{ToString()}\n{StackTrace}";
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<Package
|
||||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
IgnorableNamespaces="uap rescap">
|
||||
|
||||
<Identity
|
||||
Name="7329af59-6d61-48e9-9041-8f2d3d23696b"
|
||||
Publisher="CN=Misaki"
|
||||
Version="1.0.0.0" />
|
||||
|
||||
<mp:PhoneIdentity PhoneProductId="7329af59-6d61-48e9-9041-8f2d3d23696b" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
<Properties>
|
||||
<DisplayName>Ghost.UnitTest</DisplayName>
|
||||
<PublisherDisplayName>Misaki</PublisherDisplayName>
|
||||
<Logo>Assets\StoreLogo.png</Logo>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
<Resource Language="x-generate"/>
|
||||
</Resources>
|
||||
|
||||
<Applications>
|
||||
<Application Id="App"
|
||||
Executable="$targetnametoken$.exe"
|
||||
EntryPoint="$targetentrypoint$">
|
||||
<uap:VisualElements
|
||||
DisplayName="Ghost.UnitTest"
|
||||
Description="Ghost.UnitTest"
|
||||
BackgroundColor="transparent"
|
||||
Square150x150Logo="Assets\Square150x150Logo.png"
|
||||
Square44x44Logo="Assets\Square44x44Logo.png">
|
||||
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" />
|
||||
<uap:SplashScreen Image="Assets\SplashScreen.png" />
|
||||
</uap:VisualElements>
|
||||
</Application>
|
||||
</Applications>
|
||||
|
||||
<Capabilities>
|
||||
<rescap:Capability Name="runFullTrust" />
|
||||
</Capabilities>
|
||||
</Package>
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"profiles": {
|
||||
"Ghost.UnitTest (Package)": {
|
||||
"commandName": "MsixPackage",
|
||||
"nativeDebugging": false
|
||||
},
|
||||
"Ghost.UnitTest (Unpackaged)": {
|
||||
"commandName": "Project"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
using Ghost.UnitTest.Models;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ghost.UnitTest.Services;
|
||||
|
||||
internal class LoggingService
|
||||
{
|
||||
private const int MAX_LOGS = 4096;
|
||||
private static readonly Lazy<LoggingService> _instance = new(() => new LoggingService());
|
||||
|
||||
private readonly List<LogItem> _logs = [];
|
||||
private readonly object _lockObject = new();
|
||||
|
||||
public static LoggingService Instance => _instance.Value;
|
||||
|
||||
public IReadOnlyList<LogItem> Logs
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
return _logs.AsReadOnly();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool CaptureStackTrace { get; set; } = false;
|
||||
|
||||
public event Action<LogItem>? LogAdded;
|
||||
public event Action? LogsCleared;
|
||||
|
||||
private LoggingService()
|
||||
{
|
||||
}
|
||||
|
||||
private void AddLog(LogItem logItem)
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
if (_logs.Count >= MAX_LOGS)
|
||||
{
|
||||
_logs.RemoveAt(0);
|
||||
}
|
||||
|
||||
_logs.Add(logItem);
|
||||
}
|
||||
|
||||
// Invoke event outside of lock to prevent deadlock
|
||||
LogAdded?.Invoke(logItem);
|
||||
}
|
||||
|
||||
private string? CaptureCurrentStackTrace()
|
||||
{
|
||||
if (!CaptureStackTrace)
|
||||
return null;
|
||||
|
||||
var stackTrace = new StackTrace(skipFrames: 2, fNeedFileInfo: true);
|
||||
return stackTrace.ToString();
|
||||
}
|
||||
|
||||
public void Log(LogLevel level, object? message)
|
||||
{
|
||||
var stackTrace = CaptureCurrentStackTrace();
|
||||
var logItem = new LogItem(level, message?.ToString() ?? string.Empty, stackTrace);
|
||||
AddLog(logItem);
|
||||
}
|
||||
|
||||
public void LogInfo(object? message)
|
||||
{
|
||||
Log(LogLevel.Info, message);
|
||||
}
|
||||
|
||||
public void LogWarning(object? message)
|
||||
{
|
||||
Log(LogLevel.Warning, message);
|
||||
}
|
||||
|
||||
public void LogError(object? message)
|
||||
{
|
||||
Log(LogLevel.Error, message);
|
||||
}
|
||||
|
||||
public void LogError(Exception exception)
|
||||
{
|
||||
var logItem = new LogItem(LogLevel.Error, exception.Message, exception.StackTrace);
|
||||
AddLog(logItem);
|
||||
}
|
||||
|
||||
public void LogDebug(object? message)
|
||||
{
|
||||
Log(LogLevel.Debug, message);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
_logs.Clear();
|
||||
}
|
||||
|
||||
LogsCleared?.Invoke();
|
||||
}
|
||||
|
||||
// Static methods for easier usage throughout the test project
|
||||
public static void Info(object? message) => Instance.LogInfo(message);
|
||||
public static void Warning(object? message) => Instance.LogWarning(message);
|
||||
public static void Error(object? message) => Instance.LogError(message);
|
||||
public static void Error(Exception exception) => Instance.LogError(exception);
|
||||
public static void Debug(object? message) => Instance.LogDebug(message);
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
using Ghost.Entities;
|
||||
using Ghost.Entities.Components;
|
||||
using Ghost.Entities.Systems;
|
||||
using Ghost.UnitTest.Services;
|
||||
using Ghost.UnitTest.TestFramework;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Ghost.UnitTest.Test;
|
||||
|
||||
public partial class EntityTest : ITest
|
||||
{
|
||||
public void Run()
|
||||
{
|
||||
var world = World.Create();
|
||||
|
||||
var entity1 = world.EntityManager.CreateEntity();
|
||||
var entity2 = world.EntityManager.CreateEntity();
|
||||
var entity3 = world.EntityManager.CreateEntity();
|
||||
|
||||
world.EntityManager.AddComponent(entity1, new Transform { position = new Vector3(1, 2, 3) });
|
||||
world.EntityManager.AddComponent(entity1, new Mesh { index = 42 });
|
||||
world.EntityManager.AddScript<UIManager>(entity1);
|
||||
world.EntityManager.AddScript<EventManager>(entity1);
|
||||
|
||||
world.EntityManager.AddComponent(entity2, new Transform { position = new Vector3(4, 5, 6) });
|
||||
world.EntityManager.AddComponent(entity2, new Mesh { index = 43 });
|
||||
world.EntityManager.AddScript<UserScript>(entity2);
|
||||
|
||||
world.EntityManager.AddComponent(entity3, new Transform { position = new Vector3(7, 8, 9) });
|
||||
world.EntityManager.AddScript<EventManager>(entity3);
|
||||
|
||||
foreach (var (_, transform) in world.Query<Transform>())
|
||||
{
|
||||
transform.ValueRW.position += new Vector3(1, 1, 1);
|
||||
}
|
||||
|
||||
foreach (var (_, mesh) in world.Query<Mesh>())
|
||||
{
|
||||
mesh.ValueRW.index += 1;
|
||||
}
|
||||
|
||||
world.EntityManager.RemoveEntity(ref entity2);
|
||||
|
||||
var entity4 = world.EntityManager.CreateEntity();
|
||||
world.EntityManager.AddComponent(entity4, new Transform { position = new Vector3(10, 11, 12) });
|
||||
world.EntityManager.AddComponent(entity4, new Mesh { index = 44 });
|
||||
world.EntityManager.AddScript<UserScript>(entity4);
|
||||
|
||||
world.SystemStorage.AddSystem<TestSystem2>();
|
||||
world.SystemStorage.AddSystem<TestSystem>();
|
||||
|
||||
world.SystemStorage.CreateSystems();
|
||||
world.SystemStorage.UpdateSystems();
|
||||
|
||||
world.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public class TestSystem : ISystem
|
||||
{
|
||||
public void OnCreate(in SystemState state)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnUpdate(in SystemState state)
|
||||
{
|
||||
foreach (var (entity, transform) in state.World.Query<Transform>())
|
||||
{
|
||||
LoggingService.Info($"Entity {entity.ID}: Transform Position = {transform.ValueRO.position}");
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDestroy(in SystemState state)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[DependsOn(typeof(TestSystem))]
|
||||
public class TestSystem2 : ISystem
|
||||
{
|
||||
public void OnCreate(in SystemState state)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnUpdate(in SystemState state)
|
||||
{
|
||||
foreach (var (entity, mesh) in state.World.Query<Mesh>())
|
||||
{
|
||||
LoggingService.Info($"Entity {entity.ID}: Mesh Index = {mesh.ValueRO.index}");
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDestroy(in SystemState state)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public struct Transform : IComponentData
|
||||
{
|
||||
public Vector3 position;
|
||||
public Quaternion rotation;
|
||||
public Vector3 scale;
|
||||
}
|
||||
|
||||
public struct Mesh : IComponentData
|
||||
{
|
||||
public uint index;
|
||||
}
|
||||
|
||||
public class UserScript : ScriptComponent
|
||||
{
|
||||
public override int ExecutionOrder => -1;
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
LoggingService.Info("UserScript started for entity: " + Owner.ID);
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
LoggingService.Info("UserScript updating for entity: " + Owner.ID);
|
||||
}
|
||||
|
||||
public override void OnDestroy()
|
||||
{
|
||||
LoggingService.Info("UserScript destroyed for entity: " + Owner.ID);
|
||||
}
|
||||
}
|
||||
|
||||
public class UIManager : ScriptComponent
|
||||
{
|
||||
public override void Start()
|
||||
{
|
||||
LoggingService.Info("UIManager started for entity: " + Owner.ID);
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
LoggingService.Info("UIManager updating for entity: " + Owner.ID);
|
||||
}
|
||||
|
||||
public override void OnDestroy()
|
||||
{
|
||||
LoggingService.Info("UIManager destroyed for entity: " + Owner.ID);
|
||||
}
|
||||
}
|
||||
|
||||
public class EventManager : ScriptComponent
|
||||
{
|
||||
public override void Start()
|
||||
{
|
||||
LoggingService.Info("EventManager started for entity: " + Owner.ID);
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
LoggingService.Info("EventManager updating for entity: " + Owner.ID);
|
||||
}
|
||||
|
||||
public override void OnDestroy()
|
||||
{
|
||||
LoggingService.Info("EventManager destroyed for entity: " + Owner.ID);
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
using Ghost.Editor.Core.SceneGraph;
|
||||
using Ghost.Entities;
|
||||
using Ghost.UnitTest.TestFramework;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Ghost.UnitTest.Test;
|
||||
|
||||
internal class SerializationTest : ITest
|
||||
{
|
||||
private const string _TEST_FILE_PATH = "C:/Users/Misaki/Downloads/testScene.ghostscene";
|
||||
|
||||
public void Run()
|
||||
{
|
||||
var testWorld = World.Create();
|
||||
var testScene = new WorldNode(testWorld, "Test Scene");
|
||||
|
||||
var entity1 = SceneGraphHelpers.CreateEntityNode(testScene, "entity 1");
|
||||
var entity2 = SceneGraphHelpers.CreateEntityNode(testScene, "entity 2");
|
||||
var entity3 = SceneGraphHelpers.CreateEntityNode(testScene, "entity 3");
|
||||
var entity4 = SceneGraphHelpers.CreateEntityNode(testScene, "entity 4");
|
||||
var entity5 = SceneGraphHelpers.CreateEntityNode(testScene, "entity 5");
|
||||
|
||||
testWorld.SystemStorage.AddSystem<TestSystem>();
|
||||
|
||||
SceneGraphHelpers.AttachChild(testScene, entity1, entity2);
|
||||
SceneGraphHelpers.AttachChild(testScene, entity1, entity3);
|
||||
SceneGraphHelpers.AttachChild(testScene, entity2, entity4);
|
||||
|
||||
testScene.AddChild(entity1);
|
||||
testScene.AddChild(entity5);
|
||||
|
||||
var createStream = new FileStream(_TEST_FILE_PATH, FileMode.Create, FileAccess.Write, FileShare.None);
|
||||
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
IncludeFields = true,
|
||||
IgnoreReadOnlyProperties = true,
|
||||
};
|
||||
|
||||
JsonSerializer.Serialize(createStream, testScene, options);
|
||||
|
||||
createStream.Dispose();
|
||||
testWorld.Dispose();
|
||||
|
||||
var readStream = new FileStream(_TEST_FILE_PATH, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
|
||||
var deserializedScene = JsonSerializer.Deserialize<WorldNode>(readStream, options) ?? throw new Exception("Deserialization failed.");
|
||||
deserializedScene.LoadAsync();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Ghost.UnitTest.TestFramework;
|
||||
|
||||
internal interface ITest
|
||||
{
|
||||
public void Run();
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
namespace Ghost.UnitTest.TestFramework;
|
||||
|
||||
internal class TestRunner
|
||||
{
|
||||
public static void Run<T>()
|
||||
where T : ITest, new()
|
||||
{
|
||||
var test = new T();
|
||||
test.Run();
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Application
|
||||
x:Class="Ghost.UnitTest.UnitTestApp"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Ghost.UnitTest">
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
<ResourceDictionary Source="ms-appx:///Microsoft.UI.Xaml/DensityStyles/Compact.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<!-- Other app resources here -->
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
@@ -1,43 +0,0 @@
|
||||
using Ghost.UnitTest.Test;
|
||||
using Ghost.UnitTest.TestFramework;
|
||||
using Ghost.UnitTest.Windows;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
|
||||
namespace Ghost.UnitTest;
|
||||
/// <summary>
|
||||
/// Provides application-specific behavior to supplement the default Application class.
|
||||
/// </summary>
|
||||
public partial class UnitTestApp : Application
|
||||
{
|
||||
private Window? _window;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the singleton application object. This is the first line of authored code
|
||||
/// executed, and as such is the logical equivalent of main() or WinMain().
|
||||
/// </summary>
|
||||
public UnitTestApp()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the application is launched.
|
||||
/// </summary>
|
||||
/// <param name="args">Details about the launch request and process.</param>
|
||||
protected override void OnLaunched(LaunchActivatedEventArgs args)
|
||||
{
|
||||
Microsoft.VisualStudio.TestPlatform.TestExecutor.UnitTestClient.CreateDefaultUI();
|
||||
|
||||
_window = new DebugOutputWindow();
|
||||
_window.Activate();
|
||||
|
||||
UITestMethodAttribute.DispatcherQueue = _window.DispatcherQueue;
|
||||
|
||||
Microsoft.VisualStudio.TestPlatform.TestExecutor.UnitTestClient.Run(Environment.CommandLine);
|
||||
TestRunner.Run<EntityTest>();
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Window
|
||||
x:Class="Ghost.UnitTest.Windows.DebugOutputWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Ghost.UnitTest.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Ghost.UnitTest.Windows"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Title="DebugOutputWindow"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Window.SystemBackdrop>
|
||||
<MicaBackdrop />
|
||||
</Window.SystemBackdrop>
|
||||
|
||||
<Grid>
|
||||
<controls:DebugConsole HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,11 +0,0 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
|
||||
namespace Ghost.UnitTest.Windows;
|
||||
|
||||
internal sealed partial class DebugOutputWindow : Window
|
||||
{
|
||||
public DebugOutputWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Window
|
||||
x:Class="Ghost.UnitTest.Windows.GraphicsTestWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Ghost.UnitTest.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Ghost.UnitTest.Windows"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Title="GraphicsTestWindow"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Window.SystemBackdrop>
|
||||
<MicaBackdrop />
|
||||
</Window.SystemBackdrop>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="300" MinHeight="150" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Main test content area -->
|
||||
<SwapChainPanel
|
||||
x:Name="Panel"
|
||||
Grid.Row="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch" />
|
||||
|
||||
<!-- Splitter -->
|
||||
<Border
|
||||
Grid.Row="1"
|
||||
Height="4"
|
||||
HorizontalAlignment="Stretch"
|
||||
Background="{ThemeResource SystemControlBackgroundBaseLowBrush}" />
|
||||
|
||||
<!-- Debug Console -->
|
||||
<Border
|
||||
Grid.Row="2"
|
||||
Background="{ThemeResource SystemControlBackgroundAltHighBrush}"
|
||||
BorderBrush="{ThemeResource SystemControlForegroundBaseLowBrush}"
|
||||
BorderThickness="0,1,0,0">
|
||||
<controls:DebugConsole x:Name="DebugConsole" />
|
||||
</Border>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,67 +0,0 @@
|
||||
using Ghost.Graphics;
|
||||
using Ghost.Graphics.RHI;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||
|
||||
namespace Ghost.UnitTest.Windows;
|
||||
|
||||
public sealed partial class GraphicsTestWindow : Window
|
||||
{
|
||||
private RenderSystem? _renderSystem;
|
||||
private IRenderer? _renderer;
|
||||
private ISwapChain? _swapChain;
|
||||
|
||||
public GraphicsTestWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Panel.Loaded += SwapChainPanel_Loaded;
|
||||
Panel.Unloaded += SwapChainPanel_Unloaded;
|
||||
|
||||
Panel.SizeChanged += SwapChainPanel_SizeChanged;
|
||||
}
|
||||
|
||||
private void SwapChainPanel_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
#if DEBUG
|
||||
AllocationManager.EnableDebugLayer();
|
||||
#endif
|
||||
|
||||
_renderSystem = new(GraphicsAPI.Direct3D12);
|
||||
_renderer = _renderSystem.CreateRenderer();
|
||||
|
||||
_swapChain = _renderSystem.GraphicsEngine.CreateSwapChain(new SwapChainDesc((uint)AppWindow.Size.Width, (uint)AppWindow.Size.Height, SwapChainTarget.FromCompositionSurface(Panel)));
|
||||
_renderer.SetSwapChain(_swapChain);
|
||||
|
||||
CompositionTarget.Rendering += OnRendering;
|
||||
}
|
||||
|
||||
private void SwapChainPanel_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
CompositionTarget.Rendering -= OnRendering;
|
||||
|
||||
_swapChain?.Dispose();
|
||||
_renderer?.Dispose();
|
||||
_renderSystem?.Dispose();
|
||||
}
|
||||
|
||||
private void SwapChainPanel_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
if (e.NewSize.Width > 8.0 && e.NewSize.Height > 8.0)
|
||||
{
|
||||
_renderer?.RequestResize((uint)e.NewSize.Width, (uint)e.NewSize.Height);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRendering(object? sender, object e)
|
||||
{
|
||||
//if (GraphicsPipeline.CPUFenceValue < GraphicsPipeline.GPUFenceValue + GraphicsPipeline._FRAME_COUNT)
|
||||
//{
|
||||
// DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.High, () =>
|
||||
// {
|
||||
// GraphicsPipeline.SignalCPUReady();
|
||||
// });
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="1.0.0.0" name="Ghost.UnitTest.app"/>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- The ID below informs the system that this application is compatible with OS features first introduced in Windows 10.
|
||||
It is necessary to support features in unpackaged applications, for example the custom titlebar implementation.
|
||||
For more info see https://docs.microsoft.com/windows/apps/windows-app-sdk/use-windows-app-sdk-run-time#declare-os-compatibility-in-your-application-manifest -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
</application>
|
||||
</compatibility>
|
||||
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
</assembly>
|
||||