Compare commits

..

22 Commits

Author SHA1 Message Date
max
6f505f34a9 Unload resources before destroying device. 2024-07-20 00:45:16 +02:00
92cf24fe9f - Added resource manager
- Shader building now inspects the spir-v for descriptor sets and writes the info to the output binary
2024-07-13 13:45:12 +02:00
cce6e00960 - Merge 2024-07-12 23:11:47 +02:00
1096597161 - Fixed bug in builder when no content files exist 2024-07-12 23:10:44 +02:00
d45f7c3b8c - Fixed bug in builder when no content files exist 2024-07-12 23:08:52 +02:00
max
7a81026ca5 Merge remote-tracking branch 'origin/ImGui' 2024-07-12 19:51:41 +02:00
max
60b85960ff EditorGui setup 2024-07-12 19:09:59 +02:00
max
b003ffbaec Merge branch 'main' into ImGui 2024-07-12 18:08:28 +02:00
max
777059489c updated project structure 2024-07-12 17:59:06 +02:00
max
16b04ea22a Editor dummy code 2024-07-12 17:27:01 +02:00
max
4b824f3205 Add License 2024-07-12 16:38:54 +02:00
max
9890026656 Fix viewports 2024-07-12 16:38:42 +02:00
max
d8b41b0827 Fix viewports 2024-07-12 16:38:30 +02:00
dd3bbf1d5b - Re-added win libs 2024-07-11 23:48:45 +02:00
38080703ec - Deleted ignored folders 2024-07-11 23:47:43 +02:00
fe582c4fba - Added build configurations
- Configured csprojects
- CopyLibs functionality in builder
2024-07-11 23:46:32 +02:00
max
42b978e8c9 working on window handling 2024-07-10 23:18:56 +02:00
max
2c839d8fad Rename and mouse cursor support 2024-07-10 21:50:04 +02:00
97c2b308f1 Added builder
Added shader importer
2024-07-06 23:33:04 +02:00
max
1eb899b240 gui events
fix scroll input
handle gui side, move and closed events
2024-07-06 01:29:12 +02:00
max
7cbb745721 fix library and input 2024-07-05 23:22:11 +02:00
max
1e1ed303ad Added ImGui.NET
Start working on controller.
2024-07-05 21:56:14 +02:00
74 changed files with 2167 additions and 1013 deletions

9
.gitignore vendored
View File

@ -451,8 +451,13 @@ FodyWeavers.xsd
#------------------------- Nerfed ------------------------- #------------------------- Nerfed -------------------------
Bin/
Intermediate/
imgui.ini imgui.ini
# include libs # include libs
!/libs/lib64 !/Native/lib64
!/libs/x64 !/Native/x64

3
.gitmodules vendored
View File

@ -13,3 +13,6 @@
[submodule "Nerfed.Runtime/Libraries/dav1dfile"] [submodule "Nerfed.Runtime/Libraries/dav1dfile"]
path = Nerfed.Runtime/Libraries/dav1dfile path = Nerfed.Runtime/Libraries/dav1dfile
url = https://github.com/MoonsideGames/dav1dfile.git url = https://github.com/MoonsideGames/dav1dfile.git
[submodule "Nerfed.Runtime/Libraries/ImGui.NET"]
path = Nerfed.Runtime/Libraries/ImGui.NET
url = https://github.com/ImGuiNET/ImGui.NET.git

View File

@ -2,5 +2,11 @@
<project version="4"> <project version="4">
<component name="VcsDirectoryMappings"> <component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" /> <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/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> </component>
</project> </project>

7
Directory.Build.props Normal file
View File

@ -0,0 +1,7 @@
<Project>
<PropertyGroup>
<OutDir>../Bin/$(MSBuildProjectName)</OutDir>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">../Intermediate/$(MSBuildProjectName)</BaseIntermediateOutputPath>
</PropertyGroup>
</Project>

9
LICENSE Normal file
View File

@ -0,0 +1,9 @@
MIT License
Copyright (c) 2024 Nerfed Engine
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

BIN
Native/x64/cimgui.dll (Stored with Git LFS) Normal file

Binary file not shown.

View 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;
}
}

View File

@ -0,0 +1,11 @@
namespace Nerfed.Builder;
public class ArgumentAttribute : Attribute
{
public string ArgKey { get; }
public ArgumentAttribute(string argKey)
{
ArgKey = argKey;
}
}

View 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; }
}

View 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() { }
}

View 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;
}
}

View File

@ -0,0 +1,6 @@
namespace Nerfed.Builder;
public interface IImporter
{
void Import(string inFile, string outFile);
}

View File

@ -0,0 +1,9 @@
namespace Nerfed.Builder;
public class RawFileImporter : IImporter
{
public void Import(string inFile, string outFile)
{
FileUtil.Copy(inFile, outFile);
}
}

View 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));
}
}
}

View 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>

View 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>

View File

@ -0,0 +1,6 @@
namespace Nerfed.Builder;
public class PackageArgs
{
}

View File

@ -0,0 +1,12 @@
namespace Nerfed.Builder;
public class Packager : IDisposable
{
public void Run(PackageArgs args)
{
}
public void Dispose()
{
}
}

View File

@ -0,0 +1,6 @@
namespace Nerfed.Builder;
public static class PathUtil
{
public const string ImportedFileExtension = ".bin";
}

70
Nerfed.Builder/Program.cs Normal file
View 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;
}
}

View 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>

View File

@ -0,0 +1,71 @@
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();
}
}
}

View File

@ -0,0 +1,34 @@
<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' ">
</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="&quot;$(ProjectDir)../Bin/Nerfed.Builder/Nerfed.Builder&quot; -build -resourcePath &quot;$(ProjectDir)Resources&quot; -resourceOutPath &quot;$(TargetDir)Resources&quot; " />
</Target>
</Project>

42
Nerfed.Editor/Program.cs Normal file
View File

@ -0,0 +1,42 @@
using Nerfed.Runtime;
namespace Nerfed.Editor;
internal class Program
{
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()
{
// Open project.
// Setip EditorGui.
EditorGui.Initialize();
}
private static void HandleOnUpdate()
{
// Editor Update.
EditorGui.Update();
// Try Catch UserCode Update.
}
private static void HandleOnRender()
{
EditorGui.Render();
}
private static void HandleOnQuit()
{
EditorGui.Quit();
}
}

View 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);
}

View File

@ -0,0 +1,13 @@
#version 450
layout (location = 0) in vec4 color;
layout (location = 1) in vec2 texCoord;
layout(set = 2, binding = 0) uniform sampler2D Sampler;
layout (location = 0) out vec4 outputColor;
void main()
{
outputColor = color * texture(Sampler, texCoord);
}

View File

@ -0,0 +1,20 @@
#version 450
layout (location = 0) in vec2 in_position;
layout (location = 1) in vec2 in_texCoord;
layout (location = 2) in vec4 in_color;
layout (set = 1, binding = 0) uniform ProjectionMatrixBuffer
{
mat4 projection_matrix;
};
layout (location = 0) out vec4 color;
layout (location = 1) out vec2 texCoord;
void main()
{
gl_Position = projection_matrix * vec4(in_position, 0, 1);
color = in_color;
texCoord = in_texCoord;
}

View 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);
}

View 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;
}

View 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;
}

Binary file not shown.

View File

@ -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>

View File

@ -1,12 +1,17 @@
using System.Diagnostics;
using Nerfed.Runtime.Audio; using Nerfed.Runtime.Audio;
using Nerfed.Runtime.Graphics; using Nerfed.Runtime.Graphics;
using SDL2; using SDL2;
using System.Diagnostics;
namespace Nerfed.Runtime; namespace Nerfed.Runtime;
public static class Engine 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 TimeSpan MaxDeltaTime { get; set; } = TimeSpan.FromMilliseconds(100);
public static bool VSync { get; set; } public static bool VSync { get; set; }
@ -39,7 +44,7 @@ public static class Engine
private const string WindowTitle = "Nerfed"; private const string WindowTitle = "Nerfed";
//.. //..
internal static void Run(string[] args) public static void Run(string[] args)
{ {
Timestep = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / TargetTimestep); Timestep = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / TargetTimestep);
gameTimer = Stopwatch.StartNew(); gameTimer = Stopwatch.StartNew();
@ -56,6 +61,7 @@ internal static void Run(string[] args)
} }
GraphicsDevice = new GraphicsDevice(BackendFlags.All); GraphicsDevice = new GraphicsDevice(BackendFlags.All);
GraphicsDevice.LoadDefaultPipelines();
MainWindow = new Window(GraphicsDevice, new WindowCreateInfo(WindowTitle, WindowWidth, WindowHeight, ScreenMode.Windowed)); MainWindow = new Window(GraphicsDevice, new WindowCreateInfo(WindowTitle, WindowWidth, WindowHeight, ScreenMode.Windowed));
if (!GraphicsDevice.ClaimWindow(MainWindow, SwapchainComposition.SDR, VSync ? PresentMode.VSync : PresentMode.Mailbox)) if (!GraphicsDevice.ClaimWindow(MainWindow, SwapchainComposition.SDR, VSync ? PresentMode.VSync : PresentMode.Mailbox))
@ -65,11 +71,15 @@ internal static void Run(string[] args)
AudioDevice = new AudioDevice(); AudioDevice = new AudioDevice();
OnInitialize?.Invoke();
while (!quit) while (!quit)
{ {
Tick(); Tick();
} }
OnQuit?.Invoke();
GraphicsDevice.UnclaimWindow(MainWindow); GraphicsDevice.UnclaimWindow(MainWindow);
MainWindow.Dispose(); MainWindow.Dispose();
GraphicsDevice.Dispose(); GraphicsDevice.Dispose();
@ -146,6 +156,7 @@ private static void Tick()
ProcessSDLEvents(); ProcessSDLEvents();
// Tick game here... // Tick game here...
OnUpdate?.Invoke();
AudioDevice.WakeThread(); AudioDevice.WakeThread();
accumulatedUpdateTime -= Timestep; accumulatedUpdateTime -= Timestep;
@ -154,6 +165,7 @@ private static void Tick()
double alpha = accumulatedUpdateTime / Timestep; double alpha = accumulatedUpdateTime / Timestep;
// Render here.. // Render here..
OnRender?.Invoke();
accumulatedDrawTime -= framerateCapTimeSpan; accumulatedDrawTime -= framerateCapTimeSpan;
} }

View File

@ -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,
];
}

View File

@ -1,6 +1,6 @@
using System.Runtime.InteropServices; using Nerfed.Runtime.Video;
using Nerfed.Runtime.Video;
using RefreshCS; using RefreshCS;
using System.Runtime.InteropServices;
namespace Nerfed.Runtime.Graphics; namespace Nerfed.Runtime.Graphics;
@ -13,12 +13,16 @@ public class GraphicsDevice : IDisposable
public BackendFlags Backend { get; } public BackendFlags Backend { get; }
public bool DebugMode { 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 // Built-in video pipeline
internal GraphicsPipeline VideoPipeline { get; } internal GraphicsPipeline VideoPipeline { get; private set; }
// Built-in text shader info // Built-in text shader info
public Shader TextVertexShader;
public Shader TextFragmentShader;
public VertexInputState TextVertexInputState { get; } public VertexInputState TextVertexInputState { get; }
// Built-in samplers // Built-in samplers
@ -53,85 +57,21 @@ internal GraphicsDevice(BackendFlags preferredBackends)
Backend = (BackendFlags)Refresh.Refresh_GetBackend(Handle); Backend = (BackendFlags)Refresh.Refresh_GetBackend(Handle);
IEmbeddedShaders embeddedShaders; TextVertexInputState = VertexInputState.CreateSingleBinding<FontVertex>();
switch (Backend)
{ PointSampler = new Sampler(this, SamplerCreateInfo.PointClamp);
case BackendFlags.Vulkan: LinearSampler = new Sampler(this, SamplerCreateInfo.LinearClamp);
embeddedShaders = new EmbeddedShadersSpirV();
break; fencePool = new FencePool(this);
case BackendFlags.D3D11: commandBufferPool = new CommandBufferPool(this);
throw new NotImplementedException("D3D11 embedded shaders");
break;
case BackendFlags.Metal:
throw new NotImplementedException("Metal embedded shaders");
break;
default: throw new ArgumentOutOfRangeException();
} }
Shader fullscreenVertShader; internal void LoadDefaultPipelines()
Shader textVertShader;
Shader textFragShader;
Shader videoFragShader;
using (MemoryStream fullscreenVertStream = new MemoryStream(embeddedShaders.FullscreenVert))
{ {
fullscreenVertShader = new Shader( FullscreenVertexShader = ResourceManager.Load<Shader>("Shaders/Fullscreen.vert");
this, VideoFragmentShader = ResourceManager.Load<Shader>("Shaders/Video.frag");
fullscreenVertStream, TextVertexShader = ResourceManager.Load<Shader>("Shaders/Text.vert");
"main", TextFragmentShader = ResourceManager.Load<Shader>("Shaders/Text.frag");
new ShaderCreateInfo
{
ShaderStage = ShaderStage.Vertex,
ShaderFormat = embeddedShaders.ShaderFormat
}
);
}
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
}
);
}
VideoPipeline = new GraphicsPipeline( VideoPipeline = new GraphicsPipeline(
this, this,
@ -144,25 +84,14 @@ internal GraphicsDevice(BackendFlags preferredBackends)
) )
), ),
DepthStencilState = DepthStencilState.Disable, DepthStencilState = DepthStencilState.Disable,
VertexShader = fullscreenVertShader, VertexShader = FullscreenVertexShader,
FragmentShader = videoFragShader, FragmentShader = VideoFragmentShader,
VertexInputState = VertexInputState.Empty, VertexInputState = VertexInputState.Empty,
RasterizerState = RasterizerState.CCW_CullNone, RasterizerState = RasterizerState.CCW_CullNone,
PrimitiveType = PrimitiveType.TriangleList, PrimitiveType = PrimitiveType.TriangleList,
MultisampleState = MultisampleState.None 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> /// <summary>
@ -443,6 +372,11 @@ private void Dispose(bool disposing)
resources.Clear(); resources.Clear();
} }
ResourceManager.Unload(FullscreenVertexShader);
ResourceManager.Unload(TextFragmentShader);
ResourceManager.Unload(TextVertexShader);
ResourceManager.Unload(VideoFragmentShader);
} }
Refresh.Refresh_DestroyDevice(Handle); Refresh.Refresh_DestroyDevice(Handle);

View File

@ -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; }
}

View File

@ -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;
}
}

View File

@ -0,0 +1,50 @@
using System.Runtime.InteropServices;
using System.Text;
namespace Nerfed.Runtime.Gui;
public static unsafe class GuiClipboard
{
private static IntPtr clipboard;
private static readonly Dictionary<Delegate, IntPtr> pinned = new Dictionary<Delegate, IntPtr>();
public static readonly IntPtr GetFnPtr = GetPointerTo(Get);
public static readonly IntPtr SetFnPtr = GetPointerTo(Set);
private static unsafe void Set(void* userdata, byte* text)
{
int len = 0; while (text[len] != 0) len++;
string str = Encoding.UTF8.GetString(text, len);
SDL2.SDL.SDL_SetClipboardText(str);
}
private static unsafe byte* Get(void* userdata)
{
if (clipboard != IntPtr.Zero)
{
NativeMemory.Free((void*) clipboard);
clipboard = IntPtr.Zero;
}
string str = SDL2.SDL.SDL_GetClipboardText();
int length = Encoding.UTF8.GetByteCount(str);
byte* bytes = (byte*)(clipboard = (nint)NativeMemory.Alloc((nuint)(length + 1)));
Encoding.UTF8.GetBytes(str, new Span<byte>(bytes, length));
bytes[length] = 0;
return bytes;
}
// Stops the delegate pointer from being collected
private static IntPtr GetPointerTo<T>(T fn) where T : Delegate
{
if (pinned.TryGetValue(fn, out nint ptr))
{
return ptr;
}
ptr = Marshal.GetFunctionPointerForDelegate(fn);
pinned.Add(fn, ptr);
return ptr;
}
}

View File

@ -0,0 +1,639 @@
// ImGuiController with docking and viewport support for MoonWorks/Refresh.
// Based on the example im ImGui.NET and MoonWorksDearImGuiScaffold.
using ImGuiNET;
using Nerfed.Runtime.Graphics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Nerfed.Runtime.Gui;
public class GuiController : IDisposable
{
public event Action OnGui;
private readonly string shaderContentPath = Path.Combine(System.AppContext.BaseDirectory, "Content", "Shaders");
private readonly GraphicsDevice graphicsDevice;
private readonly Window mainWindow;
private readonly Color clearColor;
private readonly Platform_CreateWindow createWindow;
private readonly Platform_DestroyWindow destroyWindow;
private readonly Platform_GetWindowPos getWindowPos;
private readonly Platform_ShowWindow showWindow;
private readonly Platform_SetWindowPos setWindowPos;
private readonly Platform_SetWindowSize setWindowSize;
private readonly Platform_GetWindowSize getWindowSize;
private readonly Platform_SetWindowFocus setWindowFocus;
private readonly Platform_GetWindowFocus getWindowFocus;
private readonly Platform_GetWindowMinimized getWindowMinimized;
private readonly Platform_SetWindowTitle setWindowTitle;
private readonly ResourceUploader resourceUploader;
private readonly GraphicsPipeline imGuiPipeline;
private readonly Shader imGuiVertexShader;
private readonly Shader imGuiFragmentShader;
private readonly Sampler imGuiSampler;
private readonly GuiTextureStorage textureStorage = new GuiTextureStorage();
private readonly GuiViewportWindow mainViewportWindow;
private Texture fontTexture = null;
private uint vertexCount = 0;
private uint indexCount = 0;
private Graphics.Buffer imGuiVertexBuffer = null;
private Graphics.Buffer imGuiIndexBuffer = null;
private bool frameBegun = false;
public GuiController(GraphicsDevice graphicsDevice, Window mainWindow, Color clearColor, ImGuiConfigFlags configFlags = ImGuiConfigFlags.NavEnableKeyboard | ImGuiConfigFlags.DockingEnable | ImGuiConfigFlags.ViewportsEnable)
{
this.graphicsDevice = graphicsDevice;
this.mainWindow = mainWindow;
this.clearColor = clearColor;
resourceUploader = new ResourceUploader(graphicsDevice);
ImGui.CreateContext();
ImGuiIOPtr io = ImGui.GetIO();
io.DisplaySize = new Vector2(mainWindow.Width, mainWindow.Height);
io.DisplayFramebufferScale = Vector2.One;
imGuiVertexShader = ResourceManager.Load<Shader>("Shaders/ImGui.vert");
imGuiFragmentShader = ResourceManager.Load<Shader>("Shaders/ImGui.frag");
imGuiSampler = new Sampler(graphicsDevice, SamplerCreateInfo.LinearClamp);
imGuiPipeline = new GraphicsPipeline(
graphicsDevice,
new GraphicsPipelineCreateInfo
{
AttachmentInfo = new GraphicsPipelineAttachmentInfo(
new ColorAttachmentDescription(
mainWindow.SwapchainFormat,
ColorAttachmentBlendState.NonPremultiplied
)
),
DepthStencilState = DepthStencilState.Disable,
MultisampleState = MultisampleState.None,
PrimitiveType = PrimitiveType.TriangleList,
RasterizerState = RasterizerState.CW_CullNone,
VertexInputState = VertexInputState.CreateSingleBinding<Position2DTextureColorVertex>(),
VertexShader = imGuiVertexShader,
FragmentShader = imGuiFragmentShader,
}
);
BuildFontAtlas();
io.ConfigFlags = configFlags;
if (!OperatingSystem.IsWindows())
{
io.SetClipboardTextFn = GuiClipboard.SetFnPtr;
io.GetClipboardTextFn = GuiClipboard.GetFnPtr;
}
ImGuiPlatformIOPtr platformIO = ImGui.GetPlatformIO();
ImGuiViewportPtr mainViewport = platformIO.Viewports[0];
mainViewport.PlatformHandle = mainWindow.Handle;
mainViewportWindow = new GuiViewportWindow(graphicsDevice, mainViewport, mainWindow);
unsafe
{
createWindow = CreateWindow;
destroyWindow = DestroyWindow;
getWindowPos = GetWindowPos;
showWindow = ShowWindow;
setWindowPos = SetWindowPos;
setWindowSize = SetWindowSize;
getWindowSize = GetWindowSize;
setWindowFocus = SetWindowFocus;
getWindowFocus = GetWindowFocus;
getWindowMinimized = GetWindowMinimized;
setWindowTitle = SetWindowTitle;
platformIO.Platform_CreateWindow = Marshal.GetFunctionPointerForDelegate(createWindow);
platformIO.Platform_DestroyWindow = Marshal.GetFunctionPointerForDelegate(destroyWindow);
platformIO.Platform_ShowWindow = Marshal.GetFunctionPointerForDelegate(showWindow);
platformIO.Platform_SetWindowPos = Marshal.GetFunctionPointerForDelegate(setWindowPos);
platformIO.Platform_SetWindowSize = Marshal.GetFunctionPointerForDelegate(setWindowSize);
platformIO.Platform_SetWindowFocus = Marshal.GetFunctionPointerForDelegate(setWindowFocus);
platformIO.Platform_GetWindowFocus = Marshal.GetFunctionPointerForDelegate(getWindowFocus);
platformIO.Platform_GetWindowMinimized = Marshal.GetFunctionPointerForDelegate(getWindowMinimized);
platformIO.Platform_SetWindowTitle = Marshal.GetFunctionPointerForDelegate(setWindowTitle);
ImGuiNative.ImGuiPlatformIO_Set_Platform_GetWindowPos(platformIO.NativePtr, Marshal.GetFunctionPointerForDelegate(getWindowPos));
ImGuiNative.ImGuiPlatformIO_Set_Platform_GetWindowSize(platformIO.NativePtr, Marshal.GetFunctionPointerForDelegate(getWindowSize));
}
io.BackendFlags |= ImGuiBackendFlags.HasMouseCursors;
io.BackendFlags |= ImGuiBackendFlags.HasSetMousePos;
io.BackendFlags |= ImGuiBackendFlags.PlatformHasViewports;
io.BackendFlags |= ImGuiBackendFlags.RendererHasViewports;
UpdatePerFrameImGuiData(1.0 / 60.0);
ImGui.NewFrame();
frameBegun = true;
}
public void Update(double deltaTime)
{
if (frameBegun)
{
ImGui.Render();
ImGui.UpdatePlatformWindows();
}
UpdatePerFrameImGuiData(deltaTime);
UpdateInput();
UpdateCursor();
UpdateMonitors();
frameBegun = true;
ImGui.NewFrame();
OnGui?.Invoke();
ImGui.EndFrame();
}
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 = (float)deltaSeconds; // DeltaTime is in seconds.
}
private void UpdateInput()
{
ImGuiIOPtr io = ImGui.GetIO();
if ((ImGui.GetIO().ConfigFlags & ImGuiConfigFlags.ViewportsEnable) != 0)
{
// For viewports we use the global mouse position.
_ = SDL2.SDL.SDL_GetGlobalMouseState(out int x, out int y);
io.MousePos = new Vector2(x, y);
}
else
{
// Without viewports we need to use the relative position.
//_ = SDL2.SDL.SDL_GetMouseState(out int x, out int y);
io.MousePos = Mouse.Position;
}
io.MouseDown[0] = Mouse.IsButtonDown(MouseButton.Left);
io.MouseDown[1] = Mouse.IsButtonDown(MouseButton.Right);
io.MouseDown[2] = Mouse.IsButtonDown(MouseButton.Middle);
io.MouseWheel = Mouse.GetWheel();
io.AddKeyEvent(ImGuiKey.A, Keyboard.IsKeyDown(Key.A));
io.AddKeyEvent(ImGuiKey.Z, Keyboard.IsKeyDown(Key.Z));
io.AddKeyEvent(ImGuiKey.Y, Keyboard.IsKeyDown(Key.Y));
io.AddKeyEvent(ImGuiKey.X, Keyboard.IsKeyDown(Key.X));
io.AddKeyEvent(ImGuiKey.C, Keyboard.IsKeyDown(Key.C));
io.AddKeyEvent(ImGuiKey.V, Keyboard.IsKeyDown(Key.V));
io.AddKeyEvent(ImGuiKey.Tab, Keyboard.IsKeyDown(Key.Tab));
io.AddKeyEvent(ImGuiKey.LeftArrow, Keyboard.IsKeyDown(Key.Left));
io.AddKeyEvent(ImGuiKey.RightArrow, Keyboard.IsKeyDown(Key.Right));
io.AddKeyEvent(ImGuiKey.UpArrow, Keyboard.IsKeyDown(Key.Up));
io.AddKeyEvent(ImGuiKey.DownArrow, Keyboard.IsKeyDown(Key.Down));
io.AddKeyEvent(ImGuiKey.Enter, Keyboard.IsKeyDown(Key.Enter));
io.AddKeyEvent(ImGuiKey.Escape, Keyboard.IsKeyDown(Key.Escape));
io.AddKeyEvent(ImGuiKey.Delete, Keyboard.IsKeyDown(Key.Delete));
io.AddKeyEvent(ImGuiKey.Backspace, Keyboard.IsKeyDown(Key.Backspace));
io.AddKeyEvent(ImGuiKey.Home, Keyboard.IsKeyDown(Key.Home));
io.AddKeyEvent(ImGuiKey.End, Keyboard.IsKeyDown(Key.End));
io.AddKeyEvent(ImGuiKey.PageDown, Keyboard.IsKeyDown(Key.PageDown));
io.AddKeyEvent(ImGuiKey.PageUp, Keyboard.IsKeyDown(Key.PageUp));
io.AddKeyEvent(ImGuiKey.Insert, Keyboard.IsKeyDown(Key.Insert));
io.AddKeyEvent(ImGuiKey.ModCtrl, Keyboard.IsKeyDown(Key.LeftControl) || Keyboard.IsKeyDown(Key.RightControl));
io.AddKeyEvent(ImGuiKey.ModShift, Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift));
io.AddKeyEvent(ImGuiKey.ModAlt, Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt));
io.AddKeyEvent(ImGuiKey.ModSuper, Keyboard.IsKeyDown(Key.LeftSuper) || Keyboard.IsKeyDown(Key.RightSuper));
ReadOnlySpan<char> input = Keyboard.GetTextInput();
if (!input.IsEmpty)
{
foreach (char c in input)
{
if (c == '\t')
{
break;
}
io.AddInputCharacter(c);
}
}
}
private void UpdateCursor()
{
ImGuiIOPtr io = ImGui.GetIO();
if ((io.ConfigFlags & ImGuiConfigFlags.NoMouseCursorChange) != 0)
{
return;
}
ImGuiMouseCursor imGuiCursor = ImGui.GetMouseCursor();
if (imGuiCursor == ImGuiMouseCursor.None || io.MouseDrawCursor)
{
_ = SDL2.SDL.SDL_ShowCursor(0);
}
else
{
nint sdlCursor = imGuiCursor switch
{
ImGuiMouseCursor.Arrow => SDL2.SDL.SDL_CreateSystemCursor(SDL2.SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_ARROW),
ImGuiMouseCursor.TextInput => SDL2.SDL.SDL_CreateSystemCursor(SDL2.SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_IBEAM),
ImGuiMouseCursor.ResizeAll => SDL2.SDL.SDL_CreateSystemCursor(SDL2.SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZEALL),
ImGuiMouseCursor.ResizeNS => SDL2.SDL.SDL_CreateSystemCursor(SDL2.SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZENS),
ImGuiMouseCursor.ResizeEW => SDL2.SDL.SDL_CreateSystemCursor(SDL2.SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZEWE),
ImGuiMouseCursor.ResizeNESW => SDL2.SDL.SDL_CreateSystemCursor(SDL2.SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZENESW),
ImGuiMouseCursor.ResizeNWSE => SDL2.SDL.SDL_CreateSystemCursor(SDL2.SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZENWSE),
ImGuiMouseCursor.Hand => SDL2.SDL.SDL_CreateSystemCursor(SDL2.SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_HAND),
ImGuiMouseCursor.NotAllowed => SDL2.SDL.SDL_CreateSystemCursor(SDL2.SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_NO),
_ => SDL2.SDL.SDL_CreateSystemCursor(SDL2.SDL.SDL_SystemCursor.SDL_SYSTEM_CURSOR_ARROW),
};
SDL2.SDL.SDL_SetCursor(sdlCursor);
_ = SDL2.SDL.SDL_ShowCursor(1);
}
}
private unsafe void UpdateMonitors()
{
ImGuiPlatformIOPtr platformIO = ImGui.GetPlatformIO();
Marshal.FreeHGlobal(platformIO.NativePtr->Monitors.Data);
int videoDisplayCount = SDL2.SDL.SDL_GetNumVideoDisplays();
IntPtr data = Marshal.AllocHGlobal(Unsafe.SizeOf<ImGuiPlatformMonitor>() * videoDisplayCount);
platformIO.NativePtr->Monitors = new ImVector(videoDisplayCount, videoDisplayCount, data);
for (int i = 0; i < videoDisplayCount; i++)
{
_ = SDL2.SDL.SDL_GetDisplayUsableBounds(i, out SDL2.SDL.SDL_Rect usableBounds);
_ = SDL2.SDL.SDL_GetDisplayBounds(i, out SDL2.SDL.SDL_Rect bounds);
_ = SDL2.SDL.SDL_GetDisplayDPI(i, out float ddpi, out float hdpi, out float vdpi);
ImGuiPlatformMonitorPtr monitor = platformIO.Monitors[i];
float standardDpi = 96f; // Standard DPI typically used
monitor.DpiScale = hdpi / standardDpi;
monitor.MainPos = new Vector2(bounds.x, bounds.y);
monitor.MainSize = new Vector2(bounds.w, bounds.h);
monitor.WorkPos = new Vector2(usableBounds.x, usableBounds.y);
monitor.WorkSize = new Vector2(usableBounds.w, usableBounds.h);
}
}
public void Render()
{
if (!frameBegun)
{
return;
}
frameBegun = false;
if ((ImGui.GetIO().ConfigFlags & ImGuiConfigFlags.ViewportsEnable) != 0)
{
ImGui.Render();
ImGui.UpdatePlatformWindows();
ImGuiPlatformIOPtr platformIO = ImGui.GetPlatformIO();
for (int i = 0; i < platformIO.Viewports.Size; i++)
{
ImGuiViewportPtr vp = platformIO.Viewports[i];
GuiViewportWindow window = (GuiViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target;
if (!window.Window.Claimed)
{
continue;
}
UpdateImGuiBuffers(vp.DrawData);
CommandBuffer commandBuffer = graphicsDevice.AcquireCommandBuffer();
Texture swapchainTexture = commandBuffer.AcquireSwapchainTexture(window.Window);
if (swapchainTexture != null)
{
RenderCommandLists(commandBuffer, swapchainTexture, vp.DrawData);
graphicsDevice.Submit(commandBuffer);
//graphicsDevice.Wait();
}
}
}
else
{
ImGui.Render();
if (!mainWindow.Claimed)
{
return;
}
ImDrawDataPtr drawDataPtr = ImGui.GetDrawData();
UpdateImGuiBuffers(drawDataPtr);
CommandBuffer commandBuffer = graphicsDevice.AcquireCommandBuffer();
Texture swapchainTexture = commandBuffer.AcquireSwapchainTexture(mainWindow);
if (swapchainTexture != null)
{
RenderCommandLists(commandBuffer, swapchainTexture, drawDataPtr);
graphicsDevice.Submit(commandBuffer);
//graphicsDevice.Wait();
}
}
}
private unsafe void UpdateImGuiBuffers(ImDrawDataPtr drawDataPtr)
{
if (drawDataPtr.TotalVtxCount == 0 || drawDataPtr.CmdListsCount == 0)
{
return;
}
if (drawDataPtr.TotalVtxCount > vertexCount)
{
imGuiVertexBuffer?.Dispose();
vertexCount = (uint)(drawDataPtr.TotalVtxCount * 1.5f);
imGuiVertexBuffer = Graphics.Buffer.Create<Position2DTextureColorVertex>(
graphicsDevice,
BufferUsageFlags.Vertex,
vertexCount
);
}
if (drawDataPtr.TotalIdxCount > indexCount)
{
imGuiIndexBuffer?.Dispose();
indexCount = (uint)(drawDataPtr.TotalIdxCount * 1.5f);
imGuiIndexBuffer = Graphics.Buffer.Create<ushort>(
graphicsDevice,
BufferUsageFlags.Index,
indexCount
);
}
uint vertexOffset = 0;
uint indexOffset = 0;
for (int n = 0; n < drawDataPtr.CmdListsCount; n++)
{
ImDrawListPtr cmdList = drawDataPtr.CmdLists[n];
resourceUploader.SetBufferData(
imGuiVertexBuffer,
vertexOffset,
new Span<Position2DTextureColorVertex>(cmdList.VtxBuffer.Data.ToPointer(), cmdList.VtxBuffer.Size),
n == 0
);
resourceUploader.SetBufferData(
imGuiIndexBuffer,
indexOffset,
new Span<ushort>(cmdList.IdxBuffer.Data.ToPointer(), cmdList.IdxBuffer.Size),
n == 0
);
vertexOffset += (uint)cmdList.VtxBuffer.Size;
indexOffset += (uint)cmdList.IdxBuffer.Size;
}
resourceUploader.Upload();
}
private void RenderCommandLists(CommandBuffer commandBuffer, Texture renderTexture, ImDrawDataPtr drawDataPtr)
{
Vector2 pos = drawDataPtr.DisplayPos;
RenderPass renderPass = commandBuffer.BeginRenderPass(
new ColorAttachmentInfo(renderTexture, false, clearColor)
);
renderPass.BindGraphicsPipeline(imGuiPipeline);
// It is possible that the buffers are null (for example nothing is in our main windows viewport, then we exixt early but still clear it).
if (imGuiVertexBuffer == null || imGuiIndexBuffer == null)
{
commandBuffer.EndRenderPass(renderPass);
return;
}
Matrix4x4 projectionMatrix = Matrix4x4.CreateOrthographicOffCenter(
pos.X,
pos.X + drawDataPtr.DisplaySize.X,
pos.Y + drawDataPtr.DisplaySize.Y,
pos.Y,
-1.0f,
1.0f
);
TransformVertexUniform vertexUniform = new TransformVertexUniform(projectionMatrix);
renderPass.BindVertexBuffer(imGuiVertexBuffer);
renderPass.BindIndexBuffer(imGuiIndexBuffer, IndexElementSize.Sixteen);
commandBuffer.PushVertexUniformData(in vertexUniform);
uint vertexOffset = 0;
uint indexOffset = 0;
for (int n = 0; n < drawDataPtr.CmdListsCount; n++)
{
ImDrawListPtr cmdList = drawDataPtr.CmdLists[n];
for (int cmdIndex = 0; cmdIndex < cmdList.CmdBuffer.Size; cmdIndex++)
{
ImDrawCmdPtr drawCmd = cmdList.CmdBuffer[cmdIndex];
Texture texture = textureStorage.GetTexture(drawCmd.TextureId);
if (texture == null)
{
Log.Error("Texture or drawCmd.TextureId became null. Fit it!");
continue;
}
renderPass.BindFragmentSampler(new TextureSamplerBinding(texture, imGuiSampler));
float width = drawCmd.ClipRect.Z - (int)drawCmd.ClipRect.X;
float height = drawCmd.ClipRect.W - (int)drawCmd.ClipRect.Y;
if (width <= 0 || height <= 0)
{
continue;
}
renderPass.SetScissor(
new Rect(
(int)drawCmd.ClipRect.X - (int)pos.X,
(int)drawCmd.ClipRect.Y - (int)pos.Y,
(int)drawCmd.ClipRect.Z - (int)drawCmd.ClipRect.X,
(int)drawCmd.ClipRect.W - (int)drawCmd.ClipRect.Y
)
);
renderPass.DrawIndexedPrimitives(vertexOffset, indexOffset, drawCmd.ElemCount / 3);
indexOffset += drawCmd.ElemCount;
}
vertexOffset += (uint)cmdList.VtxBuffer.Size;
}
commandBuffer.EndRenderPass(renderPass);
}
#region Resources
private unsafe void BuildFontAtlas()
{
ResourceUploader resourceUploader = new ResourceUploader(graphicsDevice);
ImGuiIOPtr io = ImGui.GetIO();
io.Fonts.GetTexDataAsRGBA32(
out nint pixelData,
out int width,
out int height,
out int bytesPerPixel
);
Texture fontTexture = resourceUploader.CreateTexture2D(
new Span<byte>((void*)pixelData, width * height * bytesPerPixel),
(uint)width,
(uint)height
);
resourceUploader.Upload();
resourceUploader.Dispose();
io.Fonts.SetTexID(fontTexture.Handle);
io.Fonts.ClearTexData();
textureStorage.Add(fontTexture); // <-- The fontTexture seems to get lost after some time (CG?).
this.fontTexture = fontTexture; // <-- So we also keep a reference to make sure it doesn't happen.
}
#endregion
#region Window
private void CreateWindow(ImGuiViewportPtr vp)
{
GuiViewportWindow window = new GuiViewportWindow(graphicsDevice, vp);
}
private void DestroyWindow(ImGuiViewportPtr vp)
{
if (vp.PlatformUserData == IntPtr.Zero) return;
GuiViewportWindow window = (GuiViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target;
window.Dispose();
vp.PlatformUserData = IntPtr.Zero;
}
private void ShowWindow(ImGuiViewportPtr vp)
{
if (vp.PlatformUserData == IntPtr.Zero) return;
GuiViewportWindow window = (GuiViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target;
SDL2.SDL.SDL_ShowWindow(window.Window.Handle);
}
private unsafe void GetWindowPos(ImGuiViewportPtr vp, Vector2* outPos)
{
if (vp.PlatformUserData == IntPtr.Zero) return;
GuiViewportWindow window = (GuiViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target;
SDL2.SDL.SDL_GetWindowPosition(window.Window.Handle, out int x, out int y);
*outPos = new Vector2(x, y);
}
private void SetWindowPos(ImGuiViewportPtr vp, Vector2 pos)
{
if (vp.PlatformUserData == IntPtr.Zero) return;
GuiViewportWindow window = (GuiViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target;
SDL2.SDL.SDL_SetWindowPosition(window.Window.Handle, (int)pos.X, (int)pos.Y);
}
private void SetWindowSize(ImGuiViewportPtr vp, Vector2 size)
{
if (vp.PlatformUserData == IntPtr.Zero) return;
GuiViewportWindow window = (GuiViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target;
SDL2.SDL.SDL_SetWindowSize(window.Window.Handle, (int)size.X, (int)size.Y);
}
private unsafe void GetWindowSize(ImGuiViewportPtr vp, Vector2* outSize)
{
if (vp.PlatformUserData == IntPtr.Zero) return;
GuiViewportWindow window = (GuiViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target;
SDL2.SDL.SDL_GetWindowSize(window.Window.Handle, out int w, out int h);
*outSize = new Vector2(w, h);
}
private void SetWindowFocus(ImGuiViewportPtr vp)
{
if (vp.PlatformUserData == IntPtr.Zero) return;
GuiViewportWindow window = (GuiViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target;
//SDL2.SDL.SDL_SetWindowInputFocus(window.Handle);
SDL2.SDL.SDL_RaiseWindow(window.Window.Handle);
}
private byte GetWindowFocus(ImGuiViewportPtr vp)
{
if (vp.PlatformUserData == IntPtr.Zero) return (byte)0;
GuiViewportWindow window = (GuiViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target;
SDL2.SDL.SDL_WindowFlags flags = (SDL2.SDL.SDL_WindowFlags)SDL2.SDL.SDL_GetWindowFlags(window.Window.Handle);
return (flags & SDL2.SDL.SDL_WindowFlags.SDL_WINDOW_INPUT_FOCUS) != 0 ? (byte)1 : (byte)0;
}
private byte GetWindowMinimized(ImGuiViewportPtr vp)
{
if (vp.PlatformUserData == IntPtr.Zero) return 0;
GuiViewportWindow window = (GuiViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target;
SDL2.SDL.SDL_WindowFlags flags = (SDL2.SDL.SDL_WindowFlags)SDL2.SDL.SDL_GetWindowFlags(window.Window.Handle);
return (flags & SDL2.SDL.SDL_WindowFlags.SDL_WINDOW_MINIMIZED) != 0 ? (byte)1 : (byte)0;
}
private unsafe void SetWindowTitle(ImGuiViewportPtr vp, IntPtr title)
{
if (vp.PlatformUserData == IntPtr.Zero) return;
GuiViewportWindow window = (GuiViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target;
byte* titlePtr = (byte*)title;
int count = 0;
while (titlePtr[count] != 0)
{
count += 1;
}
SDL2.SDL.SDL_SetWindowTitle(window.Window.Handle, System.Text.Encoding.ASCII.GetString(titlePtr, count));
}
#endregion
public void Dispose()
{
fontTexture?.Dispose();
imGuiVertexBuffer?.Dispose();
imGuiIndexBuffer?.Dispose();
ResourceManager.Unload(imGuiVertexShader);
ResourceManager.Unload(imGuiFragmentShader);
imGuiPipeline?.Dispose();
imGuiSampler?.Dispose();
resourceUploader?.Dispose();
}
}

View File

@ -0,0 +1,33 @@
using Nerfed.Runtime.Graphics;
using System.Numerics;
using System.Runtime.InteropServices;
namespace Nerfed.Runtime.Gui;
[StructLayout(LayoutKind.Sequential)]
public struct Position2DTextureColorVertex(Vector2 position, Vector2 texcoord, Color color) : IVertexType
{
public Vector2 Position = position;
public Vector2 TexCoord = texcoord;
public Color Color = color;
public static VertexElementFormat[] Formats { get; } = new VertexElementFormat[3]
{
VertexElementFormat.Vector2,
VertexElementFormat.Vector2,
VertexElementFormat.Color
};
public static uint[] Offsets { get; } = new uint[3]
{
0,
8,
16
};
}
[StructLayout(LayoutKind.Sequential)]
public struct TransformVertexUniform(Matrix4x4 projectionMatrix)
{
public Matrix4x4 ProjectionMatrix = projectionMatrix;
}

View File

@ -0,0 +1,35 @@
using Nerfed.Runtime.Graphics;
namespace Nerfed.Runtime.Gui;
public class GuiTextureStorage
{
private readonly Dictionary<IntPtr, WeakReference<Texture>> pointerToTexture = new Dictionary<IntPtr, WeakReference<Texture>>();
public IntPtr Add(Texture texture)
{
if (!pointerToTexture.ContainsKey(texture.Handle))
{
pointerToTexture.Add(texture.Handle, new WeakReference<Texture>(texture));
}
return texture.Handle;
}
public Texture GetTexture(IntPtr pointer)
{
if (!pointerToTexture.TryGetValue(pointer, out WeakReference<Texture> value))
{
return null;
}
WeakReference<Texture> result = value;
if (!result.TryGetTarget(out Texture texture))
{
pointerToTexture.Remove(pointer);
return null;
}
return texture;
}
}

View File

@ -0,0 +1,87 @@
using ImGuiNET;
using Nerfed.Runtime.Graphics;
using System.Runtime.InteropServices;
namespace Nerfed.Runtime.Gui
{
internal class GuiViewportWindow
{
public Window Window => window;
private readonly GCHandle gcHandle;
private readonly GraphicsDevice graphicsDevice;
private readonly ImGuiViewportPtr vp;
private readonly Window window;
public GuiViewportWindow(GraphicsDevice graphicsDevice, ImGuiViewportPtr vp, Window window)
{
this.graphicsDevice = graphicsDevice;
this.vp = vp;
this.window = window;
gcHandle = GCHandle.Alloc(this);
if (!window.Claimed)
{
graphicsDevice.ClaimWindow(window, SwapchainComposition.SDR, PresentMode.Immediate); // What PresentMode do we need?
}
vp.PlatformUserData = (IntPtr)gcHandle;
}
public GuiViewportWindow(GraphicsDevice graphicsDevice, ImGuiViewportPtr vp)
{
this.graphicsDevice = graphicsDevice;
this.vp = vp;
gcHandle = GCHandle.Alloc(this);
// TODO: Handle all flags.
ScreenMode screenMode = ScreenMode.Windowed;
bool systemResizable = true;
if ((vp.Flags & ImGuiViewportFlags.NoDecoration) == ImGuiViewportFlags.NoDecoration)
{
screenMode = ScreenMode.WindowedBorderless;
systemResizable = false;
}
WindowCreateInfo info = new WindowCreateInfo("Window Title", (uint)vp.Pos.X, (uint)vp.Pos.Y, screenMode, systemResizable, false);
window = new Window(graphicsDevice, info);
graphicsDevice.ClaimWindow(window, SwapchainComposition.SDR, PresentMode.Immediate); // What PresentMode do we need?
window.OnMovedEvent += HandleOnMovedEvent;
window.OnResizedEvent += HandleOnResizedEvent;
window.OnCloseEvent += HandleOnCloseEvent;
vp.PlatformUserData = (IntPtr)gcHandle;
}
public void Dispose()
{
window.OnMovedEvent -= HandleOnMovedEvent;
window.OnResizedEvent -= HandleOnResizedEvent;
window.OnCloseEvent -= HandleOnCloseEvent;
graphicsDevice.UnclaimWindow(window);
window.Dispose();
gcHandle.Free();
}
private void HandleOnMovedEvent(Window window, int x, int y)
{
vp.PlatformRequestMove = true;
}
private void HandleOnResizedEvent(Window window, uint w, uint h)
{
vp.PlatformRequestResize = true;
}
private void HandleOnCloseEvent(Window window)
{
vp.PlatformRequestClose = true;
}
}
}

View File

@ -1,5 +1,5 @@
using System.Numerics; using SDL2;
using SDL2; using System.Numerics;
namespace Nerfed.Runtime; namespace Nerfed.Runtime;
@ -65,6 +65,8 @@ public static int GetWheelHorizontal()
internal static void Update() internal static void Update()
{ {
wheelX = 0;
wheelY = 0;
Array.Copy(buttonStates, lastButtonStates, buttonStates.Length); Array.Copy(buttonStates, lastButtonStates, buttonStates.Length);
} }
@ -105,8 +107,8 @@ private static void ProcessButtonUpEvent(ref SDL.SDL_MouseButtonEvent ev)
private static void ProcessWheelEvent(ref SDL.SDL_MouseWheelEvent ev) private static void ProcessWheelEvent(ref SDL.SDL_MouseWheelEvent ev)
{ {
wheelX += ev.x; wheelX = ev.x;
wheelY += ev.y; wheelY = ev.y;
} }
private static void ProcessMotionEvent(ref SDL.SDL_MouseMotionEvent ev) private static void ProcessMotionEvent(ref SDL.SDL_MouseMotionEvent ev)

@ -0,0 +1 @@
Subproject commit ae493d92a312810b66483af1922babe2eb434a47

View File

@ -1,26 +1,43 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <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" />
</ItemGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable> <Nullable>disable</Nullable>
<PublishAot>true</PublishAot> <PublishAot>true</PublishAot>
<InvariantGlobalization>true</InvariantGlobalization> <InvariantGlobalization>true</InvariantGlobalization>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<IsPackable>false</IsPackable>
<Configurations>Debug;Test;Release</Configurations>
<Platforms>x64</Platforms>
</PropertyGroup> </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\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>
</Project> </Project>

View 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>

View File

@ -17,12 +17,12 @@ public void Dispose() {
public static class Profiler public static class Profiler
{ {
[Conditional("PROFILER")] [Conditional("PROFILING")]
public static void BeginSample(string label) { public static void BeginSample(string label) {
} }
[Conditional("PROFILER")] [Conditional("PROFILING")]
public static void EndSample() { public static void EndSample() {
} }

View File

@ -1,9 +0,0 @@
namespace Nerfed.Runtime;
internal class Program
{
private static void Main(string[] args)
{
Engine.Run(args);
}
}

View 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();
}

View 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);
}
}

View 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;
}
}

View File

@ -3,6 +3,7 @@ namespace Nerfed.Runtime;
public enum ScreenMode public enum ScreenMode
{ {
Fullscreen, Fullscreen,
BorderlessFullscreen, FullscreenBorderless,
Windowed Windowed,
WindowedBorderless
} }

View File

@ -11,6 +11,10 @@ namespace Nerfed.Runtime;
/// </summary> /// </summary>
public class Window public class Window
{ {
public event Action<Window, uint, uint> OnResizedEvent;
public event Action<Window, int, int> OnMovedEvent;
public event Action<Window> OnCloseEvent;
internal IntPtr Handle { get; } internal IntPtr Handle { get; }
public ScreenMode ScreenMode { get; private set; } public ScreenMode ScreenMode { get; private set; }
public uint Width { get; private set; } public uint Width { get; private set; }
@ -33,8 +37,6 @@ public class Window
public string Title { get; private set;} public string Title { get; private set;}
private bool IsDisposed; private bool IsDisposed;
private System.Action<uint, uint> SizeChangeCallback = null;
private static readonly Dictionary<uint, Window> windowsById = new Dictionary<uint, Window>(); private static readonly Dictionary<uint, Window> windowsById = new Dictionary<uint, Window>();
public Window(GraphicsDevice graphicsDevice, WindowCreateInfo windowCreateInfo) public Window(GraphicsDevice graphicsDevice, WindowCreateInfo windowCreateInfo)
@ -54,10 +56,14 @@ public Window(GraphicsDevice graphicsDevice, WindowCreateInfo windowCreateInfo)
{ {
flags |= SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN; flags |= SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN;
} }
else if (windowCreateInfo.ScreenMode == ScreenMode.BorderlessFullscreen) else if (windowCreateInfo.ScreenMode == ScreenMode.FullscreenBorderless)
{ {
flags |= SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP; flags |= SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP;
} }
else if(windowCreateInfo.ScreenMode == ScreenMode.WindowedBorderless)
{
flags |= SDL.SDL_WindowFlags.SDL_WINDOW_BORDERLESS;
}
if (windowCreateInfo.SystemResizable) if (windowCreateInfo.SystemResizable)
{ {
@ -87,14 +93,6 @@ public Window(GraphicsDevice graphicsDevice, WindowCreateInfo windowCreateInfo)
Width = (uint) width; Width = (uint) width;
Height = (uint) height; Height = (uint) height;
unsafe
{
byte* pixels = ImageUtils.GetPixelDataFromFile(Path.Combine(System.AppContext.BaseDirectory, "Assets", "Textures", "NerfedIcon.png"), out uint w, out uint h, out uint size);
nint icon = SDL.SDL_CreateRGBSurfaceFrom(new IntPtr(pixels), (int)w, (int)h, 8 * 4, (int)w * 4, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
SDL.SDL_SetWindowIcon(Handle, icon);
ImageUtils.FreePixelData(pixels);
}
windowsById.Add(SDL.SDL_GetWindowID(Handle), this); windowsById.Add(SDL.SDL_GetWindowID(Handle), this);
} }
@ -112,6 +110,9 @@ internal static void ProcessEvent(ref SDL.SDL_Event ev)
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_SIZE_CHANGED: case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_SIZE_CHANGED:
window.ProcessSizeChangedEvent(ref ev.window); window.ProcessSizeChangedEvent(ref ev.window);
break; break;
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_MOVED:
window.ProcessMovedChangedEvent(ref ev.window);
break;
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_CLOSE: case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_CLOSE:
window.ProcessCloseEvent(ref ev.window); window.ProcessCloseEvent(ref ev.window);
break; break;
@ -125,14 +126,17 @@ private void ProcessSizeChangedEvent(ref SDL.SDL_WindowEvent ev)
Width = newWidth; Width = newWidth;
Height = newHeight; Height = newHeight;
if (SizeChangeCallback != null) OnResizedEvent?.Invoke(this, Width, Height);
{
SizeChangeCallback(newWidth, newHeight);
} }
private void ProcessMovedChangedEvent(ref SDL.SDL_WindowEvent ev)
{
OnMovedEvent?.Invoke(this, ev.data1, ev.data2);
} }
private void ProcessCloseEvent(ref SDL.SDL_WindowEvent ev) private void ProcessCloseEvent(ref SDL.SDL_WindowEvent ev)
{ {
OnCloseEvent?.Invoke(this);
Engine.GraphicsDevice.UnclaimWindow(this); Engine.GraphicsDevice.UnclaimWindow(this);
Dispose(); Dispose();
} }
@ -148,7 +152,7 @@ public void SetScreenMode(ScreenMode screenMode)
{ {
windowFlag = SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN; windowFlag = SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN;
} }
else if (screenMode == ScreenMode.BorderlessFullscreen) else if (screenMode == ScreenMode.FullscreenBorderless)
{ {
windowFlag = SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP; windowFlag = SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP;
} }
@ -203,14 +207,6 @@ internal void Show()
SDL.SDL_ShowWindow(Handle); SDL.SDL_ShowWindow(Handle);
} }
/// <summary>
/// You can specify a method to run when the window size changes.
/// </summary>
public void RegisterSizeChangeCallback(System.Action<uint, uint> sizeChangeCallback)
{
SizeChangeCallback = sizeChangeCallback;
}
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
{ {
if (!IsDisposed) if (!IsDisposed)

View File

@ -5,16 +5,38 @@ VisualStudioVersion = 17.10.35013.160
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerfed.Runtime", "Nerfed.Runtime\Nerfed.Runtime.csproj", "{98E09BAF-587F-4238-89BD-7693C036C233}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerfed.Runtime", "Nerfed.Runtime\Nerfed.Runtime.csproj", "{98E09BAF-587F-4238-89BD-7693C036C233}"
EndProject 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 Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Test|x64 = Test|x64
Release|Any CPU = Release|Any CPU Release|x64 = Release|x64
Debug|x64 = Debug|x64
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{98E09BAF-587F-4238-89BD-7693C036C233}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1B88DE56-2AD8-441E-9B10-073AA43840BF}.Test|x64.ActiveCfg = Test|x64
{98E09BAF-587F-4238-89BD-7693C036C233}.Debug|Any CPU.Build.0 = Debug|Any CPU {1B88DE56-2AD8-441E-9B10-073AA43840BF}.Test|x64.Build.0 = Test|x64
{98E09BAF-587F-4238-89BD-7693C036C233}.Release|Any CPU.ActiveCfg = Release|Any CPU {1B88DE56-2AD8-441E-9B10-073AA43840BF}.Release|x64.ActiveCfg = Release|x64
{98E09BAF-587F-4238-89BD-7693C036C233}.Release|Any CPU.Build.0 = Release|Any CPU {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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -1,3 +1,11 @@
# Nerfed # Nerfed
nerfed game engine nerfed game engine
## License
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
## Third-Party Licenses
This project includes third-party libraries with their respective licenses, which can be found in the [THIRD_PARTY_LICENSES](THIRD_PARTY_LICENSES) file.

29
THIRD_PARTY_LICENSES Normal file
View File

@ -0,0 +1,29 @@
# Third-Party Licenses
## ImGui
**Name:** Dear ImGui
**License:** MIT License
MIT License
Copyright (c) 2014-2022 Omar Cornut
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Binary file not shown.

View 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

Binary file not shown.

View 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

Binary file not shown.

BIN
Tools/glslc/Win64/glslc.exe (Stored with Git LFS) Executable file

Binary file not shown.