Compare commits
	
		
			32 Commits
		
	
	
		
			777059489c
			...
			ecs-test
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 5eaf3547dc | |||
| d80e1177b9 | |||
| cf6cd080c6 | |||
| 87ee6df46f | |||
| 57b42d8daa | |||
| 2a351f7b9d | |||
| 7225d13880 | |||
| 567714a52d | |||
| 2c84e650d6 | |||
| 82fe47f627 | |||
| 6be63195f0 | |||
| 9387bfa59c | |||
| 86b54e1521 | |||
| ba88432e77 | |||
| 5cc876fce9 | |||
| 91b4f5fafb | |||
| 0d14a32726 | |||
| b3adef3a40 | |||
| 30deeca452 | |||
| 6f505f34a9 | |||
| 92cf24fe9f | |||
| cce6e00960 | |||
| 1096597161 | |||
| d45f7c3b8c | |||
| 7a81026ca5 | |||
| 60b85960ff | |||
| b003ffbaec | |||
| 16b04ea22a | |||
| dd3bbf1d5b | |||
| 38080703ec | |||
| fe582c4fba | |||
| 97c2b308f1 | 
							
								
								
									
										9
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -451,8 +451,13 @@ FodyWeavers.xsd | ||||
|  | ||||
| #------------------------- Nerfed ------------------------- | ||||
|  | ||||
| Bin/ | ||||
| Intermediate/ | ||||
|  | ||||
| imgui.ini | ||||
|  | ||||
| # include libs | ||||
| !/libs/lib64 | ||||
| !/libs/x64 | ||||
| !/Native/lib64 | ||||
| !/Native/x64 | ||||
|  | ||||
|  | ||||
|   | ||||
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @@ -16,3 +16,6 @@ | ||||
| [submodule "Nerfed.Runtime/Libraries/ImGui.NET"] | ||||
| 	path = Nerfed.Runtime/Libraries/ImGui.NET | ||||
| 	url = https://github.com/ImGuiNET/ImGui.NET.git | ||||
| [submodule "Nerfed.Runtime/Libraries/MoonTools.ECS"] | ||||
| 	path = Nerfed.Runtime/Libraries/MoonTools.ECS | ||||
| 	url = https://github.com/MoonsideGames/MoonTools.ECS.git | ||||
|   | ||||
							
								
								
									
										7
									
								
								.idea/.idea.Nerfed/.idea/vcs.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										7
									
								
								.idea/.idea.Nerfed/.idea/vcs.xml
									
									
									
										generated
									
									
									
								
							| @@ -2,5 +2,12 @@ | ||||
| <project version="4"> | ||||
|   <component name="VcsDirectoryMappings"> | ||||
|     <mapping directory="" vcs="Git" /> | ||||
|     <mapping directory="$PROJECT_DIR$/Nerfed.Runtime/Libraries/FAudio" vcs="Git" /> | ||||
|     <mapping directory="$PROJECT_DIR$/Nerfed.Runtime/Libraries/ImGui.NET" vcs="Git" /> | ||||
|     <mapping directory="$PROJECT_DIR$/Nerfed.Runtime/Libraries/MoonTools.ECS" vcs="Git" /> | ||||
|     <mapping directory="$PROJECT_DIR$/Nerfed.Runtime/Libraries/RefreshCS" vcs="Git" /> | ||||
|     <mapping directory="$PROJECT_DIR$/Nerfed.Runtime/Libraries/SDL2CS" vcs="Git" /> | ||||
|     <mapping directory="$PROJECT_DIR$/Nerfed.Runtime/Libraries/WellspringCS" vcs="Git" /> | ||||
|     <mapping directory="$PROJECT_DIR$/Nerfed.Runtime/Libraries/dav1dfile" vcs="Git" /> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										7
									
								
								Directory.Build.props
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								Directory.Build.props
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| <Project> | ||||
|    <PropertyGroup> | ||||
|       <OutDir>../Bin/$(MSBuildProjectName)</OutDir> | ||||
|       <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">../Intermediate/$(MSBuildProjectName)</BaseIntermediateOutputPath> | ||||
|    </PropertyGroup> | ||||
| </Project> | ||||
|  | ||||
							
								
								
									
										129
									
								
								Nerfed.Builder/ArgsParser.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								Nerfed.Builder/ArgsParser.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,129 @@ | ||||
| using System.Collections; | ||||
| using System.ComponentModel; | ||||
| using System.Reflection; | ||||
| 
 | ||||
| namespace Nerfed.Builder; | ||||
| 
 | ||||
| 
 | ||||
| public class ArgsParser<TArgs> where TArgs : new() | ||||
| { | ||||
|     private enum ArgType | ||||
|     { | ||||
|         None, | ||||
|         Key, | ||||
|         Value | ||||
|     } | ||||
| 
 | ||||
|     public TArgs Arguments { get; } | ||||
| 
 | ||||
|     private readonly string[] args; | ||||
|     private readonly Dictionary<string, PropertyInfo> argKeyPropertyMap = new Dictionary<string, PropertyInfo>(); | ||||
| 
 | ||||
|     public ArgsParser(string[] args) | ||||
|     { | ||||
|         this.args = args; | ||||
|         Arguments = new TArgs(); | ||||
|         PropertyInfo[] properties = Arguments.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); | ||||
|         foreach (PropertyInfo property in properties) | ||||
|         { | ||||
|             ArgumentAttribute argAttribute = property.GetCustomAttribute<ArgumentAttribute>(); | ||||
|             if (argAttribute == null || string.IsNullOrEmpty(argAttribute.ArgKey)) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             argKeyPropertyMap.Add(argAttribute.ArgKey, property); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public bool Parse() | ||||
|     { | ||||
|         PropertyInfo property = null; | ||||
|         ArgType lastArgType = ArgType.None; | ||||
| 
 | ||||
|         for (int i = 0; i < args.Length; i++) | ||||
|         { | ||||
|             string arg = args[i]; | ||||
|             if (arg[0] == '-') | ||||
|             { | ||||
|                 if (!argKeyPropertyMap.TryGetValue(arg, out property)) | ||||
|                 { | ||||
|                     Console.Error.WriteLine($"Invalid argument: {arg}, no such argument key exists"); | ||||
|                     return false; | ||||
|                 } | ||||
| 
 | ||||
|                 // Boolean arguments require no value, set to true immidiately. | ||||
|                 if (property.PropertyType == typeof(bool)) | ||||
|                 { | ||||
|                     property.SetValue(Arguments, true); | ||||
|                     lastArgType = ArgType.Value; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     lastArgType = ArgType.Key; | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (lastArgType == ArgType.None) | ||||
|                 { | ||||
|                     Console.Error.WriteLine($"Invalid argument: {arg}, no argument key was provided"); | ||||
|                     return false; | ||||
|                 } | ||||
| 
 | ||||
|                 Type propertyType = property.PropertyType; | ||||
|                 if (propertyType.IsArray) | ||||
|                 { | ||||
|                     throw new InvalidOperationException("Arrays are not supported, use List<T> instead"); | ||||
|                 } | ||||
| 
 | ||||
|                 bool propertyTypeIsList = propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(List<>); | ||||
|                 if (propertyTypeIsList) | ||||
|                 { | ||||
|                     propertyType = propertyType.GenericTypeArguments[0]; | ||||
|                 } | ||||
| 
 | ||||
|                 TypeConverter typeConverter = TypeDescriptor.GetConverter(propertyType); | ||||
|                 object value = typeConverter.ConvertFromString(arg); | ||||
| 
 | ||||
|                 if (value is string stringValue) | ||||
|                 { | ||||
|                     if (!string.IsNullOrEmpty(stringValue)) | ||||
|                     { | ||||
|                         if (stringValue[0] == '"') | ||||
|                         { | ||||
|                             stringValue = stringValue.Substring(1, stringValue.Length - 1); | ||||
|                         } | ||||
| 
 | ||||
|                         if (stringValue[^1] == '"') | ||||
|                         { | ||||
|                             stringValue = stringValue.Substring(0, stringValue.Length - 1); | ||||
|                         } | ||||
| 
 | ||||
|                         value = stringValue; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if (propertyTypeIsList) | ||||
|                 { | ||||
|                     IList list = (IList)property.GetValue(Arguments); | ||||
|                     if (list == null) | ||||
|                     { | ||||
|                         list = (IList)Activator.CreateInstance(property.PropertyType); | ||||
|                         property.SetValue(Arguments, list); | ||||
|                     } | ||||
| 
 | ||||
|                     list.Add(value); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     property.SetValue(Arguments, value); | ||||
|                 } | ||||
| 
 | ||||
|                 lastArgType = ArgType.Value; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return true; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										11
									
								
								Nerfed.Builder/ArgumentAttribute.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Nerfed.Builder/ArgumentAttribute.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| namespace Nerfed.Builder; | ||||
| 
 | ||||
| public class ArgumentAttribute : Attribute | ||||
| { | ||||
|     public string ArgKey { get; } | ||||
| 
 | ||||
|     public ArgumentAttribute(string argKey) | ||||
|     { | ||||
|         ArgKey = argKey; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										19
									
								
								Nerfed.Builder/Builder/BuildArgs.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								Nerfed.Builder/Builder/BuildArgs.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| namespace Nerfed.Builder; | ||||
| 
 | ||||
| public class BuildArgs | ||||
| { | ||||
|     [Argument("-build")] | ||||
|     public bool Build { get; set; } | ||||
|      | ||||
|     [Argument("-resourcePath")] | ||||
|     public string ResourcePath { get; set; } | ||||
| 
 | ||||
|     [Argument("-resourceOutPath")] | ||||
|     public string ResourceOutPath { get; set; } | ||||
| 
 | ||||
|     [Argument("-platform")] | ||||
|     public string Platform { get; set; } | ||||
| 
 | ||||
|     [Argument("-resourceFiles")] | ||||
|     public List<string> ResourceFiles { get; set; } | ||||
| } | ||||
							
								
								
									
										144
									
								
								Nerfed.Builder/Builder/Builder.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								Nerfed.Builder/Builder/Builder.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,144 @@ | ||||
| using System.Diagnostics; | ||||
| 
 | ||||
| namespace Nerfed.Builder; | ||||
| 
 | ||||
| public class Builder : IDisposable | ||||
| { | ||||
|     private readonly Dictionary<string, IImporter> importers = new Dictionary<string, IImporter>(); | ||||
|     private readonly RawFileImporter rawFileImporter; | ||||
| 
 | ||||
|     public Builder() | ||||
|     { | ||||
|         rawFileImporter = new RawFileImporter(); | ||||
| 
 | ||||
|         importers.Add(".vert", new ShaderImporter(ShaderStage.Vertex)); // Vertex shader | ||||
|         importers.Add(".frag", new ShaderImporter(ShaderStage.Fragment)); // Fragment shader | ||||
|         //importers.Add(".tesc", shaderImporter); // Tessellation control shader | ||||
|         //importers.Add(".tese", shaderImporter); // Tessellation evaluation shader | ||||
|         //importers.Add(".geom", shaderImporter); // Geometry shader | ||||
|         //importers.Add(".comp", shaderImporter); // Compute shader | ||||
|     } | ||||
| 
 | ||||
|     public void Run(BuildArgs args) | ||||
|     { | ||||
|         Stopwatch stopwatch = new Stopwatch(); | ||||
|         stopwatch.Start(); | ||||
| 
 | ||||
|         //CopyLibs(args.ResourcePath); | ||||
| 
 | ||||
|         List<string> contentFiles = args.ResourceFiles; | ||||
| 
 | ||||
|         // If no files are provided, build all content. | ||||
|         if (args.ResourceFiles == null) | ||||
|         { | ||||
|             contentFiles = []; | ||||
|             CollectAssetFiles(args.ResourcePath, args.ResourcePath, ref contentFiles); | ||||
|         } | ||||
| 
 | ||||
|         if (contentFiles.Count > 0) | ||||
|         { | ||||
|             ParallelOptions parallelOptions = new ParallelOptions | ||||
|             { | ||||
|                 MaxDegreeOfParallelism = contentFiles.Count | ||||
|             }; | ||||
| 
 | ||||
|             Parallel.ForEach(contentFiles, parallelOptions, relativeFile => | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     string inFile = $"{args.ResourcePath}/{relativeFile}"; | ||||
| 
 | ||||
|                     if (!File.Exists(inFile)) | ||||
|                     { | ||||
|                         Console.Error.WriteLine($"Asset file '{relativeFile}' not found"); | ||||
|                         return; | ||||
|                     } | ||||
| 
 | ||||
|                     string outFile = $"{args.ResourceOutPath}/{relativeFile}{PathUtil.ImportedFileExtension}"; | ||||
| 
 | ||||
|                     FileInfo inFileInfo = new FileInfo(inFile); | ||||
|                     FileInfo outFileInfo = new FileInfo(outFile); | ||||
| 
 | ||||
|                     if (!FileUtil.IsNewer(inFileInfo, outFileInfo)) | ||||
|                     { | ||||
|                         // File has not changed since last build, no need to build this one. | ||||
|                         return; | ||||
|                     } | ||||
| 
 | ||||
|                     string outDir = Path.GetDirectoryName(outFile); | ||||
|                     if (!Directory.Exists(outDir)) | ||||
|                     { | ||||
|                         Directory.CreateDirectory(outDir); | ||||
|                     } | ||||
| 
 | ||||
|                     string ext = Path.GetExtension(inFile).ToLower(); | ||||
|                     if (importers.TryGetValue(ext, out IImporter importer)) | ||||
|                     { | ||||
|                         importer.Import(inFile, outFile); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         rawFileImporter.Import(inFile, outFile); | ||||
|                     } | ||||
| 
 | ||||
|                     Console.WriteLine(relativeFile); | ||||
|                 } | ||||
|                 catch (Exception e) | ||||
|                 { | ||||
|                     Console.Error.WriteLine($"Import error on asset '{relativeFile}': {e.Message}"); | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         Console.WriteLine($"Build content completed in {stopwatch.Elapsed.TotalSeconds:F2} seconds"); | ||||
|     } | ||||
| 
 | ||||
|     /*private void CopyLibs(string projectPath) | ||||
|     { | ||||
|         string libDir = $"{AppDomain.CurrentDomain.BaseDirectory}/../../Native/"; | ||||
|         if (OperatingSystem.IsWindows()) | ||||
|         { | ||||
|             libDir += "x64"; | ||||
|         } | ||||
|         else if (OperatingSystem.IsLinux()) | ||||
|         { | ||||
|             libDir += "lib64"; | ||||
|         } | ||||
|         else if (OperatingSystem.IsMacOS()) | ||||
|         { | ||||
|             libDir += "osx"; | ||||
|         } | ||||
| 
 | ||||
|         libDir = Path.GetFullPath(libDir); | ||||
|         foreach (string libFile in Directory.EnumerateFiles(libDir)) | ||||
|         { | ||||
|             FileInfo srcFileInfo = new FileInfo(libFile); | ||||
|             FileInfo dstFileInfo = new FileInfo($"{projectPath}/{PathUtil.BuildFolderName}/{Path.GetFileName(libFile)}"); | ||||
|             if (FileUtil.IsNewer(srcFileInfo, dstFileInfo)) | ||||
|             { | ||||
|                 FileUtil.Copy(srcFileInfo, dstFileInfo); | ||||
|             } | ||||
|         } | ||||
|     }*/ | ||||
| 
 | ||||
|     private void CollectAssetFiles(string assetDir, string dir, ref List<string> files) | ||||
|     { | ||||
|         foreach (string file in Directory.EnumerateFiles(dir)) | ||||
|         { | ||||
|             string relativeFile = file.Substring(assetDir.Length, file.Length - assetDir.Length); | ||||
|             if (relativeFile[0] == Path.DirectorySeparatorChar || relativeFile[0] == Path.AltDirectorySeparatorChar) | ||||
|             { | ||||
|                 relativeFile = relativeFile.Substring(1, relativeFile.Length - 1); | ||||
|             } | ||||
| 
 | ||||
|             files.Add(relativeFile); | ||||
|         } | ||||
| 
 | ||||
|         foreach (string subDir in Directory.EnumerateDirectories(dir)) | ||||
|         { | ||||
|             CollectAssetFiles(assetDir, subDir, ref files); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void Dispose() { } | ||||
| } | ||||
							
								
								
									
										49
									
								
								Nerfed.Builder/Builder/FileUtil.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								Nerfed.Builder/Builder/FileUtil.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| namespace Nerfed.Builder; | ||||
| 
 | ||||
| public static class FileUtil | ||||
| { | ||||
|     public static void Copy(FileInfo srcFile, FileInfo dstFile) | ||||
|     { | ||||
|         Copy(srcFile.FullName, dstFile.FullName); | ||||
|     } | ||||
| 
 | ||||
|     public static void Copy(string srcFile, string dstFile) | ||||
|     { | ||||
|         string dstDir = Path.GetDirectoryName(dstFile); | ||||
|         if (!Directory.Exists(dstDir)) | ||||
|         { | ||||
|             Directory.CreateDirectory(dstDir); | ||||
|         } | ||||
| 
 | ||||
|         File.Copy(srcFile, dstFile, true); | ||||
|         UpdateFileTimeAttributes(dstFile); | ||||
|     } | ||||
| 
 | ||||
|     public static void WriteBytes(string dstFile, byte[] bytes) | ||||
|     { | ||||
|         File.WriteAllBytes(dstFile, bytes); | ||||
|         UpdateFileTimeAttributes(dstFile); | ||||
|     } | ||||
| 
 | ||||
|     public static void UpdateFileTimeAttributes(string file) | ||||
|     { | ||||
|         // Copy over date time attributes so we can check if the file changed. | ||||
|         FileInfo dstFileInfo = new FileInfo(file); | ||||
|         DateTime now = DateTime.Now; | ||||
|         DateTime utcNow = DateTime.UtcNow; | ||||
|         dstFileInfo.CreationTime = now; | ||||
|         dstFileInfo.CreationTimeUtc = utcNow; | ||||
|         dstFileInfo.LastWriteTime = now; | ||||
|         dstFileInfo.LastWriteTimeUtc = utcNow; | ||||
|         dstFileInfo.LastAccessTime = now; | ||||
|         dstFileInfo.LastAccessTimeUtc = utcNow; | ||||
|     } | ||||
| 
 | ||||
|     /// <summary> | ||||
|     /// True if the inFileInfo is newer than the outFileInfo. | ||||
|     /// </summary> | ||||
|     public static bool IsNewer(FileInfo inFileInfo, FileInfo outFileInfo) | ||||
|     { | ||||
|         return !outFileInfo.Exists || outFileInfo.LastWriteTime <= inFileInfo.LastWriteTime; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										6
									
								
								Nerfed.Builder/Builder/IImporter.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Nerfed.Builder/Builder/IImporter.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| namespace Nerfed.Builder; | ||||
| 
 | ||||
| public interface IImporter | ||||
| { | ||||
|     void Import(string inFile, string outFile); | ||||
| } | ||||
							
								
								
									
										9
									
								
								Nerfed.Builder/Builder/Importers/RawFileImporter.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								Nerfed.Builder/Builder/Importers/RawFileImporter.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| namespace Nerfed.Builder; | ||||
| 
 | ||||
| public class RawFileImporter : IImporter | ||||
| { | ||||
|     public void Import(string inFile, string outFile) | ||||
|     { | ||||
|         FileUtil.Copy(inFile, outFile); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										157
									
								
								Nerfed.Builder/Builder/Importers/ShaderImporter.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								Nerfed.Builder/Builder/Importers/ShaderImporter.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,157 @@ | ||||
| using Vortice.ShaderCompiler; | ||||
| using Vortice.SPIRV.Reflect; | ||||
| 
 | ||||
| namespace Nerfed.Builder; | ||||
| 
 | ||||
| // Values should match the ShaderStage enum in the runtime. | ||||
| public enum ShaderStage | ||||
| { | ||||
|     Vertex, | ||||
|     Fragment | ||||
| } | ||||
| 
 | ||||
| // Values should match the ShaderFormat enum in the runtime. | ||||
| public enum ShaderFormat | ||||
| { | ||||
|     Invalid, | ||||
|     SPIRV, | ||||
|     HLSL, | ||||
|     DXBC, | ||||
|     DXIL, | ||||
|     MSL, | ||||
|     METALLIB, | ||||
|     SECRET | ||||
| } | ||||
| 
 | ||||
| public class ShaderImporter : IImporter | ||||
| { | ||||
|     private readonly ShaderStage shaderStage; | ||||
| 
 | ||||
|     public ShaderImporter(ShaderStage shaderStage) | ||||
|     { | ||||
|         this.shaderStage = shaderStage; | ||||
|     } | ||||
| 
 | ||||
|     public unsafe void Import(string inFile, string outFile) | ||||
|     { | ||||
|         string name = Path.GetFileNameWithoutExtension(inFile); | ||||
|         string nameWithExt = Path.GetFileName(inFile); | ||||
| 
 | ||||
|         // Compile the shader. | ||||
|         Result compileResult; | ||||
|         using (Compiler compiler = new Compiler()) | ||||
|         { | ||||
|             string shaderSource = File.ReadAllText(inFile); | ||||
|             compileResult = compiler.Compile(shaderSource, nameWithExt, ToShaderKind(shaderStage)); | ||||
|         } | ||||
| 
 | ||||
|         if (compileResult.Status != CompilationStatus.Success) | ||||
|         { | ||||
|             Console.Error.WriteLine($"Failed to compile {nameWithExt}\n{compileResult.ErrorMessage}"); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if (compileResult.ErrorsCount > 0 || compileResult.WarningsCount > 0) | ||||
|         { | ||||
|             Console.Error.WriteLine(compileResult.ErrorMessage); | ||||
|         } | ||||
| 
 | ||||
|         Span<byte> byteCode = compileResult.GetBytecode(); | ||||
| 
 | ||||
|         // Inspect SPIR-V bytecode for information which the runtime requires to create a shader resource. | ||||
|         SpvReflectShaderModule module = new SpvReflectShaderModule(); | ||||
|         if (!CheckReflectResult(SPIRVReflectApi.spvReflectCreateShaderModule(byteCode, &module), name)) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         uint descriptorSetCount = 0; | ||||
|         if (!CheckReflectResult(SPIRVReflectApi.spvReflectEnumerateDescriptorSets(&module, &descriptorSetCount, null), name)) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         int uniformBufferCount = 0; | ||||
|         int storageBufferCount = 0; | ||||
|         int storageTextureCount = 0; | ||||
|         int samplerCount = 0; | ||||
| 
 | ||||
|         if (descriptorSetCount > 0) | ||||
|         { | ||||
|             SpvReflectDescriptorSet* descriptorSets = stackalloc SpvReflectDescriptorSet[(int)descriptorSetCount]; | ||||
|             if (!CheckReflectResult( | ||||
|                     SPIRVReflectApi.spvReflectEnumerateDescriptorSets(&module, &descriptorSetCount, &descriptorSets), | ||||
|                     name | ||||
|                 )) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             for (int i = 0; i < descriptorSetCount; i++) | ||||
|             { | ||||
|                 SpvReflectDescriptorSet set = descriptorSets[i]; | ||||
|                 for (int j = 0; j < set.binding_count; j++) | ||||
|                 { | ||||
|                     SpvReflectDescriptorBinding binding = *set.bindings[j]; | ||||
|                     if (binding.descriptor_type == SpvReflectDescriptorType.UniformBuffer) | ||||
|                     { | ||||
|                         uniformBufferCount++; | ||||
|                     } | ||||
|                     else if (binding.descriptor_type == SpvReflectDescriptorType.StorageBuffer) | ||||
|                     { | ||||
|                         storageBufferCount++; | ||||
|                     } | ||||
|                     else if (binding.descriptor_type == SpvReflectDescriptorType.StorageTexelBuffer) | ||||
|                     { | ||||
|                         storageTextureCount++; | ||||
|                     } | ||||
|                     else if (binding.descriptor_type == SpvReflectDescriptorType.Sampler || | ||||
|                              binding.descriptor_type == SpvReflectDescriptorType.CombinedImageSampler) | ||||
|                     { | ||||
|                         samplerCount++; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         //TODO: Convert SPIR-V to other bytecode formats here (DX/Consoles). | ||||
|         ShaderFormat format = ShaderFormat.SPIRV; | ||||
| 
 | ||||
|         // Write shader meta-data and bytecode to the output file. | ||||
|         using (FileStream stream = new FileStream(outFile, FileMode.Create, FileAccess.Write)) | ||||
|         { | ||||
|             using (BinaryWriter writer = new BinaryWriter(stream)) | ||||
|             { | ||||
|                 writer.Write((int)format); | ||||
|                 writer.Write((int)shaderStage); | ||||
|                 writer.Write(uniformBufferCount); | ||||
|                 writer.Write(storageBufferCount); | ||||
|                 writer.Write(storageTextureCount); | ||||
|                 writer.Write(samplerCount); | ||||
|                 writer.Write(byteCode.Length); | ||||
|                 writer.Write(byteCode); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private bool CheckReflectResult(SpvReflectResult result, string name) | ||||
|     { | ||||
|         if (result != SpvReflectResult.Success) | ||||
|         { | ||||
|             Console.Error.WriteLine($"SpirV-Reflect failure for '{name}': {result}"); | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     private ShaderKind ToShaderKind(ShaderStage shaderStage) | ||||
|     { | ||||
|         switch (shaderStage) | ||||
|         { | ||||
|             case ShaderStage.Vertex: return ShaderKind.VertexShader; | ||||
|             case ShaderStage.Fragment: return ShaderKind.FragmentShader; | ||||
|             default: throw new ArgumentOutOfRangeException(nameof(shaderStage)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										33
									
								
								Nerfed.Builder/Nerfed.Builder.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								Nerfed.Builder/Nerfed.Builder.csproj
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|  | ||||
|     <PropertyGroup> | ||||
|         <OutputType>Exe</OutputType> | ||||
|         <TargetFramework>net8.0</TargetFramework> | ||||
|         <ImplicitUsings>enable</ImplicitUsings> | ||||
|         <Nullable>disable</Nullable> | ||||
|         <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> | ||||
|         <IsPackable>false</IsPackable> | ||||
|         <Configurations>Debug;Test;Release</Configurations> | ||||
|         <Platforms>x64</Platforms> | ||||
|     </PropertyGroup> | ||||
|  | ||||
|     <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' "> | ||||
|       <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | ||||
|     </PropertyGroup> | ||||
|  | ||||
|     <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Test|x64' "> | ||||
|         <Optimize>true</Optimize> | ||||
|         <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | ||||
|     </PropertyGroup> | ||||
|      | ||||
|     <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' "> | ||||
|         <Optimize>true</Optimize> | ||||
|         <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | ||||
|     </PropertyGroup> | ||||
|      | ||||
|     <ItemGroup> | ||||
|       <PackageReference Include="Vortice.ShaderCompiler" Version="1.7.3" /> | ||||
|       <PackageReference Include="Vortice.SPIRV.Reflect" Version="1.0.3" /> | ||||
|     </ItemGroup> | ||||
|      | ||||
| </Project> | ||||
							
								
								
									
										4
									
								
								Nerfed.Builder/Nerfed.Builder.csproj.DotSettings
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								Nerfed.Builder/Nerfed.Builder.csproj.DotSettings
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> | ||||
| 	<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=builder/@EntryIndexedValue">True</s:Boolean> | ||||
| 	<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=builder_005Cimporters/@EntryIndexedValue">True</s:Boolean> | ||||
| 	<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=packager/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary> | ||||
							
								
								
									
										6
									
								
								Nerfed.Builder/Packager/PackageArgs.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Nerfed.Builder/Packager/PackageArgs.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| namespace Nerfed.Builder; | ||||
| 
 | ||||
| public class PackageArgs | ||||
| { | ||||
|      | ||||
| } | ||||
							
								
								
									
										12
									
								
								Nerfed.Builder/Packager/Packager.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								Nerfed.Builder/Packager/Packager.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| namespace Nerfed.Builder; | ||||
| 
 | ||||
| public class Packager : IDisposable | ||||
| { | ||||
|     public void Run(PackageArgs args) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|     public void Dispose() | ||||
|     { | ||||
|     } | ||||
| } | ||||
							
								
								
									
										6
									
								
								Nerfed.Builder/PathUtil.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Nerfed.Builder/PathUtil.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| namespace Nerfed.Builder; | ||||
| 
 | ||||
| public static class PathUtil | ||||
| { | ||||
|     public const string ImportedFileExtension = ".bin"; | ||||
| } | ||||
							
								
								
									
										70
									
								
								Nerfed.Builder/Program.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								Nerfed.Builder/Program.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | ||||
| using System.Diagnostics; | ||||
| 
 | ||||
| namespace Nerfed.Builder; | ||||
| 
 | ||||
| internal class Program | ||||
| { | ||||
|     private static int Main(string[] args) | ||||
|     { | ||||
|         if (Debugger.IsAttached) | ||||
|         { | ||||
|             return Run(args); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 return Run(args); | ||||
|             } | ||||
|             catch (Exception e) | ||||
|             { | ||||
|                 Console.Error.WriteLine(e.Message); | ||||
|                 return -1; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static int Run(string[] rawArgs) | ||||
|     { | ||||
|         if (rawArgs.Length == 0) | ||||
|         { | ||||
|             Console.Error.WriteLine($"Invalid build type '{rawArgs[0]}' expected '-build' or '-package'"); | ||||
|             return -1; | ||||
|         } | ||||
| 
 | ||||
|         string buildType = rawArgs[0].ToLower(); | ||||
|         if (buildType == "-build") | ||||
|         { | ||||
|             ArgsParser<BuildArgs> parser = new ArgsParser<BuildArgs>(rawArgs); | ||||
|             if (!parser.Parse()) | ||||
|             { | ||||
|                 Console.Error.Write("Failed to parse build arguments"); | ||||
|                 return -1; | ||||
|             } | ||||
| 
 | ||||
|             using (Builder builder = new Builder()) | ||||
|             { | ||||
|                 builder.Run(parser.Arguments); | ||||
|             } | ||||
|         } | ||||
|         else if (buildType == "-package") | ||||
|         { | ||||
|             ArgsParser<PackageArgs> parser = new ArgsParser<PackageArgs>(rawArgs); | ||||
|             if (!parser.Parse()) | ||||
|             { | ||||
|                 Console.Error.Write("Failed to parse package arguments"); | ||||
|                 return -1; | ||||
|             } | ||||
| 
 | ||||
|             using (Packager packager = new Packager()) | ||||
|             { | ||||
|                 packager.Run(parser.Arguments); | ||||
|             } | ||||
| 
 | ||||
|             Console.Error.WriteLine("Packaging not yet implemented"); | ||||
|             return -1; | ||||
|         } | ||||
| 
 | ||||
|         return 0; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										4
									
								
								Nerfed.Editor/Components/HierachyComponents.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								Nerfed.Editor/Components/HierachyComponents.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| namespace Nerfed.Editor.Components; | ||||
| 
 | ||||
| public readonly record struct SelectedInHierachy; | ||||
| public readonly record struct ClickedInHierachy; | ||||
							
								
								
									
										21
									
								
								Nerfed.Editor/CopyLibs.targets
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								Nerfed.Editor/CopyLibs.targets
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||||
|     <Target Name="Runtime ID" AfterTargets="Build"> | ||||
|         <Message Text="Runtime ID: $(RuntimeIdentifier)" Importance="high"/> | ||||
|     </Target> | ||||
|  | ||||
|     <ItemGroup Condition="$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))"> | ||||
|         <Libs Include="..\Native\x64\**\*.*"/> | ||||
|     </ItemGroup> | ||||
|     <ItemGroup Condition="$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))"> | ||||
|         <Libs Include="..\Native\lib64\**\*.*"/> | ||||
|     </ItemGroup> | ||||
|     <ItemGroup Condition="$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))"> | ||||
|         <Libs Include="..\Native\osx\**\*.*"/> | ||||
|     </ItemGroup> | ||||
|  | ||||
|     <Target Name="CopyLibs" AfterTargets="Build"> | ||||
|         <Copy SourceFiles="@(Libs)" DestinationFolder="$(OutDir)" SkipUnchangedFiles="true" OverwriteReadOnlyFiles="true"/> | ||||
|     </Target> | ||||
|  | ||||
| </Project> | ||||
							
								
								
									
										77
									
								
								Nerfed.Editor/Editor/EditorGui.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								Nerfed.Editor/Editor/EditorGui.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | ||||
| using ImGuiNET; | ||||
| using Nerfed.Runtime; | ||||
| using Nerfed.Runtime.Graphics; | ||||
| using Nerfed.Runtime.Gui; | ||||
| 
 | ||||
| namespace Nerfed.Editor | ||||
| { | ||||
|     internal static class EditorGui | ||||
|     { | ||||
|         private static GuiController guiController; | ||||
| 
 | ||||
|         internal static void Initialize() | ||||
|         { | ||||
|             // Create GuiController. | ||||
|             guiController = new GuiController(Engine.GraphicsDevice, Engine.MainWindow, Color.DimGray); | ||||
|             // Subscribe to GUI update. | ||||
|             // GuiController.OnGui call => UpdateDock; | ||||
|             // GuiController.OnGui call => UpdateEditorWindows; | ||||
|             // GuiController.OnGui call => ...; | ||||
|             guiController.OnGui += HandleOnGui; | ||||
|         } | ||||
| 
 | ||||
|         internal static void Update() | ||||
|         { | ||||
|             // Update GuiController. | ||||
|             guiController.Update(Engine.Timestep.TotalSeconds); | ||||
|         } | ||||
| 
 | ||||
|         internal static void Render() | ||||
|         { | ||||
|             // Reneder GuiController. | ||||
|             guiController.Render(); | ||||
|         } | ||||
| 
 | ||||
|         internal static void Quit() | ||||
|         { | ||||
|             guiController.Dispose(); | ||||
|         } | ||||
| 
 | ||||
|         private static void UpdateDock() | ||||
|         { | ||||
|             // Setup default dockspace for the main window. | ||||
|             uint id = ImGui.GetID("MainDockSpace"); | ||||
|             ImGui.DockSpaceOverViewport(id, ImGui.GetMainViewport(), ImGuiDockNodeFlags.None); | ||||
|         } | ||||
| 
 | ||||
|         private static void UpdateMainMenu() | ||||
|         { | ||||
|             if (ImGui.BeginMainMenuBar()) | ||||
|             { | ||||
|                 if (ImGui.BeginMenu("File")) | ||||
|                 { | ||||
|                     if (ImGui.MenuItem("Exit")) | ||||
|                     { | ||||
|                         Engine.Quit(); | ||||
|                     } | ||||
|                     ImGui.EndMenu(); | ||||
|                 } | ||||
|                 ImGui.EndMainMenuBar(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static void HandleOnGui() | ||||
|         { | ||||
|             UpdateMainMenu(); | ||||
|             UpdateDock(); | ||||
| 
 | ||||
|             ImGui.ShowDemoWindow(); | ||||
| 
 | ||||
|             foreach (MoonTools.ECS.System system in Program.editorSystems) | ||||
|             { | ||||
|                 using ProfilerScope scope = new(system.GetType().Name); | ||||
|                 system.Update(Engine.Timestep); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										35
									
								
								Nerfed.Editor/Nerfed.Editor.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								Nerfed.Editor/Nerfed.Editor.csproj
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|  | ||||
|     <PropertyGroup> | ||||
|         <OutputType>Exe</OutputType> | ||||
|         <TargetFramework>net8.0</TargetFramework> | ||||
|         <ImplicitUsings>enable</ImplicitUsings> | ||||
|         <Nullable>disable</Nullable> | ||||
|         <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> | ||||
|         <IsPackable>false</IsPackable> | ||||
|         <Configurations>Debug;Test;Release</Configurations> | ||||
|         <Platforms>x64</Platforms> | ||||
|         <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | ||||
|     </PropertyGroup> | ||||
|  | ||||
|     <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' "> | ||||
|     </PropertyGroup> | ||||
|  | ||||
|     <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Test|x64' "> | ||||
|         <Optimize>true</Optimize> | ||||
|     </PropertyGroup> | ||||
|      | ||||
|     <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' "> | ||||
|         <Optimize>true</Optimize> | ||||
|     </PropertyGroup> | ||||
|      | ||||
|     <ItemGroup> | ||||
|         <ProjectReference Include="..\Nerfed.Runtime\Nerfed.Runtime.csproj" /> | ||||
|     </ItemGroup> | ||||
|  | ||||
|     <Import Project=".\CopyLibs.targets" /> | ||||
|  | ||||
|     <Target Name="PostBuild" AfterTargets="PostBuildEvent"> | ||||
|       <Exec Command=""$(ProjectDir)../Bin/Nerfed.Builder/Nerfed.Builder" -build -resourcePath "$(ProjectDir)Resources" -resourceOutPath "$(TargetDir)Resources" " /> | ||||
|     </Target> | ||||
| </Project> | ||||
							
								
								
									
										107
									
								
								Nerfed.Editor/Program.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								Nerfed.Editor/Program.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,107 @@ | ||||
| using MoonTools.ECS; | ||||
| using Nerfed.Editor.Systems; | ||||
| using Nerfed.Runtime; | ||||
| using Nerfed.Runtime.Components; | ||||
| using Nerfed.Runtime.Systems; | ||||
| using Nerfed.Runtime.Util; | ||||
| using System.Numerics; | ||||
| 
 | ||||
| namespace Nerfed.Editor; | ||||
| 
 | ||||
| internal class Program | ||||
| { | ||||
|     private static readonly World world = new World(); | ||||
|     private static List<MoonTools.ECS.System> systems = new List<MoonTools.ECS.System>(); | ||||
|     public static List<MoonTools.ECS.System> editorSystems = new List<MoonTools.ECS.System>(); | ||||
| 
 | ||||
|     private static void Main(string[] args) | ||||
|     { | ||||
|         Engine.OnInitialize += HandleOnInitialize; | ||||
|         Engine.OnUpdate += HandleOnUpdate; | ||||
|         Engine.OnRender += HandleOnRender; | ||||
|         Engine.OnQuit += HandleOnQuit; | ||||
| 
 | ||||
|         Engine.Run(args); | ||||
|     } | ||||
| 
 | ||||
|     private static void HandleOnInitialize() | ||||
|     { | ||||
|         //systems.Add(new ParentSystem(world)); | ||||
|         systems.Add(new LocalToWorldSystem(world)); | ||||
|         editorSystems.Add(new EditorProfilerWindow(world)); | ||||
|         editorSystems.Add(new EditorHierarchyWindow(world)); | ||||
| #if DEBUG | ||||
|         editorSystems.Add(new EditorInspectorWindow(world)); | ||||
| #endif | ||||
| 
 | ||||
|         Entity ent1 = world.CreateEntity("parent"); | ||||
|         world.Set(ent1, new Root()); | ||||
|         world.Set(ent1, new LocalTransform(new Vector3(1, 0, 0), Quaternion.Identity, Vector3.One)); | ||||
| 
 | ||||
|         Entity ent2 = world.CreateEntity("child"); | ||||
|         world.Set(ent2, new LocalTransform(new Vector3(0, 1, 0), Quaternion.Identity, Vector3.One)); | ||||
|         Transform.SetParent(world, ent2, ent1); | ||||
| 
 | ||||
|         Entity ent3 = world.CreateEntity("entity3"); | ||||
|         world.Set(ent3, new Root()); | ||||
|         Transform.SetParent(world, ent3, ent2); | ||||
| 
 | ||||
|         Entity ent4 = world.CreateEntity("entity4"); | ||||
|         world.Set(ent4, new Root()); | ||||
| 
 | ||||
|         Entity ent5 = world.CreateBaseEntity("entity5"); | ||||
| 
 | ||||
|         for (int i = 0; i < 256; i++) | ||||
|         { | ||||
|             Entity newEnt = world.CreateBaseEntity(); | ||||
|             world.Set(newEnt, new LocalTransform(new Vector3(i, i, i), Quaternion.Identity, Vector3.One)); | ||||
| 
 | ||||
|             Entity parent = newEnt; | ||||
|             for (int j = 0; j < 2; j++) { | ||||
|                 Entity newChildEnt = world.CreateEntity(); | ||||
|                 world.Set(newChildEnt, new LocalTransform(new Vector3(i + j * i, i - j * i, j - i * i), Quaternion.Identity, Vector3.One)); | ||||
|                 Transform.SetParent(world, newChildEnt, parent); | ||||
|                 parent = newChildEnt; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Open project. | ||||
|         // Setip EditorGui. | ||||
|         EditorGui.Initialize(); | ||||
|     } | ||||
| 
 | ||||
|     private static void HandleOnUpdate() | ||||
|     { | ||||
|         foreach (MoonTools.ECS.System system in systems) | ||||
|         { | ||||
|             using ProfilerScope scope = new(system.GetType().Name); | ||||
|             system.Update(Engine.Timestep); | ||||
|         } | ||||
| 
 | ||||
|         using (new ProfilerScope("EditorGui.Update")) | ||||
|         { | ||||
|             // Editor Update. | ||||
|             EditorGui.Update(); | ||||
|         } | ||||
| 
 | ||||
|         // Try Catch UserCode Update. | ||||
| 
 | ||||
|         using (new ProfilerScope("world.FinishUpdate")) | ||||
|         { | ||||
|             world.FinishUpdate(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static void HandleOnRender() | ||||
|     { | ||||
|         using (new ProfilerScope("EditorGui.Render")) | ||||
|         { | ||||
|             EditorGui.Render(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static void HandleOnQuit() | ||||
|     { | ||||
|         EditorGui.Quit(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										9
									
								
								Nerfed.Editor/Resources/Shaders/Fullscreen.vert
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								Nerfed.Editor/Resources/Shaders/Fullscreen.vert
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| #version 450 | ||||
|  | ||||
| layout(location = 0) out vec2 outTexCoord; | ||||
|  | ||||
| void main() | ||||
| { | ||||
| 	outTexCoord = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); | ||||
| 	gl_Position = vec4(outTexCoord * vec2(2.0, -2.0) + vec2(-1.0, 1.0), 0.0, 1.0); | ||||
| } | ||||
							
								
								
									
										34
									
								
								Nerfed.Editor/Resources/Shaders/Text.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								Nerfed.Editor/Resources/Shaders/Text.frag
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| #version 450 | ||||
|  | ||||
| layout(location = 0) in vec2 inTexCoord; | ||||
| layout(location = 1) in vec4 inColor; | ||||
|  | ||||
| layout(location = 0) out vec4 outColor; | ||||
|  | ||||
| layout(set = 2, binding = 0) uniform sampler2D msdf; | ||||
|  | ||||
| layout(set = 3, binding = 0) uniform UBO | ||||
| { | ||||
| 	float pxRange; | ||||
| } ubo; | ||||
|  | ||||
| float median(float r, float g, float b) | ||||
| { | ||||
| 	return max(min(r, g), min(max(r, g), b)); | ||||
| } | ||||
|  | ||||
| float screenPxRange() | ||||
| { | ||||
|     vec2 unitRange = vec2(ubo.pxRange)/vec2(textureSize(msdf, 0)); | ||||
|     vec2 screenTexSize = vec2(1.0)/fwidth(inTexCoord); | ||||
|     return max(0.5*dot(unitRange, screenTexSize), 1.0); | ||||
| } | ||||
|  | ||||
| void main() | ||||
| { | ||||
| 	vec3 msd = texture(msdf, inTexCoord).rgb; | ||||
| 	float sd = median(msd.r, msd.g, msd.b); | ||||
|     float screenPxDistance = screenPxRange() * (sd - 0.5); | ||||
|     float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0); | ||||
|     outColor = mix(vec4(0.0, 0.0, 0.0, 0.0), inColor, opacity); | ||||
| } | ||||
							
								
								
									
										20
									
								
								Nerfed.Editor/Resources/Shaders/Text.vert
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								Nerfed.Editor/Resources/Shaders/Text.vert
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| #version 450 | ||||
|  | ||||
| layout(location = 0) in vec3 inPos; | ||||
| layout(location = 1) in vec2 inTexCoord; | ||||
| layout(location = 2) in vec4 inColor; | ||||
|  | ||||
| layout(location = 0) out vec2 outTexCoord; | ||||
| layout(location = 1) out vec4 outColor; | ||||
|  | ||||
| layout(set = 1, binding = 0) uniform UBO | ||||
| { | ||||
| 	mat4 ViewProjection; | ||||
| } ubo; | ||||
|  | ||||
| void main() | ||||
| { | ||||
| 	gl_Position = ubo.ViewProjection * vec4(inPos, 1.0); | ||||
| 	outTexCoord = inTexCoord; | ||||
| 	outColor = inColor; | ||||
| } | ||||
							
								
								
									
										38
									
								
								Nerfed.Editor/Resources/Shaders/Video.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								Nerfed.Editor/Resources/Shaders/Video.frag
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| /* | ||||
|  * This effect is based on the YUV-to-RGBA GLSL shader found in SDL. | ||||
|  * Thus, it also released under the zlib license: | ||||
|  * http://libsdl.org/license.php | ||||
|  */ | ||||
| #version 450 | ||||
|  | ||||
| layout(location = 0) in vec2 TexCoord; | ||||
|  | ||||
| layout(location = 0) out vec4 FragColor; | ||||
|  | ||||
| layout(set = 2, binding = 0) uniform sampler2D YSampler; | ||||
| layout(set = 2, binding = 1) uniform sampler2D USampler; | ||||
| layout(set = 2, binding = 2) uniform sampler2D VSampler; | ||||
|  | ||||
| /* More info about colorspace conversion: | ||||
|  * http://www.equasys.de/colorconversion.html | ||||
|  * http://www.equasys.de/colorformat.html | ||||
|  */ | ||||
|  | ||||
| const vec3 offset = vec3(-0.0625, -0.5, -0.5); | ||||
| const vec3 Rcoeff = vec3(1.164,  0.000,  1.793); | ||||
| const vec3 Gcoeff = vec3(1.164, -0.213, -0.533); | ||||
| const vec3 Bcoeff = vec3(1.164,  2.112,  0.000); | ||||
|  | ||||
| void main() | ||||
| { | ||||
| 	vec3 yuv; | ||||
| 	yuv.x = texture(YSampler, TexCoord).r; | ||||
| 	yuv.y = texture(USampler, TexCoord).r; | ||||
| 	yuv.z = texture(VSampler, TexCoord).r; | ||||
| 	yuv += offset; | ||||
|  | ||||
| 	FragColor.r = dot(yuv, Rcoeff); | ||||
| 	FragColor.g = dot(yuv, Gcoeff); | ||||
| 	FragColor.b = dot(yuv, Bcoeff); | ||||
| 	FragColor.a = 1.0; | ||||
| } | ||||
							
								
								
									
										190
									
								
								Nerfed.Editor/Systems/EditorHierarchyWindow.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								Nerfed.Editor/Systems/EditorHierarchyWindow.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,190 @@ | ||||
| using ImGuiNET; | ||||
| using MoonTools.ECS; | ||||
| using Nerfed.Editor.Components; | ||||
| using Nerfed.Runtime; | ||||
| using Nerfed.Runtime.Components; | ||||
| using Nerfed.Runtime.Util; | ||||
| 
 | ||||
| namespace Nerfed.Editor.Systems | ||||
| { | ||||
|     // Window that draws entities. | ||||
|     internal class EditorHierarchyWindow : MoonTools.ECS.System | ||||
|     { | ||||
|         private const ImGuiTreeNodeFlags baseFlags = ImGuiTreeNodeFlags.OpenOnArrow | ImGuiTreeNodeFlags.OpenOnDoubleClick | ImGuiTreeNodeFlags.SpanAvailWidth; | ||||
| 
 | ||||
|         //private readonly Filter rootEntitiesWithTransformFilter; | ||||
|         //private readonly Filter rootEntitiesFilterBroken; | ||||
|         private readonly Filter rootEntitiesFilter; | ||||
| 
 | ||||
|         private readonly EditorHierachySelectionSystem hierachySelectionSystem; | ||||
| 
 | ||||
|         public EditorHierarchyWindow(World world) : base(world) | ||||
|         { | ||||
|             //rootEntitiesWithTransformFilter = FilterBuilder.Include<LocalTransform>().Exclude<Child>().Build(); | ||||
| 
 | ||||
|             // TODO: this doesn't work. | ||||
|             //rootEntitiesFilterBroken = FilterBuilder.Exclude<Child>().Build(); | ||||
| 
 | ||||
|             // Maybe the parent/child functions should add a root component when not being a child. | ||||
|             rootEntitiesFilter = FilterBuilder.Include<Root>().Build(); | ||||
| 
 | ||||
|             // Maybe instead of a root, if we need a component that is always on an entity and has some use we could create something like a VersionComponent which only hold an int. | ||||
|             // The version would update each time something changes on the entity. | ||||
|             // Or a EditorComponent, just a component that always gets added when in editor mode. | ||||
| 
 | ||||
|             hierachySelectionSystem = new EditorHierachySelectionSystem(world); | ||||
|         } | ||||
| 
 | ||||
|         public override void Update(TimeSpan delta) | ||||
|         { | ||||
|             ImGui.Begin("Hierarchy"); | ||||
| 
 | ||||
|             ImGuiTreeNodeFlags flags = baseFlags; | ||||
|             flags |= ImGuiTreeNodeFlags.DefaultOpen; | ||||
| 
 | ||||
|             if (ImGui.TreeNodeEx("World", flags)) | ||||
|             { | ||||
|                 if (ImGui.BeginDragDropTarget()) | ||||
|                 { | ||||
|                     unsafe | ||||
|                     { | ||||
|                         ImGuiPayloadPtr payload = ImGui.AcceptDragDropPayload($"{nameof(EditorHierarchyWindow)}"); | ||||
|                         if (payload.NativePtr != null) | ||||
|                         { | ||||
|                             Entity* data = (Entity*)payload.Data; | ||||
|                             Entity child = data[0]; | ||||
| 
 | ||||
|                             Log.Info($"Dropped {child.ID}"); | ||||
| 
 | ||||
|                             Transform.RemoveParent(World, child); | ||||
|                         } | ||||
|                     } | ||||
|                     ImGui.EndDragDropTarget(); | ||||
|                 } | ||||
| 
 | ||||
|                 //foreach (Entity entity in rootEntitiesWithTransformFilter.Entities) | ||||
|                 //{ | ||||
|                 //    DrawEntityAndChildren(entity); | ||||
|                 //} | ||||
| 
 | ||||
|                 foreach (Entity entity in rootEntitiesFilter.Entities) | ||||
|                 { | ||||
|                     DrawEntityAndChildren(entity); | ||||
|                 } | ||||
| 
 | ||||
|                 ImGui.TreePop(); | ||||
|             } | ||||
| 
 | ||||
|             ImGui.End(); | ||||
| 
 | ||||
|             hierachySelectionSystem.Update(delta); | ||||
|         } | ||||
| 
 | ||||
|         private void DrawEntityAndChildren(in Entity entity) | ||||
|         { | ||||
|             ImGuiTreeNodeFlags flags = baseFlags; | ||||
| 
 | ||||
|             if (!World.HasInRelation<ChildParentRelation>(entity)) | ||||
|             { | ||||
|                 flags |= ImGuiTreeNodeFlags.Leaf; | ||||
|             } | ||||
| 
 | ||||
|             if (World.Has<SelectedInHierachy>(entity)) | ||||
|             { | ||||
|                 flags |= ImGuiTreeNodeFlags.Selected; | ||||
|             } | ||||
| 
 | ||||
|             if (ImGui.TreeNodeEx($"{entity.ID} | {GetTag(entity)}", flags)) | ||||
|             { | ||||
|                 // TODO: fix selection, look at ImGui 1.91, https://github.com/ocornut/imgui/wiki/Multi-Select | ||||
|                 // Selection. | ||||
|                 if (ImGui.IsItemClicked() && !ImGui.IsItemToggledOpen()) | ||||
|                 { | ||||
|                     World.Set(entity, new ClickedInHierachy()); | ||||
|                 } | ||||
| 
 | ||||
|                 // Drag and drop. | ||||
|                 if (ImGui.BeginDragDropSource()) | ||||
|                 { | ||||
|                     unsafe | ||||
|                     { | ||||
|                         fixed (Entity* payload = &entity) | ||||
|                         { | ||||
|                             ImGui.SetDragDropPayload($"{nameof(EditorHierarchyWindow)}", (IntPtr)payload, (uint)sizeof(Entity)); | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     ImGui.EndDragDropSource(); | ||||
|                 } | ||||
| 
 | ||||
|                 if (ImGui.BeginDragDropTarget()) | ||||
|                 { | ||||
|                     unsafe | ||||
|                     { | ||||
|                         ImGuiPayloadPtr payload = ImGui.AcceptDragDropPayload($"{nameof(EditorHierarchyWindow)}"); | ||||
|                         if (payload.NativePtr != null) | ||||
|                         { | ||||
|                             Entity ent = *(Entity*)payload.Data; | ||||
| 
 | ||||
|                             Log.Info($"Dropped {ent.ID}"); | ||||
| 
 | ||||
|                             Transform.SetParent(World, ent, entity); | ||||
|                         } | ||||
|                     } | ||||
|                     ImGui.EndDragDropTarget(); | ||||
|                 } | ||||
| 
 | ||||
|                 // Draw children. | ||||
|                 ReverseSpanEnumerator<Entity> childEntities = World.InRelations<ChildParentRelation>(entity); | ||||
|                 foreach (Entity childEntity in childEntities) | ||||
|                 { | ||||
|                     DrawEntityAndChildren(childEntity); | ||||
|                 } | ||||
| 
 | ||||
|                 ImGui.TreePop(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // System for handling the selected entities in the hierachy. | ||||
|         private class EditorHierachySelectionSystem : MoonTools.ECS.System | ||||
|         { | ||||
|             private readonly Filter selectedEntities; | ||||
|             private readonly Filter clickedEntities; | ||||
| 
 | ||||
|             public EditorHierachySelectionSystem(World world) : base(world) | ||||
|             { | ||||
|                 selectedEntities = FilterBuilder.Include<SelectedInHierachy>().Build(); | ||||
|                 clickedEntities = FilterBuilder.Include<ClickedInHierachy>().Build(); | ||||
|             } | ||||
| 
 | ||||
|             public override void Update(TimeSpan delta) | ||||
|             { | ||||
|                 ImGuiIOPtr io = ImGui.GetIO(); | ||||
| 
 | ||||
|                 if (!clickedEntities.Empty && !io.KeyCtrl) | ||||
|                 { | ||||
|                     foreach (Entity entity in selectedEntities.Entities) | ||||
|                     { | ||||
|                         Remove<SelectedInHierachy>(entity); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 foreach (Entity entity in clickedEntities.Entities) | ||||
|                 { | ||||
|                     // Unselect. | ||||
|                     if (Has<SelectedInHierachy>(entity)) | ||||
|                     { | ||||
|                         Remove<SelectedInHierachy>(entity); | ||||
|                     } | ||||
|                     // Select. | ||||
|                     else | ||||
|                     { | ||||
|                         Set(entity, new SelectedInHierachy()); | ||||
|                     } | ||||
| 
 | ||||
|                     Remove<ClickedInHierachy>(entity); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										100
									
								
								Nerfed.Editor/Systems/EditorInspectorWindow.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								Nerfed.Editor/Systems/EditorInspectorWindow.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | ||||
| using System.Numerics; | ||||
| using ImGuiNET; | ||||
| using MoonTools.ECS; | ||||
| using Nerfed.Editor.Components; | ||||
| using Nerfed.Runtime.Serialization; | ||||
| 
 | ||||
| #if DEBUG | ||||
| namespace Nerfed.Editor.Systems | ||||
| { | ||||
|     // Window that draws entities. | ||||
|     internal class EditorInspectorWindow : MoonTools.ECS.DebugSystem | ||||
|     { | ||||
|         private readonly Filter selectedEntityFilter; | ||||
| 
 | ||||
|         public EditorInspectorWindow(World world) : base(world) | ||||
|         { | ||||
|             selectedEntityFilter = FilterBuilder.Include<SelectedInHierachy>().Build(); | ||||
|         } | ||||
| 
 | ||||
|         public override void Update(TimeSpan delta) | ||||
|         { | ||||
|             ImGui.Begin("Inspector"); | ||||
| 
 | ||||
|             foreach (Entity entity in selectedEntityFilter.Entities) | ||||
|             { | ||||
|                 DrawEntityComponents(entity); | ||||
|             } | ||||
| 
 | ||||
|             ImGui.End(); | ||||
|         } | ||||
| 
 | ||||
|         private void DrawEntityComponents(Entity entity) | ||||
|         { | ||||
|             World.ComponentTypeEnumerator componentTypes = World.Debug_GetAllComponentTypes(entity); | ||||
|              | ||||
|             // Add button of all types that we can add. Also filter out types we already have. | ||||
|             List<Type> componentTypesToAdd = ComponentHelper.AddComponentByType.Keys.ToList(); | ||||
|             foreach (Type componentType in componentTypes) | ||||
|             { | ||||
|                 componentTypesToAdd.Remove(componentType); | ||||
|             } | ||||
| 
 | ||||
|             const string popupId = "AddComponentPopup"; | ||||
|             if (ImGui.Button("Add Component")) | ||||
|             { | ||||
|                 ImGui.OpenPopup(popupId); | ||||
|             } | ||||
| 
 | ||||
|             if (ImGui.BeginPopup(popupId)) | ||||
|             { | ||||
|                 foreach (Type componentType in componentTypesToAdd) | ||||
|                 { | ||||
|                     if (ImGui.Selectable(componentType.Name)) | ||||
|                     { | ||||
|                         if (ComponentHelper.AddComponentByType.TryGetValue(componentType, out Action<World, Entity> componentSetter)) | ||||
|                         { | ||||
|                             componentSetter.Invoke(World, entity); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 ImGui.EndPopup(); | ||||
|             } | ||||
| 
 | ||||
|             ImGui.Dummy(new Vector2(16, 16)); | ||||
|              | ||||
|             ImGui.Text("ComponentInspectorByType"); | ||||
|             foreach (Type componentType in componentTypes) | ||||
|             { | ||||
|                 if (ComponentHelper.ComponentInspectorByType.TryGetValue(componentType, out Action<World, Entity> componentInspector)) | ||||
|                 { | ||||
|                     componentInspector(World, entity); | ||||
|                 } | ||||
|                 else if (ComponentHelper.GetComponentByType.TryGetValue(componentType, out Func<World, Entity, ValueType> componentGetter)) | ||||
|                 { | ||||
|                     ValueType component = componentGetter.Invoke(World, entity); | ||||
|                     ImGui.Text(component.ToString()); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     ImGui.Text(componentType.Name); | ||||
|                 } | ||||
|                 ImGui.Separator(); | ||||
|             } | ||||
|              | ||||
|             ImGui.Dummy(new Vector2(16, 16)); | ||||
| 
 | ||||
|             // ImGui.Text("Reflection"); | ||||
|             // foreach (Type component in componentTypes) | ||||
|             // { | ||||
|             //     System.Reflection.MethodInfo getMethodInfo = typeof(World).GetMethod("Get"); | ||||
|             //     System.Reflection.MethodInfo getComponentMethod = getMethodInfo.MakeGenericMethod(component); | ||||
|             //     object result = getComponentMethod.Invoke(World, [entity]); | ||||
|             // | ||||
|             //     // process here | ||||
|             //     ImGui.Text(result.ToString()); | ||||
|             // } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										204
									
								
								Nerfed.Editor/Systems/EditorProfilerWindow.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								Nerfed.Editor/Systems/EditorProfilerWindow.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,204 @@ | ||||
| using ImGuiNET; | ||||
| using MoonTools.ECS; | ||||
| using Nerfed.Runtime; | ||||
| 
 | ||||
| namespace Nerfed.Editor.Systems | ||||
| { | ||||
|     internal class EditorProfilerWindow : MoonTools.ECS.System | ||||
|     { | ||||
|         const ImGuiTableFlags tableFlags = ImGuiTableFlags.Resizable | ImGuiTableFlags.BordersOuter | ImGuiTableFlags.NoBordersInBody | ImGuiTableFlags.ScrollY | ImGuiTableFlags.ScrollX; | ||||
|         const ImGuiTreeNodeFlags treeNodeFlags = ImGuiTreeNodeFlags.SpanAllColumns; | ||||
|         const ImGuiTreeNodeFlags treeNodeLeafFlags = ImGuiTreeNodeFlags.SpanAllColumns | ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.NoTreePushOnOpen; | ||||
| 
 | ||||
|         private int selectedFrame = 0; | ||||
|         private int previousSelectedFrame = -1; | ||||
|         private IOrderedEnumerable<KeyValuePair<string, (double ms, uint calls)>> orderedCombinedData = null; | ||||
| 
 | ||||
|         public EditorProfilerWindow(World world) : base(world) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         public override void Update(TimeSpan delta) | ||||
|         { | ||||
|             if (Profiler.Frames.Count <= 0) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             ImGui.Begin("Profiler"); | ||||
| 
 | ||||
|             ImGui.BeginChild("Toolbar", new System.Numerics.Vector2(0, 0), ImGuiChildFlags.AutoResizeY); | ||||
|             if (ImGui.RadioButton("Recording", Profiler.IsRecording)) | ||||
|             { | ||||
|                 Profiler.SetActive(!Profiler.IsRecording); | ||||
|             } | ||||
| 
 | ||||
|             ImGui.SameLine(); | ||||
| 
 | ||||
|             if (Profiler.IsRecording) | ||||
|             { | ||||
|                 // Select last frame when recording to see latest frame data. | ||||
|                 selectedFrame = Profiler.Frames.Count - 1; | ||||
|             } | ||||
|             if (ImGui.SliderInt(string.Empty, ref selectedFrame, 0, Profiler.Frames.Count - 1)) | ||||
|             { | ||||
|                 // Stop recording when browsing frames. | ||||
|                 Profiler.SetActive(false); | ||||
|             } | ||||
| 
 | ||||
|             Profiler.Frame frame = Profiler.Frames.ElementAt(selectedFrame); | ||||
|             double ms = frame.ElapsedMilliseconds(); | ||||
|             double s = 1000; | ||||
|             ImGui.Text($"Frame: {frame.FrameCount} ({ms:0.000} ms | {(s / ms):0} fps)"); | ||||
|             ImGui.EndChild(); | ||||
| 
 | ||||
|             if (!Profiler.IsRecording) { | ||||
|                 if (previousSelectedFrame != selectedFrame) | ||||
|                 { | ||||
|                     previousSelectedFrame = selectedFrame; | ||||
|                     orderedCombinedData = CalculateCombinedData(frame); | ||||
|                 } | ||||
| 
 | ||||
|                 DrawFlameGraph(frame); | ||||
| 
 | ||||
|                 DrawHierachy(frame); | ||||
| 
 | ||||
|                 ImGui.SameLine(); | ||||
| 
 | ||||
|                 DrawCombined(orderedCombinedData); | ||||
|             } | ||||
| 
 | ||||
|             ImGui.End(); | ||||
|         } | ||||
| 
 | ||||
|         private static void DrawHierachy(Profiler.Frame frame) | ||||
|         { | ||||
|             if(frame == null) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             ImGui.BeginChild("Hierachy", new System.Numerics.Vector2(150, 0), ImGuiChildFlags.ResizeX); | ||||
| 
 | ||||
|             if (ImGui.BeginTable("ProfilerData", 3, tableFlags, new System.Numerics.Vector2(0, 0))) | ||||
|             { | ||||
|                 ImGui.TableSetupColumn("name", ImGuiTableColumnFlags.WidthStretch, 0.8f, 0); | ||||
|                 ImGui.TableSetupColumn("thread", ImGuiTableColumnFlags.WidthStretch, 0.2f, 1); | ||||
|                 ImGui.TableSetupColumn("ms", ImGuiTableColumnFlags.WidthStretch, 0.2f, 1); | ||||
|                 ImGui.TableSetupScrollFreeze(0, 1); // Make row always visible | ||||
|                 ImGui.TableHeadersRow(); | ||||
| 
 | ||||
|                 foreach (Profiler.ScopeNode node in frame.RootNodes) | ||||
|                 { | ||||
|                     DrawHierachyNode(node); | ||||
|                 } | ||||
| 
 | ||||
|                 ImGui.EndTable(); | ||||
|             } | ||||
| 
 | ||||
|             ImGui.EndChild(); | ||||
|         } | ||||
| 
 | ||||
|         private static void DrawHierachyNode(Profiler.ScopeNode node) | ||||
|         { | ||||
|             ImGui.TableNextRow(); | ||||
|             ImGui.TableNextColumn(); | ||||
| 
 | ||||
|             bool isOpen = false; | ||||
|             bool isLeaf = node.Children.Count == 0; | ||||
| 
 | ||||
|             if (isLeaf) { | ||||
|                 ImGui.TreeNodeEx(node.Label, treeNodeLeafFlags); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 isOpen = ImGui.TreeNodeEx(node.Label, treeNodeFlags); | ||||
|             } | ||||
| 
 | ||||
|             ImGui.TableNextColumn(); | ||||
|             ImGui.Text($"{node.ManagedThreadId}"); | ||||
|             ImGui.TableNextColumn(); | ||||
|             ImGui.Text($"{node.ElapsedMilliseconds():0.000}"); | ||||
| 
 | ||||
|             if (isOpen) | ||||
|             { | ||||
|                 for (int i = 0; i < node.Children.Count; i++) | ||||
|                 { | ||||
|                     DrawHierachyNode(node.Children[i]); | ||||
|                 } | ||||
|                 ImGui.TreePop(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static void DrawCombined(in IOrderedEnumerable<KeyValuePair<string, (double ms, uint calls)>> orderedCombinedData) | ||||
|         { | ||||
|             if(orderedCombinedData == null) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             ImGui.BeginChild("Combined", new System.Numerics.Vector2(0, 0)); | ||||
| 
 | ||||
|             if (ImGui.BeginTable("ProfilerCombinedData", 3, tableFlags, new System.Numerics.Vector2(0, 0))) | ||||
|             { | ||||
|                 ImGui.TableSetupColumn("name", ImGuiTableColumnFlags.WidthStretch, 0.6f, 0); | ||||
|                 ImGui.TableSetupColumn("ms", ImGuiTableColumnFlags.WidthStretch, 0.2f, 1); | ||||
|                 ImGui.TableSetupColumn("calls", ImGuiTableColumnFlags.WidthStretch, 0.2f, 2); | ||||
|                 ImGui.TableSetupScrollFreeze(0, 1); // Make row always visible | ||||
|                 ImGui.TableHeadersRow(); | ||||
| 
 | ||||
|                 foreach (KeyValuePair<string, (double ms, uint calls)> combinedData in orderedCombinedData) | ||||
|                 { | ||||
|                     ImGui.TableNextRow(); | ||||
|                     ImGui.TableNextColumn(); | ||||
|                     ImGui.Text($"{combinedData.Key}"); | ||||
|                     ImGui.TableNextColumn(); | ||||
|                     ImGui.Text($"{combinedData.Value.ms:0.000}"); | ||||
|                     ImGui.TableNextColumn(); | ||||
|                     ImGui.Text($"{combinedData.Value.calls}"); | ||||
|                 } | ||||
| 
 | ||||
|                 ImGui.EndTable(); | ||||
|             } | ||||
| 
 | ||||
|             ImGui.EndChild(); | ||||
|         } | ||||
| 
 | ||||
|         private static IOrderedEnumerable<KeyValuePair<string, (double ms, uint calls)>> CalculateCombinedData(Profiler.Frame frame) | ||||
|         { | ||||
|             Dictionary<string, (double ms, uint calls)> combinedRecordData = new Dictionary<string, (double ms, uint calls)>(128); | ||||
|             foreach (Profiler.ScopeNode node in frame.RootNodes) | ||||
|             { | ||||
|                 CalculateCombinedData(node, in combinedRecordData); | ||||
|             } | ||||
|             return combinedRecordData.OrderByDescending(x => x.Value.ms); | ||||
|         } | ||||
| 
 | ||||
|         private static void CalculateCombinedData(Profiler.ScopeNode node, in Dictionary<string, (double ms, uint calls)> combinedRecordData) | ||||
|         { | ||||
|             if (combinedRecordData.TryGetValue(node.Label, out (double ms, uint calls) combined)) | ||||
|             { | ||||
|                 combinedRecordData[node.Label] = (combined.ms + node.ElapsedMilliseconds(), combined.calls + 1); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 combinedRecordData.Add(node.Label, (node.ElapsedMilliseconds(), 1)); | ||||
|             } | ||||
| 
 | ||||
|             for (int i = 0; i < node.Children.Count; i++) | ||||
|             { | ||||
|                 CalculateCombinedData(node.Children[i], combinedRecordData); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static void DrawFlameGraph(Profiler.Frame frame) | ||||
|         { | ||||
|             if (frame == null) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             ProfilerVisualizer.RenderFlameGraph(frame); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										6
									
								
								Nerfed.Runtime/Components/LocalToWorld.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Nerfed.Runtime/Components/LocalToWorld.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| using System.Numerics; | ||||
| 
 | ||||
| namespace Nerfed.Runtime.Components | ||||
| { | ||||
|     public readonly record struct LocalToWorld(Matrix4x4 localToWorldMatrix); | ||||
| } | ||||
							
								
								
									
										9
									
								
								Nerfed.Runtime/Components/LocalTransform.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								Nerfed.Runtime/Components/LocalTransform.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| using System.Numerics; | ||||
| 
 | ||||
| namespace Nerfed.Runtime.Components | ||||
| { | ||||
|     public readonly record struct LocalTransform(Vector3 position, Quaternion rotation, Vector3 scale) | ||||
|     { | ||||
|         public static readonly LocalTransform Identity = new(Vector3.Zero, Quaternion.Identity, Vector3.One); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										11
									
								
								Nerfed.Runtime/Components/Parent.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Nerfed.Runtime/Components/Parent.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| using MoonTools.ECS; | ||||
| 
 | ||||
| namespace Nerfed.Runtime.Components | ||||
| { | ||||
|     public readonly record struct Root; | ||||
|     //public readonly record struct Parent; | ||||
|     //public readonly record struct PreviousParent; | ||||
|     public readonly record struct Child; | ||||
|     // Describes a relation from the child to the parent. | ||||
|     public readonly record struct ChildParentRelation; | ||||
| } | ||||
							
								
								
									
										4
									
								
								Nerfed.Runtime/Components/Test.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								Nerfed.Runtime/Components/Test.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| namespace Nerfed.Runtime.Components | ||||
| { | ||||
|     public readonly record struct Test(); | ||||
| } | ||||
| @@ -1,2 +0,0 @@ | ||||
| glslangvalidator -V imgui-vertex.glsl -o imgui-vertex.spv -S vert | ||||
| glslangvalidator -V imgui-frag.glsl -o imgui-frag.spv -S frag | ||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -1,27 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||||
|  | ||||
| 	<Target Name="Runtime ID"  AfterTargets="Build"> | ||||
|     	<Message Text="Runtime ID: $(RuntimeIdentifier)" Importance="high"/> | ||||
| 	</Target> | ||||
|  | ||||
| 	<ItemGroup Condition="$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))"> | ||||
| 		<Content Include="..\libs\x64\**\*.*" > | ||||
| 			<Link>%(RecursiveDir)%(Filename)%(Extension)</Link> | ||||
| 			<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||||
| 		</Content> | ||||
| 	</ItemGroup> | ||||
| 	<ItemGroup Condition="$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))"> | ||||
| 		<Content Include="..\libs\lib64\**\*.*" > | ||||
| 			<Link>%(RecursiveDir)%(Filename)%(Extension)</Link> | ||||
| 			<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||||
| 		</Content> | ||||
| 	</ItemGroup> | ||||
| 	<ItemGroup Condition="$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))"> | ||||
| 		<Content Include="..\libs\osx\**\*.*" > | ||||
| 			<Link>%(RecursiveDir)%(Filename)%(Extension)</Link> | ||||
| 			<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||||
| 		</Content> | ||||
| 	</ItemGroup> | ||||
|  | ||||
| </Project> | ||||
| @@ -7,6 +7,11 @@ namespace Nerfed.Runtime; | ||||
| 
 | ||||
| public static class Engine | ||||
| { | ||||
|     public static event Action OnInitialize; | ||||
|     public static event Action OnUpdate; | ||||
|     public static event Action OnRender; | ||||
|     public static event Action OnQuit; | ||||
| 
 | ||||
|     public static TimeSpan MaxDeltaTime { get; set; } = TimeSpan.FromMilliseconds(100); | ||||
|     public static bool VSync { get; set; } | ||||
| 
 | ||||
| @@ -19,6 +24,7 @@ public static class Engine | ||||
|     private static Stopwatch gameTimer; | ||||
|     private static long previousTicks = 0; | ||||
|     private static TimeSpan accumulatedUpdateTime = TimeSpan.Zero; | ||||
| 
 | ||||
|     private static TimeSpan accumulatedDrawTime = TimeSpan.Zero; | ||||
| 
 | ||||
|     // must be a power of 2 so we can do a bitmask optimization when checking worst case | ||||
| @@ -38,9 +44,7 @@ public static class Engine | ||||
|     private const string WindowTitle = "Nerfed"; | ||||
|     //.. | ||||
| 
 | ||||
|     private static Gui.GuiController Controller; | ||||
| 
 | ||||
|     internal static void Run(string[] args) | ||||
|     public static void Run(string[] args) | ||||
|     { | ||||
|         Timestep = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / TargetTimestep); | ||||
|         gameTimer = Stopwatch.StartNew(); | ||||
| @@ -55,8 +59,9 @@ public static class Engine | ||||
|         { | ||||
|             throw new Exception("Failed to init SDL"); | ||||
|         } | ||||
| 
 | ||||
|          | ||||
|         GraphicsDevice = new GraphicsDevice(BackendFlags.All); | ||||
|         GraphicsDevice.LoadDefaultPipelines(); | ||||
| 
 | ||||
|         MainWindow = new Window(GraphicsDevice, new WindowCreateInfo(WindowTitle, WindowWidth, WindowHeight, ScreenMode.Windowed)); | ||||
|         if (!GraphicsDevice.ClaimWindow(MainWindow, SwapchainComposition.SDR, VSync ? PresentMode.VSync : PresentMode.Mailbox)) | ||||
| @@ -64,23 +69,17 @@ public static class Engine | ||||
|             throw new Exception("Failed to claim window"); | ||||
|         } | ||||
| 
 | ||||
|         MainWindow.OnCloseEvent += (w) => { | ||||
|             Quit(); | ||||
|         }; | ||||
| 
 | ||||
|         AudioDevice = new AudioDevice(); | ||||
| 
 | ||||
|         Controller = new Gui.GuiController(GraphicsDevice, MainWindow, Color.DarkOliveGreen); | ||||
|         Controller.OnGui += () => { | ||||
|             ImGuiNET.ImGui.ShowDemoWindow(); | ||||
|         }; | ||||
|         OnInitialize?.Invoke(); | ||||
| 
 | ||||
|         while (!quit) | ||||
|         { | ||||
|             Tick(); | ||||
|         } | ||||
| 
 | ||||
|         Controller.Dispose(); | ||||
|         OnQuit?.Invoke(); | ||||
| 
 | ||||
|         GraphicsDevice.UnclaimWindow(MainWindow); | ||||
|         MainWindow.Dispose(); | ||||
|         GraphicsDevice.Dispose(); | ||||
| @@ -112,10 +111,14 @@ public static class Engine | ||||
| 
 | ||||
|     private static void Tick() | ||||
|     { | ||||
|         Profiler.BeginFrame(); | ||||
| 
 | ||||
|         AdvanceElapsedTime(); | ||||
| 
 | ||||
|         if (framerateCapped) | ||||
|         { | ||||
|             Profiler.BeginSample("framerateCapped"); | ||||
| 
 | ||||
|             /* We want to wait until the framerate cap, | ||||
|              * but we don't want to oversleep. Requesting repeated 1ms sleeps and | ||||
|              * seeing how long we actually slept for lets us estimate the worst case | ||||
| @@ -138,6 +141,8 @@ public static class Engine | ||||
|                 Thread.SpinWait(1); | ||||
|                 AdvanceElapsedTime(); | ||||
|             } | ||||
| 
 | ||||
|             Profiler.EndSample(); | ||||
|         } | ||||
| 
 | ||||
|         // Do not let any step take longer than our maximum. | ||||
| @@ -150,6 +155,7 @@ public static class Engine | ||||
|         { | ||||
|             while (accumulatedUpdateTime >= Timestep) | ||||
|             { | ||||
|                 Profiler.BeginSample("Update"); | ||||
|                 Keyboard.Update(); | ||||
|                 Mouse.Update(); | ||||
|                 GamePad.Update(); | ||||
| @@ -157,19 +163,26 @@ public static class Engine | ||||
|                 ProcessSDLEvents(); | ||||
| 
 | ||||
|                 // Tick game here... | ||||
|                 Controller.Update((float)Timestep.TotalSeconds); | ||||
|                 Profiler.BeginSample("OnUpdate"); | ||||
|                 OnUpdate?.Invoke(); | ||||
|                 Profiler.EndSample(); | ||||
| 
 | ||||
|                 AudioDevice.WakeThread(); | ||||
|                 accumulatedUpdateTime -= Timestep; | ||||
|                 Profiler.EndSample(); | ||||
|             } | ||||
| 
 | ||||
|             double alpha = accumulatedUpdateTime / Timestep; | ||||
| 
 | ||||
|             // Render here.. | ||||
|             Controller.Render(); | ||||
|             Profiler.BeginSample("OnRender"); | ||||
|             OnRender?.Invoke(); | ||||
|             Profiler.EndSample(); | ||||
| 
 | ||||
|             accumulatedDrawTime -= framerateCapTimeSpan; | ||||
|         } | ||||
| 
 | ||||
|         Profiler.EndFrame(); | ||||
|     } | ||||
| 
 | ||||
|     private static TimeSpan AdvanceElapsedTime() | ||||
|   | ||||
| @@ -1,716 +0,0 @@ | ||||
| namespace Nerfed.Runtime.Graphics; | ||||
| 
 | ||||
| internal class EmbeddedShadersSpirV : IEmbeddedShaders | ||||
| { | ||||
|     public ShaderFormat ShaderFormat => ShaderFormat.SPIRV; | ||||
| 
 | ||||
|     public byte[] FullscreenVert { get; } = | ||||
|     [ | ||||
|         0x3, 0x2, 0x23, 0x7, 0x0, 0x0, 0x1, 0x0, 0xB, 0x0, | ||||
|         0x8, 0x0, 0x2E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x11, 0x0, 0x2, 0x0, 0x1, 0x0, 0x0, 0x0, 0xB, 0x0, | ||||
|         0x6, 0x0, 0x1, 0x0, 0x0, 0x0, 0x47, 0x4C, 0x53, 0x4C, | ||||
|         0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, 0x0, 0x0, | ||||
|         0x0, 0x0, 0xE, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x1, 0x0, 0x0, 0x0, 0xF, 0x0, 0x8, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x6D, 0x61, 0x69, 0x6E, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0xC, 0x0, | ||||
|         0x0, 0x0, 0x1D, 0x0, 0x0, 0x0, 0x3, 0x0, 0x3, 0x0, | ||||
|         0x2, 0x0, 0x0, 0x0, 0xC2, 0x1, 0x0, 0x0, 0x5, 0x0, | ||||
|         0x4, 0x0, 0x4, 0x0, 0x0, 0x0, 0x6D, 0x61, 0x69, 0x6E, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x5, 0x0, 0x5, 0x0, 0x9, 0x0, | ||||
|         0x0, 0x0, 0x6F, 0x75, 0x74, 0x54, 0x65, 0x78, 0x43, 0x6F, | ||||
|         0x6F, 0x72, 0x64, 0x0, 0x5, 0x0, 0x6, 0x0, 0xC, 0x0, | ||||
|         0x0, 0x0, 0x67, 0x6C, 0x5F, 0x56, 0x65, 0x72, 0x74, 0x65, | ||||
|         0x78, 0x49, 0x6E, 0x64, 0x65, 0x78, 0x0, 0x0, 0x5, 0x0, | ||||
|         0x6, 0x0, 0x1B, 0x0, 0x0, 0x0, 0x67, 0x6C, 0x5F, 0x50, | ||||
|         0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x6, 0x0, 0x6, 0x0, 0x1B, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x67, 0x6C, 0x5F, 0x50, 0x6F, 0x73, | ||||
|         0x69, 0x74, 0x69, 0x6F, 0x6E, 0x0, 0x6, 0x0, 0x7, 0x0, | ||||
|         0x1B, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x67, 0x6C, | ||||
|         0x5F, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x53, 0x69, 0x7A, 0x65, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x6, 0x0, 0x7, 0x0, 0x1B, 0x0, | ||||
|         0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x67, 0x6C, 0x5F, 0x43, | ||||
|         0x6C, 0x69, 0x70, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, | ||||
|         0x65, 0x0, 0x6, 0x0, 0x7, 0x0, 0x1B, 0x0, 0x0, 0x0, | ||||
|         0x3, 0x0, 0x0, 0x0, 0x67, 0x6C, 0x5F, 0x43, 0x75, 0x6C, | ||||
|         0x6C, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x0, | ||||
|         0x5, 0x0, 0x3, 0x0, 0x1D, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x47, 0x0, 0x4, 0x0, 0x9, 0x0, 0x0, 0x0, | ||||
|         0x1E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x47, 0x0, | ||||
|         0x4, 0x0, 0xC, 0x0, 0x0, 0x0, 0xB, 0x0, 0x0, 0x0, | ||||
|         0x2A, 0x0, 0x0, 0x0, 0x48, 0x0, 0x5, 0x0, 0x1B, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xB, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x48, 0x0, 0x5, 0x0, 0x1B, 0x0, | ||||
|         0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0xB, 0x0, 0x0, 0x0, | ||||
|         0x1, 0x0, 0x0, 0x0, 0x48, 0x0, 0x5, 0x0, 0x1B, 0x0, | ||||
|         0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0xB, 0x0, 0x0, 0x0, | ||||
|         0x3, 0x0, 0x0, 0x0, 0x48, 0x0, 0x5, 0x0, 0x1B, 0x0, | ||||
|         0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0xB, 0x0, 0x0, 0x0, | ||||
|         0x4, 0x0, 0x0, 0x0, 0x47, 0x0, 0x3, 0x0, 0x1B, 0x0, | ||||
|         0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x13, 0x0, 0x2, 0x0, | ||||
|         0x2, 0x0, 0x0, 0x0, 0x21, 0x0, 0x3, 0x0, 0x3, 0x0, | ||||
|         0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x16, 0x0, 0x3, 0x0, | ||||
|         0x6, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x17, 0x0, | ||||
|         0x4, 0x0, 0x7, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, | ||||
|         0x2, 0x0, 0x0, 0x0, 0x20, 0x0, 0x4, 0x0, 0x8, 0x0, | ||||
|         0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, | ||||
|         0x3B, 0x0, 0x4, 0x0, 0x8, 0x0, 0x0, 0x0, 0x9, 0x0, | ||||
|         0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x15, 0x0, 0x4, 0x0, | ||||
|         0xA, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x1, 0x0, | ||||
|         0x0, 0x0, 0x20, 0x0, 0x4, 0x0, 0xB, 0x0, 0x0, 0x0, | ||||
|         0x1, 0x0, 0x0, 0x0, 0xA, 0x0, 0x0, 0x0, 0x3B, 0x0, | ||||
|         0x4, 0x0, 0xB, 0x0, 0x0, 0x0, 0xC, 0x0, 0x0, 0x0, | ||||
|         0x1, 0x0, 0x0, 0x0, 0x2B, 0x0, 0x4, 0x0, 0xA, 0x0, | ||||
|         0x0, 0x0, 0xE, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, | ||||
|         0x2B, 0x0, 0x4, 0x0, 0xA, 0x0, 0x0, 0x0, 0x10, 0x0, | ||||
|         0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x17, 0x0, 0x4, 0x0, | ||||
|         0x17, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x4, 0x0, | ||||
|         0x0, 0x0, 0x15, 0x0, 0x4, 0x0, 0x18, 0x0, 0x0, 0x0, | ||||
|         0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2B, 0x0, | ||||
|         0x4, 0x0, 0x18, 0x0, 0x0, 0x0, 0x19, 0x0, 0x0, 0x0, | ||||
|         0x1, 0x0, 0x0, 0x0, 0x1C, 0x0, 0x4, 0x0, 0x1A, 0x0, | ||||
|         0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x19, 0x0, 0x0, 0x0, | ||||
|         0x1E, 0x0, 0x6, 0x0, 0x1B, 0x0, 0x0, 0x0, 0x17, 0x0, | ||||
|         0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x1A, 0x0, 0x0, 0x0, | ||||
|         0x1A, 0x0, 0x0, 0x0, 0x20, 0x0, 0x4, 0x0, 0x1C, 0x0, | ||||
|         0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x1B, 0x0, 0x0, 0x0, | ||||
|         0x3B, 0x0, 0x4, 0x0, 0x1C, 0x0, 0x0, 0x0, 0x1D, 0x0, | ||||
|         0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x2B, 0x0, 0x4, 0x0, | ||||
|         0xA, 0x0, 0x0, 0x0, 0x1E, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x2B, 0x0, 0x4, 0x0, 0x6, 0x0, 0x0, 0x0, | ||||
|         0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x2B, 0x0, | ||||
|         0x4, 0x0, 0x6, 0x0, 0x0, 0x0, 0x21, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x0, 0xC0, 0x2C, 0x0, 0x5, 0x0, 0x7, 0x0, | ||||
|         0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, | ||||
|         0x21, 0x0, 0x0, 0x0, 0x2B, 0x0, 0x4, 0x0, 0x6, 0x0, | ||||
|         0x0, 0x0, 0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0xBF, | ||||
|         0x2B, 0x0, 0x4, 0x0, 0x6, 0x0, 0x0, 0x0, 0x25, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x80, 0x3F, 0x2C, 0x0, 0x5, 0x0, | ||||
|         0x7, 0x0, 0x0, 0x0, 0x26, 0x0, 0x0, 0x0, 0x24, 0x0, | ||||
|         0x0, 0x0, 0x25, 0x0, 0x0, 0x0, 0x2B, 0x0, 0x4, 0x0, | ||||
|         0x6, 0x0, 0x0, 0x0, 0x28, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x20, 0x0, 0x4, 0x0, 0x2C, 0x0, 0x0, 0x0, | ||||
|         0x3, 0x0, 0x0, 0x0, 0x17, 0x0, 0x0, 0x0, 0x36, 0x0, | ||||
|         0x5, 0x0, 0x2, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0xF8, 0x0, | ||||
|         0x2, 0x0, 0x5, 0x0, 0x0, 0x0, 0x3D, 0x0, 0x4, 0x0, | ||||
|         0xA, 0x0, 0x0, 0x0, 0xD, 0x0, 0x0, 0x0, 0xC, 0x0, | ||||
|         0x0, 0x0, 0xC4, 0x0, 0x5, 0x0, 0xA, 0x0, 0x0, 0x0, | ||||
|         0xF, 0x0, 0x0, 0x0, 0xD, 0x0, 0x0, 0x0, 0xE, 0x0, | ||||
|         0x0, 0x0, 0xC7, 0x0, 0x5, 0x0, 0xA, 0x0, 0x0, 0x0, | ||||
|         0x11, 0x0, 0x0, 0x0, 0xF, 0x0, 0x0, 0x0, 0x10, 0x0, | ||||
|         0x0, 0x0, 0x6F, 0x0, 0x4, 0x0, 0x6, 0x0, 0x0, 0x0, | ||||
|         0x12, 0x0, 0x0, 0x0, 0x11, 0x0, 0x0, 0x0, 0x3D, 0x0, | ||||
|         0x4, 0x0, 0xA, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, | ||||
|         0xC, 0x0, 0x0, 0x0, 0xC7, 0x0, 0x5, 0x0, 0xA, 0x0, | ||||
|         0x0, 0x0, 0x14, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, | ||||
|         0x10, 0x0, 0x0, 0x0, 0x6F, 0x0, 0x4, 0x0, 0x6, 0x0, | ||||
|         0x0, 0x0, 0x15, 0x0, 0x0, 0x0, 0x14, 0x0, 0x0, 0x0, | ||||
|         0x50, 0x0, 0x5, 0x0, 0x7, 0x0, 0x0, 0x0, 0x16, 0x0, | ||||
|         0x0, 0x0, 0x12, 0x0, 0x0, 0x0, 0x15, 0x0, 0x0, 0x0, | ||||
|         0x3E, 0x0, 0x3, 0x0, 0x9, 0x0, 0x0, 0x0, 0x16, 0x0, | ||||
|         0x0, 0x0, 0x3D, 0x0, 0x4, 0x0, 0x7, 0x0, 0x0, 0x0, | ||||
|         0x1F, 0x0, 0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x85, 0x0, | ||||
|         0x5, 0x0, 0x7, 0x0, 0x0, 0x0, 0x23, 0x0, 0x0, 0x0, | ||||
|         0x1F, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x81, 0x0, | ||||
|         0x5, 0x0, 0x7, 0x0, 0x0, 0x0, 0x27, 0x0, 0x0, 0x0, | ||||
|         0x23, 0x0, 0x0, 0x0, 0x26, 0x0, 0x0, 0x0, 0x51, 0x0, | ||||
|         0x5, 0x0, 0x6, 0x0, 0x0, 0x0, 0x29, 0x0, 0x0, 0x0, | ||||
|         0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x51, 0x0, | ||||
|         0x5, 0x0, 0x6, 0x0, 0x0, 0x0, 0x2A, 0x0, 0x0, 0x0, | ||||
|         0x27, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x50, 0x0, | ||||
|         0x7, 0x0, 0x17, 0x0, 0x0, 0x0, 0x2B, 0x0, 0x0, 0x0, | ||||
|         0x29, 0x0, 0x0, 0x0, 0x2A, 0x0, 0x0, 0x0, 0x28, 0x0, | ||||
|         0x0, 0x0, 0x25, 0x0, 0x0, 0x0, 0x41, 0x0, 0x5, 0x0, | ||||
|         0x2C, 0x0, 0x0, 0x0, 0x2D, 0x0, 0x0, 0x0, 0x1D, 0x0, | ||||
|         0x0, 0x0, 0x1E, 0x0, 0x0, 0x0, 0x3E, 0x0, 0x3, 0x0, | ||||
|         0x2D, 0x0, 0x0, 0x0, 0x2B, 0x0, 0x0, 0x0, 0xFD, 0x0, | ||||
|         0x1, 0x0, 0x38, 0x0, 0x1, 0x0, | ||||
|     ]; | ||||
| 
 | ||||
|     public byte[] TextMsdfFrag { get; } = | ||||
|     [ | ||||
|         0x3, 0x2, 0x23, 0x7, 0x0, 0x0, 0x1, 0x0, 0xB, 0x0, | ||||
|         0x8, 0x0, 0x6C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x11, 0x0, 0x2, 0x0, 0x1, 0x0, 0x0, 0x0, 0x11, 0x0, | ||||
|         0x2, 0x0, 0x32, 0x0, 0x0, 0x0, 0xB, 0x0, 0x6, 0x0, | ||||
|         0x1, 0x0, 0x0, 0x0, 0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, | ||||
|         0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, 0x0, 0x0, 0x0, 0x0, | ||||
|         0xE, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, | ||||
|         0x0, 0x0, 0xF, 0x0, 0x8, 0x0, 0x4, 0x0, 0x0, 0x0, | ||||
|         0x4, 0x0, 0x0, 0x0, 0x6D, 0x61, 0x69, 0x6E, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x36, 0x0, 0x0, 0x0, 0x64, 0x0, 0x0, 0x0, | ||||
|         0x67, 0x0, 0x0, 0x0, 0x10, 0x0, 0x3, 0x0, 0x4, 0x0, | ||||
|         0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x3, 0x0, 0x3, 0x0, | ||||
|         0x2, 0x0, 0x0, 0x0, 0xC2, 0x1, 0x0, 0x0, 0x5, 0x0, | ||||
|         0x4, 0x0, 0x4, 0x0, 0x0, 0x0, 0x6D, 0x61, 0x69, 0x6E, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x5, 0x0, 0x7, 0x0, 0xC, 0x0, | ||||
|         0x0, 0x0, 0x6D, 0x65, 0x64, 0x69, 0x61, 0x6E, 0x28, 0x66, | ||||
|         0x31, 0x3B, 0x66, 0x31, 0x3B, 0x66, 0x31, 0x3B, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x5, 0x0, 0x3, 0x0, 0x9, 0x0, 0x0, 0x0, | ||||
|         0x72, 0x0, 0x0, 0x0, 0x5, 0x0, 0x3, 0x0, 0xA, 0x0, | ||||
|         0x0, 0x0, 0x67, 0x0, 0x0, 0x0, 0x5, 0x0, 0x3, 0x0, | ||||
|         0xB, 0x0, 0x0, 0x0, 0x62, 0x0, 0x0, 0x0, 0x5, 0x0, | ||||
|         0x6, 0x0, 0xF, 0x0, 0x0, 0x0, 0x73, 0x63, 0x72, 0x65, | ||||
|         0x65, 0x6E, 0x50, 0x78, 0x52, 0x61, 0x6E, 0x67, 0x65, 0x28, | ||||
|         0x0, 0x0, 0x5, 0x0, 0x5, 0x0, 0x1E, 0x0, 0x0, 0x0, | ||||
|         0x75, 0x6E, 0x69, 0x74, 0x52, 0x61, 0x6E, 0x67, 0x65, 0x0, | ||||
|         0x0, 0x0, 0x5, 0x0, 0x3, 0x0, 0x1F, 0x0, 0x0, 0x0, | ||||
|         0x55, 0x42, 0x4F, 0x0, 0x6, 0x0, 0x5, 0x0, 0x1F, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x70, 0x78, 0x52, 0x61, | ||||
|         0x6E, 0x67, 0x65, 0x0, 0x5, 0x0, 0x3, 0x0, 0x21, 0x0, | ||||
|         0x0, 0x0, 0x75, 0x62, 0x6F, 0x0, 0x5, 0x0, 0x4, 0x0, | ||||
|         0x2B, 0x0, 0x0, 0x0, 0x6D, 0x73, 0x64, 0x66, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x5, 0x0, 0x6, 0x0, 0x32, 0x0, 0x0, 0x0, | ||||
|         0x73, 0x63, 0x72, 0x65, 0x65, 0x6E, 0x54, 0x65, 0x78, 0x53, | ||||
|         0x69, 0x7A, 0x65, 0x0, 0x0, 0x0, 0x5, 0x0, 0x5, 0x0, | ||||
|         0x36, 0x0, 0x0, 0x0, 0x69, 0x6E, 0x54, 0x65, 0x78, 0x43, | ||||
|         0x6F, 0x6F, 0x72, 0x64, 0x0, 0x0, 0x5, 0x0, 0x3, 0x0, | ||||
|         0x44, 0x0, 0x0, 0x0, 0x6D, 0x73, 0x64, 0x0, 0x5, 0x0, | ||||
|         0x3, 0x0, 0x4A, 0x0, 0x0, 0x0, 0x73, 0x64, 0x0, 0x0, | ||||
|         0x5, 0x0, 0x4, 0x0, 0x4B, 0x0, 0x0, 0x0, 0x70, 0x61, | ||||
|         0x72, 0x61, 0x6D, 0x0, 0x0, 0x0, 0x5, 0x0, 0x4, 0x0, | ||||
|         0x50, 0x0, 0x0, 0x0, 0x70, 0x61, 0x72, 0x61, 0x6D, 0x0, | ||||
|         0x0, 0x0, 0x5, 0x0, 0x4, 0x0, 0x54, 0x0, 0x0, 0x0, | ||||
|         0x70, 0x61, 0x72, 0x61, 0x6D, 0x0, 0x0, 0x0, 0x5, 0x0, | ||||
|         0x7, 0x0, 0x59, 0x0, 0x0, 0x0, 0x73, 0x63, 0x72, 0x65, | ||||
|         0x65, 0x6E, 0x50, 0x78, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6E, | ||||
|         0x63, 0x65, 0x0, 0x0, 0x0, 0x0, 0x5, 0x0, 0x4, 0x0, | ||||
|         0x5E, 0x0, 0x0, 0x0, 0x6F, 0x70, 0x61, 0x63, 0x69, 0x74, | ||||
|         0x79, 0x0, 0x5, 0x0, 0x5, 0x0, 0x64, 0x0, 0x0, 0x0, | ||||
|         0x6F, 0x75, 0x74, 0x43, 0x6F, 0x6C, 0x6F, 0x72, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x5, 0x0, 0x4, 0x0, 0x67, 0x0, 0x0, 0x0, | ||||
|         0x69, 0x6E, 0x43, 0x6F, 0x6C, 0x6F, 0x72, 0x0, 0x48, 0x0, | ||||
|         0x5, 0x0, 0x1F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x23, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x47, 0x0, | ||||
|         0x3, 0x0, 0x1F, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, | ||||
|         0x47, 0x0, 0x4, 0x0, 0x21, 0x0, 0x0, 0x0, 0x22, 0x0, | ||||
|         0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x47, 0x0, 0x4, 0x0, | ||||
|         0x21, 0x0, 0x0, 0x0, 0x21, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x47, 0x0, 0x4, 0x0, 0x2B, 0x0, 0x0, 0x0, | ||||
|         0x22, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x47, 0x0, | ||||
|         0x4, 0x0, 0x2B, 0x0, 0x0, 0x0, 0x21, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x47, 0x0, 0x4, 0x0, 0x36, 0x0, | ||||
|         0x0, 0x0, 0x1E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x47, 0x0, 0x4, 0x0, 0x64, 0x0, 0x0, 0x0, 0x1E, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x47, 0x0, 0x4, 0x0, | ||||
|         0x67, 0x0, 0x0, 0x0, 0x1E, 0x0, 0x0, 0x0, 0x1, 0x0, | ||||
|         0x0, 0x0, 0x13, 0x0, 0x2, 0x0, 0x2, 0x0, 0x0, 0x0, | ||||
|         0x21, 0x0, 0x3, 0x0, 0x3, 0x0, 0x0, 0x0, 0x2, 0x0, | ||||
|         0x0, 0x0, 0x16, 0x0, 0x3, 0x0, 0x6, 0x0, 0x0, 0x0, | ||||
|         0x20, 0x0, 0x0, 0x0, 0x20, 0x0, 0x4, 0x0, 0x7, 0x0, | ||||
|         0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, | ||||
|         0x21, 0x0, 0x6, 0x0, 0x8, 0x0, 0x0, 0x0, 0x6, 0x0, | ||||
|         0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, | ||||
|         0x7, 0x0, 0x0, 0x0, 0x21, 0x0, 0x3, 0x0, 0xE, 0x0, | ||||
|         0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x17, 0x0, 0x4, 0x0, | ||||
|         0x1C, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x2, 0x0, | ||||
|         0x0, 0x0, 0x20, 0x0, 0x4, 0x0, 0x1D, 0x0, 0x0, 0x0, | ||||
|         0x7, 0x0, 0x0, 0x0, 0x1C, 0x0, 0x0, 0x0, 0x1E, 0x0, | ||||
|         0x3, 0x0, 0x1F, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, | ||||
|         0x20, 0x0, 0x4, 0x0, 0x20, 0x0, 0x0, 0x0, 0x2, 0x0, | ||||
|         0x0, 0x0, 0x1F, 0x0, 0x0, 0x0, 0x3B, 0x0, 0x4, 0x0, | ||||
|         0x20, 0x0, 0x0, 0x0, 0x21, 0x0, 0x0, 0x0, 0x2, 0x0, | ||||
|         0x0, 0x0, 0x15, 0x0, 0x4, 0x0, 0x22, 0x0, 0x0, 0x0, | ||||
|         0x20, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x2B, 0x0, | ||||
|         0x4, 0x0, 0x22, 0x0, 0x0, 0x0, 0x23, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x4, 0x0, 0x24, 0x0, | ||||
|         0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, | ||||
|         0x19, 0x0, 0x9, 0x0, 0x28, 0x0, 0x0, 0x0, 0x6, 0x0, | ||||
|         0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1B, 0x0, 0x3, 0x0, | ||||
|         0x29, 0x0, 0x0, 0x0, 0x28, 0x0, 0x0, 0x0, 0x20, 0x0, | ||||
|         0x4, 0x0, 0x2A, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x29, 0x0, 0x0, 0x0, 0x3B, 0x0, 0x4, 0x0, 0x2A, 0x0, | ||||
|         0x0, 0x0, 0x2B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x17, 0x0, 0x4, 0x0, 0x2E, 0x0, 0x0, 0x0, 0x22, 0x0, | ||||
|         0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x2B, 0x0, 0x4, 0x0, | ||||
|         0x6, 0x0, 0x0, 0x0, 0x33, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x80, 0x3F, 0x2C, 0x0, 0x5, 0x0, 0x1C, 0x0, 0x0, 0x0, | ||||
|         0x34, 0x0, 0x0, 0x0, 0x33, 0x0, 0x0, 0x0, 0x33, 0x0, | ||||
|         0x0, 0x0, 0x20, 0x0, 0x4, 0x0, 0x35, 0x0, 0x0, 0x0, | ||||
|         0x1, 0x0, 0x0, 0x0, 0x1C, 0x0, 0x0, 0x0, 0x3B, 0x0, | ||||
|         0x4, 0x0, 0x35, 0x0, 0x0, 0x0, 0x36, 0x0, 0x0, 0x0, | ||||
|         0x1, 0x0, 0x0, 0x0, 0x2B, 0x0, 0x4, 0x0, 0x6, 0x0, | ||||
|         0x0, 0x0, 0x3A, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3F, | ||||
|         0x17, 0x0, 0x4, 0x0, 0x42, 0x0, 0x0, 0x0, 0x6, 0x0, | ||||
|         0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x20, 0x0, 0x4, 0x0, | ||||
|         0x43, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x42, 0x0, | ||||
|         0x0, 0x0, 0x17, 0x0, 0x4, 0x0, 0x47, 0x0, 0x0, 0x0, | ||||
|         0x6, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x15, 0x0, | ||||
|         0x4, 0x0, 0x4C, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x2B, 0x0, 0x4, 0x0, 0x4C, 0x0, | ||||
|         0x0, 0x0, 0x4D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x2B, 0x0, 0x4, 0x0, 0x4C, 0x0, 0x0, 0x0, 0x51, 0x0, | ||||
|         0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x2B, 0x0, 0x4, 0x0, | ||||
|         0x4C, 0x0, 0x0, 0x0, 0x55, 0x0, 0x0, 0x0, 0x2, 0x0, | ||||
|         0x0, 0x0, 0x2B, 0x0, 0x4, 0x0, 0x6, 0x0, 0x0, 0x0, | ||||
|         0x61, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, | ||||
|         0x4, 0x0, 0x63, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, | ||||
|         0x47, 0x0, 0x0, 0x0, 0x3B, 0x0, 0x4, 0x0, 0x63, 0x0, | ||||
|         0x0, 0x0, 0x64, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, | ||||
|         0x2C, 0x0, 0x7, 0x0, 0x47, 0x0, 0x0, 0x0, 0x65, 0x0, | ||||
|         0x0, 0x0, 0x61, 0x0, 0x0, 0x0, 0x61, 0x0, 0x0, 0x0, | ||||
|         0x61, 0x0, 0x0, 0x0, 0x61, 0x0, 0x0, 0x0, 0x20, 0x0, | ||||
|         0x4, 0x0, 0x66, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, | ||||
|         0x47, 0x0, 0x0, 0x0, 0x3B, 0x0, 0x4, 0x0, 0x66, 0x0, | ||||
|         0x0, 0x0, 0x67, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, | ||||
|         0x36, 0x0, 0x5, 0x0, 0x2, 0x0, 0x0, 0x0, 0x4, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, | ||||
|         0xF8, 0x0, 0x2, 0x0, 0x5, 0x0, 0x0, 0x0, 0x3B, 0x0, | ||||
|         0x4, 0x0, 0x43, 0x0, 0x0, 0x0, 0x44, 0x0, 0x0, 0x0, | ||||
|         0x7, 0x0, 0x0, 0x0, 0x3B, 0x0, 0x4, 0x0, 0x7, 0x0, | ||||
|         0x0, 0x0, 0x4A, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, | ||||
|         0x3B, 0x0, 0x4, 0x0, 0x7, 0x0, 0x0, 0x0, 0x4B, 0x0, | ||||
|         0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x3B, 0x0, 0x4, 0x0, | ||||
|         0x7, 0x0, 0x0, 0x0, 0x50, 0x0, 0x0, 0x0, 0x7, 0x0, | ||||
|         0x0, 0x0, 0x3B, 0x0, 0x4, 0x0, 0x7, 0x0, 0x0, 0x0, | ||||
|         0x54, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x3B, 0x0, | ||||
|         0x4, 0x0, 0x7, 0x0, 0x0, 0x0, 0x59, 0x0, 0x0, 0x0, | ||||
|         0x7, 0x0, 0x0, 0x0, 0x3B, 0x0, 0x4, 0x0, 0x7, 0x0, | ||||
|         0x0, 0x0, 0x5E, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, | ||||
|         0x3D, 0x0, 0x4, 0x0, 0x29, 0x0, 0x0, 0x0, 0x45, 0x0, | ||||
|         0x0, 0x0, 0x2B, 0x0, 0x0, 0x0, 0x3D, 0x0, 0x4, 0x0, | ||||
|         0x1C, 0x0, 0x0, 0x0, 0x46, 0x0, 0x0, 0x0, 0x36, 0x0, | ||||
|         0x0, 0x0, 0x57, 0x0, 0x5, 0x0, 0x47, 0x0, 0x0, 0x0, | ||||
|         0x48, 0x0, 0x0, 0x0, 0x45, 0x0, 0x0, 0x0, 0x46, 0x0, | ||||
|         0x0, 0x0, 0x4F, 0x0, 0x8, 0x0, 0x42, 0x0, 0x0, 0x0, | ||||
|         0x49, 0x0, 0x0, 0x0, 0x48, 0x0, 0x0, 0x0, 0x48, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, | ||||
|         0x2, 0x0, 0x0, 0x0, 0x3E, 0x0, 0x3, 0x0, 0x44, 0x0, | ||||
|         0x0, 0x0, 0x49, 0x0, 0x0, 0x0, 0x41, 0x0, 0x5, 0x0, | ||||
|         0x7, 0x0, 0x0, 0x0, 0x4E, 0x0, 0x0, 0x0, 0x44, 0x0, | ||||
|         0x0, 0x0, 0x4D, 0x0, 0x0, 0x0, 0x3D, 0x0, 0x4, 0x0, | ||||
|         0x6, 0x0, 0x0, 0x0, 0x4F, 0x0, 0x0, 0x0, 0x4E, 0x0, | ||||
|         0x0, 0x0, 0x3E, 0x0, 0x3, 0x0, 0x4B, 0x0, 0x0, 0x0, | ||||
|         0x4F, 0x0, 0x0, 0x0, 0x41, 0x0, 0x5, 0x0, 0x7, 0x0, | ||||
|         0x0, 0x0, 0x52, 0x0, 0x0, 0x0, 0x44, 0x0, 0x0, 0x0, | ||||
|         0x51, 0x0, 0x0, 0x0, 0x3D, 0x0, 0x4, 0x0, 0x6, 0x0, | ||||
|         0x0, 0x0, 0x53, 0x0, 0x0, 0x0, 0x52, 0x0, 0x0, 0x0, | ||||
|         0x3E, 0x0, 0x3, 0x0, 0x50, 0x0, 0x0, 0x0, 0x53, 0x0, | ||||
|         0x0, 0x0, 0x41, 0x0, 0x5, 0x0, 0x7, 0x0, 0x0, 0x0, | ||||
|         0x56, 0x0, 0x0, 0x0, 0x44, 0x0, 0x0, 0x0, 0x55, 0x0, | ||||
|         0x0, 0x0, 0x3D, 0x0, 0x4, 0x0, 0x6, 0x0, 0x0, 0x0, | ||||
|         0x57, 0x0, 0x0, 0x0, 0x56, 0x0, 0x0, 0x0, 0x3E, 0x0, | ||||
|         0x3, 0x0, 0x54, 0x0, 0x0, 0x0, 0x57, 0x0, 0x0, 0x0, | ||||
|         0x39, 0x0, 0x7, 0x0, 0x6, 0x0, 0x0, 0x0, 0x58, 0x0, | ||||
|         0x0, 0x0, 0xC, 0x0, 0x0, 0x0, 0x4B, 0x0, 0x0, 0x0, | ||||
|         0x50, 0x0, 0x0, 0x0, 0x54, 0x0, 0x0, 0x0, 0x3E, 0x0, | ||||
|         0x3, 0x0, 0x4A, 0x0, 0x0, 0x0, 0x58, 0x0, 0x0, 0x0, | ||||
|         0x39, 0x0, 0x4, 0x0, 0x6, 0x0, 0x0, 0x0, 0x5A, 0x0, | ||||
|         0x0, 0x0, 0xF, 0x0, 0x0, 0x0, 0x3D, 0x0, 0x4, 0x0, | ||||
|         0x6, 0x0, 0x0, 0x0, 0x5B, 0x0, 0x0, 0x0, 0x4A, 0x0, | ||||
|         0x0, 0x0, 0x83, 0x0, 0x5, 0x0, 0x6, 0x0, 0x0, 0x0, | ||||
|         0x5C, 0x0, 0x0, 0x0, 0x5B, 0x0, 0x0, 0x0, 0x3A, 0x0, | ||||
|         0x0, 0x0, 0x85, 0x0, 0x5, 0x0, 0x6, 0x0, 0x0, 0x0, | ||||
|         0x5D, 0x0, 0x0, 0x0, 0x5A, 0x0, 0x0, 0x0, 0x5C, 0x0, | ||||
|         0x0, 0x0, 0x3E, 0x0, 0x3, 0x0, 0x59, 0x0, 0x0, 0x0, | ||||
|         0x5D, 0x0, 0x0, 0x0, 0x3D, 0x0, 0x4, 0x0, 0x6, 0x0, | ||||
|         0x0, 0x0, 0x5F, 0x0, 0x0, 0x0, 0x59, 0x0, 0x0, 0x0, | ||||
|         0x81, 0x0, 0x5, 0x0, 0x6, 0x0, 0x0, 0x0, 0x60, 0x0, | ||||
|         0x0, 0x0, 0x5F, 0x0, 0x0, 0x0, 0x3A, 0x0, 0x0, 0x0, | ||||
|         0xC, 0x0, 0x8, 0x0, 0x6, 0x0, 0x0, 0x0, 0x62, 0x0, | ||||
|         0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x2B, 0x0, 0x0, 0x0, | ||||
|         0x60, 0x0, 0x0, 0x0, 0x61, 0x0, 0x0, 0x0, 0x33, 0x0, | ||||
|         0x0, 0x0, 0x3E, 0x0, 0x3, 0x0, 0x5E, 0x0, 0x0, 0x0, | ||||
|         0x62, 0x0, 0x0, 0x0, 0x3D, 0x0, 0x4, 0x0, 0x47, 0x0, | ||||
|         0x0, 0x0, 0x68, 0x0, 0x0, 0x0, 0x67, 0x0, 0x0, 0x0, | ||||
|         0x3D, 0x0, 0x4, 0x0, 0x6, 0x0, 0x0, 0x0, 0x69, 0x0, | ||||
|         0x0, 0x0, 0x5E, 0x0, 0x0, 0x0, 0x50, 0x0, 0x7, 0x0, | ||||
|         0x47, 0x0, 0x0, 0x0, 0x6A, 0x0, 0x0, 0x0, 0x69, 0x0, | ||||
|         0x0, 0x0, 0x69, 0x0, 0x0, 0x0, 0x69, 0x0, 0x0, 0x0, | ||||
|         0x69, 0x0, 0x0, 0x0, 0xC, 0x0, 0x8, 0x0, 0x47, 0x0, | ||||
|         0x0, 0x0, 0x6B, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, | ||||
|         0x2E, 0x0, 0x0, 0x0, 0x65, 0x0, 0x0, 0x0, 0x68, 0x0, | ||||
|         0x0, 0x0, 0x6A, 0x0, 0x0, 0x0, 0x3E, 0x0, 0x3, 0x0, | ||||
|         0x64, 0x0, 0x0, 0x0, 0x6B, 0x0, 0x0, 0x0, 0xFD, 0x0, | ||||
|         0x1, 0x0, 0x38, 0x0, 0x1, 0x0, 0x36, 0x0, 0x5, 0x0, | ||||
|         0x6, 0x0, 0x0, 0x0, 0xC, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x37, 0x0, 0x3, 0x0, | ||||
|         0x7, 0x0, 0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x37, 0x0, | ||||
|         0x3, 0x0, 0x7, 0x0, 0x0, 0x0, 0xA, 0x0, 0x0, 0x0, | ||||
|         0x37, 0x0, 0x3, 0x0, 0x7, 0x0, 0x0, 0x0, 0xB, 0x0, | ||||
|         0x0, 0x0, 0xF8, 0x0, 0x2, 0x0, 0xD, 0x0, 0x0, 0x0, | ||||
|         0x3D, 0x0, 0x4, 0x0, 0x6, 0x0, 0x0, 0x0, 0x11, 0x0, | ||||
|         0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x3D, 0x0, 0x4, 0x0, | ||||
|         0x6, 0x0, 0x0, 0x0, 0x12, 0x0, 0x0, 0x0, 0xA, 0x0, | ||||
|         0x0, 0x0, 0xC, 0x0, 0x7, 0x0, 0x6, 0x0, 0x0, 0x0, | ||||
|         0x13, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x25, 0x0, | ||||
|         0x0, 0x0, 0x11, 0x0, 0x0, 0x0, 0x12, 0x0, 0x0, 0x0, | ||||
|         0x3D, 0x0, 0x4, 0x0, 0x6, 0x0, 0x0, 0x0, 0x14, 0x0, | ||||
|         0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x3D, 0x0, 0x4, 0x0, | ||||
|         0x6, 0x0, 0x0, 0x0, 0x15, 0x0, 0x0, 0x0, 0xA, 0x0, | ||||
|         0x0, 0x0, 0xC, 0x0, 0x7, 0x0, 0x6, 0x0, 0x0, 0x0, | ||||
|         0x16, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x28, 0x0, | ||||
|         0x0, 0x0, 0x14, 0x0, 0x0, 0x0, 0x15, 0x0, 0x0, 0x0, | ||||
|         0x3D, 0x0, 0x4, 0x0, 0x6, 0x0, 0x0, 0x0, 0x17, 0x0, | ||||
|         0x0, 0x0, 0xB, 0x0, 0x0, 0x0, 0xC, 0x0, 0x7, 0x0, | ||||
|         0x6, 0x0, 0x0, 0x0, 0x18, 0x0, 0x0, 0x0, 0x1, 0x0, | ||||
|         0x0, 0x0, 0x25, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, | ||||
|         0x17, 0x0, 0x0, 0x0, 0xC, 0x0, 0x7, 0x0, 0x6, 0x0, | ||||
|         0x0, 0x0, 0x19, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, | ||||
|         0x28, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x18, 0x0, | ||||
|         0x0, 0x0, 0xFE, 0x0, 0x2, 0x0, 0x19, 0x0, 0x0, 0x0, | ||||
|         0x38, 0x0, 0x1, 0x0, 0x36, 0x0, 0x5, 0x0, 0x6, 0x0, | ||||
|         0x0, 0x0, 0xF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0xE, 0x0, 0x0, 0x0, 0xF8, 0x0, 0x2, 0x0, 0x10, 0x0, | ||||
|         0x0, 0x0, 0x3B, 0x0, 0x4, 0x0, 0x1D, 0x0, 0x0, 0x0, | ||||
|         0x1E, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x3B, 0x0, | ||||
|         0x4, 0x0, 0x1D, 0x0, 0x0, 0x0, 0x32, 0x0, 0x0, 0x0, | ||||
|         0x7, 0x0, 0x0, 0x0, 0x41, 0x0, 0x5, 0x0, 0x24, 0x0, | ||||
|         0x0, 0x0, 0x25, 0x0, 0x0, 0x0, 0x21, 0x0, 0x0, 0x0, | ||||
|         0x23, 0x0, 0x0, 0x0, 0x3D, 0x0, 0x4, 0x0, 0x6, 0x0, | ||||
|         0x0, 0x0, 0x26, 0x0, 0x0, 0x0, 0x25, 0x0, 0x0, 0x0, | ||||
|         0x50, 0x0, 0x5, 0x0, 0x1C, 0x0, 0x0, 0x0, 0x27, 0x0, | ||||
|         0x0, 0x0, 0x26, 0x0, 0x0, 0x0, 0x26, 0x0, 0x0, 0x0, | ||||
|         0x3D, 0x0, 0x4, 0x0, 0x29, 0x0, 0x0, 0x0, 0x2C, 0x0, | ||||
|         0x0, 0x0, 0x2B, 0x0, 0x0, 0x0, 0x64, 0x0, 0x4, 0x0, | ||||
|         0x28, 0x0, 0x0, 0x0, 0x2D, 0x0, 0x0, 0x0, 0x2C, 0x0, | ||||
|         0x0, 0x0, 0x67, 0x0, 0x5, 0x0, 0x2E, 0x0, 0x0, 0x0, | ||||
|         0x2F, 0x0, 0x0, 0x0, 0x2D, 0x0, 0x0, 0x0, 0x23, 0x0, | ||||
|         0x0, 0x0, 0x6F, 0x0, 0x4, 0x0, 0x1C, 0x0, 0x0, 0x0, | ||||
|         0x30, 0x0, 0x0, 0x0, 0x2F, 0x0, 0x0, 0x0, 0x88, 0x0, | ||||
|         0x5, 0x0, 0x1C, 0x0, 0x0, 0x0, 0x31, 0x0, 0x0, 0x0, | ||||
|         0x27, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x3E, 0x0, | ||||
|         0x3, 0x0, 0x1E, 0x0, 0x0, 0x0, 0x31, 0x0, 0x0, 0x0, | ||||
|         0x3D, 0x0, 0x4, 0x0, 0x1C, 0x0, 0x0, 0x0, 0x37, 0x0, | ||||
|         0x0, 0x0, 0x36, 0x0, 0x0, 0x0, 0xD1, 0x0, 0x4, 0x0, | ||||
|         0x1C, 0x0, 0x0, 0x0, 0x38, 0x0, 0x0, 0x0, 0x37, 0x0, | ||||
|         0x0, 0x0, 0x88, 0x0, 0x5, 0x0, 0x1C, 0x0, 0x0, 0x0, | ||||
|         0x39, 0x0, 0x0, 0x0, 0x34, 0x0, 0x0, 0x0, 0x38, 0x0, | ||||
|         0x0, 0x0, 0x3E, 0x0, 0x3, 0x0, 0x32, 0x0, 0x0, 0x0, | ||||
|         0x39, 0x0, 0x0, 0x0, 0x3D, 0x0, 0x4, 0x0, 0x1C, 0x0, | ||||
|         0x0, 0x0, 0x3B, 0x0, 0x0, 0x0, 0x1E, 0x0, 0x0, 0x0, | ||||
|         0x3D, 0x0, 0x4, 0x0, 0x1C, 0x0, 0x0, 0x0, 0x3C, 0x0, | ||||
|         0x0, 0x0, 0x32, 0x0, 0x0, 0x0, 0x94, 0x0, 0x5, 0x0, | ||||
|         0x6, 0x0, 0x0, 0x0, 0x3D, 0x0, 0x0, 0x0, 0x3B, 0x0, | ||||
|         0x0, 0x0, 0x3C, 0x0, 0x0, 0x0, 0x85, 0x0, 0x5, 0x0, | ||||
|         0x6, 0x0, 0x0, 0x0, 0x3E, 0x0, 0x0, 0x0, 0x3A, 0x0, | ||||
|         0x0, 0x0, 0x3D, 0x0, 0x0, 0x0, 0xC, 0x0, 0x7, 0x0, | ||||
|         0x6, 0x0, 0x0, 0x0, 0x3F, 0x0, 0x0, 0x0, 0x1, 0x0, | ||||
|         0x0, 0x0, 0x28, 0x0, 0x0, 0x0, 0x3E, 0x0, 0x0, 0x0, | ||||
|         0x33, 0x0, 0x0, 0x0, 0xFE, 0x0, 0x2, 0x0, 0x3F, 0x0, | ||||
|         0x0, 0x0, 0x38, 0x0, 0x1, 0x0, | ||||
|     ]; | ||||
| 
 | ||||
|     public byte[] TextTransformVert { get; } = | ||||
|     [ | ||||
|         0x3, 0x2, 0x23, 0x7, 0x0, 0x0, 0x1, 0x0, 0xB, 0x0, | ||||
|         0x8, 0x0, 0x2D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x11, 0x0, 0x2, 0x0, 0x1, 0x0, 0x0, 0x0, 0xB, 0x0, | ||||
|         0x6, 0x0, 0x1, 0x0, 0x0, 0x0, 0x47, 0x4C, 0x53, 0x4C, | ||||
|         0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, 0x0, 0x0, | ||||
|         0x0, 0x0, 0xE, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x1, 0x0, 0x0, 0x0, 0xF, 0x0, 0xB, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x6D, 0x61, 0x69, 0x6E, | ||||
|         0x0, 0x0, 0x0, 0x0, 0xD, 0x0, 0x0, 0x0, 0x19, 0x0, | ||||
|         0x0, 0x0, 0x25, 0x0, 0x0, 0x0, 0x27, 0x0, 0x0, 0x0, | ||||
|         0x29, 0x0, 0x0, 0x0, 0x2B, 0x0, 0x0, 0x0, 0x3, 0x0, | ||||
|         0x3, 0x0, 0x2, 0x0, 0x0, 0x0, 0xC2, 0x1, 0x0, 0x0, | ||||
|         0x5, 0x0, 0x4, 0x0, 0x4, 0x0, 0x0, 0x0, 0x6D, 0x61, | ||||
|         0x69, 0x6E, 0x0, 0x0, 0x0, 0x0, 0x5, 0x0, 0x6, 0x0, | ||||
|         0xB, 0x0, 0x0, 0x0, 0x67, 0x6C, 0x5F, 0x50, 0x65, 0x72, | ||||
|         0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x6, 0x0, 0x6, 0x0, 0xB, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x67, 0x6C, 0x5F, 0x50, 0x6F, 0x73, 0x69, 0x74, | ||||
|         0x69, 0x6F, 0x6E, 0x0, 0x6, 0x0, 0x7, 0x0, 0xB, 0x0, | ||||
|         0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x67, 0x6C, 0x5F, 0x50, | ||||
|         0x6F, 0x69, 0x6E, 0x74, 0x53, 0x69, 0x7A, 0x65, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x6, 0x0, 0x7, 0x0, 0xB, 0x0, 0x0, 0x0, | ||||
|         0x2, 0x0, 0x0, 0x0, 0x67, 0x6C, 0x5F, 0x43, 0x6C, 0x69, | ||||
|         0x70, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x0, | ||||
|         0x6, 0x0, 0x7, 0x0, 0xB, 0x0, 0x0, 0x0, 0x3, 0x0, | ||||
|         0x0, 0x0, 0x67, 0x6C, 0x5F, 0x43, 0x75, 0x6C, 0x6C, 0x44, | ||||
|         0x69, 0x73, 0x74, 0x61, 0x6E, 0x63, 0x65, 0x0, 0x5, 0x0, | ||||
|         0x3, 0x0, 0xD, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x5, 0x0, 0x3, 0x0, 0x11, 0x0, 0x0, 0x0, 0x55, 0x42, | ||||
|         0x4F, 0x0, 0x6, 0x0, 0x7, 0x0, 0x11, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, | ||||
|         0x6F, 0x6A, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x0, 0x0, | ||||
|         0x5, 0x0, 0x3, 0x0, 0x13, 0x0, 0x0, 0x0, 0x75, 0x62, | ||||
|         0x6F, 0x0, 0x5, 0x0, 0x4, 0x0, 0x19, 0x0, 0x0, 0x0, | ||||
|         0x69, 0x6E, 0x50, 0x6F, 0x73, 0x0, 0x0, 0x0, 0x5, 0x0, | ||||
|         0x5, 0x0, 0x25, 0x0, 0x0, 0x0, 0x6F, 0x75, 0x74, 0x54, | ||||
|         0x65, 0x78, 0x43, 0x6F, 0x6F, 0x72, 0x64, 0x0, 0x5, 0x0, | ||||
|         0x5, 0x0, 0x27, 0x0, 0x0, 0x0, 0x69, 0x6E, 0x54, 0x65, | ||||
|         0x78, 0x43, 0x6F, 0x6F, 0x72, 0x64, 0x0, 0x0, 0x5, 0x0, | ||||
|         0x5, 0x0, 0x29, 0x0, 0x0, 0x0, 0x6F, 0x75, 0x74, 0x43, | ||||
|         0x6F, 0x6C, 0x6F, 0x72, 0x0, 0x0, 0x0, 0x0, 0x5, 0x0, | ||||
|         0x4, 0x0, 0x2B, 0x0, 0x0, 0x0, 0x69, 0x6E, 0x43, 0x6F, | ||||
|         0x6C, 0x6F, 0x72, 0x0, 0x48, 0x0, 0x5, 0x0, 0xB, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xB, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x48, 0x0, 0x5, 0x0, 0xB, 0x0, | ||||
|         0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0xB, 0x0, 0x0, 0x0, | ||||
|         0x1, 0x0, 0x0, 0x0, 0x48, 0x0, 0x5, 0x0, 0xB, 0x0, | ||||
|         0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0xB, 0x0, 0x0, 0x0, | ||||
|         0x3, 0x0, 0x0, 0x0, 0x48, 0x0, 0x5, 0x0, 0xB, 0x0, | ||||
|         0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0xB, 0x0, 0x0, 0x0, | ||||
|         0x4, 0x0, 0x0, 0x0, 0x47, 0x0, 0x3, 0x0, 0xB, 0x0, | ||||
|         0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x48, 0x0, 0x4, 0x0, | ||||
|         0x11, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0x0, | ||||
|         0x0, 0x0, 0x48, 0x0, 0x5, 0x0, 0x11, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x23, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x48, 0x0, 0x5, 0x0, 0x11, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x10, 0x0, | ||||
|         0x0, 0x0, 0x47, 0x0, 0x3, 0x0, 0x11, 0x0, 0x0, 0x0, | ||||
|         0x2, 0x0, 0x0, 0x0, 0x47, 0x0, 0x4, 0x0, 0x13, 0x0, | ||||
|         0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, | ||||
|         0x47, 0x0, 0x4, 0x0, 0x13, 0x0, 0x0, 0x0, 0x21, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x47, 0x0, 0x4, 0x0, | ||||
|         0x19, 0x0, 0x0, 0x0, 0x1E, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x47, 0x0, 0x4, 0x0, 0x25, 0x0, 0x0, 0x0, | ||||
|         0x1E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x47, 0x0, | ||||
|         0x4, 0x0, 0x27, 0x0, 0x0, 0x0, 0x1E, 0x0, 0x0, 0x0, | ||||
|         0x1, 0x0, 0x0, 0x0, 0x47, 0x0, 0x4, 0x0, 0x29, 0x0, | ||||
|         0x0, 0x0, 0x1E, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, | ||||
|         0x47, 0x0, 0x4, 0x0, 0x2B, 0x0, 0x0, 0x0, 0x1E, 0x0, | ||||
|         0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x13, 0x0, 0x2, 0x0, | ||||
|         0x2, 0x0, 0x0, 0x0, 0x21, 0x0, 0x3, 0x0, 0x3, 0x0, | ||||
|         0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x16, 0x0, 0x3, 0x0, | ||||
|         0x6, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x17, 0x0, | ||||
|         0x4, 0x0, 0x7, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, | ||||
|         0x4, 0x0, 0x0, 0x0, 0x15, 0x0, 0x4, 0x0, 0x8, 0x0, | ||||
|         0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x2B, 0x0, 0x4, 0x0, 0x8, 0x0, 0x0, 0x0, 0x9, 0x0, | ||||
|         0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1C, 0x0, 0x4, 0x0, | ||||
|         0xA, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x9, 0x0, | ||||
|         0x0, 0x0, 0x1E, 0x0, 0x6, 0x0, 0xB, 0x0, 0x0, 0x0, | ||||
|         0x7, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0xA, 0x0, | ||||
|         0x0, 0x0, 0xA, 0x0, 0x0, 0x0, 0x20, 0x0, 0x4, 0x0, | ||||
|         0xC, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0xB, 0x0, | ||||
|         0x0, 0x0, 0x3B, 0x0, 0x4, 0x0, 0xC, 0x0, 0x0, 0x0, | ||||
|         0xD, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x15, 0x0, | ||||
|         0x4, 0x0, 0xE, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, | ||||
|         0x1, 0x0, 0x0, 0x0, 0x2B, 0x0, 0x4, 0x0, 0xE, 0x0, | ||||
|         0x0, 0x0, 0xF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x18, 0x0, 0x4, 0x0, 0x10, 0x0, 0x0, 0x0, 0x7, 0x0, | ||||
|         0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x1E, 0x0, 0x3, 0x0, | ||||
|         0x11, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x20, 0x0, | ||||
|         0x4, 0x0, 0x12, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, | ||||
|         0x11, 0x0, 0x0, 0x0, 0x3B, 0x0, 0x4, 0x0, 0x12, 0x0, | ||||
|         0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, | ||||
|         0x20, 0x0, 0x4, 0x0, 0x14, 0x0, 0x0, 0x0, 0x2, 0x0, | ||||
|         0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x17, 0x0, 0x4, 0x0, | ||||
|         0x17, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x3, 0x0, | ||||
|         0x0, 0x0, 0x20, 0x0, 0x4, 0x0, 0x18, 0x0, 0x0, 0x0, | ||||
|         0x1, 0x0, 0x0, 0x0, 0x17, 0x0, 0x0, 0x0, 0x3B, 0x0, | ||||
|         0x4, 0x0, 0x18, 0x0, 0x0, 0x0, 0x19, 0x0, 0x0, 0x0, | ||||
|         0x1, 0x0, 0x0, 0x0, 0x2B, 0x0, 0x4, 0x0, 0x6, 0x0, | ||||
|         0x0, 0x0, 0x1B, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3F, | ||||
|         0x20, 0x0, 0x4, 0x0, 0x21, 0x0, 0x0, 0x0, 0x3, 0x0, | ||||
|         0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x17, 0x0, 0x4, 0x0, | ||||
|         0x23, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x2, 0x0, | ||||
|         0x0, 0x0, 0x20, 0x0, 0x4, 0x0, 0x24, 0x0, 0x0, 0x0, | ||||
|         0x3, 0x0, 0x0, 0x0, 0x23, 0x0, 0x0, 0x0, 0x3B, 0x0, | ||||
|         0x4, 0x0, 0x24, 0x0, 0x0, 0x0, 0x25, 0x0, 0x0, 0x0, | ||||
|         0x3, 0x0, 0x0, 0x0, 0x20, 0x0, 0x4, 0x0, 0x26, 0x0, | ||||
|         0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x23, 0x0, 0x0, 0x0, | ||||
|         0x3B, 0x0, 0x4, 0x0, 0x26, 0x0, 0x0, 0x0, 0x27, 0x0, | ||||
|         0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x3B, 0x0, 0x4, 0x0, | ||||
|         0x21, 0x0, 0x0, 0x0, 0x29, 0x0, 0x0, 0x0, 0x3, 0x0, | ||||
|         0x0, 0x0, 0x20, 0x0, 0x4, 0x0, 0x2A, 0x0, 0x0, 0x0, | ||||
|         0x1, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x3B, 0x0, | ||||
|         0x4, 0x0, 0x2A, 0x0, 0x0, 0x0, 0x2B, 0x0, 0x0, 0x0, | ||||
|         0x1, 0x0, 0x0, 0x0, 0x36, 0x0, 0x5, 0x0, 0x2, 0x0, | ||||
|         0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x3, 0x0, 0x0, 0x0, 0xF8, 0x0, 0x2, 0x0, 0x5, 0x0, | ||||
|         0x0, 0x0, 0x41, 0x0, 0x5, 0x0, 0x14, 0x0, 0x0, 0x0, | ||||
|         0x15, 0x0, 0x0, 0x0, 0x13, 0x0, 0x0, 0x0, 0xF, 0x0, | ||||
|         0x0, 0x0, 0x3D, 0x0, 0x4, 0x0, 0x10, 0x0, 0x0, 0x0, | ||||
|         0x16, 0x0, 0x0, 0x0, 0x15, 0x0, 0x0, 0x0, 0x3D, 0x0, | ||||
|         0x4, 0x0, 0x17, 0x0, 0x0, 0x0, 0x1A, 0x0, 0x0, 0x0, | ||||
|         0x19, 0x0, 0x0, 0x0, 0x51, 0x0, 0x5, 0x0, 0x6, 0x0, | ||||
|         0x0, 0x0, 0x1C, 0x0, 0x0, 0x0, 0x1A, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x51, 0x0, 0x5, 0x0, 0x6, 0x0, | ||||
|         0x0, 0x0, 0x1D, 0x0, 0x0, 0x0, 0x1A, 0x0, 0x0, 0x0, | ||||
|         0x1, 0x0, 0x0, 0x0, 0x51, 0x0, 0x5, 0x0, 0x6, 0x0, | ||||
|         0x0, 0x0, 0x1E, 0x0, 0x0, 0x0, 0x1A, 0x0, 0x0, 0x0, | ||||
|         0x2, 0x0, 0x0, 0x0, 0x50, 0x0, 0x7, 0x0, 0x7, 0x0, | ||||
|         0x0, 0x0, 0x1F, 0x0, 0x0, 0x0, 0x1C, 0x0, 0x0, 0x0, | ||||
|         0x1D, 0x0, 0x0, 0x0, 0x1E, 0x0, 0x0, 0x0, 0x1B, 0x0, | ||||
|         0x0, 0x0, 0x91, 0x0, 0x5, 0x0, 0x7, 0x0, 0x0, 0x0, | ||||
|         0x20, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0x1F, 0x0, | ||||
|         0x0, 0x0, 0x41, 0x0, 0x5, 0x0, 0x21, 0x0, 0x0, 0x0, | ||||
|         0x22, 0x0, 0x0, 0x0, 0xD, 0x0, 0x0, 0x0, 0xF, 0x0, | ||||
|         0x0, 0x0, 0x3E, 0x0, 0x3, 0x0, 0x22, 0x0, 0x0, 0x0, | ||||
|         0x20, 0x0, 0x0, 0x0, 0x3D, 0x0, 0x4, 0x0, 0x23, 0x0, | ||||
|         0x0, 0x0, 0x28, 0x0, 0x0, 0x0, 0x27, 0x0, 0x0, 0x0, | ||||
|         0x3E, 0x0, 0x3, 0x0, 0x25, 0x0, 0x0, 0x0, 0x28, 0x0, | ||||
|         0x0, 0x0, 0x3D, 0x0, 0x4, 0x0, 0x7, 0x0, 0x0, 0x0, | ||||
|         0x2C, 0x0, 0x0, 0x0, 0x2B, 0x0, 0x0, 0x0, 0x3E, 0x0, | ||||
|         0x3, 0x0, 0x29, 0x0, 0x0, 0x0, 0x2C, 0x0, 0x0, 0x0, | ||||
|         0xFD, 0x0, 0x1, 0x0, 0x38, 0x0, 0x1, 0x0, | ||||
|     ]; | ||||
| 
 | ||||
|     public byte[] VideoYuv2RgbaFrag { get; } = | ||||
|     [ | ||||
|         0x3, 0x2, 0x23, 0x7, 0x0, 0x0, 0x1, 0x0, 0xB, 0x0, | ||||
|         0x8, 0x0, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x11, 0x0, 0x2, 0x0, 0x1, 0x0, 0x0, 0x0, 0xB, 0x0, | ||||
|         0x6, 0x0, 0x1, 0x0, 0x0, 0x0, 0x47, 0x4C, 0x53, 0x4C, | ||||
|         0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, 0x0, 0x0, | ||||
|         0x0, 0x0, 0xE, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x1, 0x0, 0x0, 0x0, 0xF, 0x0, 0x7, 0x0, 0x4, 0x0, | ||||
|         0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x6D, 0x61, 0x69, 0x6E, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x11, 0x0, 0x0, 0x0, 0x2E, 0x0, | ||||
|         0x0, 0x0, 0x10, 0x0, 0x3, 0x0, 0x4, 0x0, 0x0, 0x0, | ||||
|         0x7, 0x0, 0x0, 0x0, 0x3, 0x0, 0x3, 0x0, 0x2, 0x0, | ||||
|         0x0, 0x0, 0xC2, 0x1, 0x0, 0x0, 0x5, 0x0, 0x4, 0x0, | ||||
|         0x4, 0x0, 0x0, 0x0, 0x6D, 0x61, 0x69, 0x6E, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x5, 0x0, 0x3, 0x0, 0x9, 0x0, 0x0, 0x0, | ||||
|         0x79, 0x75, 0x76, 0x0, 0x5, 0x0, 0x5, 0x0, 0xD, 0x0, | ||||
|         0x0, 0x0, 0x59, 0x53, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x5, 0x0, 0x5, 0x0, 0x11, 0x0, | ||||
|         0x0, 0x0, 0x54, 0x65, 0x78, 0x43, 0x6F, 0x6F, 0x72, 0x64, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x5, 0x0, 0x5, 0x0, 0x1A, 0x0, | ||||
|         0x0, 0x0, 0x55, 0x53, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x5, 0x0, 0x5, 0x0, 0x21, 0x0, | ||||
|         0x0, 0x0, 0x56, 0x53, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x5, 0x0, 0x5, 0x0, 0x2E, 0x0, | ||||
|         0x0, 0x0, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6F, 0x6C, 0x6F, | ||||
|         0x72, 0x0, 0x0, 0x0, 0x47, 0x0, 0x4, 0x0, 0xD, 0x0, | ||||
|         0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, | ||||
|         0x47, 0x0, 0x4, 0x0, 0xD, 0x0, 0x0, 0x0, 0x21, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x47, 0x0, 0x4, 0x0, | ||||
|         0x11, 0x0, 0x0, 0x0, 0x1E, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x47, 0x0, 0x4, 0x0, 0x1A, 0x0, 0x0, 0x0, | ||||
|         0x22, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x47, 0x0, | ||||
|         0x4, 0x0, 0x1A, 0x0, 0x0, 0x0, 0x21, 0x0, 0x0, 0x0, | ||||
|         0x1, 0x0, 0x0, 0x0, 0x47, 0x0, 0x4, 0x0, 0x21, 0x0, | ||||
|         0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, | ||||
|         0x47, 0x0, 0x4, 0x0, 0x21, 0x0, 0x0, 0x0, 0x21, 0x0, | ||||
|         0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x47, 0x0, 0x4, 0x0, | ||||
|         0x2E, 0x0, 0x0, 0x0, 0x1E, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x13, 0x0, 0x2, 0x0, 0x2, 0x0, 0x0, 0x0, | ||||
|         0x21, 0x0, 0x3, 0x0, 0x3, 0x0, 0x0, 0x0, 0x2, 0x0, | ||||
|         0x0, 0x0, 0x16, 0x0, 0x3, 0x0, 0x6, 0x0, 0x0, 0x0, | ||||
|         0x20, 0x0, 0x0, 0x0, 0x17, 0x0, 0x4, 0x0, 0x7, 0x0, | ||||
|         0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, | ||||
|         0x20, 0x0, 0x4, 0x0, 0x8, 0x0, 0x0, 0x0, 0x7, 0x0, | ||||
|         0x0, 0x0, 0x7, 0x0, 0x0, 0x0, 0x19, 0x0, 0x9, 0x0, | ||||
|         0xA, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x1, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x1B, 0x0, 0x3, 0x0, 0xB, 0x0, 0x0, 0x0, | ||||
|         0xA, 0x0, 0x0, 0x0, 0x20, 0x0, 0x4, 0x0, 0xC, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xB, 0x0, 0x0, 0x0, | ||||
|         0x3B, 0x0, 0x4, 0x0, 0xC, 0x0, 0x0, 0x0, 0xD, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x17, 0x0, 0x4, 0x0, | ||||
|         0xF, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x2, 0x0, | ||||
|         0x0, 0x0, 0x20, 0x0, 0x4, 0x0, 0x10, 0x0, 0x0, 0x0, | ||||
|         0x1, 0x0, 0x0, 0x0, 0xF, 0x0, 0x0, 0x0, 0x3B, 0x0, | ||||
|         0x4, 0x0, 0x10, 0x0, 0x0, 0x0, 0x11, 0x0, 0x0, 0x0, | ||||
|         0x1, 0x0, 0x0, 0x0, 0x17, 0x0, 0x4, 0x0, 0x13, 0x0, | ||||
|         0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, | ||||
|         0x15, 0x0, 0x4, 0x0, 0x15, 0x0, 0x0, 0x0, 0x20, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2B, 0x0, 0x4, 0x0, | ||||
|         0x15, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x20, 0x0, 0x4, 0x0, 0x18, 0x0, 0x0, 0x0, | ||||
|         0x7, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x3B, 0x0, | ||||
|         0x4, 0x0, 0xC, 0x0, 0x0, 0x0, 0x1A, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x2B, 0x0, 0x4, 0x0, 0x15, 0x0, | ||||
|         0x0, 0x0, 0x1F, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, | ||||
|         0x3B, 0x0, 0x4, 0x0, 0xC, 0x0, 0x0, 0x0, 0x21, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2B, 0x0, 0x4, 0x0, | ||||
|         0x15, 0x0, 0x0, 0x0, 0x26, 0x0, 0x0, 0x0, 0x2, 0x0, | ||||
|         0x0, 0x0, 0x2B, 0x0, 0x4, 0x0, 0x6, 0x0, 0x0, 0x0, | ||||
|         0x28, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0xBD, 0x2B, 0x0, | ||||
|         0x4, 0x0, 0x6, 0x0, 0x0, 0x0, 0x29, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x0, 0xBF, 0x2C, 0x0, 0x6, 0x0, 0x7, 0x0, | ||||
|         0x0, 0x0, 0x2A, 0x0, 0x0, 0x0, 0x28, 0x0, 0x0, 0x0, | ||||
|         0x29, 0x0, 0x0, 0x0, 0x29, 0x0, 0x0, 0x0, 0x20, 0x0, | ||||
|         0x4, 0x0, 0x2D, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, | ||||
|         0x13, 0x0, 0x0, 0x0, 0x3B, 0x0, 0x4, 0x0, 0x2D, 0x0, | ||||
|         0x0, 0x0, 0x2E, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, | ||||
|         0x2B, 0x0, 0x4, 0x0, 0x6, 0x0, 0x0, 0x0, 0x30, 0x0, | ||||
|         0x0, 0x0, 0xF4, 0xFD, 0x94, 0x3F, 0x2B, 0x0, 0x4, 0x0, | ||||
|         0x6, 0x0, 0x0, 0x0, 0x31, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x2B, 0x0, 0x4, 0x0, 0x6, 0x0, 0x0, 0x0, | ||||
|         0x32, 0x0, 0x0, 0x0, 0x6, 0x81, 0xE5, 0x3F, 0x2C, 0x0, | ||||
|         0x6, 0x0, 0x7, 0x0, 0x0, 0x0, 0x33, 0x0, 0x0, 0x0, | ||||
|         0x30, 0x0, 0x0, 0x0, 0x31, 0x0, 0x0, 0x0, 0x32, 0x0, | ||||
|         0x0, 0x0, 0x20, 0x0, 0x4, 0x0, 0x35, 0x0, 0x0, 0x0, | ||||
|         0x3, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x2B, 0x0, | ||||
|         0x4, 0x0, 0x6, 0x0, 0x0, 0x0, 0x38, 0x0, 0x0, 0x0, | ||||
|         0xAC, 0x1C, 0x5A, 0xBE, 0x2B, 0x0, 0x4, 0x0, 0x6, 0x0, | ||||
|         0x0, 0x0, 0x39, 0x0, 0x0, 0x0, 0xB0, 0x72, 0x8, 0xBF, | ||||
|         0x2C, 0x0, 0x6, 0x0, 0x7, 0x0, 0x0, 0x0, 0x3A, 0x0, | ||||
|         0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x38, 0x0, 0x0, 0x0, | ||||
|         0x39, 0x0, 0x0, 0x0, 0x2B, 0x0, 0x4, 0x0, 0x6, 0x0, | ||||
|         0x0, 0x0, 0x3E, 0x0, 0x0, 0x0, 0x2, 0x2B, 0x7, 0x40, | ||||
|         0x2C, 0x0, 0x6, 0x0, 0x7, 0x0, 0x0, 0x0, 0x3F, 0x0, | ||||
|         0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x3E, 0x0, 0x0, 0x0, | ||||
|         0x31, 0x0, 0x0, 0x0, 0x2B, 0x0, 0x4, 0x0, 0x6, 0x0, | ||||
|         0x0, 0x0, 0x42, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x3F, | ||||
|         0x2B, 0x0, 0x4, 0x0, 0x15, 0x0, 0x0, 0x0, 0x43, 0x0, | ||||
|         0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x36, 0x0, 0x5, 0x0, | ||||
|         0x2, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0xF8, 0x0, 0x2, 0x0, | ||||
|         0x5, 0x0, 0x0, 0x0, 0x3B, 0x0, 0x4, 0x0, 0x8, 0x0, | ||||
|         0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0, | ||||
|         0x3D, 0x0, 0x4, 0x0, 0xB, 0x0, 0x0, 0x0, 0xE, 0x0, | ||||
|         0x0, 0x0, 0xD, 0x0, 0x0, 0x0, 0x3D, 0x0, 0x4, 0x0, | ||||
|         0xF, 0x0, 0x0, 0x0, 0x12, 0x0, 0x0, 0x0, 0x11, 0x0, | ||||
|         0x0, 0x0, 0x57, 0x0, 0x5, 0x0, 0x13, 0x0, 0x0, 0x0, | ||||
|         0x14, 0x0, 0x0, 0x0, 0xE, 0x0, 0x0, 0x0, 0x12, 0x0, | ||||
|         0x0, 0x0, 0x51, 0x0, 0x5, 0x0, 0x6, 0x0, 0x0, 0x0, | ||||
|         0x17, 0x0, 0x0, 0x0, 0x14, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x0, 0x0, 0x41, 0x0, 0x5, 0x0, 0x18, 0x0, 0x0, 0x0, | ||||
|         0x19, 0x0, 0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x16, 0x0, | ||||
|         0x0, 0x0, 0x3E, 0x0, 0x3, 0x0, 0x19, 0x0, 0x0, 0x0, | ||||
|         0x17, 0x0, 0x0, 0x0, 0x3D, 0x0, 0x4, 0x0, 0xB, 0x0, | ||||
|         0x0, 0x0, 0x1B, 0x0, 0x0, 0x0, 0x1A, 0x0, 0x0, 0x0, | ||||
|         0x3D, 0x0, 0x4, 0x0, 0xF, 0x0, 0x0, 0x0, 0x1C, 0x0, | ||||
|         0x0, 0x0, 0x11, 0x0, 0x0, 0x0, 0x57, 0x0, 0x5, 0x0, | ||||
|         0x13, 0x0, 0x0, 0x0, 0x1D, 0x0, 0x0, 0x0, 0x1B, 0x0, | ||||
|         0x0, 0x0, 0x1C, 0x0, 0x0, 0x0, 0x51, 0x0, 0x5, 0x0, | ||||
|         0x6, 0x0, 0x0, 0x0, 0x1E, 0x0, 0x0, 0x0, 0x1D, 0x0, | ||||
|         0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x41, 0x0, 0x5, 0x0, | ||||
|         0x18, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x9, 0x0, | ||||
|         0x0, 0x0, 0x1F, 0x0, 0x0, 0x0, 0x3E, 0x0, 0x3, 0x0, | ||||
|         0x20, 0x0, 0x0, 0x0, 0x1E, 0x0, 0x0, 0x0, 0x3D, 0x0, | ||||
|         0x4, 0x0, 0xB, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, | ||||
|         0x21, 0x0, 0x0, 0x0, 0x3D, 0x0, 0x4, 0x0, 0xF, 0x0, | ||||
|         0x0, 0x0, 0x23, 0x0, 0x0, 0x0, 0x11, 0x0, 0x0, 0x0, | ||||
|         0x57, 0x0, 0x5, 0x0, 0x13, 0x0, 0x0, 0x0, 0x24, 0x0, | ||||
|         0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x23, 0x0, 0x0, 0x0, | ||||
|         0x51, 0x0, 0x5, 0x0, 0x6, 0x0, 0x0, 0x0, 0x25, 0x0, | ||||
|         0x0, 0x0, 0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | ||||
|         0x41, 0x0, 0x5, 0x0, 0x18, 0x0, 0x0, 0x0, 0x27, 0x0, | ||||
|         0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x26, 0x0, 0x0, 0x0, | ||||
|         0x3E, 0x0, 0x3, 0x0, 0x27, 0x0, 0x0, 0x0, 0x25, 0x0, | ||||
|         0x0, 0x0, 0x3D, 0x0, 0x4, 0x0, 0x7, 0x0, 0x0, 0x0, | ||||
|         0x2B, 0x0, 0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x81, 0x0, | ||||
|         0x5, 0x0, 0x7, 0x0, 0x0, 0x0, 0x2C, 0x0, 0x0, 0x0, | ||||
|         0x2B, 0x0, 0x0, 0x0, 0x2A, 0x0, 0x0, 0x0, 0x3E, 0x0, | ||||
|         0x3, 0x0, 0x9, 0x0, 0x0, 0x0, 0x2C, 0x0, 0x0, 0x0, | ||||
|         0x3D, 0x0, 0x4, 0x0, 0x7, 0x0, 0x0, 0x0, 0x2F, 0x0, | ||||
|         0x0, 0x0, 0x9, 0x0, 0x0, 0x0, 0x94, 0x0, 0x5, 0x0, | ||||
|         0x6, 0x0, 0x0, 0x0, 0x34, 0x0, 0x0, 0x0, 0x2F, 0x0, | ||||
|         0x0, 0x0, 0x33, 0x0, 0x0, 0x0, 0x41, 0x0, 0x5, 0x0, | ||||
|         0x35, 0x0, 0x0, 0x0, 0x36, 0x0, 0x0, 0x0, 0x2E, 0x0, | ||||
|         0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0x3E, 0x0, 0x3, 0x0, | ||||
|         0x36, 0x0, 0x0, 0x0, 0x34, 0x0, 0x0, 0x0, 0x3D, 0x0, | ||||
|         0x4, 0x0, 0x7, 0x0, 0x0, 0x0, 0x37, 0x0, 0x0, 0x0, | ||||
|         0x9, 0x0, 0x0, 0x0, 0x94, 0x0, 0x5, 0x0, 0x6, 0x0, | ||||
|         0x0, 0x0, 0x3B, 0x0, 0x0, 0x0, 0x37, 0x0, 0x0, 0x0, | ||||
|         0x3A, 0x0, 0x0, 0x0, 0x41, 0x0, 0x5, 0x0, 0x35, 0x0, | ||||
|         0x0, 0x0, 0x3C, 0x0, 0x0, 0x0, 0x2E, 0x0, 0x0, 0x0, | ||||
|         0x1F, 0x0, 0x0, 0x0, 0x3E, 0x0, 0x3, 0x0, 0x3C, 0x0, | ||||
|         0x0, 0x0, 0x3B, 0x0, 0x0, 0x0, 0x3D, 0x0, 0x4, 0x0, | ||||
|         0x7, 0x0, 0x0, 0x0, 0x3D, 0x0, 0x0, 0x0, 0x9, 0x0, | ||||
|         0x0, 0x0, 0x94, 0x0, 0x5, 0x0, 0x6, 0x0, 0x0, 0x0, | ||||
|         0x40, 0x0, 0x0, 0x0, 0x3D, 0x0, 0x0, 0x0, 0x3F, 0x0, | ||||
|         0x0, 0x0, 0x41, 0x0, 0x5, 0x0, 0x35, 0x0, 0x0, 0x0, | ||||
|         0x41, 0x0, 0x0, 0x0, 0x2E, 0x0, 0x0, 0x0, 0x26, 0x0, | ||||
|         0x0, 0x0, 0x3E, 0x0, 0x3, 0x0, 0x41, 0x0, 0x0, 0x0, | ||||
|         0x40, 0x0, 0x0, 0x0, 0x41, 0x0, 0x5, 0x0, 0x35, 0x0, | ||||
|         0x0, 0x0, 0x44, 0x0, 0x0, 0x0, 0x2E, 0x0, 0x0, 0x0, | ||||
|         0x43, 0x0, 0x0, 0x0, 0x3E, 0x0, 0x3, 0x0, 0x44, 0x0, | ||||
|         0x0, 0x0, 0x42, 0x0, 0x0, 0x0, 0xFD, 0x0, 0x1, 0x0, | ||||
|         0x38, 0x0, 0x1, 0x0, | ||||
|     ]; | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| using System.Runtime.InteropServices; | ||||
| using Nerfed.Runtime.Video; | ||||
| using Nerfed.Runtime.Video; | ||||
| using RefreshCS; | ||||
| using System.Runtime.InteropServices; | ||||
| 
 | ||||
| namespace Nerfed.Runtime.Graphics; | ||||
| 
 | ||||
| @@ -13,12 +13,16 @@ public class GraphicsDevice : IDisposable | ||||
|     public BackendFlags Backend { get; } | ||||
|     public bool DebugMode { get; } | ||||
| 
 | ||||
|     // Built-in shaders | ||||
|     public Shader FullscreenVertexShader { get; private set; } | ||||
|     public Shader VideoFragmentShader { get; private set; } | ||||
|     public Shader TextVertexShader { get; private set; } | ||||
|     public Shader TextFragmentShader { get; private set; } | ||||
|      | ||||
|     // Built-in video pipeline | ||||
|     internal GraphicsPipeline VideoPipeline { get; } | ||||
|     internal GraphicsPipeline VideoPipeline { get; private set; } | ||||
| 
 | ||||
|     // Built-in text shader info | ||||
|     public Shader TextVertexShader; | ||||
|     public Shader TextFragmentShader; | ||||
|     public VertexInputState TextVertexInputState { get; } | ||||
| 
 | ||||
|     // Built-in samplers | ||||
| @@ -53,85 +57,21 @@ public class GraphicsDevice : IDisposable | ||||
| 
 | ||||
|         Backend = (BackendFlags)Refresh.Refresh_GetBackend(Handle); | ||||
| 
 | ||||
|         IEmbeddedShaders embeddedShaders; | ||||
|         switch (Backend) | ||||
|         { | ||||
|             case BackendFlags.Vulkan: | ||||
|                 embeddedShaders = new EmbeddedShadersSpirV(); | ||||
|                 break; | ||||
|             case BackendFlags.D3D11: | ||||
|                 throw new NotImplementedException("D3D11 embedded shaders"); | ||||
|                 break; | ||||
|             case BackendFlags.Metal: | ||||
|                 throw new NotImplementedException("Metal embedded shaders"); | ||||
|                 break; | ||||
|             default: throw new ArgumentOutOfRangeException(); | ||||
|         } | ||||
|         TextVertexInputState = VertexInputState.CreateSingleBinding<FontVertex>(); | ||||
| 
 | ||||
|         Shader fullscreenVertShader; | ||||
|         Shader textVertShader; | ||||
|         Shader textFragShader; | ||||
|         Shader videoFragShader; | ||||
|         PointSampler = new Sampler(this, SamplerCreateInfo.PointClamp); | ||||
|         LinearSampler = new Sampler(this, SamplerCreateInfo.LinearClamp); | ||||
| 
 | ||||
|         using (MemoryStream fullscreenVertStream = new MemoryStream(embeddedShaders.FullscreenVert)) | ||||
|         { | ||||
|             fullscreenVertShader = new Shader( | ||||
|                 this, | ||||
|                 fullscreenVertStream, | ||||
|                 "main", | ||||
|                 new ShaderCreateInfo | ||||
|                 { | ||||
|                     ShaderStage = ShaderStage.Vertex, | ||||
|                     ShaderFormat = embeddedShaders.ShaderFormat | ||||
|                 } | ||||
|             ); | ||||
|         } | ||||
|         fencePool = new FencePool(this); | ||||
|         commandBufferPool = new CommandBufferPool(this); | ||||
|     } | ||||
| 
 | ||||
|         using (MemoryStream videoYuv2RgbaFragStream = new MemoryStream(embeddedShaders.VideoYuv2RgbaFrag)) | ||||
|         { | ||||
|             videoFragShader = new Shader( | ||||
|                 this, | ||||
|                 videoYuv2RgbaFragStream, | ||||
|                 "main", | ||||
|                 new ShaderCreateInfo | ||||
|                 { | ||||
|                     ShaderStage = ShaderStage.Fragment, | ||||
|                     ShaderFormat = embeddedShaders.ShaderFormat, | ||||
|                     SamplerCount = 3 | ||||
|                 } | ||||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         using (MemoryStream textTransformVertStream = new MemoryStream(embeddedShaders.TextTransformVert)) | ||||
|         { | ||||
|             textVertShader = new Shader( | ||||
|                 this, | ||||
|                 textTransformVertStream, | ||||
|                 "main", | ||||
|                 new ShaderCreateInfo | ||||
|                 { | ||||
|                     ShaderStage = ShaderStage.Vertex, | ||||
|                     ShaderFormat = embeddedShaders.ShaderFormat, | ||||
|                     UniformBufferCount = 1 | ||||
|                 } | ||||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         using (MemoryStream textMsdfFragStream = new MemoryStream(embeddedShaders.TextMsdfFrag)) | ||||
|         { | ||||
|             textFragShader = new Shader( | ||||
|                 this, | ||||
|                 textMsdfFragStream, | ||||
|                 "main", | ||||
|                 new ShaderCreateInfo | ||||
|                 { | ||||
|                     ShaderStage = ShaderStage.Fragment, | ||||
|                     ShaderFormat = embeddedShaders.ShaderFormat, | ||||
|                     SamplerCount = 1, | ||||
|                     UniformBufferCount = 1 | ||||
|                 } | ||||
|             ); | ||||
|         } | ||||
|     internal void LoadDefaultPipelines() | ||||
|     { | ||||
|         FullscreenVertexShader = ResourceManager.Load<Shader>("Shaders/Fullscreen.vert"); | ||||
|         VideoFragmentShader = ResourceManager.Load<Shader>("Shaders/Video.frag"); | ||||
|         TextVertexShader = ResourceManager.Load<Shader>("Shaders/Text.vert"); | ||||
|         TextFragmentShader = ResourceManager.Load<Shader>("Shaders/Text.frag"); | ||||
| 
 | ||||
|         VideoPipeline = new GraphicsPipeline( | ||||
|             this, | ||||
| @@ -144,25 +84,14 @@ public class GraphicsDevice : IDisposable | ||||
|                     ) | ||||
|                 ), | ||||
|                 DepthStencilState = DepthStencilState.Disable, | ||||
|                 VertexShader = fullscreenVertShader, | ||||
|                 FragmentShader = videoFragShader, | ||||
|                 VertexShader = FullscreenVertexShader, | ||||
|                 FragmentShader = VideoFragmentShader, | ||||
|                 VertexInputState = VertexInputState.Empty, | ||||
|                 RasterizerState = RasterizerState.CCW_CullNone, | ||||
|                 PrimitiveType = PrimitiveType.TriangleList, | ||||
|                 MultisampleState = MultisampleState.None | ||||
|             } | ||||
|         ); | ||||
| 
 | ||||
|         TextVertexShader = textVertShader; | ||||
|         TextFragmentShader = textFragShader; | ||||
| 
 | ||||
|         TextVertexInputState = VertexInputState.CreateSingleBinding<FontVertex>(); | ||||
| 
 | ||||
|         PointSampler = new Sampler(this, SamplerCreateInfo.PointClamp); | ||||
|         LinearSampler = new Sampler(this, SamplerCreateInfo.LinearClamp); | ||||
| 
 | ||||
|         fencePool = new FencePool(this); | ||||
|         commandBufferPool = new CommandBufferPool(this); | ||||
|     } | ||||
| 
 | ||||
|     /// <summary> | ||||
| @@ -443,6 +372,11 @@ public class GraphicsDevice : IDisposable | ||||
| 
 | ||||
|                     resources.Clear(); | ||||
|                 } | ||||
| 
 | ||||
|                 ResourceManager.Unload(FullscreenVertexShader); | ||||
|                 ResourceManager.Unload(TextFragmentShader); | ||||
|                 ResourceManager.Unload(TextVertexShader); | ||||
|                 ResourceManager.Unload(VideoFragmentShader); | ||||
|             } | ||||
| 
 | ||||
|             Refresh.Refresh_DestroyDevice(Handle); | ||||
|   | ||||
| @@ -1,10 +0,0 @@ | ||||
| namespace Nerfed.Runtime.Graphics; | ||||
| 
 | ||||
| internal interface IEmbeddedShaders | ||||
| { | ||||
|     ShaderFormat ShaderFormat { get; } | ||||
|     byte[] FullscreenVert { get; } | ||||
|     byte[] TextMsdfFrag { get; } | ||||
|     byte[] TextTransformVert { get; } | ||||
|     byte[] VideoYuv2RgbaFrag { get; } | ||||
| } | ||||
| @@ -1,91 +0,0 @@ | ||||
| using RefreshCS; | ||||
| using System; | ||||
| using System.IO; | ||||
| using System.Runtime.InteropServices; | ||||
| 
 | ||||
| namespace Nerfed.Runtime.Graphics; | ||||
| 
 | ||||
| /// <summary> | ||||
| /// Shaders are used to create graphics pipelines. | ||||
| /// Graphics pipelines take a vertex shader and a fragment shader. | ||||
| /// </summary> | ||||
| public class Shader : RefreshResource | ||||
| { | ||||
| 	protected override Action<IntPtr, IntPtr> ReleaseFunction => Refresh.Refresh_ReleaseShader; | ||||
| 
 | ||||
| 	public uint SamplerCount { get; } | ||||
| 	public uint StorageTextureCount { get; } | ||||
| 	public uint StorageBufferCount { get; } | ||||
| 	public uint UniformBufferCount { get; } | ||||
| 
 | ||||
| 	public unsafe Shader( | ||||
| 		GraphicsDevice device, | ||||
| 		string filePath, | ||||
| 		string entryPointName, | ||||
| 		in ShaderCreateInfo shaderCreateInfo | ||||
| 	) : base(device) | ||||
| 	{ | ||||
| 		using FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read); | ||||
| 		Handle = CreateFromStream( | ||||
| 			device, | ||||
| 			stream, | ||||
| 			entryPointName, | ||||
| 			shaderCreateInfo | ||||
| 		); | ||||
| 
 | ||||
| 		SamplerCount = shaderCreateInfo.SamplerCount; | ||||
| 		StorageTextureCount = shaderCreateInfo.StorageTextureCount; | ||||
| 		StorageBufferCount = shaderCreateInfo.StorageBufferCount; | ||||
| 		UniformBufferCount = shaderCreateInfo.UniformBufferCount; | ||||
| 	} | ||||
| 
 | ||||
| 	public unsafe Shader( | ||||
| 		GraphicsDevice device, | ||||
| 		Stream stream, | ||||
| 		string entryPointName, | ||||
| 		in ShaderCreateInfo shaderCreateInfo | ||||
| 	) : base(device) | ||||
| 	{ | ||||
| 		Handle = CreateFromStream( | ||||
| 			device, | ||||
| 			stream, | ||||
| 			entryPointName, | ||||
| 			shaderCreateInfo | ||||
| 		); | ||||
| 
 | ||||
| 		SamplerCount = shaderCreateInfo.SamplerCount; | ||||
| 		StorageTextureCount = shaderCreateInfo.StorageTextureCount; | ||||
| 		StorageBufferCount = shaderCreateInfo.StorageBufferCount; | ||||
| 		UniformBufferCount = shaderCreateInfo.UniformBufferCount; | ||||
| 	} | ||||
| 
 | ||||
| 	private static unsafe IntPtr CreateFromStream( | ||||
| 		GraphicsDevice device, | ||||
| 		Stream stream, | ||||
| 		string entryPointName, | ||||
| 		in ShaderCreateInfo shaderCreateInfo | ||||
| 	) { | ||||
| 		void* bytecodeBuffer = NativeMemory.Alloc((nuint) stream.Length); | ||||
| 		Span<byte> bytecodeSpan = new Span<byte>(bytecodeBuffer, (int) stream.Length); | ||||
| 		stream.ReadExactly(bytecodeSpan); | ||||
| 
 | ||||
| 		Refresh.ShaderCreateInfo refreshShaderCreateInfo; | ||||
| 		refreshShaderCreateInfo.CodeSize = (nuint) stream.Length; | ||||
| 		refreshShaderCreateInfo.Code = (byte*) bytecodeBuffer; | ||||
| 		refreshShaderCreateInfo.EntryPointName = entryPointName; | ||||
| 		refreshShaderCreateInfo.Stage = (Refresh.ShaderStage) shaderCreateInfo.ShaderStage; | ||||
| 		refreshShaderCreateInfo.Format = (Refresh.ShaderFormat) shaderCreateInfo.ShaderFormat; | ||||
| 		refreshShaderCreateInfo.SamplerCount = shaderCreateInfo.SamplerCount; | ||||
| 		refreshShaderCreateInfo.StorageTextureCount = shaderCreateInfo.StorageTextureCount; | ||||
| 		refreshShaderCreateInfo.StorageBufferCount = shaderCreateInfo.StorageBufferCount; | ||||
| 		refreshShaderCreateInfo.UniformBufferCount = shaderCreateInfo.UniformBufferCount; | ||||
| 
 | ||||
| 		IntPtr shaderModule = Refresh.Refresh_CreateShader( | ||||
| 			device.Handle, | ||||
| 			refreshShaderCreateInfo | ||||
| 		); | ||||
| 
 | ||||
| 		NativeMemory.Free(bytecodeBuffer); | ||||
| 		return shaderModule; | ||||
| 	} | ||||
| } | ||||
| @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; | ||||
| 
 | ||||
| namespace Nerfed.Runtime.Gui; | ||||
| 
 | ||||
| internal class GuiController : IDisposable | ||||
| public class GuiController : IDisposable | ||||
| { | ||||
|     public event Action OnGui; | ||||
| 
 | ||||
| @@ -60,20 +60,8 @@ internal class GuiController : IDisposable | ||||
|         io.DisplaySize = new Vector2(mainWindow.Width, mainWindow.Height); | ||||
|         io.DisplayFramebufferScale = Vector2.One; | ||||
| 
 | ||||
|         ShaderCreateInfo vertexCreateInfo = new ShaderCreateInfo { | ||||
|             ShaderStage = ShaderStage.Vertex, | ||||
|             ShaderFormat = ShaderFormat.SPIRV, | ||||
|             UniformBufferCount = 1, | ||||
|         }; | ||||
|         imGuiVertexShader = new Shader(graphicsDevice, Path.Combine(shaderContentPath, "imgui-vertex.spv"), "main", in vertexCreateInfo); | ||||
| 
 | ||||
|         ShaderCreateInfo fragCreateInfo = new ShaderCreateInfo { | ||||
|             ShaderStage = ShaderStage.Fragment, | ||||
|             ShaderFormat = ShaderFormat.SPIRV, | ||||
|             SamplerCount = 1, | ||||
|              | ||||
|         }; | ||||
|         imGuiFragmentShader = new Shader(graphicsDevice, Path.Combine(shaderContentPath, "imgui-frag.spv"), "main", in fragCreateInfo); | ||||
|         imGuiVertexShader = ResourceManager.Load<Shader>("Shaders/ImGui.vert"); | ||||
|         imGuiFragmentShader = ResourceManager.Load<Shader>("Shaders/ImGui.frag"); | ||||
| 
 | ||||
|         imGuiSampler = new Sampler(graphicsDevice, SamplerCreateInfo.LinearClamp); | ||||
| 
 | ||||
| @@ -144,9 +132,13 @@ internal class GuiController : IDisposable | ||||
|         io.BackendFlags |= ImGuiBackendFlags.HasSetMousePos; | ||||
|         io.BackendFlags |= ImGuiBackendFlags.PlatformHasViewports; | ||||
|         io.BackendFlags |= ImGuiBackendFlags.RendererHasViewports; | ||||
| 
 | ||||
|         UpdatePerFrameImGuiData(1.0 / 60.0); | ||||
|         ImGui.NewFrame(); | ||||
|         frameBegun = true; | ||||
|     } | ||||
| 
 | ||||
|     public void Update(float deltaTime) | ||||
|     public void Update(double deltaTime) | ||||
|     { | ||||
|         if (frameBegun) | ||||
|         { | ||||
| @@ -167,12 +159,12 @@ internal class GuiController : IDisposable | ||||
|         ImGui.EndFrame(); | ||||
|     } | ||||
| 
 | ||||
|     private void UpdatePerFrameImGuiData(float deltaSeconds) | ||||
|     private void UpdatePerFrameImGuiData(double deltaSeconds) | ||||
|     { | ||||
|         ImGuiIOPtr io = ImGui.GetIO(); | ||||
|         io.DisplaySize = new Vector2(mainWindow.Width, mainWindow.Height); | ||||
|         io.DisplayFramebufferScale = new Vector2(1, 1); | ||||
|         io.DeltaTime = deltaSeconds; // DeltaTime is in seconds. | ||||
|         io.DeltaTime = (float)deltaSeconds; // DeltaTime is in seconds. | ||||
|     } | ||||
| 
 | ||||
|     private void UpdateInput() | ||||
| @@ -638,8 +630,8 @@ internal class GuiController : IDisposable | ||||
|         fontTexture?.Dispose(); | ||||
|         imGuiVertexBuffer?.Dispose(); | ||||
|         imGuiIndexBuffer?.Dispose(); | ||||
|         imGuiFragmentShader?.Dispose(); | ||||
|         imGuiVertexShader?.Dispose(); | ||||
|         ResourceManager.Unload(imGuiVertexShader); | ||||
|         ResourceManager.Unload(imGuiFragmentShader); | ||||
|         imGuiPipeline?.Dispose(); | ||||
|         imGuiSampler?.Dispose(); | ||||
|         resourceUploader?.Dispose(); | ||||
|   | ||||
							
								
								
									
										1
									
								
								Nerfed.Runtime/Libraries/MoonTools.ECS
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								Nerfed.Runtime/Libraries/MoonTools.ECS
									
									
									
									
									
										Submodule
									
								
							 Submodule Nerfed.Runtime/Libraries/MoonTools.ECS added at 76b18a6ba9
									
								
							| @@ -1,33 +1,44 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|  | ||||
|     <PropertyGroup> | ||||
|         <DefaultItemExcludes>$(DefaultItemExcludes);Libraries\**\*</DefaultItemExcludes> | ||||
|     </PropertyGroup> | ||||
|  | ||||
|     <ItemGroup> | ||||
|         <Compile Include="Libraries\SDL2CS\src\SDL2.cs" /> | ||||
|         <Compile Include="Libraries\RefreshCS\RefreshCS.cs" /> | ||||
|         <Compile Include="Libraries\FAudio\csharp\FAudio.cs" /> | ||||
|         <Compile Include="Libraries\WellspringCS\WellspringCS.cs" /> | ||||
| 		<Compile Include="Libraries\dav1dfile\csharp\dav1dfile.cs" /> | ||||
| 		<Compile Include="Libraries\ImGui.NET\src\ImGui.NET\**\*.cs" /> | ||||
|     </ItemGroup> | ||||
|  | ||||
|     <ItemGroup> | ||||
|         <Content Include="Content\**\*.*"> | ||||
|             <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||||
|         </Content> | ||||
|     </ItemGroup> | ||||
|  | ||||
|     <PropertyGroup> | ||||
|         <OutputType>Exe</OutputType> | ||||
|         <TargetFramework>net8.0</TargetFramework> | ||||
|         <ImplicitUsings>enable</ImplicitUsings> | ||||
|         <Nullable>disable</Nullable> | ||||
|         <PublishAot>true</PublishAot> | ||||
|         <InvariantGlobalization>true</InvariantGlobalization> | ||||
|         <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | ||||
|         <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> | ||||
|         <IsPackable>false</IsPackable> | ||||
|         <Configurations>Debug;Test;Release</Configurations> | ||||
|         <Platforms>x64</Platforms> | ||||
|     </PropertyGroup> | ||||
|  | ||||
|     <Import Project=".\CopyLibs.targets" /> | ||||
|     <PropertyGroup> | ||||
|         <DefaultItemExcludes>$(DefaultItemExcludes);Libraries\**\*</DefaultItemExcludes> | ||||
|     </PropertyGroup> | ||||
|  | ||||
|     <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' "> | ||||
|         <DefineConstants>TRACE;LOG_INFO;PROFILING</DefineConstants> | ||||
|     </PropertyGroup> | ||||
|  | ||||
|     <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Test|x64' "> | ||||
|         <DefineConstants>TRACE;LOG_ERROR;PROFILING</DefineConstants> | ||||
|         <Optimize>true</Optimize> | ||||
|     </PropertyGroup> | ||||
|      | ||||
|     <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' "> | ||||
|         <DefineConstants>TRACE;LOG_ERROR</DefineConstants> | ||||
|         <Optimize>true</Optimize> | ||||
|     </PropertyGroup> | ||||
|      | ||||
|     <ItemGroup> | ||||
|         <Compile Include="Libraries\FAudio\csharp\FAudio.cs" /> | ||||
|         <Compile Include="Libraries\ImGui.NET\src\ImGui.NET\**\*.cs" /> | ||||
|         <Compile Include="Libraries\MoonTools.ECS\src\**\*.cs" /> | ||||
|         <Compile Include="Libraries\RefreshCS\RefreshCS.cs" /> | ||||
|         <Compile Include="Libraries\SDL2CS\src\SDL2.cs" /> | ||||
|         <Compile Include="Libraries\WellspringCS\WellspringCS.cs" /> | ||||
|         <Compile Include="Libraries\dav1dfile\csharp\dav1dfile.cs" /> | ||||
|     </ItemGroup> | ||||
|      | ||||
| </Project> | ||||
							
								
								
									
										2
									
								
								Nerfed.Runtime/Nerfed.Runtime.csproj.DotSettings
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								Nerfed.Runtime/Nerfed.Runtime.csproj.DotSettings
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> | ||||
| 	<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=resource/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary> | ||||
| @@ -1,29 +1,166 @@ | ||||
| using System.Diagnostics; | ||||
| using System.Reflection; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Collections.Concurrent; | ||||
| using System.Diagnostics; | ||||
| 
 | ||||
| namespace Nerfed.Runtime; | ||||
| 
 | ||||
| public struct ProfilerScope : IDisposable | ||||
| { | ||||
|     public ProfilerScope(string label) { | ||||
|     public ProfilerScope(string label) | ||||
|     { | ||||
|         Profiler.BeginSample(label); | ||||
|     } | ||||
| 
 | ||||
|     public void Dispose() { | ||||
|     public void Dispose() | ||||
|     { | ||||
|         Profiler.EndSample(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| public static class Profiler | ||||
| { | ||||
|     [Conditional("PROFILER")] | ||||
|     public static void BeginSample(string label) { | ||||
|     public class Frame(uint frameCount) | ||||
|     { | ||||
|         public uint FrameCount { get; } = frameCount; | ||||
|         public long StartTime { get; } = Stopwatch.GetTimestamp(); | ||||
|         public long EndTime { get; private set; } | ||||
| 
 | ||||
|         // Use a concurrent list to collect all thread root nodes per frame. | ||||
|         public ConcurrentBag<ScopeNode> RootNodes = new ConcurrentBag<ScopeNode>(); | ||||
| 
 | ||||
|         internal void End() | ||||
|         { | ||||
|             EndTime = Stopwatch.GetTimestamp(); | ||||
|         } | ||||
| 
 | ||||
|         public double ElapsedMilliseconds() | ||||
|         { | ||||
|             long elapsedTicks = EndTime - StartTime; | ||||
|             return ((double)(elapsedTicks * 1000)) / Stopwatch.Frequency; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     [Conditional("PROFILER")] | ||||
|     public static void EndSample() { | ||||
|     public class ScopeNode(string label) | ||||
|     { | ||||
|         public string Label { get; } = label; | ||||
|         public long StartTime { get; private set; } = Stopwatch.GetTimestamp();  // Start time in ticks | ||||
|         public long EndTime { get; private set; } | ||||
|         public int ManagedThreadId { get; } = Environment.CurrentManagedThreadId; | ||||
|         public List<ScopeNode> Children { get; } = new List<ScopeNode>(); | ||||
| 
 | ||||
|         internal void End() | ||||
|         { | ||||
|             EndTime = Stopwatch.GetTimestamp();  // End time in ticks | ||||
|         } | ||||
| 
 | ||||
|         public double ElapsedMilliseconds() | ||||
|         { | ||||
|             return ((double)(EndTime - StartTime)) * 1000 / Stopwatch.Frequency;  // Convert ticks to ms | ||||
|         } | ||||
| 
 | ||||
|         // Add a child node (used for nested scopes) | ||||
|         internal ScopeNode AddChild(string label) | ||||
|         { | ||||
|             ScopeNode child = new ScopeNode(label); | ||||
|             Children.Add(child); | ||||
|             return child; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private const int maxFrames = 128; | ||||
| 
 | ||||
|     public static bool IsRecording { get; private set; } = true; | ||||
| 
 | ||||
|     // Store only the last x amount of frames in memory. | ||||
|     public static readonly BoundedQueue<Frame> Frames = new(maxFrames); | ||||
| 
 | ||||
|     // Use ThreadLocal to store a stack of ScopeNodes per thread and enable tracking of thread-local values. | ||||
|     private static readonly ThreadLocal<Stack<ScopeNode>> threadLocalScopes = new ThreadLocal<Stack<ScopeNode>>(() => new Stack<ScopeNode>(), true); | ||||
| 
 | ||||
|     private static Frame currentFrame = null; | ||||
|     private static uint frameCount = 0; | ||||
| 
 | ||||
|     public static void SetActive(bool isRecording) | ||||
|     { | ||||
|         IsRecording = isRecording; | ||||
|     } | ||||
| 
 | ||||
|     [Conditional("PROFILING")] | ||||
|     public static void BeginFrame() | ||||
|     { | ||||
|         if (!IsRecording) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         currentFrame = new Frame(frameCount); | ||||
|     } | ||||
| 
 | ||||
|     [Conditional("PROFILING")] | ||||
|     public static void EndFrame() | ||||
|     { | ||||
|         if (!IsRecording) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         foreach (Stack<ScopeNode> scopes in threadLocalScopes.Values) | ||||
|         { | ||||
|             if (scopes.Count > 0) | ||||
|             { | ||||
|                 // Pop the left over root nodes. | ||||
|                 ScopeNode currentScope = scopes.Pop(); | ||||
|                 currentScope.End(); | ||||
|             } | ||||
| 
 | ||||
|             // Clean up the thread-local stack to ensure it's empty for the next frame. | ||||
|             scopes.Clear(); | ||||
|         } | ||||
| 
 | ||||
|         currentFrame.End(); | ||||
|         Frames.Enqueue(currentFrame); | ||||
|         frameCount++; | ||||
|     } | ||||
| 
 | ||||
|     [Conditional("PROFILING")] | ||||
|     public static void BeginSample(string label) | ||||
|     { | ||||
|         if (!IsRecording) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         Stack<ScopeNode> scopes = threadLocalScopes.Value;  // Get the stack for the current thread | ||||
| 
 | ||||
|         if (scopes.Count == 0) | ||||
|         { | ||||
|             // First scope for this thread (new root for this thread) | ||||
|             ScopeNode rootScopeNode = new ScopeNode($"Thread-{Environment.CurrentManagedThreadId}"); | ||||
|             scopes.Push(rootScopeNode); | ||||
|             currentFrame.RootNodes.Add(rootScopeNode);  // Add root node to the frame list | ||||
|         } | ||||
| 
 | ||||
|         // Create a new child under the current top of the stack | ||||
|         ScopeNode newScope = scopes.Peek().AddChild(label); | ||||
| 
 | ||||
|         scopes.Push(newScope);  // Push new scope to the thread's stack | ||||
|     } | ||||
| 
 | ||||
|     [Conditional("PROFILING")] | ||||
|     public static void EndSample() | ||||
|     { | ||||
|         if (!IsRecording) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         Stack<ScopeNode> scopes = threadLocalScopes.Value; | ||||
| 
 | ||||
|         if (scopes.Count > 0) | ||||
|         { | ||||
|             // Only pop if this is not the root node. | ||||
|             //ScopeNode currentScope = scopes.Count > 1 ? scopes.Pop() : scopes.Peek(); | ||||
|             ScopeNode currentScope = scopes.Pop(); | ||||
|             currentScope.End(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										156
									
								
								Nerfed.Runtime/ProfilerVisualizer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								Nerfed.Runtime/ProfilerVisualizer.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,156 @@ | ||||
| using ImGuiNET; | ||||
| using System.Numerics; | ||||
| 
 | ||||
| namespace Nerfed.Runtime; | ||||
| 
 | ||||
| public static class ProfilerVisualizer | ||||
| { | ||||
|     private const float barHeight = 20f; | ||||
|     private const float barPadding = 2f; | ||||
| 
 | ||||
|     // Render the flame graph across multiple threads | ||||
|     public static void RenderFlameGraph(Profiler.Frame frame) | ||||
|     { | ||||
|         if (frame == null) return; | ||||
|         if (frame.RootNodes == null) return; | ||||
| 
 | ||||
|         // Calculate the total timeline duration (max end time across all nodes) | ||||
|         double totalDuration = frame.EndTime - frame.StartTime; | ||||
|         double startTime = frame.StartTime; | ||||
| 
 | ||||
|         // Precompute the maximum depth for each thread's call stack | ||||
|         Dictionary<int, int> threadMaxDepths = new Dictionary<int, int>(); | ||||
|         foreach (IGrouping<int, Profiler.ScopeNode> threadGroup in frame.RootNodes.GroupBy(node => node.ManagedThreadId)) | ||||
|         { | ||||
|             int maxDepth = 0; | ||||
|             foreach (Profiler.ScopeNode rootNode in threadGroup) | ||||
|             { | ||||
|                 maxDepth = Math.Max(maxDepth, GetMaxDepth(rootNode, 0)); | ||||
|             } | ||||
|             threadMaxDepths[threadGroup.Key] = maxDepth; | ||||
|         } | ||||
| 
 | ||||
|         // Start a child window to support scrolling | ||||
|         ImGui.BeginChild("FlameGraph", new Vector2(0, 64), ImGuiChildFlags.Border | ImGuiChildFlags.ResizeY, ImGuiWindowFlags.HorizontalScrollbar | ImGuiWindowFlags.AlwaysVerticalScrollbar); | ||||
| 
 | ||||
|         ImDrawListPtr drawList = ImGui.GetWindowDrawList(); | ||||
|         Vector2 windowPos = ImGui.GetCursorScreenPos(); | ||||
| 
 | ||||
|         // Sort nodes by ThreadID, ensuring main thread (Thread ID 1) is on top | ||||
|         IOrderedEnumerable<IGrouping<int, Profiler.ScopeNode>> threadGroups = frame.RootNodes.GroupBy(node => node.ManagedThreadId).OrderBy(g => g.Key); | ||||
| 
 | ||||
|         // Initial Y position for drawing | ||||
|         float baseY = windowPos.Y; | ||||
|         bool alternate = false; | ||||
|         float contentWidth = ImGui.GetContentRegionAvail().X; | ||||
| 
 | ||||
|         // Draw each thread's flame graph row by row | ||||
|         foreach (IGrouping<int, Profiler.ScopeNode> threadGroup in threadGroups) | ||||
|         { | ||||
|             int threadId = threadGroup.Key; | ||||
| 
 | ||||
|             // Compute the base Y position for this thread | ||||
|             float threadBaseY = baseY; | ||||
| 
 | ||||
|             // Calculate the maximum height for this thread's flame graph | ||||
|             float threadHeight = (threadMaxDepths[threadId] + 1) * (barHeight + barPadding); | ||||
| 
 | ||||
|             // Draw the alternating background for each thread row | ||||
|             uint backgroundColor = ImGui.ColorConvertFloat4ToU32(alternate ? new Vector4(0.2f, 0.2f, 0.2f, 1f) : new Vector4(0.1f, 0.1f, 0.1f, 1f)); | ||||
|             drawList.AddRectFilled(new Vector2(windowPos.X, threadBaseY), new Vector2(windowPos.X + contentWidth, threadBaseY + threadHeight), backgroundColor); | ||||
| 
 | ||||
|             alternate = !alternate; | ||||
| 
 | ||||
|             // Draw each root node in the group (one per thread) | ||||
|             foreach (Profiler.ScopeNode rootNode in threadGroup) | ||||
|             { | ||||
|                 RenderNode(drawList, rootNode, startTime, totalDuration, windowPos.X, threadBaseY, 0, contentWidth, false); | ||||
|             } | ||||
| 
 | ||||
|             // Move to the next thread's row (max depth * height per level) | ||||
|             baseY += (threadMaxDepths[threadId] + 1) * (barHeight + barPadding); | ||||
|         } | ||||
| 
 | ||||
|         // Ensure that ImGui knows the size of the content. | ||||
|         ImGui.Dummy(new Vector2(contentWidth, baseY)); | ||||
| 
 | ||||
|         ImGui.EndChild(); | ||||
|     } | ||||
| 
 | ||||
|     private static void RenderNode(ImDrawListPtr drawList, Profiler.ScopeNode node, double startTime, double totalDuration, float startX, float baseY, int depth, float contentWidth, bool alternate) | ||||
|     { | ||||
|         if (node == null) return; | ||||
| 
 | ||||
|         double nodeStartTime = node.StartTime - startTime; | ||||
|         double nodeEndTime = node.EndTime - startTime; | ||||
|         double nodeDuration = nodeEndTime - nodeStartTime; | ||||
| 
 | ||||
|         // Calculate the position and width of the bar based on time | ||||
|         float xPos = (float)(startX + (nodeStartTime / totalDuration) * contentWidth); | ||||
|         float width = (float)((nodeDuration / totalDuration) * contentWidth); | ||||
| 
 | ||||
|         // Calculate the Y position based on depth | ||||
|         float yPos = baseY + (depth * (barHeight + barPadding)) + (barPadding * 0.5f); | ||||
| 
 | ||||
|         // Define the rectangle bounds for the node | ||||
|         Vector2 min = new Vector2(xPos, yPos); | ||||
|         Vector2 max = new Vector2(xPos + width, yPos + barHeight); | ||||
| 
 | ||||
|         // Define color. | ||||
|         Vector4 barColor = alternate ? new Vector4(0.4f, 0.6f, 0.9f, 1f) : new Vector4(0.4f, 0.5f, 0.8f, 1f); | ||||
|         Vector4 textColor = new Vector4(1f, 1f, 1f, 1f); | ||||
| 
 | ||||
|         if (depth != 0) | ||||
|         { | ||||
|             // Draw the bar for the node (colored based on thread depth) | ||||
|             drawList.AddRectFilled(min, max, ImGui.ColorConvertFloat4ToU32(barColor)); | ||||
| 
 | ||||
|             // Draw the label if it fits inside the bar | ||||
|             string label = $"{node.Label} ({node.ElapsedMilliseconds():0.000} ms)"; | ||||
|             if (width > ImGui.CalcTextSize(label).X) | ||||
|             { | ||||
|                 drawList.AddText(new Vector2(xPos + barPadding, yPos + barPadding), ImGui.ColorConvertFloat4ToU32(textColor), label); | ||||
|             } | ||||
| 
 | ||||
|             // Add tooltip on hover | ||||
|             if (ImGui.IsMouseHoveringRect(min, max)) | ||||
|             { | ||||
|                 // Show tooltip when hovering over the node | ||||
|                 ImGui.BeginTooltip(); | ||||
|                 ImGui.Text($"{node.Label}"); | ||||
|                 ImGui.Text($"{node.ElapsedMilliseconds():0.000} ms"); | ||||
|                 ImGui.Text($"{node.ManagedThreadId}"); | ||||
|                 ImGui.EndTooltip(); | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             // Aka root node. | ||||
|             string label = $"{node.Label}"; | ||||
|             drawList.AddText(new Vector2(startX + barPadding, yPos + barPadding), ImGui.ColorConvertFloat4ToU32(textColor), label); | ||||
|         } | ||||
| 
 | ||||
|         // Draw each child node under this node | ||||
|         foreach (Profiler.ScopeNode child in node.Children) | ||||
|         { | ||||
|             alternate = !alternate; | ||||
|             RenderNode(drawList, child, startTime, totalDuration, startX, baseY, depth + 1, contentWidth, alternate); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Recursive function to calculate the maximum depth of the node tree | ||||
|     private static int GetMaxDepth(Profiler.ScopeNode node, int currentDepth) | ||||
|     { | ||||
|         if (node.Children == null || node.Children.Count == 0) | ||||
|         { | ||||
|             return currentDepth; | ||||
|         } | ||||
| 
 | ||||
|         int maxDepth = currentDepth; | ||||
|         foreach (Profiler.ScopeNode child in node.Children) | ||||
|         { | ||||
|             maxDepth = Math.Max(maxDepth, GetMaxDepth(child, currentDepth + 1)); | ||||
|         } | ||||
|         return maxDepth; | ||||
|     } | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| namespace Nerfed.Runtime; | ||||
| 
 | ||||
| internal class Program | ||||
| { | ||||
|     private static void Main(string[] args) | ||||
|     { | ||||
|         Engine.Run(args); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										9
									
								
								Nerfed.Runtime/Resource/Resource.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								Nerfed.Runtime/Resource/Resource.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| namespace Nerfed.Runtime; | ||||
| 
 | ||||
| public abstract class Resource | ||||
| { | ||||
|     public string Path { get; internal set; } | ||||
| 
 | ||||
|     internal abstract void Load(Stream stream); | ||||
|     internal abstract void Unload(); | ||||
| } | ||||
							
								
								
									
										43
									
								
								Nerfed.Runtime/Resource/ResourceManager.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								Nerfed.Runtime/Resource/ResourceManager.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| namespace Nerfed.Runtime; | ||||
| 
 | ||||
| public static class ResourceManager | ||||
| { | ||||
|     private const string rootName = "Resources"; | ||||
|     private static readonly Dictionary<string, Resource> loadedResources = new Dictionary<string, Resource>(); | ||||
| 
 | ||||
|     public static T Load<T>(string resourcePath) where T : Resource | ||||
|     { | ||||
|         if (loadedResources.TryGetValue(resourcePath, out Resource resource)) | ||||
|         { | ||||
|             return (T)resource; | ||||
|         } | ||||
| 
 | ||||
|         if (typeof(T) == typeof(Shader)) | ||||
|         { | ||||
|             resource = new Shader(); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             throw new Exception("Failed to create resource"); | ||||
|         } | ||||
| 
 | ||||
|         Assert.Always(resource != null); | ||||
|         resource.Path = resourcePath; | ||||
|         resource.Load(StorageContainer.OpenStream(Path.Combine(AppContext.BaseDirectory, rootName, resourcePath) + ".bin")); | ||||
| 
 | ||||
|         loadedResources.Add(resourcePath, resource); | ||||
|         return (T)resource; | ||||
|     } | ||||
| 
 | ||||
|     public static void Unload(Resource resource) | ||||
|     { | ||||
|         if (!loadedResources.ContainsKey(resource.Path)) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         resource.Unload(); | ||||
|         resource.Path = string.Empty; | ||||
|         loadedResources.Remove(resource.Path); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										58
									
								
								Nerfed.Runtime/Resource/Shader.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								Nerfed.Runtime/Resource/Shader.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| using System.Runtime.InteropServices; | ||||
| using RefreshCS; | ||||
| 
 | ||||
| namespace Nerfed.Runtime; | ||||
| 
 | ||||
| public class Shader : Resource | ||||
| { | ||||
|     public IntPtr Handle { get; private set; } | ||||
| 
 | ||||
|     public uint SamplerCount { get; private set; } | ||||
|     public uint StorageTextureCount { get; private set; } | ||||
|     public uint StorageBufferCount { get; private set; } | ||||
|     public uint UniformBufferCount { get; private set; } | ||||
| 
 | ||||
|     internal Shader() { } | ||||
| 
 | ||||
|     internal override unsafe void Load(Stream stream) | ||||
|     { | ||||
|         using (BinaryReader reader = new BinaryReader(stream)) | ||||
|         { | ||||
|             Refresh.ShaderCreateInfo createInfo; | ||||
|             createInfo.Format = (Refresh.ShaderFormat)reader.ReadInt32(); | ||||
|             createInfo.Stage = (Refresh.ShaderStage)reader.ReadInt32(); | ||||
|             createInfo.UniformBufferCount = (uint)reader.ReadInt32(); | ||||
|             createInfo.StorageBufferCount = (uint)reader.ReadInt32(); | ||||
|             createInfo.StorageTextureCount = (uint)reader.ReadInt32(); | ||||
|             createInfo.SamplerCount = (uint)reader.ReadInt32(); | ||||
| 
 | ||||
|             int byteCodeSize = reader.ReadInt32(); | ||||
|             void* byteCodeBuffer = NativeMemory.Alloc((nuint)byteCodeSize); | ||||
|             Span<byte> byteCodeSpan = new Span<byte>(byteCodeBuffer, byteCodeSize); | ||||
| 
 | ||||
|             int bytesRead = 0; | ||||
|             while (bytesRead < byteCodeSize) | ||||
|             { | ||||
|                 bytesRead += reader.Read(byteCodeSpan.Slice(bytesRead)); | ||||
|             } | ||||
| 
 | ||||
|             createInfo.CodeSize = (nuint)byteCodeSize; | ||||
|             createInfo.Code = (byte*)byteCodeBuffer; | ||||
|             createInfo.EntryPointName = "main"; | ||||
| 
 | ||||
|             Handle = Refresh.Refresh_CreateShader(Engine.GraphicsDevice.Handle, createInfo); | ||||
|             NativeMemory.Free(byteCodeBuffer); | ||||
| 
 | ||||
|             SamplerCount = createInfo.SamplerCount; | ||||
|             StorageTextureCount = createInfo.StorageTextureCount; | ||||
|             StorageBufferCount = createInfo.StorageBufferCount; | ||||
|             UniformBufferCount = createInfo.UniformBufferCount; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     internal override void Unload() | ||||
|     { | ||||
|         Refresh.Refresh_ReleaseShader(Engine.GraphicsDevice.Handle, Handle); | ||||
|         Handle = IntPtr.Zero; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										68
									
								
								Nerfed.Runtime/Serialization/ComponentHelper.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								Nerfed.Runtime/Serialization/ComponentHelper.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| using System.Numerics; | ||||
| using ImGuiNET; | ||||
| using MoonTools.ECS; | ||||
| using Nerfed.Runtime.Components; | ||||
| 
 | ||||
| namespace Nerfed.Runtime.Serialization; | ||||
| 
 | ||||
| public static class ComponentHelper | ||||
| { | ||||
|     // Auto generate this. | ||||
|     public static readonly Dictionary<Type, Func<World, Entity, ValueType>> GetComponentByType = new() | ||||
|     { | ||||
|         { typeof(LocalTransform), (world, entity) => world.Get<LocalTransform>(entity) }, | ||||
|         { typeof(Root), (world, entity) => world.Get<Root>(entity) }, | ||||
|     }; | ||||
|      | ||||
|     // Auto generate this. | ||||
|     public static readonly Dictionary<Type, Action<World, Entity, ValueType>> SetComponentByType = new() | ||||
|     { | ||||
|         { typeof(LocalTransform), (world, entity, component) => world.Set(entity, (LocalTransform)component) }, | ||||
|         { typeof(Root), (world, entity, component) => world.Set(entity, (Root)component) }, | ||||
|     }; | ||||
|      | ||||
|     // Auto generate this, but it should only contain user assignable components (so something like 'root' should be excluded). | ||||
|     // Maybe use an attribute for this. | ||||
|     public static readonly Dictionary<Type, Action<World, Entity>> AddComponentByType = new() | ||||
|     { | ||||
|         { typeof(LocalTransform), (world, entity) => world.Set(entity, LocalTransform.Identity) }, | ||||
|     }; | ||||
| 
 | ||||
|     // Auto generate this, but also keep the option for 'custom inspectors'. | ||||
|     // Maybe via attribute? | ||||
|     public static readonly Dictionary<Type, Action<World, Entity>> ComponentInspectorByType = new() | ||||
|     { | ||||
|         { | ||||
|             typeof(LocalTransform), (world, entity) => | ||||
|             { | ||||
|                 (Vector3 position, Quaternion rotation, Vector3 scale) = world.Get<LocalTransform>(entity); | ||||
|                 Vector3 eulerAngles = MathEx.ToEulerAngles(rotation); | ||||
|                 eulerAngles = new Vector3(float.RadiansToDegrees(eulerAngles.X), float.RadiansToDegrees(eulerAngles.Y), float.RadiansToDegrees(eulerAngles.Z)); | ||||
|                 bool isDirty = false; | ||||
|                  | ||||
|                 ImGui.BeginGroup(); | ||||
|                 ImGui.Text($"{nameof(LocalTransform)}"); | ||||
|                 isDirty |= ImGui.DragFloat3("Position", ref position, 0.2f, float.MinValue, float.MaxValue /*, "%f0 m" */); // TODO: right format. | ||||
|                 isDirty |= ImGui.DragFloat3("Rotation", ref eulerAngles); | ||||
|                 isDirty |= ImGui.DragFloat3("Scale", ref scale); | ||||
|                 ImGui.EndGroup(); | ||||
| 
 | ||||
|                 if (!isDirty) | ||||
|                 { | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 eulerAngles = new Vector3(float.DegreesToRadians(eulerAngles.X), float.DegreesToRadians(eulerAngles.Y), float.DegreesToRadians(eulerAngles.Z)); | ||||
|                 world.Set(entity, new LocalTransform(position, MathEx.ToQuaternion(eulerAngles), scale)); | ||||
|             } | ||||
|         }, | ||||
|         { | ||||
|             typeof(Root), (world, entity) => | ||||
|             { | ||||
|                 ImGui.BeginGroup(); | ||||
|                 ImGui.Text($"{nameof(Root)}"); | ||||
|                 ImGui.EndGroup(); | ||||
|             } | ||||
|         }, | ||||
|     }; | ||||
| } | ||||
							
								
								
									
										95
									
								
								Nerfed.Runtime/Systems/LocalToWorldSystem.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								Nerfed.Runtime/Systems/LocalToWorldSystem.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,95 @@ | ||||
| using MoonTools.ECS; | ||||
| using Nerfed.Runtime.Components; | ||||
| using Nerfed.Runtime.Util; | ||||
| using System.Numerics; | ||||
| 
 | ||||
| // TODO: | ||||
| // Explore if having a WorldTransform and LocalTransfom component each holding position, rotation, scale values and the matricies is useful. | ||||
| // Often you need to either get or set these values. | ||||
| // If so, we probably need a utility funciton to do so. Since changing these values means that we need to update all the related data + children as well. | ||||
| 
 | ||||
| // TODO: | ||||
| // When modifying transform all the children need to be updated as well. | ||||
| 
 | ||||
| namespace Nerfed.Runtime.Systems | ||||
| { | ||||
|     public class LocalToWorldSystem : MoonTools.ECS.System | ||||
|     { | ||||
|         private readonly bool useParallelFor = true; // When having a low amount of transforms or when in debug mode this might be slower. | ||||
|         private readonly Filter rootEntitiesFilter; | ||||
|         private readonly Filter entitiesWithoutLocalToWorldFilter; | ||||
|         private readonly Action<int> updateWorldTransform; | ||||
| 
 | ||||
|         public LocalToWorldSystem(World world) : base(world) | ||||
|         { | ||||
|             rootEntitiesFilter = FilterBuilder.Include<LocalTransform>().Exclude<Child>().Build(); | ||||
|             if (useParallelFor) | ||||
|             { | ||||
|                 entitiesWithoutLocalToWorldFilter = FilterBuilder.Include<LocalTransform>().Exclude<LocalToWorld>().Build(); | ||||
|                 updateWorldTransform = UpdateWorldTransformByIndex; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public override void Update(TimeSpan delta) | ||||
|         { | ||||
|             if (rootEntitiesFilter.Empty) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             if (useParallelFor) | ||||
|             { | ||||
|                 Profiler.BeginSample("ParallelFor.LocalToWorldCheck"); | ||||
|                 // This check is needed because some entities might not have a LocalToWorld component yet. | ||||
|                 // Adding this during the loop will break. | ||||
|                 foreach (Entity entity in entitiesWithoutLocalToWorldFilter.Entities) { | ||||
|                     Set(entity, new LocalToWorld(Matrix4x4.Identity)); | ||||
|                 } | ||||
|                 Profiler.EndSample(); | ||||
| 
 | ||||
|                 Profiler.BeginSample("ParallelFor.LocalToWorldUpdate"); | ||||
|                 // This should only be used when the filter doesn't change by executing these functions! | ||||
|                 // So no entity deletion or setting/removing of components used by the filters in this loop. | ||||
|                 Parallel.For(0, rootEntitiesFilter.Count, updateWorldTransform); | ||||
|                 Profiler.EndSample(); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 foreach (Entity entity in rootEntitiesFilter.Entities) | ||||
|                 { | ||||
|                     Profiler.BeginSample("UpdateWorldTransform"); | ||||
|                     UpdateWorldTransform(entity, Matrix4x4.Identity); | ||||
|                     Profiler.EndSample(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private void UpdateWorldTransformByIndex(int entityFilterIndex) | ||||
|         { | ||||
|             Profiler.BeginSample("UpdateWorldTransformByIndex"); | ||||
|             Entity entity = rootEntitiesFilter.NthEntity(entityFilterIndex); | ||||
|             UpdateWorldTransform(entity, Matrix4x4.Identity); | ||||
|             Profiler.EndSample(); | ||||
|         } | ||||
| 
 | ||||
|         private void UpdateWorldTransform(in Entity entity, Matrix4x4 localToWorldMatrix) | ||||
|         { | ||||
|             // TODO: Only update dirty transforms. | ||||
|             // If a parent is dirty all the children need to update their localToWorld matrix. | ||||
|             // How do we check if something is dirty? How do we know if a LocalTransform has been changed? | ||||
|             if (Has<LocalTransform>(entity)) | ||||
|             { | ||||
|                 LocalTransform localTransform = Get<LocalTransform>(entity); | ||||
|                 localToWorldMatrix = Matrix4x4.Multiply(localToWorldMatrix, localTransform.TRS()); | ||||
|                 LocalToWorld localToWorld = new(localToWorldMatrix); | ||||
|                 Set(entity, localToWorld); | ||||
|             } | ||||
| 
 | ||||
|             ReverseSpanEnumerator<Entity> childEntities = World.InRelations<ChildParentRelation>(entity); | ||||
|             foreach (Entity childEntity in childEntities) | ||||
|             { | ||||
|                 UpdateWorldTransform(childEntity, localToWorldMatrix); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										73
									
								
								Nerfed.Runtime/Util/BoundedQueue.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								Nerfed.Runtime/Util/BoundedQueue.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | ||||
| using System.Collections; | ||||
| 
 | ||||
| namespace Nerfed.Runtime; | ||||
| 
 | ||||
| public class BoundedQueue<T> : IEnumerable<T>, ICollection, IReadOnlyCollection<T> | ||||
| { | ||||
|     private readonly Queue<T> queue = null; | ||||
|     private readonly int maxSize = 10; | ||||
|     private T lastAddedElement; | ||||
| 
 | ||||
|     public BoundedQueue(int maxSize) | ||||
|     { | ||||
|         this.maxSize = maxSize; | ||||
|         queue = new Queue<T>(maxSize); | ||||
|     } | ||||
| 
 | ||||
|     public void Enqueue(T item) | ||||
|     { | ||||
|         queue.Enqueue(item); | ||||
|         if (queue.Count > maxSize) | ||||
|         { | ||||
|             queue.Dequeue(); // Remove the oldest element | ||||
|         } | ||||
| 
 | ||||
|         lastAddedElement = item; | ||||
|     } | ||||
| 
 | ||||
|     public T Dequeue() | ||||
|     { | ||||
|         return queue.Dequeue(); | ||||
|     } | ||||
| 
 | ||||
|     public T Peek() | ||||
|     { | ||||
|         return queue.Peek(); | ||||
|     } | ||||
| 
 | ||||
|     public T LastAddedElement() | ||||
|     { | ||||
|         return lastAddedElement; | ||||
|     } | ||||
| 
 | ||||
|     public void Clear() | ||||
|     { | ||||
|         queue.Clear(); | ||||
|     } | ||||
| 
 | ||||
|     public bool Contains(T item) | ||||
|     { | ||||
|         return queue.Contains(item); | ||||
|     } | ||||
| 
 | ||||
|     public IEnumerator<T> GetEnumerator() | ||||
|     { | ||||
|         return queue.GetEnumerator(); | ||||
|     } | ||||
| 
 | ||||
|     IEnumerator IEnumerable.GetEnumerator() | ||||
|     { | ||||
|         return queue.GetEnumerator(); | ||||
|     } | ||||
| 
 | ||||
|     public void CopyTo(Array array, int index) | ||||
|     { | ||||
|         ((ICollection)queue).CopyTo(array, index); | ||||
|     } | ||||
| 
 | ||||
|     public int Count => queue.Count; | ||||
|     public int Capacity => maxSize; | ||||
|     public bool IsSynchronized => ((ICollection)queue).IsSynchronized; | ||||
|     public object SyncRoot => ((ICollection)queue).SyncRoot; | ||||
|     int IReadOnlyCollection<T>.Count => queue.Count; | ||||
| } | ||||
| @@ -1,3 +1,5 @@ | ||||
| using System.Numerics; | ||||
| 
 | ||||
| namespace Nerfed.Runtime; | ||||
| 
 | ||||
| public static class MathEx | ||||
| @@ -17,4 +19,51 @@ public static class MathEx | ||||
|     public static float Remap(float value, float oldMin, float oldMax, float newMin, float newMax) { | ||||
|         return (value - oldMin) / (oldMax - oldMin) * (newMax - newMin) + newMin; | ||||
|     } | ||||
| } | ||||
|      | ||||
|     // https://stackoverflow.com/questions/70462758/c-sharp-how-to-convert-quaternions-to-euler-angles-xyz | ||||
|     public static Quaternion ToQuaternion(Vector3 v) | ||||
|     { | ||||
|         float cy = (float)Math.Cos(v.Z * 0.5); | ||||
|         float sy = (float)Math.Sin(v.Z * 0.5); | ||||
|         float cp = (float)Math.Cos(v.Y * 0.5); | ||||
|         float sp = (float)Math.Sin(v.Y * 0.5); | ||||
|         float cr = (float)Math.Cos(v.X * 0.5); | ||||
|         float sr = (float)Math.Sin(v.X * 0.5); | ||||
| 
 | ||||
|         return new Quaternion | ||||
|         { | ||||
|             W = (cr * cp * cy + sr * sp * sy), | ||||
|             X = (sr * cp * cy - cr * sp * sy), | ||||
|             Y = (cr * sp * cy + sr * cp * sy), | ||||
|             Z = (cr * cp * sy - sr * sp * cy), | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     public static Vector3 ToEulerAngles(Quaternion q) | ||||
|     { | ||||
|         Vector3 angles = new(); | ||||
| 
 | ||||
|         // roll / x | ||||
|         double sinrCosp = 2 * (q.W * q.X + q.Y * q.Z); | ||||
|         double cosrCosp = 1 - 2 * (q.X * q.X + q.Y * q.Y); | ||||
|         angles.X = (float)Math.Atan2(sinrCosp, cosrCosp); | ||||
| 
 | ||||
|         // pitch / y | ||||
|         double sinp = 2 * (q.W * q.Y - q.Z * q.X); | ||||
|         if (Math.Abs(sinp) >= 1) | ||||
|         { | ||||
|             angles.Y = (float)Math.CopySign(Math.PI / 2, sinp); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             angles.Y = (float)Math.Asin(sinp); | ||||
|         } | ||||
| 
 | ||||
|         // yaw / z | ||||
|         double sinyCosp = 2 * (q.W * q.Z + q.X * q.Y); | ||||
|         double cosyCosp = 1 - 2 * (q.Y * q.Y + q.Z * q.Z); | ||||
|         angles.Z = (float)Math.Atan2(sinyCosp, cosyCosp); | ||||
| 
 | ||||
|         return angles; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										13
									
								
								Nerfed.Runtime/Util/RandomId.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								Nerfed.Runtime/Util/RandomId.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| using System.Security.Cryptography; | ||||
| 
 | ||||
| namespace Nerfed.Runtime.Util; | ||||
| 
 | ||||
| public static class RandomId | ||||
| { | ||||
|     public static uint GenerateSecureRandomUInt() | ||||
|     { | ||||
|         byte[] buffer = new byte[4]; | ||||
|         RandomNumberGenerator.Fill(buffer); | ||||
|         return BitConverter.ToUInt32(buffer, 0); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										99
									
								
								Nerfed.Runtime/Util/Transform.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								Nerfed.Runtime/Util/Transform.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,99 @@ | ||||
| using MoonTools.ECS; | ||||
| using Nerfed.Runtime.Components; | ||||
| using System.Collections.Generic; | ||||
| using System.Numerics; | ||||
| 
 | ||||
| namespace Nerfed.Runtime.Util | ||||
| { | ||||
|     // https://github.com/needle-mirror/com.unity.entities/blob/master/Unity.Transforms/TransformHelpers.cs | ||||
|     public static class Transform | ||||
|     { | ||||
|         public static Vector3 Forward(in this Matrix4x4 matrix) => new Vector3(matrix.M31, matrix.M32, matrix.M33); | ||||
|         public static Vector3 Back(in this Matrix4x4 matrix) => -matrix.Forward(); | ||||
|         public static Vector3 Up(in this Matrix4x4 matrix) => new Vector3(matrix.M21, matrix.M22, matrix.M23); | ||||
|         public static Vector3 Down(in this Matrix4x4 matrix) => -matrix.Up(); | ||||
|         public static Vector3 Right(in this Matrix4x4 matrix) => new Vector3(matrix.M11, matrix.M12, matrix.M13); | ||||
|         public static Vector3 Left(in this Matrix4x4 matrix) => -matrix.Right(); | ||||
|         //public static Vector3 Translation(in this Matrix4x4 matrix) => new Vector3(); | ||||
|         //public static Quaternion Rotation(in this Matrix4x4 matrix) => new Quaternion(); | ||||
| 
 | ||||
|         public static Matrix4x4 TRS(in this LocalTransform localTransform) | ||||
|         { | ||||
|             return Matrix4x4.CreateScale(localTransform.scale) * | ||||
|                 Matrix4x4.CreateFromQuaternion(localTransform.rotation) * | ||||
|                 Matrix4x4.CreateTranslation(localTransform.position); | ||||
|         } | ||||
| 
 | ||||
|         // Sets the parent child relation and adds a child component. | ||||
|         // Relation goes from child to parent. | ||||
|         public static void SetParent(in World world, in Entity child, in Entity parent) | ||||
|         { | ||||
|             RemoveParent(world, child); | ||||
| 
 | ||||
|             world.Relate(child, parent, new ChildParentRelation()); | ||||
|             world.Set(child, new Child()); | ||||
|             world.Remove<Root>(child); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // Removes any parent child relation ship, thus making it a 'root' object. | ||||
|         public static void RemoveParent(in World world, in Entity child) | ||||
|         { | ||||
|             if (!world.HasOutRelation<ChildParentRelation>(child)) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             Entity parent = world.OutRelationSingleton<ChildParentRelation>(child); | ||||
| 
 | ||||
|             // TODO: Check if Unrelate all also unrelates incomming relations..? | ||||
|             world.Unrelate<ChildParentRelation>(child, parent); | ||||
|             world.Remove<Child>(child); | ||||
|             world.Set(child, new Root()); | ||||
|         } | ||||
| 
 | ||||
|         public static Entity CreateBaseEntity(this World world, string tag = "") | ||||
|         { | ||||
|             Entity entity = world.CreateEntity(tag); | ||||
|             world.Set(entity, new Root()); | ||||
|             return entity; | ||||
|         } | ||||
| 
 | ||||
|         // Force update the transform data of an entity (and children). | ||||
|         // Useful for when you need precise up to date transform data. | ||||
|         public static void ForceUpdateLocalToWorld(in World world, in Entity entity) | ||||
|         { | ||||
|             Matrix4x4 parentLocalToWorldMatrix = Matrix4x4.Identity; | ||||
| 
 | ||||
|             if (world.HasOutRelation<ChildParentRelation>(entity)) { | ||||
|                 Entity parent = world.OutRelationSingleton<ChildParentRelation>(entity); | ||||
| 
 | ||||
|                 if (world.Has<LocalToWorld>(parent)) | ||||
|                 { | ||||
|                     parentLocalToWorldMatrix = world.Get<LocalToWorld>(parent).localToWorldMatrix; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             ForceUpdateLocalToWorld(world, entity, parentLocalToWorldMatrix); | ||||
|         } | ||||
| 
 | ||||
|         private static void ForceUpdateLocalToWorld(in World world, in Entity entity, Matrix4x4 localToWorldMatrix) | ||||
|         { | ||||
|             if (world.Has<LocalTransform>(entity)) | ||||
|             { | ||||
|                 LocalTransform localTransform = world.Get<LocalTransform>(entity); | ||||
|                 localToWorldMatrix = Matrix4x4.Multiply(localToWorldMatrix, localTransform.TRS()); | ||||
|                 LocalToWorld localToWorld = new(localToWorldMatrix); | ||||
|                 world.Set(entity, localToWorld); | ||||
| 
 | ||||
|                 Log.Info($"Entity {entity} | local position {localTransform.position} | world position {localToWorldMatrix.Translation}"); | ||||
|             } | ||||
| 
 | ||||
|             ReverseSpanEnumerator<Entity> childEntities = world.InRelations<ChildParentRelation>(entity); | ||||
|             foreach (Entity childEntity in childEntities) | ||||
|             { | ||||
|                 ForceUpdateLocalToWorld(world, childEntity, localToWorldMatrix); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										34
									
								
								Nerfed.sln
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								Nerfed.sln
									
									
									
									
									
								
							| @@ -5,16 +5,38 @@ VisualStudioVersion = 17.10.35013.160 | ||||
| MinimumVisualStudioVersion = 10.0.40219.1 | ||||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerfed.Runtime", "Nerfed.Runtime\Nerfed.Runtime.csproj", "{98E09BAF-587F-4238-89BD-7693C036C233}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nerfed.Builder", "Nerfed.Builder\Nerfed.Builder.csproj", "{1B88DE56-2AD8-441E-9B10-073AA43840BF}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nerfed.Editor", "Nerfed.Editor\Nerfed.Editor.csproj", "{FF7D032D-7F0B-4700-A818-0606D66AECF8}" | ||||
| 	ProjectSection(ProjectDependencies) = postProject | ||||
| 		{1B88DE56-2AD8-441E-9B10-073AA43840BF} = {1B88DE56-2AD8-441E-9B10-073AA43840BF} | ||||
| 	EndProjectSection | ||||
| EndProject | ||||
| Global | ||||
| 	GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||
| 		Debug|Any CPU = Debug|Any CPU | ||||
| 		Release|Any CPU = Release|Any CPU | ||||
| 		Test|x64 = Test|x64 | ||||
| 		Release|x64 = Release|x64 | ||||
| 		Debug|x64 = Debug|x64 | ||||
| 	EndGlobalSection | ||||
| 	GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||||
| 		{98E09BAF-587F-4238-89BD-7693C036C233}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||
| 		{98E09BAF-587F-4238-89BD-7693C036C233}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||
| 		{98E09BAF-587F-4238-89BD-7693C036C233}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||
| 		{98E09BAF-587F-4238-89BD-7693C036C233}.Release|Any CPU.Build.0 = Release|Any CPU | ||||
| 		{1B88DE56-2AD8-441E-9B10-073AA43840BF}.Test|x64.ActiveCfg = Test|x64 | ||||
| 		{1B88DE56-2AD8-441E-9B10-073AA43840BF}.Test|x64.Build.0 = Test|x64 | ||||
| 		{1B88DE56-2AD8-441E-9B10-073AA43840BF}.Release|x64.ActiveCfg = Release|x64 | ||||
| 		{1B88DE56-2AD8-441E-9B10-073AA43840BF}.Release|x64.Build.0 = Release|x64 | ||||
| 		{1B88DE56-2AD8-441E-9B10-073AA43840BF}.Debug|x64.ActiveCfg = Debug|x64 | ||||
| 		{1B88DE56-2AD8-441E-9B10-073AA43840BF}.Debug|x64.Build.0 = Debug|x64 | ||||
| 		{FF7D032D-7F0B-4700-A818-0606D66AECF8}.Test|x64.ActiveCfg = Test|x64 | ||||
| 		{FF7D032D-7F0B-4700-A818-0606D66AECF8}.Test|x64.Build.0 = Test|x64 | ||||
| 		{FF7D032D-7F0B-4700-A818-0606D66AECF8}.Release|x64.ActiveCfg = Release|x64 | ||||
| 		{FF7D032D-7F0B-4700-A818-0606D66AECF8}.Release|x64.Build.0 = Release|x64 | ||||
| 		{FF7D032D-7F0B-4700-A818-0606D66AECF8}.Debug|x64.ActiveCfg = Debug|x64 | ||||
| 		{FF7D032D-7F0B-4700-A818-0606D66AECF8}.Debug|x64.Build.0 = Debug|x64 | ||||
| 		{98E09BAF-587F-4238-89BD-7693C036C233}.Test|x64.ActiveCfg = Test|x64 | ||||
| 		{98E09BAF-587F-4238-89BD-7693C036C233}.Test|x64.Build.0 = Test|x64 | ||||
| 		{98E09BAF-587F-4238-89BD-7693C036C233}.Release|x64.ActiveCfg = Release|x64 | ||||
| 		{98E09BAF-587F-4238-89BD-7693C036C233}.Release|x64.Build.0 = Release|x64 | ||||
| 		{98E09BAF-587F-4238-89BD-7693C036C233}.Debug|x64.ActiveCfg = Debug|x64 | ||||
| 		{98E09BAF-587F-4238-89BD-7693C036C233}.Debug|x64.Build.0 = Debug|x64 | ||||
| 	EndGlobalSection | ||||
| 	GlobalSection(SolutionProperties) = preSolution | ||||
| 		HideSolutionNode = FALSE | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								Tools/Nerfed.Builder/Nerfed.Builder
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Tools/Nerfed.Builder/Nerfed.Builder
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										23
									
								
								Tools/Nerfed.Builder/Nerfed.Builder.deps.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								Tools/Nerfed.Builder/Nerfed.Builder.deps.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| { | ||||
|   "runtimeTarget": { | ||||
|     "name": ".NETCoreApp,Version=v8.0", | ||||
|     "signature": "" | ||||
|   }, | ||||
|   "compilationOptions": {}, | ||||
|   "targets": { | ||||
|     ".NETCoreApp,Version=v8.0": { | ||||
|       "Nerfed.Builder/1.0.0": { | ||||
|         "runtime": { | ||||
|           "Nerfed.Builder.dll": {} | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   "libraries": { | ||||
|     "Nerfed.Builder/1.0.0": { | ||||
|       "type": "project", | ||||
|       "serviceable": false, | ||||
|       "sha512": "" | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								Tools/Nerfed.Builder/Nerfed.Builder.dll
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Tools/Nerfed.Builder/Nerfed.Builder.dll
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										13
									
								
								Tools/Nerfed.Builder/Nerfed.Builder.runtimeconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								Tools/Nerfed.Builder/Nerfed.Builder.runtimeconfig.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| { | ||||
|   "runtimeOptions": { | ||||
|     "tfm": "net8.0", | ||||
|     "framework": { | ||||
|       "name": "Microsoft.NETCore.App", | ||||
|       "version": "8.0.0" | ||||
|     }, | ||||
|     "configProperties": { | ||||
|       "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, | ||||
|       "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								Tools/glslc/Linux/glslc
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Tools/glslc/Linux/glslc
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Tools/glslc/Win64/glslc.exe
									 (Stored with Git LFS)
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Tools/glslc/Win64/glslc.exe
									 (Stored with Git LFS)
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
		Reference in New Issue
	
	Block a user