Fix and improve Texture2D convert

This commit is contained in:
Perfare 2022-03-22 01:00:20 +08:00
parent 7d3a4a10fc
commit b1205808e2
4 changed files with 103 additions and 36 deletions

View File

@ -154,7 +154,8 @@ namespace AssetStudio
RGB565 = 7, RGB565 = 7,
R16 = 9, R16 = 9,
DXT1, DXT1,
DXT5 = 12, DXT3,
DXT5,
RGBA4444, RGBA4444,
BGRA32, BGRA32,
RHalf, RHalf,
@ -165,11 +166,11 @@ namespace AssetStudio
RGBAFloat, RGBAFloat,
YUY2, YUY2,
RGB9e5Float, RGB9e5Float,
BC4 = 26,
BC5,
BC6H = 24, BC6H = 24,
BC7, BC7,
DXT1Crunched = 28, BC4,
BC5,
DXT1Crunched,
DXT5Crunched, DXT5Crunched,
PVRTC_RGB2, PVRTC_RGB2,
PVRTC_RGBA2, PVRTC_RGBA2,

View File

@ -759,7 +759,7 @@ namespace AssetStudioGUI
var image = m_Texture2D.ConvertToImage(true); var image = m_Texture2D.ConvertToImage(true);
if (image != null) if (image != null)
{ {
var bitmap = new DirectBitmap(image.ConvertToBgra32Bytes(), m_Texture2D.m_Width, m_Texture2D.m_Height); var bitmap = new DirectBitmap(image.ConvertToBytes(), m_Texture2D.m_Width, m_Texture2D.m_Height);
image.Dispose(); image.Dispose();
assetItem.InfoText = $"Width: {m_Texture2D.m_Width}\nHeight: {m_Texture2D.m_Height}\nFormat: {m_Texture2D.m_TextureFormat}"; assetItem.InfoText = $"Width: {m_Texture2D.m_Width}\nHeight: {m_Texture2D.m_Height}\nFormat: {m_Texture2D.m_TextureFormat}";
switch (m_Texture2D.m_TextureSettings.m_FilterMode) switch (m_Texture2D.m_TextureSettings.m_FilterMode)
@ -1167,7 +1167,7 @@ namespace AssetStudioGUI
var image = m_Sprite.GetImage(); var image = m_Sprite.GetImage();
if (image != null) if (image != null)
{ {
var bitmap = new DirectBitmap(image.ConvertToBgra32Bytes(), image.Width, image.Height); var bitmap = new DirectBitmap(image.ConvertToBytes(), image.Width, image.Height);
image.Dispose(); image.Dispose();
assetItem.InfoText = $"Width: {bitmap.Width}\nHeight: {bitmap.Height}\n"; assetItem.InfoText = $"Width: {bitmap.Width}\nHeight: {bitmap.Height}\n";
PreviewTexture(bitmap); PreviewTexture(bitmap);

View File

@ -43,7 +43,7 @@ namespace AssetStudio
return stream; return stream;
} }
public static byte[] ConvertToBgra32Bytes(this Image<Bgra32> image) public static byte[] ConvertToBytes<TPixel>(this Image<TPixel> image) where TPixel : unmanaged, IPixel<TPixel>
{ {
if (image.TryGetSinglePixelSpan(out var pixelSpan)) if (image.TryGetSinglePixelSpan(out var pixelSpan))
{ {

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Runtime.CompilerServices;
using Texture2DDecoder; using Texture2DDecoder;
namespace AssetStudio namespace AssetStudio
@ -11,6 +12,7 @@ namespace AssetStudio
private TextureFormat m_TextureFormat; private TextureFormat m_TextureFormat;
private int[] version; private int[] version;
private BuildTarget platform; private BuildTarget platform;
private int outPutSize;
public Texture2DConverter(Texture2D m_Texture2D) public Texture2DConverter(Texture2D m_Texture2D)
{ {
@ -20,6 +22,7 @@ namespace AssetStudio
m_TextureFormat = m_Texture2D.m_TextureFormat; m_TextureFormat = m_Texture2D.m_TextureFormat;
version = m_Texture2D.version; version = m_Texture2D.version;
platform = m_Texture2D.platform; platform = m_Texture2D.platform;
outPutSize = m_Width * m_Height * 4;
} }
public bool DecodeTexture2D(byte[] bytes) public bool DecodeTexture2D(byte[] bytes)
@ -60,6 +63,8 @@ namespace AssetStudio
SwapBytesForXbox(buff); SwapBytesForXbox(buff);
flag = DecodeDXT1(buff, bytes); flag = DecodeDXT1(buff, bytes);
break; break;
case TextureFormat.DXT3:
break;
case TextureFormat.DXT5: //test pass case TextureFormat.DXT5: //test pass
SwapBytesForXbox(buff); SwapBytesForXbox(buff);
flag = DecodeDXT5(buff, bytes); flag = DecodeDXT5(buff, bytes);
@ -94,18 +99,18 @@ namespace AssetStudio
case TextureFormat.RGB9e5Float: //test pass case TextureFormat.RGB9e5Float: //test pass
flag = DecodeRGB9e5Float(buff, bytes); flag = DecodeRGB9e5Float(buff, bytes);
break; break;
case TextureFormat.BC4: //test pass
flag = DecodeBC4(buff, bytes);
break;
case TextureFormat.BC5: //test pass
flag = DecodeBC5(buff, bytes);
break;
case TextureFormat.BC6H: //test pass case TextureFormat.BC6H: //test pass
flag = DecodeBC6H(buff, bytes); flag = DecodeBC6H(buff, bytes);
break; break;
case TextureFormat.BC7: //test pass case TextureFormat.BC7: //test pass
flag = DecodeBC7(buff, bytes); flag = DecodeBC7(buff, bytes);
break; break;
case TextureFormat.BC4: //test pass
flag = DecodeBC4(buff, bytes);
break;
case TextureFormat.BC5: //test pass
flag = DecodeBC5(buff, bytes);
break;
case TextureFormat.DXT1Crunched: //test pass case TextureFormat.DXT1Crunched: //test pass
flag = DecodeDXT1Crunched(buff, bytes); flag = DecodeDXT1Crunched(buff, bytes);
break; break;
@ -194,6 +199,15 @@ namespace AssetStudio
case TextureFormat.ETC2_RGBA8Crunched: //test pass case TextureFormat.ETC2_RGBA8Crunched: //test pass
flag = DecodeETC2A8Crunched(buff, bytes); flag = DecodeETC2A8Crunched(buff, bytes);
break; break;
case TextureFormat.RG32: //test pass
flag = DecodeRG32(buff, bytes);
break;
case TextureFormat.RGB48: //test pass
flag = DecodeRGB48(buff, bytes);
break;
case TextureFormat.RGBA64: //test pass
flag = DecodeRGBA64(buff, bytes);
break;
} }
BigArrayPool<byte>.Shared.Return(buff); BigArrayPool<byte>.Shared.Return(buff);
return flag; return flag;
@ -214,9 +228,10 @@ namespace AssetStudio
private bool DecodeAlpha8(byte[] image_data, byte[] buff) private bool DecodeAlpha8(byte[] image_data, byte[] buff)
{ {
var size = m_Width * m_Height;
var span = new Span<byte>(buff); var span = new Span<byte>(buff);
span.Fill(0xFF); span.Fill(0xFF);
for (var i = 0; i < m_Width * m_Height; i++) for (var i = 0; i < size; i++)
{ {
buff[i * 4 + 3] = image_data[i]; buff[i * 4 + 3] = image_data[i];
} }
@ -225,8 +240,9 @@ namespace AssetStudio
private bool DecodeARGB4444(byte[] image_data, byte[] buff) private bool DecodeARGB4444(byte[] image_data, byte[] buff)
{ {
var size = m_Width * m_Height;
var pixelNew = new byte[4]; var pixelNew = new byte[4];
for (var i = 0; i < m_Width * m_Height; i++) for (var i = 0; i < size; i++)
{ {
var pixelOldShort = BitConverter.ToUInt16(image_data, i * 2); var pixelOldShort = BitConverter.ToUInt16(image_data, i * 2);
pixelNew[0] = (byte)(pixelOldShort & 0x000f); pixelNew[0] = (byte)(pixelOldShort & 0x000f);
@ -242,7 +258,8 @@ namespace AssetStudio
private bool DecodeRGB24(byte[] image_data, byte[] buff) private bool DecodeRGB24(byte[] image_data, byte[] buff)
{ {
for (var i = 0; i < m_Width * m_Height; i++) var size = m_Width * m_Height;
for (var i = 0; i < size; i++)
{ {
buff[i * 4] = image_data[i * 3 + 2]; buff[i * 4] = image_data[i * 3 + 2];
buff[i * 4 + 1] = image_data[i * 3 + 1]; buff[i * 4 + 1] = image_data[i * 3 + 1];
@ -254,7 +271,7 @@ namespace AssetStudio
private bool DecodeRGBA32(byte[] image_data, byte[] buff) private bool DecodeRGBA32(byte[] image_data, byte[] buff)
{ {
for (var i = 0; i < buff.Length; i += 4) for (var i = 0; i < outPutSize; i += 4)
{ {
buff[i] = image_data[i + 2]; buff[i] = image_data[i + 2];
buff[i + 1] = image_data[i + 1]; buff[i + 1] = image_data[i + 1];
@ -266,7 +283,7 @@ namespace AssetStudio
private bool DecodeARGB32(byte[] image_data, byte[] buff) private bool DecodeARGB32(byte[] image_data, byte[] buff)
{ {
for (var i = 0; i < buff.Length; i += 4) for (var i = 0; i < outPutSize; i += 4)
{ {
buff[i] = image_data[i + 3]; buff[i] = image_data[i + 3];
buff[i + 1] = image_data[i + 2]; buff[i + 1] = image_data[i + 2];
@ -278,7 +295,8 @@ namespace AssetStudio
private bool DecodeRGB565(byte[] image_data, byte[] buff) private bool DecodeRGB565(byte[] image_data, byte[] buff)
{ {
for (var i = 0; i < m_Width * m_Height; i++) var size = m_Width * m_Height;
for (var i = 0; i < size; i++)
{ {
var p = BitConverter.ToUInt16(image_data, i * 2); var p = BitConverter.ToUInt16(image_data, i * 2);
buff[i * 4] = (byte)((p << 3) | (p >> 2 & 7)); buff[i * 4] = (byte)((p << 3) | (p >> 2 & 7));
@ -291,11 +309,12 @@ namespace AssetStudio
private bool DecodeR16(byte[] image_data, byte[] buff) private bool DecodeR16(byte[] image_data, byte[] buff)
{ {
for (var i = 0; i < m_Width * m_Height; i++) var size = m_Width * m_Height;
for (var i = 0; i < size; i++)
{ {
buff[i * 4] = 0; //b buff[i * 4] = 0; //b
buff[i * 4 + 1] = 0; //g buff[i * 4 + 1] = 0; //g
buff[i * 4 + 2] = image_data[i * 2 + 1]; //r buff[i * 4 + 2] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 2)); //r
buff[i * 4 + 3] = 255; //a buff[i * 4 + 3] = 255; //a
} }
return true; return true;
@ -313,8 +332,9 @@ namespace AssetStudio
private bool DecodeRGBA4444(byte[] image_data, byte[] buff) private bool DecodeRGBA4444(byte[] image_data, byte[] buff)
{ {
var size = m_Width * m_Height;
var pixelNew = new byte[4]; var pixelNew = new byte[4];
for (var i = 0; i < m_Width * m_Height; i++) for (var i = 0; i < size; i++)
{ {
var pixelOldShort = BitConverter.ToUInt16(image_data, i * 2); var pixelOldShort = BitConverter.ToUInt16(image_data, i * 2);
pixelNew[0] = (byte)((pixelOldShort & 0x00f0) >> 4); pixelNew[0] = (byte)((pixelOldShort & 0x00f0) >> 4);
@ -330,7 +350,7 @@ namespace AssetStudio
private bool DecodeBGRA32(byte[] image_data, byte[] buff) private bool DecodeBGRA32(byte[] image_data, byte[] buff)
{ {
for (var i = 0; i < buff.Length; i += 4) for (var i = 0; i < outPutSize; i += 4)
{ {
buff[i] = image_data[i]; buff[i] = image_data[i];
buff[i + 1] = image_data[i + 1]; buff[i + 1] = image_data[i + 1];
@ -342,7 +362,7 @@ namespace AssetStudio
private bool DecodeRHalf(byte[] image_data, byte[] buff) private bool DecodeRHalf(byte[] image_data, byte[] buff)
{ {
for (var i = 0; i < buff.Length; i += 4) for (var i = 0; i < outPutSize; i += 4)
{ {
buff[i] = 0; buff[i] = 0;
buff[i + 1] = 0; buff[i + 1] = 0;
@ -354,7 +374,7 @@ namespace AssetStudio
private bool DecodeRGHalf(byte[] image_data, byte[] buff) private bool DecodeRGHalf(byte[] image_data, byte[] buff)
{ {
for (var i = 0; i < buff.Length; i += 4) for (var i = 0; i < outPutSize; i += 4)
{ {
buff[i] = 0; buff[i] = 0;
buff[i + 1] = (byte)Math.Round(Half.ToHalf(image_data, i + 2) * 255f); buff[i + 1] = (byte)Math.Round(Half.ToHalf(image_data, i + 2) * 255f);
@ -366,7 +386,7 @@ namespace AssetStudio
private bool DecodeRGBAHalf(byte[] image_data, byte[] buff) private bool DecodeRGBAHalf(byte[] image_data, byte[] buff)
{ {
for (var i = 0; i < buff.Length; i += 4) for (var i = 0; i < outPutSize; i += 4)
{ {
buff[i] = (byte)Math.Round(Half.ToHalf(image_data, i * 2 + 4) * 255f); buff[i] = (byte)Math.Round(Half.ToHalf(image_data, i * 2 + 4) * 255f);
buff[i + 1] = (byte)Math.Round(Half.ToHalf(image_data, i * 2 + 2) * 255f); buff[i + 1] = (byte)Math.Round(Half.ToHalf(image_data, i * 2 + 2) * 255f);
@ -378,7 +398,7 @@ namespace AssetStudio
private bool DecodeRFloat(byte[] image_data, byte[] buff) private bool DecodeRFloat(byte[] image_data, byte[] buff)
{ {
for (var i = 0; i < buff.Length; i += 4) for (var i = 0; i < outPutSize; i += 4)
{ {
buff[i] = 0; buff[i] = 0;
buff[i + 1] = 0; buff[i + 1] = 0;
@ -390,7 +410,7 @@ namespace AssetStudio
private bool DecodeRGFloat(byte[] image_data, byte[] buff) private bool DecodeRGFloat(byte[] image_data, byte[] buff)
{ {
for (var i = 0; i < buff.Length; i += 4) for (var i = 0; i < outPutSize; i += 4)
{ {
buff[i] = 0; buff[i] = 0;
buff[i + 1] = (byte)Math.Round(BitConverter.ToSingle(image_data, i * 2 + 4) * 255f); buff[i + 1] = (byte)Math.Round(BitConverter.ToSingle(image_data, i * 2 + 4) * 255f);
@ -402,7 +422,7 @@ namespace AssetStudio
private bool DecodeRGBAFloat(byte[] image_data, byte[] buff) private bool DecodeRGBAFloat(byte[] image_data, byte[] buff)
{ {
for (var i = 0; i < buff.Length; i += 4) for (var i = 0; i < outPutSize; i += 4)
{ {
buff[i] = (byte)Math.Round(BitConverter.ToSingle(image_data, i * 4 + 8) * 255f); buff[i] = (byte)Math.Round(BitConverter.ToSingle(image_data, i * 4 + 8) * 255f);
buff[i + 1] = (byte)Math.Round(BitConverter.ToSingle(image_data, i * 4 + 4) * 255f); buff[i + 1] = (byte)Math.Round(BitConverter.ToSingle(image_data, i * 4 + 4) * 255f);
@ -412,6 +432,7 @@ namespace AssetStudio
return true; return true;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static byte ClampByte(int x) private static byte ClampByte(int x)
{ {
return (byte)(byte.MaxValue < x ? byte.MaxValue : (x > byte.MinValue ? x : byte.MinValue)); return (byte)(byte.MaxValue < x ? byte.MaxValue : (x > byte.MinValue ? x : byte.MinValue));
@ -449,7 +470,7 @@ namespace AssetStudio
private bool DecodeRGB9e5Float(byte[] image_data, byte[] buff) private bool DecodeRGB9e5Float(byte[] image_data, byte[] buff)
{ {
for (var i = 0; i < buff.Length; i += 4) for (var i = 0; i < outPutSize; i += 4)
{ {
var n = BitConverter.ToInt32(image_data, i); var n = BitConverter.ToInt32(image_data, i);
var scale = n >> 27 & 0x1f; var scale = n >> 27 & 0x1f;
@ -571,19 +592,21 @@ namespace AssetStudio
private bool DecodeRG16(byte[] image_data, byte[] buff) private bool DecodeRG16(byte[] image_data, byte[] buff)
{ {
for (var i = 0; i < m_Width * m_Height; i += 2) var size = m_Width * m_Height;
for (var i = 0; i < size; i++)
{ {
buff[i * 2] = 0; //B buff[i * 4] = 0; //B
buff[i * 2 + 1] = image_data[i + 1];//G buff[i * 4 + 1] = image_data[i * 2 + 1];//G
buff[i * 2 + 2] = image_data[i];//R buff[i * 4 + 2] = image_data[i * 2];//R
buff[i * 2 + 3] = 255;//A buff[i * 4 + 3] = 255;//A
} }
return true; return true;
} }
private bool DecodeR8(byte[] image_data, byte[] buff) private bool DecodeR8(byte[] image_data, byte[] buff)
{ {
for (var i = 0; i < m_Width * m_Height; i++) var size = m_Width * m_Height;
for (var i = 0; i < size; i++)
{ {
buff[i * 4] = 0; //B buff[i * 4] = 0; //B
buff[i * 4 + 1] = 0; //G buff[i * 4 + 1] = 0; //G
@ -617,6 +640,49 @@ namespace AssetStudio
return false; return false;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static byte DownScaleFrom16BitTo8Bit(ushort component)
{
return (byte)(((component * 255) + 32895) >> 16);
}
private bool DecodeRG32(byte[] image_data, byte[] buff)
{
for (var i = 0; i < outPutSize; i += 4)
{
buff[i] = 0; //b
buff[i + 1] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i + 2)); //g
buff[i + 2] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i)); //r
buff[i + 3] = byte.MaxValue; //a
}
return true;
}
private bool DecodeRGB48(byte[] image_data, byte[] buff)
{
var size = m_Width * m_Height;
for (var i = 0; i < size; i++)
{
buff[i * 4] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 6 + 4)); //b
buff[i * 4 + 1] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 6 + 2)); //g
buff[i * 4 + 2] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 6)); //r
buff[i * 4 + 3] = byte.MaxValue; //a
}
return true;
}
private bool DecodeRGBA64(byte[] image_data, byte[] buff)
{
for (var i = 0; i < outPutSize; i += 4)
{
buff[i] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 2 + 4)); //b
buff[i + 1] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 2 + 2)); //g
buff[i + 2] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 2)); //r
buff[i + 3] = DownScaleFrom16BitTo8Bit(BitConverter.ToUInt16(image_data, i * 2 + 6)); //a
}
return true;
}
private bool UnpackCrunch(byte[] image_data, out byte[] result) private bool UnpackCrunch(byte[] image_data, out byte[] result)
{ {
if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 3) //2017.3 and up if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 3) //2017.3 and up