mirror of
https://github.com/AssetRipper/AssetRipper.git
synced 2025-12-11 20:15:29 +01:00
562 lines
21 KiB
C#
562 lines
21 KiB
C#
using AssetRipper.Export.UnityProjects.Textures;
|
|
using AssetRipper.Import.Logging;
|
|
using AssetRipper.SourceGenerated.Classes.ClassID_117;
|
|
using AssetRipper.SourceGenerated.Classes.ClassID_187;
|
|
using AssetRipper.SourceGenerated.Classes.ClassID_188;
|
|
using AssetRipper.SourceGenerated.Classes.ClassID_189;
|
|
using AssetRipper.SourceGenerated.Classes.ClassID_28;
|
|
using AssetRipper.SourceGenerated.Classes.ClassID_89;
|
|
using AssetRipper.SourceGenerated.Enums;
|
|
using AssetRipper.SourceGenerated.Extensions;
|
|
using AssetRipper.TextureDecoder.Astc;
|
|
using AssetRipper.TextureDecoder.Atc;
|
|
using AssetRipper.TextureDecoder.Bc;
|
|
using AssetRipper.TextureDecoder.Dxt;
|
|
using AssetRipper.TextureDecoder.Etc;
|
|
using AssetRipper.TextureDecoder.Pvrtc;
|
|
using AssetRipper.TextureDecoder.Rgb;
|
|
using AssetRipper.TextureDecoder.Rgb.Formats;
|
|
using AssetRipper.TextureDecoder.Yuy2;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
namespace AssetRipper.Export.Modules.Textures;
|
|
|
|
public static class TextureConverter
|
|
{
|
|
public static bool TryConvertToBitmap(IImageTexture texture, out DirectBitmap bitmap)
|
|
{
|
|
return texture switch
|
|
{
|
|
ICubemapArray cubemapArray => TryConvertToBitmap(cubemapArray, out bitmap),
|
|
ITexture2DArray texture2DArray => TryConvertToBitmap(texture2DArray, out bitmap),
|
|
ITexture3D texture3D => TryConvertToBitmap(texture3D, out bitmap),
|
|
ITexture2D texture2D => TryConvertToBitmap(texture2D, out bitmap),
|
|
_ => ReturnFalse(out bitmap),
|
|
};
|
|
|
|
static bool ReturnFalse(out DirectBitmap bitmap)
|
|
{
|
|
bitmap = DirectBitmap.Empty;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static bool TryConvertToBitmap(ITexture3D texture, out DirectBitmap bitmap)
|
|
{
|
|
byte[] buffer = texture.GetImageData();
|
|
if (buffer.Length == 0)
|
|
{
|
|
bitmap = DirectBitmap.Empty;
|
|
return false;
|
|
}
|
|
|
|
if (!TryGetTextureFormat((GraphicsFormat)texture.Format, out TextureFormat format))
|
|
{
|
|
bitmap = DirectBitmap.Empty;
|
|
return false;
|
|
}
|
|
|
|
if (!TryConvertToBitmap(
|
|
format,
|
|
texture.Width,
|
|
texture.Height,
|
|
texture.Depth,
|
|
texture.GetCompleteImageSize(),
|
|
texture.Collection.Version,
|
|
buffer,
|
|
out bitmap))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bitmap.FlipY();
|
|
|
|
// despite the name, this packing works for different formats
|
|
if (texture.LightmapFormatE == TextureUsageMode.NormalmapDXT5nm)
|
|
{
|
|
UnpackNormal(bitmap.Bits);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static bool TryConvertToBitmap(ITexture2DArray texture, out DirectBitmap bitmap)
|
|
{
|
|
byte[] buffer = texture.GetImageData();
|
|
if (buffer.Length == 0)
|
|
{
|
|
bitmap = DirectBitmap.Empty;
|
|
return false;
|
|
}
|
|
|
|
if (!TryGetTextureFormat((GraphicsFormat)texture.Format, out TextureFormat format))
|
|
{
|
|
bitmap = DirectBitmap.Empty;
|
|
return false;
|
|
}
|
|
|
|
if (!TryConvertToBitmap(
|
|
format,
|
|
texture.Width,
|
|
texture.Height,
|
|
texture.Depth,
|
|
texture.GetCompleteImageSize(),
|
|
texture.Collection.Version,
|
|
buffer,
|
|
out bitmap))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bitmap.FlipY();
|
|
|
|
return true;
|
|
}
|
|
|
|
public static bool TryConvertToBitmap(ICubemapArray texture, out DirectBitmap bitmap)
|
|
{
|
|
byte[] buffer = texture.GetImageData();
|
|
if (buffer.Length == 0)
|
|
{
|
|
bitmap = DirectBitmap.Empty;
|
|
return false;
|
|
}
|
|
|
|
if (!TryGetTextureFormat((GraphicsFormat)texture.Format, out TextureFormat format))
|
|
{
|
|
bitmap = DirectBitmap.Empty;
|
|
return false;
|
|
}
|
|
|
|
if (!TryConvertToBitmap(
|
|
format,
|
|
texture.Width,
|
|
texture.GetHeight(),
|
|
texture.GetDepth(),
|
|
texture.GetCompleteImageSize(),
|
|
texture.Collection.Version,
|
|
buffer,
|
|
out bitmap))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bitmap.FlipY();// Maybe not needed?
|
|
|
|
return true;
|
|
}
|
|
|
|
public static bool TryConvertToBitmap(ITexture2D texture, out DirectBitmap bitmap)
|
|
{
|
|
byte[] buffer = texture.GetImageData();
|
|
if (buffer.Length == 0)
|
|
{
|
|
bitmap = DirectBitmap.Empty;
|
|
return false;
|
|
}
|
|
|
|
if (!TryConvertToBitmap(
|
|
texture.Format_C28E,
|
|
texture.Width_C28,
|
|
texture.Height_C28,
|
|
texture.ImageCount_C28,
|
|
texture.ActualImageSize,
|
|
texture.Collection.Version,
|
|
buffer,
|
|
out bitmap))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// cubemaps dont need flipping, for some reason
|
|
if (texture is not ICubemap)
|
|
{
|
|
bitmap.FlipY();
|
|
}
|
|
|
|
// despite the name, this packing works for different formats
|
|
if (texture.LightmapFormat_C28E == TextureUsageMode.NormalmapDXT5nm)
|
|
{
|
|
UnpackNormal(bitmap.Bits);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private static bool TryConvertToBitmap(
|
|
TextureFormat textureFormat,
|
|
int width,
|
|
int height,
|
|
int depth,
|
|
int imageSize,
|
|
UnityVersion version,
|
|
byte[] data,
|
|
out DirectBitmap bitmap)
|
|
{
|
|
return textureFormat switch
|
|
{
|
|
TextureFormat.Alpha8 => TryConvertToBitmap<ColorA<byte>, byte>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.ARGB4444 => TryConvertToBitmap<ColorARGB16, byte>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.RGB24 => TryConvertToBitmap<ColorRGB<byte>, byte>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.RGBA32 => TryConvertToBitmap<ColorRGBA<byte>, byte>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.ARGB32 => TryConvertToBitmap<ColorARGB<byte>, byte>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.ARGBFloat => TryConvertToBitmap<ColorARGB<float>, float>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.RGB565 => TryConvertToBitmap<ColorRGB16, byte>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.BGR24 => TryConvertToBitmap<ColorBGR<byte>, byte>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.R16 => TryConvertToBitmap<ColorR<ushort>, ushort>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.RGBA4444 => TryConvertToBitmap<ColorRGBA16, byte>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.BGRA32_14 or TextureFormat.BGRA32_37 => TryConvertToBitmap<ColorBGRA<byte>, byte>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.RHalf => TryConvertToBitmap<ColorR<Half>, Half>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.RGHalf => TryConvertToBitmap<ColorRG<Half>, Half>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.RGBAHalf => TryConvertToBitmap<ColorRGBA<Half>, Half>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.RFloat => TryConvertToBitmap<ColorR<float>, float>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.RGFloat => TryConvertToBitmap<ColorRG<float>, float>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.RGBAFloat => TryConvertToBitmap<ColorRGBA<float>, float>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.RGB9e5Float => TryConvertToBitmap<ColorRGB9e5, double>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.RG16 => TryConvertToBitmap<ColorRG<byte>, byte>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.R8 => TryConvertToBitmap<ColorR<byte>, byte>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.RG32 => TryConvertToBitmap<ColorRG<ushort>, ushort>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.RGB48 => TryConvertToBitmap<ColorRGB<ushort>, ushort>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.RGBA64 => TryConvertToBitmap<ColorRGBA<ushort>, ushort>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.R8_SIGNED => TryConvertToBitmap<ColorR<sbyte>, sbyte>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.RG16_SIGNED => TryConvertToBitmap<ColorRG<sbyte>, sbyte>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.RGB24_SIGNED => TryConvertToBitmap<ColorRGB<sbyte>, sbyte>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.RGBA32_SIGNED => TryConvertToBitmap<ColorRGBA<sbyte>, sbyte>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.R16_SIGNED => TryConvertToBitmap<ColorR<short>, short>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.RG32_SIGNED => TryConvertToBitmap<ColorRG<short>, short>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.RGB48_SIGNED => TryConvertToBitmap<ColorRGB<short>, short>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
TextureFormat.RGBA64_SIGNED => TryConvertToBitmap<ColorRGBA<short>, short>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
_ => TryConvertToBitmap<ColorRGBA<byte>, byte>(textureFormat, width, height, depth, imageSize, version, data, out bitmap),
|
|
};
|
|
}
|
|
|
|
private static bool TryConvertToBitmap<TColor, TChannelValue>(
|
|
TextureFormat textureFormat,
|
|
int width,
|
|
int height,
|
|
int depth,
|
|
int imageSize,
|
|
UnityVersion version,
|
|
byte[] data,
|
|
out DirectBitmap bitmap)
|
|
where TColor : unmanaged, IColor<TChannelValue>
|
|
where TChannelValue : unmanaged
|
|
{
|
|
if (width <= 0 || height <= 0 || depth <= 0)
|
|
{
|
|
Logger.Log(LogType.Error, LogCategory.Export, $"Invalid texture dimensions. Width: {width}, Height: {height}, Depth: {depth}.");
|
|
bitmap = DirectBitmap.Empty;
|
|
return false;
|
|
}
|
|
|
|
if (1L * width * height * depth * Unsafe.SizeOf<TColor>() > int.MaxValue)
|
|
{
|
|
Logger.Log(LogType.Error, LogCategory.Export, $"Texture size is too large. Width: {width}, Height: {height}, Depth: {depth}.");
|
|
bitmap = DirectBitmap.Empty;
|
|
return false;
|
|
}
|
|
|
|
ReadOnlySpan<byte> uncompressedSpan;
|
|
int bytesPerLayer;
|
|
if (textureFormat.IsCrunched())
|
|
{
|
|
if (CrunchHandler.DecompressCrunch(textureFormat, version, data, out byte[]? decompressedData))
|
|
{
|
|
uncompressedSpan = decompressedData;
|
|
bytesPerLayer = decompressedData.Length / depth;
|
|
}
|
|
else
|
|
{
|
|
bitmap = DirectBitmap.Empty;
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (data.Length == imageSize)
|
|
{
|
|
// This can happen for Texture3D
|
|
// For mips, all 3 dimensions get halved with each mip level, unlike Texture2DArray.
|
|
// https://github.com/AssetRipper/AssetRipper/issues/1886
|
|
bytesPerLayer = -1;
|
|
}
|
|
else if (data.Length < (long)imageSize * depth)
|
|
{
|
|
Logger.Log(LogType.Error, LogCategory.Export, $"Image data length {data.Length} is less than expected {(long)imageSize * depth}. Width: {width}, Height: {height}, Depth: {depth}, Image Size: {imageSize}, Format {textureFormat}.");
|
|
bitmap = DirectBitmap.Empty;
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
bytesPerLayer = imageSize;
|
|
}
|
|
uncompressedSpan = data;
|
|
}
|
|
|
|
bitmap = new DirectBitmap<TColor, TChannelValue>(width, height, depth);
|
|
int outputSize = width * height * bitmap.PixelSize;
|
|
int inputOffset = 0;
|
|
for (int i = 0; i < depth; i++)
|
|
{
|
|
ReadOnlySpan<byte> inputSpan = uncompressedSpan.Slice(inputOffset, int.Max(uncompressedSpan.Length - inputOffset, bytesPerLayer));
|
|
Span<byte> outputSpan = bitmap.Bits.Slice(i * outputSize, outputSize);
|
|
|
|
int bytesRead = DecodeTexture<TColor, TChannelValue>(textureFormat, width, height, inputSpan, outputSpan);
|
|
if (bytesRead < 0)
|
|
{
|
|
bitmap = DirectBitmap.Empty;
|
|
return false;
|
|
}
|
|
|
|
inputOffset += bytesPerLayer > 0 ? bytesPerLayer : bytesRead;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private static int DecodeTexture<TColor, TChannelValue>(TextureFormat textureFormat, int width, int height, ReadOnlySpan<byte> inputSpan, Span<byte> outputSpan)
|
|
where TColor : unmanaged, IColor<TChannelValue>
|
|
where TChannelValue : unmanaged
|
|
{
|
|
switch (textureFormat)
|
|
{
|
|
//ASTC
|
|
case TextureFormat.ASTC_RGB_4x4:
|
|
case TextureFormat.ASTC_RGBA_4x4:
|
|
return AstcDecoder.DecodeASTC<TColor, TChannelValue>(inputSpan, width, height, 4, 4, outputSpan);
|
|
|
|
case TextureFormat.ASTC_RGB_5x5:
|
|
case TextureFormat.ASTC_RGBA_5x5:
|
|
return AstcDecoder.DecodeASTC<TColor, TChannelValue>(inputSpan, width, height, 5, 5, outputSpan);
|
|
|
|
case TextureFormat.ASTC_RGB_6x6:
|
|
case TextureFormat.ASTC_RGBA_6x6:
|
|
return AstcDecoder.DecodeASTC<TColor, TChannelValue>(inputSpan, width, height, 6, 6, outputSpan);
|
|
|
|
case TextureFormat.ASTC_RGB_8x8:
|
|
case TextureFormat.ASTC_RGBA_8x8:
|
|
return AstcDecoder.DecodeASTC<TColor, TChannelValue>(inputSpan, width, height, 8, 8, outputSpan);
|
|
|
|
case TextureFormat.ASTC_RGB_10x10:
|
|
case TextureFormat.ASTC_RGBA_10x10:
|
|
return AstcDecoder.DecodeASTC<TColor, TChannelValue>(inputSpan, width, height, 10, 10, outputSpan);
|
|
|
|
case TextureFormat.ASTC_RGB_12x12:
|
|
case TextureFormat.ASTC_RGBA_12x12:
|
|
return AstcDecoder.DecodeASTC<TColor, TChannelValue>(inputSpan, width, height, 12, 12, outputSpan);
|
|
|
|
//ATC
|
|
case TextureFormat.ATC_RGB4:
|
|
return AtcDecoder.DecompressAtcRgb4<TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.ATC_RGBA8:
|
|
return AtcDecoder.DecompressAtcRgba8<TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
//BC
|
|
case TextureFormat.BC4:
|
|
return Bc4.Decompress<TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.BC5:
|
|
return Bc5.Decompress<TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.BC6H:
|
|
return Bc6h.Decompress<TColor, TChannelValue>(inputSpan, width, height, false, outputSpan);
|
|
|
|
case TextureFormat.BC7:
|
|
return Bc7.Decompress<TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
//DXT
|
|
case TextureFormat.DXT1:
|
|
case TextureFormat.DXT1Crunched:
|
|
return DxtDecoder.DecompressDXT1<TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.DXT3:
|
|
return DxtDecoder.DecompressDXT3<TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.DXT5:
|
|
case TextureFormat.DXT5Crunched:
|
|
return DxtDecoder.DecompressDXT5<TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
//ETC
|
|
case TextureFormat.ETC_RGB4:
|
|
case TextureFormat.ETC_RGB4_3DS:
|
|
case TextureFormat.ETC_RGB4Crunched:
|
|
return EtcDecoder.DecompressETC<TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.EAC_R:
|
|
return EtcDecoder.DecompressEACRUnsigned<TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.EAC_R_SIGNED:
|
|
return EtcDecoder.DecompressEACRSigned<TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.EAC_RG:
|
|
return EtcDecoder.DecompressEACRGUnsigned<TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.EAC_RG_SIGNED:
|
|
return EtcDecoder.DecompressEACRGSigned<TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.ETC2_RGB:
|
|
return EtcDecoder.DecompressETC2<TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.ETC2_RGBA1:
|
|
return EtcDecoder.DecompressETC2A1<TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.ETC2_RGBA8:
|
|
case TextureFormat.ETC_RGBA8_3DS:
|
|
case TextureFormat.ETC2_RGBA8Crunched:
|
|
return EtcDecoder.DecompressETC2A8<TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
//PVRTC
|
|
case TextureFormat.PVRTC_RGB2:
|
|
case TextureFormat.PVRTC_RGBA2:
|
|
return PvrtcDecoder.DecompressPVRTC<TColor, TChannelValue>(inputSpan, width, height, true, outputSpan);
|
|
|
|
case TextureFormat.PVRTC_RGB4:
|
|
case TextureFormat.PVRTC_RGBA4:
|
|
return PvrtcDecoder.DecompressPVRTC<TColor, TChannelValue>(inputSpan, width, height, false, outputSpan);
|
|
|
|
//YUY2
|
|
case TextureFormat.YUY2:
|
|
return Yuy2Decoder.DecompressYUY2<TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
//RGB
|
|
case TextureFormat.Alpha8:
|
|
return RgbConverter.Convert<ColorA<byte>, byte, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.ARGB4444:
|
|
return RgbConverter.Convert<ColorARGB16, byte, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.RGBA4444:
|
|
return RgbConverter.Convert<ColorRGBA16, byte, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.RGB565:
|
|
return RgbConverter.Convert<ColorRGB16, byte, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.R8:
|
|
return RgbConverter.Convert<ColorR<byte>, byte, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.RG16:
|
|
return RgbConverter.Convert<ColorRG<byte>, byte, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.RGB24:
|
|
return RgbConverter.Convert<ColorRGB<byte>, byte, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.RGBA32:
|
|
return RgbConverter.Convert<ColorRGBA<byte>, byte, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.ARGB32:
|
|
return RgbConverter.Convert<ColorARGB<byte>, byte, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.ARGBFloat:
|
|
return RgbConverter.Convert<ColorARGB<float>, float, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.BGR24:
|
|
return RgbConverter.Convert<ColorBGR<byte>, byte, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.BGRA32_14:
|
|
case TextureFormat.BGRA32_37:
|
|
return RgbConverter.Convert<ColorBGRA<byte>, byte, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.R16:
|
|
return RgbConverter.Convert<ColorR<ushort>, ushort, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.RG32:
|
|
return RgbConverter.Convert<ColorRG<ushort>, ushort, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.RGB48:
|
|
return RgbConverter.Convert<ColorRGB<ushort>, ushort, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.RGBA64:
|
|
return RgbConverter.Convert<ColorRGBA<ushort>, ushort, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.RHalf:
|
|
return RgbConverter.Convert<ColorR<Half>, Half, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.RGHalf:
|
|
return RgbConverter.Convert<ColorRG<Half>, Half, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.RGBAHalf:
|
|
return RgbConverter.Convert<ColorRGBA<Half>, Half, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.RFloat:
|
|
return RgbConverter.Convert<ColorR<float>, float, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.RGFloat:
|
|
return RgbConverter.Convert<ColorRG<float>, float, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.RGBAFloat:
|
|
return RgbConverter.Convert<ColorRGBA<float>, float, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.RGB9e5Float:
|
|
return RgbConverter.Convert<ColorRGB9e5, double, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.R8_SIGNED:
|
|
return RgbConverter.Convert<ColorR<sbyte>, sbyte, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.RG16_SIGNED:
|
|
return RgbConverter.Convert<ColorRG<sbyte>, sbyte, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.RGB24_SIGNED:
|
|
return RgbConverter.Convert<ColorRGB<sbyte>, sbyte, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.RGBA32_SIGNED:
|
|
return RgbConverter.Convert<ColorRGBA<sbyte>, sbyte, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.R16_SIGNED:
|
|
return RgbConverter.Convert<ColorR<short>, short, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.RG32_SIGNED:
|
|
return RgbConverter.Convert<ColorRG<short>, short, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.RGB48_SIGNED:
|
|
return RgbConverter.Convert<ColorRGB<short>, short, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
case TextureFormat.RGBA64_SIGNED:
|
|
return RgbConverter.Convert<ColorRGBA<short>, short, TColor, TChannelValue>(inputSpan, width, height, outputSpan);
|
|
|
|
default:
|
|
Logger.Log(LogType.Error, LogCategory.Export, $"Unsupported texture format '{textureFormat}'");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
private static bool TryGetTextureFormat(GraphicsFormat graphicsFormat, out TextureFormat format)
|
|
{
|
|
try
|
|
{
|
|
format = graphicsFormat.ToTextureFormat();
|
|
return true;
|
|
}
|
|
catch (NotSupportedException)
|
|
{
|
|
format = default;
|
|
return false;
|
|
}
|
|
catch (ArgumentOutOfRangeException)
|
|
{
|
|
Logger.Log(LogType.Error, LogCategory.Export, $"Unknown GraphicsFormat '{(int)graphicsFormat}'");
|
|
format = default;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static void UnpackNormal(Span<byte> data)
|
|
{
|
|
for (int i = 0; i < data.Length; i += 4)
|
|
{
|
|
Span<byte> pixelSpan = data.Slice(i, 4);
|
|
byte r = pixelSpan[3];
|
|
byte g = pixelSpan[1];
|
|
byte a = pixelSpan[2];
|
|
pixelSpan[2] = r;
|
|
pixelSpan[3] = a;
|
|
|
|
const double MagnitudeSqr = 255 * 255;
|
|
double vr = r * 2.0 - 255.0;
|
|
double vg = g * 2.0 - 255.0;
|
|
double hypotenuseSqr = Math.Min(vr * vr + vg * vg, MagnitudeSqr);
|
|
double b = (Math.Sqrt(MagnitudeSqr - hypotenuseSqr) + 255.0) / 2.0;
|
|
pixelSpan[0] = (byte)b;
|
|
}
|
|
}
|
|
}
|