Setup entry point + integrated moonworks stuff
This commit is contained in:
.idea/.idea.Nerfed/.idea
Libraries
Nerfed.Runtime
Assert.cs
Audio
AudioBuffer.csAudioDataOgg.csAudioDataQoa.csAudioDataStreamable.csAudioDataWav.csAudioDevice.csAudioEmitter.csAudioListener.csAudioResource.csFilterType.csFormat.csIPoolable.csPersistentVoice.csReverbEffect.csSoundSequence.csSoundState.csSourceVoice.csSourceVoicePool.csStreamingVoice.csSubmixVoice.csTransientVoice.csUpdatingSourceVoice.csVoice.cs
Engine.csFrameLimiterSettings.csGraphics
Color.csCommandBuffer.csCommandBufferPool.csComputePass.csComputePassPool.csCopyPass.csCopyPassPool.csEmbeddedShadersSpirV.csFencePool.cs
Font
GraphicsDevice.csGraphicsResource.csIEmbeddedShaders.csIVertexType.csImageUtils.csPackedVector
Alpha8.csBgr565.csBgra4444.csBgra5551.csByte4.csHalfSingle.csHalfTypeHelper.csHalfVector2.csHalfVector4.csIPackedVector.csNormalizedByte2.csNormalizedByte4.csNormalizedShort2.csNormalizedShort4.csRg32.csRgba1010102.csRgba64.csShort2.csShort4.cs
RefreshResource.csRefreshTypes.csRenderPass.csRenderPassPool.csResourceUploader.csResources
Buffer.csComputePipeline.csFence.csGraphicsPipeline.csSampler.csShader.csTexture.csTransferBuffer.cs
StockShaders
Input
Interop
Log.csNerfed.Runtime.csprojProfiler.csProgram.csStorage
Util
Video
Window
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;
|
||||
}
|
Reference in New Issue
Block a user