rj-action-library/Runtime/Rendering/Objects/RDTextureFormats.cs

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