440 lines
14 KiB
C#
440 lines
14 KiB
C#
![]() |
|
||
|
using System;
|
||
|
using Godot;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Text;
|
||
|
|
||
|
namespace Rokojori
|
||
|
{
|
||
|
public class RDTextureFormats
|
||
|
{
|
||
|
public enum PixelChannelEncoding
|
||
|
{
|
||
|
Unknown,
|
||
|
|
||
|
uInt8,
|
||
|
sInt8,
|
||
|
|
||
|
uInt16,
|
||
|
sInt16,
|
||
|
sFloat16,
|
||
|
uNorm16,
|
||
|
sNorm16,
|
||
|
|
||
|
uInt32,
|
||
|
sInt32,
|
||
|
sFloat32
|
||
|
}
|
||
|
|
||
|
public static readonly List<PixelChannelEncoding> bits8 = new List<PixelChannelEncoding>()
|
||
|
{
|
||
|
PixelChannelEncoding.uInt8,
|
||
|
PixelChannelEncoding.sInt8
|
||
|
};
|
||
|
|
||
|
public static readonly List<PixelChannelEncoding> bits32 = new List<PixelChannelEncoding>()
|
||
|
{
|
||
|
PixelChannelEncoding.uInt32,
|
||
|
PixelChannelEncoding.sInt32,
|
||
|
PixelChannelEncoding.sFloat32
|
||
|
};
|
||
|
|
||
|
public static int NumBytesFor( PixelChannelEncoding encoding )
|
||
|
{
|
||
|
if ( PixelChannelEncoding.Unknown == encoding )
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if ( bits8.Contains( encoding ) )
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if ( bits32.Contains( encoding ) )
|
||
|
{
|
||
|
return 4;
|
||
|
}
|
||
|
|
||
|
return 2;
|
||
|
}
|
||
|
|
||
|
public static string UsageInfo( RenderingDevice.TextureUsageBits bits )
|
||
|
{
|
||
|
var enums = Enum.GetValues<RenderingDevice.TextureUsageBits>();
|
||
|
|
||
|
var sb = new StringBuilder();
|
||
|
var first = true;
|
||
|
|
||
|
Array.ForEach( enums,
|
||
|
e =>
|
||
|
{
|
||
|
if ( ! BitMath.IsMaskSet( (long)bits, (long)e ) )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( first ){ first = false; }
|
||
|
else { sb.Append( ", " ); }
|
||
|
|
||
|
sb.Append( e + "" );
|
||
|
|
||
|
}
|
||
|
);
|
||
|
|
||
|
return sb.ToString();
|
||
|
}
|
||
|
|
||
|
public const RenderingDevice.TextureUsageBits Usage_Default =
|
||
|
RenderingDevice.TextureUsageBits.SamplingBit |
|
||
|
RenderingDevice.TextureUsageBits.StorageBit |
|
||
|
RenderingDevice.TextureUsageBits.CpuReadBit |
|
||
|
RenderingDevice.TextureUsageBits.CanUpdateBit |
|
||
|
RenderingDevice.TextureUsageBits.CanCopyFromBit |
|
||
|
RenderingDevice.TextureUsageBits.CanCopyToBit;
|
||
|
|
||
|
|
||
|
public static RDTextureFormat DefaultFormat( int w, int h, RenderingDevice.DataFormat dataFormat = RenderingDevice.DataFormat.R16G16B16A16Unorm )
|
||
|
{
|
||
|
var format = new RDTextureFormat();
|
||
|
|
||
|
format.Width = (uint) w;
|
||
|
format.Height = (uint) h;
|
||
|
format.Format = dataFormat;
|
||
|
format.UsageBits = Usage_Default;
|
||
|
|
||
|
return format;
|
||
|
}
|
||
|
|
||
|
public static RDTextureFormat FormatChangeSize( RDTextureFormat tf, Vector2I size )
|
||
|
{
|
||
|
return FormatChangeSize( tf, size.X, size.Y );
|
||
|
}
|
||
|
|
||
|
public static RDTextureFormat FormatChangeSize( RDTextureFormat tf, int w, int h )
|
||
|
{
|
||
|
var clone = FormatCopy( tf );
|
||
|
clone.Width = (uint) w;
|
||
|
clone.Height = (uint) h;
|
||
|
return clone;
|
||
|
}
|
||
|
|
||
|
public static int GetNumPixels( SubViewport viewport )
|
||
|
{
|
||
|
return viewport.Size.X * viewport.Size.Y;
|
||
|
}
|
||
|
|
||
|
public static int GetNumBytes( SubViewport viewport )
|
||
|
{
|
||
|
var numChannels = viewport.TransparentBg ? 4 : 3;
|
||
|
var encoding = viewport.UseHdr2D ? 2 : 1;
|
||
|
|
||
|
return GetNumPixels( viewport ) * numChannels * encoding;
|
||
|
}
|
||
|
|
||
|
public static RenderingDevice.DataFormat GetDataFormat( Viewport viewport )
|
||
|
{
|
||
|
var imageFormat = viewport.GetTexture().GetImage().GetFormat();
|
||
|
return ImageFormatToDataFormat( imageFormat );
|
||
|
}
|
||
|
|
||
|
public static RDTextureFormat FormatCopy( RDTextureFormat tf )
|
||
|
{
|
||
|
var format = new RDTextureFormat();
|
||
|
|
||
|
format.Format = tf.Format;
|
||
|
|
||
|
format.Width = tf.Width;
|
||
|
format.Height = tf.Height;
|
||
|
format.Depth = tf.Depth;
|
||
|
|
||
|
format.ArrayLayers = tf.ArrayLayers;
|
||
|
format.Mipmaps = tf.Mipmaps;
|
||
|
format.TextureType = tf.TextureType;
|
||
|
format.Samples = tf.Samples;
|
||
|
format.UsageBits = tf.UsageBits;
|
||
|
format.IsResolveBuffer = tf.IsResolveBuffer;
|
||
|
format.IsDiscardable = tf.IsDiscardable;
|
||
|
|
||
|
return tf;
|
||
|
|
||
|
}
|
||
|
|
||
|
public static RenderingDevice.DataFormat DataFormat( int channels, PixelChannelEncoding encoding )
|
||
|
{
|
||
|
if ( 1 == channels )
|
||
|
{
|
||
|
return DataFormat_1Channel( encoding );
|
||
|
}
|
||
|
|
||
|
if ( 2 == channels )
|
||
|
{
|
||
|
return DataFormat_2Channels( encoding );
|
||
|
}
|
||
|
|
||
|
if ( 3 == channels )
|
||
|
{
|
||
|
return DataFormat_3Channels( encoding );
|
||
|
}
|
||
|
|
||
|
if ( 4 == channels )
|
||
|
{
|
||
|
return DataFormat_4Channels( encoding );
|
||
|
}
|
||
|
|
||
|
return RenderingDevice.DataFormat.Max;
|
||
|
}
|
||
|
|
||
|
public static RenderingDevice.DataFormat ImageFormatToDataFormat( Image.Format imageFormat )
|
||
|
{
|
||
|
RJLog.Log( "ImageFormatToDataFormat", imageFormat );
|
||
|
|
||
|
switch ( imageFormat )
|
||
|
{
|
||
|
case Image.Format.Rgb8: return RenderingDevice.DataFormat.R8G8B8Uint;
|
||
|
case Image.Format.Rgba8: return RenderingDevice.DataFormat.R8G8B8A8Uint;
|
||
|
case Image.Format.Rgbah: return RenderingDevice.DataFormat.R16G16B16A16Sfloat;
|
||
|
}
|
||
|
|
||
|
return RenderingDevice.DataFormat.Max;
|
||
|
}
|
||
|
|
||
|
public static Image.Format DataFormatToImageFormat( RenderingDevice.DataFormat dataFormat )
|
||
|
{
|
||
|
switch ( dataFormat )
|
||
|
{
|
||
|
case RenderingDevice.DataFormat.R8G8B8A8Uint: return Image.Format.Rgba8;
|
||
|
case RenderingDevice.DataFormat.R8G8B8Uint: return Image.Format.Rgb8;
|
||
|
case RenderingDevice.DataFormat.R16G16B16A16Sfloat: return Image.Format.Rgbah;
|
||
|
}
|
||
|
|
||
|
return Image.Format.Max;
|
||
|
}
|
||
|
|
||
|
public static RenderingDevice.DataFormat DataFormat_1Channel( PixelChannelEncoding encoding )
|
||
|
{
|
||
|
switch ( encoding )
|
||
|
{
|
||
|
case PixelChannelEncoding.uInt8: return RenderingDevice.DataFormat.R8Uint;
|
||
|
}
|
||
|
|
||
|
return RenderingDevice.DataFormat.Max;
|
||
|
}
|
||
|
|
||
|
public static RenderingDevice.DataFormat DataFormat_2Channels( PixelChannelEncoding encoding )
|
||
|
{
|
||
|
switch ( encoding )
|
||
|
{
|
||
|
case PixelChannelEncoding.uInt8: return RenderingDevice.DataFormat.R8Uint;
|
||
|
}
|
||
|
|
||
|
return RenderingDevice.DataFormat.Max;
|
||
|
}
|
||
|
|
||
|
public static RenderingDevice.DataFormat DataFormat_3Channels( PixelChannelEncoding encoding )
|
||
|
{
|
||
|
switch ( encoding )
|
||
|
{
|
||
|
case PixelChannelEncoding.uInt8: return RenderingDevice.DataFormat.R8G8B8Uint;
|
||
|
case PixelChannelEncoding.sInt8: return RenderingDevice.DataFormat.R8G8B8Sint;
|
||
|
|
||
|
case PixelChannelEncoding.uInt16: return RenderingDevice.DataFormat.R16G16B16Uint;
|
||
|
case PixelChannelEncoding.sInt16: return RenderingDevice.DataFormat.R16G16B16Sint;
|
||
|
case PixelChannelEncoding.sFloat16: return RenderingDevice.DataFormat.R16G16B16Sfloat;
|
||
|
case PixelChannelEncoding.uNorm16: return RenderingDevice.DataFormat.R16G16B16Unorm;
|
||
|
case PixelChannelEncoding.sNorm16: return RenderingDevice.DataFormat.R16G16B16Snorm;
|
||
|
|
||
|
case PixelChannelEncoding.uInt32: return RenderingDevice.DataFormat.R32G32B32Uint;
|
||
|
case PixelChannelEncoding.sInt32: return RenderingDevice.DataFormat.R32G32B32Sint;
|
||
|
case PixelChannelEncoding.sFloat32: return RenderingDevice.DataFormat.R32G32B32Sfloat;
|
||
|
|
||
|
}
|
||
|
|
||
|
return RenderingDevice.DataFormat.Max;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
public static RenderingDevice.DataFormat DataFormat_4Channels( PixelChannelEncoding encoding )
|
||
|
{
|
||
|
switch ( encoding )
|
||
|
{
|
||
|
|
||
|
case PixelChannelEncoding.uInt8: return RenderingDevice.DataFormat.R8G8B8A8Uint;
|
||
|
case PixelChannelEncoding.sInt8: return RenderingDevice.DataFormat.R8G8B8A8Sint;
|
||
|
|
||
|
case PixelChannelEncoding.uInt16: return RenderingDevice.DataFormat.R16G16B16A16Uint;
|
||
|
case PixelChannelEncoding.sInt16: return RenderingDevice.DataFormat.R16G16B16A16Sint;
|
||
|
case PixelChannelEncoding.sFloat16: return RenderingDevice.DataFormat.R16G16B16A16Sfloat;
|
||
|
case PixelChannelEncoding.uNorm16: return RenderingDevice.DataFormat.R16G16B16A16Unorm;
|
||
|
case PixelChannelEncoding.sNorm16: return RenderingDevice.DataFormat.R16G16B16A16Snorm;
|
||
|
|
||
|
case PixelChannelEncoding.uInt32: return RenderingDevice.DataFormat.R32G32B32A32Uint;
|
||
|
case PixelChannelEncoding.sInt32: return RenderingDevice.DataFormat.R32G32B32A32Sint;
|
||
|
case PixelChannelEncoding.sFloat32: return RenderingDevice.DataFormat.R32G32B32A32Sfloat;
|
||
|
|
||
|
}
|
||
|
|
||
|
return RenderingDevice.DataFormat.Max;
|
||
|
}
|
||
|
|
||
|
// m: case ((?:\w|\.)*): return ((?:\w|\.)*);
|
||
|
// r: case $2: return $1;
|
||
|
|
||
|
public static PixelChannelEncoding GetPixelChannelEncoding( RenderingDevice.DataFormat format )
|
||
|
{
|
||
|
switch ( format )
|
||
|
{
|
||
|
case RenderingDevice.DataFormat.R8G8B8Sint: return PixelChannelEncoding.sInt8;
|
||
|
|
||
|
case RenderingDevice.DataFormat.R16G16B16Uint: return PixelChannelEncoding.uInt16;
|
||
|
case RenderingDevice.DataFormat.R16G16B16Sint: return PixelChannelEncoding.sInt16;
|
||
|
case RenderingDevice.DataFormat.R16G16B16Sfloat: return PixelChannelEncoding.sFloat16;
|
||
|
case RenderingDevice.DataFormat.R16G16B16Unorm: return PixelChannelEncoding.uNorm16;
|
||
|
case RenderingDevice.DataFormat.R16G16B16Snorm: return PixelChannelEncoding.sNorm16;
|
||
|
|
||
|
case RenderingDevice.DataFormat.R32G32B32Uint: return PixelChannelEncoding.uInt32;
|
||
|
case RenderingDevice.DataFormat.R32G32B32Sint: return PixelChannelEncoding.sInt32;
|
||
|
case RenderingDevice.DataFormat.R32G32B32Sfloat: return PixelChannelEncoding.sFloat32;
|
||
|
|
||
|
case RenderingDevice.DataFormat.R8G8B8A8Uint: return PixelChannelEncoding.uInt8;
|
||
|
case RenderingDevice.DataFormat.R8G8B8A8Sint: return PixelChannelEncoding.sInt8;
|
||
|
|
||
|
case RenderingDevice.DataFormat.R16G16B16A16Uint: return PixelChannelEncoding.uInt16;
|
||
|
case RenderingDevice.DataFormat.R16G16B16A16Sint: return PixelChannelEncoding.sInt16;
|
||
|
case RenderingDevice.DataFormat.R16G16B16A16Sfloat: return PixelChannelEncoding.sFloat16;
|
||
|
case RenderingDevice.DataFormat.R16G16B16A16Unorm: return PixelChannelEncoding.uNorm16;
|
||
|
case RenderingDevice.DataFormat.R16G16B16A16Snorm: return PixelChannelEncoding.sNorm16;
|
||
|
|
||
|
case RenderingDevice.DataFormat.R32G32B32A32Uint: return PixelChannelEncoding.uInt32;
|
||
|
case RenderingDevice.DataFormat.R32G32B32A32Sint: return PixelChannelEncoding.sInt32;
|
||
|
case RenderingDevice.DataFormat.R32G32B32A32Sfloat: return PixelChannelEncoding.sFloat32;
|
||
|
}
|
||
|
|
||
|
return PixelChannelEncoding.Unknown;
|
||
|
}
|
||
|
|
||
|
public static int GetNumChannels( RenderingDevice.DataFormat format )
|
||
|
{
|
||
|
switch ( format )
|
||
|
{
|
||
|
case RenderingDevice.DataFormat.R8G8B8Sint:
|
||
|
|
||
|
case RenderingDevice.DataFormat.R16G16B16Uint:
|
||
|
case RenderingDevice.DataFormat.R16G16B16Sint:
|
||
|
case RenderingDevice.DataFormat.R16G16B16Sfloat:
|
||
|
case RenderingDevice.DataFormat.R16G16B16Unorm:
|
||
|
case RenderingDevice.DataFormat.R16G16B16Snorm:
|
||
|
|
||
|
case RenderingDevice.DataFormat.R32G32B32Uint:
|
||
|
case RenderingDevice.DataFormat.R32G32B32Sint:
|
||
|
case RenderingDevice.DataFormat.R32G32B32Sfloat:
|
||
|
|
||
|
return 3;
|
||
|
|
||
|
case RenderingDevice.DataFormat.R8G8B8A8Uint:
|
||
|
case RenderingDevice.DataFormat.R8G8B8A8Sint:
|
||
|
|
||
|
case RenderingDevice.DataFormat.R16G16B16A16Uint:
|
||
|
case RenderingDevice.DataFormat.R16G16B16A16Sint:
|
||
|
case RenderingDevice.DataFormat.R16G16B16A16Sfloat:
|
||
|
case RenderingDevice.DataFormat.R16G16B16A16Unorm:
|
||
|
case RenderingDevice.DataFormat.R16G16B16A16Snorm:
|
||
|
|
||
|
case RenderingDevice.DataFormat.R32G32B32A32Uint:
|
||
|
case RenderingDevice.DataFormat.R32G32B32A32Sint:
|
||
|
case RenderingDevice.DataFormat.R32G32B32A32Sfloat:
|
||
|
return 4;
|
||
|
}
|
||
|
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
static void WriteUShort( ushort shortValue, byte[] output, int offset )
|
||
|
{
|
||
|
output[ offset + 0 ] = (byte)(shortValue & 0xFF);
|
||
|
output[ offset + 1 ] = (byte)((shortValue >> 8) & 0xFF);
|
||
|
}
|
||
|
|
||
|
static void WriteUNorm( float value, byte[] output, int offset )
|
||
|
{
|
||
|
var shortValue = (ushort)( Mathf.Clamp( value, 0.0f, 1.0f ) * 65535 );
|
||
|
WriteUShort( shortValue, output, offset );
|
||
|
}
|
||
|
|
||
|
static ushort FloatToHalf( float value )
|
||
|
{
|
||
|
uint fbits = BitConverter.SingleToUInt32Bits(value);
|
||
|
|
||
|
uint sign = (fbits >> 16) & 0x8000;
|
||
|
uint val = (fbits & 0x7FFFFFFF);
|
||
|
|
||
|
// NaN / Inf -> maximal darstellen
|
||
|
if ( val > 0x47FFEFFF )
|
||
|
{
|
||
|
return (ushort)(sign | 0x7FFF);
|
||
|
}
|
||
|
|
||
|
if ( val < 0x38800000) // Subnormal
|
||
|
{
|
||
|
uint mant = (val & 0x007FFFFF) | 0x00800000;
|
||
|
int exp = 113 - (int)(val >> 23);
|
||
|
mant = (mant >> exp);
|
||
|
|
||
|
return (ushort)(sign | (mant >> 13));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
uint exp = (val >> 23) - 112;
|
||
|
uint mant = (val & 0x007FFFFF);
|
||
|
return (ushort)(sign | (exp << 10) | (mant >> 13));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void WriteFloat16( float value, byte[] output, int offset )
|
||
|
{
|
||
|
ushort r = FloatToHalf( value );
|
||
|
WriteUShort( r, output, offset );
|
||
|
}
|
||
|
|
||
|
public static byte[] ColorToBytes( Color color, RenderingDevice.DataFormat format )
|
||
|
{
|
||
|
switch ( format )
|
||
|
{
|
||
|
case RenderingDevice.DataFormat.R8G8B8A8Uint:
|
||
|
{
|
||
|
var bytes = new byte[ 4 ];
|
||
|
bytes[ 0 ] = (byte) ( color.R * 255 );
|
||
|
bytes[ 1 ] = (byte) ( color.G * 255 );
|
||
|
bytes[ 2 ] = (byte) ( color.B * 255 );
|
||
|
bytes[ 3 ] = (byte) ( color.A * 255 );
|
||
|
return bytes;
|
||
|
}
|
||
|
|
||
|
case RenderingDevice.DataFormat.R16G16B16A16Unorm:
|
||
|
{
|
||
|
var bytes = new byte[ 8 ];
|
||
|
WriteUNorm( color.R, bytes, 0 );
|
||
|
WriteUNorm( color.G, bytes, 2 );
|
||
|
WriteUNorm( color.B, bytes, 4 );
|
||
|
WriteUNorm( color.A, bytes, 6 );
|
||
|
return bytes;
|
||
|
}
|
||
|
|
||
|
case RenderingDevice.DataFormat.R16G16B16A16Sfloat:
|
||
|
{
|
||
|
var bytes = new byte[ 8 ];
|
||
|
WriteFloat16( color.R, bytes, 0 );
|
||
|
WriteFloat16( color.G, bytes, 2 );
|
||
|
WriteFloat16( color.B, bytes, 4 );
|
||
|
WriteFloat16( color.A, bytes, 6 );
|
||
|
return bytes;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
}
|