Improve vertex format parsing. Close #689

This commit is contained in:
Perfare 2021-04-12 15:11:17 +08:00
parent f1f2430f97
commit 6d99f5ebf6

View File

@ -195,7 +195,7 @@ namespace AssetStudio
if (m_Channel.dimension > 0)
{
chnMask |= 1u << chn;
stride += m_Channel.dimension * MeshHelper.GetFormatSize(version, m_Channel.format);
stride += m_Channel.dimension * MeshHelper.GetFormatSize(MeshHelper.ToVertexFormat(m_Channel.format, version));
}
}
}
@ -253,7 +253,7 @@ namespace AssetStudio
m_Channel.dimension = 4;
break;
}
offset += (byte)(m_Channel.dimension * MeshHelper.GetFormatSize(version, m_Channel.format));
offset += (byte)(m_Channel.dimension * MeshHelper.GetFormatSize(MeshHelper.ToVertexFormat(m_Channel.format, version)));
}
}
}
@ -711,12 +711,13 @@ namespace AssetStudio
var channelMask = new BitArray(new[] { (int)m_Stream.channelMask });
if (channelMask.Get(chn))
{
if (version[0] < 2018 && chn == 2 && m_Channel.format == 2)
if (version[0] < 2018 && chn == 2 && m_Channel.format == 2) //kShaderChannelColor && kChannelFormatColor
{
m_Channel.dimension = 4;
}
var componentByteSize = (int)MeshHelper.GetFormatSize(version, m_Channel.format);
var vertexFormat = MeshHelper.ToVertexFormat(m_Channel.format, version);
var componentByteSize = (int)MeshHelper.GetFormatSize(vertexFormat);
var componentBytes = new byte[m_VertexCount * m_Channel.dimension * componentByteSize];
for (int v = 0; v < m_VertexCount; v++)
{
@ -741,10 +742,10 @@ namespace AssetStudio
int[] componentsIntArray = null;
float[] componentsFloatArray = null;
if (MeshHelper.IsIntFormat(version, m_Channel.format))
componentsIntArray = MeshHelper.BytesToIntArray(componentBytes, componentByteSize);
if (MeshHelper.IsIntFormat(vertexFormat))
componentsIntArray = MeshHelper.BytesToIntArray(componentBytes, vertexFormat);
else
componentsFloatArray = MeshHelper.BytesToFloatArray(componentBytes, componentByteSize);
componentsFloatArray = MeshHelper.BytesToFloatArray(componentBytes, vertexFormat);
if (version[0] >= 2018)
{
@ -1190,7 +1191,7 @@ namespace AssetStudio
public static class MeshHelper
{
private enum VertexChannelFormat
public enum VertexChannelFormat
{
kChannelFormatFloat,
kChannelFormatFloat16,
@ -1199,7 +1200,7 @@ namespace AssetStudio
kChannelFormatUInt32
}
private enum VertexFormat
public enum VertexFormat2017
{
kVertexFormatFloat,
kVertexFormatFloat16,
@ -1216,7 +1217,7 @@ namespace AssetStudio
kVertexFormatSInt32
}
private enum VertexFormatV2019
public enum VertexFormat
{
kVertexFormatFloat,
kVertexFormatFloat16,
@ -1232,147 +1233,146 @@ namespace AssetStudio
kVertexFormatSInt32
}
public static uint GetFormatSize(int[] version, int format)
public static VertexFormat ToVertexFormat(int format, int[] version)
{
if (version[0] < 2017)
{
switch ((VertexChannelFormat)format)
{
case VertexChannelFormat.kChannelFormatFloat:
return 4u;
return VertexFormat.kVertexFormatFloat;
case VertexChannelFormat.kChannelFormatFloat16:
return 2u;
return VertexFormat.kVertexFormatFloat16;
case VertexChannelFormat.kChannelFormatColor: //in 4.x is size 4
return 1u;
return VertexFormat.kVertexFormatUNorm8;
case VertexChannelFormat.kChannelFormatByte:
return 1u;
return VertexFormat.kVertexFormatUInt8;
case VertexChannelFormat.kChannelFormatUInt32: //in 5.x
return 4u;
return VertexFormat.kVertexFormatUInt32;
default:
throw new ArgumentOutOfRangeException(nameof(format), format, null);
}
}
else if (version[0] < 2019)
{
switch ((VertexFormat)format)
switch ((VertexFormat2017)format)
{
case VertexFormat2017.kVertexFormatFloat:
return VertexFormat.kVertexFormatFloat;
case VertexFormat2017.kVertexFormatFloat16:
return VertexFormat.kVertexFormatFloat16;
case VertexFormat2017.kVertexFormatColor:
case VertexFormat2017.kVertexFormatUNorm8:
return VertexFormat.kVertexFormatUNorm8;
case VertexFormat2017.kVertexFormatSNorm8:
return VertexFormat.kVertexFormatSNorm8;
case VertexFormat2017.kVertexFormatUNorm16:
return VertexFormat.kVertexFormatUNorm16;
case VertexFormat2017.kVertexFormatSNorm16:
return VertexFormat.kVertexFormatSNorm16;
case VertexFormat2017.kVertexFormatUInt8:
return VertexFormat.kVertexFormatUInt8;
case VertexFormat2017.kVertexFormatSInt8:
return VertexFormat.kVertexFormatSInt8;
case VertexFormat2017.kVertexFormatUInt16:
return VertexFormat.kVertexFormatUInt16;
case VertexFormat2017.kVertexFormatSInt16:
return VertexFormat.kVertexFormatSInt16;
case VertexFormat2017.kVertexFormatUInt32:
return VertexFormat.kVertexFormatUInt32;
case VertexFormat2017.kVertexFormatSInt32:
return VertexFormat.kVertexFormatSInt32;
default:
throw new ArgumentOutOfRangeException(nameof(format), format, null);
}
}
else
{
return (VertexFormat)format;
}
}
public static uint GetFormatSize(VertexFormat format)
{
switch (format)
{
case VertexFormat.kVertexFormatFloat:
case VertexFormat.kVertexFormatUInt32:
case VertexFormat.kVertexFormatSInt32:
return 4u;
case VertexFormat.kVertexFormatFloat16:
case VertexFormat.kVertexFormatUNorm16:
case VertexFormat.kVertexFormatSNorm16:
case VertexFormat.kVertexFormatUInt16:
case VertexFormat.kVertexFormatSInt16:
return 2u;
case VertexFormat.kVertexFormatUNorm8:
case VertexFormat.kVertexFormatSNorm8:
case VertexFormat.kVertexFormatUInt8:
case VertexFormat.kVertexFormatSInt8:
return 1u;
default:
throw new ArgumentOutOfRangeException(nameof(format), format, null);
}
}
public static bool IsIntFormat(VertexFormat format)
{
return format >= VertexFormat.kVertexFormatUInt8;
}
public static float[] BytesToFloatArray(byte[] inputBytes, VertexFormat format)
{
var size = GetFormatSize(format);
var len = inputBytes.Length / size;
var result = new float[len];
for (int i = 0; i < len; i++)
{
switch (format)
{
case VertexFormat.kVertexFormatFloat:
return 4u;
result[i] = BitConverter.ToSingle(inputBytes, i * 4);
break;
case VertexFormat.kVertexFormatFloat16:
return 2u;
case VertexFormat.kVertexFormatColor:
return 1u;
result[i] = Half.ToHalf(inputBytes, i * 2);
break;
case VertexFormat.kVertexFormatUNorm8:
return 1u;
result[i] = inputBytes[i] / 255f;
break;
case VertexFormat.kVertexFormatSNorm8:
return 1u;
result[i] = Math.Max((sbyte)inputBytes[i] / 127f, -1f);
break;
case VertexFormat.kVertexFormatUNorm16:
return 2u;
result[i] = BitConverter.ToUInt16(inputBytes, i * 2) / 65535f;
break;
case VertexFormat.kVertexFormatSNorm16:
return 2u;
case VertexFormat.kVertexFormatUInt8:
return 1u;
case VertexFormat.kVertexFormatSInt8:
return 1u;
case VertexFormat.kVertexFormatUInt16:
return 2u;
case VertexFormat.kVertexFormatSInt16:
return 2u;
case VertexFormat.kVertexFormatUInt32:
return 4u;
case VertexFormat.kVertexFormatSInt32:
return 4u;
default:
throw new ArgumentOutOfRangeException(nameof(format), format, null);
}
}
else
{
switch ((VertexFormatV2019)format)
{
case VertexFormatV2019.kVertexFormatFloat:
return 4u;
case VertexFormatV2019.kVertexFormatFloat16:
return 2u;
case VertexFormatV2019.kVertexFormatUNorm8:
return 1u;
case VertexFormatV2019.kVertexFormatSNorm8:
return 1u;
case VertexFormatV2019.kVertexFormatUNorm16:
return 2u;
case VertexFormatV2019.kVertexFormatSNorm16:
return 2u;
case VertexFormatV2019.kVertexFormatUInt8:
return 1u;
case VertexFormatV2019.kVertexFormatSInt8:
return 1u;
case VertexFormatV2019.kVertexFormatUInt16:
return 2u;
case VertexFormatV2019.kVertexFormatSInt16:
return 2u;
case VertexFormatV2019.kVertexFormatUInt32:
return 4u;
case VertexFormatV2019.kVertexFormatSInt32:
return 4u;
default:
throw new ArgumentOutOfRangeException(nameof(format), format, null);
}
}
}
public static bool IsIntFormat(int[] version, int format)
{
if (version[0] < 2017)
{
return format == 4;
}
else if (version[0] < 2019)
{
return format >= 7;
}
else
{
return format >= 6;
}
}
public static float[] BytesToFloatArray(byte[] inputBytes, int size)
{
var result = new float[inputBytes.Length / size];
for (int i = 0; i < inputBytes.Length / size; i++)
{
var value = 0f;
switch (size)
{
case 1:
value = inputBytes[i] / 255.0f;
break;
case 2:
value = Half.ToHalf(inputBytes, i * 2);
break;
case 4:
value = BitConverter.ToSingle(inputBytes, i * 4);
result[i] = Math.Max(BitConverter.ToInt16(inputBytes, i * 2) / 32767f, -1f);
break;
}
result[i] = value;
}
return result;
}
public static int[] BytesToIntArray(byte[] inputBytes, int size)
public static int[] BytesToIntArray(byte[] inputBytes, VertexFormat format)
{
var result = new int[inputBytes.Length / size];
for (int i = 0; i < inputBytes.Length / size; i++)
var size = GetFormatSize(format);
var len = inputBytes.Length / size;
var result = new int[len];
for (int i = 0; i < len; i++)
{
switch (size)
switch (format)
{
case 1:
case VertexFormat.kVertexFormatUInt8:
case VertexFormat.kVertexFormatSInt8:
result[i] = inputBytes[i];
break;
case 2:
case VertexFormat.kVertexFormatUInt16:
case VertexFormat.kVertexFormatSInt16:
result[i] = BitConverter.ToInt16(inputBytes, i * 2);
break;
case 4:
case VertexFormat.kVertexFormatUInt32:
case VertexFormat.kVertexFormatSInt32:
result[i] = BitConverter.ToInt32(inputBytes, i * 4);
break;
}