Compare commits
	
		
			9 Commits
		
	
	
		
			4794fbc647
			...
			NerfedIcon
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 71657cf8d8 | |||
| 26eb1da3f0 | |||
| e46b43281f | |||
| 1c64d6fe54 | |||
| 5d2c350bb8 | |||
| 8334a24fd1 | |||
| e7a4a862be | |||
| 56cb14441f | |||
| cd8beb0337 | 
							
								
								
									
										9
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,5 +1,3 @@
 | 
				
			|||||||
imgui.ini
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#------------------------- Rider -------------------------
 | 
					#------------------------- Rider -------------------------
 | 
				
			||||||
# Source: https://github.com/JetBrains/resharper-rider-samples/blob/master/.gitignore 
 | 
					# Source: https://github.com/JetBrains/resharper-rider-samples/blob/master/.gitignore 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -451,3 +449,10 @@ FodyWeavers.xsd
 | 
				
			|||||||
# Built Visual Studio Code Extensions
 | 
					# Built Visual Studio Code Extensions
 | 
				
			||||||
*.vsix
 | 
					*.vsix
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#------------------------- Nerfed -------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					imgui.ini
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# include libs
 | 
				
			||||||
 | 
					!/libs/lib64
 | 
				
			||||||
 | 
					!/libs/x64
 | 
				
			||||||
							
								
								
									
										11
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							@@ -1,6 +1,15 @@
 | 
				
			|||||||
[submodule "Libraries/RefreshCS"]
 | 
					[submodule "Libraries/RefreshCS"]
 | 
				
			||||||
	path = Nerfed.Runtime/Libraries/RefreshCS/RefreshCS
 | 
						path = Nerfed.Runtime/Libraries/RefreshCS
 | 
				
			||||||
	url = https://github.com/MoonsideGames/RefreshCS.git
 | 
						url = https://github.com/MoonsideGames/RefreshCS.git
 | 
				
			||||||
[submodule "Libraries/SDL2CS"]
 | 
					[submodule "Libraries/SDL2CS"]
 | 
				
			||||||
	path = Nerfed.Runtime/Libraries/SDL2CS
 | 
						path = Nerfed.Runtime/Libraries/SDL2CS
 | 
				
			||||||
	url = https://github.com/flibitijibibo/SDL2-CS.git
 | 
						url = https://github.com/flibitijibibo/SDL2-CS.git
 | 
				
			||||||
 | 
					[submodule "Nerfed.Runtime/Libraries/FAudio"]
 | 
				
			||||||
 | 
						path = Nerfed.Runtime/Libraries/FAudio
 | 
				
			||||||
 | 
						url = https://github.com/FNA-XNA/FAudio.git
 | 
				
			||||||
 | 
					[submodule "Nerfed.Runtime/Libraries/WellspringCS"]
 | 
				
			||||||
 | 
						path = Nerfed.Runtime/Libraries/WellspringCS
 | 
				
			||||||
 | 
						url = https://github.com/MoonsideGames/WellspringCS.git
 | 
				
			||||||
 | 
					[submodule "Nerfed.Runtime/Libraries/dav1dfile"]
 | 
				
			||||||
 | 
						path = Nerfed.Runtime/Libraries/dav1dfile
 | 
				
			||||||
 | 
						url = https://github.com/MoonsideGames/dav1dfile.git
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										13
									
								
								.idea/.idea.Nerfed/.idea/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								.idea/.idea.Nerfed/.idea/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					# Default ignored files
 | 
				
			||||||
 | 
					/shelf/
 | 
				
			||||||
 | 
					/workspace.xml
 | 
				
			||||||
 | 
					# Rider ignored files
 | 
				
			||||||
 | 
					/modules.xml
 | 
				
			||||||
 | 
					/contentModel.xml
 | 
				
			||||||
 | 
					/projectSettingsUpdater.xml
 | 
				
			||||||
 | 
					/.idea.Nerfed.iml
 | 
				
			||||||
 | 
					# Editor-based HTTP Client requests
 | 
				
			||||||
 | 
					/httpRequests/
 | 
				
			||||||
 | 
					# Datasource local storage ignored files
 | 
				
			||||||
 | 
					/dataSources/
 | 
				
			||||||
 | 
					/dataSources.local.xml
 | 
				
			||||||
							
								
								
									
										4
									
								
								.idea/.idea.Nerfed/.idea/encodings.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								.idea/.idea.Nerfed/.idea/encodings.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<project version="4">
 | 
				
			||||||
 | 
					  <component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
 | 
				
			||||||
 | 
					</project>
 | 
				
			||||||
							
								
								
									
										8
									
								
								.idea/.idea.Nerfed/.idea/indexLayout.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								.idea/.idea.Nerfed/.idea/indexLayout.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<project version="4">
 | 
				
			||||||
 | 
					  <component name="UserContentModel">
 | 
				
			||||||
 | 
					    <attachedFolders />
 | 
				
			||||||
 | 
					    <explicitIncludes />
 | 
				
			||||||
 | 
					    <explicitExcludes />
 | 
				
			||||||
 | 
					  </component>
 | 
				
			||||||
 | 
					</project>
 | 
				
			||||||
							
								
								
									
										10
									
								
								.idea/.idea.Nerfed/.idea/inspectionProfiles/Project_Default.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								.idea/.idea.Nerfed/.idea/inspectionProfiles/Project_Default.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					<component name="InspectionProjectProfileManager">
 | 
				
			||||||
 | 
					  <profile version="1.0">
 | 
				
			||||||
 | 
					    <option name="myName" value="Project Default" />
 | 
				
			||||||
 | 
					    <inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
 | 
				
			||||||
 | 
					      <option name="processCode" value="true" />
 | 
				
			||||||
 | 
					      <option name="processLiterals" value="true" />
 | 
				
			||||||
 | 
					      <option name="processComments" value="true" />
 | 
				
			||||||
 | 
					    </inspection_tool>
 | 
				
			||||||
 | 
					  </profile>
 | 
				
			||||||
 | 
					</component>
 | 
				
			||||||
							
								
								
									
										6
									
								
								.idea/.idea.Nerfed/.idea/vcs.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.idea/.idea.Nerfed/.idea/vcs.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<project version="4">
 | 
				
			||||||
 | 
					  <component name="VcsDirectoryMappings">
 | 
				
			||||||
 | 
					    <mapping directory="" vcs="Git" />
 | 
				
			||||||
 | 
					  </component>
 | 
				
			||||||
 | 
					</project>
 | 
				
			||||||
							
								
								
									
										24
									
								
								Nerfed.Runtime/Assert.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								Nerfed.Runtime/Assert.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					using System.Diagnostics;
 | 
				
			||||||
 | 
					using System.Diagnostics.CodeAnalysis;
 | 
				
			||||||
 | 
					using System.Runtime.CompilerServices;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class AssertionException(string msg) : Exception(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public static class Assert
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    [Conditional("DEBUG"), DebuggerHidden]
 | 
				
			||||||
 | 
					    public static void Debug([DoesNotReturnIf(false)] bool cond, [CallerArgumentExpression("cond")] string expression = "") {
 | 
				
			||||||
 | 
					        if (!cond) {
 | 
				
			||||||
 | 
					            throw new AssertionException(expression);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [DebuggerHidden]
 | 
				
			||||||
 | 
					    public static void Always([DoesNotReturnIf(false)] bool cond, [CallerArgumentExpression("cond")] string expression = "") {
 | 
				
			||||||
 | 
					        if (!cond) {
 | 
				
			||||||
 | 
					            throw new AssertionException(expression);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								Nerfed.Runtime/Assets/Textures/NerfedIcon.png
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Nerfed.Runtime/Assets/Textures/NerfedIcon.png
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										78
									
								
								Nerfed.Runtime/Audio/AudioBuffer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								Nerfed.Runtime/Audio/AudioBuffer.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Contains raw audio data in a specified Format. <br/>
 | 
				
			||||||
 | 
					/// Submit this to a SourceVoice to play audio.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class AudioBuffer : AudioResource
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						IntPtr BufferDataPtr;
 | 
				
			||||||
 | 
						uint BufferDataLength;
 | 
				
			||||||
 | 
						private bool OwnsBufferData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Format Format { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Create a new AudioBuffer.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="ownsBufferData">If true, the buffer data will be destroyed when this AudioBuffer is destroyed.</param>
 | 
				
			||||||
 | 
						public AudioBuffer(
 | 
				
			||||||
 | 
							AudioDevice device,
 | 
				
			||||||
 | 
							Format format,
 | 
				
			||||||
 | 
							IntPtr bufferPtr,
 | 
				
			||||||
 | 
							uint bufferLengthInBytes,
 | 
				
			||||||
 | 
							bool ownsBufferData) : base(device)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Format = format;
 | 
				
			||||||
 | 
							BufferDataPtr = bufferPtr;
 | 
				
			||||||
 | 
							BufferDataLength = bufferLengthInBytes;
 | 
				
			||||||
 | 
							OwnsBufferData = ownsBufferData;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Create another AudioBuffer from this audio buffer.
 | 
				
			||||||
 | 
						/// It will not own the buffer data.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="offset">Offset in bytes from the top of the original buffer.</param>
 | 
				
			||||||
 | 
						/// <param name="length">Length in bytes of the new buffer.</param>
 | 
				
			||||||
 | 
						/// <returns></returns>
 | 
				
			||||||
 | 
						public AudioBuffer Slice(int offset, uint length)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new AudioBuffer(Device, Format, BufferDataPtr + offset, length, false);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Create an FAudioBuffer struct from this AudioBuffer.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="loop">Whether we should set the FAudioBuffer to loop.</param>
 | 
				
			||||||
 | 
						public FAudio.FAudioBuffer ToFAudioBuffer(bool loop = false)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new FAudio.FAudioBuffer
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Flags = FAudio.FAUDIO_END_OF_STREAM,
 | 
				
			||||||
 | 
								pContext = IntPtr.Zero,
 | 
				
			||||||
 | 
								pAudioData = BufferDataPtr,
 | 
				
			||||||
 | 
								AudioBytes = BufferDataLength,
 | 
				
			||||||
 | 
								PlayBegin = 0,
 | 
				
			||||||
 | 
								PlayLength = 0,
 | 
				
			||||||
 | 
								LoopBegin = 0,
 | 
				
			||||||
 | 
								LoopLength = 0,
 | 
				
			||||||
 | 
								LoopCount = loop ? FAudio.FAUDIO_LOOP_INFINITE : 0
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected override unsafe void Dispose(bool disposing)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (!IsDisposed)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (OwnsBufferData)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									NativeMemory.Free((void*) BufferDataPtr);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							base.Dispose(disposing);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										146
									
								
								Nerfed.Runtime/Audio/AudioDataOgg.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								Nerfed.Runtime/Audio/AudioDataOgg.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,146 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Streamable audio in Ogg format.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class AudioDataOgg : AudioDataStreamable
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						private IntPtr FileDataPtr = IntPtr.Zero;
 | 
				
			||||||
 | 
						private IntPtr VorbisHandle = IntPtr.Zero;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private string FilePath;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override bool Loaded => VorbisHandle != IntPtr.Zero;
 | 
				
			||||||
 | 
						public override uint DecodeBufferSize => 32768;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public AudioDataOgg(AudioDevice device, string filePath) : base(device)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							FilePath = filePath;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							IntPtr handle = FAudio.stb_vorbis_open_filename(filePath, out int error, IntPtr.Zero);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (error != 0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new InvalidOperationException("Error loading file!");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							FAudio.stb_vorbis_info info = FAudio.stb_vorbis_get_info(handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Format = new Format
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Tag = FormatTag.IEEE_FLOAT,
 | 
				
			||||||
 | 
								BitsPerSample = 32,
 | 
				
			||||||
 | 
								Channels = (ushort) info.channels,
 | 
				
			||||||
 | 
								SampleRate = info.sample_rate
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							FAudio.stb_vorbis_close(handle);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override unsafe void Decode(void* buffer, int bufferLengthInBytes, out int filledLengthInBytes, out bool reachedEnd)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							int lengthInFloats = bufferLengthInBytes / sizeof(float);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* NOTE: this function returns samples per channel, not total samples */
 | 
				
			||||||
 | 
							int samples = FAudio.stb_vorbis_get_samples_float_interleaved(
 | 
				
			||||||
 | 
								VorbisHandle,
 | 
				
			||||||
 | 
								Format.Channels,
 | 
				
			||||||
 | 
								(IntPtr) buffer,
 | 
				
			||||||
 | 
								lengthInFloats
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							int sampleCount = samples * Format.Channels;
 | 
				
			||||||
 | 
							reachedEnd = sampleCount < lengthInFloats;
 | 
				
			||||||
 | 
							filledLengthInBytes = sampleCount * sizeof(float);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Prepares the Ogg data for streaming.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public override unsafe void Load()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (!Loaded)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								FileStream fileStream = new FileStream(FilePath, FileMode.Open, FileAccess.Read);
 | 
				
			||||||
 | 
								FileDataPtr = (nint) NativeMemory.Alloc((nuint) fileStream.Length);
 | 
				
			||||||
 | 
								Span<byte> fileDataSpan = new Span<byte>((void*) FileDataPtr, (int) fileStream.Length);
 | 
				
			||||||
 | 
								fileStream.ReadExactly(fileDataSpan);
 | 
				
			||||||
 | 
								fileStream.Close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VorbisHandle = FAudio.stb_vorbis_open_memory(FileDataPtr, fileDataSpan.Length, out int error, IntPtr.Zero);
 | 
				
			||||||
 | 
								if (error != 0)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									NativeMemory.Free((void*) FileDataPtr);
 | 
				
			||||||
 | 
									Log.Error("Error opening OGG file!");
 | 
				
			||||||
 | 
									Log.Error("Error: " + error);
 | 
				
			||||||
 | 
									throw new InvalidOperationException("Error opening OGG file!");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override void Seek(uint sampleFrame)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							FAudio.stb_vorbis_seek(VorbisHandle, sampleFrame);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Unloads the Ogg data, freeing resources.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public override unsafe void Unload()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (Loaded)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								FAudio.stb_vorbis_close(VorbisHandle);
 | 
				
			||||||
 | 
								NativeMemory.Free((void*) FileDataPtr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VorbisHandle = IntPtr.Zero;
 | 
				
			||||||
 | 
								FileDataPtr = IntPtr.Zero;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Loads an entire ogg file into an AudioBuffer. Useful for static audio.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public static unsafe AudioBuffer CreateBuffer(AudioDevice device, string filePath)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							IntPtr filePointer = FAudio.stb_vorbis_open_filename(filePath, out int error, IntPtr.Zero);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (error != 0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new InvalidOperationException("Error loading file!");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							FAudio.stb_vorbis_info info = FAudio.stb_vorbis_get_info(filePointer);
 | 
				
			||||||
 | 
							long lengthInFloats =
 | 
				
			||||||
 | 
								FAudio.stb_vorbis_stream_length_in_samples(filePointer) * info.channels;
 | 
				
			||||||
 | 
							long lengthInBytes = lengthInFloats * Marshal.SizeOf<float>();
 | 
				
			||||||
 | 
							void* buffer = NativeMemory.Alloc((nuint) lengthInBytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							FAudio.stb_vorbis_get_samples_float_interleaved(
 | 
				
			||||||
 | 
								filePointer,
 | 
				
			||||||
 | 
								info.channels,
 | 
				
			||||||
 | 
								(nint) buffer,
 | 
				
			||||||
 | 
								(int) lengthInFloats
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							FAudio.stb_vorbis_close(filePointer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Format format = new Format
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Tag = FormatTag.IEEE_FLOAT,
 | 
				
			||||||
 | 
								BitsPerSample = 32,
 | 
				
			||||||
 | 
								Channels = (ushort) info.channels,
 | 
				
			||||||
 | 
								SampleRate = info.sample_rate
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return new AudioBuffer(
 | 
				
			||||||
 | 
								device,
 | 
				
			||||||
 | 
								format,
 | 
				
			||||||
 | 
								(nint) buffer,
 | 
				
			||||||
 | 
								(uint) lengthInBytes,
 | 
				
			||||||
 | 
								true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										163
									
								
								Nerfed.Runtime/Audio/AudioDataQoa.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								Nerfed.Runtime/Audio/AudioDataQoa.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,163 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Streamable audio in QOA format.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class AudioDataQoa : AudioDataStreamable
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						private IntPtr QoaHandle = IntPtr.Zero;
 | 
				
			||||||
 | 
						private IntPtr FileDataPtr = IntPtr.Zero;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private string FilePath;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private const uint QOA_MAGIC = 0x716f6166; /* 'qoaf' */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override bool Loaded => QoaHandle != IntPtr.Zero;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private uint decodeBufferSize;
 | 
				
			||||||
 | 
						public override uint DecodeBufferSize => decodeBufferSize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public AudioDataQoa(AudioDevice device, string filePath) : base(device)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							FilePath = filePath;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							using FileStream stream = new FileStream(FilePath, FileMode.Open, FileAccess.Read);
 | 
				
			||||||
 | 
							using BinaryReader reader = new BinaryReader(stream);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							UInt64 fileHeader = ReverseEndianness(reader.ReadUInt64());
 | 
				
			||||||
 | 
							if ((fileHeader >> 32) != QOA_MAGIC)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new InvalidOperationException("Specified file is not a QOA file.");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							uint totalSamplesPerChannel = (uint) (fileHeader & (0xFFFFFFFF));
 | 
				
			||||||
 | 
							if (totalSamplesPerChannel == 0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new InvalidOperationException("Specified file is not a valid QOA file.");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							UInt64 frameHeader = ReverseEndianness(reader.ReadUInt64());
 | 
				
			||||||
 | 
							uint channels = (uint) ((frameHeader >> 56) & 0x0000FF);
 | 
				
			||||||
 | 
							uint samplerate = (uint) ((frameHeader >> 32) & 0xFFFFFF);
 | 
				
			||||||
 | 
							uint samplesPerChannelPerFrame = (uint) ((frameHeader >> 16) & 0x00FFFF);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Format = new Format
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Tag = FormatTag.PCM,
 | 
				
			||||||
 | 
								BitsPerSample = 16,
 | 
				
			||||||
 | 
								Channels = (ushort) channels,
 | 
				
			||||||
 | 
								SampleRate = samplerate
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							decodeBufferSize = channels * samplesPerChannelPerFrame * sizeof(short);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override unsafe void Decode(void* buffer, int bufferLengthInBytes, out int filledLengthInBytes, out bool reachedEnd)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							int lengthInShorts = bufferLengthInBytes / sizeof(short);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// NOTE: this function returns samples per channel!
 | 
				
			||||||
 | 
							uint samples = FAudio.qoa_decode_next_frame(QoaHandle, (short*) buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							uint sampleCount = samples * Format.Channels;
 | 
				
			||||||
 | 
							reachedEnd = sampleCount < lengthInShorts;
 | 
				
			||||||
 | 
							filledLengthInBytes = (int) (sampleCount * sizeof(short));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Prepares qoa data for streaming.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public override unsafe void Load()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (!Loaded)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								FileStream fileStream = new FileStream(FilePath, FileMode.Open, FileAccess.Read);
 | 
				
			||||||
 | 
								FileDataPtr = (nint) NativeMemory.Alloc((nuint) fileStream.Length);
 | 
				
			||||||
 | 
								Span<byte> fileDataSpan = new Span<byte>((void*) FileDataPtr, (int) fileStream.Length);
 | 
				
			||||||
 | 
								fileStream.ReadExactly(fileDataSpan);
 | 
				
			||||||
 | 
								fileStream.Close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								QoaHandle = FAudio.qoa_open_from_memory((char*) FileDataPtr, (uint) fileDataSpan.Length, 0);
 | 
				
			||||||
 | 
								if (QoaHandle == IntPtr.Zero)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									NativeMemory.Free((void*) FileDataPtr);
 | 
				
			||||||
 | 
									Log.Error("Error opening QOA file!");
 | 
				
			||||||
 | 
									throw new InvalidOperationException("Error opening QOA file!");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override void Seek(uint sampleFrame)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							FAudio.qoa_seek_frame(QoaHandle, (int) sampleFrame);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Unloads the qoa data, freeing resources.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public override unsafe void Unload()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (Loaded)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								FAudio.qoa_close(QoaHandle);
 | 
				
			||||||
 | 
								NativeMemory.Free((void*) FileDataPtr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								QoaHandle = IntPtr.Zero;
 | 
				
			||||||
 | 
								FileDataPtr = IntPtr.Zero;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Loads the entire qoa file into an AudioBuffer. Useful for static audio.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public unsafe static AudioBuffer CreateBuffer(AudioDevice device, string filePath)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							using FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
 | 
				
			||||||
 | 
							void* fileDataPtr = NativeMemory.Alloc((nuint) fileStream.Length);
 | 
				
			||||||
 | 
							Span<byte> fileDataSpan = new Span<byte>(fileDataPtr, (int) fileStream.Length);
 | 
				
			||||||
 | 
							fileStream.ReadExactly(fileDataSpan);
 | 
				
			||||||
 | 
							fileStream.Close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							IntPtr qoaHandle = FAudio.qoa_open_from_memory((char*) fileDataPtr, (uint) fileDataSpan.Length, 0);
 | 
				
			||||||
 | 
							if (qoaHandle == 0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								NativeMemory.Free(fileDataPtr);
 | 
				
			||||||
 | 
								Log.Error("Error opening QOA file!");
 | 
				
			||||||
 | 
								throw new InvalidOperationException("Error opening QOA file!");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							FAudio.qoa_attributes(qoaHandle, out uint channels, out uint samplerate, out uint samples_per_channel_per_frame, out uint total_samples_per_channel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							uint bufferLengthInBytes = total_samples_per_channel * channels * sizeof(short);
 | 
				
			||||||
 | 
							void* buffer = NativeMemory.Alloc(bufferLengthInBytes);
 | 
				
			||||||
 | 
							FAudio.qoa_decode_entire(qoaHandle, (short*) buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							FAudio.qoa_close(qoaHandle);
 | 
				
			||||||
 | 
							NativeMemory.Free(fileDataPtr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Format format = new Format
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Tag = FormatTag.PCM,
 | 
				
			||||||
 | 
								BitsPerSample = 16,
 | 
				
			||||||
 | 
								Channels = (ushort) channels,
 | 
				
			||||||
 | 
								SampleRate = samplerate
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return new AudioBuffer(device, format, (nint) buffer, bufferLengthInBytes, true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static unsafe UInt64 ReverseEndianness(UInt64 value)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							byte* bytes = (byte*) &value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
								((UInt64)(bytes[0]) << 56) | ((UInt64)(bytes[1]) << 48) |
 | 
				
			||||||
 | 
								((UInt64)(bytes[2]) << 40) | ((UInt64)(bytes[3]) << 32) |
 | 
				
			||||||
 | 
								((UInt64)(bytes[4]) << 24) | ((UInt64)(bytes[5]) << 16) |
 | 
				
			||||||
 | 
								((UInt64)(bytes[6]) <<  8) | ((UInt64)(bytes[7]) <<  0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										48
									
								
								Nerfed.Runtime/Audio/AudioDataStreamable.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								Nerfed.Runtime/Audio/AudioDataStreamable.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					namespace Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Use this in conjunction with a StreamingVoice to play back streaming audio data.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public abstract class AudioDataStreamable : AudioResource
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public Format Format { get; protected set; }
 | 
				
			||||||
 | 
						public abstract bool Loaded { get; }
 | 
				
			||||||
 | 
						public abstract uint DecodeBufferSize { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected AudioDataStreamable(AudioDevice device) : base(device)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Loads the raw audio data into memory to prepare it for stream decoding.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public abstract void Load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Unloads the raw audio data from memory.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public abstract void Unload();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Seeks to the given sample frame.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public abstract void Seek(uint sampleFrame);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Attempts to decodes data of length bufferLengthInBytes into the provided buffer.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="buffer">The buffer that decoded bytes will be placed into.</param>
 | 
				
			||||||
 | 
						/// <param name="bufferLengthInBytes">Requested length of decoded audio data.</param>
 | 
				
			||||||
 | 
						/// <param name="filledLengthInBytes">How much data was actually filled in by the decode.</param>
 | 
				
			||||||
 | 
						/// <param name="reachedEnd">Whether the end of the data was reached on this decode.</param>
 | 
				
			||||||
 | 
						public abstract unsafe void Decode(void* buffer, int bufferLengthInBytes, out int filledLengthInBytes, out bool reachedEnd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected override void Dispose(bool disposing)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								if (!IsDisposed)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									Unload();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								base.Dispose(disposing);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										99
									
								
								Nerfed.Runtime/Audio/AudioDataWav.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								Nerfed.Runtime/Audio/AudioDataWav.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,99 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public static class AudioDataWav
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Create an AudioBuffer containing all the WAV audio data in a file.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns></returns>
 | 
				
			||||||
 | 
						public unsafe static AudioBuffer CreateBuffer(AudioDevice device, string filePath)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								// mostly borrowed from https://github.com/FNA-XNA/FNA/blob/b71b4a35ae59970ff0070dea6f8620856d8d4fec/src/Audio/SoundEffect.cs#L385
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// WaveFormatEx data
 | 
				
			||||||
 | 
								ushort wFormatTag;
 | 
				
			||||||
 | 
								ushort nChannels;
 | 
				
			||||||
 | 
								uint nSamplesPerSec;
 | 
				
			||||||
 | 
								uint nAvgBytesPerSec;
 | 
				
			||||||
 | 
								ushort nBlockAlign;
 | 
				
			||||||
 | 
								ushort wBitsPerSample;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								using FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
 | 
				
			||||||
 | 
								using BinaryReader reader = new BinaryReader(stream);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// RIFF Signature
 | 
				
			||||||
 | 
								string signature = new string(reader.ReadChars(4));
 | 
				
			||||||
 | 
								if (signature != "RIFF")
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									throw new NotSupportedException("Specified stream is not a wave file.");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								reader.ReadUInt32(); // Riff Chunk Size
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								string wformat = new string(reader.ReadChars(4));
 | 
				
			||||||
 | 
								if (wformat != "WAVE")
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									throw new NotSupportedException("Specified stream is not a wave file.");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// WAVE Header
 | 
				
			||||||
 | 
								string format_signature = new string(reader.ReadChars(4));
 | 
				
			||||||
 | 
								while (format_signature != "fmt ")
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									reader.ReadBytes(reader.ReadInt32());
 | 
				
			||||||
 | 
									format_signature = new string(reader.ReadChars(4));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								int format_chunk_size = reader.ReadInt32();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								wFormatTag = reader.ReadUInt16();
 | 
				
			||||||
 | 
								nChannels = reader.ReadUInt16();
 | 
				
			||||||
 | 
								nSamplesPerSec = reader.ReadUInt32();
 | 
				
			||||||
 | 
								nAvgBytesPerSec = reader.ReadUInt32();
 | 
				
			||||||
 | 
								nBlockAlign = reader.ReadUInt16();
 | 
				
			||||||
 | 
								wBitsPerSample = reader.ReadUInt16();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Reads residual bytes
 | 
				
			||||||
 | 
								if (format_chunk_size > 16)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									reader.ReadBytes(format_chunk_size - 16);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// data Signature
 | 
				
			||||||
 | 
								string data_signature = new string(reader.ReadChars(4));
 | 
				
			||||||
 | 
								while (data_signature.ToLowerInvariant() != "data")
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									reader.ReadBytes(reader.ReadInt32());
 | 
				
			||||||
 | 
									data_signature = new string(reader.ReadChars(4));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (data_signature != "data")
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									throw new NotSupportedException("Specified wave file is not supported.");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								int waveDataLength = reader.ReadInt32();
 | 
				
			||||||
 | 
								void* waveDataBuffer = NativeMemory.Alloc((nuint) waveDataLength);
 | 
				
			||||||
 | 
								Span<byte> waveDataSpan = new Span<byte>(waveDataBuffer, waveDataLength);
 | 
				
			||||||
 | 
								stream.ReadExactly(waveDataSpan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Format format = new Format
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									Tag = (FormatTag) wFormatTag,
 | 
				
			||||||
 | 
									BitsPerSample = wBitsPerSample,
 | 
				
			||||||
 | 
									Channels = nChannels,
 | 
				
			||||||
 | 
									SampleRate = nSamplesPerSec
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return new AudioBuffer(
 | 
				
			||||||
 | 
									device,
 | 
				
			||||||
 | 
									format,
 | 
				
			||||||
 | 
									(nint) waveDataBuffer,
 | 
				
			||||||
 | 
									(uint) waveDataLength,
 | 
				
			||||||
 | 
									true
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										309
									
								
								Nerfed.Runtime/Audio/AudioDevice.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										309
									
								
								Nerfed.Runtime/Audio/AudioDevice.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,309 @@
 | 
				
			|||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// AudioDevice manages all audio-related concerns.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class AudioDevice : IDisposable
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public IntPtr Handle { get; }
 | 
				
			||||||
 | 
						public byte[] Handle3D { get; }
 | 
				
			||||||
 | 
						public FAudio.FAudioDeviceDetails DeviceDetails { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private IntPtr trueMasteringVoice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// this is a fun little trick where we use a submix voice as a "faux" mastering voice
 | 
				
			||||||
 | 
						// this lets us maintain API consistency for effects like panning and reverb
 | 
				
			||||||
 | 
						private SubmixVoice fauxMasteringVoice;
 | 
				
			||||||
 | 
						public SubmixVoice MasteringVoice => fauxMasteringVoice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public float CurveDistanceScalar = 1f;
 | 
				
			||||||
 | 
						public float DopplerScale = 1f;
 | 
				
			||||||
 | 
						public float SpeedOfSound = 343.5f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private readonly HashSet<GCHandle> resourceHandles = new HashSet<GCHandle>();
 | 
				
			||||||
 | 
						private readonly HashSet<UpdatingSourceVoice> updatingSourceVoices = new HashSet<UpdatingSourceVoice>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private SourceVoicePool VoicePool;
 | 
				
			||||||
 | 
						private List<SourceVoice> VoicesToReturn = new List<SourceVoice>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private const int Step = 200;
 | 
				
			||||||
 | 
						private TimeSpan UpdateInterval;
 | 
				
			||||||
 | 
						private System.Diagnostics.Stopwatch TickStopwatch = new System.Diagnostics.Stopwatch();
 | 
				
			||||||
 | 
						private long previousTickTime;
 | 
				
			||||||
 | 
						private Thread Thread;
 | 
				
			||||||
 | 
						private AutoResetEvent WakeSignal;
 | 
				
			||||||
 | 
						internal readonly object StateLock = new object();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private bool Running;
 | 
				
			||||||
 | 
						public bool IsDisposed { get; private set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						internal unsafe AudioDevice()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								UpdateInterval = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / Step);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								FAudio.FAudioCreate(out IntPtr handle, 0, FAudio.FAUDIO_DEFAULT_PROCESSOR);
 | 
				
			||||||
 | 
								Handle = handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* Find a suitable device */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								FAudio.FAudio_GetDeviceCount(Handle, out uint devices);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (devices == 0)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									Log.Error("No audio devices found!");
 | 
				
			||||||
 | 
									FAudio.FAudio_Release(Handle);
 | 
				
			||||||
 | 
									Handle = IntPtr.Zero;
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								FAudio.FAudioDeviceDetails deviceDetails;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								uint i = 0;
 | 
				
			||||||
 | 
								for (i = 0; i < devices; i++)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									FAudio.FAudio_GetDeviceDetails(
 | 
				
			||||||
 | 
										Handle,
 | 
				
			||||||
 | 
										i,
 | 
				
			||||||
 | 
										out deviceDetails
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
									if ((deviceDetails.Role & FAudio.FAudioDeviceRole.FAudioDefaultGameDevice) == FAudio.FAudioDeviceRole.FAudioDefaultGameDevice)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										DeviceDetails = deviceDetails;
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (i == devices)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									i = 0; /* whatever we'll just use the first one I guess */
 | 
				
			||||||
 | 
									FAudio.FAudio_GetDeviceDetails(
 | 
				
			||||||
 | 
										Handle,
 | 
				
			||||||
 | 
										i,
 | 
				
			||||||
 | 
										out deviceDetails
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
									DeviceDetails = deviceDetails;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* Init Mastering Voice */
 | 
				
			||||||
 | 
								uint result = FAudio.FAudio_CreateMasteringVoice(
 | 
				
			||||||
 | 
									Handle,
 | 
				
			||||||
 | 
									out trueMasteringVoice,
 | 
				
			||||||
 | 
									FAudio.FAUDIO_DEFAULT_CHANNELS,
 | 
				
			||||||
 | 
									FAudio.FAUDIO_DEFAULT_SAMPLERATE,
 | 
				
			||||||
 | 
									0,
 | 
				
			||||||
 | 
									i,
 | 
				
			||||||
 | 
									IntPtr.Zero
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (result != 0)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									Log.Error("Failed to create a mastering voice!");
 | 
				
			||||||
 | 
									Log.Error("Audio device creation failed!");
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								fauxMasteringVoice = SubmixVoice.CreateFauxMasteringVoice(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* Init 3D Audio */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Handle3D = new byte[FAudio.F3DAUDIO_HANDLE_BYTESIZE];
 | 
				
			||||||
 | 
								FAudio.F3DAudioInitialize(
 | 
				
			||||||
 | 
									DeviceDetails.OutputFormat.dwChannelMask,
 | 
				
			||||||
 | 
									SpeedOfSound,
 | 
				
			||||||
 | 
									Handle3D
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VoicePool = new SourceVoicePool(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								WakeSignal = new AutoResetEvent(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Thread = new Thread(ThreadMain);
 | 
				
			||||||
 | 
								Thread.IsBackground = true;
 | 
				
			||||||
 | 
								Thread.Start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Running = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								TickStopwatch.Start();
 | 
				
			||||||
 | 
								previousTickTime = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void ThreadMain()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								while (Running)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									lock (StateLock)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										try
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											ThreadMainTick();
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										catch (Exception e)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Log.Error(e.ToString());
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									WakeSignal.WaitOne(UpdateInterval);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void ThreadMainTick()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								previousTickTime = TickStopwatch.Elapsed.Ticks;
 | 
				
			||||||
 | 
								foreach (UpdatingSourceVoice voice in updatingSourceVoices)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									voice.Update();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								foreach (SourceVoice voice in VoicesToReturn)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (voice is UpdatingSourceVoice updatingSourceVoice)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										updatingSourceVoices.Remove(updatingSourceVoice);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									voice.Reset();
 | 
				
			||||||
 | 
									VoicePool.Return(voice);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								VoicesToReturn.Clear();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Triggers all pending operations with the given syncGroup value.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public void TriggerSyncGroup(uint syncGroup)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								FAudio.FAudio_CommitChanges(Handle, syncGroup);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Obtains an appropriate source voice from the voice pool.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="format">The format that the voice must match.</param>
 | 
				
			||||||
 | 
						/// <returns>A source voice with the given format.</returns>
 | 
				
			||||||
 | 
						public T Obtain<T>(Format format) where T : SourceVoice, IPoolable<T>
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								lock (StateLock)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									T voice = VoicePool.Obtain<T>(format);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (voice is UpdatingSourceVoice updatingSourceVoice)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										updatingSourceVoices.Add(updatingSourceVoice);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return voice;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Returns the source voice to the voice pool.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="voice"></param>
 | 
				
			||||||
 | 
						internal void Return(SourceVoice voice)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								lock (StateLock)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									VoicesToReturn.Add(voice);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						internal void WakeThread()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								WakeSignal.Set();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						internal void AddResourceReference(GCHandle resourceReference)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								lock (StateLock)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									resourceHandles.Add(resourceReference);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (resourceReference.Target is UpdatingSourceVoice updatableVoice)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										updatingSourceVoices.Add(updatableVoice);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						internal void RemoveResourceReference(GCHandle resourceReference)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								lock (StateLock)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									resourceHandles.Remove(resourceReference);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (resourceReference.Target is UpdatingSourceVoice updatableVoice)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										updatingSourceVoices.Remove(updatableVoice);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected virtual void Dispose(bool disposing)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								if (!IsDisposed)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									Running = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (disposing)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Thread.Join();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// dispose all source voices first
 | 
				
			||||||
 | 
										foreach (GCHandle handle in resourceHandles)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											if (handle.Target is SourceVoice voice)
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												voice.Dispose();
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// dispose all submix voices except the faux mastering voice
 | 
				
			||||||
 | 
										foreach (GCHandle handle in resourceHandles)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											if (handle.Target is SubmixVoice voice && voice != fauxMasteringVoice)
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												voice.Dispose();
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// dispose the faux mastering voice
 | 
				
			||||||
 | 
										fauxMasteringVoice.Dispose();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// dispose the true mastering voice
 | 
				
			||||||
 | 
										FAudio.FAudioVoice_DestroyVoice(trueMasteringVoice);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// destroy all other audio resources
 | 
				
			||||||
 | 
										foreach (GCHandle handle in resourceHandles)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											if (handle.Target is AudioResource resource)
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												resource.Dispose();
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										resourceHandles.Clear();
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									FAudio.FAudio_Release(Handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									IsDisposed = true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						~AudioDevice()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
 | 
				
			||||||
 | 
								Dispose(disposing: false);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void Dispose()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
 | 
				
			||||||
 | 
								Dispose(disposing: true);
 | 
				
			||||||
 | 
								GC.SuppressFinalize(this);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										135
									
								
								Nerfed.Runtime/Audio/AudioEmitter.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								Nerfed.Runtime/Audio/AudioEmitter.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,135 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// An emitter for 3D spatial audio.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class AudioEmitter : AudioResource
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						internal FAudio.F3DAUDIO_EMITTER emitterData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public float DopplerScale
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return emitterData.DopplerScaler;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (value < 0.0f)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									throw new ArgumentOutOfRangeException("AudioEmitter.DopplerScale must be greater than or equal to 0.0f");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								emitterData.DopplerScaler = value;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Vector3 Forward
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return new Vector3(
 | 
				
			||||||
 | 
									emitterData.OrientFront.x,
 | 
				
			||||||
 | 
									emitterData.OrientFront.y,
 | 
				
			||||||
 | 
									-emitterData.OrientFront.z
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								emitterData.OrientFront.x = value.X;
 | 
				
			||||||
 | 
								emitterData.OrientFront.y = value.Y;
 | 
				
			||||||
 | 
								emitterData.OrientFront.z = -value.Z;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Vector3 Position
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return new Vector3(
 | 
				
			||||||
 | 
									emitterData.Position.x,
 | 
				
			||||||
 | 
									emitterData.Position.y,
 | 
				
			||||||
 | 
									-emitterData.Position.z
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								emitterData.Position.x = value.X;
 | 
				
			||||||
 | 
								emitterData.Position.y = value.Y;
 | 
				
			||||||
 | 
								emitterData.Position.z = -value.Z;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Vector3 Up
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return new Vector3(
 | 
				
			||||||
 | 
									emitterData.OrientTop.x,
 | 
				
			||||||
 | 
									emitterData.OrientTop.y,
 | 
				
			||||||
 | 
									-emitterData.OrientTop.z
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								emitterData.OrientTop.x = value.X;
 | 
				
			||||||
 | 
								emitterData.OrientTop.y = value.Y;
 | 
				
			||||||
 | 
								emitterData.OrientTop.z = -value.Z;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Vector3 Velocity
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return new Vector3(
 | 
				
			||||||
 | 
									emitterData.Velocity.x,
 | 
				
			||||||
 | 
									emitterData.Velocity.y,
 | 
				
			||||||
 | 
									-emitterData.Velocity.z
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								emitterData.Velocity.x = value.X;
 | 
				
			||||||
 | 
								emitterData.Velocity.y = value.Y;
 | 
				
			||||||
 | 
								emitterData.Velocity.z = -value.Z;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static readonly float[] stereoAzimuth = new float[]
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							0.0f, 0.0f
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static readonly GCHandle stereoAzimuthHandle = GCHandle.Alloc(
 | 
				
			||||||
 | 
							stereoAzimuth,
 | 
				
			||||||
 | 
							GCHandleType.Pinned
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public AudioEmitter(AudioDevice device) : base(device)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							emitterData = new FAudio.F3DAUDIO_EMITTER();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							DopplerScale = 1f;
 | 
				
			||||||
 | 
							Forward = Vector3.UnitZ;
 | 
				
			||||||
 | 
							Position = Vector3.Zero;
 | 
				
			||||||
 | 
							Up = Vector3.UnitY;
 | 
				
			||||||
 | 
							Velocity = Vector3.Zero;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Unexposed variables, defaults based on XNA behavior */
 | 
				
			||||||
 | 
							emitterData.pCone = IntPtr.Zero;
 | 
				
			||||||
 | 
							emitterData.ChannelCount = 1;
 | 
				
			||||||
 | 
							emitterData.ChannelRadius = 1.0f;
 | 
				
			||||||
 | 
							emitterData.pChannelAzimuths = stereoAzimuthHandle.AddrOfPinnedObject();
 | 
				
			||||||
 | 
							emitterData.pVolumeCurve = IntPtr.Zero;
 | 
				
			||||||
 | 
							emitterData.pLFECurve = IntPtr.Zero;
 | 
				
			||||||
 | 
							emitterData.pLPFDirectCurve = IntPtr.Zero;
 | 
				
			||||||
 | 
							emitterData.pLPFReverbCurve = IntPtr.Zero;
 | 
				
			||||||
 | 
							emitterData.pReverbCurve = IntPtr.Zero;
 | 
				
			||||||
 | 
							emitterData.CurveDistanceScaler = 1.0f;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										97
									
								
								Nerfed.Runtime/Audio/AudioListener.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								Nerfed.Runtime/Audio/AudioListener.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,97 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// A listener for 3D spatial audio. Usually attached to a camera.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class AudioListener : AudioResource
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						internal FAudio.F3DAUDIO_LISTENER listenerData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Vector3 Forward
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return new Vector3(
 | 
				
			||||||
 | 
									listenerData.OrientFront.x,
 | 
				
			||||||
 | 
									listenerData.OrientFront.y,
 | 
				
			||||||
 | 
									-listenerData.OrientFront.z
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								listenerData.OrientFront.x = value.X;
 | 
				
			||||||
 | 
								listenerData.OrientFront.y = value.Y;
 | 
				
			||||||
 | 
								listenerData.OrientFront.z = -value.Z;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Vector3 Position
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return new Vector3(
 | 
				
			||||||
 | 
									listenerData.Position.x,
 | 
				
			||||||
 | 
									listenerData.Position.y,
 | 
				
			||||||
 | 
									-listenerData.Position.z
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								listenerData.Position.x = value.X;
 | 
				
			||||||
 | 
								listenerData.Position.y = value.Y;
 | 
				
			||||||
 | 
								listenerData.Position.z = -value.Z;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Vector3 Up
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return new Vector3(
 | 
				
			||||||
 | 
									listenerData.OrientTop.x,
 | 
				
			||||||
 | 
									listenerData.OrientTop.y,
 | 
				
			||||||
 | 
									-listenerData.OrientTop.z
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								listenerData.OrientTop.x = value.X;
 | 
				
			||||||
 | 
								listenerData.OrientTop.y = value.Y;
 | 
				
			||||||
 | 
								listenerData.OrientTop.z = -value.Z;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Vector3 Velocity
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return new Vector3(
 | 
				
			||||||
 | 
									listenerData.Velocity.x,
 | 
				
			||||||
 | 
									listenerData.Velocity.y,
 | 
				
			||||||
 | 
									-listenerData.Velocity.z
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								listenerData.Velocity.x = value.X;
 | 
				
			||||||
 | 
								listenerData.Velocity.y = value.Y;
 | 
				
			||||||
 | 
								listenerData.Velocity.z = -value.Z;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public AudioListener(AudioDevice device) : base(device)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							listenerData = new FAudio.F3DAUDIO_LISTENER();
 | 
				
			||||||
 | 
							Forward = Vector3.UnitZ;
 | 
				
			||||||
 | 
							Position = Vector3.Zero;
 | 
				
			||||||
 | 
							Up = Vector3.UnitY;
 | 
				
			||||||
 | 
							Velocity = Vector3.Zero;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Unexposed variables, defaults based on XNA behavior */
 | 
				
			||||||
 | 
							listenerData.pCone = IntPtr.Zero;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										52
									
								
								Nerfed.Runtime/Audio/AudioResource.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								Nerfed.Runtime/Audio/AudioResource.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public abstract class AudioResource : IDisposable
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public AudioDevice Device { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public bool IsDisposed { get; private set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private GCHandle SelfReference;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected AudioResource(AudioDevice device)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								Device = device;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								SelfReference = GCHandle.Alloc(this, GCHandleType.Weak);
 | 
				
			||||||
 | 
								Device.AddResourceReference(SelfReference);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected virtual void Dispose(bool disposing)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								if (!IsDisposed)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (disposing)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Device.RemoveResourceReference(SelfReference);
 | 
				
			||||||
 | 
										SelfReference.Free();
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									IsDisposed = true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						~AudioResource()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
							// If you see this log message, you leaked an audio resource without disposing it!
 | 
				
			||||||
 | 
							// We can't clean it up for you because this can cause catastrophic issues.
 | 
				
			||||||
 | 
							// You should really fix this when it happens.
 | 
				
			||||||
 | 
							Log.Warning($"A resource of type {GetType().Name} was not Disposed.");
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void Dispose()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
 | 
				
			||||||
 | 
								Dispose(disposing: true);
 | 
				
			||||||
 | 
								GC.SuppressFinalize(this);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										9
									
								
								Nerfed.Runtime/Audio/FilterType.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								Nerfed.Runtime/Audio/FilterType.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					namespace Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public enum FilterType
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						None,
 | 
				
			||||||
 | 
						LowPass,
 | 
				
			||||||
 | 
						BandPass,
 | 
				
			||||||
 | 
						HighPass
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										35
									
								
								Nerfed.Runtime/Audio/Format.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								Nerfed.Runtime/Audio/Format.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					namespace Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public enum FormatTag : ushort
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						Unknown = 0,
 | 
				
			||||||
 | 
						PCM = 1,
 | 
				
			||||||
 | 
						MSADPCM = 2,
 | 
				
			||||||
 | 
						IEEE_FLOAT = 3
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Describes the format of audio data. Usually specified in an audio file's header information.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public record struct Format
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public FormatTag Tag;
 | 
				
			||||||
 | 
						public ushort Channels;
 | 
				
			||||||
 | 
						public uint SampleRate;
 | 
				
			||||||
 | 
						public ushort BitsPerSample;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						internal FAudio.FAudioWaveFormatEx ToFAudioFormat()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							ushort blockAlign = (ushort) ((BitsPerSample / 8) * Channels);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return new FAudio.FAudioWaveFormatEx
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								wFormatTag = (ushort) Tag,
 | 
				
			||||||
 | 
								nChannels = Channels,
 | 
				
			||||||
 | 
								nSamplesPerSec = SampleRate,
 | 
				
			||||||
 | 
								wBitsPerSample = BitsPerSample,
 | 
				
			||||||
 | 
								nBlockAlign = blockAlign,
 | 
				
			||||||
 | 
								nAvgBytesPerSec = blockAlign * SampleRate
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										6
									
								
								Nerfed.Runtime/Audio/IPoolable.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Nerfed.Runtime/Audio/IPoolable.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					namespace Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public interface IPoolable<T>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static abstract T Create(AudioDevice device, Format format);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										27
									
								
								Nerfed.Runtime/Audio/PersistentVoice.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								Nerfed.Runtime/Audio/PersistentVoice.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					namespace Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// PersistentVoice should be used when you need to maintain a long-term reference to a source voice.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class PersistentVoice : SourceVoice, IPoolable<PersistentVoice>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public PersistentVoice(AudioDevice device, Format format) : base(device, format)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static PersistentVoice Create(AudioDevice device, Format format)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								return new PersistentVoice(device, format);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Adds an AudioBuffer to the voice queue.
 | 
				
			||||||
 | 
						/// The voice processes and plays back the buffers in its queue in the order that they were submitted.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="buffer">The buffer to submit to the voice.</param>
 | 
				
			||||||
 | 
						/// <param name="loop">Whether the voice should loop this buffer.</param>
 | 
				
			||||||
 | 
						public void Submit(AudioBuffer buffer, bool loop = false)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								Submit(buffer.ToFAudioBuffer(loop));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										82
									
								
								Nerfed.Runtime/Audio/ReverbEffect.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								Nerfed.Runtime/Audio/ReverbEffect.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Use this in conjunction with SourceVoice.SetReverbEffectChain to add reverb to a voice.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public unsafe class ReverbEffect : SubmixVoice
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						// Defaults based on FAUDIOFX_I3DL2_PRESET_GENERIC
 | 
				
			||||||
 | 
						public static FAudio.FAudioFXReverbParameters DefaultParams = new FAudio.FAudioFXReverbParameters
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							WetDryMix = 100.0f,
 | 
				
			||||||
 | 
							ReflectionsDelay = 7,
 | 
				
			||||||
 | 
							ReverbDelay = 11,
 | 
				
			||||||
 | 
							RearDelay = FAudio.FAUDIOFX_REVERB_DEFAULT_REAR_DELAY,
 | 
				
			||||||
 | 
							PositionLeft = FAudio.FAUDIOFX_REVERB_DEFAULT_POSITION,
 | 
				
			||||||
 | 
							PositionRight = FAudio.FAUDIOFX_REVERB_DEFAULT_POSITION,
 | 
				
			||||||
 | 
							PositionMatrixLeft = FAudio.FAUDIOFX_REVERB_DEFAULT_POSITION_MATRIX,
 | 
				
			||||||
 | 
							PositionMatrixRight = FAudio.FAUDIOFX_REVERB_DEFAULT_POSITION_MATRIX,
 | 
				
			||||||
 | 
							EarlyDiffusion = 15,
 | 
				
			||||||
 | 
							LateDiffusion = 15,
 | 
				
			||||||
 | 
							LowEQGain = 8,
 | 
				
			||||||
 | 
							LowEQCutoff = 4,
 | 
				
			||||||
 | 
							HighEQGain = 8,
 | 
				
			||||||
 | 
							HighEQCutoff = 6,
 | 
				
			||||||
 | 
							RoomFilterFreq = 5000f,
 | 
				
			||||||
 | 
							RoomFilterMain = -10f,
 | 
				
			||||||
 | 
							RoomFilterHF = -1f,
 | 
				
			||||||
 | 
							ReflectionsGain = -26.0200005f,
 | 
				
			||||||
 | 
							ReverbGain = 10.0f,
 | 
				
			||||||
 | 
							DecayTime = 1.49000001f,
 | 
				
			||||||
 | 
							Density = 100.0f,
 | 
				
			||||||
 | 
							RoomSize = FAudio.FAUDIOFX_REVERB_DEFAULT_ROOM_SIZE
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public FAudio.FAudioFXReverbParameters Params { get; private set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public ReverbEffect(AudioDevice audioDevice, uint processingStage) : base(audioDevice, 1, audioDevice.DeviceDetails.OutputFormat.Format.nSamplesPerSec, processingStage)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							/* Init reverb */
 | 
				
			||||||
 | 
							IntPtr reverb;
 | 
				
			||||||
 | 
							FAudio.FAudioCreateReverb(out reverb, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							FAudio.FAudioEffectChain chain = new FAudio.FAudioEffectChain();
 | 
				
			||||||
 | 
							FAudio.FAudioEffectDescriptor descriptor = new FAudio.FAudioEffectDescriptor
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								InitialState = 1,
 | 
				
			||||||
 | 
								OutputChannels = 1,
 | 
				
			||||||
 | 
								pEffect = reverb
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							chain.EffectCount = 1;
 | 
				
			||||||
 | 
							chain.pEffectDescriptors = (nint) (&descriptor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							FAudio.FAudioVoice_SetEffectChain(
 | 
				
			||||||
 | 
								Handle,
 | 
				
			||||||
 | 
								ref chain
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							FAudio.FAPOBase_Release(reverb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							SetParams(DefaultParams);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void SetParams(in FAudio.FAudioFXReverbParameters reverbParams)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Params = reverbParams;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							fixed (FAudio.FAudioFXReverbParameters* reverbParamsPtr = &reverbParams)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								FAudio.FAudioVoice_SetEffectParameters(
 | 
				
			||||||
 | 
									Handle,
 | 
				
			||||||
 | 
									0,
 | 
				
			||||||
 | 
									(nint) reverbParamsPtr,
 | 
				
			||||||
 | 
									(uint) Marshal.SizeOf<FAudio.FAudioFXReverbParameters>(),
 | 
				
			||||||
 | 
									0
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										63
									
								
								Nerfed.Runtime/Audio/SoundSequence.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								Nerfed.Runtime/Audio/SoundSequence.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
				
			|||||||
 | 
					namespace Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Plays back a series of AudioBuffers in sequence. Set the OnSoundNeeded callback to add AudioBuffers dynamically.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class SoundSequence : UpdatingSourceVoice, IPoolable<SoundSequence>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public int NeedSoundThreshold = 0;
 | 
				
			||||||
 | 
						public delegate void OnSoundNeededFunc();
 | 
				
			||||||
 | 
						public OnSoundNeededFunc OnSoundNeeded;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public SoundSequence(AudioDevice device, Format format) : base(device, format)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public SoundSequence(AudioDevice device, AudioBuffer templateSound) : base(device, templateSound.Format)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static SoundSequence Create(AudioDevice device, Format format)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								return new SoundSequence(device, format);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override void Update()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								lock (StateLock)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (State != SoundState.Playing) { return; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (NeedSoundThreshold > 0)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										int buffersNeeded = NeedSoundThreshold - (int) BuffersQueued;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										for (int i = 0; i < buffersNeeded; i += 1)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											if (OnSoundNeeded != null)
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												OnSoundNeeded();
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void EnqueueSound(AudioBuffer buffer)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
							if (!(buffer.Format == Format))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Log.Warning("Sound sequence audio format mismatch!");
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							lock (StateLock)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Submit(buffer.ToFAudioBuffer());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										8
									
								
								Nerfed.Runtime/Audio/SoundState.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								Nerfed.Runtime/Audio/SoundState.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					namespace Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public enum SoundState
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						Playing,
 | 
				
			||||||
 | 
						Paused,
 | 
				
			||||||
 | 
						Stopped
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										217
									
								
								Nerfed.Runtime/Audio/SourceVoice.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								Nerfed.Runtime/Audio/SourceVoice.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,217 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Emits audio from submitted audio buffers.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public abstract class SourceVoice : Voice
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						private Format format;
 | 
				
			||||||
 | 
						public Format Format => format;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected bool PlaybackInitiated;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// The number of buffers queued in the voice.
 | 
				
			||||||
 | 
						/// This includes the currently playing voice!
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public uint BuffersQueued
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								FAudio.FAudioSourceVoice_GetState(
 | 
				
			||||||
 | 
									Handle,
 | 
				
			||||||
 | 
									out FAudio.FAudioVoiceState state,
 | 
				
			||||||
 | 
									FAudio.FAUDIO_VOICE_NOSAMPLESPLAYED
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return state.BuffersQueued;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private SoundState state = SoundState.Stopped;
 | 
				
			||||||
 | 
						public SoundState State
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (BuffersQueued == 0)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									Stop();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return state;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							internal set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								state = value;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected object StateLock = new object();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public SourceVoice(
 | 
				
			||||||
 | 
							AudioDevice device,
 | 
				
			||||||
 | 
							Format format
 | 
				
			||||||
 | 
						) : base(device, format.Channels, device.DeviceDetails.OutputFormat.Format.nChannels)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							this.format = format;
 | 
				
			||||||
 | 
							FAudio.FAudioWaveFormatEx fAudioFormat = format.ToFAudioFormat();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							FAudio.FAudio_CreateSourceVoice(
 | 
				
			||||||
 | 
								device.Handle,
 | 
				
			||||||
 | 
								out handle,
 | 
				
			||||||
 | 
								ref fAudioFormat,
 | 
				
			||||||
 | 
								FAudio.FAUDIO_VOICE_USEFILTER,
 | 
				
			||||||
 | 
								FAudio.FAUDIO_DEFAULT_FREQ_RATIO,
 | 
				
			||||||
 | 
								IntPtr.Zero,
 | 
				
			||||||
 | 
								IntPtr.Zero, // default sends to mastering voice!
 | 
				
			||||||
 | 
								IntPtr.Zero
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							SetOutputVoice(device.MasteringVoice);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Starts consumption and processing of audio by the voice.
 | 
				
			||||||
 | 
						/// Delivers the result to any connected submix or mastering voice.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="syncGroup">Optional. Denotes that the operation will be pending until AudioDevice.TriggerSyncGroup is called.</param>
 | 
				
			||||||
 | 
						public void Play(uint syncGroup = FAudio.FAUDIO_COMMIT_NOW)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							lock (StateLock)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								FAudio.FAudioSourceVoice_Start(Handle, 0, syncGroup);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								State = SoundState.Playing;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Pauses playback.
 | 
				
			||||||
 | 
						/// All source buffers that are queued on the voice and the current cursor position are preserved.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="syncGroup">Optional. Denotes that the operation will be pending until AudioDevice.TriggerSyncGroup is called.</param>
 | 
				
			||||||
 | 
						public void Pause(uint syncGroup = FAudio.FAUDIO_COMMIT_NOW)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							lock (StateLock)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								FAudio.FAudioSourceVoice_Stop(Handle, 0, syncGroup);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								State = SoundState.Paused;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Stops looping the voice when it reaches the end of the current loop region.
 | 
				
			||||||
 | 
						/// If the cursor for the voice is not in a loop region, ExitLoop does nothing.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="syncGroup">Optional. Denotes that the operation will be pending until AudioDevice.TriggerSyncGroup is called.</param>
 | 
				
			||||||
 | 
						public void ExitLoop(uint syncGroup = FAudio.FAUDIO_COMMIT_NOW)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							lock (StateLock)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								FAudio.FAudioSourceVoice_ExitLoop(Handle, syncGroup);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Stops playback and removes all pending audio buffers from the voice queue.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="syncGroup">Optional. Denotes that the operation will be pending until AudioDevice.TriggerSyncGroup is called.</param>
 | 
				
			||||||
 | 
						public void Stop(uint syncGroup = FAudio.FAUDIO_COMMIT_NOW)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							lock (StateLock)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								FAudio.FAudioSourceVoice_Stop(Handle, 0, syncGroup);
 | 
				
			||||||
 | 
								FAudio.FAudioSourceVoice_FlushSourceBuffers(Handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								State = SoundState.Stopped;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Adds an AudioBuffer to the voice queue.
 | 
				
			||||||
 | 
						/// The voice processes and plays back the buffers in its queue in the order that they were submitted.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="buffer">The buffer to submit to the voice.</param>
 | 
				
			||||||
 | 
						public void Submit(AudioBuffer buffer)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Submit(buffer.ToFAudioBuffer());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Calculates positional sound. This must be called continuously to update positional sound.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="listener"></param>
 | 
				
			||||||
 | 
						/// <param name="emitter"></param>
 | 
				
			||||||
 | 
						public unsafe void Apply3D(AudioListener listener, AudioEmitter emitter)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Is3D = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							emitter.emitterData.CurveDistanceScaler = Device.CurveDistanceScalar;
 | 
				
			||||||
 | 
							emitter.emitterData.ChannelCount = SourceChannelCount;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							FAudio.F3DAUDIO_DSP_SETTINGS dspSettings = new FAudio.F3DAUDIO_DSP_SETTINGS
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								DopplerFactor = DopplerFactor,
 | 
				
			||||||
 | 
								SrcChannelCount = SourceChannelCount,
 | 
				
			||||||
 | 
								DstChannelCount = DestinationChannelCount,
 | 
				
			||||||
 | 
								pMatrixCoefficients = (nint) pMatrixCoefficients
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							FAudio.F3DAudioCalculate(
 | 
				
			||||||
 | 
								Device.Handle3D,
 | 
				
			||||||
 | 
								ref listener.listenerData,
 | 
				
			||||||
 | 
								ref emitter.emitterData,
 | 
				
			||||||
 | 
								FAudio.F3DAUDIO_CALCULATE_MATRIX | FAudio.F3DAUDIO_CALCULATE_DOPPLER,
 | 
				
			||||||
 | 
								ref dspSettings
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							UpdatePitch();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							FAudio.FAudioVoice_SetOutputMatrix(
 | 
				
			||||||
 | 
								Handle,
 | 
				
			||||||
 | 
								OutputVoice.Handle,
 | 
				
			||||||
 | 
								SourceChannelCount,
 | 
				
			||||||
 | 
								DestinationChannelCount,
 | 
				
			||||||
 | 
								(nint) pMatrixCoefficients,
 | 
				
			||||||
 | 
								0
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Specifies that this source voice can be returned to the voice pool.
 | 
				
			||||||
 | 
						/// Holding on to the reference after calling this will cause problems!
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public void Return()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Stop();
 | 
				
			||||||
 | 
							Device.Return(this);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Adds an FAudio buffer to the voice queue.
 | 
				
			||||||
 | 
						/// The voice processes and plays back the buffers in its queue in the order that they were submitted.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="buffer">The buffer to submit to the voice.</param>
 | 
				
			||||||
 | 
						protected void Submit(FAudio.FAudioBuffer buffer)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							lock (StateLock)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								FAudio.FAudioSourceVoice_SubmitSourceBuffer(
 | 
				
			||||||
 | 
									Handle,
 | 
				
			||||||
 | 
									ref buffer,
 | 
				
			||||||
 | 
									IntPtr.Zero
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override void Reset()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Stop();
 | 
				
			||||||
 | 
							PlaybackInitiated = false;
 | 
				
			||||||
 | 
							base.Reset();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										38
									
								
								Nerfed.Runtime/Audio/SourceVoicePool.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								Nerfed.Runtime/Audio/SourceVoicePool.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					internal class SourceVoicePool
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						private AudioDevice Device;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Dictionary<(System.Type, Format), Queue<SourceVoice>> VoiceLists = new Dictionary<(System.Type, Format), Queue<SourceVoice>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public SourceVoicePool(AudioDevice device)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								Device = device;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public T Obtain<T>(Format format) where T : SourceVoice, IPoolable<T>
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								if (!VoiceLists.ContainsKey((typeof(T), format)))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									VoiceLists.Add((typeof(T), format), new Queue<SourceVoice>());
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Queue<SourceVoice> list = VoiceLists[(typeof(T), format)];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (list.Count == 0)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									list.Enqueue(T.Create(Device, format));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return (T) list.Dequeue();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void Return(SourceVoice voice)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								Queue<SourceVoice> list = VoiceLists[(voice.GetType(), voice.Format)];
 | 
				
			||||||
 | 
								list.Enqueue(voice);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										168
									
								
								Nerfed.Runtime/Audio/StreamingVoice.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								Nerfed.Runtime/Audio/StreamingVoice.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,168 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Use in conjunction with an AudioDataStreamable object to play back streaming audio data.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class StreamingVoice : UpdatingSourceVoice, IPoolable<StreamingVoice>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						private const int BUFFER_COUNT = 3;
 | 
				
			||||||
 | 
						private readonly IntPtr[] buffers;
 | 
				
			||||||
 | 
						private int nextBufferIndex = 0;
 | 
				
			||||||
 | 
						private uint BufferSize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public bool Loop { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public AudioDataStreamable AudioData { get; protected set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public unsafe StreamingVoice(AudioDevice device, Format format) : base(device, format)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							buffers = new IntPtr[BUFFER_COUNT];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static StreamingVoice Create(AudioDevice device, Format format)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new StreamingVoice(device, format);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Loads and prepares an AudioDataStreamable for streaming playback.
 | 
				
			||||||
 | 
						/// This automatically calls Load on the given AudioDataStreamable.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public void Load(AudioDataStreamable data)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							lock (StateLock)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (AudioData != null)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									AudioData.Unload();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								data.Load();
 | 
				
			||||||
 | 
								AudioData = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								InitializeBuffers();
 | 
				
			||||||
 | 
								QueueBuffers();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Unloads AudioDataStreamable from this voice.
 | 
				
			||||||
 | 
						/// This automatically calls Unload on the given AudioDataStreamable.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public void Unload()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							lock (StateLock)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (AudioData != null)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									Stop();
 | 
				
			||||||
 | 
									AudioData.Unload();
 | 
				
			||||||
 | 
									AudioData = null;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override void Reset()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Unload();
 | 
				
			||||||
 | 
							base.Reset();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override void Update()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							lock (StateLock)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (AudioData == null || State != SoundState.Playing)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								QueueBuffers();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void QueueBuffers()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							int buffersNeeded = BUFFER_COUNT - (int) BuffersQueued; // don't get got by uint underflow!
 | 
				
			||||||
 | 
							for (int i = 0; i < buffersNeeded; i += 1)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								AddBuffer();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private unsafe void AddBuffer()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							IntPtr buffer = buffers[nextBufferIndex];
 | 
				
			||||||
 | 
							nextBufferIndex = (nextBufferIndex + 1) % BUFFER_COUNT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							AudioData.Decode(
 | 
				
			||||||
 | 
								(void*) buffer,
 | 
				
			||||||
 | 
								(int) BufferSize,
 | 
				
			||||||
 | 
								out int filledLengthInBytes,
 | 
				
			||||||
 | 
								out bool reachedEnd
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (filledLengthInBytes > 0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								FAudio.FAudioBuffer buf = new FAudio.FAudioBuffer
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									AudioBytes = (uint) filledLengthInBytes,
 | 
				
			||||||
 | 
									pAudioData = buffer,
 | 
				
			||||||
 | 
									PlayLength = (
 | 
				
			||||||
 | 
										(uint) (filledLengthInBytes /
 | 
				
			||||||
 | 
										        Format.Channels /
 | 
				
			||||||
 | 
										        (uint) (Format.BitsPerSample / 8))
 | 
				
			||||||
 | 
									)
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Submit(buf);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (reachedEnd)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								/* We have reached the end of the data, what do we do? */
 | 
				
			||||||
 | 
								if (Loop)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									AudioData.Seek(0);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private unsafe void InitializeBuffers()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							BufferSize = AudioData.DecodeBufferSize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (int i = 0; i < BUFFER_COUNT; i += 1)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (buffers[i] != IntPtr.Zero)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									NativeMemory.Free((void*) buffers[i]);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								buffers[i] = (IntPtr) NativeMemory.Alloc(BufferSize);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected override unsafe void Dispose(bool disposing)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (!IsDisposed)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								lock (StateLock)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									Stop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									for (int i = 0; i < BUFFER_COUNT; i += 1)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										if (buffers[i] != IntPtr.Zero)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											NativeMemory.Free((void*) buffers[i]);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							base.Dispose(disposing);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										55
									
								
								Nerfed.Runtime/Audio/SubmixVoice.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								Nerfed.Runtime/Audio/SubmixVoice.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// SourceVoices can send audio to a SubmixVoice for convenient effects processing.
 | 
				
			||||||
 | 
					/// Submixes process in order of processingStage, from lowest to highest.
 | 
				
			||||||
 | 
					/// Therefore submixes early in a chain should have a low processingStage, and later in the chain they should have a higher one.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class SubmixVoice : Voice
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public SubmixVoice(
 | 
				
			||||||
 | 
							AudioDevice device,
 | 
				
			||||||
 | 
							uint sourceChannelCount,
 | 
				
			||||||
 | 
							uint sampleRate,
 | 
				
			||||||
 | 
							uint processingStage
 | 
				
			||||||
 | 
						) : base(device, sourceChannelCount, device.DeviceDetails.OutputFormat.Format.nChannels)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							FAudio.FAudio_CreateSubmixVoice(
 | 
				
			||||||
 | 
								device.Handle,
 | 
				
			||||||
 | 
								out handle,
 | 
				
			||||||
 | 
								sourceChannelCount,
 | 
				
			||||||
 | 
								sampleRate,
 | 
				
			||||||
 | 
								FAudio.FAUDIO_VOICE_USEFILTER,
 | 
				
			||||||
 | 
								processingStage,
 | 
				
			||||||
 | 
								IntPtr.Zero,
 | 
				
			||||||
 | 
								IntPtr.Zero
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							SetOutputVoice(device.MasteringVoice);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private SubmixVoice(
 | 
				
			||||||
 | 
							AudioDevice device
 | 
				
			||||||
 | 
						) : base(device, device.DeviceDetails.OutputFormat.Format.nChannels, device.DeviceDetails.OutputFormat.Format.nChannels)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							FAudio.FAudio_CreateSubmixVoice(
 | 
				
			||||||
 | 
								device.Handle,
 | 
				
			||||||
 | 
								out handle,
 | 
				
			||||||
 | 
								device.DeviceDetails.OutputFormat.Format.nChannels,
 | 
				
			||||||
 | 
								device.DeviceDetails.OutputFormat.Format.nSamplesPerSec,
 | 
				
			||||||
 | 
								FAudio.FAUDIO_VOICE_USEFILTER,
 | 
				
			||||||
 | 
								int.MaxValue,
 | 
				
			||||||
 | 
								IntPtr.Zero, // default sends to mastering voice
 | 
				
			||||||
 | 
								IntPtr.Zero
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							OutputVoice = null;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						internal static SubmixVoice CreateFauxMasteringVoice(AudioDevice device)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new SubmixVoice(device);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										28
									
								
								Nerfed.Runtime/Audio/TransientVoice.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								Nerfed.Runtime/Audio/TransientVoice.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					namespace Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// TransientVoice is intended for playing one-off sound effects that don't have a long term reference. <br/>
 | 
				
			||||||
 | 
					/// It will be automatically returned to the AudioDevice SourceVoice pool once it is done playing back.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class TransientVoice : UpdatingSourceVoice, IPoolable<TransientVoice>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static TransientVoice IPoolable<TransientVoice>.Create(AudioDevice device, Format format)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								return new TransientVoice(device, format);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public TransientVoice(AudioDevice device, Format format) : base(device, format)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override void Update()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								lock (StateLock)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (PlaybackInitiated && BuffersQueued == 0)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Return();
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										10
									
								
								Nerfed.Runtime/Audio/UpdatingSourceVoice.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Nerfed.Runtime/Audio/UpdatingSourceVoice.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					namespace Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public abstract class UpdatingSourceVoice : SourceVoice
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						protected UpdatingSourceVoice(AudioDevice device, Format format) : base(device, format)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public abstract void Update();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										433
									
								
								Nerfed.Runtime/Audio/Voice.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										433
									
								
								Nerfed.Runtime/Audio/Voice.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,433 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					using EasingFunction = System.Func<float, float>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Handles audio playback from audio buffer data. Can be configured with a variety of parameters.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public abstract unsafe class Voice : AudioResource
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						protected IntPtr handle;
 | 
				
			||||||
 | 
						public IntPtr Handle => handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public uint SourceChannelCount { get; }
 | 
				
			||||||
 | 
						public uint DestinationChannelCount { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected SubmixVoice OutputVoice;
 | 
				
			||||||
 | 
						private ReverbEffect ReverbEffect;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected byte* pMatrixCoefficients;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public bool Is3D { get; protected set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private float dopplerFactor;
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// The strength of the doppler effect on this voice.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public float DopplerFactor
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get => dopplerFactor;
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (dopplerFactor != value)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									dopplerFactor = value;
 | 
				
			||||||
 | 
									UpdatePitch();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private float volume = 1;
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// The overall volume level for the voice.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public float Volume
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get => volume;
 | 
				
			||||||
 | 
							internal set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								value = MathF.Max(0f, value);
 | 
				
			||||||
 | 
								if (volume != value)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									volume = value;
 | 
				
			||||||
 | 
									FAudio.FAudioVoice_SetVolume(Handle, volume, 0);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private float pitch = 0;
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// The pitch of the voice.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public float Pitch
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get => pitch;
 | 
				
			||||||
 | 
							internal set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								value = Math.Clamp(value, -1f, 1f);
 | 
				
			||||||
 | 
								if (pitch != value)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									pitch = value;
 | 
				
			||||||
 | 
									UpdatePitch();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private const float MAX_FILTER_FREQUENCY = 1f;
 | 
				
			||||||
 | 
						private const float MAX_FILTER_ONEOVERQ = 1.5f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private FAudio.FAudioFilterParameters filterParameters = new FAudio.FAudioFilterParameters
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Type = FAudio.FAudioFilterType.FAudioLowPassFilter,
 | 
				
			||||||
 | 
							Frequency = 1f,
 | 
				
			||||||
 | 
							OneOverQ = 1f
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// The frequency cutoff on the voice filter.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public float FilterFrequency
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get => filterParameters.Frequency;
 | 
				
			||||||
 | 
							internal set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								value = System.Math.Clamp(value, 0.01f, MAX_FILTER_FREQUENCY);
 | 
				
			||||||
 | 
								if (filterParameters.Frequency != value)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									filterParameters.Frequency = value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									FAudio.FAudioVoice_SetFilterParameters(
 | 
				
			||||||
 | 
										Handle,
 | 
				
			||||||
 | 
										ref filterParameters,
 | 
				
			||||||
 | 
										0
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Reciprocal of Q factor.
 | 
				
			||||||
 | 
						/// Controls how quickly frequencies beyond the filter frequency are dampened.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public float FilterOneOverQ
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get => filterParameters.OneOverQ;
 | 
				
			||||||
 | 
							internal set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								value = System.Math.Clamp(value, 0.01f, MAX_FILTER_ONEOVERQ);
 | 
				
			||||||
 | 
								if (filterParameters.OneOverQ != value)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									filterParameters.OneOverQ = value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									FAudio.FAudioVoice_SetFilterParameters(
 | 
				
			||||||
 | 
										Handle,
 | 
				
			||||||
 | 
										ref filterParameters,
 | 
				
			||||||
 | 
										0
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private FilterType filterType;
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// The frequency filter that is applied to the voice.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public FilterType FilterType
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get => filterType;
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (filterType != value)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									filterType = value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									switch (filterType)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										case FilterType.None:
 | 
				
			||||||
 | 
											filterParameters = new FAudio.FAudioFilterParameters
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Type = FAudio.FAudioFilterType.FAudioLowPassFilter,
 | 
				
			||||||
 | 
												Frequency = 1f,
 | 
				
			||||||
 | 
												OneOverQ = 1f
 | 
				
			||||||
 | 
											};
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										case FilterType.LowPass:
 | 
				
			||||||
 | 
											filterParameters.Type = FAudio.FAudioFilterType.FAudioLowPassFilter;
 | 
				
			||||||
 | 
											filterParameters.Frequency = 1f;
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										case FilterType.BandPass:
 | 
				
			||||||
 | 
											filterParameters.Type = FAudio.FAudioFilterType.FAudioBandPassFilter;
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										case FilterType.HighPass:
 | 
				
			||||||
 | 
											filterParameters.Type = FAudio.FAudioFilterType.FAudioHighPassFilter;
 | 
				
			||||||
 | 
											filterParameters.Frequency = 0f;
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									FAudio.FAudioVoice_SetFilterParameters(
 | 
				
			||||||
 | 
										Handle,
 | 
				
			||||||
 | 
										ref filterParameters,
 | 
				
			||||||
 | 
										0
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected float pan = 0;
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Left-right panning. -1 is hard left pan, 1 is hard right pan.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public float Pan
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get => pan;
 | 
				
			||||||
 | 
							internal set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								value = Math.Clamp(value, -1f, 1f);
 | 
				
			||||||
 | 
								if (pan != value)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									pan = value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (pan < -1f)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										pan = -1f;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (pan > 1f)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										pan = 1f;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (Is3D) { return; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									SetPanMatrixCoefficients();
 | 
				
			||||||
 | 
									FAudio.FAudioVoice_SetOutputMatrix(
 | 
				
			||||||
 | 
										Handle,
 | 
				
			||||||
 | 
										OutputVoice.Handle,
 | 
				
			||||||
 | 
										SourceChannelCount,
 | 
				
			||||||
 | 
										DestinationChannelCount,
 | 
				
			||||||
 | 
										(nint) pMatrixCoefficients,
 | 
				
			||||||
 | 
										0
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private float reverb;
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// The wet-dry mix of the reverb effect.
 | 
				
			||||||
 | 
						/// Has no effect if SetReverbEffectChain has not been called.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public unsafe float Reverb
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get => reverb;
 | 
				
			||||||
 | 
							internal set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (ReverbEffect != null)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									value = MathF.Max(0, value);
 | 
				
			||||||
 | 
									if (reverb != value)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										reverb = value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										float* outputMatrix = (float*) pMatrixCoefficients;
 | 
				
			||||||
 | 
										outputMatrix[0] = reverb;
 | 
				
			||||||
 | 
										if (SourceChannelCount == 2)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											outputMatrix[1] = reverb;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										FAudio.FAudioVoice_SetOutputMatrix(
 | 
				
			||||||
 | 
											Handle,
 | 
				
			||||||
 | 
											ReverbEffect.Handle,
 | 
				
			||||||
 | 
											SourceChannelCount,
 | 
				
			||||||
 | 
											1,
 | 
				
			||||||
 | 
											(nint) pMatrixCoefficients,
 | 
				
			||||||
 | 
											0
 | 
				
			||||||
 | 
										);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
								if (ReverbEffect == null)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									Log.Warning("Tried to set reverb value before applying a reverb effect");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Voice(AudioDevice device, uint sourceChannelCount, uint destinationChannelCount) : base(device)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							SourceChannelCount = sourceChannelCount;
 | 
				
			||||||
 | 
							DestinationChannelCount = destinationChannelCount;
 | 
				
			||||||
 | 
							nuint memsize = 4 * sourceChannelCount * destinationChannelCount;
 | 
				
			||||||
 | 
							pMatrixCoefficients = (byte*) NativeMemory.AllocZeroed(memsize);
 | 
				
			||||||
 | 
							SetPanMatrixCoefficients();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Sets the output voice for this voice.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="send">Where the output should be sent.</param>
 | 
				
			||||||
 | 
						public unsafe void SetOutputVoice(SubmixVoice send)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							OutputVoice = send;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ReverbEffect != null)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								SetReverbEffectChain(ReverbEffect);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								FAudio.FAudioSendDescriptor* sendDesc = stackalloc FAudio.FAudioSendDescriptor[1];
 | 
				
			||||||
 | 
								sendDesc[0].Flags = 0;
 | 
				
			||||||
 | 
								sendDesc[0].pOutputVoice = send.Handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								FAudio.FAudioVoiceSends sends = new FAudio.FAudioVoiceSends();
 | 
				
			||||||
 | 
								sends.SendCount = 1;
 | 
				
			||||||
 | 
								sends.pSends = (nint) sendDesc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								FAudio.FAudioVoice_SetOutputVoices(
 | 
				
			||||||
 | 
									Handle,
 | 
				
			||||||
 | 
									ref sends
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Applies a reverb effect chain to this voice.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public unsafe void SetReverbEffectChain(ReverbEffect reverbEffect)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							FAudio.FAudioSendDescriptor* sendDesc = stackalloc FAudio.FAudioSendDescriptor[2];
 | 
				
			||||||
 | 
							sendDesc[0].Flags = 0;
 | 
				
			||||||
 | 
							sendDesc[0].pOutputVoice = OutputVoice.Handle;
 | 
				
			||||||
 | 
							sendDesc[1].Flags = 0;
 | 
				
			||||||
 | 
							sendDesc[1].pOutputVoice = reverbEffect.Handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							FAudio.FAudioVoiceSends sends = new FAudio.FAudioVoiceSends();
 | 
				
			||||||
 | 
							sends.SendCount = 2;
 | 
				
			||||||
 | 
							sends.pSends = (nint) sendDesc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							FAudio.FAudioVoice_SetOutputVoices(
 | 
				
			||||||
 | 
								Handle,
 | 
				
			||||||
 | 
								ref sends
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ReverbEffect = reverbEffect;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Removes the reverb effect chain from this voice.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public void RemoveReverbEffectChain()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (ReverbEffect != null)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								ReverbEffect = null;
 | 
				
			||||||
 | 
								reverb = 0;
 | 
				
			||||||
 | 
								SetOutputVoice(OutputVoice);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Resets all voice parameters to defaults.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public virtual void Reset()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							RemoveReverbEffectChain();
 | 
				
			||||||
 | 
							Volume = 1;
 | 
				
			||||||
 | 
							Pan = 0;
 | 
				
			||||||
 | 
							Pitch = 0;
 | 
				
			||||||
 | 
							FilterType = FilterType.None;
 | 
				
			||||||
 | 
							SetOutputVoice(Device.MasteringVoice);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Taken from https://github.com/FNA-XNA/FNA/blob/master/src/Audio/SoundEffectInstance.cs
 | 
				
			||||||
 | 
						private unsafe void SetPanMatrixCoefficients()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							/* Two major things to notice:
 | 
				
			||||||
 | 
							 * 1. The spec assumes any speaker count >= 2 has Front Left/Right.
 | 
				
			||||||
 | 
							 * 2. Stereo panning is WAY more complicated than you think.
 | 
				
			||||||
 | 
							 *    The main thing is that hard panning does NOT eliminate an
 | 
				
			||||||
 | 
							 *    entire channel; the two channels are blended on each side.
 | 
				
			||||||
 | 
							 * -flibit
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							float* outputMatrix = (float*) pMatrixCoefficients;
 | 
				
			||||||
 | 
							if (SourceChannelCount == 1)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (DestinationChannelCount == 1)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									outputMatrix[0] = 1.0f;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									outputMatrix[0] = (pan > 0.0f) ? (1.0f - pan) : 1.0f;
 | 
				
			||||||
 | 
									outputMatrix[1] = (pan < 0.0f) ? (1.0f + pan) : 1.0f;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (DestinationChannelCount == 1)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									outputMatrix[0] = 1.0f;
 | 
				
			||||||
 | 
									outputMatrix[1] = 1.0f;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (pan <= 0.0f)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										// Left speaker blends left/right channels
 | 
				
			||||||
 | 
										outputMatrix[0] = 0.5f * pan + 1.0f;
 | 
				
			||||||
 | 
										outputMatrix[1] = 0.5f * -pan;
 | 
				
			||||||
 | 
										// Right speaker gets less of the right channel
 | 
				
			||||||
 | 
										outputMatrix[2] = 0.0f;
 | 
				
			||||||
 | 
										outputMatrix[3] = pan + 1.0f;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										// Left speaker gets less of the left channel
 | 
				
			||||||
 | 
										outputMatrix[0] = -pan + 1.0f;
 | 
				
			||||||
 | 
										outputMatrix[1] = 0.0f;
 | 
				
			||||||
 | 
										// Right speaker blends right/left channels
 | 
				
			||||||
 | 
										outputMatrix[2] = 0.5f * pan;
 | 
				
			||||||
 | 
										outputMatrix[3] = 0.5f * -pan + 1.0f;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected void UpdatePitch()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							float doppler;
 | 
				
			||||||
 | 
							float dopplerScale = Device.DopplerScale;
 | 
				
			||||||
 | 
							if (!Is3D || dopplerScale == 0.0f)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								doppler = 1.0f;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								doppler = DopplerFactor * dopplerScale;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							FAudio.FAudioSourceVoice_SetFrequencyRatio(
 | 
				
			||||||
 | 
								Handle,
 | 
				
			||||||
 | 
								(float) System.Math.Pow(2.0, pitch) * doppler,
 | 
				
			||||||
 | 
								0
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected override unsafe void Dispose(bool disposing)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (!IsDisposed)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								NativeMemory.Free(pMatrixCoefficients);
 | 
				
			||||||
 | 
								FAudio.FAudioVoice_DestroyVoice(Handle);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							base.Dispose(disposing);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										27
									
								
								Nerfed.Runtime/CopyLibs.targets
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								Nerfed.Runtime/CopyLibs.targets
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					<?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>
 | 
				
			||||||
							
								
								
									
										252
									
								
								Nerfed.Runtime/Engine.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										252
									
								
								Nerfed.Runtime/Engine.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,252 @@
 | 
				
			|||||||
 | 
					using System.Diagnostics;
 | 
				
			||||||
 | 
					using Nerfed.Runtime.Audio;
 | 
				
			||||||
 | 
					using Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					using SDL2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public static class Engine
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public static TimeSpan MaxDeltaTime { get; set; } = TimeSpan.FromMilliseconds(100);
 | 
				
			||||||
 | 
					    public static bool VSync { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static GraphicsDevice GraphicsDevice { get; private set; }
 | 
				
			||||||
 | 
					    public static AudioDevice AudioDevice { get; private set; }
 | 
				
			||||||
 | 
					    public static Window MainWindow { get; private set; }
 | 
				
			||||||
 | 
					    public static TimeSpan Timestep { get; private set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static bool quit;
 | 
				
			||||||
 | 
					    private static Stopwatch gameTimer;
 | 
				
			||||||
 | 
					    private static long previousTicks = 0;
 | 
				
			||||||
 | 
					    private static TimeSpan accumulatedUpdateTime = TimeSpan.Zero;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static TimeSpan accumulatedDrawTime = TimeSpan.Zero;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // must be a power of 2 so we can do a bitmask optimization when checking worst case
 | 
				
			||||||
 | 
					    private const int previousSleepTimeCount = 128;
 | 
				
			||||||
 | 
					    private const int sleepTimeMask = previousSleepTimeCount - 1;
 | 
				
			||||||
 | 
					    private static readonly TimeSpan[] previousSleepTimes = new TimeSpan[previousSleepTimeCount];
 | 
				
			||||||
 | 
					    private static int sleepTimeIndex;
 | 
				
			||||||
 | 
					    private static TimeSpan worstCaseSleepPrecision = TimeSpan.FromMilliseconds(1);
 | 
				
			||||||
 | 
					    private static bool framerateCapped;
 | 
				
			||||||
 | 
					    private static TimeSpan framerateCapTimeSpan = TimeSpan.Zero;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //TODO: These are temp
 | 
				
			||||||
 | 
					    private const int MaxFps = 300;
 | 
				
			||||||
 | 
					    private const int TargetTimestep = 60;
 | 
				
			||||||
 | 
					    private const int WindowWidth = 1280;
 | 
				
			||||||
 | 
					    private const int WindowHeight = 720;
 | 
				
			||||||
 | 
					    private const string WindowTitle = "Nerfed";
 | 
				
			||||||
 | 
					    //..
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal static void Run(string[] args)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Timestep = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / TargetTimestep);
 | 
				
			||||||
 | 
					        gameTimer = Stopwatch.StartNew();
 | 
				
			||||||
 | 
					        SetFrameLimiter(new FrameLimiterSettings(FrameLimiterMode.Capped, MaxFps));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (int i = 0; i < previousSleepTimes.Length; i += 1)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            previousSleepTimes[i] = TimeSpan.FromMilliseconds(1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (SDL.SDL_Init(SDL.SDL_INIT_VIDEO | SDL.SDL_INIT_TIMER | SDL.SDL_INIT_GAMECONTROLLER) < 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            throw new Exception("Failed to init SDL");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        GraphicsDevice = new GraphicsDevice(BackendFlags.All);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        MainWindow = new Window(GraphicsDevice, new WindowCreateInfo(WindowTitle, WindowWidth, WindowHeight, ScreenMode.Windowed));
 | 
				
			||||||
 | 
					        if (!GraphicsDevice.ClaimWindow(MainWindow, SwapchainComposition.SDR, VSync ? PresentMode.VSync : PresentMode.Mailbox))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            throw new Exception("Failed to claim window");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        AudioDevice = new AudioDevice();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while (!quit)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Tick();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        GraphicsDevice.UnclaimWindow(MainWindow);
 | 
				
			||||||
 | 
					        MainWindow.Dispose();
 | 
				
			||||||
 | 
					        GraphicsDevice.Dispose();
 | 
				
			||||||
 | 
					        AudioDevice.Dispose();
 | 
				
			||||||
 | 
					        SDL.SDL_Quit();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Updates the frame limiter settings.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public static void SetFrameLimiter(FrameLimiterSettings settings)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        framerateCapped = settings.Mode == FrameLimiterMode.Capped;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (framerateCapped)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            framerateCapTimeSpan = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / settings.Cap);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            framerateCapTimeSpan = TimeSpan.Zero;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void Quit()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        quit = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static void Tick()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        AdvanceElapsedTime();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (framerateCapped)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            /* We want to wait until the framerate cap,
 | 
				
			||||||
 | 
					             * but we don't want to oversleep. Requesting repeated 1ms sleeps and
 | 
				
			||||||
 | 
					             * seeing how long we actually slept for lets us estimate the worst case
 | 
				
			||||||
 | 
					             * sleep precision so we don't oversleep the next frame.
 | 
				
			||||||
 | 
					             */
 | 
				
			||||||
 | 
					            while (accumulatedDrawTime + worstCaseSleepPrecision < framerateCapTimeSpan)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Thread.Sleep(1);
 | 
				
			||||||
 | 
					                TimeSpan timeAdvancedSinceSleeping = AdvanceElapsedTime();
 | 
				
			||||||
 | 
					                UpdateEstimatedSleepPrecision(timeAdvancedSinceSleeping);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* Now that we have slept into the sleep precision threshold, we need to wait
 | 
				
			||||||
 | 
					             * for just a little bit longer until the target elapsed time has been reached.
 | 
				
			||||||
 | 
					             * SpinWait(1) works by pausing the thread for very short intervals, so it is
 | 
				
			||||||
 | 
					             * an efficient and time-accurate way to wait out the rest of the time.
 | 
				
			||||||
 | 
					             */
 | 
				
			||||||
 | 
					            while (accumulatedDrawTime < framerateCapTimeSpan)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Thread.SpinWait(1);
 | 
				
			||||||
 | 
					                AdvanceElapsedTime();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Do not let any step take longer than our maximum.
 | 
				
			||||||
 | 
					        if (accumulatedUpdateTime > MaxDeltaTime)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            accumulatedUpdateTime = MaxDeltaTime;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!quit)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            while (accumulatedUpdateTime >= Timestep)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Keyboard.Update();
 | 
				
			||||||
 | 
					                Mouse.Update();
 | 
				
			||||||
 | 
					                GamePad.Update();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                ProcessSDLEvents();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // Tick game here...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                AudioDevice.WakeThread();
 | 
				
			||||||
 | 
					                accumulatedUpdateTime -= Timestep;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            double alpha = accumulatedUpdateTime / Timestep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Render here..
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            accumulatedDrawTime -= framerateCapTimeSpan;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static TimeSpan AdvanceElapsedTime()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        long currentTicks = gameTimer.Elapsed.Ticks;
 | 
				
			||||||
 | 
					        TimeSpan timeAdvanced = TimeSpan.FromTicks(currentTicks - previousTicks);
 | 
				
			||||||
 | 
					        accumulatedUpdateTime += timeAdvanced;
 | 
				
			||||||
 | 
					        accumulatedDrawTime += timeAdvanced;
 | 
				
			||||||
 | 
					        previousTicks = currentTicks;
 | 
				
			||||||
 | 
					        return timeAdvanced;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static void ProcessSDLEvents()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        while (SDL.SDL_PollEvent(out SDL.SDL_Event ev) == 1)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            switch (ev.type)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case SDL.SDL_EventType.SDL_QUIT:
 | 
				
			||||||
 | 
					                    Quit();
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case SDL.SDL_EventType.SDL_TEXTINPUT:
 | 
				
			||||||
 | 
					                case SDL.SDL_EventType.SDL_KEYDOWN:
 | 
				
			||||||
 | 
					                case SDL.SDL_EventType.SDL_KEYUP:
 | 
				
			||||||
 | 
					                    Keyboard.ProcessEvent(ref ev);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN:
 | 
				
			||||||
 | 
					                case SDL.SDL_EventType.SDL_MOUSEBUTTONUP:
 | 
				
			||||||
 | 
					                case SDL.SDL_EventType.SDL_MOUSEWHEEL:
 | 
				
			||||||
 | 
					                case SDL.SDL_EventType.SDL_MOUSEMOTION:
 | 
				
			||||||
 | 
					                    Mouse.ProcessEvent(ref ev);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case SDL.SDL_EventType.SDL_CONTROLLERDEVICEADDED:
 | 
				
			||||||
 | 
					                case SDL.SDL_EventType.SDL_CONTROLLERDEVICEREMOVED:
 | 
				
			||||||
 | 
					                case SDL.SDL_EventType.SDL_CONTROLLERBUTTONDOWN:
 | 
				
			||||||
 | 
					                case SDL.SDL_EventType.SDL_CONTROLLERBUTTONUP:
 | 
				
			||||||
 | 
					                case SDL.SDL_EventType.SDL_CONTROLLERAXISMOTION:
 | 
				
			||||||
 | 
					                case SDL.SDL_EventType.SDL_CONTROLLERTOUCHPADDOWN:
 | 
				
			||||||
 | 
					                case SDL.SDL_EventType.SDL_CONTROLLERTOUCHPADUP:
 | 
				
			||||||
 | 
					                case SDL.SDL_EventType.SDL_CONTROLLERTOUCHPADMOTION:
 | 
				
			||||||
 | 
					                case SDL.SDL_EventType.SDL_CONTROLLERSENSORUPDATE:
 | 
				
			||||||
 | 
					                    GamePad.ProcessEvent(ref ev);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case SDL.SDL_EventType.SDL_WINDOWEVENT:
 | 
				
			||||||
 | 
					                    Window.ProcessEvent(ref ev);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* To calculate the sleep precision of the OS, we take the worst case
 | 
				
			||||||
 | 
					     * time spent sleeping over the results of previous requests to sleep 1ms.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private static void UpdateEstimatedSleepPrecision(TimeSpan timeSpentSleeping)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        /* It is unlikely that the scheduler will actually be more imprecise than
 | 
				
			||||||
 | 
					         * 4ms and we don't want to get wrecked by a single long sleep so we cap this
 | 
				
			||||||
 | 
					         * value at 4ms for sanity.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        TimeSpan upperTimeBound = TimeSpan.FromMilliseconds(4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (timeSpentSleeping > upperTimeBound)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            timeSpentSleeping = upperTimeBound;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* We know the previous worst case - it's saved in worstCaseSleepPrecision.
 | 
				
			||||||
 | 
					         * We also know the current index. So the only way the worst case changes
 | 
				
			||||||
 | 
					         * is if we either 1) just got a new worst case, or 2) the worst case was
 | 
				
			||||||
 | 
					         * the oldest entry on the list.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        if (timeSpentSleeping >= worstCaseSleepPrecision)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            worstCaseSleepPrecision = timeSpentSleeping;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (previousSleepTimes[sleepTimeIndex] == worstCaseSleepPrecision)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            TimeSpan maxSleepTime = TimeSpan.MinValue;
 | 
				
			||||||
 | 
					            for (int i = 0; i < previousSleepTimes.Length; i++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (previousSleepTimes[i] > maxSleepTime)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    maxSleepTime = previousSleepTimes[i];
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            worstCaseSleepPrecision = maxSleepTime;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        previousSleepTimes[sleepTimeIndex] = timeSpentSleeping;
 | 
				
			||||||
 | 
					        sleepTimeIndex = (sleepTimeIndex + 1) & sleepTimeMask;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										35
									
								
								Nerfed.Runtime/FrameLimiterSettings.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								Nerfed.Runtime/FrameLimiterSettings.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					namespace Nerfed.Runtime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public enum FrameLimiterMode
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// The game will render at the maximum possible framerate that the computing resources allow. <br/>
 | 
				
			||||||
 | 
						/// Note that this may lead to overheating, resource starvation, etc.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						Uncapped,
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// The game will render no more than the specified frames per second.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						Capped
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// The Game's frame limiter setting. Specifies uncapped framerate or a maximum rendering frames per second value. <br/>
 | 
				
			||||||
 | 
					/// Note that this is separate from the Game's Update timestep and can be a different value.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public struct FrameLimiterSettings
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public FrameLimiterMode Mode;
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// If Mode is set to Capped, this is the maximum frames per second that will be rendered.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public int Cap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public FrameLimiterSettings(
 | 
				
			||||||
 | 
							FrameLimiterMode mode,
 | 
				
			||||||
 | 
							int cap
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							Mode = mode;
 | 
				
			||||||
 | 
							Cap = cap;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1948
									
								
								Nerfed.Runtime/Graphics/Color.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1948
									
								
								Nerfed.Runtime/Graphics/Color.cs
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1042
									
								
								Nerfed.Runtime/Graphics/CommandBuffer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1042
									
								
								Nerfed.Runtime/Graphics/CommandBuffer.cs
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										33
									
								
								Nerfed.Runtime/Graphics/CommandBufferPool.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								Nerfed.Runtime/Graphics/CommandBufferPool.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Concurrent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					internal class CommandBufferPool
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						private GraphicsDevice GraphicsDevice;
 | 
				
			||||||
 | 
						private ConcurrentQueue<CommandBuffer> CommandBuffers = new ConcurrentQueue<CommandBuffer>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public CommandBufferPool(GraphicsDevice graphicsDevice)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							GraphicsDevice = graphicsDevice;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public CommandBuffer Obtain()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (CommandBuffers.TryDequeue(out CommandBuffer commandBuffer))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return commandBuffer;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return new CommandBuffer(GraphicsDevice);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void Return(CommandBuffer commandBuffer)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							commandBuffer.Handle = IntPtr.Zero;
 | 
				
			||||||
 | 
							CommandBuffers.Enqueue(commandBuffer);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										171
									
								
								Nerfed.Runtime/Graphics/ComputePass.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								Nerfed.Runtime/Graphics/ComputePass.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,171 @@
 | 
				
			|||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					using RefreshCS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class ComputePass
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public nint Handle { get; private set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						internal void SetHandle(nint handle)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Handle = handle;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
						internal bool active;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ComputePipeline currentComputePipeline;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Binds a compute pipeline so that compute work may be dispatched.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="computePipeline">The compute pipeline to bind.</param>
 | 
				
			||||||
 | 
						public void BindComputePipeline(
 | 
				
			||||||
 | 
							ComputePipeline computePipeline
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
							AssertComputePassActive();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// TODO: validate formats?
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Refresh.Refresh_BindComputePipeline(
 | 
				
			||||||
 | 
								Handle,
 | 
				
			||||||
 | 
								computePipeline.Handle
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
							currentComputePipeline = computePipeline;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Binds a texture to be used in the compute shader.
 | 
				
			||||||
 | 
						/// This texture must have been created with the ComputeShaderRead usage flag.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public unsafe void BindStorageTexture(
 | 
				
			||||||
 | 
							in TextureSlice textureSlice,
 | 
				
			||||||
 | 
							uint slot = 0
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
							AssertComputePassActive();
 | 
				
			||||||
 | 
							AssertComputePipelineBound();
 | 
				
			||||||
 | 
							AssertTextureNonNull(textureSlice.Texture);
 | 
				
			||||||
 | 
							AssertTextureHasComputeStorageReadFlag(textureSlice.Texture);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Refresh.TextureSlice refreshTextureSlice = textureSlice.ToRefresh();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Refresh.Refresh_BindComputeStorageTextures(
 | 
				
			||||||
 | 
								Handle,
 | 
				
			||||||
 | 
								slot,
 | 
				
			||||||
 | 
								&refreshTextureSlice,
 | 
				
			||||||
 | 
								1
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Binds a buffer to be used in the compute shader.
 | 
				
			||||||
 | 
						/// This buffer must have been created with the ComputeShaderRead usage flag.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public unsafe void BindStorageBuffer(
 | 
				
			||||||
 | 
							Buffer buffer,
 | 
				
			||||||
 | 
							uint slot = 0
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
							AssertComputePassActive();
 | 
				
			||||||
 | 
							AssertComputePipelineBound();
 | 
				
			||||||
 | 
							AssertBufferNonNull(buffer);
 | 
				
			||||||
 | 
							AssertBufferHasComputeStorageReadFlag(buffer);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							IntPtr bufferHandle = buffer.Handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Refresh.Refresh_BindComputeStorageBuffers(
 | 
				
			||||||
 | 
								Handle,
 | 
				
			||||||
 | 
								slot,
 | 
				
			||||||
 | 
								&bufferHandle,
 | 
				
			||||||
 | 
								1
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Dispatches compute work.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public void Dispatch(
 | 
				
			||||||
 | 
							uint groupCountX,
 | 
				
			||||||
 | 
							uint groupCountY,
 | 
				
			||||||
 | 
							uint groupCountZ
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
							AssertComputePassActive();
 | 
				
			||||||
 | 
							AssertComputePipelineBound();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (groupCountX < 1 || groupCountY < 1 || groupCountZ < 1)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new System.ArgumentException("All dimensions for the compute work groups must be >= 1!");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Refresh.Refresh_DispatchCompute(
 | 
				
			||||||
 | 
								Handle,
 | 
				
			||||||
 | 
								groupCountX,
 | 
				
			||||||
 | 
								groupCountY,
 | 
				
			||||||
 | 
								groupCountZ
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
						private void AssertComputePassActive(string message = "Render pass is not active!")
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (!active)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new System.InvalidOperationException(message);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void AssertComputePipelineBound(string message = "No compute pipeline is bound!")
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (currentComputePipeline == null)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new System.InvalidOperationException(message);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void AssertTextureNonNull(in TextureSlice textureSlice)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (textureSlice.Texture == null || textureSlice.Texture.Handle == nint.Zero)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new System.NullReferenceException("Texture must not be null!");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void AssertTextureHasComputeStorageReadFlag(Texture texture)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if ((texture.UsageFlags & TextureUsageFlags.ComputeStorageRead) == 0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new System.ArgumentException("The bound Texture's UsageFlags must include TextureUsageFlags.ComputeStorageRead!");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void AssertBufferNonNull(Buffer buffer)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (buffer == null || buffer.Handle == nint.Zero)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new System.NullReferenceException("Buffer must not be null!");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void AssertBufferHasComputeStorageReadFlag(Buffer buffer)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if ((buffer.UsageFlags & BufferUsageFlags.ComputeStorageRead) == 0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new System.ArgumentException("The bound Buffer's UsageFlags must include BufferUsageFlag.ComputeStorageRead!");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										25
									
								
								Nerfed.Runtime/Graphics/ComputePassPool.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Nerfed.Runtime/Graphics/ComputePassPool.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					using System.Collections.Concurrent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					internal class ComputePassPool
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						private ConcurrentQueue<ComputePass> ComputePasses = new ConcurrentQueue<ComputePass>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public ComputePass Obtain()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (ComputePasses.TryDequeue(out ComputePass computePass))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return computePass;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return new ComputePass();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void Return(ComputePass computePass)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							ComputePasses.Enqueue(computePass);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										241
									
								
								Nerfed.Runtime/Graphics/CopyPass.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										241
									
								
								Nerfed.Runtime/Graphics/CopyPass.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,241 @@
 | 
				
			|||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					using RefreshCS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class CopyPass
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public nint Handle { get; private set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						internal void SetHandle(nint handle)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Handle = handle;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Uploads data from a TransferBuffer to a TextureSlice.
 | 
				
			||||||
 | 
						/// This copy occurs on the GPU timeline.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// Overwriting the contents of the TransferBuffer before the command buffer
 | 
				
			||||||
 | 
						/// has finished execution will cause undefined behavior.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// You MAY assume that the copy has finished for subsequent commands.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="cycle">If true, cycles the texture if the given slice is bound.</param>
 | 
				
			||||||
 | 
						public void UploadToTexture(
 | 
				
			||||||
 | 
							in TextureTransferInfo source,
 | 
				
			||||||
 | 
							in TextureRegion destination,
 | 
				
			||||||
 | 
							bool cycle
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
							AssertTransferBufferNotMapped(source.TransferBuffer);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Refresh.Refresh_UploadToTexture(
 | 
				
			||||||
 | 
								Handle,
 | 
				
			||||||
 | 
								source.ToRefresh(),
 | 
				
			||||||
 | 
								destination.ToRefresh(),
 | 
				
			||||||
 | 
								Conversions.BoolToInt(cycle)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Uploads the contents of an entire buffer to a 2D texture with no mips.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public void UploadToTexture(
 | 
				
			||||||
 | 
							TransferBuffer source,
 | 
				
			||||||
 | 
							Texture destination,
 | 
				
			||||||
 | 
							bool cycle
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							UploadToTexture(
 | 
				
			||||||
 | 
								new TextureTransferInfo(source),
 | 
				
			||||||
 | 
								new TextureRegion(destination),
 | 
				
			||||||
 | 
								cycle
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Uploads data from a TransferBuffer to a Buffer.
 | 
				
			||||||
 | 
						/// This copy occurs on the GPU timeline.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// Overwriting the contents of the TransferBuffer before the command buffer
 | 
				
			||||||
 | 
						/// has finished execution will cause undefined behavior.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// You MAY assume that the copy has finished for subsequent commands.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="cycle">If true, cycles the buffer if it is bound.</param>
 | 
				
			||||||
 | 
						public void UploadToBuffer(
 | 
				
			||||||
 | 
							in TransferBufferLocation source,
 | 
				
			||||||
 | 
							in BufferRegion destination,
 | 
				
			||||||
 | 
							bool cycle
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
							AssertBufferBoundsCheck(source.TransferBuffer.Size, source.Offset, destination.Size);
 | 
				
			||||||
 | 
							AssertBufferBoundsCheck(destination.Buffer.Size, destination.Offset, destination.Size);
 | 
				
			||||||
 | 
							AssertTransferBufferNotMapped(source.TransferBuffer);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Refresh.Refresh_UploadToBuffer(
 | 
				
			||||||
 | 
								Handle,
 | 
				
			||||||
 | 
								source.ToRefresh(),
 | 
				
			||||||
 | 
								destination.ToRefresh(),
 | 
				
			||||||
 | 
								Conversions.BoolToInt(cycle)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Copies the entire contents of a TransferBuffer to a Buffer.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public void UploadToBuffer(
 | 
				
			||||||
 | 
							TransferBuffer source,
 | 
				
			||||||
 | 
							Buffer destination,
 | 
				
			||||||
 | 
							bool cycle
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							UploadToBuffer(
 | 
				
			||||||
 | 
								new TransferBufferLocation(source),
 | 
				
			||||||
 | 
								new BufferRegion(destination, 0, destination.Size),
 | 
				
			||||||
 | 
								cycle
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Copies data element-wise into from a TransferBuffer to a Buffer.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public void UploadToBuffer<T>(
 | 
				
			||||||
 | 
							TransferBuffer source,
 | 
				
			||||||
 | 
							Buffer destination,
 | 
				
			||||||
 | 
							uint sourceStartElement,
 | 
				
			||||||
 | 
							uint destinationStartElement,
 | 
				
			||||||
 | 
							uint numElements,
 | 
				
			||||||
 | 
							bool cycle
 | 
				
			||||||
 | 
						) where T : unmanaged
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							int elementSize = Marshal.SizeOf<T>();
 | 
				
			||||||
 | 
							uint dataLengthInBytes = (uint) (elementSize * numElements);
 | 
				
			||||||
 | 
							uint srcOffsetInBytes = (uint) (elementSize * sourceStartElement);
 | 
				
			||||||
 | 
							uint dstOffsetInBytes = (uint) (elementSize * destinationStartElement);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							UploadToBuffer(
 | 
				
			||||||
 | 
								new TransferBufferLocation(source, srcOffsetInBytes),
 | 
				
			||||||
 | 
								new BufferRegion(destination, dstOffsetInBytes, dataLengthInBytes),
 | 
				
			||||||
 | 
								cycle
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Copies the contents of a TextureLocation to another TextureLocation.
 | 
				
			||||||
 | 
						/// This copy occurs on the GPU timeline.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// You MAY assume that the copy has finished in subsequent commands.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public void CopyTextureToTexture(
 | 
				
			||||||
 | 
							in TextureLocation source,
 | 
				
			||||||
 | 
							in TextureLocation destination,
 | 
				
			||||||
 | 
							uint w,
 | 
				
			||||||
 | 
							uint h,
 | 
				
			||||||
 | 
							uint d,
 | 
				
			||||||
 | 
							bool cycle
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
							AssertTextureBoundsCheck(source, w, h, d);
 | 
				
			||||||
 | 
							AssertTextureBoundsCheck(destination, w, h, d);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Refresh.Refresh_CopyTextureToTexture(
 | 
				
			||||||
 | 
								Handle,
 | 
				
			||||||
 | 
								source.ToRefresh(),
 | 
				
			||||||
 | 
								destination.ToRefresh(),
 | 
				
			||||||
 | 
								w,
 | 
				
			||||||
 | 
								h,
 | 
				
			||||||
 | 
								d,
 | 
				
			||||||
 | 
								Conversions.BoolToInt(cycle)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Copies data from a Buffer to another Buffer.
 | 
				
			||||||
 | 
						/// This copy occurs on the GPU timeline.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// You MAY assume that the copy has finished in subsequent commands.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public void CopyBufferToBuffer(
 | 
				
			||||||
 | 
							in BufferLocation source,
 | 
				
			||||||
 | 
							in BufferLocation destination,
 | 
				
			||||||
 | 
							uint size,
 | 
				
			||||||
 | 
							bool cycle
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
							AssertBufferBoundsCheck(source.Buffer.Size, source.Offset, size);
 | 
				
			||||||
 | 
							AssertBufferBoundsCheck(destination.Buffer.Size, destination.Offset, size);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Refresh.Refresh_CopyBufferToBuffer(
 | 
				
			||||||
 | 
								Handle,
 | 
				
			||||||
 | 
								source.ToRefresh(),
 | 
				
			||||||
 | 
								destination.ToRefresh(),
 | 
				
			||||||
 | 
								size,
 | 
				
			||||||
 | 
								Conversions.BoolToInt(cycle)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void DownloadFromBuffer(
 | 
				
			||||||
 | 
							in BufferRegion source,
 | 
				
			||||||
 | 
							in TransferBufferLocation destination
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
							AssertBufferBoundsCheck(source.Buffer.Size, source.Offset, source.Size);
 | 
				
			||||||
 | 
							AssertBufferBoundsCheck(destination.TransferBuffer.Size, destination.Offset, source.Size);
 | 
				
			||||||
 | 
							AssertTransferBufferNotMapped(destination.TransferBuffer);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Refresh.Refresh_DownloadFromBuffer(
 | 
				
			||||||
 | 
								Handle,
 | 
				
			||||||
 | 
								source.ToRefresh(),
 | 
				
			||||||
 | 
								destination.ToRefresh()
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void DownloadFromTexture(
 | 
				
			||||||
 | 
							in TextureRegion source,
 | 
				
			||||||
 | 
							in TextureTransferInfo destination
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
							AssertTransferBufferNotMapped(destination.TransferBuffer);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Refresh.Refresh_DownloadFromTexture(
 | 
				
			||||||
 | 
								Handle,
 | 
				
			||||||
 | 
								source.ToRefresh(),
 | 
				
			||||||
 | 
								destination.ToRefresh()
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
						private void AssertBufferBoundsCheck(uint bufferLengthInBytes, uint offsetInBytes, uint copyLengthInBytes)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (copyLengthInBytes > bufferLengthInBytes + offsetInBytes)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new System.InvalidOperationException($"SetBufferData overflow! buffer length {bufferLengthInBytes}, offset {offsetInBytes}, copy length {copyLengthInBytes}");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void AssertTextureBoundsCheck(in TextureLocation textureLocation, uint w, uint h, uint d)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (
 | 
				
			||||||
 | 
								textureLocation.X + w > textureLocation.TextureSlice.Texture.Width ||
 | 
				
			||||||
 | 
								textureLocation.Y + h > textureLocation.TextureSlice.Texture.Height ||
 | 
				
			||||||
 | 
								textureLocation.Z + d > textureLocation.TextureSlice.Texture.Depth
 | 
				
			||||||
 | 
							) {
 | 
				
			||||||
 | 
								throw new System.InvalidOperationException($"Texture data is out of bounds!");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void AssertTransferBufferNotMapped(TransferBuffer transferBuffer)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (transferBuffer.Mapped)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new System.InvalidOperationException("Transfer buffer must not be mapped!");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										25
									
								
								Nerfed.Runtime/Graphics/CopyPassPool.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Nerfed.Runtime/Graphics/CopyPassPool.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					using System.Collections.Concurrent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					internal class CopyPassPool
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						private ConcurrentQueue<CopyPass> CopyPasses = new ConcurrentQueue<CopyPass>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public CopyPass Obtain()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (CopyPasses.TryDequeue(out CopyPass copyPass))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return copyPass;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return new CopyPass();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void Return(CopyPass copyPass)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							CopyPasses.Enqueue(copyPass);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										716
									
								
								Nerfed.Runtime/Graphics/EmbeddedShadersSpirV.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										716
									
								
								Nerfed.Runtime/Graphics/EmbeddedShadersSpirV.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,716 @@
 | 
				
			|||||||
 | 
					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,
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										31
									
								
								Nerfed.Runtime/Graphics/FencePool.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								Nerfed.Runtime/Graphics/FencePool.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					using System.Collections.Concurrent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					internal class FencePool
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						private GraphicsDevice GraphicsDevice;
 | 
				
			||||||
 | 
						private ConcurrentQueue<Fence> Fences = new ConcurrentQueue<Fence>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public FencePool(GraphicsDevice graphicsDevice)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							GraphicsDevice = graphicsDevice;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Fence Obtain()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (Fences.TryDequeue(out Fence fence))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return fence;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return new Fence(GraphicsDevice);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void Return(Fence fence)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Fences.Enqueue(fence);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										16
									
								
								Nerfed.Runtime/Graphics/Font/Enums.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								Nerfed.Runtime/Graphics/Font/Enums.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public enum HorizontalAlignment
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Left,
 | 
				
			||||||
 | 
					    Center,
 | 
				
			||||||
 | 
					    Right
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public enum VerticalAlignment
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Baseline,
 | 
				
			||||||
 | 
					    Top,
 | 
				
			||||||
 | 
					    Middle,
 | 
				
			||||||
 | 
					    Bottom
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										123
									
								
								Nerfed.Runtime/Graphics/Font/Font.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								Nerfed.Runtime/Graphics/Font/Font.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,123 @@
 | 
				
			|||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					using WellspringCS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public unsafe class Font : GraphicsResource
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public Texture Texture { get; }
 | 
				
			||||||
 | 
					    public float PixelsPerEm { get; }
 | 
				
			||||||
 | 
					    public float DistanceRange { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal IntPtr Handle { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private byte* StringBytes;
 | 
				
			||||||
 | 
					    private int StringBytesLength;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Loads a TTF or OTF font from a path for use in MSDF rendering.
 | 
				
			||||||
 | 
					    /// Note that there must be an msdf-atlas-gen JSON and image file alongside.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    public static Font Load(GraphicsDevice graphicsDevice, CommandBuffer commandBuffer, string fontPath)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        FileStream fontFileStream = new FileStream(fontPath, FileMode.Open, FileAccess.Read);
 | 
				
			||||||
 | 
					        void* fontFileByteBuffer = NativeMemory.Alloc((nuint)fontFileStream.Length);
 | 
				
			||||||
 | 
					        Span<byte> fontFileByteSpan = new Span<byte>(fontFileByteBuffer, (int)fontFileStream.Length);
 | 
				
			||||||
 | 
					        fontFileStream.ReadExactly(fontFileByteSpan);
 | 
				
			||||||
 | 
					        fontFileStream.Close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        FileStream atlasFileStream = new FileStream(Path.ChangeExtension(fontPath, ".json"), FileMode.Open, FileAccess.Read);
 | 
				
			||||||
 | 
					        void* atlasFileByteBuffer = NativeMemory.Alloc((nuint)atlasFileStream.Length);
 | 
				
			||||||
 | 
					        Span<byte> atlasFileByteSpan = new Span<byte>(atlasFileByteBuffer, (int)atlasFileStream.Length);
 | 
				
			||||||
 | 
					        atlasFileStream.ReadExactly(atlasFileByteSpan);
 | 
				
			||||||
 | 
					        atlasFileStream.Close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        IntPtr handle = Wellspring.Wellspring_CreateFont(
 | 
				
			||||||
 | 
					            (IntPtr)fontFileByteBuffer,
 | 
				
			||||||
 | 
					            (uint)fontFileByteSpan.Length,
 | 
				
			||||||
 | 
					            (IntPtr)atlasFileByteBuffer,
 | 
				
			||||||
 | 
					            (uint)atlasFileByteSpan.Length,
 | 
				
			||||||
 | 
					            out float pixelsPerEm,
 | 
				
			||||||
 | 
					            out float distanceRange
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        string imagePath = Path.ChangeExtension(fontPath, ".png");
 | 
				
			||||||
 | 
					        ImageUtils.ImageInfoFromFile(imagePath, out uint width, out uint height, out uint sizeInBytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ResourceUploader uploader = new ResourceUploader(graphicsDevice);
 | 
				
			||||||
 | 
					        Texture texture = uploader.CreateTexture2DFromCompressed(imagePath);
 | 
				
			||||||
 | 
					        uploader.Upload();
 | 
				
			||||||
 | 
					        uploader.Dispose();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        NativeMemory.Free(fontFileByteBuffer);
 | 
				
			||||||
 | 
					        NativeMemory.Free(atlasFileByteBuffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return new Font(graphicsDevice, handle, texture, pixelsPerEm, distanceRange);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private Font(GraphicsDevice device, IntPtr handle, Texture texture, float pixelsPerEm, float distanceRange) : base(device)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Handle = handle;
 | 
				
			||||||
 | 
					        Texture = texture;
 | 
				
			||||||
 | 
					        PixelsPerEm = pixelsPerEm;
 | 
				
			||||||
 | 
					        DistanceRange = distanceRange;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        StringBytesLength = 32;
 | 
				
			||||||
 | 
					        StringBytes = (byte*)NativeMemory.Alloc((nuint)StringBytesLength);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public unsafe bool TextBounds(
 | 
				
			||||||
 | 
					        string text,
 | 
				
			||||||
 | 
					        int pixelSize,
 | 
				
			||||||
 | 
					        HorizontalAlignment horizontalAlignment,
 | 
				
			||||||
 | 
					        VerticalAlignment verticalAlignment,
 | 
				
			||||||
 | 
					        out Wellspring.Rectangle rectangle
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int byteCount = System.Text.Encoding.UTF8.GetByteCount(text);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (StringBytesLength < byteCount)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            StringBytes = (byte*)NativeMemory.Realloc(StringBytes, (nuint)byteCount);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fixed (char* chars = text)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            System.Text.Encoding.UTF8.GetBytes(chars, text.Length, StringBytes, byteCount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            byte result = Wellspring.Wellspring_TextBounds(
 | 
				
			||||||
 | 
					                Handle,
 | 
				
			||||||
 | 
					                pixelSize,
 | 
				
			||||||
 | 
					                (Wellspring.HorizontalAlignment)horizontalAlignment,
 | 
				
			||||||
 | 
					                (Wellspring.VerticalAlignment)verticalAlignment,
 | 
				
			||||||
 | 
					                (IntPtr)StringBytes,
 | 
				
			||||||
 | 
					                (uint)byteCount,
 | 
				
			||||||
 | 
					                out rectangle
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (result == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Log.Warning("Could not decode string: " + text);
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected override void Dispose(bool disposing)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!IsDisposed)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (disposing)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Texture.Dispose();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Wellspring.Wellspring_DestroyFont(Handle);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        base.Dispose(disposing);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										26
									
								
								Nerfed.Runtime/Graphics/Font/Structs.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								Nerfed.Runtime/Graphics/Font/Structs.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[StructLayout(LayoutKind.Sequential)]
 | 
				
			||||||
 | 
					public struct FontVertex : IVertexType
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public Vector3 Position;
 | 
				
			||||||
 | 
						public Vector2 TexCoord;
 | 
				
			||||||
 | 
						public Color Color;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static VertexElementFormat[] Formats { get; } =
 | 
				
			||||||
 | 
						[
 | 
				
			||||||
 | 
							VertexElementFormat.Vector3,
 | 
				
			||||||
 | 
							VertexElementFormat.Vector2,
 | 
				
			||||||
 | 
							VertexElementFormat.Color
 | 
				
			||||||
 | 
						];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static uint[] Offsets { get; } =
 | 
				
			||||||
 | 
						[
 | 
				
			||||||
 | 
							0,
 | 
				
			||||||
 | 
							12,
 | 
				
			||||||
 | 
							20
 | 
				
			||||||
 | 
						];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										191
									
								
								Nerfed.Runtime/Graphics/Font/TextBatch.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								Nerfed.Runtime/Graphics/Font/TextBatch.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,191 @@
 | 
				
			|||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					using WellspringCS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public unsafe class TextBatch : GraphicsResource
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public const int INITIAL_CHAR_COUNT = 64;
 | 
				
			||||||
 | 
					    public const int INITIAL_VERTEX_COUNT = INITIAL_CHAR_COUNT * 4;
 | 
				
			||||||
 | 
					    public const int INITIAL_INDEX_COUNT = INITIAL_CHAR_COUNT * 6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public IntPtr Handle { get; }
 | 
				
			||||||
 | 
					    public Buffer VertexBuffer { get; protected set; } = null;
 | 
				
			||||||
 | 
					    public Buffer IndexBuffer { get; protected set; } = null;
 | 
				
			||||||
 | 
					    public uint PrimitiveCount { get; protected set; }
 | 
				
			||||||
 | 
					    public Font CurrentFont { get; private set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private readonly GraphicsDevice graphicsDevice;
 | 
				
			||||||
 | 
					    private readonly int stringBytesLength;
 | 
				
			||||||
 | 
					    private TransferBuffer TransferBuffer;
 | 
				
			||||||
 | 
					    private byte* stringBytes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public TextBatch(GraphicsDevice device) : base(device)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        graphicsDevice = device;
 | 
				
			||||||
 | 
					        Handle = Wellspring.Wellspring_CreateTextBatch();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        stringBytesLength = 128;
 | 
				
			||||||
 | 
					        stringBytes = (byte*)NativeMemory.Alloc((nuint)stringBytesLength);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        VertexBuffer = Buffer.Create<FontVertex>(graphicsDevice, BufferUsageFlags.Vertex, INITIAL_VERTEX_COUNT);
 | 
				
			||||||
 | 
					        IndexBuffer = Buffer.Create<uint>(graphicsDevice, BufferUsageFlags.Index, INITIAL_INDEX_COUNT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        TransferBuffer = TransferBuffer.Create<byte>(
 | 
				
			||||||
 | 
					            graphicsDevice,
 | 
				
			||||||
 | 
					            TransferBufferUsage.Upload,
 | 
				
			||||||
 | 
					            VertexBuffer.Size + IndexBuffer.Size
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Call this to initialize or reset the batch.
 | 
				
			||||||
 | 
					    public void Start(Font font)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Wellspring.Wellspring_StartTextBatch(Handle, font.Handle);
 | 
				
			||||||
 | 
					        CurrentFont = font;
 | 
				
			||||||
 | 
					        PrimitiveCount = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Add text with size and color to the batch
 | 
				
			||||||
 | 
					    public unsafe bool Add(
 | 
				
			||||||
 | 
					        string text,
 | 
				
			||||||
 | 
					        int pixelSize,
 | 
				
			||||||
 | 
					        Color color,
 | 
				
			||||||
 | 
					        HorizontalAlignment horizontalAlignment = HorizontalAlignment.Left,
 | 
				
			||||||
 | 
					        VerticalAlignment verticalAlignment = VerticalAlignment.Baseline
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int byteCount = System.Text.Encoding.UTF8.GetByteCount(text);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (stringBytesLength < byteCount)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            stringBytes = (byte*)NativeMemory.Realloc(stringBytes, (nuint)byteCount);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fixed (char* chars = text)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            System.Text.Encoding.UTF8.GetBytes(chars, text.Length, stringBytes, byteCount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            byte result = Wellspring.Wellspring_AddToTextBatch(
 | 
				
			||||||
 | 
					                Handle,
 | 
				
			||||||
 | 
					                pixelSize,
 | 
				
			||||||
 | 
					                new Wellspring.Color { R = color.R, G = color.G, B = color.B, A = color.A },
 | 
				
			||||||
 | 
					                (Wellspring.HorizontalAlignment)horizontalAlignment,
 | 
				
			||||||
 | 
					                (Wellspring.VerticalAlignment)verticalAlignment,
 | 
				
			||||||
 | 
					                (IntPtr)stringBytes,
 | 
				
			||||||
 | 
					                (uint)byteCount
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (result == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Log.Warning("Could not decode string: " + text);
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Call this after you have made all the Add calls you want, but before beginning a render pass.
 | 
				
			||||||
 | 
					    public unsafe void UploadBufferData(CommandBuffer commandBuffer)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Wellspring.Wellspring_GetBufferData(
 | 
				
			||||||
 | 
					            Handle,
 | 
				
			||||||
 | 
					            out uint vertexCount,
 | 
				
			||||||
 | 
					            out IntPtr vertexDataPointer,
 | 
				
			||||||
 | 
					            out uint vertexDataLengthInBytes,
 | 
				
			||||||
 | 
					            out IntPtr indexDataPointer,
 | 
				
			||||||
 | 
					            out uint indexDataLengthInBytes
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Span<byte> vertexSpan = new Span<byte>((void*)vertexDataPointer, (int)vertexDataLengthInBytes);
 | 
				
			||||||
 | 
					        Span<byte> indexSpan = new Span<byte>((void*)indexDataPointer, (int)indexDataLengthInBytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bool newTransferBufferNeeded = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (VertexBuffer.Size < vertexDataLengthInBytes)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            VertexBuffer.Dispose();
 | 
				
			||||||
 | 
					            VertexBuffer = new Buffer(graphicsDevice, BufferUsageFlags.Vertex, vertexDataLengthInBytes);
 | 
				
			||||||
 | 
					            newTransferBufferNeeded = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (IndexBuffer.Size < indexDataLengthInBytes)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            IndexBuffer.Dispose();
 | 
				
			||||||
 | 
					            IndexBuffer = new Buffer(graphicsDevice, BufferUsageFlags.Index, vertexDataLengthInBytes);
 | 
				
			||||||
 | 
					            newTransferBufferNeeded = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (newTransferBufferNeeded)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            TransferBuffer.Dispose();
 | 
				
			||||||
 | 
					            TransferBuffer = new TransferBuffer(
 | 
				
			||||||
 | 
					                graphicsDevice,
 | 
				
			||||||
 | 
					                TransferBufferUsage.Upload,
 | 
				
			||||||
 | 
					                VertexBuffer.Size + IndexBuffer.Size
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (vertexDataLengthInBytes > 0 && indexDataLengthInBytes > 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            TransferBuffer.SetData(vertexSpan, true);
 | 
				
			||||||
 | 
					            TransferBuffer.SetData(indexSpan, (uint)vertexSpan.Length, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            CopyPass copyPass = commandBuffer.BeginCopyPass();
 | 
				
			||||||
 | 
					            copyPass.UploadToBuffer(
 | 
				
			||||||
 | 
					                new TransferBufferLocation(TransferBuffer),
 | 
				
			||||||
 | 
					                new BufferRegion(VertexBuffer, 0, (uint)vertexSpan.Length),
 | 
				
			||||||
 | 
					                true
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            copyPass.UploadToBuffer(
 | 
				
			||||||
 | 
					                new TransferBufferLocation(TransferBuffer, (uint)vertexSpan.Length),
 | 
				
			||||||
 | 
					                new BufferRegion(IndexBuffer, 0, (uint)indexSpan.Length),
 | 
				
			||||||
 | 
					                true
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            commandBuffer.EndCopyPass(copyPass);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        PrimitiveCount = vertexCount / 2;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Call this AFTER binding your text pipeline!
 | 
				
			||||||
 | 
					    public void Render(CommandBuffer commandBuffer, RenderPass renderPass, Matrix4x4 transformMatrix)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        commandBuffer.PushVertexUniformData(transformMatrix);
 | 
				
			||||||
 | 
					        commandBuffer.PushFragmentUniformData(CurrentFont.DistanceRange);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        renderPass.BindFragmentSampler(
 | 
				
			||||||
 | 
					            new TextureSamplerBinding(
 | 
				
			||||||
 | 
					                CurrentFont.Texture,
 | 
				
			||||||
 | 
					                graphicsDevice.LinearSampler
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        renderPass.BindVertexBuffer(VertexBuffer);
 | 
				
			||||||
 | 
					        renderPass.BindIndexBuffer(IndexBuffer, IndexElementSize.ThirtyTwo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        renderPass.DrawIndexedPrimitives(
 | 
				
			||||||
 | 
					            0,
 | 
				
			||||||
 | 
					            0,
 | 
				
			||||||
 | 
					            PrimitiveCount
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected override void Dispose(bool disposing)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!IsDisposed)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (disposing)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                VertexBuffer.Dispose();
 | 
				
			||||||
 | 
					                IndexBuffer.Dispose();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            NativeMemory.Free(stringBytes);
 | 
				
			||||||
 | 
					            Wellspring.Wellspring_DestroyTextBatch(Handle);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        base.Dispose(disposing);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										466
									
								
								Nerfed.Runtime/Graphics/GraphicsDevice.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										466
									
								
								Nerfed.Runtime/Graphics/GraphicsDevice.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,466 @@
 | 
				
			|||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					using Nerfed.Runtime.Video;
 | 
				
			||||||
 | 
					using RefreshCS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Manages all graphics-related concerns.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class GraphicsDevice : IDisposable
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public IntPtr Handle { get; }
 | 
				
			||||||
 | 
					    public BackendFlags Backend { get; }
 | 
				
			||||||
 | 
					    public bool DebugMode { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Built-in video pipeline
 | 
				
			||||||
 | 
					    internal GraphicsPipeline VideoPipeline { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Built-in text shader info
 | 
				
			||||||
 | 
					    public Shader TextVertexShader;
 | 
				
			||||||
 | 
					    public Shader TextFragmentShader;
 | 
				
			||||||
 | 
					    public VertexInputState TextVertexInputState { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Built-in samplers
 | 
				
			||||||
 | 
					    public Sampler PointSampler { get; }
 | 
				
			||||||
 | 
					    public Sampler LinearSampler { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public bool IsDisposed { get; private set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal readonly RenderPassPool RenderPassPool = new RenderPassPool();
 | 
				
			||||||
 | 
					    internal readonly ComputePassPool ComputePassPool = new ComputePassPool();
 | 
				
			||||||
 | 
					    internal readonly CopyPassPool CopyPassPool = new CopyPassPool();
 | 
				
			||||||
 | 
					    private readonly HashSet<GCHandle> resources = new HashSet<GCHandle>();
 | 
				
			||||||
 | 
					    private readonly CommandBufferPool commandBufferPool;
 | 
				
			||||||
 | 
					    private readonly FencePool fencePool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal GraphicsDevice(BackendFlags preferredBackends)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (preferredBackends == BackendFlags.Invalid)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            throw new System.Exception("Could not set graphics backend!");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bool debugMode = false;
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					        debugMode = true;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Handle = Refresh.Refresh_CreateDevice((Refresh.BackendFlags)preferredBackends, Conversions.BoolToInt(debugMode));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        DebugMode = debugMode;
 | 
				
			||||||
 | 
					        // TODO: check for CreateDevice fail
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Backend = (BackendFlags)Refresh.Refresh_GetBackend(Handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        IEmbeddedShaders embeddedShaders;
 | 
				
			||||||
 | 
					        switch (Backend)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            case BackendFlags.Vulkan:
 | 
				
			||||||
 | 
					                embeddedShaders = new EmbeddedShadersSpirV();
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case BackendFlags.D3D11:
 | 
				
			||||||
 | 
					                throw new NotImplementedException("D3D11 embedded shaders");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case BackendFlags.Metal:
 | 
				
			||||||
 | 
					                throw new NotImplementedException("Metal embedded shaders");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            default: throw new ArgumentOutOfRangeException();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Shader fullscreenVertShader;
 | 
				
			||||||
 | 
					        Shader textVertShader;
 | 
				
			||||||
 | 
					        Shader textFragShader;
 | 
				
			||||||
 | 
					        Shader videoFragShader;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        using (MemoryStream fullscreenVertStream = new MemoryStream(embeddedShaders.FullscreenVert))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            fullscreenVertShader = new Shader(
 | 
				
			||||||
 | 
					                this,
 | 
				
			||||||
 | 
					                fullscreenVertStream,
 | 
				
			||||||
 | 
					                "main",
 | 
				
			||||||
 | 
					                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(
 | 
				
			||||||
 | 
					            this,
 | 
				
			||||||
 | 
					            new GraphicsPipelineCreateInfo
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                AttachmentInfo = new GraphicsPipelineAttachmentInfo(
 | 
				
			||||||
 | 
					                    new ColorAttachmentDescription(
 | 
				
			||||||
 | 
					                        TextureFormat.R8G8B8A8,
 | 
				
			||||||
 | 
					                        ColorAttachmentBlendState.None
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                DepthStencilState = DepthStencilState.Disable,
 | 
				
			||||||
 | 
					                VertexShader = fullscreenVertShader,
 | 
				
			||||||
 | 
					                FragmentShader = videoFragShader,
 | 
				
			||||||
 | 
					                VertexInputState = VertexInputState.Empty,
 | 
				
			||||||
 | 
					                RasterizerState = RasterizerState.CCW_CullNone,
 | 
				
			||||||
 | 
					                PrimitiveType = PrimitiveType.TriangleList,
 | 
				
			||||||
 | 
					                MultisampleState = MultisampleState.None
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        TextVertexShader = textVertShader;
 | 
				
			||||||
 | 
					        TextFragmentShader = textFragShader;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        TextVertexInputState = VertexInputState.CreateSingleBinding<FontVertex>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        PointSampler = new Sampler(this, SamplerCreateInfo.PointClamp);
 | 
				
			||||||
 | 
					        LinearSampler = new Sampler(this, SamplerCreateInfo.LinearClamp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fencePool = new FencePool(this);
 | 
				
			||||||
 | 
					        commandBufferPool = new CommandBufferPool(this);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Prepares a window so that frames can be presented to it.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="swapchainComposition">The desired composition of the swapchain. Ignore this unless you are using HDR or tonemapping.</param>
 | 
				
			||||||
 | 
					    /// <param name="presentMode">The desired presentation mode for the window. Roughly equivalent to V-Sync.</param>
 | 
				
			||||||
 | 
					    /// <returns>True if successfully claimed.</returns>
 | 
				
			||||||
 | 
					    public bool ClaimWindow(
 | 
				
			||||||
 | 
					        Window window,
 | 
				
			||||||
 | 
					        SwapchainComposition swapchainComposition,
 | 
				
			||||||
 | 
					        PresentMode presentMode
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (window.Claimed)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Log.Error("Window already claimed!");
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bool success = Conversions.IntToBool(
 | 
				
			||||||
 | 
					            Refresh.Refresh_ClaimWindow(
 | 
				
			||||||
 | 
					                Handle,
 | 
				
			||||||
 | 
					                window.Handle,
 | 
				
			||||||
 | 
					                (Refresh.SwapchainComposition)swapchainComposition,
 | 
				
			||||||
 | 
					                (Refresh.PresentMode)presentMode
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (success)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            window.Claimed = true;
 | 
				
			||||||
 | 
					            window.SwapchainComposition = swapchainComposition;
 | 
				
			||||||
 | 
					            window.SwapchainFormat = GetSwapchainFormat(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (window.SwapchainTexture == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                window.SwapchainTexture = new Texture(this, window.SwapchainFormat);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return success;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Unclaims a window, making it unavailable for presenting and freeing associated resources.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public void UnclaimWindow(Window window)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (window.Claimed)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Refresh.Refresh_UnclaimWindow(
 | 
				
			||||||
 | 
					                Handle,
 | 
				
			||||||
 | 
					                window.Handle
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            window.Claimed = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // The swapchain texture doesn't actually have a permanent texture reference, so we zero the handle before disposing.
 | 
				
			||||||
 | 
					            window.SwapchainTexture.Handle = IntPtr.Zero;
 | 
				
			||||||
 | 
					            window.SwapchainTexture.Dispose();
 | 
				
			||||||
 | 
					            window.SwapchainTexture = null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Changes the present mode of a claimed window. Does nothing if the window is not claimed.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool SetSwapchainParameters(
 | 
				
			||||||
 | 
					        Window window,
 | 
				
			||||||
 | 
					        SwapchainComposition swapchainComposition,
 | 
				
			||||||
 | 
					        PresentMode presentMode
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!window.Claimed)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Log.Error("Cannot set present mode on unclaimed window!");
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bool success = Conversions.IntToBool(
 | 
				
			||||||
 | 
					            Refresh.Refresh_SetSwapchainParameters(
 | 
				
			||||||
 | 
					                Handle,
 | 
				
			||||||
 | 
					                window.Handle,
 | 
				
			||||||
 | 
					                (Refresh.SwapchainComposition)swapchainComposition,
 | 
				
			||||||
 | 
					                (Refresh.PresentMode)presentMode
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (success)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            window.SwapchainComposition = swapchainComposition;
 | 
				
			||||||
 | 
					            window.SwapchainFormat = GetSwapchainFormat(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (window.SwapchainTexture != null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                window.SwapchainTexture.Format = window.SwapchainFormat;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return success;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Acquires a command buffer.
 | 
				
			||||||
 | 
					    /// This is the start of your rendering process.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    public CommandBuffer AcquireCommandBuffer()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        CommandBuffer commandBuffer = commandBufferPool.Obtain();
 | 
				
			||||||
 | 
					        commandBuffer.SetHandle(Refresh.Refresh_AcquireCommandBuffer(Handle));
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					        commandBuffer.ResetStateTracking();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					        return commandBuffer;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Submits a command buffer to the GPU for processing.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public void Submit(CommandBuffer commandBuffer)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					        if (commandBuffer.Submitted)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            throw new System.InvalidOperationException("Command buffer already submitted!");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Refresh.Refresh_Submit(
 | 
				
			||||||
 | 
					            commandBuffer.Handle
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        commandBufferPool.Return(commandBuffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					        commandBuffer.Submitted = true;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Submits a command buffer to the GPU for processing and acquires a fence associated with the submission.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    public Fence SubmitAndAcquireFence(CommandBuffer commandBuffer)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        IntPtr fenceHandle = Refresh.Refresh_SubmitAndAcquireFence(
 | 
				
			||||||
 | 
					            commandBuffer.Handle
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Fence fence = fencePool.Obtain();
 | 
				
			||||||
 | 
					        fence.SetHandle(fenceHandle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return fence;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Wait for the graphics device to become idle.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public void Wait()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Refresh.Refresh_Wait(Handle);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Waits for the given fence to become signaled.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public unsafe void WaitForFence(Fence fence)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        IntPtr fenceHandle = fence.Handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Refresh.Refresh_WaitForFences(
 | 
				
			||||||
 | 
					            Handle,
 | 
				
			||||||
 | 
					            1,
 | 
				
			||||||
 | 
					            &fenceHandle,
 | 
				
			||||||
 | 
					            1
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Wait for one or more fences to become signaled.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="waitAll">If true, will wait for all given fences to be signaled.</param>
 | 
				
			||||||
 | 
					    public unsafe void WaitForFences(Span<Fence> fences, bool waitAll)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        IntPtr* handlePtr = stackalloc nint[fences.Length];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (int i = 0; i < fences.Length; i += 1)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            handlePtr[i] = fences[i].Handle;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Refresh.Refresh_WaitForFences(
 | 
				
			||||||
 | 
					            Handle,
 | 
				
			||||||
 | 
					            Conversions.BoolToInt(waitAll),
 | 
				
			||||||
 | 
					            handlePtr,
 | 
				
			||||||
 | 
					            (uint)fences.Length
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Returns true if the fence is signaled, indicating that the associated command buffer has finished processing.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <exception cref="InvalidOperationException">Throws if the fence query indicates that the graphics device has been lost.</exception>
 | 
				
			||||||
 | 
					    public bool QueryFence(Fence fence)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int result = Refresh.Refresh_QueryFence(Handle, fence.Handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (result < 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            throw new InvalidOperationException("The graphics device has been lost.");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return result != 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Release reference to an acquired fence, enabling it to be reused.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public void ReleaseFence(Fence fence)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Refresh.Refresh_ReleaseFence(Handle, fence.Handle);
 | 
				
			||||||
 | 
					        fence.Handle = IntPtr.Zero;
 | 
				
			||||||
 | 
					        fencePool.Return(fence);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private TextureFormat GetSwapchainFormat(Window window)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!window.Claimed)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            throw new System.ArgumentException("Cannot get swapchain format of unclaimed window!");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return (TextureFormat)Refresh.Refresh_GetSwapchainTextureFormat(Handle, window.Handle);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal void AddResourceReference(GCHandle resourceReference)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        lock (resources)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            resources.Add(resourceReference);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal void RemoveResourceReference(GCHandle resourceReference)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        lock (resources)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            resources.Remove(resourceReference);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void Dispose(bool disposing)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!IsDisposed)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (disposing)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                lock (resources)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    // Dispose video players first to avoid race condition on threaded decoding
 | 
				
			||||||
 | 
					                    foreach (GCHandle resource in resources)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (resource.Target is VideoPlayer player)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            player.Dispose();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    // Dispose everything else
 | 
				
			||||||
 | 
					                    foreach (GCHandle resource in resources)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if (resource.Target is IDisposable disposable)
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            disposable.Dispose();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    resources.Clear();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Refresh.Refresh_DestroyDevice(Handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            IsDisposed = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ~GraphicsDevice()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
 | 
				
			||||||
 | 
					        Dispose(disposing: false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void Dispose()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
 | 
				
			||||||
 | 
					        Dispose(disposing: true);
 | 
				
			||||||
 | 
					        GC.SuppressFinalize(this);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										53
									
								
								Nerfed.Runtime/Graphics/GraphicsResource.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								Nerfed.Runtime/Graphics/GraphicsResource.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public abstract class GraphicsResource : IDisposable
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public GraphicsDevice Device { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private GCHandle SelfReference;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public bool IsDisposed { get; private set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected GraphicsResource(GraphicsDevice device)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Device = device;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        SelfReference = GCHandle.Alloc(this, GCHandleType.Weak);
 | 
				
			||||||
 | 
					        Device.AddResourceReference(SelfReference);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected virtual void Dispose(bool disposing)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (!IsDisposed)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (disposing)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Device.RemoveResourceReference(SelfReference);
 | 
				
			||||||
 | 
					                SelfReference.Free();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            IsDisposed = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ~GraphicsResource()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					        // If you see this log message, you leaked a graphics resource without disposing it!
 | 
				
			||||||
 | 
					        // We'll try to clean it up for you but you really should fix this.
 | 
				
			||||||
 | 
					        Log.Warning($"A resource of type {GetType().Name} was not Disposed.");
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Dispose(false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void Dispose()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
 | 
				
			||||||
 | 
					        Dispose(disposing: true);
 | 
				
			||||||
 | 
					        GC.SuppressFinalize(this);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										10
									
								
								Nerfed.Runtime/Graphics/IEmbeddedShaders.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Nerfed.Runtime/Graphics/IEmbeddedShaders.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					internal interface IEmbeddedShaders
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ShaderFormat ShaderFormat { get; }
 | 
				
			||||||
 | 
					    byte[] FullscreenVert { get; }
 | 
				
			||||||
 | 
					    byte[] TextMsdfFrag { get; }
 | 
				
			||||||
 | 
					    byte[] TextTransformVert { get; }
 | 
				
			||||||
 | 
					    byte[] VideoYuv2RgbaFrag { get; }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										17
									
								
								Nerfed.Runtime/Graphics/IVertexType.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								Nerfed.Runtime/Graphics/IVertexType.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Can be defined on your struct type to enable simplified vertex input state definition.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public interface IVertexType
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// An ordered list of the types in your vertex struct.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						static abstract VertexElementFormat[] Formats { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// An ordered list of the offsets in your vertex struct.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						static abstract uint[] Offsets { get; }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										455
									
								
								Nerfed.Runtime/Graphics/ImageUtils.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										455
									
								
								Nerfed.Runtime/Graphics/ImageUtils.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,455 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					using RefreshCS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public static class ImageUtils
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets pointer to pixel data from compressed image byte data.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// The returned pointer must be freed by calling FreePixelData.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public static unsafe byte* GetPixelDataFromBytes(
 | 
				
			||||||
 | 
							Span<byte> data,
 | 
				
			||||||
 | 
							out uint width,
 | 
				
			||||||
 | 
							out uint height,
 | 
				
			||||||
 | 
							out uint sizeInBytes
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							fixed (byte* ptr = data)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								byte* pixelData =
 | 
				
			||||||
 | 
									Refresh.Refresh_Image_Load(
 | 
				
			||||||
 | 
									ptr,
 | 
				
			||||||
 | 
									data.Length,
 | 
				
			||||||
 | 
									out int w,
 | 
				
			||||||
 | 
									out int h,
 | 
				
			||||||
 | 
									out int len
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								width = (uint) w;
 | 
				
			||||||
 | 
								height = (uint) h;
 | 
				
			||||||
 | 
								sizeInBytes = (uint) len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return pixelData;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets pointer to pixel data from a compressed image stream.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// The returned pointer must be freed by calling FreePixelData.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public static unsafe byte* GetPixelDataFromStream(
 | 
				
			||||||
 | 
							Stream stream,
 | 
				
			||||||
 | 
							out uint width,
 | 
				
			||||||
 | 
							out uint height,
 | 
				
			||||||
 | 
							out uint sizeInBytes
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							long length = stream.Length;
 | 
				
			||||||
 | 
							void* buffer = NativeMemory.Alloc((nuint) length);
 | 
				
			||||||
 | 
							Span<byte> span = new Span<byte>(buffer, (int) length);
 | 
				
			||||||
 | 
							stream.ReadExactly(span);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							byte* pixelData = GetPixelDataFromBytes(span, out width, out height, out sizeInBytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							NativeMemory.Free(buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return pixelData;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets pointer to pixel data from a compressed image file.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// The returned pointer must be freed by calling FreePixelData.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public static unsafe byte* GetPixelDataFromFile(
 | 
				
			||||||
 | 
							string path,
 | 
				
			||||||
 | 
							out uint width,
 | 
				
			||||||
 | 
							out uint height,
 | 
				
			||||||
 | 
							out uint sizeInBytes
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
 | 
				
			||||||
 | 
							return GetPixelDataFromStream(fileStream, out width, out height, out sizeInBytes);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Get metadata from compressed image bytes.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public static unsafe bool ImageInfoFromBytes(
 | 
				
			||||||
 | 
							Span<byte> data,
 | 
				
			||||||
 | 
							out uint width,
 | 
				
			||||||
 | 
							out uint height,
 | 
				
			||||||
 | 
							out uint sizeInBytes
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							fixed (byte* ptr = data)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								int result =
 | 
				
			||||||
 | 
									Refresh.Refresh_Image_Info(
 | 
				
			||||||
 | 
									ptr,
 | 
				
			||||||
 | 
									data.Length,
 | 
				
			||||||
 | 
									out int w,
 | 
				
			||||||
 | 
									out int h,
 | 
				
			||||||
 | 
									out int len
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								width = (uint) w;
 | 
				
			||||||
 | 
								height = (uint) h;
 | 
				
			||||||
 | 
								sizeInBytes = (uint) len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return Conversions.IntToBool(result);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Get metadata from a compressed image stream.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public static unsafe bool ImageInfoFromStream(
 | 
				
			||||||
 | 
							Stream stream,
 | 
				
			||||||
 | 
							out uint width,
 | 
				
			||||||
 | 
							out uint height,
 | 
				
			||||||
 | 
							out uint sizeInBytes
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							long length = stream.Length;
 | 
				
			||||||
 | 
							void* buffer = NativeMemory.Alloc((nuint) length);
 | 
				
			||||||
 | 
							Span<byte> span = new Span<byte>(buffer, (int) length);
 | 
				
			||||||
 | 
							stream.ReadExactly(span);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							bool result = ImageInfoFromBytes(span, out width, out height, out sizeInBytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							NativeMemory.Free(buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return result;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Get metadata from a compressed image file.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public static bool ImageInfoFromFile(
 | 
				
			||||||
 | 
							string path,
 | 
				
			||||||
 | 
							out uint width,
 | 
				
			||||||
 | 
							out uint height,
 | 
				
			||||||
 | 
							out uint sizeInBytes
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
 | 
				
			||||||
 | 
							return ImageInfoFromStream(fileStream, out width, out height, out sizeInBytes);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Frees pixel data obtained from GetPixelData methods.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public unsafe static void FreePixelData(byte* pixels)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Refresh.Refresh_Image_Free(pixels);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Saves pixel data contained in a TransferBuffer to a PNG file.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public static unsafe void SavePNG(
 | 
				
			||||||
 | 
							string path,
 | 
				
			||||||
 | 
							TransferBuffer transferBuffer,
 | 
				
			||||||
 | 
							uint bufferOffsetInBytes,
 | 
				
			||||||
 | 
							int width,
 | 
				
			||||||
 | 
							int height,
 | 
				
			||||||
 | 
							bool bgra
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							int sizeInBytes = width * height * 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							byte* pixelsPtr = (byte*) NativeMemory.Alloc((nuint) sizeInBytes);
 | 
				
			||||||
 | 
							Span<byte> pixelsSpan = new Span<byte>(pixelsPtr, sizeInBytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							transferBuffer.GetData(pixelsSpan, bufferOffsetInBytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (bgra)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								// if data is bgra, we have to swap the R and B channels
 | 
				
			||||||
 | 
								byte* rgbaPtr = (byte*) NativeMemory.Alloc((nuint) sizeInBytes);
 | 
				
			||||||
 | 
								Span<byte> rgbaSpan = new Span<byte>(rgbaPtr, sizeInBytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for (int i = 0; i < sizeInBytes; i += 4)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									rgbaSpan[i] = pixelsSpan[i + 2];
 | 
				
			||||||
 | 
									rgbaSpan[i + 1] = pixelsSpan[i + 1];
 | 
				
			||||||
 | 
									rgbaSpan[i + 2] = pixelsSpan[i];
 | 
				
			||||||
 | 
									rgbaSpan[i + 3] = pixelsSpan[i + 3];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								NativeMemory.Free(pixelsPtr);
 | 
				
			||||||
 | 
								pixelsPtr = rgbaPtr;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Refresh.Refresh_Image_SavePNG(path, pixelsPtr, width, height);
 | 
				
			||||||
 | 
							NativeMemory.Free(pixelsPtr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// DDS loading extension, based on MojoDDS
 | 
				
			||||||
 | 
						// Taken from https://github.com/FNA-XNA/FNA/blob/1e49f868f595f62bc6385db45949a03186a7cd7f/src/Graphics/Texture.cs#L194
 | 
				
			||||||
 | 
						public static void ParseDDS(
 | 
				
			||||||
 | 
							BinaryReader reader,
 | 
				
			||||||
 | 
							out TextureFormat format,
 | 
				
			||||||
 | 
							out int width,
 | 
				
			||||||
 | 
							out int height,
 | 
				
			||||||
 | 
							out int levels,
 | 
				
			||||||
 | 
							out bool isCube
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							// A whole bunch of magic numbers, yay DDS!
 | 
				
			||||||
 | 
							const uint DDS_MAGIC = 0x20534444;
 | 
				
			||||||
 | 
							const uint DDS_HEADERSIZE = 124;
 | 
				
			||||||
 | 
							const uint DDS_PIXFMTSIZE = 32;
 | 
				
			||||||
 | 
							const uint DDSD_HEIGHT = 0x2;
 | 
				
			||||||
 | 
							const uint DDSD_WIDTH = 0x4;
 | 
				
			||||||
 | 
							const uint DDSD_PITCH = 0x8;
 | 
				
			||||||
 | 
							const uint DDSD_LINEARSIZE = 0x80000;
 | 
				
			||||||
 | 
							const uint DDSD_REQ = (
 | 
				
			||||||
 | 
								DDSD_HEIGHT | DDSD_WIDTH
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							const uint DDSCAPS_MIPMAP = 0x400000;
 | 
				
			||||||
 | 
							const uint DDSCAPS_TEXTURE = 0x1000;
 | 
				
			||||||
 | 
							const uint DDSCAPS2_CUBEMAP = 0x200;
 | 
				
			||||||
 | 
							const uint DDPF_FOURCC = 0x4;
 | 
				
			||||||
 | 
							const uint DDPF_RGB = 0x40;
 | 
				
			||||||
 | 
							const uint FOURCC_DXT1 = 0x31545844;
 | 
				
			||||||
 | 
							const uint FOURCC_DXT3 = 0x33545844;
 | 
				
			||||||
 | 
							const uint FOURCC_DXT5 = 0x35545844;
 | 
				
			||||||
 | 
							const uint FOURCC_DX10 = 0x30315844;
 | 
				
			||||||
 | 
							const uint pitchAndLinear = (
 | 
				
			||||||
 | 
								DDSD_PITCH | DDSD_LINEARSIZE
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// File should start with 'DDS '
 | 
				
			||||||
 | 
							if (reader.ReadUInt32() != DDS_MAGIC)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new NotSupportedException("Not a DDS!");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Texture info
 | 
				
			||||||
 | 
							uint size = reader.ReadUInt32();
 | 
				
			||||||
 | 
							if (size != DDS_HEADERSIZE)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new NotSupportedException("Invalid DDS header!");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							uint flags = reader.ReadUInt32();
 | 
				
			||||||
 | 
							if ((flags & DDSD_REQ) != DDSD_REQ)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new NotSupportedException("Invalid DDS flags!");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if ((flags & pitchAndLinear) == pitchAndLinear)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new NotSupportedException("Invalid DDS flags!");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							height = reader.ReadInt32();
 | 
				
			||||||
 | 
							width = reader.ReadInt32();
 | 
				
			||||||
 | 
							reader.ReadUInt32(); // dwPitchOrLinearSize, unused
 | 
				
			||||||
 | 
							reader.ReadUInt32(); // dwDepth, unused
 | 
				
			||||||
 | 
							levels = reader.ReadInt32();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// "Reserved"
 | 
				
			||||||
 | 
							reader.ReadBytes(4 * 11);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Format info
 | 
				
			||||||
 | 
							uint formatSize = reader.ReadUInt32();
 | 
				
			||||||
 | 
							if (formatSize != DDS_PIXFMTSIZE)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new NotSupportedException("Bogus PIXFMTSIZE!");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							uint formatFlags = reader.ReadUInt32();
 | 
				
			||||||
 | 
							uint formatFourCC = reader.ReadUInt32();
 | 
				
			||||||
 | 
							uint formatRGBBitCount = reader.ReadUInt32();
 | 
				
			||||||
 | 
							uint formatRBitMask = reader.ReadUInt32();
 | 
				
			||||||
 | 
							uint formatGBitMask = reader.ReadUInt32();
 | 
				
			||||||
 | 
							uint formatBBitMask = reader.ReadUInt32();
 | 
				
			||||||
 | 
							uint formatABitMask = reader.ReadUInt32();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// dwCaps "stuff"
 | 
				
			||||||
 | 
							uint caps = reader.ReadUInt32();
 | 
				
			||||||
 | 
							if ((caps & DDSCAPS_TEXTURE) == 0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new NotSupportedException("Not a texture!");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							isCube = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							uint caps2 = reader.ReadUInt32();
 | 
				
			||||||
 | 
							if (caps2 != 0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if ((caps2 & DDSCAPS2_CUBEMAP) == DDSCAPS2_CUBEMAP)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									isCube = true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									throw new NotSupportedException("Invalid caps2!");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							reader.ReadUInt32(); // dwCaps3, unused
 | 
				
			||||||
 | 
							reader.ReadUInt32(); // dwCaps4, unused
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// "Reserved"
 | 
				
			||||||
 | 
							reader.ReadUInt32();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Mipmap sanity check
 | 
				
			||||||
 | 
							if ((caps & DDSCAPS_MIPMAP) != DDSCAPS_MIPMAP)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								levels = 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Determine texture format
 | 
				
			||||||
 | 
							if ((formatFlags & DDPF_FOURCC) == DDPF_FOURCC)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								switch (formatFourCC)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									case 0x71: // D3DFMT_A16B16G16R16F
 | 
				
			||||||
 | 
										format = TextureFormat.R16G16B16A16_SFLOAT;
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									case 0x74: // D3DFMT_A32B32G32R32F
 | 
				
			||||||
 | 
										format = TextureFormat.R32G32B32A32_SFLOAT;
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									case FOURCC_DXT1:
 | 
				
			||||||
 | 
										format = TextureFormat.BC1;
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									case FOURCC_DXT3:
 | 
				
			||||||
 | 
										format = TextureFormat.BC2;
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									case FOURCC_DXT5:
 | 
				
			||||||
 | 
										format = TextureFormat.BC3;
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									case FOURCC_DX10:
 | 
				
			||||||
 | 
										// If the fourCC is DX10, there is an extra header with additional format information.
 | 
				
			||||||
 | 
										uint dxgiFormat = reader.ReadUInt32();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// These values are taken from the DXGI_FORMAT enum.
 | 
				
			||||||
 | 
										switch (dxgiFormat)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											case 2:
 | 
				
			||||||
 | 
												format = TextureFormat.R32G32B32A32_SFLOAT;
 | 
				
			||||||
 | 
												break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											case 10:
 | 
				
			||||||
 | 
												format = TextureFormat.R16G16B16A16_SFLOAT;
 | 
				
			||||||
 | 
												break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											case 71:
 | 
				
			||||||
 | 
												format = TextureFormat.BC1;
 | 
				
			||||||
 | 
												break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											case 74:
 | 
				
			||||||
 | 
												format = TextureFormat.BC2;
 | 
				
			||||||
 | 
												break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											case 77:
 | 
				
			||||||
 | 
												format = TextureFormat.BC3;
 | 
				
			||||||
 | 
												break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											case 98:
 | 
				
			||||||
 | 
												format = TextureFormat.BC7;
 | 
				
			||||||
 | 
												break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											default:
 | 
				
			||||||
 | 
												throw new NotSupportedException(
 | 
				
			||||||
 | 
													"Unsupported DDS texture format"
 | 
				
			||||||
 | 
												);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										uint resourceDimension = reader.ReadUInt32();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										// These values are taken from the D3D10_RESOURCE_DIMENSION enum.
 | 
				
			||||||
 | 
										switch (resourceDimension)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											case 0: // Unknown
 | 
				
			||||||
 | 
											case 1: // Buffer
 | 
				
			||||||
 | 
												throw new NotSupportedException(
 | 
				
			||||||
 | 
													"Unsupported DDS texture format"
 | 
				
			||||||
 | 
												);
 | 
				
			||||||
 | 
											default:
 | 
				
			||||||
 | 
												break;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										/*
 | 
				
			||||||
 | 
										 * This flag seemingly only indicates if the texture is a cube map.
 | 
				
			||||||
 | 
										 * This is already determined above. Cool!
 | 
				
			||||||
 | 
										 */
 | 
				
			||||||
 | 
										uint miscFlag = reader.ReadUInt32();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										/*
 | 
				
			||||||
 | 
										 * Indicates the number of elements in the texture array.
 | 
				
			||||||
 | 
										 * We don't support texture arrays so just throw if it's greater than 1.
 | 
				
			||||||
 | 
										 */
 | 
				
			||||||
 | 
										uint arraySize = reader.ReadUInt32();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (arraySize > 1)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											throw new NotSupportedException(
 | 
				
			||||||
 | 
												"Unsupported DDS texture format"
 | 
				
			||||||
 | 
											);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										reader.ReadUInt32(); // reserved
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									default:
 | 
				
			||||||
 | 
										throw new NotSupportedException(
 | 
				
			||||||
 | 
											"Unsupported DDS texture format"
 | 
				
			||||||
 | 
										);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else if ((formatFlags & DDPF_RGB) == DDPF_RGB)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (	formatRGBBitCount != 32 ||
 | 
				
			||||||
 | 
									formatRBitMask != 0x00FF0000 ||
 | 
				
			||||||
 | 
									formatGBitMask != 0x0000FF00 ||
 | 
				
			||||||
 | 
									formatBBitMask != 0x000000FF ||
 | 
				
			||||||
 | 
									formatABitMask != 0xFF000000	)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									throw new NotSupportedException(
 | 
				
			||||||
 | 
										"Unsupported DDS texture format"
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								format = TextureFormat.B8G8R8A8;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new NotSupportedException(
 | 
				
			||||||
 | 
									"Unsupported DDS texture format"
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static int CalculateDDSLevelSize(
 | 
				
			||||||
 | 
							int width,
 | 
				
			||||||
 | 
							int height,
 | 
				
			||||||
 | 
							TextureFormat format
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							if (format == TextureFormat.R8G8B8A8)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return (((width * 32) + 7) / 8) * height;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else if (format == TextureFormat.R16G16B16A16_SFLOAT)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return (((width * 64) + 7) / 8) * height;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else if (format == TextureFormat.R32G32B32A32_SFLOAT)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return (((width * 128) + 7) / 8) * height;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								int blockSize = 16;
 | 
				
			||||||
 | 
								if (format == TextureFormat.BC1)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									blockSize = 8;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								width = System.Math.Max(width, 1);
 | 
				
			||||||
 | 
								height = System.Math.Max(height, 1);
 | 
				
			||||||
 | 
								return (
 | 
				
			||||||
 | 
									((width + 3) / 4) *
 | 
				
			||||||
 | 
									((height + 3) / 4) *
 | 
				
			||||||
 | 
									blockSize
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										161
									
								
								Nerfed.Runtime/Graphics/PackedVector/Alpha8.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								Nerfed.Runtime/Graphics/PackedVector/Alpha8.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,161 @@
 | 
				
			|||||||
 | 
					/* MoonWorks - Game Development Framework
 | 
				
			||||||
 | 
					 * Copyright 2021 Evan Hemsley
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Derived from code by Ethan Lee (Copyright 2009-2021).
 | 
				
			||||||
 | 
					 * Released under the Microsoft Public License.
 | 
				
			||||||
 | 
					 * See fna.LICENSE for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Derived from code by the Mono.Xna Team (Copyright 2006).
 | 
				
			||||||
 | 
					 * Released under the MIT License. See monoxna.LICENSE for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics.PackedVector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Packed vector type containing unsigned normalized values ranging from 0 to 1.
 | 
				
			||||||
 | 
					/// The x and z components use 5 bits, and the y component uses 6 bits.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public struct Alpha8 : IPackedVector<byte>, IEquatable<Alpha8>, IPackedVector
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						#region Public Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets and sets the packed value.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public byte PackedValue
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return packedValue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								packedValue = value;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Variables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private byte packedValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Constructor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a new instance of Alpha8.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="alpha">The alpha component</param>
 | 
				
			||||||
 | 
						public Alpha8(float alpha)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(alpha);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets the packed vector in float format.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>The packed vector in Vector3 format</returns>
 | 
				
			||||||
 | 
						public float ToAlpha()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (float) (packedValue / 255.0f);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region IPackedVector Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Sets the packed vector from a Vector4.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="vector">Vector containing the components.</param>
 | 
				
			||||||
 | 
						void IPackedVector.PackFromVector4(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.W);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets the packed vector in Vector4 format.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>The packed vector in Vector4 format</returns>
 | 
				
			||||||
 | 
						Vector4 IPackedVector.ToVector4()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new Vector4(
 | 
				
			||||||
 | 
								0.0f,
 | 
				
			||||||
 | 
								0.0f,
 | 
				
			||||||
 | 
								0.0f,
 | 
				
			||||||
 | 
								(float) (packedValue / 255.0f)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Static Operators and Override Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Compares an object with the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="obj">The object to compare.</param>
 | 
				
			||||||
 | 
						/// <returns>True if the object is equal to the packed vector.</returns>
 | 
				
			||||||
 | 
						public override bool Equals(object obj)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (obj is Alpha8) && Equals((Alpha8) obj);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Compares another Bgra5551 packed vector with the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="other">The Bgra5551 packed vector to compare.</param>
 | 
				
			||||||
 | 
						/// <returns>True if the packed vectors are equal.</returns>
 | 
				
			||||||
 | 
						public bool Equals(Alpha8 other)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue == other.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets a string representation of the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>A string representation of the packed vector.</returns>
 | 
				
			||||||
 | 
						public override string ToString()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.ToString("X");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets a hash code of the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>The hash code for the packed vector.</returns>
 | 
				
			||||||
 | 
						public override int GetHashCode()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.GetHashCode();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator ==(Alpha8 lhs, Alpha8 rhs)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return lhs.packedValue == rhs.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator !=(Alpha8 lhs, Alpha8 rhs)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return lhs.packedValue != rhs.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Static Pack Method
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static byte Pack(float alpha)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (byte) System.Math.Round(Math.Clamp(alpha, 0, 1) * 255.0f);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										184
									
								
								Nerfed.Runtime/Graphics/PackedVector/Bgr565.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								Nerfed.Runtime/Graphics/PackedVector/Bgr565.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,184 @@
 | 
				
			|||||||
 | 
					#region License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MoonWorks - Game Development Framework
 | 
				
			||||||
 | 
					 * Copyright 2021 Evan Hemsley
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Derived from code by Ethan Lee (Copyright 2009-2021).
 | 
				
			||||||
 | 
					 * Released under the Microsoft Public License.
 | 
				
			||||||
 | 
					 * See fna.LICENSE for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Derived from code by the Mono.Xna Team (Copyright 2006).
 | 
				
			||||||
 | 
					 * Released under the MIT License. See monoxna.LICENSE for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#region Using Statements
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics.PackedVector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Packed vector type containing unsigned normalized values ranging from 0 to 1.
 | 
				
			||||||
 | 
					/// The x and z components use 5 bits, and the y component uses 6 bits.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public struct Bgr565 : IPackedVector<ushort>, IEquatable<Bgr565>, IPackedVector
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						#region Public Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets and sets the packed value.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public ushort PackedValue
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return packedValue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								packedValue = value;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Variables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private ushort packedValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Constructors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a new instance of Bgr565.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="x">The x component</param>
 | 
				
			||||||
 | 
						/// <param name="y">The y component</param>
 | 
				
			||||||
 | 
						/// <param name="z">The z component</param>
 | 
				
			||||||
 | 
						public Bgr565(float x, float y, float z)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(x, y, z);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a new instance of Bgr565.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="vector">
 | 
				
			||||||
 | 
						/// Vector containing the components for the packed vector.
 | 
				
			||||||
 | 
						/// </param>
 | 
				
			||||||
 | 
						public Bgr565(Vector3 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.X, vector.Y, vector.Z);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets the packed vector in Vector3 format.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>The packed vector in Vector3 format</returns>
 | 
				
			||||||
 | 
						public Vector3 ToVector3()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new Vector3(
 | 
				
			||||||
 | 
								(packedValue >> 11) / 31.0f,
 | 
				
			||||||
 | 
								((packedValue >> 5) & 0x3F) / 63.0f,
 | 
				
			||||||
 | 
								(packedValue & 0x1F) / 31.0f
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region IPackedVector Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Sets the packed vector from a Vector4.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="vector">Vector containing the components.</param>
 | 
				
			||||||
 | 
						void IPackedVector.PackFromVector4(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Pack(vector.X, vector.Y, vector.Z);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets the packed vector in Vector4 format.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>The packed vector in Vector4 format</returns>
 | 
				
			||||||
 | 
						Vector4 IPackedVector.ToVector4()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new Vector4(ToVector3(), 1.0f);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Static Operators and Override Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Compares an object with the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="obj">The object to compare.</param>
 | 
				
			||||||
 | 
						/// <returns>True if the object is equal to the packed vector.</returns>
 | 
				
			||||||
 | 
						public override bool Equals(object obj)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (obj is Bgr565) && Equals((Bgr565) obj);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Compares another Bgr565 packed vector with the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="other">The Bgr565 packed vector to compare.</param>
 | 
				
			||||||
 | 
						/// <returns>True if the packed vectors are equal.</returns>
 | 
				
			||||||
 | 
						public bool Equals(Bgr565 other)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue == other.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets a string representation of the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>A string representation of the packed vector.</returns>
 | 
				
			||||||
 | 
						public override string ToString()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.ToString("X");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets a hash code of the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>The hash code for the packed vector.</returns>
 | 
				
			||||||
 | 
						public override int GetHashCode()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.GetHashCode();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator ==(Bgr565 lhs, Bgr565 rhs)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return lhs.packedValue == rhs.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator !=(Bgr565 lhs, Bgr565 rhs)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return lhs.packedValue != rhs.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Static Pack Method
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static ushort Pack(float x, float y, float z)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (ushort) (
 | 
				
			||||||
 | 
								(((ushort) System.Math.Round(Math.Clamp(x, 0, 1) * 31.0f)) << 11) |
 | 
				
			||||||
 | 
								(((ushort) System.Math.Round(Math.Clamp(y, 0, 1) * 63.0f)) << 5) |
 | 
				
			||||||
 | 
								((ushort) System.Math.Round(Math.Clamp(z, 0, 1) * 31.0f))
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										178
									
								
								Nerfed.Runtime/Graphics/PackedVector/Bgra4444.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								Nerfed.Runtime/Graphics/PackedVector/Bgra4444.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,178 @@
 | 
				
			|||||||
 | 
					#region License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MoonWorks - Game Development Framework
 | 
				
			||||||
 | 
					 * Copyright 2021 Evan Hemsley
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Derived from code by Ethan Lee (Copyright 2009-2021).
 | 
				
			||||||
 | 
					 * Released under the Microsoft Public License.
 | 
				
			||||||
 | 
					 * See fna.LICENSE for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Derived from code by the Mono.Xna Team (Copyright 2006).
 | 
				
			||||||
 | 
					 * Released under the MIT License. See monoxna.LICENSE for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#region Using Statements
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics.PackedVector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Packed vector type containing unsigned normalized values, ranging from 0 to 1, using
 | 
				
			||||||
 | 
					/// 4 bits each for x, y, z, and w.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public struct Bgra4444 : IPackedVector<ushort>, IEquatable<Bgra4444>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						#region Public Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets and sets the packed value.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public ushort PackedValue
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return packedValue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								packedValue = value;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Variables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private ushort packedValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Constructors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a new instance of Bgra4444.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="x">The x component</param>
 | 
				
			||||||
 | 
						/// <param name="y">The y component</param>
 | 
				
			||||||
 | 
						/// <param name="z">The z component</param>
 | 
				
			||||||
 | 
						/// <param name="w">The w component</param>
 | 
				
			||||||
 | 
						public Bgra4444(float x, float y, float z, float w)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(x, y, z, w);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a new instance of Bgra4444.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="vector">
 | 
				
			||||||
 | 
						/// Vector containing the components for the packed vector.
 | 
				
			||||||
 | 
						/// </param>
 | 
				
			||||||
 | 
						public Bgra4444(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets the packed vector in Vector4 format.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>The packed vector in Vector4 format</returns>
 | 
				
			||||||
 | 
						public Vector4 ToVector4()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new Vector4(
 | 
				
			||||||
 | 
								((packedValue >> 8) & 0x0F) / 15.0f,
 | 
				
			||||||
 | 
								((packedValue >> 4) & 0x0F) / 15.0f,
 | 
				
			||||||
 | 
								(packedValue & 0x0F) / 15.0f,
 | 
				
			||||||
 | 
								(packedValue >> 12) / 15.0f
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region IPackedVector Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Sets the packed vector from a Vector4.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="vector">Vector containing the components.</param>
 | 
				
			||||||
 | 
						void IPackedVector.PackFromVector4(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Static Operators and Override Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Compares an object with the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="obj">The object to compare.</param>
 | 
				
			||||||
 | 
						/// <returns>True if the object is equal to the packed vector.</returns>
 | 
				
			||||||
 | 
						public override bool Equals(object obj)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (obj is Bgra4444) && Equals((Bgra4444) obj);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Compares another Bgra4444 packed vector with the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="other">The Bgra4444 packed vector to compare.</param>
 | 
				
			||||||
 | 
						/// <returns>True if the packed vectors are equal.</returns>
 | 
				
			||||||
 | 
						public bool Equals(Bgra4444 other)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue == other.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets a string representation of the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>A string representation of the packed vector.</returns>
 | 
				
			||||||
 | 
						public override string ToString()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.ToString("X");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets a hash code of the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>The hash code for the packed vector.</returns>
 | 
				
			||||||
 | 
						public override int GetHashCode()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.GetHashCode();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator ==(Bgra4444 lhs, Bgra4444 rhs)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return lhs.packedValue == rhs.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator !=(Bgra4444 lhs, Bgra4444 rhs)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return lhs.packedValue != rhs.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Static Pack Method
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static ushort Pack(float x, float y, float z, float w)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (ushort) (
 | 
				
			||||||
 | 
								(((ushort) System.Math.Round(Math.Clamp(x, 0, 1) * 15.0f)) << 8) |
 | 
				
			||||||
 | 
								(((ushort) System.Math.Round(Math.Clamp(y, 0, 1) * 15.0f)) << 4) |
 | 
				
			||||||
 | 
								((ushort) System.Math.Round(Math.Clamp(z, 0, 1) * 15.0f)) |
 | 
				
			||||||
 | 
								(((ushort) System.Math.Round(Math.Clamp(w, 0, 1) * 15.0f)) << 12)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										178
									
								
								Nerfed.Runtime/Graphics/PackedVector/Bgra5551.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								Nerfed.Runtime/Graphics/PackedVector/Bgra5551.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,178 @@
 | 
				
			|||||||
 | 
					#region License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MoonWorks - Game Development Framework
 | 
				
			||||||
 | 
					 * Copyright 2021 Evan Hemsley
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Derived from code by Ethan Lee (Copyright 2009-2021).
 | 
				
			||||||
 | 
					 * Released under the Microsoft Public License.
 | 
				
			||||||
 | 
					 * See fna.LICENSE for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Derived from code by the Mono.Xna Team (Copyright 2006).
 | 
				
			||||||
 | 
					 * Released under the MIT License. See monoxna.LICENSE for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#region Using Statements
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics.PackedVector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Packed vector type containing unsigned normalized values ranging from 0 to 1.
 | 
				
			||||||
 | 
					/// The x and z components use 5 bits, and the y component uses 6 bits.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public struct Bgra5551 : IPackedVector<ushort>, IEquatable<Bgra5551>, IPackedVector
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						#region Public Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets and sets the packed value.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public ushort PackedValue
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return packedValue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								packedValue = value;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Variables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private ushort packedValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Constructors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a new instance of Bgra5551.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="x">The x component</param>
 | 
				
			||||||
 | 
						/// <param name="y">The y component</param>
 | 
				
			||||||
 | 
						/// <param name="z">The z component</param>
 | 
				
			||||||
 | 
						/// <param name="w">The w component</param>
 | 
				
			||||||
 | 
						public Bgra5551(float x, float y, float z, float w)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(x, y, z, w);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a new instance of Bgra5551.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="vector">
 | 
				
			||||||
 | 
						/// Vector containing the components for the packed vector.
 | 
				
			||||||
 | 
						/// </param>
 | 
				
			||||||
 | 
						public Bgra5551(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets the packed vector in Vector4 format.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>The packed vector in Vector4 format</returns>
 | 
				
			||||||
 | 
						public Vector4 ToVector4()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new Vector4(
 | 
				
			||||||
 | 
								((packedValue >> 10) & 0x1F) / 31.0f,
 | 
				
			||||||
 | 
								((packedValue >> 5) & 0x1F) / 31.0f,
 | 
				
			||||||
 | 
								(packedValue & 0x1F) / 31.0f,
 | 
				
			||||||
 | 
								(float) (packedValue >> 15)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region IPackedVector Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Sets the packed vector from a Vector4.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="vector">Vector containing the components.</param>
 | 
				
			||||||
 | 
						void IPackedVector.PackFromVector4(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Static Operators and Override Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Compares an object with the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="obj">The object to compare.</param>
 | 
				
			||||||
 | 
						/// <returns>True if the object is equal to the packed vector.</returns>
 | 
				
			||||||
 | 
						public override bool Equals(object obj)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (obj is Bgra5551) && Equals((Bgra5551) obj);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Compares another Bgra5551 packed vector with the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="other">The Bgra5551 packed vector to compare.</param>
 | 
				
			||||||
 | 
						/// <returns>True if the packed vectors are equal.</returns>
 | 
				
			||||||
 | 
						public bool Equals(Bgra5551 other)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue == other.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets a string representation of the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>A string representation of the packed vector.</returns>
 | 
				
			||||||
 | 
						public override string ToString()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.ToString("X");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets a hash code of the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>The hash code for the packed vector.</returns>
 | 
				
			||||||
 | 
						public override int GetHashCode()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.GetHashCode();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator ==(Bgra5551 lhs, Bgra5551 rhs)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return lhs.packedValue == rhs.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator !=(Bgra5551 lhs, Bgra5551 rhs)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return lhs.packedValue != rhs.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Static Pack Method
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static ushort Pack(float x, float y, float z, float w)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (ushort) (
 | 
				
			||||||
 | 
								(((ushort) System.Math.Round(Math.Clamp(x, 0, 1) * 31.0f)) << 10) |
 | 
				
			||||||
 | 
								(((ushort) System.Math.Round(Math.Clamp(y, 0, 1) * 31.0f)) << 5) |
 | 
				
			||||||
 | 
								((ushort) System.Math.Round(Math.Clamp(z, 0, 1) * 31.0f)) |
 | 
				
			||||||
 | 
								((ushort) System.Math.Round(Math.Clamp(w, 0, 1)) << 15)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										204
									
								
								Nerfed.Runtime/Graphics/PackedVector/Byte4.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								Nerfed.Runtime/Graphics/PackedVector/Byte4.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,204 @@
 | 
				
			|||||||
 | 
					#region License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MoonWorks - Game Development Framework
 | 
				
			||||||
 | 
					 * Copyright 2021 Evan Hemsley
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Derived from code by Ethan Lee (Copyright 2009-2021).
 | 
				
			||||||
 | 
					 * Released under the Microsoft Public License.
 | 
				
			||||||
 | 
					 * See fna.LICENSE for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Derived from code by the Mono.Xna Team (Copyright 2006).
 | 
				
			||||||
 | 
					 * Released under the MIT License. See monoxna.LICENSE for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#region Using Statements
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics.PackedVector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Packed vector type containing four 8-bit unsigned integer values, ranging from 0 to 255.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public struct Byte4 : IPackedVector<uint>, IEquatable<Byte4>, IPackedVector
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						#region Public Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Directly gets or sets the packed representation of the value.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <value>The packed representation of the value.</value>
 | 
				
			||||||
 | 
						public uint PackedValue
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return packedValue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								packedValue = value;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Variables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private uint packedValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Constructors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Initializes a new instance of the Byte4 class.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="vector">
 | 
				
			||||||
 | 
						/// A vector containing the initial values for the components of the Byte4 structure.
 | 
				
			||||||
 | 
						/// </param>
 | 
				
			||||||
 | 
						public Byte4(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Initializes a new instance of the Byte4 class.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="x">Initial value for the x component.</param>
 | 
				
			||||||
 | 
						/// <param name="y">Initial value for the y component.</param>
 | 
				
			||||||
 | 
						/// <param name="z">Initial value for the z component.</param>
 | 
				
			||||||
 | 
						/// <param name="w">Initial value for the w component.</param>
 | 
				
			||||||
 | 
						public Byte4(float x, float y, float z, float w)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(x, y, z, w);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Expands the packed representation into a Vector4.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>The expanded vector.</returns>
 | 
				
			||||||
 | 
						public Vector4 ToVector4()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new Vector4(
 | 
				
			||||||
 | 
								(packedValue & 0xFF),
 | 
				
			||||||
 | 
								((packedValue >> 8) & 0xFF),
 | 
				
			||||||
 | 
								((packedValue >> 16) & 0xFF),
 | 
				
			||||||
 | 
								(packedValue >> 24)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region IPackedVector Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Sets the packed representation from a Vector4.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="vector">The vector to create the packed representation from.</param>
 | 
				
			||||||
 | 
						void IPackedVector.PackFromVector4(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Static Operators and Override Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Compares the current instance of a class to another instance to determine
 | 
				
			||||||
 | 
						/// whether they are different.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="a">The object to the left of the equality operator.</param>
 | 
				
			||||||
 | 
						/// <param name="b">The object to the right of the equality operator.</param>
 | 
				
			||||||
 | 
						/// <returns>True if the objects are different; false otherwise.</returns>
 | 
				
			||||||
 | 
						public static bool operator !=(Byte4 a, Byte4 b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return a.packedValue != b.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Compares the current instance of a class to another instance to determine
 | 
				
			||||||
 | 
						/// whether they are the same.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="a">The object to the left of the equality operator.</param>
 | 
				
			||||||
 | 
						/// <param name="b">The object to the right of the equality operator.</param>
 | 
				
			||||||
 | 
						/// <returns>True if the objects are the same; false otherwise.</returns>
 | 
				
			||||||
 | 
						public static bool operator ==(Byte4 a, Byte4 b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return a.packedValue == b.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Returns a value that indicates whether the current instance is equal to a
 | 
				
			||||||
 | 
						/// specified object.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="obj">The object with which to make the comparison.</param>
 | 
				
			||||||
 | 
						/// <returns>
 | 
				
			||||||
 | 
						/// True if the current instance is equal to the specified object; false otherwise.
 | 
				
			||||||
 | 
						/// </returns>
 | 
				
			||||||
 | 
						public override bool Equals(object obj)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (obj is Byte4) && Equals((Byte4) obj);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Returns a value that indicates whether the current instance is equal to a
 | 
				
			||||||
 | 
						/// specified object.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="other">The object with which to make the comparison.</param>
 | 
				
			||||||
 | 
						/// <returns>
 | 
				
			||||||
 | 
						/// True if the current instance is equal to the specified object; false otherwise.
 | 
				
			||||||
 | 
						/// </returns>
 | 
				
			||||||
 | 
						public bool Equals(Byte4 other)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return this == other;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets the hash code for the current instance.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>Hash code for the instance.</returns>
 | 
				
			||||||
 | 
						public override int GetHashCode()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.GetHashCode();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Returns a string representation of the current instance.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>String that represents the object.</returns>
 | 
				
			||||||
 | 
						public override string ToString()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.ToString("X");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Static Pack Method
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Packs a vector into a uint.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="vector">The vector containing the values to pack.</param>
 | 
				
			||||||
 | 
						/// <returns>The ulong containing the packed values.</returns>
 | 
				
			||||||
 | 
						static uint Pack(float x, float y, float z, float w)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (uint) (
 | 
				
			||||||
 | 
								((uint) System.Math.Round(Math.Clamp(x, 0, 255))) |
 | 
				
			||||||
 | 
								((uint) System.Math.Round(Math.Clamp(y, 0, 255)) << 8) |
 | 
				
			||||||
 | 
								((uint) System.Math.Round(Math.Clamp(z, 0, 255)) << 16) |
 | 
				
			||||||
 | 
								((uint) System.Math.Round(Math.Clamp(w, 0, 255)) << 24)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										113
									
								
								Nerfed.Runtime/Graphics/PackedVector/HalfSingle.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								Nerfed.Runtime/Graphics/PackedVector/HalfSingle.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,113 @@
 | 
				
			|||||||
 | 
					#region License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MoonWorks - Game Development Framework
 | 
				
			||||||
 | 
					 * Copyright 2021 Evan Hemsley
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Derived from code by Ethan Lee (Copyright 2009-2021).
 | 
				
			||||||
 | 
					 * Released under the Microsoft Public License.
 | 
				
			||||||
 | 
					 * See fna.LICENSE for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Derived from code by the Mono.Xna Team (Copyright 2006).
 | 
				
			||||||
 | 
					 * Released under the MIT License. See monoxna.LICENSE for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#region Using Statements
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics.PackedVector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public struct HalfSingle : IPackedVector<ushort>, IEquatable<HalfSingle>, IPackedVector
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						#region Public Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public ushort PackedValue
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return packedValue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								packedValue = value;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Variables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private ushort packedValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Constructors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public HalfSingle(float single)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = HalfTypeHelper.Convert(single);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public float ToSingle()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return HalfTypeHelper.Convert(packedValue);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region IPackedVector Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void IPackedVector.PackFromVector4(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = HalfTypeHelper.Convert(vector.X);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Vector4 IPackedVector.ToVector4()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new Vector4(ToSingle(), 0.0f, 0.0f, 1.0f);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Static Operators and Override Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override bool Equals(object obj)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (obj is HalfSingle) && Equals((HalfSingle) obj);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public bool Equals(HalfSingle other)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue == other.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override string ToString()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.ToString("X");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override int GetHashCode()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.GetHashCode();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator ==(HalfSingle lhs, HalfSingle rhs)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return lhs.packedValue == rhs.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator !=(HalfSingle lhs, HalfSingle rhs)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return lhs.packedValue != rhs.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										138
									
								
								Nerfed.Runtime/Graphics/PackedVector/HalfTypeHelper.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								Nerfed.Runtime/Graphics/PackedVector/HalfTypeHelper.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,138 @@
 | 
				
			|||||||
 | 
					#region License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MoonWorks - Game Development Framework
 | 
				
			||||||
 | 
					 * Copyright 2021 Evan Hemsley
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Derived from code by Ethan Lee (Copyright 2009-2021).
 | 
				
			||||||
 | 
					 * Released under the Microsoft Public License.
 | 
				
			||||||
 | 
					 * See fna.LICENSE for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Derived from code by the Mono.Xna Team (Copyright 2006).
 | 
				
			||||||
 | 
					 * Released under the MIT License. See monoxna.LICENSE for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#region Using Statements
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics.PackedVector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					internal static class HalfTypeHelper
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						#region Private Struct uif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[StructLayout(LayoutKind.Explicit)]
 | 
				
			||||||
 | 
						private struct uif
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							[FieldOffset(0)]
 | 
				
			||||||
 | 
							public float f;
 | 
				
			||||||
 | 
							[FieldOffset(0)]
 | 
				
			||||||
 | 
							public int i;
 | 
				
			||||||
 | 
							[FieldOffset(0)]
 | 
				
			||||||
 | 
							public uint u;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Internal Static Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						internal static ushort Convert(float f)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							uif uif = new uif();
 | 
				
			||||||
 | 
							uif.f = f;
 | 
				
			||||||
 | 
							return Convert(uif.i);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						internal static ushort Convert(int i)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							int s = (i >> 16) & 0x00008000;
 | 
				
			||||||
 | 
							int e = ((i >> 23) & 0x000000ff) - (127 - 15);
 | 
				
			||||||
 | 
							int m = i & 0x007fffff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (e <= 0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (e < -10)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return (ushort) s;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								m = m | 0x00800000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								int t = 14 - e;
 | 
				
			||||||
 | 
								int a = (1 << (t - 1)) - 1;
 | 
				
			||||||
 | 
								int b = (m >> t) & 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								m = (m + a + b) >> t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return (ushort) (s | m);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else if (e == 0xff - (127 - 15))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (m == 0)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return (ushort) (s | 0x7c00);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									m >>= 13;
 | 
				
			||||||
 | 
									return (ushort) (s | 0x7c00 | m | ((m == 0) ? 1 : 0));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								m = m + 0x00000fff + ((m >> 13) & 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if ((m & 0x00800000) != 0)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									m = 0;
 | 
				
			||||||
 | 
									e += 1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (e > 30)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return (ushort) (s | 0x7c00);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return (ushort) (s | (e << 10) | (m >> 13));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						internal static float Convert(ushort value)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							uint rst;
 | 
				
			||||||
 | 
							uint mantissa = (uint) (value & 1023);
 | 
				
			||||||
 | 
							uint exp = 0xfffffff2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if ((value & -33792) == 0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (mantissa != 0)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									while ((mantissa & 1024) == 0)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										exp--;
 | 
				
			||||||
 | 
										mantissa = mantissa << 1;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									mantissa &= 0xfffffbff;
 | 
				
			||||||
 | 
									rst = ((uint) ((((uint) value & 0x8000) << 16) | ((exp + 127) << 23))) | (mantissa << 13);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									rst = (uint) ((value & 0x8000) << 16);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								rst = (uint) (((((uint) value & 0x8000) << 16) | ((((((uint) value >> 10) & 0x1f) - 15) + 127) << 23)) | (mantissa << 13));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							uif uif = new uif();
 | 
				
			||||||
 | 
							uif.u = rst;
 | 
				
			||||||
 | 
							return uif.f;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										133
									
								
								Nerfed.Runtime/Graphics/PackedVector/HalfVector2.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								Nerfed.Runtime/Graphics/PackedVector/HalfVector2.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,133 @@
 | 
				
			|||||||
 | 
					#region License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MoonWorks - Game Development Framework
 | 
				
			||||||
 | 
					 * Copyright 2021 Evan Hemsley
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Derived from code by Ethan Lee (Copyright 2009-2021).
 | 
				
			||||||
 | 
					 * Released under the Microsoft Public License.
 | 
				
			||||||
 | 
					 * See fna.LICENSE for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Derived from code by the Mono.Xna Team (Copyright 2006).
 | 
				
			||||||
 | 
					 * Released under the MIT License. See monoxna.LICENSE for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#region Using Statements
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics.PackedVector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public struct HalfVector2 : IPackedVector<uint>, IPackedVector, IEquatable<HalfVector2>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						#region Public Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public uint PackedValue
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return packedValue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								packedValue = value;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Variables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private uint packedValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Constructors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public HalfVector2(float x, float y)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = PackHelper(x, y);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public HalfVector2(Vector2 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = PackHelper(vector.X, vector.Y);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Vector2 ToVector2()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Vector2 vector;
 | 
				
			||||||
 | 
							vector.X = HalfTypeHelper.Convert((ushort) packedValue);
 | 
				
			||||||
 | 
							vector.Y = HalfTypeHelper.Convert((ushort) (packedValue >> 0x10));
 | 
				
			||||||
 | 
							return vector;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region IPackedVector Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void IPackedVector.PackFromVector4(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = PackHelper(vector.X, vector.Y);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Vector4 IPackedVector.ToVector4()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new Vector4(ToVector2(), 0.0f, 1.0f);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Static Operators and Override Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override string ToString()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.ToString("X");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override int GetHashCode()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.GetHashCode();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override bool Equals(object obj)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return ((obj is HalfVector2) && Equals((HalfVector2) obj));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public bool Equals(HalfVector2 other)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.Equals(other.packedValue);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator ==(HalfVector2 a, HalfVector2 b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return a.Equals(b);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator !=(HalfVector2 a, HalfVector2 b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return !a.Equals(b);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Static Pack Method
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static uint PackHelper(float vectorX, float vectorY)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (uint) (
 | 
				
			||||||
 | 
								HalfTypeHelper.Convert(vectorX) |
 | 
				
			||||||
 | 
								((uint) (HalfTypeHelper.Convert(vectorY) << 0x10))
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										204
									
								
								Nerfed.Runtime/Graphics/PackedVector/HalfVector4.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								Nerfed.Runtime/Graphics/PackedVector/HalfVector4.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,204 @@
 | 
				
			|||||||
 | 
					#region License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MoonWorks - Game Development Framework
 | 
				
			||||||
 | 
					 * Copyright 2021 Evan Hemsley
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Derived from code by Ethan Lee (Copyright 2009-2021).
 | 
				
			||||||
 | 
					 * Released under the Microsoft Public License.
 | 
				
			||||||
 | 
					 * See fna.LICENSE for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Derived from code by the Mono.Xna Team (Copyright 2006).
 | 
				
			||||||
 | 
					 * Released under the MIT License. See monoxna.LICENSE for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#region Using Statements
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics.PackedVector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Packed vector type containing four 16-bit floating-point values.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public struct HalfVector4 : IPackedVector<ulong>, IPackedVector, IEquatable<HalfVector4>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						#region Public Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Directly gets or sets the packed representation of the value.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <value>The packed representation of the value.</value>
 | 
				
			||||||
 | 
						public ulong PackedValue
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return packedValue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								packedValue = value;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Variables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private ulong packedValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Constructors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Initializes a new instance of the HalfVector4 structure.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="x">Initial value for the x component.</param>
 | 
				
			||||||
 | 
						/// <param name="y">Initial value for the y component.</param>
 | 
				
			||||||
 | 
						/// <param name="z">Initial value for the z component.</param>
 | 
				
			||||||
 | 
						/// <param name="w">Initial value for the q component.</param>
 | 
				
			||||||
 | 
						public HalfVector4(float x, float y, float z, float w)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(x, y, z, w);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Initializes a new instance of the HalfVector4 structure.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="vector">
 | 
				
			||||||
 | 
						/// A vector containing the initial values for the components of the HalfVector4
 | 
				
			||||||
 | 
						/// structure.
 | 
				
			||||||
 | 
						/// </param>
 | 
				
			||||||
 | 
						public HalfVector4(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Expands the packed representation into a Vector4.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>The expanded vector.</returns>
 | 
				
			||||||
 | 
						public Vector4 ToVector4()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new Vector4(
 | 
				
			||||||
 | 
								HalfTypeHelper.Convert((ushort) packedValue),
 | 
				
			||||||
 | 
								HalfTypeHelper.Convert((ushort) (packedValue >> 0x10)),
 | 
				
			||||||
 | 
								HalfTypeHelper.Convert((ushort) (packedValue >> 0x20)),
 | 
				
			||||||
 | 
								HalfTypeHelper.Convert((ushort) (packedValue >> 0x30))
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region IPackedVector Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Sets the packed representation from a Vector4.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="vector">The vector to create the packed representation from.</param>
 | 
				
			||||||
 | 
						void IPackedVector.PackFromVector4(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Static Operators and Override Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Returns a string representation of the current instance.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>String that represents the object.</returns>
 | 
				
			||||||
 | 
						public override string ToString()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.ToString("X");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets the hash code for the current instance.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>Hash code for the instance.</returns>
 | 
				
			||||||
 | 
						public override int GetHashCode()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.GetHashCode();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Returns a value that indicates whether the current instance is equal to a
 | 
				
			||||||
 | 
						/// specified object.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="obj">The object with which to make the comparison.</param>
 | 
				
			||||||
 | 
						/// <returns>
 | 
				
			||||||
 | 
						/// True if the current instance is equal to the specified object; false otherwise.
 | 
				
			||||||
 | 
						/// </returns>
 | 
				
			||||||
 | 
						public override bool Equals(object obj)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return ((obj is HalfVector4) && Equals((HalfVector4) obj));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Returns a value that indicates whether the current instance is equal to a
 | 
				
			||||||
 | 
						/// specified object.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="other">The object with which to make the comparison.</param>
 | 
				
			||||||
 | 
						/// <returns>
 | 
				
			||||||
 | 
						/// True if the current instance is equal to the specified object; false otherwise.
 | 
				
			||||||
 | 
						/// </returns>
 | 
				
			||||||
 | 
						public bool Equals(HalfVector4 other)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.Equals(other.packedValue);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Compares the current instance of a class to another instance to determine
 | 
				
			||||||
 | 
						/// whether they are the same.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="a">The object to the left of the equality operator.</param>
 | 
				
			||||||
 | 
						/// <param name="b">The object to the right of the equality operator.</param>
 | 
				
			||||||
 | 
						/// <returns>True if the objects are the same; false otherwise.</returns>
 | 
				
			||||||
 | 
						public static bool operator ==(HalfVector4 a, HalfVector4 b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return a.Equals(b);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Compares the current instance of a class to another instance to determine
 | 
				
			||||||
 | 
						/// whether they are different.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="a">The object to the left of the equality operator.</param>
 | 
				
			||||||
 | 
						/// <param name="b">The object to the right of the equality operator.</param>
 | 
				
			||||||
 | 
						/// <returns>True if the objects are different; false otherwise.</returns>
 | 
				
			||||||
 | 
						public static bool operator !=(HalfVector4 a, HalfVector4 b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return !a.Equals(b);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Static Pack Method
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Packs a vector into a ulong.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="vector">The vector containing the values to pack.</param>
 | 
				
			||||||
 | 
						/// <returns>The ulong containing the packed values.</returns>
 | 
				
			||||||
 | 
						private static ulong Pack(float x, float y, float z, float w)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (ulong) (
 | 
				
			||||||
 | 
								((ulong) HalfTypeHelper.Convert(x)) |
 | 
				
			||||||
 | 
								(((ulong) HalfTypeHelper.Convert(y) << 0x10)) |
 | 
				
			||||||
 | 
								(((ulong) HalfTypeHelper.Convert(z) << 0x20)) |
 | 
				
			||||||
 | 
								(((ulong) HalfTypeHelper.Convert(w) << 0x30))
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										38
									
								
								Nerfed.Runtime/Graphics/PackedVector/IPackedVector.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								Nerfed.Runtime/Graphics/PackedVector/IPackedVector.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					#region License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MoonWorks - Game Development Framework
 | 
				
			||||||
 | 
					 * Copyright 2021 Evan Hemsley
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Derived from code by Ethan Lee (Copyright 2009-2021).
 | 
				
			||||||
 | 
					 * Released under the Microsoft Public License.
 | 
				
			||||||
 | 
					 * See fna.LICENSE for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Derived from code by the Mono.Xna Team (Copyright 2006).
 | 
				
			||||||
 | 
					 * Released under the MIT License. See monoxna.LICENSE for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics.PackedVector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.packedvector.ipackedvector.aspx
 | 
				
			||||||
 | 
					public interface IPackedVector
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						void PackFromVector4(Vector4 vector);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Vector4 ToVector4();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PackedVector Generic interface
 | 
				
			||||||
 | 
					// http://msdn.microsoft.com/en-us/library/bb197661.aspx
 | 
				
			||||||
 | 
					public interface IPackedVector<TPacked> : IPackedVector
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						TPacked PackedValue
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get;
 | 
				
			||||||
 | 
							set;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										141
									
								
								Nerfed.Runtime/Graphics/PackedVector/NormalizedByte2.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								Nerfed.Runtime/Graphics/PackedVector/NormalizedByte2.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,141 @@
 | 
				
			|||||||
 | 
					#region License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MoonWorks - Game Development Framework
 | 
				
			||||||
 | 
					 * Copyright 2021 Evan Hemsley
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Derived from code by Ethan Lee (Copyright 2009-2021).
 | 
				
			||||||
 | 
					 * Released under the Microsoft Public License.
 | 
				
			||||||
 | 
					 * See fna.LICENSE for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Derived from code by the Mono.Xna Team (Copyright 2006).
 | 
				
			||||||
 | 
					 * Released under the MIT License. See monoxna.LICENSE for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#region Using Statements
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics.PackedVector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public struct NormalizedByte2 : IPackedVector<ushort>, IEquatable<NormalizedByte2>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						#region Public Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public ushort PackedValue
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return packedValue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								packedValue = value;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Variables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private ushort packedValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Constructors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public NormalizedByte2(Vector2 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.X, vector.Y);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public NormalizedByte2(float x, float y)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(x, y);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Vector2 ToVector2()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new Vector2(
 | 
				
			||||||
 | 
								((sbyte) (packedValue & 0xFF)) / 127.0f,
 | 
				
			||||||
 | 
								((sbyte) ((packedValue >> 8) & 0xFF)) / 127.0f
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region IPackedVector Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void IPackedVector.PackFromVector4(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.X, vector.Y);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Vector4 IPackedVector.ToVector4()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new Vector4(ToVector2(), 0.0f, 1.0f);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Static Operators and Override Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator !=(NormalizedByte2 a, NormalizedByte2 b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return a.packedValue != b.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator ==(NormalizedByte2 a, NormalizedByte2 b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return a.packedValue == b.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override bool Equals(object obj)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (obj is NormalizedByte2) && Equals((NormalizedByte2) obj);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public bool Equals(NormalizedByte2 other)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue == other.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override int GetHashCode()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.GetHashCode();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override string ToString()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.ToString("X");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Static Pack Method
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static ushort Pack(float x, float y)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							int byte2 = (
 | 
				
			||||||
 | 
								((ushort)
 | 
				
			||||||
 | 
									System.Math.Round(Math.Clamp(x, -1.0f, 1.0f) * 127.0f)
 | 
				
			||||||
 | 
								)
 | 
				
			||||||
 | 
							) & 0x00FF;
 | 
				
			||||||
 | 
							int byte1 = (
 | 
				
			||||||
 | 
								((ushort)
 | 
				
			||||||
 | 
									System.Math.Round(Math.Clamp(y, -1.0f, 1.0f) * 127.0f)
 | 
				
			||||||
 | 
								) << 8
 | 
				
			||||||
 | 
							) & 0xFF00;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return (ushort) (byte2 | byte1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										146
									
								
								Nerfed.Runtime/Graphics/PackedVector/NormalizedByte4.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								Nerfed.Runtime/Graphics/PackedVector/NormalizedByte4.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,146 @@
 | 
				
			|||||||
 | 
					#region License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MoonWorks - Game Development Framework
 | 
				
			||||||
 | 
					 * Copyright 2021 Evan Hemsley
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Derived from code by Ethan Lee (Copyright 2009-2021).
 | 
				
			||||||
 | 
					 * Released under the Microsoft Public License.
 | 
				
			||||||
 | 
					 * See fna.LICENSE for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Derived from code by the Mono.Xna Team (Copyright 2006).
 | 
				
			||||||
 | 
					 * Released under the MIT License. See monoxna.LICENSE for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#region Using Statements
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics.PackedVector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public struct NormalizedByte4 : IPackedVector<uint>, IEquatable<NormalizedByte4>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						#region Public Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public uint PackedValue
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return packedValue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								packedValue = value;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Variables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private uint packedValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Constructors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public NormalizedByte4(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public NormalizedByte4(float x, float y, float z, float w)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(x, y, z, w);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Vector4 ToVector4()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new Vector4(
 | 
				
			||||||
 | 
								((sbyte) (packedValue & 0xFF)) / 127.0f,
 | 
				
			||||||
 | 
								((sbyte) ((packedValue >> 8) & 0xFF)) / 127.0f,
 | 
				
			||||||
 | 
								((sbyte) ((packedValue >> 16) & 0xFF)) / 127.0f,
 | 
				
			||||||
 | 
								((sbyte) ((packedValue >> 24) & 0xFF)) / 127.0f
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region IPackedVector Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void IPackedVector.PackFromVector4(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Static Operators and Override Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator !=(NormalizedByte4 a, NormalizedByte4 b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return a.packedValue != b.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator ==(NormalizedByte4 a, NormalizedByte4 b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return a.packedValue == b.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override bool Equals(object obj)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (obj is NormalizedByte4) && Equals((NormalizedByte4) obj);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public bool Equals(NormalizedByte4 other)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue == other.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override int GetHashCode()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.GetHashCode();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override string ToString()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.ToString("X");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Static Pack Method
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static uint Pack(float x, float y, float z, float w)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							uint byte4 = (
 | 
				
			||||||
 | 
								(uint) System.Math.Round(Math.Clamp(x, -1.0f, 1.0f) * 127.0f)
 | 
				
			||||||
 | 
							) & 0x000000FF;
 | 
				
			||||||
 | 
							uint byte3 = (
 | 
				
			||||||
 | 
								(
 | 
				
			||||||
 | 
									(uint) System.Math.Round(Math.Clamp(y, -1.0f, 1.0f) * 127.0f)
 | 
				
			||||||
 | 
								) << 8
 | 
				
			||||||
 | 
							) & 0x0000FF00;
 | 
				
			||||||
 | 
							uint byte2 = (
 | 
				
			||||||
 | 
								(
 | 
				
			||||||
 | 
									(uint) System.Math.Round(Math.Clamp(z, -1.0f, 1.0f) * 127.0f)
 | 
				
			||||||
 | 
								) << 16
 | 
				
			||||||
 | 
							) & 0x00FF0000;
 | 
				
			||||||
 | 
							uint byte1 = (
 | 
				
			||||||
 | 
								(
 | 
				
			||||||
 | 
									(uint) System.Math.Round(Math.Clamp(w, -1.0f, 1.0f) * 127.0f)
 | 
				
			||||||
 | 
								) << 24
 | 
				
			||||||
 | 
							) & 0xFF000000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return byte4 | byte3 | byte2 | byte1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										150
									
								
								Nerfed.Runtime/Graphics/PackedVector/NormalizedShort2.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								Nerfed.Runtime/Graphics/PackedVector/NormalizedShort2.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,150 @@
 | 
				
			|||||||
 | 
					#region License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MoonWorks - Game Development Framework
 | 
				
			||||||
 | 
					 * Copyright 2021 Evan Hemsley
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Derived from code by Ethan Lee (Copyright 2009-2021).
 | 
				
			||||||
 | 
					 * Released under the Microsoft Public License.
 | 
				
			||||||
 | 
					 * See fna.LICENSE for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Derived from code by the Mono.Xna Team (Copyright 2006).
 | 
				
			||||||
 | 
					 * Released under the MIT License. See monoxna.LICENSE for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#region Using Statements
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics.PackedVector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public struct NormalizedShort2 : IPackedVector<uint>, IEquatable<NormalizedShort2>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						#region Public Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public uint PackedValue
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return packedValue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								packedValue = value;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Variables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private uint packedValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Constructors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public NormalizedShort2(Vector2 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.X, vector.Y);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public NormalizedShort2(float x, float y)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(x, y);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Vector2 ToVector2()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							const float maxVal = 0x7FFF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return new Vector2(
 | 
				
			||||||
 | 
								(short) (packedValue & 0xFFFF) / maxVal,
 | 
				
			||||||
 | 
								(short) (packedValue >> 0x10) / maxVal
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region IPackedVector Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void IPackedVector.PackFromVector4(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.X, vector.Y);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Vector4 IPackedVector.ToVector4()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new Vector4(ToVector2(), 0.0f, 1.0f);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Static Operators and Override Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator !=(NormalizedShort2 a, NormalizedShort2 b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return !a.Equals(b);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator ==(NormalizedShort2 a, NormalizedShort2 b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return a.Equals(b);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override bool Equals(object obj)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (obj is NormalizedShort2) && Equals((NormalizedShort2) obj);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public bool Equals(NormalizedShort2 other)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.Equals(other.packedValue);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override int GetHashCode()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.GetHashCode();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override string ToString()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.ToString("X");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Static Pack Method
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static uint Pack(float x, float y)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							const float max = 0x7FFF;
 | 
				
			||||||
 | 
							const float min = -max;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							uint word2 = (uint) (
 | 
				
			||||||
 | 
								(int) Math.Clamp(
 | 
				
			||||||
 | 
									(float) System.Math.Round(x * max),
 | 
				
			||||||
 | 
									min,
 | 
				
			||||||
 | 
									max
 | 
				
			||||||
 | 
								) & 0xFFFF
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							uint word1 = (uint) ((
 | 
				
			||||||
 | 
								(int) Math.Clamp(
 | 
				
			||||||
 | 
									(float) System.Math.Round(y * max),
 | 
				
			||||||
 | 
									min,
 | 
				
			||||||
 | 
									max
 | 
				
			||||||
 | 
								) & 0xFFFF
 | 
				
			||||||
 | 
							) << 0x10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return (word2 | word1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										161
									
								
								Nerfed.Runtime/Graphics/PackedVector/NormalizedShort4.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								Nerfed.Runtime/Graphics/PackedVector/NormalizedShort4.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,161 @@
 | 
				
			|||||||
 | 
					#region License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MoonWorks - Game Development Framework
 | 
				
			||||||
 | 
					 * Copyright 2021 Evan Hemsley
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Derived from code by Ethan Lee (Copyright 2009-2021).
 | 
				
			||||||
 | 
					 * Released under the Microsoft Public License.
 | 
				
			||||||
 | 
					 * See fna.LICENSE for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Derived from code by the Mono.Xna Team (Copyright 2006).
 | 
				
			||||||
 | 
					 * Released under the MIT License. See monoxna.LICENSE for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#region Using Statements
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics.PackedVector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public struct NormalizedShort4 : IPackedVector<ulong>, IEquatable<NormalizedShort4>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						#region Public Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public ulong PackedValue
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return packedValue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								packedValue = value;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Variables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private ulong packedValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Constructors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public NormalizedShort4(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public NormalizedShort4(float x, float y, float z, float w)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(x, y, z, w);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Vector4 ToVector4()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							const float maxVal = 0x7FFF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return new Vector4(
 | 
				
			||||||
 | 
								((short) (packedValue & 0xFFFF)) / maxVal,
 | 
				
			||||||
 | 
								((short) ((packedValue >> 0x10) & 0xFFFF)) / maxVal,
 | 
				
			||||||
 | 
								((short) ((packedValue >> 0x20) & 0xFFFF)) / maxVal,
 | 
				
			||||||
 | 
								((short) ((packedValue >> 0x30) & 0xFFFF)) / maxVal
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region IPackedVector Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void IPackedVector.PackFromVector4(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Static Operators and Override Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator !=(NormalizedShort4 a, NormalizedShort4 b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return !a.Equals(b);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator ==(NormalizedShort4 a, NormalizedShort4 b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return a.Equals(b);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override bool Equals(object obj)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (obj is NormalizedShort4) && Equals((NormalizedShort4) obj);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public bool Equals(NormalizedShort4 other)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.Equals(other.packedValue);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override int GetHashCode()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.GetHashCode();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override string ToString()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.ToString("X");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Static Pack Method
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static ulong Pack(float x, float y, float z, float w)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							const float max = 0x7FFF;
 | 
				
			||||||
 | 
							const float min = -max;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ulong word4 = (
 | 
				
			||||||
 | 
								(ulong) Math.Clamp(
 | 
				
			||||||
 | 
									(float) System.Math.Round(x * max),
 | 
				
			||||||
 | 
									min,
 | 
				
			||||||
 | 
									max
 | 
				
			||||||
 | 
								) & 0xFFFF
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							ulong word3 = (
 | 
				
			||||||
 | 
								(ulong) Math.Clamp(
 | 
				
			||||||
 | 
									(float) System.Math.Round(y * max),
 | 
				
			||||||
 | 
									min,
 | 
				
			||||||
 | 
									max
 | 
				
			||||||
 | 
								) & 0xFFFF
 | 
				
			||||||
 | 
							) << 0x10;
 | 
				
			||||||
 | 
							ulong word2 = (
 | 
				
			||||||
 | 
								(ulong) Math.Clamp(
 | 
				
			||||||
 | 
									(float) System.Math.Round(z * max),
 | 
				
			||||||
 | 
									min,
 | 
				
			||||||
 | 
									max
 | 
				
			||||||
 | 
								) & 0xFFFF
 | 
				
			||||||
 | 
							) << 0x20;
 | 
				
			||||||
 | 
							ulong word1 = (
 | 
				
			||||||
 | 
								(ulong) Math.Clamp(
 | 
				
			||||||
 | 
									(float) System.Math.Round(w * max),
 | 
				
			||||||
 | 
									min,
 | 
				
			||||||
 | 
									max
 | 
				
			||||||
 | 
								) & 0xFFFF
 | 
				
			||||||
 | 
							) << 0x30;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return (word4 | word3 | word2 | word1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										182
									
								
								Nerfed.Runtime/Graphics/PackedVector/Rg32.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								Nerfed.Runtime/Graphics/PackedVector/Rg32.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,182 @@
 | 
				
			|||||||
 | 
					#region License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MoonWorks - Game Development Framework
 | 
				
			||||||
 | 
					 * Copyright 2021 Evan Hemsley
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Derived from code by Ethan Lee (Copyright 2009-2021).
 | 
				
			||||||
 | 
					 * Released under the Microsoft Public License.
 | 
				
			||||||
 | 
					 * See fna.LICENSE for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Derived from code by the Mono.Xna Team (Copyright 2006).
 | 
				
			||||||
 | 
					 * Released under the MIT License. See monoxna.LICENSE for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#region Using Statements
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics.PackedVector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Packed vector type containing unsigned normalized values ranging from 0 to 1.
 | 
				
			||||||
 | 
					/// The x and z components use 5 bits, and the y component uses 6 bits.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public struct Rg32 : IPackedVector<uint>, IEquatable<Rg32>, IPackedVector
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						#region Public Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets and sets the packed value.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public uint PackedValue
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return packedValue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								packedValue = value;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Variables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private uint packedValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Constructors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a new instance of Rg32.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="x">The x component</param>
 | 
				
			||||||
 | 
						/// <param name="y">The y component</param>
 | 
				
			||||||
 | 
						public Rg32(float x, float y)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(x, y);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a new instance of Rg32.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="vector">
 | 
				
			||||||
 | 
						/// Vector containing the components for the packed vector.
 | 
				
			||||||
 | 
						/// </param>
 | 
				
			||||||
 | 
						public Rg32(Vector2 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.X, vector.Y);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets the packed vector in Vector2 format.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>The packed vector in Vector2 format</returns>
 | 
				
			||||||
 | 
						public Vector2 ToVector2()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new Vector2(
 | 
				
			||||||
 | 
								(packedValue & 0xFFFF) / 65535.0f,
 | 
				
			||||||
 | 
								(packedValue >> 16) / 65535.0f
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region IPackedVector Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Sets the packed vector from a Vector4.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="vector">Vector containing the components.</param>
 | 
				
			||||||
 | 
						void IPackedVector.PackFromVector4(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.X, vector.Y);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets the packed vector in Vector4 format.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>The packed vector in Vector4 format</returns>
 | 
				
			||||||
 | 
						Vector4 IPackedVector.ToVector4()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new Vector4(ToVector2(), 0.0f, 1.0f);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Static Operators and Override Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Compares an object with the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="obj">The object to compare.</param>
 | 
				
			||||||
 | 
						/// <returns>True if the object is equal to the packed vector.</returns>
 | 
				
			||||||
 | 
						public override bool Equals(object obj)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (obj is Rg32) && Equals((Rg32) obj);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Compares another Rg32 packed vector with the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="other">The Rg32 packed vector to compare.</param>
 | 
				
			||||||
 | 
						/// <returns>True if the packed vectors are equal.</returns>
 | 
				
			||||||
 | 
						public bool Equals(Rg32 other)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue == other.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets a string representation of the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>A string representation of the packed vector.</returns>
 | 
				
			||||||
 | 
						public override string ToString()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.ToString("X");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets a hash code of the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>The hash code for the packed vector.</returns>
 | 
				
			||||||
 | 
						public override int GetHashCode()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.GetHashCode();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator ==(Rg32 lhs, Rg32 rhs)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return lhs.packedValue == rhs.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator !=(Rg32 lhs, Rg32 rhs)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return lhs.packedValue != rhs.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Static Pack Method
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static uint Pack(float x, float y)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (uint) (
 | 
				
			||||||
 | 
								((uint) System.Math.Round(Math.Clamp(x, 0, 1) * 65535.0f)) |
 | 
				
			||||||
 | 
								(((uint) System.Math.Round(Math.Clamp(y, 0, 1) * 65535.0f)) << 16)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										178
									
								
								Nerfed.Runtime/Graphics/PackedVector/Rgba1010102.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								Nerfed.Runtime/Graphics/PackedVector/Rgba1010102.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,178 @@
 | 
				
			|||||||
 | 
					#region License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MoonWorks - Game Development Framework
 | 
				
			||||||
 | 
					 * Copyright 2021 Evan Hemsley
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Derived from code by Ethan Lee (Copyright 2009-2021).
 | 
				
			||||||
 | 
					 * Released under the Microsoft Public License.
 | 
				
			||||||
 | 
					 * See fna.LICENSE for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Derived from code by the Mono.Xna Team (Copyright 2006).
 | 
				
			||||||
 | 
					 * Released under the MIT License. See monoxna.LICENSE for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#region Using Statements
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics.PackedVector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Packed vector type containing unsigned normalized values ranging from 0 to 1.
 | 
				
			||||||
 | 
					/// The x and z components use 5 bits, and the y component uses 6 bits.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public struct Rgba1010102 : IPackedVector<uint>, IEquatable<Rgba1010102>, IPackedVector
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						#region Public Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets and sets the packed value.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public uint PackedValue
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
									return packedValue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
									packedValue = value;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Variables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private uint packedValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Constructors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a new instance of Rgba1010102.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="x">The x component</param>
 | 
				
			||||||
 | 
						/// <param name="y">The y component</param>
 | 
				
			||||||
 | 
						/// <param name="z">The z component</param>
 | 
				
			||||||
 | 
						/// <param name="w">The w component</param>
 | 
				
			||||||
 | 
						public Rgba1010102(float x, float y, float z, float w)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								packedValue = Pack(x, y, z, w);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a new instance of Rgba1010102.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="vector">
 | 
				
			||||||
 | 
						/// Vector containing the components for the packed vector.
 | 
				
			||||||
 | 
						/// </param>
 | 
				
			||||||
 | 
						public Rgba1010102(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								packedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets the packed vector in Vector4 format.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>The packed vector in Vector4 format</returns>
 | 
				
			||||||
 | 
						public Vector4 ToVector4()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								return new Vector4(
 | 
				
			||||||
 | 
									(packedValue & 0x03FF) / 1023.0f,
 | 
				
			||||||
 | 
									((packedValue >> 10) & 0x03FF) / 1023.0f,
 | 
				
			||||||
 | 
									((packedValue >> 20) & 0x03FF) / 1023.0f,
 | 
				
			||||||
 | 
									(packedValue >> 30) / 3.0f
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region IPackedVector Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Sets the packed vector from a Vector4.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="vector">Vector containing the components.</param>
 | 
				
			||||||
 | 
						void IPackedVector.PackFromVector4(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								packedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Static Operators and Override Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Compares an object with the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="obj">The object to compare.</param>
 | 
				
			||||||
 | 
						/// <returns>True if the object is equal to the packed vector.</returns>
 | 
				
			||||||
 | 
						public override bool Equals(object obj)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								return (obj is Rgba1010102) && Equals((Rgba1010102) obj);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Compares another Rgba1010102 packed vector with the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="other">The Rgba1010102 packed vector to compare.</param>
 | 
				
			||||||
 | 
						/// <returns>True if the packed vectors are equal.</returns>
 | 
				
			||||||
 | 
						public bool Equals(Rgba1010102 other)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								return packedValue == other.packedValue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets a string representation of the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>A string representation of the packed vector.</returns>
 | 
				
			||||||
 | 
						public override string ToString()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								return packedValue.ToString("X");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets a hash code of the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>The hash code for the packed vector.</returns>
 | 
				
			||||||
 | 
						public override int GetHashCode()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								return packedValue.GetHashCode();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator ==(Rgba1010102 lhs, Rgba1010102 rhs)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								return lhs.packedValue == rhs.packedValue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator !=(Rgba1010102 lhs, Rgba1010102 rhs)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								return lhs.packedValue != rhs.packedValue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Static Pack Method
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static uint Pack(float x, float y, float z, float w)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								return (uint) (
 | 
				
			||||||
 | 
									((uint) System.Math.Round(Math.Clamp(x, 0, 1) * 1023.0f)) |
 | 
				
			||||||
 | 
									((uint) System.Math.Round(Math.Clamp(y, 0, 1) * 1023.0f) << 10) |
 | 
				
			||||||
 | 
									((uint) System.Math.Round(Math.Clamp(z, 0, 1) * 1023.0f) << 20) |
 | 
				
			||||||
 | 
									((uint) System.Math.Round(Math.Clamp(w, 0, 1) * 3.0f) << 30)
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										178
									
								
								Nerfed.Runtime/Graphics/PackedVector/Rgba64.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								Nerfed.Runtime/Graphics/PackedVector/Rgba64.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,178 @@
 | 
				
			|||||||
 | 
					#region License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MoonWorks - Game Development Framework
 | 
				
			||||||
 | 
					 * Copyright 2021 Evan Hemsley
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Derived from code by Ethan Lee (Copyright 2009-2021).
 | 
				
			||||||
 | 
					 * Released under the Microsoft Public License.
 | 
				
			||||||
 | 
					 * See fna.LICENSE for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Derived from code by the Mono.Xna Team (Copyright 2006).
 | 
				
			||||||
 | 
					 * Released under the MIT License. See monoxna.LICENSE for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#region Using Statements
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics.PackedVector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Packed vector type containing unsigned normalized values ranging from 0 to 1.
 | 
				
			||||||
 | 
					/// The x and z components use 5 bits, and the y component uses 6 bits.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public struct Rgba64 : IPackedVector<ulong>, IEquatable<Rgba64>, IPackedVector
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						#region Public Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets and sets the packed value.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public ulong PackedValue
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return packedValue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								packedValue = value;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Variables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private ulong packedValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Constructors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a new instance of Rgba64.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="x">The x component</param>
 | 
				
			||||||
 | 
						/// <param name="y">The y component</param>
 | 
				
			||||||
 | 
						/// <param name="z">The z component</param>
 | 
				
			||||||
 | 
						/// <param name="w">The w component</param>
 | 
				
			||||||
 | 
						public Rgba64(float x, float y, float z, float w)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(x, y, z, w);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a new instance of Rgba64.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="vector">
 | 
				
			||||||
 | 
						/// Vector containing the components for the packed vector.
 | 
				
			||||||
 | 
						/// </param>
 | 
				
			||||||
 | 
						public Rgba64(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets the packed vector in Vector4 format.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>The packed vector in Vector4 format</returns>
 | 
				
			||||||
 | 
						public Vector4 ToVector4()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new Vector4(
 | 
				
			||||||
 | 
								(packedValue & 0xFFFF) / 65535.0f,
 | 
				
			||||||
 | 
								((packedValue >> 16) & 0xFFFF) / 65535.0f,
 | 
				
			||||||
 | 
								((packedValue >> 32) & 0xFFFF) / 65535.0f,
 | 
				
			||||||
 | 
								(packedValue >> 48) / 65535.0f
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region IPackedVector Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Sets the packed vector from a Vector4.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="vector">Vector containing the components.</param>
 | 
				
			||||||
 | 
						void IPackedVector.PackFromVector4(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Static Operators and Override Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Compares an object with the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="obj">The object to compare.</param>
 | 
				
			||||||
 | 
						/// <returns>True if the object is equal to the packed vector.</returns>
 | 
				
			||||||
 | 
						public override bool Equals(object obj)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (obj is Rgba64) && Equals((Rgba64) obj);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Compares another Rgba64 packed vector with the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="other">The Rgba64 packed vector to compare.</param>
 | 
				
			||||||
 | 
						/// <returns>True if the packed vectors are equal.</returns>
 | 
				
			||||||
 | 
						public bool Equals(Rgba64 other)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue == other.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets a string representation of the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>A string representation of the packed vector.</returns>
 | 
				
			||||||
 | 
						public override string ToString()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.ToString("X");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets a hash code of the packed vector.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>The hash code for the packed vector.</returns>
 | 
				
			||||||
 | 
						public override int GetHashCode()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.GetHashCode();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator ==(Rgba64 lhs, Rgba64 rhs)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return lhs.packedValue == rhs.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator !=(Rgba64 lhs, Rgba64 rhs)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return lhs.packedValue != rhs.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Static Pack Method
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static ulong Pack(float x, float y, float z, float w)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (ulong) (
 | 
				
			||||||
 | 
								((ulong) System.Math.Round(Math.Clamp(x, 0, 1) * 65535.0f)) |
 | 
				
			||||||
 | 
								(((ulong) System.Math.Round(Math.Clamp(y, 0, 1) * 65535.0f)) << 16) |
 | 
				
			||||||
 | 
								(((ulong) System.Math.Round(Math.Clamp(z, 0, 1) * 65535.0f)) << 32) |
 | 
				
			||||||
 | 
								(((ulong) System.Math.Round(Math.Clamp(w, 0, 1) * 65535.0f)) << 48)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										134
									
								
								Nerfed.Runtime/Graphics/PackedVector/Short2.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								Nerfed.Runtime/Graphics/PackedVector/Short2.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,134 @@
 | 
				
			|||||||
 | 
					#region License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MoonWorks - Game Development Framework
 | 
				
			||||||
 | 
					 * Copyright 2021 Evan Hemsley
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Derived from code by Ethan Lee (Copyright 2009-2021).
 | 
				
			||||||
 | 
					 * Released under the Microsoft Public License.
 | 
				
			||||||
 | 
					 * See fna.LICENSE for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Derived from code by the Mono.Xna Team (Copyright 2006).
 | 
				
			||||||
 | 
					 * Released under the MIT License. See monoxna.LICENSE for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#region Using Statements
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics.PackedVector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public struct Short2 : IPackedVector<uint>, IEquatable<Short2>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						#region Public Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public uint PackedValue
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return packedValue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								packedValue = value;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Variables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private uint packedValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Constructors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Short2(Vector2 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.X, vector.Y);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Short2(float x, float y)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(x, y);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Vector2 ToVector2()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new Vector2(
 | 
				
			||||||
 | 
								(short) (packedValue & 0xFFFF),
 | 
				
			||||||
 | 
								(short) (packedValue >> 16)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region IPackedVector Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void IPackedVector.PackFromVector4(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							packedValue = Pack(vector.X, vector.Y);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Vector4 IPackedVector.ToVector4()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new Vector4(ToVector2(), 0.0f, 1.0f);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Static Operators and Override Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator !=(Short2 a, Short2 b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return a.packedValue != b.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static bool operator ==(Short2 a, Short2 b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return a.packedValue == b.packedValue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override bool Equals(object obj)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (obj is Short2) && Equals((Short2) obj);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public bool Equals(Short2 other)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return this == other;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override int GetHashCode()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.GetHashCode();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public override string ToString()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return packedValue.ToString("X");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Static Pack Method
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static uint Pack(float x, float y)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (uint) (
 | 
				
			||||||
 | 
								((int) System.Math.Round(Math.Clamp(x, -32768, 32767)) & 0x0000FFFF) |
 | 
				
			||||||
 | 
								(((int) System.Math.Round(Math.Clamp(y, -32768, 32767))) << 16)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										204
									
								
								Nerfed.Runtime/Graphics/PackedVector/Short4.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								Nerfed.Runtime/Graphics/PackedVector/Short4.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,204 @@
 | 
				
			|||||||
 | 
					#region License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* MoonWorks - Game Development Framework
 | 
				
			||||||
 | 
					 * Copyright 2021 Evan Hemsley
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Derived from code by Ethan Lee (Copyright 2009-2021).
 | 
				
			||||||
 | 
					 * Released under the Microsoft Public License.
 | 
				
			||||||
 | 
					 * See fna.LICENSE for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Derived from code by the Mono.Xna Team (Copyright 2006).
 | 
				
			||||||
 | 
					 * Released under the MIT License. See monoxna.LICENSE for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#region Using Statements
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics.PackedVector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Packed vector type containing four 16-bit signed integer values.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public struct Short4 : IPackedVector<ulong>, IEquatable<Short4>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						#region Public Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Directly gets or sets the packed representation of the value.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <value>The packed representation of the value.</value>
 | 
				
			||||||
 | 
						public ulong PackedValue
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
									return packedValue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
									packedValue = value;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Variables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private ulong packedValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Constructors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Initializes a new instance of the Short4 class.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="vector">
 | 
				
			||||||
 | 
						/// A vector containing the initial values for the components of the Short4 structure.
 | 
				
			||||||
 | 
						/// </param>
 | 
				
			||||||
 | 
						public Short4(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								packedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Initializes a new instance of the Short4 class.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="x">Initial value for the x component.</param>
 | 
				
			||||||
 | 
						/// <param name="y">Initial value for the y component.</param>
 | 
				
			||||||
 | 
						/// <param name="z">Initial value for the z component.</param>
 | 
				
			||||||
 | 
						/// <param name="w">Initial value for the w component.</param>
 | 
				
			||||||
 | 
						public Short4(float x, float y, float z, float w)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								packedValue = Pack(x, y, z, w);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Expands the packed representation into a Vector4.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>The expanded vector.</returns>
 | 
				
			||||||
 | 
						public Vector4 ToVector4()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								return new Vector4(
 | 
				
			||||||
 | 
									(short) (packedValue & 0xFFFF),
 | 
				
			||||||
 | 
									(short) ((packedValue >> 16) & 0xFFFF),
 | 
				
			||||||
 | 
									(short) ((packedValue >> 32) & 0xFFFF),
 | 
				
			||||||
 | 
									(short) (packedValue >> 48)
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region IPackedVector Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Sets the packed representation from a Vector4.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="vector">The vector to create the packed representation from.</param>
 | 
				
			||||||
 | 
						void IPackedVector.PackFromVector4(Vector4 vector)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								packedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Public Static Operators and Override Methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Compares the current instance of a class to another instance to determine
 | 
				
			||||||
 | 
						/// whether they are different.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="a">The object to the left of the equality operator.</param>
 | 
				
			||||||
 | 
						/// <param name="b">The object to the right of the equality operator.</param>
 | 
				
			||||||
 | 
						/// <returns>True if the objects are different; false otherwise.</returns>
 | 
				
			||||||
 | 
						public static bool operator !=(Short4 a, Short4 b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								return a.PackedValue != b.PackedValue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Compares the current instance of a class to another instance to determine
 | 
				
			||||||
 | 
						/// whether they are the same.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="a">The object to the left of the equality operator.</param>
 | 
				
			||||||
 | 
						/// <param name="b">The object to the right of the equality operator.</param>
 | 
				
			||||||
 | 
						/// <returns>True if the objects are the same; false otherwise.</returns>
 | 
				
			||||||
 | 
						public static bool operator ==(Short4 a, Short4 b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								return a.PackedValue == b.PackedValue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Returns a value that indicates whether the current instance is equal to a
 | 
				
			||||||
 | 
						/// specified object.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="obj">The object with which to make the comparison.</param>
 | 
				
			||||||
 | 
						/// <returns>
 | 
				
			||||||
 | 
						/// True if the current instance is equal to the specified object; false otherwise.
 | 
				
			||||||
 | 
						/// </returns>
 | 
				
			||||||
 | 
						public override bool Equals(object obj)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								return (obj is Short4) && Equals((Short4) obj);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Returns a value that indicates whether the current instance is equal to a
 | 
				
			||||||
 | 
						/// specified object.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="other">The object with which to make the comparison.</param>
 | 
				
			||||||
 | 
						/// <returns>
 | 
				
			||||||
 | 
						/// True if the current instance is equal to the specified object; false otherwise.
 | 
				
			||||||
 | 
						/// </returns>
 | 
				
			||||||
 | 
						public bool Equals(Short4 other)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								return this == other;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Gets the hash code for the current instance.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>Hash code for the instance.</returns>
 | 
				
			||||||
 | 
						public override int GetHashCode()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								return packedValue.GetHashCode();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Returns a string representation of the current instance.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <returns>String that represents the object.</returns>
 | 
				
			||||||
 | 
						public override string ToString()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								return packedValue.ToString("X");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#region Private Static Pack Method
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Packs a vector into a ulong.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="vector">The vector containing the values to pack.</param>
 | 
				
			||||||
 | 
						/// <returns>The ulong containing the packed values.</returns>
 | 
				
			||||||
 | 
						static ulong Pack(float x, float y, float z, float w)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
								return (ulong) (
 | 
				
			||||||
 | 
									((long) System.Math.Round(Math.Clamp(x, -32768, 32767)) & 0xFFFF) |
 | 
				
			||||||
 | 
									(((long) System.Math.Round(Math.Clamp(y, -32768, 32767)) << 16) & 0xFFFF0000) |
 | 
				
			||||||
 | 
									(((long) System.Math.Round(Math.Clamp(z, -32768, 32767)) << 32) & 0xFFFF00000000) |
 | 
				
			||||||
 | 
									((long) System.Math.Round(Math.Clamp(w, -32768, 32767)) << 48)
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#endregion
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										30
									
								
								Nerfed.Runtime/Graphics/RefreshResource.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								Nerfed.Runtime/Graphics/RefreshResource.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Threading;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public abstract class RefreshResource : GraphicsResource
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public IntPtr Handle { get => handle; internal set => handle = value; }
 | 
				
			||||||
 | 
						private IntPtr handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected abstract Action<IntPtr, IntPtr> ReleaseFunction { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected RefreshResource(GraphicsDevice device) : base(device)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected override void Dispose(bool disposing)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (!IsDisposed)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								// Atomically call release function in case this is called from the finalizer thread
 | 
				
			||||||
 | 
								IntPtr toDispose = Interlocked.Exchange(ref handle, IntPtr.Zero);
 | 
				
			||||||
 | 
								if (toDispose != IntPtr.Zero)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									ReleaseFunction(Device.Handle, toDispose);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							base.Dispose(disposing);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1723
									
								
								Nerfed.Runtime/Graphics/RefreshTypes.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1723
									
								
								Nerfed.Runtime/Graphics/RefreshTypes.cs
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										495
									
								
								Nerfed.Runtime/Graphics/RenderPass.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										495
									
								
								Nerfed.Runtime/Graphics/RenderPass.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,495 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					using RefreshCS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Render passes are begun in command buffers and are used to apply render state and issue draw calls.
 | 
				
			||||||
 | 
					/// Render passes are pooled and should not be referenced after calling EndRenderPass.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class RenderPass
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public nint Handle { get; private set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					    internal uint colorAttachmentCount;
 | 
				
			||||||
 | 
					    internal SampleCount colorAttachmentSampleCount;
 | 
				
			||||||
 | 
					    internal TextureFormat colorFormatOne;
 | 
				
			||||||
 | 
					    internal TextureFormat colorFormatTwo;
 | 
				
			||||||
 | 
					    internal TextureFormat colorFormatThree;
 | 
				
			||||||
 | 
					    internal TextureFormat colorFormatFour;
 | 
				
			||||||
 | 
					    internal bool hasDepthStencilAttachment;
 | 
				
			||||||
 | 
					    internal SampleCount depthStencilAttachmentSampleCount;
 | 
				
			||||||
 | 
					    internal TextureFormat depthStencilFormat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GraphicsPipeline currentGraphicsPipeline;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal void SetHandle(nint handle)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Handle = handle;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Binds a graphics pipeline so that rendering work may be performed.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="graphicsPipeline">The graphics pipeline to bind.</param>
 | 
				
			||||||
 | 
					    public void BindGraphicsPipeline(GraphicsPipeline graphicsPipeline)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					        AssertRenderPassPipelineFormatMatch(graphicsPipeline);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (colorAttachmentCount > 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (graphicsPipeline.SampleCount != colorAttachmentSampleCount)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                throw new System.InvalidOperationException(
 | 
				
			||||||
 | 
					                    $"Sample count mismatch! Graphics pipeline sample count: {graphicsPipeline.SampleCount}, Color attachment sample count: {colorAttachmentSampleCount}"
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (hasDepthStencilAttachment)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (graphicsPipeline.SampleCount != depthStencilAttachmentSampleCount)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                throw new System.InvalidOperationException(
 | 
				
			||||||
 | 
					                    $"Sample count mismatch! Graphics pipeline sample count: {graphicsPipeline.SampleCount}, Depth stencil attachment sample count: {depthStencilAttachmentSampleCount}"
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Refresh.Refresh_BindGraphicsPipeline(
 | 
				
			||||||
 | 
					            Handle,
 | 
				
			||||||
 | 
					            graphicsPipeline.Handle
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					        currentGraphicsPipeline = graphicsPipeline;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Sets the viewport.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public void SetViewport(in Viewport viewport)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Refresh.Refresh_SetViewport(
 | 
				
			||||||
 | 
					            Handle,
 | 
				
			||||||
 | 
					            viewport.ToRefresh()
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Sets the scissor area.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public void SetScissor(in Rect scissor)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					        if (scissor.X < 0 || scissor.Y < 0 || scissor.W <= 0 || scissor.H <= 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            throw new System.ArgumentOutOfRangeException("Scissor position cannot be negative and dimensions must be positive!");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Refresh.Refresh_SetScissor(
 | 
				
			||||||
 | 
					            Handle,
 | 
				
			||||||
 | 
					            scissor.ToRefresh()
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Binds vertex buffers to be used by subsequent draw calls.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="bufferBinding">Buffer to bind and associated offset.</param>
 | 
				
			||||||
 | 
					    /// <param name="firstBinding">The index of the first vertex input binding whose state is updated by the command.</param>
 | 
				
			||||||
 | 
					    public unsafe void BindVertexBuffer(
 | 
				
			||||||
 | 
					        in BufferBinding bufferBinding,
 | 
				
			||||||
 | 
					        uint firstBinding = 0
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					        AssertGraphicsPipelineBound();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Refresh.BufferBinding refreshBufferBinding = bufferBinding.ToRefresh();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Refresh.Refresh_BindVertexBuffers(
 | 
				
			||||||
 | 
					            Handle,
 | 
				
			||||||
 | 
					            firstBinding,
 | 
				
			||||||
 | 
					            &refreshBufferBinding,
 | 
				
			||||||
 | 
					            1
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Binds an index buffer to be used by subsequent draw calls.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="indexBuffer">The index buffer to bind.</param>
 | 
				
			||||||
 | 
					    /// <param name="indexElementSize">The size in bytes of the index buffer elements.</param>
 | 
				
			||||||
 | 
					    /// <param name="offset">The offset index for the buffer.</param>
 | 
				
			||||||
 | 
					    public void BindIndexBuffer(
 | 
				
			||||||
 | 
					        BufferBinding bufferBinding,
 | 
				
			||||||
 | 
					        IndexElementSize indexElementSize
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					        AssertGraphicsPipelineBound();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Refresh.Refresh_BindIndexBuffer(
 | 
				
			||||||
 | 
					            Handle,
 | 
				
			||||||
 | 
					            bufferBinding.ToRefresh(),
 | 
				
			||||||
 | 
					            (Refresh.IndexElementSize)indexElementSize
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Binds samplers to be used by the vertex shader.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="textureSamplerBindings">The texture-sampler to bind.</param>
 | 
				
			||||||
 | 
					    public unsafe void BindVertexSampler(
 | 
				
			||||||
 | 
					        in TextureSamplerBinding textureSamplerBinding,
 | 
				
			||||||
 | 
					        uint slot = 0
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					        AssertGraphicsPipelineBound();
 | 
				
			||||||
 | 
					        AssertTextureSamplerBindingNonNull(textureSamplerBinding);
 | 
				
			||||||
 | 
					        AssertTextureHasSamplerFlag(textureSamplerBinding.Texture);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Refresh.TextureSamplerBinding refreshTextureSamplerBinding = textureSamplerBinding.ToRefresh();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Refresh.Refresh_BindVertexSamplers(
 | 
				
			||||||
 | 
					            Handle,
 | 
				
			||||||
 | 
					            slot,
 | 
				
			||||||
 | 
					            &refreshTextureSamplerBinding,
 | 
				
			||||||
 | 
					            1
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public unsafe void BindVertexStorageTexture(
 | 
				
			||||||
 | 
					        in TextureSlice textureSlice,
 | 
				
			||||||
 | 
					        uint slot = 0
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					        AssertGraphicsPipelineBound();
 | 
				
			||||||
 | 
					        AssertTextureNonNull(textureSlice.Texture);
 | 
				
			||||||
 | 
					        AssertTextureHasGraphicsStorageFlag(textureSlice.Texture);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Refresh.TextureSlice refreshTextureSlice = textureSlice.ToRefresh();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Refresh.Refresh_BindVertexStorageTextures(
 | 
				
			||||||
 | 
					            Handle,
 | 
				
			||||||
 | 
					            slot,
 | 
				
			||||||
 | 
					            &refreshTextureSlice,
 | 
				
			||||||
 | 
					            1
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public unsafe void BindVertexStorageBuffer(
 | 
				
			||||||
 | 
					        Buffer buffer,
 | 
				
			||||||
 | 
					        uint slot = 0
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					        AssertGraphicsPipelineBound();
 | 
				
			||||||
 | 
					        AssertBufferNonNull(buffer);
 | 
				
			||||||
 | 
					        AssertBufferHasGraphicsStorageFlag(buffer);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        IntPtr bufferHandle = buffer.Handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Refresh.Refresh_BindVertexStorageBuffers(
 | 
				
			||||||
 | 
					            Handle,
 | 
				
			||||||
 | 
					            slot,
 | 
				
			||||||
 | 
					            &bufferHandle,
 | 
				
			||||||
 | 
					            1
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public unsafe void BindFragmentSampler(
 | 
				
			||||||
 | 
					        in TextureSamplerBinding textureSamplerBinding,
 | 
				
			||||||
 | 
					        uint slot = 0
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					        AssertGraphicsPipelineBound();
 | 
				
			||||||
 | 
					        AssertTextureSamplerBindingNonNull(textureSamplerBinding);
 | 
				
			||||||
 | 
					        AssertTextureHasSamplerFlag(textureSamplerBinding.Texture);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Refresh.TextureSamplerBinding refreshTextureSamplerBinding = textureSamplerBinding.ToRefresh();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Refresh.Refresh_BindFragmentSamplers(
 | 
				
			||||||
 | 
					            Handle,
 | 
				
			||||||
 | 
					            slot,
 | 
				
			||||||
 | 
					            &refreshTextureSamplerBinding,
 | 
				
			||||||
 | 
					            1
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public unsafe void BindFragmentStorageTexture(
 | 
				
			||||||
 | 
					        in TextureSlice textureSlice,
 | 
				
			||||||
 | 
					        uint slot = 0
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					        AssertGraphicsPipelineBound();
 | 
				
			||||||
 | 
					        AssertTextureNonNull(textureSlice.Texture);
 | 
				
			||||||
 | 
					        AssertTextureHasGraphicsStorageFlag(textureSlice.Texture);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Refresh.TextureSlice refreshTextureSlice = textureSlice.ToRefresh();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Refresh.Refresh_BindFragmentStorageTextures(
 | 
				
			||||||
 | 
					            Handle,
 | 
				
			||||||
 | 
					            slot,
 | 
				
			||||||
 | 
					            &refreshTextureSlice,
 | 
				
			||||||
 | 
					            1
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public unsafe void BindFragmentStorageBuffer(
 | 
				
			||||||
 | 
					        Buffer buffer,
 | 
				
			||||||
 | 
					        uint slot = 0
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					        AssertGraphicsPipelineBound();
 | 
				
			||||||
 | 
					        AssertBufferNonNull(buffer);
 | 
				
			||||||
 | 
					        AssertBufferHasGraphicsStorageFlag(buffer);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        IntPtr bufferHandle = buffer.Handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Refresh.Refresh_BindFragmentStorageBuffers(
 | 
				
			||||||
 | 
					            Handle,
 | 
				
			||||||
 | 
					            slot,
 | 
				
			||||||
 | 
					            &bufferHandle,
 | 
				
			||||||
 | 
					            1
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Draws using a vertex buffer and an index buffer, and an optional instance count.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="baseVertex">The starting index offset for the vertex buffer.</param>
 | 
				
			||||||
 | 
					    /// <param name="startIndex">The starting index offset for the index buffer.</param>
 | 
				
			||||||
 | 
					    /// <param name="primitiveCount">The number of primitives to draw.</param>
 | 
				
			||||||
 | 
					    /// <param name="instanceCount">The number of instances to draw.</param>
 | 
				
			||||||
 | 
					    public void DrawIndexedPrimitives(
 | 
				
			||||||
 | 
					        uint baseVertex,
 | 
				
			||||||
 | 
					        uint startIndex,
 | 
				
			||||||
 | 
					        uint primitiveCount,
 | 
				
			||||||
 | 
					        uint instanceCount = 1
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					        AssertGraphicsPipelineBound();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Refresh.Refresh_DrawIndexedPrimitives(
 | 
				
			||||||
 | 
					            Handle,
 | 
				
			||||||
 | 
					            baseVertex,
 | 
				
			||||||
 | 
					            startIndex,
 | 
				
			||||||
 | 
					            primitiveCount,
 | 
				
			||||||
 | 
					            instanceCount
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Draws using a vertex buffer and an index buffer.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="baseVertex">The starting index offset for the vertex buffer.</param>
 | 
				
			||||||
 | 
					    /// <param name="startIndex">The starting index offset for the index buffer.</param>
 | 
				
			||||||
 | 
					    /// <param name="primitiveCount">The number of primitives to draw.</param>
 | 
				
			||||||
 | 
					    public void DrawPrimitives(
 | 
				
			||||||
 | 
					        uint vertexStart,
 | 
				
			||||||
 | 
					        uint primitiveCount
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					        AssertGraphicsPipelineBound();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Refresh.Refresh_DrawPrimitives(
 | 
				
			||||||
 | 
					            Handle,
 | 
				
			||||||
 | 
					            vertexStart,
 | 
				
			||||||
 | 
					            primitiveCount
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Similar to DrawPrimitives, but parameters are set from a buffer.
 | 
				
			||||||
 | 
					    /// The buffer must have the Indirect usage flag set.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="buffer">The draw parameters buffer.</param>
 | 
				
			||||||
 | 
					    /// <param name="offsetInBytes">The offset to start reading from the draw parameters buffer.</param>
 | 
				
			||||||
 | 
					    /// <param name="drawCount">The number of draw parameter sets that should be read from the buffer.</param>
 | 
				
			||||||
 | 
					    /// <param name="stride">The byte stride between sets of draw parameters.</param>
 | 
				
			||||||
 | 
					    public void DrawPrimitivesIndirect(
 | 
				
			||||||
 | 
					        Buffer buffer,
 | 
				
			||||||
 | 
					        uint offsetInBytes,
 | 
				
			||||||
 | 
					        uint drawCount,
 | 
				
			||||||
 | 
					        uint stride
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					        AssertGraphicsPipelineBound();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Refresh.Refresh_DrawPrimitivesIndirect(
 | 
				
			||||||
 | 
					            Handle,
 | 
				
			||||||
 | 
					            buffer.Handle,
 | 
				
			||||||
 | 
					            offsetInBytes,
 | 
				
			||||||
 | 
					            drawCount,
 | 
				
			||||||
 | 
					            stride
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Similar to DrawIndexedPrimitives, but parameters are set from a buffer.
 | 
				
			||||||
 | 
					    /// The buffer must have the Indirect usage flag set.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="buffer">The draw parameters buffer.</param>
 | 
				
			||||||
 | 
					    /// <param name="offsetInBytes">The offset to start reading from the draw parameters buffer.</param>
 | 
				
			||||||
 | 
					    /// <param name="drawCount">The number of draw parameter sets that should be read from the buffer.</param>
 | 
				
			||||||
 | 
					    /// <param name="stride">The byte stride between sets of draw parameters.</param>
 | 
				
			||||||
 | 
					    public void DrawIndexedPrimitivesIndirect(
 | 
				
			||||||
 | 
					        Buffer buffer,
 | 
				
			||||||
 | 
					        uint offsetInBytes,
 | 
				
			||||||
 | 
					        uint drawCount,
 | 
				
			||||||
 | 
					        uint stride
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					        AssertGraphicsPipelineBound();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Refresh.Refresh_DrawIndexedPrimitivesIndirect(
 | 
				
			||||||
 | 
					            Handle,
 | 
				
			||||||
 | 
					            buffer.Handle,
 | 
				
			||||||
 | 
					            offsetInBytes,
 | 
				
			||||||
 | 
					            drawCount,
 | 
				
			||||||
 | 
					            stride
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					    private void AssertRenderPassPipelineFormatMatch(GraphicsPipeline graphicsPipeline)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        for (int i = 0; i < graphicsPipeline.AttachmentInfo.ColorAttachmentDescriptions.Length; i += 1)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            TextureFormat format;
 | 
				
			||||||
 | 
					            if (i == 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                format = colorFormatOne;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (i == 1)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                format = colorFormatTwo;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (i == 2)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                format = colorFormatThree;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                format = colorFormatFour;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            TextureFormat pipelineFormat = graphicsPipeline.AttachmentInfo.ColorAttachmentDescriptions[i].Format;
 | 
				
			||||||
 | 
					            if (pipelineFormat != format)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                throw new System.InvalidOperationException(
 | 
				
			||||||
 | 
					                    $"Color texture format mismatch! Pipeline expects {pipelineFormat}, render pass attachment is {format}"
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (graphicsPipeline.AttachmentInfo.HasDepthStencilAttachment)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            TextureFormat pipelineDepthFormat = graphicsPipeline.AttachmentInfo.DepthStencilFormat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!hasDepthStencilAttachment)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                throw new System.InvalidOperationException("Pipeline expects depth attachment!");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (pipelineDepthFormat != depthStencilFormat)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                throw new System.InvalidOperationException(
 | 
				
			||||||
 | 
					                    $"Depth texture format mismatch! Pipeline expects {pipelineDepthFormat}, render pass attachment is {depthStencilFormat}"
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void AssertGraphicsPipelineBound(string message = "No graphics pipeline is bound!")
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (currentGraphicsPipeline == null)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            throw new System.InvalidOperationException(message);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void AssertTextureNonNull(in TextureSlice textureSlice)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (textureSlice.Texture == null)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            throw new NullReferenceException("Texture must not be null!");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void AssertTextureSamplerBindingNonNull(in TextureSamplerBinding binding)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (binding.Texture == null || binding.Texture.Handle == IntPtr.Zero)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            throw new NullReferenceException("Texture binding must not be null!");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (binding.Sampler == null || binding.Sampler.Handle == IntPtr.Zero)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            throw new NullReferenceException("Sampler binding must not be null!");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void AssertTextureHasSamplerFlag(Texture texture)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ((texture.UsageFlags & TextureUsageFlags.Sampler) == 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            throw new System.ArgumentException("The bound Texture's UsageFlags must include TextureUsageFlags.Sampler!");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void AssertTextureHasGraphicsStorageFlag(Texture texture)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ((texture.UsageFlags & TextureUsageFlags.GraphicsStorage) == 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            throw new System.ArgumentException("The bound Texture's UsageFlags must include TextureUsageFlags.GraphicsStorage!");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void AssertBufferNonNull(Buffer buffer)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (buffer == null || buffer.Handle == IntPtr.Zero)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            throw new System.NullReferenceException("Buffer must not be null!");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void AssertBufferHasGraphicsStorageFlag(Buffer buffer)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ((buffer.UsageFlags & BufferUsageFlags.GraphicsStorage) == 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            throw new System.ArgumentException("The bound Buffer's UsageFlags must include BufferUsageFlag.GraphicsStorage!");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										25
									
								
								Nerfed.Runtime/Graphics/RenderPassPool.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Nerfed.Runtime/Graphics/RenderPassPool.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					using System.Collections.Concurrent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					internal class RenderPassPool
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						private ConcurrentQueue<RenderPass> RenderPasses = new ConcurrentQueue<RenderPass>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public RenderPass Obtain()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (RenderPasses.TryDequeue(out RenderPass renderPass))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return renderPass;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return new RenderPass();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void Return(RenderPass renderPass)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							RenderPasses.Enqueue(renderPass);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										376
									
								
								Nerfed.Runtime/Graphics/ResourceUploader.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										376
									
								
								Nerfed.Runtime/Graphics/ResourceUploader.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,376 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FIXME: can we map the transfer buffer instead of maintaining a local pointer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// A convenience structure for creating resources and uploading data to them.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Note that Upload or UploadAndWait must be called after the Create methods for the data to actually be uploaded.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Note that this structure does not magically keep memory usage down -
 | 
				
			||||||
 | 
					/// you may want to stagger uploads over multiple submissions to minimize memory usage.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public unsafe class ResourceUploader : GraphicsResource
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						TransferBuffer BufferTransferBuffer;
 | 
				
			||||||
 | 
						TransferBuffer TextureTransferBuffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						byte* bufferData;
 | 
				
			||||||
 | 
						uint bufferDataOffset = 0;
 | 
				
			||||||
 | 
						uint bufferDataSize = 1024;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						byte* textureData;
 | 
				
			||||||
 | 
						uint textureDataOffset = 0;
 | 
				
			||||||
 | 
						uint textureDataSize = 1024;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						List<(uint, BufferRegion, bool)> BufferUploads = new List<(uint, BufferRegion, bool)>();
 | 
				
			||||||
 | 
						List<(uint, TextureRegion, bool)> TextureUploads = new List<(uint, TextureRegion, bool)>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public ResourceUploader(GraphicsDevice device) : base(device)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							bufferData = (byte*) NativeMemory.Alloc(bufferDataSize);
 | 
				
			||||||
 | 
							textureData = (byte*) NativeMemory.Alloc(textureDataSize);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Buffers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a Buffer with data to be uploaded.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public Buffer CreateBuffer<T>(Span<T> data, BufferUsageFlags usageFlags) where T : unmanaged
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							uint lengthInBytes = (uint) (Marshal.SizeOf<T>() * data.Length);
 | 
				
			||||||
 | 
							Buffer buffer = new Buffer(Device, usageFlags, lengthInBytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							SetBufferData(buffer, 0, data, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return buffer;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Prepares upload of data into a Buffer.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public void SetBufferData<T>(Buffer buffer, uint bufferOffsetInElements, Span<T> data, bool cycle) where T : unmanaged
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							uint elementSize = (uint) Marshal.SizeOf<T>();
 | 
				
			||||||
 | 
							uint offsetInBytes = elementSize * bufferOffsetInElements;
 | 
				
			||||||
 | 
							uint lengthInBytes = (uint) (elementSize * data.Length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							uint resourceOffset;
 | 
				
			||||||
 | 
							fixed (void* spanPtr = data)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								resourceOffset = CopyBufferData(spanPtr, lengthInBytes);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							BufferRegion bufferRegion = new BufferRegion(buffer, offsetInBytes, lengthInBytes);
 | 
				
			||||||
 | 
							BufferUploads.Add((resourceOffset, bufferRegion, cycle));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Textures
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Texture CreateTexture2D<T>(Span<T> pixelData, uint width, uint height) where T : unmanaged
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Texture texture = Texture.CreateTexture2D(Device, width, height, TextureFormat.R8G8B8A8, TextureUsageFlags.Sampler);
 | 
				
			||||||
 | 
							SetTextureData(texture, pixelData, false);
 | 
				
			||||||
 | 
							return texture;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a 2D Texture from compressed image data to be uploaded.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public Texture CreateTexture2DFromCompressed(Span<byte> compressedImageData)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							ImageUtils.ImageInfoFromBytes(compressedImageData, out uint width, out uint height, out uint _);
 | 
				
			||||||
 | 
							Texture texture = Texture.CreateTexture2D(Device, width, height, TextureFormat.R8G8B8A8, TextureUsageFlags.Sampler);
 | 
				
			||||||
 | 
							SetTextureDataFromCompressed(texture, compressedImageData);
 | 
				
			||||||
 | 
							return texture;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a 2D Texture from a compressed image stream to be uploaded.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public Texture CreateTexture2DFromCompressed(Stream compressedImageStream)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							long length = compressedImageStream.Length;
 | 
				
			||||||
 | 
							void* buffer = NativeMemory.Alloc((nuint) length);
 | 
				
			||||||
 | 
							Span<byte> span = new Span<byte>(buffer, (int) length);
 | 
				
			||||||
 | 
							compressedImageStream.ReadExactly(span);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Texture texture = CreateTexture2DFromCompressed(span);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							NativeMemory.Free(buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return texture;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a 2D Texture from a compressed image file to be uploaded.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public Texture CreateTexture2DFromCompressed(string compressedImageFilePath)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							FileStream fileStream = new FileStream(compressedImageFilePath, FileMode.Open, FileAccess.Read);
 | 
				
			||||||
 | 
							return CreateTexture2DFromCompressed(fileStream);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a texture from a DDS stream.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public Texture CreateTextureFromDDS(Stream stream)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							using BinaryReader reader = new BinaryReader(stream);
 | 
				
			||||||
 | 
							Texture texture;
 | 
				
			||||||
 | 
							int faces;
 | 
				
			||||||
 | 
							ImageUtils.ParseDDS(reader, out TextureFormat format, out int width, out int height, out int levels, out bool isCube);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (isCube)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								texture = Texture.CreateTextureCube(Device, (uint) width, format, TextureUsageFlags.Sampler, (uint) levels);
 | 
				
			||||||
 | 
								faces = 6;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								texture = Texture.CreateTexture2D(Device, (uint) width, (uint) height, format, TextureUsageFlags.Sampler, (uint) levels);
 | 
				
			||||||
 | 
								faces = 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (int face = 0; face < faces; face += 1)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								for (int level = 0; level < levels; level += 1)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									int levelWidth = width >> level;
 | 
				
			||||||
 | 
									int levelHeight = height >> level;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									int levelSize = ImageUtils.CalculateDDSLevelSize(levelWidth, levelHeight, format);
 | 
				
			||||||
 | 
									void* byteBuffer = NativeMemory.Alloc((nuint) levelSize);
 | 
				
			||||||
 | 
									Span<byte> byteSpan = new Span<byte>(byteBuffer, levelSize);
 | 
				
			||||||
 | 
									stream.ReadExactly(byteSpan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									TextureRegion textureRegion = new TextureRegion
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										TextureSlice = new TextureSlice
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Texture = texture,
 | 
				
			||||||
 | 
											Layer = (uint) face,
 | 
				
			||||||
 | 
											MipLevel = (uint) level
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										X = 0,
 | 
				
			||||||
 | 
										Y = 0,
 | 
				
			||||||
 | 
										Z = 0,
 | 
				
			||||||
 | 
										Width = (uint) levelWidth,
 | 
				
			||||||
 | 
										Height = (uint) levelHeight,
 | 
				
			||||||
 | 
										Depth = 1
 | 
				
			||||||
 | 
									};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									SetTextureData(textureRegion, byteSpan, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									NativeMemory.Free(byteBuffer);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return texture;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a texture from a DDS file.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public Texture CreateTextureFromDDS(string path)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read);
 | 
				
			||||||
 | 
							return CreateTextureFromDDS(stream);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void SetTextureDataFromCompressed(TextureRegion textureRegion, Span<byte> compressedImageData)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							byte* pixelData = ImageUtils.GetPixelDataFromBytes(compressedImageData, out uint _, out uint _, out uint sizeInBytes);
 | 
				
			||||||
 | 
							Span<byte> pixelSpan = new Span<byte>((void*) pixelData, (int) sizeInBytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							SetTextureData(textureRegion, pixelSpan, false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ImageUtils.FreePixelData(pixelData);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void SetTextureDataFromCompressed(TextureRegion textureRegion, Stream compressedImageStream)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							long length = compressedImageStream.Length;
 | 
				
			||||||
 | 
							void* buffer = NativeMemory.Alloc((nuint) length);
 | 
				
			||||||
 | 
							Span<byte> span = new Span<byte>(buffer, (int) length);
 | 
				
			||||||
 | 
							compressedImageStream.ReadExactly(span);
 | 
				
			||||||
 | 
							SetTextureDataFromCompressed(textureRegion, span);
 | 
				
			||||||
 | 
							NativeMemory.Free(buffer);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void SetTextureDataFromCompressed(TextureRegion textureRegion, string compressedImageFilePath)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							FileStream fileStream = new FileStream(compressedImageFilePath, FileMode.Open, FileAccess.Read);
 | 
				
			||||||
 | 
							SetTextureDataFromCompressed(textureRegion, fileStream);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Prepares upload of pixel data into a TextureSlice.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public void SetTextureData<T>(TextureRegion textureRegion, Span<T> data, bool cycle) where T : unmanaged
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							int elementSize = Marshal.SizeOf<T>();
 | 
				
			||||||
 | 
							uint dataLengthInBytes = (uint) (elementSize * data.Length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							uint resourceOffset;
 | 
				
			||||||
 | 
							fixed (T* dataPtr = data)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								resourceOffset = CopyTextureData(dataPtr, dataLengthInBytes, Texture.BytesPerPixel(textureRegion.TextureSlice.Texture.Format));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							TextureUploads.Add((resourceOffset, textureRegion, cycle));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Upload
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Uploads all the data corresponding to the created resources.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public void Upload()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							CopyToTransferBuffer();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							CommandBuffer commandBuffer = Device.AcquireCommandBuffer();
 | 
				
			||||||
 | 
							RecordUploadCommands(commandBuffer);
 | 
				
			||||||
 | 
							Device.Submit(commandBuffer);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Uploads and then blocks until the upload is finished.
 | 
				
			||||||
 | 
						/// This is useful for keeping memory usage down during threaded upload.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public void UploadAndWait()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							CopyToTransferBuffer();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							CommandBuffer commandBuffer = Device.AcquireCommandBuffer();
 | 
				
			||||||
 | 
							RecordUploadCommands(commandBuffer);
 | 
				
			||||||
 | 
							Fence fence = Device.SubmitAndAcquireFence(commandBuffer);
 | 
				
			||||||
 | 
							Device.WaitForFence(fence);
 | 
				
			||||||
 | 
							Device.ReleaseFence(fence);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Helper methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void CopyToTransferBuffer()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (BufferUploads.Count > 0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (BufferTransferBuffer == null || BufferTransferBuffer.Size < bufferDataSize)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									BufferTransferBuffer?.Dispose();
 | 
				
			||||||
 | 
									BufferTransferBuffer = new TransferBuffer(Device, TransferBufferUsage.Upload, bufferDataSize);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Span<byte> dataSpan = new Span<byte>(bufferData, (int) bufferDataSize);
 | 
				
			||||||
 | 
								BufferTransferBuffer.SetData(dataSpan, true);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (TextureUploads.Count > 0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (TextureTransferBuffer == null || TextureTransferBuffer.Size < textureDataSize)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									TextureTransferBuffer?.Dispose();
 | 
				
			||||||
 | 
									TextureTransferBuffer = new TransferBuffer(Device, TransferBufferUsage.Upload, textureDataSize);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Span<byte> dataSpan = new Span<byte>(textureData, (int) textureDataSize);
 | 
				
			||||||
 | 
								TextureTransferBuffer.SetData(dataSpan, true);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void RecordUploadCommands(CommandBuffer commandBuffer)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							CopyPass copyPass = commandBuffer.BeginCopyPass();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							foreach ((uint transferOffset, BufferRegion bufferRegion, bool option) in BufferUploads)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								copyPass.UploadToBuffer(
 | 
				
			||||||
 | 
									new TransferBufferLocation(BufferTransferBuffer, transferOffset),
 | 
				
			||||||
 | 
									bufferRegion,
 | 
				
			||||||
 | 
									option
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							foreach ((uint transferOffset, TextureRegion textureRegion, bool option) in TextureUploads)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								copyPass.UploadToTexture(
 | 
				
			||||||
 | 
									new TextureTransferInfo(TextureTransferBuffer, transferOffset),
 | 
				
			||||||
 | 
									textureRegion,
 | 
				
			||||||
 | 
									option
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							commandBuffer.EndCopyPass(copyPass);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							BufferUploads.Clear();
 | 
				
			||||||
 | 
							TextureUploads.Clear();
 | 
				
			||||||
 | 
							bufferDataOffset = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private uint CopyBufferData(void* ptr, uint lengthInBytes)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (bufferDataOffset + lengthInBytes >= bufferDataSize)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								bufferDataSize = bufferDataOffset + lengthInBytes;
 | 
				
			||||||
 | 
								bufferData = (byte*) NativeMemory.Realloc(bufferData, bufferDataSize);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							uint resourceOffset = bufferDataOffset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							NativeMemory.Copy(ptr, bufferData + bufferDataOffset, lengthInBytes);
 | 
				
			||||||
 | 
							bufferDataOffset += lengthInBytes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return resourceOffset;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private uint CopyTextureData(void* ptr, uint lengthInBytes, uint alignment)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							textureDataOffset = RoundToAlignment(textureDataOffset, alignment);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (textureDataOffset + lengthInBytes >= textureDataSize)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								textureDataSize = textureDataOffset + lengthInBytes;
 | 
				
			||||||
 | 
								textureData = (byte*) NativeMemory.Realloc(textureData, textureDataSize);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							uint resourceOffset = textureDataOffset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							NativeMemory.Copy(ptr, textureData + textureDataOffset, lengthInBytes);
 | 
				
			||||||
 | 
							textureDataOffset += lengthInBytes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return resourceOffset;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private uint RoundToAlignment(uint value, uint alignment)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return alignment * ((value + alignment - 1) / alignment);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Dispose
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// It is valid to immediately call Dispose after calling Upload.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						protected override void Dispose(bool disposing)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (!IsDisposed)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (disposing)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									BufferTransferBuffer?.Dispose();
 | 
				
			||||||
 | 
									TextureTransferBuffer?.Dispose();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								NativeMemory.Free(bufferData);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							base.Dispose(disposing);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										88
									
								
								Nerfed.Runtime/Graphics/Resources/Buffer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								Nerfed.Runtime/Graphics/Resources/Buffer.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,88 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					using RefreshCS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// A data container that can be efficiently used by the GPU.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class Buffer : RefreshResource
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						protected override Action<IntPtr, IntPtr> ReleaseFunction => Refresh.Refresh_ReleaseBuffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public BufferUsageFlags UsageFlags { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Size in bytes.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public uint Size { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private string name;
 | 
				
			||||||
 | 
						public string Name
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get => name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (Device.DebugMode)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									Refresh.Refresh_SetBufferName(
 | 
				
			||||||
 | 
										Device.Handle,
 | 
				
			||||||
 | 
										Handle,
 | 
				
			||||||
 | 
										value
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								name = value;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a buffer of appropriate size given a type and element count.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <typeparam name="T">The type that the buffer will contain.</typeparam>
 | 
				
			||||||
 | 
						/// <param name="device">The GraphicsDevice.</param>
 | 
				
			||||||
 | 
						/// <param name="usageFlags">Specifies how the buffer will be used.</param>
 | 
				
			||||||
 | 
						/// <param name="elementCount">How many elements of type T the buffer will contain.</param>
 | 
				
			||||||
 | 
						/// <returns></returns>
 | 
				
			||||||
 | 
						public unsafe static Buffer Create<T>(
 | 
				
			||||||
 | 
							GraphicsDevice device,
 | 
				
			||||||
 | 
							BufferUsageFlags usageFlags,
 | 
				
			||||||
 | 
							uint elementCount
 | 
				
			||||||
 | 
						) where T : unmanaged
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new Buffer(
 | 
				
			||||||
 | 
								device,
 | 
				
			||||||
 | 
								usageFlags,
 | 
				
			||||||
 | 
								(uint) Marshal.SizeOf<T>() * elementCount
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a buffer.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="device">An initialized GraphicsDevice.</param>
 | 
				
			||||||
 | 
						/// <param name="usageFlags">Specifies how the buffer will be used.</param>
 | 
				
			||||||
 | 
						/// <param name="sizeInBytes">The length of the array. Cannot be resized.</param>
 | 
				
			||||||
 | 
						public Buffer(
 | 
				
			||||||
 | 
							GraphicsDevice device,
 | 
				
			||||||
 | 
							BufferUsageFlags usageFlags,
 | 
				
			||||||
 | 
							uint sizeInBytes
 | 
				
			||||||
 | 
						) : base(device)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Handle = Refresh.Refresh_CreateBuffer(
 | 
				
			||||||
 | 
								device.Handle,
 | 
				
			||||||
 | 
								(Refresh.BufferUsageFlags) usageFlags,
 | 
				
			||||||
 | 
								sizeInBytes
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							UsageFlags = usageFlags;
 | 
				
			||||||
 | 
							Size = sizeInBytes;
 | 
				
			||||||
 | 
							name = "";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static implicit operator BufferBinding(Buffer b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new BufferBinding(b, 0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										91
									
								
								Nerfed.Runtime/Graphics/Resources/ComputePipeline.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								Nerfed.Runtime/Graphics/Resources/ComputePipeline.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,91 @@
 | 
				
			|||||||
 | 
					using RefreshCS;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Compute pipelines perform arbitrary parallel processing on input data.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class ComputePipeline : RefreshResource
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						protected override Action<IntPtr, IntPtr> ReleaseFunction => Refresh.Refresh_ReleaseComputePipeline;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public uint ReadOnlyStorageTextureCount { get; }
 | 
				
			||||||
 | 
						public uint ReadOnlyStorageBufferCount { get; }
 | 
				
			||||||
 | 
						public uint ReadWriteStorageTextureCount { get; }
 | 
				
			||||||
 | 
						public uint ReadWriteStorageBufferCount { get; }
 | 
				
			||||||
 | 
						public uint UniformBufferCount { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public ComputePipeline(
 | 
				
			||||||
 | 
							GraphicsDevice device,
 | 
				
			||||||
 | 
							string filePath,
 | 
				
			||||||
 | 
							string entryPointName,
 | 
				
			||||||
 | 
							in ComputePipelineCreateInfo computePipelineCreateInfo
 | 
				
			||||||
 | 
						) : base(device)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							using FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
 | 
				
			||||||
 | 
							Handle = CreateFromStream(device, stream, entryPointName, computePipelineCreateInfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ReadOnlyStorageTextureCount = computePipelineCreateInfo.ReadOnlyStorageTextureCount;
 | 
				
			||||||
 | 
							ReadOnlyStorageBufferCount = computePipelineCreateInfo.ReadOnlyStorageBufferCount;
 | 
				
			||||||
 | 
							ReadWriteStorageTextureCount = computePipelineCreateInfo.ReadWriteStorageTextureCount;
 | 
				
			||||||
 | 
							ReadWriteStorageBufferCount = computePipelineCreateInfo.ReadWriteStorageBufferCount;
 | 
				
			||||||
 | 
							UniformBufferCount = computePipelineCreateInfo.UniformBufferCount;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public ComputePipeline(
 | 
				
			||||||
 | 
							GraphicsDevice device,
 | 
				
			||||||
 | 
							Stream stream,
 | 
				
			||||||
 | 
							string entryPointName,
 | 
				
			||||||
 | 
							in ComputePipelineCreateInfo computePipelineCreateInfo
 | 
				
			||||||
 | 
						) : base(device)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Handle = CreateFromStream(device, stream, entryPointName, computePipelineCreateInfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ReadOnlyStorageTextureCount = computePipelineCreateInfo.ReadOnlyStorageTextureCount;
 | 
				
			||||||
 | 
							ReadOnlyStorageBufferCount = computePipelineCreateInfo.ReadOnlyStorageBufferCount;
 | 
				
			||||||
 | 
							ReadWriteStorageTextureCount = computePipelineCreateInfo.ReadWriteStorageTextureCount;
 | 
				
			||||||
 | 
							ReadWriteStorageBufferCount = computePipelineCreateInfo.ReadWriteStorageBufferCount;
 | 
				
			||||||
 | 
							UniformBufferCount = computePipelineCreateInfo.UniformBufferCount;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static unsafe nint CreateFromStream(
 | 
				
			||||||
 | 
							GraphicsDevice device,
 | 
				
			||||||
 | 
							Stream stream,
 | 
				
			||||||
 | 
							string entryPointName,
 | 
				
			||||||
 | 
							in ComputePipelineCreateInfo computePipelineCreateInfo
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							byte* bytecodeBuffer = (byte*) NativeMemory.Alloc((nuint) stream.Length);
 | 
				
			||||||
 | 
							Span<byte> bytecodeSpan = new Span<byte>(bytecodeBuffer, (int) stream.Length);
 | 
				
			||||||
 | 
							stream.ReadExactly(bytecodeSpan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Refresh.ComputePipelineCreateInfo refreshPipelineCreateInfo;
 | 
				
			||||||
 | 
							refreshPipelineCreateInfo.Code = bytecodeBuffer;
 | 
				
			||||||
 | 
							refreshPipelineCreateInfo.CodeSize = (nuint) stream.Length;
 | 
				
			||||||
 | 
							refreshPipelineCreateInfo.EntryPointName = entryPointName;
 | 
				
			||||||
 | 
							refreshPipelineCreateInfo.Format = (Refresh.ShaderFormat) computePipelineCreateInfo.ShaderFormat;
 | 
				
			||||||
 | 
							refreshPipelineCreateInfo.ReadOnlyStorageTextureCount = computePipelineCreateInfo.ReadOnlyStorageTextureCount;
 | 
				
			||||||
 | 
							refreshPipelineCreateInfo.ReadOnlyStorageBufferCount = computePipelineCreateInfo.ReadOnlyStorageBufferCount;
 | 
				
			||||||
 | 
							refreshPipelineCreateInfo.ReadWriteStorageTextureCount = computePipelineCreateInfo.ReadWriteStorageTextureCount;
 | 
				
			||||||
 | 
							refreshPipelineCreateInfo.ReadWriteStorageBufferCount = computePipelineCreateInfo.ReadWriteStorageBufferCount;
 | 
				
			||||||
 | 
							refreshPipelineCreateInfo.UniformBufferCount = computePipelineCreateInfo.UniformBufferCount;
 | 
				
			||||||
 | 
							refreshPipelineCreateInfo.ThreadCountX = computePipelineCreateInfo.ThreadCountX;
 | 
				
			||||||
 | 
							refreshPipelineCreateInfo.ThreadCountY = computePipelineCreateInfo.ThreadCountY;
 | 
				
			||||||
 | 
							refreshPipelineCreateInfo.ThreadCountZ = computePipelineCreateInfo.ThreadCountZ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							IntPtr computePipelineHandle = Refresh.Refresh_CreateComputePipeline(
 | 
				
			||||||
 | 
								device.Handle,
 | 
				
			||||||
 | 
								refreshPipelineCreateInfo
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (computePipelineHandle == nint.Zero)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new Exception("Could not create compute pipeline!");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							NativeMemory.Free(bytecodeBuffer);
 | 
				
			||||||
 | 
							return computePipelineHandle;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										25
									
								
								Nerfed.Runtime/Graphics/Resources/Fence.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Nerfed.Runtime/Graphics/Resources/Fence.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using RefreshCS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Fences allow you to track the status of a submitted command buffer. <br/>
 | 
				
			||||||
 | 
					/// You should only acquire a Fence if you will need to track the command buffer. <br/>
 | 
				
			||||||
 | 
					/// You should make sure to call GraphicsDevice.ReleaseFence when done with a Fence to avoid memory growth. <br/>
 | 
				
			||||||
 | 
					/// The Fence object itself is basically just a wrapper for the Refresh_Fence. <br/>
 | 
				
			||||||
 | 
					/// The internal handle is replaced so that we can pool Fence objects to manage garbage.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class Fence : RefreshResource
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						protected override Action<nint, nint> ReleaseFunction => Refresh.Refresh_ReleaseFence;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						internal Fence(GraphicsDevice device) : base(device)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						internal void SetHandle(nint handle)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Handle = handle;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										99
									
								
								Nerfed.Runtime/Graphics/Resources/GraphicsPipeline.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								Nerfed.Runtime/Graphics/Resources/GraphicsPipeline.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,99 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					using RefreshCS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Graphics pipelines encapsulate all of the render state in a single object. <br/>
 | 
				
			||||||
 | 
					/// These pipelines are bound before draw calls are issued.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class GraphicsPipeline : RefreshResource
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						protected override Action<IntPtr, IntPtr> ReleaseFunction => Refresh.Refresh_ReleaseGraphicsPipeline;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Shader VertexShader;
 | 
				
			||||||
 | 
						public Shader FragmentShader;
 | 
				
			||||||
 | 
						public SampleCount SampleCount { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
						internal GraphicsPipelineAttachmentInfo AttachmentInfo { get; }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public unsafe GraphicsPipeline(
 | 
				
			||||||
 | 
							GraphicsDevice device,
 | 
				
			||||||
 | 
							in GraphicsPipelineCreateInfo graphicsPipelineCreateInfo
 | 
				
			||||||
 | 
						) : base(device)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Refresh.GraphicsPipelineCreateInfo refreshGraphicsPipelineCreateInfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Refresh.VertexAttribute* vertexAttributes = (Refresh.VertexAttribute*) NativeMemory.Alloc(
 | 
				
			||||||
 | 
								(nuint) (graphicsPipelineCreateInfo.VertexInputState.VertexAttributes.Length * Marshal.SizeOf<Refresh.VertexAttribute>())
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (int i = 0; i < graphicsPipelineCreateInfo.VertexInputState.VertexAttributes.Length; i += 1)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								vertexAttributes[i] = graphicsPipelineCreateInfo.VertexInputState.VertexAttributes[i].ToRefresh();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Refresh.VertexBinding* vertexBindings = (Refresh.VertexBinding*) NativeMemory.Alloc(
 | 
				
			||||||
 | 
								(nuint) (graphicsPipelineCreateInfo.VertexInputState.VertexBindings.Length * Marshal.SizeOf<Refresh.VertexBinding>())
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (int i = 0; i < graphicsPipelineCreateInfo.VertexInputState.VertexBindings.Length; i += 1)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								vertexBindings[i] = graphicsPipelineCreateInfo.VertexInputState.VertexBindings[i].ToRefresh();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Refresh.ColorAttachmentDescription* colorAttachmentDescriptions = stackalloc Refresh.ColorAttachmentDescription[
 | 
				
			||||||
 | 
								graphicsPipelineCreateInfo.AttachmentInfo.ColorAttachmentDescriptions.Length
 | 
				
			||||||
 | 
							];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (int i = 0; i < graphicsPipelineCreateInfo.AttachmentInfo.ColorAttachmentDescriptions.Length; i += 1)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								colorAttachmentDescriptions[i].Format = (Refresh.TextureFormat) graphicsPipelineCreateInfo.AttachmentInfo.ColorAttachmentDescriptions[i].Format;
 | 
				
			||||||
 | 
								colorAttachmentDescriptions[i].BlendState = graphicsPipelineCreateInfo.AttachmentInfo.ColorAttachmentDescriptions[i].BlendState.ToRefresh();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							refreshGraphicsPipelineCreateInfo.VertexShader = graphicsPipelineCreateInfo.VertexShader.Handle;
 | 
				
			||||||
 | 
							refreshGraphicsPipelineCreateInfo.FragmentShader = graphicsPipelineCreateInfo.FragmentShader.Handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							refreshGraphicsPipelineCreateInfo.VertexInputState.VertexAttributes = vertexAttributes;
 | 
				
			||||||
 | 
							refreshGraphicsPipelineCreateInfo.VertexInputState.VertexAttributeCount = (uint) graphicsPipelineCreateInfo.VertexInputState.VertexAttributes.Length;
 | 
				
			||||||
 | 
							refreshGraphicsPipelineCreateInfo.VertexInputState.VertexBindings = vertexBindings;
 | 
				
			||||||
 | 
							refreshGraphicsPipelineCreateInfo.VertexInputState.VertexBindingCount = (uint) graphicsPipelineCreateInfo.VertexInputState.VertexBindings.Length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							refreshGraphicsPipelineCreateInfo.PrimitiveType = (Refresh.PrimitiveType) graphicsPipelineCreateInfo.PrimitiveType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							refreshGraphicsPipelineCreateInfo.RasterizerState = graphicsPipelineCreateInfo.RasterizerState.ToRefresh();
 | 
				
			||||||
 | 
							refreshGraphicsPipelineCreateInfo.MultisampleState = graphicsPipelineCreateInfo.MultisampleState.ToRefresh();
 | 
				
			||||||
 | 
							refreshGraphicsPipelineCreateInfo.DepthStencilState = graphicsPipelineCreateInfo.DepthStencilState.ToRefresh();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							refreshGraphicsPipelineCreateInfo.AttachmentInfo.ColorAttachmentCount = (uint) graphicsPipelineCreateInfo.AttachmentInfo.ColorAttachmentDescriptions.Length;
 | 
				
			||||||
 | 
							refreshGraphicsPipelineCreateInfo.AttachmentInfo.ColorAttachmentDescriptions = colorAttachmentDescriptions;
 | 
				
			||||||
 | 
							refreshGraphicsPipelineCreateInfo.AttachmentInfo.DepthStencilFormat = (Refresh.TextureFormat) graphicsPipelineCreateInfo.AttachmentInfo.DepthStencilFormat;
 | 
				
			||||||
 | 
							refreshGraphicsPipelineCreateInfo.AttachmentInfo.HasDepthStencilAttachment = Conversions.BoolToInt(graphicsPipelineCreateInfo.AttachmentInfo.HasDepthStencilAttachment);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							refreshGraphicsPipelineCreateInfo.BlendConstants[0] = graphicsPipelineCreateInfo.BlendConstants.R;
 | 
				
			||||||
 | 
							refreshGraphicsPipelineCreateInfo.BlendConstants[1] = graphicsPipelineCreateInfo.BlendConstants.G;
 | 
				
			||||||
 | 
							refreshGraphicsPipelineCreateInfo.BlendConstants[2] = graphicsPipelineCreateInfo.BlendConstants.B;
 | 
				
			||||||
 | 
							refreshGraphicsPipelineCreateInfo.BlendConstants[3] = graphicsPipelineCreateInfo.BlendConstants.A;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Handle = Refresh.Refresh_CreateGraphicsPipeline(device.Handle, refreshGraphicsPipelineCreateInfo);
 | 
				
			||||||
 | 
							if (Handle == IntPtr.Zero)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new Exception("Could not create graphics pipeline!");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							NativeMemory.Free(vertexAttributes);
 | 
				
			||||||
 | 
							NativeMemory.Free(vertexBindings);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							VertexShader = graphicsPipelineCreateInfo.VertexShader;
 | 
				
			||||||
 | 
							FragmentShader = graphicsPipelineCreateInfo.FragmentShader;
 | 
				
			||||||
 | 
							SampleCount = graphicsPipelineCreateInfo.MultisampleState.MultisampleCount;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
							AttachmentInfo = graphicsPipelineCreateInfo.AttachmentInfo;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										23
									
								
								Nerfed.Runtime/Graphics/Resources/Sampler.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								Nerfed.Runtime/Graphics/Resources/Sampler.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using RefreshCS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Specifies how a texture will be sampled in a shader.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class Sampler : RefreshResource
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						protected override Action<IntPtr, IntPtr> ReleaseFunction => Refresh.Refresh_ReleaseSampler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Sampler(
 | 
				
			||||||
 | 
							GraphicsDevice device,
 | 
				
			||||||
 | 
							in SamplerCreateInfo samplerCreateInfo
 | 
				
			||||||
 | 
						) : base(device)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Handle = Refresh.Refresh_CreateSampler(
 | 
				
			||||||
 | 
								device.Handle,
 | 
				
			||||||
 | 
								samplerCreateInfo.ToRefresh()
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										91
									
								
								Nerfed.Runtime/Graphics/Resources/Shader.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								Nerfed.Runtime/Graphics/Resources/Shader.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,91 @@
 | 
				
			|||||||
 | 
					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;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										326
									
								
								Nerfed.Runtime/Graphics/Resources/Texture.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										326
									
								
								Nerfed.Runtime/Graphics/Resources/Texture.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,326 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using RefreshCS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// A multi-dimensional data container that can be efficiently used by the GPU.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class Texture : RefreshResource
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public uint Width { get; internal set; }
 | 
				
			||||||
 | 
						public uint Height { get; internal set; }
 | 
				
			||||||
 | 
						public uint Depth { get; }
 | 
				
			||||||
 | 
						public TextureFormat Format { get; internal set; }
 | 
				
			||||||
 | 
						public bool IsCube { get; }
 | 
				
			||||||
 | 
						public uint LayerCount { get; }
 | 
				
			||||||
 | 
						public uint LevelCount { get; }
 | 
				
			||||||
 | 
						public SampleCount SampleCount { get; }
 | 
				
			||||||
 | 
						public TextureUsageFlags UsageFlags { get; }
 | 
				
			||||||
 | 
						public uint Size { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private string name;
 | 
				
			||||||
 | 
						public string Name
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							get => name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							set
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (Device.DebugMode)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									Refresh.Refresh_SetTextureName(
 | 
				
			||||||
 | 
										Device.Handle,
 | 
				
			||||||
 | 
										Handle,
 | 
				
			||||||
 | 
										value
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								name = value;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// FIXME: this allocates a delegate instance
 | 
				
			||||||
 | 
						protected override Action<IntPtr, IntPtr> ReleaseFunction => Refresh.Refresh_ReleaseTexture;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a 2D texture.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="device">An initialized GraphicsDevice.</param>
 | 
				
			||||||
 | 
						/// <param name="width">The width of the texture.</param>
 | 
				
			||||||
 | 
						/// <param name="height">The height of the texture.</param>
 | 
				
			||||||
 | 
						/// <param name="format">The format of the texture.</param>
 | 
				
			||||||
 | 
						/// <param name="usageFlags">Specifies how the texture will be used.</param>
 | 
				
			||||||
 | 
						/// <param name="levelCount">Specifies the number of mip levels.</param>
 | 
				
			||||||
 | 
						public static Texture CreateTexture2D(
 | 
				
			||||||
 | 
							GraphicsDevice device,
 | 
				
			||||||
 | 
							uint width,
 | 
				
			||||||
 | 
							uint height,
 | 
				
			||||||
 | 
							TextureFormat format,
 | 
				
			||||||
 | 
							TextureUsageFlags usageFlags,
 | 
				
			||||||
 | 
							uint levelCount = 1,
 | 
				
			||||||
 | 
							SampleCount sampleCount = SampleCount.One
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							TextureCreateInfo textureCreateInfo = new TextureCreateInfo
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Width = width,
 | 
				
			||||||
 | 
								Height = height,
 | 
				
			||||||
 | 
								Depth = 1,
 | 
				
			||||||
 | 
								IsCube = false,
 | 
				
			||||||
 | 
								LayerCount = 1,
 | 
				
			||||||
 | 
								LevelCount = levelCount,
 | 
				
			||||||
 | 
								SampleCount = sampleCount,
 | 
				
			||||||
 | 
								Format = format,
 | 
				
			||||||
 | 
								UsageFlags = usageFlags
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return new Texture(device, textureCreateInfo);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a 2D texture array.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="device">An initialized GraphicsDevice.</param>
 | 
				
			||||||
 | 
						/// <param name="width">The width of the texture.</param>
 | 
				
			||||||
 | 
						/// <param name="height">The height of the texture.</param>
 | 
				
			||||||
 | 
						/// <param name="layerCount">The layer count of the texture.</param>
 | 
				
			||||||
 | 
						/// <param name="format">The format of the texture.</param>
 | 
				
			||||||
 | 
						/// <param name="usageFlags">Specifies how the texture will be used.</param>
 | 
				
			||||||
 | 
						/// <param name="levelCount">Specifies the number of mip levels.</param>
 | 
				
			||||||
 | 
						public static Texture CreateTexture2DArray(
 | 
				
			||||||
 | 
							GraphicsDevice device,
 | 
				
			||||||
 | 
							uint width,
 | 
				
			||||||
 | 
							uint height,
 | 
				
			||||||
 | 
							uint layerCount,
 | 
				
			||||||
 | 
							TextureFormat format,
 | 
				
			||||||
 | 
							TextureUsageFlags usageFlags,
 | 
				
			||||||
 | 
							uint levelCount = 1
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							TextureCreateInfo textureCreateInfo = new TextureCreateInfo
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Width = width,
 | 
				
			||||||
 | 
								Height = height,
 | 
				
			||||||
 | 
								Depth = 1,
 | 
				
			||||||
 | 
								IsCube = false,
 | 
				
			||||||
 | 
								LayerCount = layerCount,
 | 
				
			||||||
 | 
								LevelCount = levelCount,
 | 
				
			||||||
 | 
								Format = format,
 | 
				
			||||||
 | 
								UsageFlags = usageFlags
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return new Texture(device, textureCreateInfo);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a 3D texture.
 | 
				
			||||||
 | 
						/// Note that the width, height and depth all form one slice and cannot be subdivided in a texture slice.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public static Texture CreateTexture3D(
 | 
				
			||||||
 | 
							GraphicsDevice device,
 | 
				
			||||||
 | 
							uint width,
 | 
				
			||||||
 | 
							uint height,
 | 
				
			||||||
 | 
							uint depth,
 | 
				
			||||||
 | 
							TextureFormat format,
 | 
				
			||||||
 | 
							TextureUsageFlags usageFlags,
 | 
				
			||||||
 | 
							uint levelCount = 1
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							TextureCreateInfo textureCreateInfo = new TextureCreateInfo
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Width = width,
 | 
				
			||||||
 | 
								Height = height,
 | 
				
			||||||
 | 
								Depth = depth,
 | 
				
			||||||
 | 
								IsCube = false,
 | 
				
			||||||
 | 
								LayerCount = 1,
 | 
				
			||||||
 | 
								LevelCount = levelCount,
 | 
				
			||||||
 | 
								Format = format,
 | 
				
			||||||
 | 
								UsageFlags = usageFlags
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return new Texture(device, textureCreateInfo);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a cube texture.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="device">An initialized GraphicsDevice.</param>
 | 
				
			||||||
 | 
						/// <param name="size">The length of one side of the cube.</param>
 | 
				
			||||||
 | 
						/// <param name="format">The format of the texture.</param>
 | 
				
			||||||
 | 
						/// <param name="usageFlags">Specifies how the texture will be used.</param>
 | 
				
			||||||
 | 
						/// <param name="levelCount">Specifies the number of mip levels.</param>
 | 
				
			||||||
 | 
						public static Texture CreateTextureCube(
 | 
				
			||||||
 | 
							GraphicsDevice device,
 | 
				
			||||||
 | 
							uint size,
 | 
				
			||||||
 | 
							TextureFormat format,
 | 
				
			||||||
 | 
							TextureUsageFlags usageFlags,
 | 
				
			||||||
 | 
							uint levelCount = 1
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							TextureCreateInfo textureCreateInfo = new TextureCreateInfo
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Width = size,
 | 
				
			||||||
 | 
								Height = size,
 | 
				
			||||||
 | 
								Depth = 1,
 | 
				
			||||||
 | 
								IsCube = true,
 | 
				
			||||||
 | 
								LayerCount = 6,
 | 
				
			||||||
 | 
								LevelCount = levelCount,
 | 
				
			||||||
 | 
								Format = format,
 | 
				
			||||||
 | 
								UsageFlags = usageFlags
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return new Texture(device, textureCreateInfo);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a new texture using a TextureCreateInfo struct.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="device">An initialized GraphicsDevice.</param>
 | 
				
			||||||
 | 
						/// <param name="textureCreateInfo">The parameters to use when creating the texture.</param>
 | 
				
			||||||
 | 
						public Texture(
 | 
				
			||||||
 | 
							GraphicsDevice device,
 | 
				
			||||||
 | 
							in TextureCreateInfo textureCreateInfo
 | 
				
			||||||
 | 
						) : base(device)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Handle = Refresh.Refresh_CreateTexture(
 | 
				
			||||||
 | 
								device.Handle,
 | 
				
			||||||
 | 
								textureCreateInfo.ToRefresh()
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Format = textureCreateInfo.Format;
 | 
				
			||||||
 | 
							Width = textureCreateInfo.Width;
 | 
				
			||||||
 | 
							Height = textureCreateInfo.Height;
 | 
				
			||||||
 | 
							Depth = textureCreateInfo.Depth;
 | 
				
			||||||
 | 
							IsCube = textureCreateInfo.IsCube;
 | 
				
			||||||
 | 
							LayerCount = textureCreateInfo.LayerCount;
 | 
				
			||||||
 | 
							LevelCount = textureCreateInfo.LevelCount;
 | 
				
			||||||
 | 
							SampleCount = textureCreateInfo.SampleCount;
 | 
				
			||||||
 | 
							UsageFlags = textureCreateInfo.UsageFlags;
 | 
				
			||||||
 | 
							Size = Width * Height * BytesPerPixel(Format) / BlockSizeSquared(Format);
 | 
				
			||||||
 | 
							name = "";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Used by Window. Swapchain texture handles are managed by the driver backend.
 | 
				
			||||||
 | 
						internal Texture(
 | 
				
			||||||
 | 
							GraphicsDevice device,
 | 
				
			||||||
 | 
							TextureFormat format
 | 
				
			||||||
 | 
						) : base(device)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Handle = IntPtr.Zero;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Format = format;
 | 
				
			||||||
 | 
							Width = 0;
 | 
				
			||||||
 | 
							Height = 0;
 | 
				
			||||||
 | 
							Depth = 1;
 | 
				
			||||||
 | 
							IsCube = false;
 | 
				
			||||||
 | 
							LevelCount = 1;
 | 
				
			||||||
 | 
							SampleCount = SampleCount.One;
 | 
				
			||||||
 | 
							UsageFlags = TextureUsageFlags.ColorTarget;
 | 
				
			||||||
 | 
							Size = Width * Height * BytesPerPixel(Format) / BlockSizeSquared(Format);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static uint BytesPerPixel(TextureFormat format)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							switch (format)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								case TextureFormat.R8:
 | 
				
			||||||
 | 
								case TextureFormat.R8_UINT:
 | 
				
			||||||
 | 
									return 1;
 | 
				
			||||||
 | 
								case TextureFormat.R5G6B5:
 | 
				
			||||||
 | 
								case TextureFormat.B4G4R4A4:
 | 
				
			||||||
 | 
								case TextureFormat.A1R5G5B5:
 | 
				
			||||||
 | 
								case TextureFormat.R16_SFLOAT:
 | 
				
			||||||
 | 
								case TextureFormat.R8G8_SNORM:
 | 
				
			||||||
 | 
								case TextureFormat.R8G8_UINT:
 | 
				
			||||||
 | 
								case TextureFormat.R16_UINT:
 | 
				
			||||||
 | 
								case TextureFormat.D16_UNORM:
 | 
				
			||||||
 | 
									return 2;
 | 
				
			||||||
 | 
								case TextureFormat.R8G8B8A8:
 | 
				
			||||||
 | 
								case TextureFormat.B8G8R8A8:
 | 
				
			||||||
 | 
								case TextureFormat.R32_SFLOAT:
 | 
				
			||||||
 | 
								case TextureFormat.R16G16:
 | 
				
			||||||
 | 
								case TextureFormat.R16G16_SFLOAT:
 | 
				
			||||||
 | 
								case TextureFormat.R8G8B8A8_SNORM:
 | 
				
			||||||
 | 
								case TextureFormat.A2R10G10B10:
 | 
				
			||||||
 | 
								case TextureFormat.R8G8B8A8_UINT:
 | 
				
			||||||
 | 
								case TextureFormat.R16G16_UINT:
 | 
				
			||||||
 | 
								case TextureFormat.D24_UNORM_S8_UINT:
 | 
				
			||||||
 | 
								case TextureFormat.D32_SFLOAT:
 | 
				
			||||||
 | 
									return 4;
 | 
				
			||||||
 | 
								case TextureFormat.D32_SFLOAT_S8_UINT:
 | 
				
			||||||
 | 
									return 5;
 | 
				
			||||||
 | 
								case TextureFormat.R16G16B16A16_SFLOAT:
 | 
				
			||||||
 | 
								case TextureFormat.R16G16B16A16:
 | 
				
			||||||
 | 
								case TextureFormat.R32G32_SFLOAT:
 | 
				
			||||||
 | 
								case TextureFormat.R16G16B16A16_UINT:
 | 
				
			||||||
 | 
								case TextureFormat.BC1:
 | 
				
			||||||
 | 
									return 8;
 | 
				
			||||||
 | 
								case TextureFormat.R32G32B32A32_SFLOAT:
 | 
				
			||||||
 | 
								case TextureFormat.BC2:
 | 
				
			||||||
 | 
								case TextureFormat.BC3:
 | 
				
			||||||
 | 
								case TextureFormat.BC7:
 | 
				
			||||||
 | 
									return 16;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									Log.Error("Texture format not recognized!");
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static uint TexelSize(TextureFormat format)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							switch (format)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								case TextureFormat.BC2:
 | 
				
			||||||
 | 
								case TextureFormat.BC3:
 | 
				
			||||||
 | 
								case TextureFormat.BC7:
 | 
				
			||||||
 | 
									return 16;
 | 
				
			||||||
 | 
								case TextureFormat.BC1:
 | 
				
			||||||
 | 
									return 8;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									return 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static uint BlockSizeSquared(TextureFormat format)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							switch (format)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								case TextureFormat.BC1:
 | 
				
			||||||
 | 
								case TextureFormat.BC2:
 | 
				
			||||||
 | 
								case TextureFormat.BC3:
 | 
				
			||||||
 | 
								case TextureFormat.BC7:
 | 
				
			||||||
 | 
									return 16;
 | 
				
			||||||
 | 
								case TextureFormat.R8G8B8A8:
 | 
				
			||||||
 | 
								case TextureFormat.B8G8R8A8:
 | 
				
			||||||
 | 
								case TextureFormat.R5G6B5:
 | 
				
			||||||
 | 
								case TextureFormat.A1R5G5B5:
 | 
				
			||||||
 | 
								case TextureFormat.B4G4R4A4:
 | 
				
			||||||
 | 
								case TextureFormat.A2R10G10B10:
 | 
				
			||||||
 | 
								case TextureFormat.R16G16:
 | 
				
			||||||
 | 
								case TextureFormat.R16G16B16A16:
 | 
				
			||||||
 | 
								case TextureFormat.R8:
 | 
				
			||||||
 | 
								case TextureFormat.R8G8_SNORM:
 | 
				
			||||||
 | 
								case TextureFormat.R8G8B8A8_SNORM:
 | 
				
			||||||
 | 
								case TextureFormat.R16_SFLOAT:
 | 
				
			||||||
 | 
								case TextureFormat.R16G16_SFLOAT:
 | 
				
			||||||
 | 
								case TextureFormat.R16G16B16A16_SFLOAT:
 | 
				
			||||||
 | 
								case TextureFormat.R32_SFLOAT:
 | 
				
			||||||
 | 
								case TextureFormat.R32G32_SFLOAT:
 | 
				
			||||||
 | 
								case TextureFormat.R32G32B32A32_SFLOAT:
 | 
				
			||||||
 | 
								case TextureFormat.R8_UINT:
 | 
				
			||||||
 | 
								case TextureFormat.R8G8_UINT:
 | 
				
			||||||
 | 
								case TextureFormat.R8G8B8A8_UINT:
 | 
				
			||||||
 | 
								case TextureFormat.R16_UINT:
 | 
				
			||||||
 | 
								case TextureFormat.R16G16_UINT:
 | 
				
			||||||
 | 
								case TextureFormat.R16G16B16A16_UINT:
 | 
				
			||||||
 | 
								case TextureFormat.D16_UNORM:
 | 
				
			||||||
 | 
								case TextureFormat.D24_UNORM:
 | 
				
			||||||
 | 
								case TextureFormat.D24_UNORM_S8_UINT:
 | 
				
			||||||
 | 
								case TextureFormat.D32_SFLOAT:
 | 
				
			||||||
 | 
								case TextureFormat.D32_SFLOAT_S8_UINT:
 | 
				
			||||||
 | 
									return 1;
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									Log.Error("Texture format not recognized!");
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static implicit operator TextureSlice(Texture t) => new TextureSlice(t);
 | 
				
			||||||
 | 
						public static implicit operator TextureRegion(Texture t) => new TextureRegion(t);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										209
									
								
								Nerfed.Runtime/Graphics/Resources/TransferBuffer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										209
									
								
								Nerfed.Runtime/Graphics/Resources/TransferBuffer.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,209 @@
 | 
				
			|||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					using RefreshCS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime.Graphics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// A data container that can efficiently transfer data to and from the GPU.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public unsafe class TransferBuffer : RefreshResource
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						protected override Action<IntPtr, IntPtr> ReleaseFunction => Refresh.Refresh_ReleaseTransferBuffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Size in bytes.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public uint Size { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
						public bool Mapped { get; private set; }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a buffer of requested size given a type and element count.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <typeparam name="T">The type that the buffer will contain.</typeparam>
 | 
				
			||||||
 | 
						/// <param name="device">The GraphicsDevice.</param>
 | 
				
			||||||
 | 
						/// <param name="elementCount">How many elements of type T the buffer will contain.</param>
 | 
				
			||||||
 | 
						/// <returns></returns>
 | 
				
			||||||
 | 
						public unsafe static TransferBuffer Create<T>(
 | 
				
			||||||
 | 
							GraphicsDevice device,
 | 
				
			||||||
 | 
							TransferBufferUsage usage,
 | 
				
			||||||
 | 
							uint elementCount
 | 
				
			||||||
 | 
						) where T : unmanaged
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return new TransferBuffer(
 | 
				
			||||||
 | 
								device,
 | 
				
			||||||
 | 
								usage,
 | 
				
			||||||
 | 
								(uint) Marshal.SizeOf<T>() * elementCount
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Creates a TransferBuffer.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						/// <param name="device">An initialized GraphicsDevice.</param>
 | 
				
			||||||
 | 
						/// <param name="usage">Whether this will be used to upload buffers or textures.</param>
 | 
				
			||||||
 | 
						/// <param name="sizeInBytes">The length of the buffer. Cannot be resized.</param>
 | 
				
			||||||
 | 
						public TransferBuffer(
 | 
				
			||||||
 | 
							GraphicsDevice device,
 | 
				
			||||||
 | 
							TransferBufferUsage usage,
 | 
				
			||||||
 | 
							uint sizeInBytes
 | 
				
			||||||
 | 
						) : base(device)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Handle = Refresh.Refresh_CreateTransferBuffer(
 | 
				
			||||||
 | 
								device.Handle,
 | 
				
			||||||
 | 
								(Refresh.TransferBufferUsage) usage,
 | 
				
			||||||
 | 
								sizeInBytes
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							Size = sizeInBytes;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Immediately copies data from a Span to the TransferBuffer.
 | 
				
			||||||
 | 
						/// Returns the length of the copy in bytes.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// If cycle is set to true and this TransferBuffer was used in an Upload command,
 | 
				
			||||||
 | 
						/// that command will still use the correct data at the cost of increased memory usage.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// If cycle is set to false, the data will be overwritten immediately,
 | 
				
			||||||
 | 
						/// which could cause a data race.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public unsafe uint SetData<T>(
 | 
				
			||||||
 | 
							Span<T> source,
 | 
				
			||||||
 | 
							uint bufferOffsetInBytes,
 | 
				
			||||||
 | 
							bool cycle
 | 
				
			||||||
 | 
						) where T : unmanaged
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							int elementSize = Marshal.SizeOf<T>();
 | 
				
			||||||
 | 
							uint dataLengthInBytes = (uint) (elementSize * source.Length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
							AssertBufferBoundsCheck(Size, bufferOffsetInBytes, dataLengthInBytes);
 | 
				
			||||||
 | 
							AssertNotMapped();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							fixed (T* dataPtr = source)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Refresh.Refresh_SetTransferData(
 | 
				
			||||||
 | 
									Device.Handle,
 | 
				
			||||||
 | 
									(nint) dataPtr,
 | 
				
			||||||
 | 
									new Refresh.TransferBufferRegion
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										TransferBuffer = Handle,
 | 
				
			||||||
 | 
										Offset = bufferOffsetInBytes,
 | 
				
			||||||
 | 
										Size = dataLengthInBytes
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Conversions.BoolToInt(cycle)
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return dataLengthInBytes;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Immediately copies data from a Span to the TransferBuffer.
 | 
				
			||||||
 | 
						/// Returns the length of the copy in bytes.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// If cycle is set to true and this TransferBuffer was used in an Upload command,
 | 
				
			||||||
 | 
						/// that command will still use the corret data at the cost of increased memory usage.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// If cycle is set to false, the data will be overwritten immediately,
 | 
				
			||||||
 | 
						/// which could cause a data race.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public unsafe uint SetData<T>(
 | 
				
			||||||
 | 
							Span<T> source,
 | 
				
			||||||
 | 
							bool cycle
 | 
				
			||||||
 | 
						) where T : unmanaged
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return SetData(source, 0, cycle);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Immediately copies data from the TransferBuffer into a Span.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public unsafe void GetData<T>(
 | 
				
			||||||
 | 
							Span<T> destination,
 | 
				
			||||||
 | 
							uint bufferOffsetInBytes = 0
 | 
				
			||||||
 | 
						) where T : unmanaged
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							int elementSize = Marshal.SizeOf<T>();
 | 
				
			||||||
 | 
							uint dataLengthInBytes = (uint) (elementSize * destination.Length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
							AssertBufferBoundsCheck(Size, bufferOffsetInBytes, dataLengthInBytes);
 | 
				
			||||||
 | 
							AssertNotMapped();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							fixed (T* dataPtr = destination)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Refresh.Refresh_GetTransferData(
 | 
				
			||||||
 | 
									Device.Handle,
 | 
				
			||||||
 | 
									new Refresh.TransferBufferRegion
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										TransferBuffer = Handle,
 | 
				
			||||||
 | 
										Offset = bufferOffsetInBytes,
 | 
				
			||||||
 | 
										Size = dataLengthInBytes
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									(nint) dataPtr
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Maps the transfer buffer into application address space.
 | 
				
			||||||
 | 
						/// You must call Unmap before encoding transfer commands.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public unsafe void Map(bool cycle, out byte* data)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
							AssertNotMapped();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Refresh.Refresh_MapTransferBuffer(
 | 
				
			||||||
 | 
								Device.Handle,
 | 
				
			||||||
 | 
								Handle,
 | 
				
			||||||
 | 
								Conversions.BoolToInt(cycle),
 | 
				
			||||||
 | 
								out data
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
							Mapped = true;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Unmaps the transfer buffer.
 | 
				
			||||||
 | 
						/// The pointer given by Map is no longer valid.
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public void Unmap()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Refresh.Refresh_UnmapTransferBuffer(
 | 
				
			||||||
 | 
								Device.Handle,
 | 
				
			||||||
 | 
								Handle
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
							Mapped = false;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
						private void AssertBufferBoundsCheck(uint bufferLengthInBytes, uint offsetInBytes, uint copyLengthInBytes)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (copyLengthInBytes > bufferLengthInBytes + offsetInBytes)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new InvalidOperationException($"Data overflow! Transfer buffer length {bufferLengthInBytes}, offset {offsetInBytes}, copy length {copyLengthInBytes}");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void AssertNotMapped()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (Mapped)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								throw new InvalidOperationException("Transfer buffer must not be mapped!");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								Nerfed.Runtime/Graphics/StockShaders/Binary/fullscreen.vert.spv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Nerfed.Runtime/Graphics/StockShaders/Binary/fullscreen.vert.spv
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Nerfed.Runtime/Graphics/StockShaders/Binary/text_msdf.frag.spv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Nerfed.Runtime/Graphics/StockShaders/Binary/text_msdf.frag.spv
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					#version 450
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					layout(location = 0) out vec2 outTexCoord;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void main()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						outTexCoord = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
 | 
				
			||||||
 | 
						gl_Position = vec4(outTexCoord * vec2(2.0, -2.0) + vec2(-1.0, 1.0), 0.0, 1.0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										34
									
								
								Nerfed.Runtime/Graphics/StockShaders/Source/text_msdf.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								Nerfed.Runtime/Graphics/StockShaders/Source/text_msdf.frag
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					#version 450
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					layout(location = 0) in vec2 inTexCoord;
 | 
				
			||||||
 | 
					layout(location = 1) in vec4 inColor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					layout(location = 0) out vec4 outColor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					layout(set = 2, binding = 0) uniform sampler2D msdf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					layout(set = 3, binding = 0) uniform UBO
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						float pxRange;
 | 
				
			||||||
 | 
					} ubo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					float median(float r, float g, float b)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return max(min(r, g), min(max(r, g), b));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					float screenPxRange()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    vec2 unitRange = vec2(ubo.pxRange)/vec2(textureSize(msdf, 0));
 | 
				
			||||||
 | 
					    vec2 screenTexSize = vec2(1.0)/fwidth(inTexCoord);
 | 
				
			||||||
 | 
					    return max(0.5*dot(unitRange, screenTexSize), 1.0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void main()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						vec3 msd = texture(msdf, inTexCoord).rgb;
 | 
				
			||||||
 | 
						float sd = median(msd.r, msd.g, msd.b);
 | 
				
			||||||
 | 
					    float screenPxDistance = screenPxRange() * (sd - 0.5);
 | 
				
			||||||
 | 
					    float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0);
 | 
				
			||||||
 | 
					    outColor = mix(vec4(0.0, 0.0, 0.0, 0.0), inColor, opacity);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										7
									
								
								Nerfed.Runtime/Input/ButtonState.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								Nerfed.Runtime/Input/ButtonState.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					namespace Nerfed.Runtime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public enum ButtonState
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Released,
 | 
				
			||||||
 | 
					    Pressed
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										224
									
								
								Nerfed.Runtime/Input/Devices/GamePad.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								Nerfed.Runtime/Input/Devices/GamePad.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,224 @@
 | 
				
			|||||||
 | 
					using SDL2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class GamePad
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private const int maxGamePads = 4;
 | 
				
			||||||
 | 
					    private static readonly GamePad[] gamePads = new GamePad[maxGamePads];
 | 
				
			||||||
 | 
					    private static readonly GamePad dummy = new GamePad();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public IntPtr Handle { get; private set; }
 | 
				
			||||||
 | 
					    public bool IsConnected => Handle != IntPtr.Zero;
 | 
				
			||||||
 | 
					    public int JoystickInstanceId { get; private set; } = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private readonly ButtonState[] buttonStates;
 | 
				
			||||||
 | 
					    private readonly ButtonState[] lastButtonStates;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static GamePad()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        for (int i = 0; i < maxGamePads; i++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            gamePads[i] = new GamePad();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private GamePad()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int gamePadButtonCount = Enum.GetValues<GamePadButton>().Length;
 | 
				
			||||||
 | 
					        buttonStates = new ButtonState[gamePadButtonCount];
 | 
				
			||||||
 | 
					        lastButtonStates = new ButtonState[gamePadButtonCount];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public bool IsButtonDown(GamePadButton button)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return buttonStates[(int)button] == ButtonState.Pressed;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void Register(IntPtr handle)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Handle = handle;
 | 
				
			||||||
 | 
					        IntPtr joystickHandle = SDL.SDL_GameControllerGetJoystick(handle);
 | 
				
			||||||
 | 
					        JoystickInstanceId = SDL.SDL_JoystickInstanceID(joystickHandle);
 | 
				
			||||||
 | 
					        Log.Info("Controller connected");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void UnRegister()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Handle = IntPtr.Zero;
 | 
				
			||||||
 | 
					        JoystickInstanceId = -1;
 | 
				
			||||||
 | 
					        Log.Info("Controller disconnected");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static GamePad Get(int slot)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return slot >= 0 && slot < maxGamePads ? gamePads[slot] : dummy;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal static void Update()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        for (int i = 0; i < maxGamePads; i++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            GamePad gamePad = gamePads[i];
 | 
				
			||||||
 | 
					            if (gamePad.IsConnected)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Array.Copy(gamePad.buttonStates, gamePad.lastButtonStates, gamePad.buttonStates.Length);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal static void ProcessEvent(ref SDL.SDL_Event ev)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        switch (ev.type)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            case SDL.SDL_EventType.SDL_CONTROLLERDEVICEADDED:
 | 
				
			||||||
 | 
					                ProcessDeviceAdded(ref ev.cdevice);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case SDL.SDL_EventType.SDL_CONTROLLERDEVICEREMOVED:
 | 
				
			||||||
 | 
					                ProcessDeviceRemoved(ref ev.cdevice);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case SDL.SDL_EventType.SDL_CONTROLLERBUTTONDOWN:
 | 
				
			||||||
 | 
					                ProcessButtonDown(ref ev.cbutton);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case SDL.SDL_EventType.SDL_CONTROLLERBUTTONUP:
 | 
				
			||||||
 | 
					                ProcessButtonUp(ref ev.cbutton);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case SDL.SDL_EventType.SDL_CONTROLLERAXISMOTION:
 | 
				
			||||||
 | 
					                ProcessAxisMotion(ref ev.caxis);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case SDL.SDL_EventType.SDL_CONTROLLERTOUCHPADDOWN:
 | 
				
			||||||
 | 
					                ProcessTouchPadDown(ref ev.ctouchpad);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case SDL.SDL_EventType.SDL_CONTROLLERTOUCHPADUP:
 | 
				
			||||||
 | 
					                ProcessTouchPadUp(ref ev.ctouchpad);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case SDL.SDL_EventType.SDL_CONTROLLERTOUCHPADMOTION:
 | 
				
			||||||
 | 
					                ProcessTouchPadMotion(ref ev.ctouchpad);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case SDL.SDL_EventType.SDL_CONTROLLERSENSORUPDATE:
 | 
				
			||||||
 | 
					                ProcessSensorUpdate(ref ev.sensor);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static void ProcessDeviceAdded(ref SDL.SDL_ControllerDeviceEvent ev)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int index = ev.which;
 | 
				
			||||||
 | 
					        if (SDL.SDL_IsGameController(index) == SDL.SDL_bool.SDL_TRUE)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            int slot = -1;
 | 
				
			||||||
 | 
					            for (int i = 0; i < maxGamePads; i++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (!gamePads[i].IsConnected)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    slot = i;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (slot == -1)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Log.Warning("Too many gamepads connected");
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            IntPtr handle = SDL.SDL_GameControllerOpen(index);
 | 
				
			||||||
 | 
					            if (handle == IntPtr.Zero)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Log.Error($"Failed to open gamepad: {SDL.SDL_GetError()}");
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            gamePads[slot].Register(handle);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static GamePad GetByJoystickId(int joystickId)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        for (int slot = 0; slot < maxGamePads; slot++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            GamePad gamePad = gamePads[slot];
 | 
				
			||||||
 | 
					            if (gamePad.IsConnected && gamePad.JoystickInstanceId == joystickId)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return gamePad;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static void ProcessDeviceRemoved(ref SDL.SDL_ControllerDeviceEvent ev)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        GamePad gamePad = GetByJoystickId(ev.which);
 | 
				
			||||||
 | 
					        gamePad?.UnRegister();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static void ProcessButtonDown(ref SDL.SDL_ControllerButtonEvent ev)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (TryConvertButton(ev.button, out GamePadButton button))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            GamePad gamePad = GetByJoystickId(ev.which);
 | 
				
			||||||
 | 
					            gamePad.buttonStates[(int)button] = ButtonState.Pressed;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static void ProcessButtonUp(ref SDL.SDL_ControllerButtonEvent ev)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (TryConvertButton(ev.button, out GamePadButton button))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            GamePad gamePad = GetByJoystickId(ev.which);
 | 
				
			||||||
 | 
					            gamePad.buttonStates[(int)button] = ButtonState.Released;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static void ProcessAxisMotion(ref SDL.SDL_ControllerAxisEvent ev)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static void ProcessTouchPadDown(ref SDL.SDL_ControllerTouchpadEvent ev)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static void ProcessTouchPadUp(ref SDL.SDL_ControllerTouchpadEvent ev)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static void ProcessTouchPadMotion(ref SDL.SDL_ControllerTouchpadEvent ev)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static void ProcessSensorUpdate(ref SDL.SDL_SensorEvent ev)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static bool TryConvertButton(byte rawButton, out GamePadButton button)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        GamePadButton? result = rawButton switch
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            (byte)SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_A => GamePadButton.A,
 | 
				
			||||||
 | 
					            (byte)SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_B => GamePadButton.B,
 | 
				
			||||||
 | 
					            (byte)SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_X => GamePadButton.X,
 | 
				
			||||||
 | 
					            (byte)SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_Y => GamePadButton.Y,
 | 
				
			||||||
 | 
					            (byte)SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_BACK => GamePadButton.Back,
 | 
				
			||||||
 | 
					            (byte)SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_START => GamePadButton.Start,
 | 
				
			||||||
 | 
					            (byte)SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSTICK => GamePadButton.LeftStick,
 | 
				
			||||||
 | 
					            (byte)SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSTICK => GamePadButton.RightStick,
 | 
				
			||||||
 | 
					            (byte)SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSHOULDER => GamePadButton.LeftShoulder,
 | 
				
			||||||
 | 
					            (byte)SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSHOULDER => GamePadButton.RightShoulder,
 | 
				
			||||||
 | 
					            (byte)SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_UP => GamePadButton.DPadUp,
 | 
				
			||||||
 | 
					            (byte)SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_DOWN => GamePadButton.DPadDown,
 | 
				
			||||||
 | 
					            (byte)SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_LEFT => GamePadButton.DPadLeft,
 | 
				
			||||||
 | 
					            (byte)SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_DPAD_RIGHT => GamePadButton.DPadRight,
 | 
				
			||||||
 | 
					            (byte)SDL.SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_TOUCHPAD => GamePadButton.BigButton,
 | 
				
			||||||
 | 
					            _ => null
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        button = result.GetValueOrDefault();
 | 
				
			||||||
 | 
					        return result.HasValue;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										295
									
								
								Nerfed.Runtime/Input/Devices/Keyboard.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										295
									
								
								Nerfed.Runtime/Input/Devices/Keyboard.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,295 @@
 | 
				
			|||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using SDL2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public static class Keyboard
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private static readonly List<char> textInput = new List<char>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private const int maxPressedKeys = 8;
 | 
				
			||||||
 | 
					    private static readonly List<Key> keys = new List<Key>(maxPressedKeys);
 | 
				
			||||||
 | 
					    private static readonly List<Key> lastKeys = new List<Key>(maxPressedKeys);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// True if the key was pressed or continued to be held down this frame.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="key"></param>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    public static bool IsKeyDown(Key key)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return HasKey(keys, key);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// True if the key was pressed this frame.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public static bool IsKeyPressed(Key key)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return HasKey(keys, key) && !HasKey(lastKeys, key);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// True if the key was released or continued to be released this frame.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public static bool IsKeyUp(Key key)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return !HasKey(keys, key);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// True if the key was released this frame.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public static bool IsKeyReleased(Key key)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return !HasKey(keys, key) && HasKey(lastKeys, key);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static ReadOnlySpan<Key> GetPressedKeys()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return CollectionsMarshal.AsSpan(keys);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static ReadOnlySpan<char> GetTextInput()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return CollectionsMarshal.AsSpan(textInput);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal static void Update()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        textInput.Clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        lastKeys.Clear();
 | 
				
			||||||
 | 
					        if (keys.Count > 0)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            lastKeys.AddRange(keys);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static bool HasKey(List<Key> list, Key key)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        for (int i = 0; i < list.Count; i++)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (keys[i] == key)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    internal static void ProcessEvent(ref SDL.SDL_Event ev)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        switch (ev.type)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            case SDL.SDL_EventType.SDL_TEXTINPUT:
 | 
				
			||||||
 | 
					                ProcessTextInputEvent(ref ev.text);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case SDL.SDL_EventType.SDL_KEYDOWN:
 | 
				
			||||||
 | 
					                ProcessKeyDownEvent(ref ev.key);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case SDL.SDL_EventType.SDL_KEYUP:
 | 
				
			||||||
 | 
					                ProcessKeyUpEvent(ref ev.key);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static unsafe void ProcessTextInputEvent(ref SDL.SDL_TextInputEvent evt)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Based on the SDL2# LPUtf8StrMarshaler
 | 
				
			||||||
 | 
					        int MeasureStringLength(byte* ptr)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            int bytes;
 | 
				
			||||||
 | 
					            for (bytes = 0; *ptr != 0; ptr += 1, bytes += 1) ;
 | 
				
			||||||
 | 
					            return bytes;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fixed (byte* textPtr = evt.text)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            int bytes = MeasureStringLength(textPtr);
 | 
				
			||||||
 | 
					            if (bytes > 0)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                /* UTF8 will never encode more characters
 | 
				
			||||||
 | 
					                 * than bytes in a string, so bytes is a
 | 
				
			||||||
 | 
					                 * suitable upper estimate of size needed
 | 
				
			||||||
 | 
					                 */
 | 
				
			||||||
 | 
					                char* charsBuffer = stackalloc char[bytes];
 | 
				
			||||||
 | 
					                int chars = Encoding.UTF8.GetChars(
 | 
				
			||||||
 | 
					                    textPtr,
 | 
				
			||||||
 | 
					                    bytes,
 | 
				
			||||||
 | 
					                    charsBuffer,
 | 
				
			||||||
 | 
					                    bytes
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (chars > 0)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    textInput.AddRange(new ReadOnlySpan<char>(charsBuffer, chars));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static void ProcessKeyDownEvent(ref SDL.SDL_KeyboardEvent ev)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Key key = ConvertScancode(ev.keysym.scancode);
 | 
				
			||||||
 | 
					        SetKeyState(key, KeyState.Down);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static void ProcessKeyUpEvent(ref SDL.SDL_KeyboardEvent ev)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Key key = ConvertScancode(ev.keysym.scancode);
 | 
				
			||||||
 | 
					        SetKeyState(key, KeyState.Up);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void SetKeyState(Key key, KeyState state)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (keys.Count >= maxPressedKeys)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (state == KeyState.Down)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (!keys.Contains(key))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                keys.Add(key);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (state == KeyState.Up)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            keys.Remove(key);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static Key ConvertScancode(SDL.SDL_Scancode scancode)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        switch (scancode)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_A: return Key.A;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_B: return Key.B;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_C: return Key.C;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_D: return Key.D;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_E: return Key.E;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F: return Key.F;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_G: return Key.G;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_H: return Key.H;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_I: return Key.I;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_J: return Key.J;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_K: return Key.K;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_L: return Key.L;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_M: return Key.M;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_N: return Key.N;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_O: return Key.O;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_P: return Key.P;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_Q: return Key.Q;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_R: return Key.R;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_S: return Key.S;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_T: return Key.T;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_U: return Key.U;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_V: return Key.V;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_W: return Key.W;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_X: return Key.X;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_Y: return Key.Y;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_Z: return Key.Z;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_1: return Key.D1;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_2: return Key.D2;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_3: return Key.D3;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_4: return Key.D4;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_5: return Key.D5;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_6: return Key.D6;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_7: return Key.D7;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_8: return Key.D8;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_9: return Key.D9;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_0: return Key.D0;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_RETURN: return Key.Enter;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_ESCAPE: return Key.Escape;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_BACKSPACE: return Key.Backspace;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_TAB: return Key.Tab;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_SPACE: return Key.Space;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_MINUS: return Key.Minus;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_EQUALS: return Key.Equals;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_LEFTBRACKET: return Key.LeftBracket;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_RIGHTBRACKET: return Key.RightBracket;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_BACKSLASH: return Key.Backslash;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_SEMICOLON: return Key.Semicolon;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_APOSTROPHE: return Key.Apostrophe;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_GRAVE: return Key.Tilde;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_COMMA: return Key.Comma;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_PERIOD: return Key.Period;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_SLASH: return Key.Slash;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_CAPSLOCK: return Key.CapsLock;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F1: return Key.F1;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F2: return Key.F2;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F3: return Key.F3;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F4: return Key.F4;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F5: return Key.F5;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F6: return Key.F6;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F7: return Key.F7;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F8: return Key.F8;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F9: return Key.F9;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F10: return Key.F10;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F11: return Key.F11;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F12: return Key.F12;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_PRINTSCREEN: return Key.PrintScreen;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_SCROLLLOCK: return Key.Scroll;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_PAUSE: return Key.Pause;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_INSERT: return Key.Insert;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_HOME: return Key.Home;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_PAGEUP: return Key.PageUp;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_DELETE: return Key.Delete;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_END: return Key.End;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_PAGEDOWN: return Key.PageDown;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_RIGHT: return Key.Right;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_LEFT: return Key.Left;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_DOWN: return Key.Down;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_UP: return Key.Up;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_NUMLOCKCLEAR: return Key.NumLock;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_KP_DIVIDE: return Key.Divide;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_KP_MULTIPLY: return Key.Multiply;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_KP_MINUS: return Key.Subtract;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_KP_PLUS: return Key.Add;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_KP_ENTER: return Key.Enter;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_KP_1: return Key.NumPad1;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_KP_2: return Key.NumPad2;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_KP_3: return Key.NumPad3;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_KP_4: return Key.NumPad4;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_KP_5: return Key.NumPad5;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_KP_6: return Key.NumPad6;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_KP_7: return Key.NumPad7;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_KP_8: return Key.NumPad8;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_KP_9: return Key.NumPad9;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_KP_0: return Key.NumPad0;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_KP_PERIOD: return Key.Period;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_APPLICATION: return Key.Apps;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_KP_EQUALS: return Key.Equals;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F13: return Key.F13;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F14: return Key.F14;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F15: return Key.F15;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F16: return Key.F16;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F17: return Key.F17;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F18: return Key.F18;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F19: return Key.F19;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F20: return Key.F20;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F21: return Key.F21;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F22: return Key.F22;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F23: return Key.F23;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_F24: return Key.F24;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_EXECUTE: return Key.Execute;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_HELP: return Key.Help;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_MENU: return Key.Apps;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_SELECT: return Key.Select;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_KP_COMMA: return Key.Comma;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_LCTRL: return Key.LeftControl;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_LSHIFT: return Key.LeftShift;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_LALT: return Key.LeftAlt;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_LGUI: return Key.LeftSuper;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_RCTRL: return Key.RightControl;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_RSHIFT: return Key.RightShift;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_RALT: return Key.RightAlt;
 | 
				
			||||||
 | 
					            case SDL.SDL_Scancode.SDL_SCANCODE_RGUI: return Key.RightSuper;
 | 
				
			||||||
 | 
					            default: return Key.None;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										132
									
								
								Nerfed.Runtime/Input/Devices/Mouse.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								Nerfed.Runtime/Input/Devices/Mouse.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,132 @@
 | 
				
			|||||||
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					using SDL2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nerfed.Runtime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					internal static class Mouse
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public static Vector2 Position { get; private set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static readonly ButtonState[] buttonStates;
 | 
				
			||||||
 | 
					    private static readonly ButtonState[] lastButtonStates;
 | 
				
			||||||
 | 
					    private static int wheelX;
 | 
				
			||||||
 | 
					    private static int wheelY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static Mouse()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int numButtons = Enum.GetValues<MouseButton>().Length;
 | 
				
			||||||
 | 
					        buttonStates = new ButtonState[numButtons];
 | 
				
			||||||
 | 
					        lastButtonStates = new ButtonState[numButtons];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// /// <summary>
 | 
				
			||||||
 | 
					    /// True if the button is pressed or continued to be held this frame.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public static bool IsButtonDown(MouseButton button)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return buttonStates[(int)button] == ButtonState.Pressed;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// True if the button is pressed this frame.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public static bool IsButtonPressed(MouseButton button)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return buttonStates[(int)button] == ButtonState.Pressed && lastButtonStates[(int)button] == ButtonState.Released;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// True if the button is released or continued to be released this frame.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="button"></param>
 | 
				
			||||||
 | 
					    /// <returns></returns>
 | 
				
			||||||
 | 
					    public static bool IsButtonUp(MouseButton button)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return buttonStates[(int)button] == ButtonState.Released;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// True if the button is released this frame.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public static bool IsButtonReleased(MouseButton button)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return buttonStates[(int)button] == ButtonState.Released && lastButtonStates[(int)button] == ButtonState.Pressed;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static int GetWheel()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return wheelY;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static int GetWheelHorizontal()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return wheelX;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal static void Update()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Array.Copy(buttonStates, lastButtonStates, buttonStates.Length);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    internal static void ProcessEvent(ref SDL.SDL_Event ev)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        switch (ev.type)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            case SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN:
 | 
				
			||||||
 | 
					                ProcessButtonDownEvent(ref ev.button);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case SDL.SDL_EventType.SDL_MOUSEBUTTONUP:
 | 
				
			||||||
 | 
					                ProcessButtonUpEvent(ref ev.button);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case SDL.SDL_EventType.SDL_MOUSEWHEEL:
 | 
				
			||||||
 | 
					                ProcessWheelEvent(ref ev.wheel);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case SDL.SDL_EventType.SDL_MOUSEMOTION:
 | 
				
			||||||
 | 
					                ProcessMotionEvent(ref ev.motion);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static void ProcessButtonDownEvent(ref SDL.SDL_MouseButtonEvent ev)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (TryConvertButton(ev.button, out MouseButton button))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            buttonStates[(int)button] = ButtonState.Pressed;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static void ProcessButtonUpEvent(ref SDL.SDL_MouseButtonEvent ev)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (TryConvertButton(ev.button, out MouseButton button))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            buttonStates[(int)button] = ButtonState.Released;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static void ProcessWheelEvent(ref SDL.SDL_MouseWheelEvent ev)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        wheelX += ev.x;
 | 
				
			||||||
 | 
					        wheelY += ev.y;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static void ProcessMotionEvent(ref SDL.SDL_MouseMotionEvent ev)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Position = new Vector2(ev.x, ev.y);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static bool TryConvertButton(byte rawButton, out MouseButton button)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        MouseButton? result = rawButton switch
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            (byte)SDL.SDL_BUTTON_LEFT => MouseButton.Left,
 | 
				
			||||||
 | 
					            (byte)SDL.SDL_BUTTON_MIDDLE => MouseButton.Middle,
 | 
				
			||||||
 | 
					            (byte)SDL.SDL_BUTTON_RIGHT => MouseButton.Right,
 | 
				
			||||||
 | 
					            (byte)SDL.SDL_BUTTON_X1 => MouseButton.XButton1,
 | 
				
			||||||
 | 
					            (byte)SDL.SDL_BUTTON_X2 => MouseButton.XButton2,
 | 
				
			||||||
 | 
					            _ => null
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        button = result.GetValueOrDefault();
 | 
				
			||||||
 | 
					        return result.HasValue;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										11
									
								
								Nerfed.Runtime/Input/GamePadAxis.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Nerfed.Runtime/Input/GamePadAxis.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					namespace Nerfed.Runtime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public enum GamePadAxis
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    LeftTrigger,
 | 
				
			||||||
 | 
					    RightTrigger,
 | 
				
			||||||
 | 
					    LeftThumbStickX,
 | 
				
			||||||
 | 
					    LeftThumbStickY,
 | 
				
			||||||
 | 
					    RightThumbStickX,
 | 
				
			||||||
 | 
					    RightThumbStickY
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										20
									
								
								Nerfed.Runtime/Input/GamePadButton.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								Nerfed.Runtime/Input/GamePadButton.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					namespace Nerfed.Runtime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public enum GamePadButton
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Start,
 | 
				
			||||||
 | 
					    A,
 | 
				
			||||||
 | 
					    B,
 | 
				
			||||||
 | 
					    X,
 | 
				
			||||||
 | 
					    Y,
 | 
				
			||||||
 | 
					    DPadLeft,
 | 
				
			||||||
 | 
					    DPadRight,
 | 
				
			||||||
 | 
					    DPadUp,
 | 
				
			||||||
 | 
					    DPadDown,
 | 
				
			||||||
 | 
					    RightShoulder,
 | 
				
			||||||
 | 
					    LeftShoulder,
 | 
				
			||||||
 | 
					    LeftStick,
 | 
				
			||||||
 | 
					    RightStick,
 | 
				
			||||||
 | 
					    Back,
 | 
				
			||||||
 | 
					    BigButton
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										127
									
								
								Nerfed.Runtime/Input/Key.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								Nerfed.Runtime/Input/Key.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,127 @@
 | 
				
			|||||||
 | 
					namespace Nerfed.Runtime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public enum Key : int // must be int32 (see KeyboardState)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						None,
 | 
				
			||||||
 | 
						Backspace,
 | 
				
			||||||
 | 
						Tab,
 | 
				
			||||||
 | 
						Enter,
 | 
				
			||||||
 | 
						CapsLock,
 | 
				
			||||||
 | 
						Escape,
 | 
				
			||||||
 | 
						Space,
 | 
				
			||||||
 | 
						PageUp,
 | 
				
			||||||
 | 
						PageDown,
 | 
				
			||||||
 | 
						End,
 | 
				
			||||||
 | 
						Home,
 | 
				
			||||||
 | 
						Left,
 | 
				
			||||||
 | 
						Up,
 | 
				
			||||||
 | 
						Right,
 | 
				
			||||||
 | 
						Down,
 | 
				
			||||||
 | 
						Select,
 | 
				
			||||||
 | 
						Execute,
 | 
				
			||||||
 | 
						PrintScreen,
 | 
				
			||||||
 | 
						Insert,
 | 
				
			||||||
 | 
						Delete,
 | 
				
			||||||
 | 
						Help,
 | 
				
			||||||
 | 
						D0,
 | 
				
			||||||
 | 
						D1,
 | 
				
			||||||
 | 
						D2,
 | 
				
			||||||
 | 
						D3,
 | 
				
			||||||
 | 
						D4,
 | 
				
			||||||
 | 
						D5,
 | 
				
			||||||
 | 
						D6,
 | 
				
			||||||
 | 
						D7,
 | 
				
			||||||
 | 
						D8,
 | 
				
			||||||
 | 
						D9,
 | 
				
			||||||
 | 
						A,
 | 
				
			||||||
 | 
						B,
 | 
				
			||||||
 | 
						C,
 | 
				
			||||||
 | 
						D,
 | 
				
			||||||
 | 
						E,
 | 
				
			||||||
 | 
						F,
 | 
				
			||||||
 | 
						G,
 | 
				
			||||||
 | 
						H,
 | 
				
			||||||
 | 
						I,
 | 
				
			||||||
 | 
						J,
 | 
				
			||||||
 | 
						K,
 | 
				
			||||||
 | 
						L,
 | 
				
			||||||
 | 
						M,
 | 
				
			||||||
 | 
						N,
 | 
				
			||||||
 | 
						O,
 | 
				
			||||||
 | 
						P,
 | 
				
			||||||
 | 
						Q,
 | 
				
			||||||
 | 
						R,
 | 
				
			||||||
 | 
						S,
 | 
				
			||||||
 | 
						T,
 | 
				
			||||||
 | 
						U,
 | 
				
			||||||
 | 
						V,
 | 
				
			||||||
 | 
						W,
 | 
				
			||||||
 | 
						X,
 | 
				
			||||||
 | 
						Y,
 | 
				
			||||||
 | 
						Z,
 | 
				
			||||||
 | 
						LeftSuper,
 | 
				
			||||||
 | 
						RightSuper,
 | 
				
			||||||
 | 
						Apps,
 | 
				
			||||||
 | 
						NumPad0,
 | 
				
			||||||
 | 
						NumPad1,
 | 
				
			||||||
 | 
						NumPad2,
 | 
				
			||||||
 | 
						NumPad3,
 | 
				
			||||||
 | 
						NumPad4,
 | 
				
			||||||
 | 
						NumPad5,
 | 
				
			||||||
 | 
						NumPad6,
 | 
				
			||||||
 | 
						NumPad7,
 | 
				
			||||||
 | 
						NumPad8,
 | 
				
			||||||
 | 
						NumPad9,
 | 
				
			||||||
 | 
						Multiply,
 | 
				
			||||||
 | 
						Add,
 | 
				
			||||||
 | 
						Separator,
 | 
				
			||||||
 | 
						Subtract,
 | 
				
			||||||
 | 
						Decimal,
 | 
				
			||||||
 | 
						Divide,
 | 
				
			||||||
 | 
						F1,
 | 
				
			||||||
 | 
						F2,
 | 
				
			||||||
 | 
						F3,
 | 
				
			||||||
 | 
						F4,
 | 
				
			||||||
 | 
						F5,
 | 
				
			||||||
 | 
						F6,
 | 
				
			||||||
 | 
						F7,
 | 
				
			||||||
 | 
						F8,
 | 
				
			||||||
 | 
						F9,
 | 
				
			||||||
 | 
						F10,
 | 
				
			||||||
 | 
						F11,
 | 
				
			||||||
 | 
						F12,
 | 
				
			||||||
 | 
						F13,
 | 
				
			||||||
 | 
						F14,
 | 
				
			||||||
 | 
						F15,
 | 
				
			||||||
 | 
						F16,
 | 
				
			||||||
 | 
						F17,
 | 
				
			||||||
 | 
						F18,
 | 
				
			||||||
 | 
						F19,
 | 
				
			||||||
 | 
						F20,
 | 
				
			||||||
 | 
						F21,
 | 
				
			||||||
 | 
						F22,
 | 
				
			||||||
 | 
						F23,
 | 
				
			||||||
 | 
						F24,
 | 
				
			||||||
 | 
						NumLock,
 | 
				
			||||||
 | 
						Scroll,
 | 
				
			||||||
 | 
						LeftShift,
 | 
				
			||||||
 | 
						RightShift,
 | 
				
			||||||
 | 
						LeftControl,
 | 
				
			||||||
 | 
						RightControl,
 | 
				
			||||||
 | 
						LeftAlt,
 | 
				
			||||||
 | 
						RightAlt,
 | 
				
			||||||
 | 
						Semicolon,
 | 
				
			||||||
 | 
						Equals,
 | 
				
			||||||
 | 
						Comma,
 | 
				
			||||||
 | 
						Minus,
 | 
				
			||||||
 | 
						Period,
 | 
				
			||||||
 | 
						Slash,
 | 
				
			||||||
 | 
						Tilde,
 | 
				
			||||||
 | 
						LeftBracket,
 | 
				
			||||||
 | 
						Backslash,
 | 
				
			||||||
 | 
						RightBracket,
 | 
				
			||||||
 | 
						Apostrophe,
 | 
				
			||||||
 | 
						Pause,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Count
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user